mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-04-16 04:28:05 +02:00
girffi: Fix g_callable_info_prepare_closure for certain callables
Namely, those that are methods and those that throw GErrors. We have very similar code in two places that calculate arg lengths and argument types to stick into libffi. Merge, clean up, and correct both. https://bugzilla.gnome.org/show_bug.cgi?id=673805
This commit is contained in:
parent
d65cec7f15
commit
3bcc0e43c6
115
girffi.c
115
girffi.c
@ -146,42 +146,65 @@ g_type_info_get_ffi_type (GITypeInfo *info)
|
|||||||
/**
|
/**
|
||||||
* g_callable_info_get_ffi_arg_types:
|
* g_callable_info_get_ffi_arg_types:
|
||||||
* @callable_info: a callable info from a typelib
|
* @callable_info: a callable info from a typelib
|
||||||
|
* @n_args_p: (out): The number of arguments
|
||||||
*
|
*
|
||||||
* Return value: an array of ffi_type*. The array itself
|
* Return value: an array of ffi_type*. The array itself
|
||||||
* should be freed using g_free() after use.
|
* should be freed using g_free() after use.
|
||||||
*/
|
*/
|
||||||
static ffi_type **
|
static ffi_type **
|
||||||
g_callable_info_get_ffi_arg_types (GICallableInfo *callable_info)
|
g_callable_info_get_ffi_arg_types (GICallableInfo *callable_info,
|
||||||
|
int *n_args_p)
|
||||||
{
|
{
|
||||||
ffi_type **arg_types;
|
ffi_type **arg_types;
|
||||||
gint n_args, i;
|
gboolean is_method, throws;
|
||||||
|
gint n_args, n_invoke_args, i, offset;
|
||||||
|
|
||||||
g_return_val_if_fail (callable_info != NULL, NULL);
|
g_return_val_if_fail (callable_info != NULL, NULL);
|
||||||
|
|
||||||
n_args = g_callable_info_get_n_args (callable_info);
|
n_args = g_callable_info_get_n_args (callable_info);
|
||||||
|
is_method = g_callable_info_is_method (callable_info);
|
||||||
|
throws = g_callable_info_can_throw_gerror (callable_info);
|
||||||
|
offset = is_method ? 1 : 0;
|
||||||
|
|
||||||
arg_types = (ffi_type **) g_new0 (ffi_type *, n_args + 1);
|
n_invoke_args = n_args;
|
||||||
|
|
||||||
|
if (is_method)
|
||||||
|
n_invoke_args++;
|
||||||
|
if (throws)
|
||||||
|
n_invoke_args++;
|
||||||
|
|
||||||
|
if (n_args_p)
|
||||||
|
*n_args_p = n_invoke_args;
|
||||||
|
|
||||||
|
arg_types = (ffi_type **) g_new0 (ffi_type *, n_invoke_args + 1);
|
||||||
|
|
||||||
|
if (is_method)
|
||||||
|
arg_types[0] = &ffi_type_pointer;
|
||||||
|
if (throws)
|
||||||
|
arg_types[n_invoke_args - 1] = &ffi_type_pointer;
|
||||||
|
|
||||||
for (i = 0; i < n_args; ++i)
|
for (i = 0; i < n_args; ++i)
|
||||||
{
|
{
|
||||||
GIArgInfo *arg_info = g_callable_info_get_arg (callable_info, i);
|
GIArgInfo arg_info;
|
||||||
GITypeInfo *arg_type = g_arg_info_get_type (arg_info);
|
GITypeInfo arg_type;
|
||||||
switch (g_arg_info_get_direction (arg_info))
|
|
||||||
|
g_callable_info_load_arg (callable_info, i, &arg_info);
|
||||||
|
g_arg_info_load_type (&arg_info, &arg_type);
|
||||||
|
switch (g_arg_info_get_direction (&arg_info))
|
||||||
{
|
{
|
||||||
case GI_DIRECTION_IN:
|
case GI_DIRECTION_IN:
|
||||||
arg_types[i] = g_type_info_get_ffi_type (arg_type);
|
arg_types[i + offset] = g_type_info_get_ffi_type (&arg_type);
|
||||||
break;
|
break;
|
||||||
case GI_DIRECTION_OUT:
|
case GI_DIRECTION_OUT:
|
||||||
case GI_DIRECTION_INOUT:
|
case GI_DIRECTION_INOUT:
|
||||||
arg_types[i] = &ffi_type_pointer;
|
arg_types[i + offset] = &ffi_type_pointer;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
g_assert_not_reached ();
|
g_assert_not_reached ();
|
||||||
}
|
}
|
||||||
g_base_info_unref ((GIBaseInfo *)arg_info);
|
|
||||||
g_base_info_unref ((GIBaseInfo *)arg_type);
|
|
||||||
}
|
}
|
||||||
arg_types[n_args] = NULL;
|
|
||||||
|
arg_types[n_invoke_args] = NULL;
|
||||||
|
|
||||||
return arg_types;
|
return arg_types;
|
||||||
}
|
}
|
||||||
@ -275,71 +298,19 @@ g_function_invoker_new_for_address (gpointer addr,
|
|||||||
GIFunctionInvoker *invoker,
|
GIFunctionInvoker *invoker,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
ffi_type *rtype;
|
|
||||||
ffi_type **atypes;
|
ffi_type **atypes;
|
||||||
GITypeInfo *tinfo;
|
gint n_args;
|
||||||
GIArgInfo *ainfo;
|
|
||||||
GIInfoType info_type;
|
|
||||||
gboolean is_method;
|
|
||||||
gboolean throws;
|
|
||||||
gint n_args, n_invoke_args, i;
|
|
||||||
|
|
||||||
g_return_val_if_fail (info != NULL, FALSE);
|
g_return_val_if_fail (info != NULL, FALSE);
|
||||||
g_return_val_if_fail (invoker != NULL, FALSE);
|
g_return_val_if_fail (invoker != NULL, FALSE);
|
||||||
|
|
||||||
invoker->native_address = addr;
|
invoker->native_address = addr;
|
||||||
|
|
||||||
is_method = g_callable_info_is_method (info);
|
atypes = g_callable_info_get_ffi_arg_types (info, &n_args);
|
||||||
throws = g_callable_info_can_throw_gerror (info);
|
|
||||||
|
|
||||||
tinfo = g_callable_info_get_return_type (info);
|
return ffi_prep_cif (&(invoker->cif), FFI_DEFAULT_ABI, n_args,
|
||||||
rtype = g_type_info_get_ffi_type (tinfo);
|
g_callable_info_get_ffi_return_type (info),
|
||||||
g_base_info_unref ((GIBaseInfo *)tinfo);
|
atypes) == FFI_OK;
|
||||||
|
|
||||||
n_args = g_callable_info_get_n_args (info);
|
|
||||||
if (is_method)
|
|
||||||
n_invoke_args = n_args+1;
|
|
||||||
else
|
|
||||||
n_invoke_args = n_args;
|
|
||||||
|
|
||||||
if (throws)
|
|
||||||
/* Add an argument for the GError */
|
|
||||||
n_invoke_args ++;
|
|
||||||
|
|
||||||
/* TODO: avoid malloc here? */
|
|
||||||
atypes = g_malloc0 (sizeof (ffi_type*) * n_invoke_args);
|
|
||||||
|
|
||||||
if (is_method)
|
|
||||||
{
|
|
||||||
atypes[0] = &ffi_type_pointer;
|
|
||||||
}
|
|
||||||
for (i = 0; i < n_args; i++)
|
|
||||||
{
|
|
||||||
int offset = (is_method ? 1 : 0);
|
|
||||||
ainfo = g_callable_info_get_arg (info, i);
|
|
||||||
switch (g_arg_info_get_direction (ainfo))
|
|
||||||
{
|
|
||||||
case GI_DIRECTION_IN:
|
|
||||||
tinfo = g_arg_info_get_type (ainfo);
|
|
||||||
atypes[i+offset] = g_type_info_get_ffi_type (tinfo);
|
|
||||||
g_base_info_unref ((GIBaseInfo *)tinfo);
|
|
||||||
break;
|
|
||||||
case GI_DIRECTION_OUT:
|
|
||||||
case GI_DIRECTION_INOUT:
|
|
||||||
atypes[i+offset] = &ffi_type_pointer;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
g_assert_not_reached ();
|
|
||||||
}
|
|
||||||
g_base_info_unref ((GIBaseInfo *)ainfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (throws)
|
|
||||||
{
|
|
||||||
atypes[n_invoke_args - 1] = &ffi_type_pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ffi_prep_cif (&(invoker->cif), FFI_DEFAULT_ABI, n_invoke_args, rtype, atypes) == FFI_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -380,6 +351,8 @@ g_callable_info_prepare_closure (GICallableInfo *callable_info,
|
|||||||
gpointer user_data)
|
gpointer user_data)
|
||||||
{
|
{
|
||||||
gpointer exec_ptr;
|
gpointer exec_ptr;
|
||||||
|
int n_args;
|
||||||
|
ffi_type **atypes;
|
||||||
GIClosureWrapper *closure;
|
GIClosureWrapper *closure;
|
||||||
ffi_status status;
|
ffi_status status;
|
||||||
|
|
||||||
@ -395,10 +368,10 @@ g_callable_info_prepare_closure (GICallableInfo *callable_info,
|
|||||||
}
|
}
|
||||||
closure->writable_self = closure;
|
closure->writable_self = closure;
|
||||||
|
|
||||||
status = ffi_prep_cif (cif, FFI_DEFAULT_ABI,
|
atypes = g_callable_info_get_ffi_arg_types (callable_info, &n_args);
|
||||||
g_callable_info_get_n_args (callable_info),
|
status = ffi_prep_cif (cif, FFI_DEFAULT_ABI, n_args,
|
||||||
g_callable_info_get_ffi_return_type (callable_info),
|
g_callable_info_get_ffi_return_type (callable_info),
|
||||||
g_callable_info_get_ffi_arg_types (callable_info));
|
atypes);
|
||||||
if (status != FFI_OK)
|
if (status != FFI_OK)
|
||||||
{
|
{
|
||||||
g_warning ("ffi_prep_cif failed: %d\n", status);
|
g_warning ("ffi_prep_cif failed: %d\n", status);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user