summaryrefslogtreecommitdiff
path: root/girepository/girffi.c
diff options
context:
space:
mode:
authorJasper St. Pierre <jstpierre@mecheye.net>2012-04-09 17:51:08 -0300
committerJasper St. Pierre <jstpierre@mecheye.net>2012-08-20 15:01:59 -0400
commitd8970fbc500a8b20853b564536251315587450d9 (patch)
tree119a27b8da81b77bdc2bb1baeb9cfe268bdc8026 /girepository/girffi.c
parentd220bb74c25ce098fb3cb074bb03a0868032e89c (diff)
downloadgobject-introspection-d8970fbc500a8b20853b564536251315587450d9.tar.gz
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
Diffstat (limited to 'girepository/girffi.c')
-rw-r--r--girepository/girffi.c115
1 files changed, 44 insertions, 71 deletions
diff --git a/girepository/girffi.c b/girepository/girffi.c
index f6e47fb0..ec710c37 100644
--- a/girepository/girffi.c
+++ b/girepository/girffi.c
@@ -146,42 +146,65 @@ g_type_info_get_ffi_type (GITypeInfo *info)
/**
* g_callable_info_get_ffi_arg_types:
* @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
* should be freed using g_free() after use.
*/
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;
- 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);
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)
{
- GIArgInfo *arg_info = g_callable_info_get_arg (callable_info, i);
- GITypeInfo *arg_type = g_arg_info_get_type (arg_info);
- switch (g_arg_info_get_direction (arg_info))
+ GIArgInfo arg_info;
+ GITypeInfo arg_type;
+
+ 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:
- arg_types[i] = g_type_info_get_ffi_type (arg_type);
+ arg_types[i + offset] = g_type_info_get_ffi_type (&arg_type);
break;
case GI_DIRECTION_OUT:
case GI_DIRECTION_INOUT:
- arg_types[i] = &ffi_type_pointer;
+ arg_types[i + offset] = &ffi_type_pointer;
break;
default:
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;
}
@@ -275,71 +298,19 @@ g_function_invoker_new_for_address (gpointer addr,
GIFunctionInvoker *invoker,
GError **error)
{
- ffi_type *rtype;
ffi_type **atypes;
- GITypeInfo *tinfo;
- GIArgInfo *ainfo;
- GIInfoType info_type;
- gboolean is_method;
- gboolean throws;
- gint n_args, n_invoke_args, i;
+ gint n_args;
g_return_val_if_fail (info != NULL, FALSE);
g_return_val_if_fail (invoker != NULL, FALSE);
invoker->native_address = addr;
- is_method = g_callable_info_is_method (info);
- throws = g_callable_info_can_throw_gerror (info);
-
- tinfo = g_callable_info_get_return_type (info);
- rtype = g_type_info_get_ffi_type (tinfo);
- g_base_info_unref ((GIBaseInfo *)tinfo);
-
- 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);
+ atypes = g_callable_info_get_ffi_arg_types (info, &n_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;
+ return ffi_prep_cif (&(invoker->cif), FFI_DEFAULT_ABI, n_args,
+ g_callable_info_get_ffi_return_type (info),
+ atypes) == FFI_OK;
}
/**
@@ -380,6 +351,8 @@ g_callable_info_prepare_closure (GICallableInfo *callable_info,
gpointer user_data)
{
gpointer exec_ptr;
+ int n_args;
+ ffi_type **atypes;
GIClosureWrapper *closure;
ffi_status status;
@@ -395,10 +368,10 @@ g_callable_info_prepare_closure (GICallableInfo *callable_info,
}
closure->writable_self = closure;
- status = ffi_prep_cif (cif, FFI_DEFAULT_ABI,
- g_callable_info_get_n_args (callable_info),
+ atypes = g_callable_info_get_ffi_arg_types (callable_info, &n_args);
+ status = ffi_prep_cif (cif, FFI_DEFAULT_ABI, n_args,
g_callable_info_get_ffi_return_type (callable_info),
- g_callable_info_get_ffi_arg_types (callable_info));
+ atypes);
if (status != FFI_OK)
{
g_warning ("ffi_prep_cif failed: %d\n", status);