summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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);