From d8970fbc500a8b20853b564536251315587450d9 Mon Sep 17 00:00:00 2001 From: "Jasper St. Pierre" Date: Mon, 9 Apr 2012 17:51:08 -0300 Subject: 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 --- girepository/girffi.c | 115 +++++++++++++++++++------------------------------- 1 file 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); -- cgit v1.2.1