diff --git a/docs/reference/gobject/gobject-sections.txt b/docs/reference/gobject/gobject-sections.txt index 7eb75fd01..6d8fa224a 100644 --- a/docs/reference/gobject/gobject-sections.txt +++ b/docs/reference/gobject/gobject-sections.txt @@ -814,6 +814,7 @@ g_cclosure_new g_cclosure_new_swap g_cclosure_new_object g_cclosure_new_object_swap +g_cclosure_marshal_generic g_closure_new_object g_closure_ref g_closure_sink diff --git a/gio/gdbus-codegen/codegen.py b/gio/gdbus-codegen/codegen.py index 974e6e998..5c67aebbd 100644 --- a/gio/gdbus-codegen/codegen.py +++ b/gio/gdbus-codegen/codegen.py @@ -749,7 +749,7 @@ class CodeGenerator: ' G_STRUCT_OFFSET (%sIface, handle_%s),\n' ' g_signal_accumulator_true_handled,\n' ' NULL,\n' # accu_data - ' _cclosure_marshal_generic,\n' + ' g_cclosure_marshal_generic,\n' ' G_TYPE_BOOLEAN,\n' ' %d,\n' ' G_TYPE_DBUS_METHOD_INVOCATION' @@ -768,7 +768,7 @@ class CodeGenerator: ' G_STRUCT_OFFSET (%sIface, %s),\n' ' NULL,\n' # accumulator ' NULL,\n' # accu_data - ' _cclosure_marshal_generic,\n' + ' g_cclosure_marshal_generic,\n' ' G_TYPE_NONE,\n' ' %d' %(s.name_hyphen, i.camel_name, s.name_lower, len(s.args))) @@ -1736,190 +1736,6 @@ class CodeGenerator: # --------------------------------------------------------------------------------------------------- - # From https://bugzilla.gnome.org/show_bug.cgi?id=567087 - # - # See https://bugzilla.gnome.org/show_bug.cgi?id=401080 for the request - # to include this in libgobject - # - def generate_generic_marshaller(self): - self.c.write('#include \n' - '' - 'static ffi_type *\n' - 'value_to_ffi_type (const GValue *gvalue, gpointer *value)\n' - '{\n' - ' ffi_type *rettype = NULL;\n' - ' GType type = g_type_fundamental (G_VALUE_TYPE (gvalue));\n' - ' g_assert (type != G_TYPE_INVALID);\n' - '\n' - ' switch (type)\n' - ' {\n' - ' case G_TYPE_BOOLEAN:\n' - ' case G_TYPE_CHAR:\n' - ' case G_TYPE_INT:\n' - ' rettype = &ffi_type_sint;\n' - ' *value = (gpointer)&(gvalue->data[0].v_int);\n' - ' break;\n' - ' case G_TYPE_UCHAR:\n' - ' case G_TYPE_UINT:\n' - ' rettype = &ffi_type_uint;\n' - ' *value = (gpointer)&(gvalue->data[0].v_uint);\n' - ' break;\n' - ' case G_TYPE_STRING:\n' - ' case G_TYPE_OBJECT:\n' - ' case G_TYPE_BOXED:\n' - ' case G_TYPE_POINTER:\n' - ' case G_TYPE_INTERFACE:\n' - ' case G_TYPE_VARIANT:\n' - ' rettype = &ffi_type_pointer;\n' - ' *value = (gpointer)&(gvalue->data[0].v_pointer);\n' - ' break;\n' - ' case G_TYPE_FLOAT:\n' - ' rettype = &ffi_type_float;\n' - ' *value = (gpointer)&(gvalue->data[0].v_float);\n' - ' break;\n' - ' case G_TYPE_DOUBLE:\n' - ' rettype = &ffi_type_double;\n' - ' *value = (gpointer)&(gvalue->data[0].v_double);\n' - ' break;\n' - ' case G_TYPE_LONG:\n' - ' rettype = &ffi_type_slong;\n' - ' *value = (gpointer)&(gvalue->data[0].v_long);\n' - ' break;\n' - ' case G_TYPE_ULONG:\n' - ' rettype = &ffi_type_ulong;\n' - ' *value = (gpointer)&(gvalue->data[0].v_ulong);\n' - ' break;\n' - ' case G_TYPE_INT64:\n' - ' rettype = &ffi_type_sint64;\n' - ' *value = (gpointer)&(gvalue->data[0].v_int64);\n' - ' break;\n' - ' case G_TYPE_UINT64:\n' - ' rettype = &ffi_type_uint64;\n' - ' *value = (gpointer)&(gvalue->data[0].v_uint64);\n' - ' break;\n' - ' default:\n' - ' rettype = &ffi_type_pointer;\n' - ' *value = NULL;\n' - ' g_warning ("value_to_ffi_type: Unsupported fundamental type: %s", g_type_name (type));\n' - ' break;\n' - ' }\n' - ' return rettype;\n' - '}\n' - '\n' - 'static void\n' - 'value_from_ffi_type (GValue *gvalue, gpointer *value)\n' - '{\n' - ' switch (g_type_fundamental (G_VALUE_TYPE (gvalue)))\n' - ' {\n' - ' case G_TYPE_INT:\n' - ' g_value_set_int (gvalue, *(gint*)value);\n' - ' break;\n' - ' case G_TYPE_FLOAT:\n' - ' g_value_set_float (gvalue, *(gfloat*)value);\n' - ' break;\n' - ' case G_TYPE_DOUBLE:\n' - ' g_value_set_double (gvalue, *(gdouble*)value);\n' - ' break;\n' - ' case G_TYPE_BOOLEAN:\n' - ' g_value_set_boolean (gvalue, *(gboolean*)value);\n' - ' break;\n' - ' case G_TYPE_STRING:\n' - ' g_value_set_string (gvalue, *(gchar**)value);\n' - ' break;\n' - ' case G_TYPE_CHAR:\n' - ' g_value_set_char (gvalue, *(gchar*)value);\n' - ' break;\n' - ' case G_TYPE_UCHAR:\n' - ' g_value_set_uchar (gvalue, *(guchar*)value);\n' - ' break;\n' - ' case G_TYPE_UINT:\n' - ' g_value_set_uint (gvalue, *(guint*)value);\n' - ' break;\n' - ' case G_TYPE_POINTER:\n' - ' g_value_set_pointer (gvalue, *(gpointer*)value);\n' - ' break;\n' - ' case G_TYPE_LONG:\n' - ' g_value_set_long (gvalue, *(glong*)value);\n' - ' break;\n' - ' case G_TYPE_ULONG:\n' - ' g_value_set_ulong (gvalue, *(gulong*)value);\n' - ' break;\n' - ' case G_TYPE_INT64:\n' - ' g_value_set_int64 (gvalue, *(gint64*)value);\n' - ' break;\n' - ' case G_TYPE_UINT64:\n' - ' g_value_set_uint64 (gvalue, *(guint64*)value);\n' - ' break;\n' - ' case G_TYPE_BOXED:\n' - ' g_value_set_boxed (gvalue, *(gpointer*)value);\n' - ' break;\n' - ' default:\n' - ' g_warning ("value_from_ffi_type: Unsupported fundamental type: %s",\n' - ' g_type_name (g_type_fundamental (G_VALUE_TYPE (gvalue))));\n' - ' }\n' - '}\n' - '\n' - 'static void\n' - '_cclosure_marshal_generic (GClosure *closure,\n' - ' GValue *return_gvalue,\n' - ' guint n_param_values,\n' - ' const GValue *param_values,\n' - ' gpointer invocation_hint,\n' - ' gpointer marshal_data)\n' - '{\n' - ' ffi_type *rtype;\n' - ' void *rvalue;\n' - ' int n_args;\n' - ' ffi_type **atypes;\n' - ' void **args;\n' - ' int i;\n' - ' ffi_cif cif;\n' - ' GCClosure *cc = (GCClosure*) closure;\n' - '\n' - ' if (return_gvalue && G_VALUE_TYPE (return_gvalue)) \n' - ' {\n' - ' rtype = value_to_ffi_type (return_gvalue, &rvalue);\n' - ' }\n' - ' else \n' - ' {\n' - ' rtype = &ffi_type_void;\n' - ' }\n' - '\n' - ' rvalue = g_alloca (MAX (rtype->size, sizeof (ffi_arg)));\n' - ' \n' - ' n_args = n_param_values + 1;\n' - ' atypes = g_alloca (sizeof (ffi_type *) * n_args);\n' - ' args = g_alloca (sizeof (gpointer) * n_args);\n' - '\n' - ' if (G_CCLOSURE_SWAP_DATA (closure))\n' - ' {\n' - ' atypes[n_args-1] = value_to_ffi_type (param_values + 0, \n' - ' &args[n_args-1]);\n' - ' atypes[0] = &ffi_type_pointer;\n' - ' args[0] = &closure->data;\n' - ' }\n' - ' else\n' - ' {\n' - ' atypes[0] = value_to_ffi_type (param_values + 0, &args[0]);\n' - ' atypes[n_args-1] = &ffi_type_pointer;\n' - ' args[n_args-1] = &closure->data;\n' - ' }\n' - '\n' - ' for (i = 1; i < n_args - 1; i++)\n' - ' atypes[i] = value_to_ffi_type (param_values + i, &args[i]);\n' - '\n' - ' if (ffi_prep_cif (&cif, FFI_DEFAULT_ABI, n_args, rtype, atypes) != FFI_OK)\n' - ' return;\n' - '\n' - ' ffi_call (&cif, marshal_data ? marshal_data : cc->callback, rvalue, args);\n' - '\n' - ' if (return_gvalue && G_VALUE_TYPE (return_gvalue))\n' - ' value_from_ffi_type (return_gvalue, rvalue);\n' - '}\n' - '\n') - - # --------------------------------------------------------------------------------------------------- - def generate_object_manager_client(self): self.c.write('/* ------------------------------------------------------------------------\n' ' * Code for proxy manager\n' @@ -2084,7 +1900,6 @@ class CodeGenerator: def generate(self): self.generate_intro() - self.generate_generic_marshaller() self.declare_types() for i in self.ifaces: self.c.write('/* ------------------------------------------------------------------------\n' diff --git a/gobject-2.0.pc.in b/gobject-2.0.pc.in index 41505a9b4..5bc67bcf6 100644 --- a/gobject-2.0.pc.in +++ b/gobject-2.0.pc.in @@ -8,4 +8,5 @@ Description: GLib Type, Object, Parameter and Signal Library Requires: glib-2.0,gthread-2.0 Version: @VERSION@ Libs: -L${libdir} -lgobject-2.0 +Libs.private: @LIBFFI_LIBS@ Cflags: diff --git a/gobject/Makefile.am b/gobject/Makefile.am index d27a18bd7..c013a2f68 100644 --- a/gobject/Makefile.am +++ b/gobject/Makefile.am @@ -80,7 +80,9 @@ libgobject_2_0_la_LDFLAGS = $(GLIB_LINK_FLAGS) \ -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) \ -export-dynamic $(no_undefined) $(export_symbols) -libgobject_2_0_la_LIBADD = $(libglib) +libgobject_2_0_la_CFLAGS = $(LIBFFI_CFLAGS) + +libgobject_2_0_la_LIBADD = $(libglib) $(LIBFFI_LIBS) libgobject_2_0_la_DEPENDENCIES = $(gobject_win32_res) $(gobject_def) diff --git a/gobject/gclosure.c b/gobject/gclosure.c index a415182da..5305efdcd 100644 --- a/gobject/gclosure.c +++ b/gobject/gclosure.c @@ -26,6 +26,8 @@ #include +#include + #include "gclosure.h" #include "gvalue.h" @@ -935,6 +937,198 @@ g_signal_type_cclosure_new (GType itype, return closure; } +#include +static ffi_type * +value_to_ffi_type (const GValue *gvalue, gpointer *value) +{ + ffi_type *rettype = NULL; + GType type = g_type_fundamental (G_VALUE_TYPE (gvalue)); + g_assert (type != G_TYPE_INVALID); + + switch (type) + { + case G_TYPE_BOOLEAN: + case G_TYPE_CHAR: + case G_TYPE_INT: + rettype = &ffi_type_sint; + *value = (gpointer)&(gvalue->data[0].v_int); + break; + case G_TYPE_UCHAR: + case G_TYPE_UINT: + rettype = &ffi_type_uint; + *value = (gpointer)&(gvalue->data[0].v_uint); + break; + case G_TYPE_STRING: + case G_TYPE_OBJECT: + case G_TYPE_BOXED: + case G_TYPE_POINTER: + case G_TYPE_INTERFACE: + case G_TYPE_VARIANT: + rettype = &ffi_type_pointer; + *value = (gpointer)&(gvalue->data[0].v_pointer); + break; + case G_TYPE_FLOAT: + rettype = &ffi_type_float; + *value = (gpointer)&(gvalue->data[0].v_float); + break; + case G_TYPE_DOUBLE: + rettype = &ffi_type_double; + *value = (gpointer)&(gvalue->data[0].v_double); + break; + case G_TYPE_LONG: + rettype = &ffi_type_slong; + *value = (gpointer)&(gvalue->data[0].v_long); + break; + case G_TYPE_ULONG: + rettype = &ffi_type_ulong; + *value = (gpointer)&(gvalue->data[0].v_ulong); + break; + case G_TYPE_INT64: + rettype = &ffi_type_sint64; + *value = (gpointer)&(gvalue->data[0].v_int64); + break; + case G_TYPE_UINT64: + rettype = &ffi_type_uint64; + *value = (gpointer)&(gvalue->data[0].v_uint64); + break; + default: + rettype = &ffi_type_pointer; + *value = NULL; + g_warning ("value_to_ffi_type: Unsupported fundamental type: %s", g_type_name (type)); + break; + } + return rettype; +} + +static void +value_from_ffi_type (GValue *gvalue, gpointer *value) +{ + switch (g_type_fundamental (G_VALUE_TYPE (gvalue))) + { + case G_TYPE_INT: + g_value_set_int (gvalue, *(gint*)value); + break; + case G_TYPE_FLOAT: + g_value_set_float (gvalue, *(gfloat*)value); + break; + case G_TYPE_DOUBLE: + g_value_set_double (gvalue, *(gdouble*)value); + break; + case G_TYPE_BOOLEAN: + g_value_set_boolean (gvalue, *(gboolean*)value); + break; + case G_TYPE_STRING: + g_value_set_string (gvalue, *(gchar**)value); + break; + case G_TYPE_CHAR: + g_value_set_char (gvalue, *(gchar*)value); + break; + case G_TYPE_UCHAR: + g_value_set_uchar (gvalue, *(guchar*)value); + break; + case G_TYPE_UINT: + g_value_set_uint (gvalue, *(guint*)value); + break; + case G_TYPE_POINTER: + g_value_set_pointer (gvalue, *(gpointer*)value); + break; + case G_TYPE_LONG: + g_value_set_long (gvalue, *(glong*)value); + break; + case G_TYPE_ULONG: + g_value_set_ulong (gvalue, *(gulong*)value); + break; + case G_TYPE_INT64: + g_value_set_int64 (gvalue, *(gint64*)value); + break; + case G_TYPE_UINT64: + g_value_set_uint64 (gvalue, *(guint64*)value); + break; + case G_TYPE_BOXED: + g_value_set_boxed (gvalue, *(gpointer*)value); + break; + default: + g_warning ("value_from_ffi_type: Unsupported fundamental type: %s", + g_type_name (g_type_fundamental (G_VALUE_TYPE (gvalue)))); + } +} + +/** + * g_cclosure_marshal_generic: + * @closure: A #GClosure. + * @return_gvalue: A #GValue to store the return value. May be %NULL + * if the callback of closure doesn't return a value. + * @n_param_values: The length of the @param_values array. + * @param_values: An array of #GValues holding the arguments + * on which to invoke the callback of closure. + * @invocation_hint: The invocation hint given as the last argument to + * g_closure_invoke(). + * @marshal_data: Additional data specified when registering the + * marshaller, see g_closure_set_marshal() and + * g_closure_set_meta_marshal() + * + * A generic marshaller function implemented via libffi. + * + * Since: 2.30 + */ +void +g_cclosure_marshal_generic (GClosure *closure, + GValue *return_gvalue, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data) +{ + ffi_type *rtype; + void *rvalue; + int n_args; + ffi_type **atypes; + void **args; + int i; + ffi_cif cif; + GCClosure *cc = (GCClosure*) closure; + + if (return_gvalue && G_VALUE_TYPE (return_gvalue)) + { + rtype = value_to_ffi_type (return_gvalue, &rvalue); + } + else + { + rtype = &ffi_type_void; + } + + rvalue = g_alloca (MAX (rtype->size, sizeof (ffi_arg))); + + n_args = n_param_values + 1; + atypes = g_alloca (sizeof (ffi_type *) * n_args); + args = g_alloca (sizeof (gpointer) * n_args); + + if (G_CCLOSURE_SWAP_DATA (closure)) + { + atypes[n_args-1] = value_to_ffi_type (param_values + 0, + &args[n_args-1]); + atypes[0] = &ffi_type_pointer; + args[0] = &closure->data; + } + else + { + atypes[0] = value_to_ffi_type (param_values + 0, &args[0]); + atypes[n_args-1] = &ffi_type_pointer; + args[n_args-1] = &closure->data; + } + + for (i = 1; i < n_args - 1; i++) + atypes[i] = value_to_ffi_type (param_values + i, &args[i]); + + if (ffi_prep_cif (&cif, FFI_DEFAULT_ABI, n_args, rtype, atypes) != FFI_OK) + return; + + ffi_call (&cif, marshal_data ? marshal_data : cc->callback, rvalue, args); + + if (return_gvalue && G_VALUE_TYPE (return_gvalue)) + value_from_ffi_type (return_gvalue, rvalue); +} /** * g_cclosure_marshal_VOID__VOID: diff --git a/gobject/gclosure.h b/gobject/gclosure.h index fc0cb47c4..1b47c65cf 100644 --- a/gobject/gclosure.h +++ b/gobject/gclosure.h @@ -246,6 +246,13 @@ void g_closure_invoke (GClosure *closure, - provide marshaller collection, virtually covering anything out there */ +void g_cclosure_marshal_generic (GClosure *closure, + GValue *return_gvalue, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data); + G_END_DECLS #endif /* __G_CLOSURE_H__ */ diff --git a/gobject/gobject.symbols b/gobject/gobject.symbols index dd4b62de8..e4722be43 100644 --- a/gobject/gobject.symbols +++ b/gobject/gobject.symbols @@ -101,6 +101,7 @@ g_closure_set_meta_marshal g_closure_sink g_closure_unref g_signal_type_cclosure_new +g_cclosure_marshal_generic #endif #endif