[glib/signal-performance: 4/10] Add optional support for varargs marshallers to GClosure
- From: Alexander Larsson <alexl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib/signal-performance: 4/10] Add optional support for varargs marshallers to GClosure
- Date: Fri, 2 Mar 2012 16:13:44 +0000 (UTC)
commit 588af03a2893615736685c43cdaff767f70d04e8
Author: Alexander Larsson <alexl redhat com>
Date: Wed Feb 22 19:29:14 2012 +0100
Add optional support for varargs marshallers to GClosure
These closures support being invoked on a va_args which can
be useful as you can then avoid boxing the va_args into
GValues in certain cases.
https://bugzilla.gnome.org/show_bug.cgi?id=661140
gobject/gclosure.c | 364 ++++++++++++++++++++++++++++++++++++++++++++++-
gobject/gclosure.h | 18 +++
gobject/gtype-private.h | 13 ++
3 files changed, 392 insertions(+), 3 deletions(-)
---
diff --git a/gobject/gclosure.c b/gobject/gclosure.c
index 4c0392a..bf79754 100644
--- a/gobject/gclosure.c
+++ b/gobject/gclosure.c
@@ -288,6 +288,24 @@ closure_invoke_notifiers (GClosure *closure,
}
}
+static void
+g_closure_set_meta_va_marshal (GClosure *closure,
+ GVaClosureMarshal va_meta_marshal)
+{
+ GRealClosure *real_closure;
+
+ g_return_if_fail (closure != NULL);
+ g_return_if_fail (va_meta_marshal != NULL);
+ g_return_if_fail (closure->is_invalid == FALSE);
+ g_return_if_fail (closure->in_marshal == FALSE);
+
+ real_closure = G_REAL_CLOSURE (closure);
+
+ g_return_if_fail (real_closure->meta_marshal != NULL);
+
+ real_closure->va_meta_marshal = va_meta_marshal;
+}
+
/**
* g_closure_set_meta_marshal: (skip)
* @closure: a #GClosure
@@ -768,6 +786,70 @@ g_closure_invoke (GClosure *closure,
g_closure_unref (closure);
}
+gboolean
+_g_closure_supports_invoke_va (GClosure *closure)
+{
+ GRealClosure *real_closure;
+
+ g_return_val_if_fail (closure != NULL, FALSE);
+
+ real_closure = G_REAL_CLOSURE (closure);
+
+ return
+ real_closure->va_marshal != NULL &&
+ (real_closure->meta_marshal == NULL ||
+ real_closure->va_meta_marshal != NULL);
+}
+
+void
+_g_closure_invoke_va (GClosure *closure,
+ GValue /*out*/ *return_value,
+ gpointer instance,
+ va_list args,
+ int n_params,
+ GType *param_types)
+{
+ GRealClosure *real_closure;
+
+ g_return_if_fail (closure != NULL);
+
+ real_closure = G_REAL_CLOSURE (closure);
+
+ g_closure_ref (closure); /* preserve floating flag */
+ if (!closure->is_invalid)
+ {
+ GVaClosureMarshal marshal;
+ gpointer marshal_data;
+ gboolean in_marshal = closure->in_marshal;
+
+ g_return_if_fail (closure->marshal || real_closure->meta_marshal);
+
+ SET (closure, in_marshal, TRUE);
+ if (real_closure->va_meta_marshal)
+ {
+ marshal_data = real_closure->meta_marshal_data;
+ marshal = real_closure->va_meta_marshal;
+ }
+ else
+ {
+ marshal_data = NULL;
+ marshal = real_closure->va_marshal;
+ }
+ if (!in_marshal)
+ closure_invoke_notifiers (closure, PRE_NOTIFY);
+ marshal (closure,
+ return_value,
+ instance, args,
+ marshal_data,
+ n_params, param_types);
+ if (!in_marshal)
+ closure_invoke_notifiers (closure, POST_NOTIFY);
+ SET (closure, in_marshal, in_marshal);
+ }
+ g_closure_unref (closure);
+}
+
+
/**
* g_closure_set_marshal: (skip)
* @closure: a #GClosure
@@ -794,6 +876,24 @@ g_closure_set_marshal (GClosure *closure,
closure->marshal = marshal;
}
+void
+_g_closure_set_va_marshal (GClosure *closure,
+ GVaClosureMarshal marshal)
+{
+ GRealClosure *real_closure;
+
+ g_return_if_fail (closure != NULL);
+ g_return_if_fail (marshal != NULL);
+
+ real_closure = G_REAL_CLOSURE (closure);
+
+ if (real_closure->va_marshal && real_closure->va_marshal != marshal)
+ g_warning ("attempt to override closure->va_marshal (%p) with new marshal (%p)",
+ real_closure->va_marshal, marshal);
+ else
+ real_closure->va_marshal = marshal;
+}
+
/**
* g_cclosure_new: (skip)
* @callback_func: the function to invoke
@@ -875,6 +975,34 @@ g_type_class_meta_marshal (GClosure *closure,
}
static void
+g_type_class_meta_marshalv (GClosure *closure,
+ GValue *return_value,
+ gpointer instance,
+ va_list args,
+ gpointer marshal_data,
+ int n_params,
+ GType *param_types)
+{
+ GRealClosure *real_closure;
+ GTypeClass *class;
+ gpointer callback;
+ /* GType itype = (GType) closure->data; */
+ guint offset = GPOINTER_TO_UINT (marshal_data);
+
+ real_closure = G_REAL_CLOSURE (closure);
+
+ class = G_TYPE_INSTANCE_GET_CLASS (instance, itype, GTypeClass);
+ callback = G_STRUCT_MEMBER (gpointer, class, offset);
+ if (callback)
+ real_closure->va_marshal (closure,
+ return_value,
+ instance, args,
+ callback,
+ n_params,
+ param_types);
+}
+
+static void
g_type_iface_meta_marshal (GClosure *closure,
GValue /*out*/ *return_value,
guint n_param_values,
@@ -897,6 +1025,34 @@ g_type_iface_meta_marshal (GClosure *closure,
callback);
}
+static void
+g_type_iface_meta_marshalv (GClosure *closure,
+ GValue *return_value,
+ gpointer instance,
+ va_list args,
+ gpointer marshal_data,
+ int n_params,
+ GType *param_types)
+{
+ GRealClosure *real_closure;
+ GTypeClass *class;
+ gpointer callback;
+ GType itype = (GType) closure->data;
+ guint offset = GPOINTER_TO_UINT (marshal_data);
+
+ real_closure = G_REAL_CLOSURE (closure);
+
+ class = G_TYPE_INSTANCE_GET_INTERFACE (instance, itype, GTypeClass);
+ callback = G_STRUCT_MEMBER (gpointer, class, offset);
+ if (callback)
+ real_closure->va_marshal (closure,
+ return_value,
+ instance, args,
+ callback,
+ n_params,
+ param_types);
+}
+
/**
* g_signal_type_cclosure_new:
* @itype: the #GType identifier of an interface or classed type
@@ -920,10 +1076,15 @@ g_signal_type_cclosure_new (GType itype,
closure = g_closure_new_simple (sizeof (GClosure), (gpointer) itype);
if (G_TYPE_IS_INTERFACE (itype))
- g_closure_set_meta_marshal (closure, GUINT_TO_POINTER (struct_offset), g_type_iface_meta_marshal);
+ {
+ g_closure_set_meta_marshal (closure, GUINT_TO_POINTER (struct_offset), g_type_iface_meta_marshal);
+ g_closure_set_meta_va_marshal (closure, g_type_iface_meta_marshalv);
+ }
else
- g_closure_set_meta_marshal (closure, GUINT_TO_POINTER (struct_offset), g_type_class_meta_marshal);
-
+ {
+ g_closure_set_meta_marshal (closure, GUINT_TO_POINTER (struct_offset), g_type_class_meta_marshal);
+ g_closure_set_meta_va_marshal (closure, g_type_class_meta_marshalv);
+ }
return closure;
}
@@ -1081,6 +1242,86 @@ value_from_ffi_type (GValue *gvalue, gpointer *value)
}
}
+typedef union {
+ gpointer _gpointer;
+ float _float;
+ double _double;
+ gint _gint;
+ guint _guint;
+ glong _glong;
+ gulong _gulong;
+ gint64 _gint64;
+ guint64 _guint64;
+} va_arg_storage;
+
+static ffi_type *
+va_to_ffi_type (GType gtype,
+ va_list *va,
+ va_arg_storage *storage)
+{
+ ffi_type *rettype = NULL;
+ GType type = g_type_fundamental (gtype);
+ g_assert (type != G_TYPE_INVALID);
+
+ switch (type)
+ {
+ case G_TYPE_BOOLEAN:
+ case G_TYPE_CHAR:
+ case G_TYPE_INT:
+ case G_TYPE_ENUM:
+ rettype = &ffi_type_sint;
+ storage->_gint = va_arg (*va, gint);
+ break;
+ case G_TYPE_UCHAR:
+ case G_TYPE_UINT:
+ case G_TYPE_FLAGS:
+ rettype = &ffi_type_uint;
+ storage->_guint = va_arg (*va, guint);
+ break;
+ case G_TYPE_STRING:
+ case G_TYPE_OBJECT:
+ case G_TYPE_BOXED:
+ case G_TYPE_PARAM:
+ case G_TYPE_POINTER:
+ case G_TYPE_INTERFACE:
+ case G_TYPE_VARIANT:
+ rettype = &ffi_type_pointer;
+ storage->_gpointer = va_arg (*va, gpointer);
+ break;
+ case G_TYPE_FLOAT:
+ /* Float args are passed as doubles in varargs */
+ rettype = &ffi_type_float;
+ storage->_float = (float)va_arg (*va, double);
+ break;
+ case G_TYPE_DOUBLE:
+ rettype = &ffi_type_double;
+ storage->_double = va_arg (*va, double);
+ break;
+ case G_TYPE_LONG:
+ rettype = &ffi_type_slong;
+ storage->_glong = va_arg (*va, glong);
+ break;
+ case G_TYPE_ULONG:
+ rettype = &ffi_type_ulong;
+ storage->_gulong = va_arg (*va, gulong);
+ break;
+ case G_TYPE_INT64:
+ rettype = &ffi_type_sint64;
+ storage->_gint64 = va_arg (*va, gint64);
+ break;
+ case G_TYPE_UINT64:
+ rettype = &ffi_type_uint64;
+ storage->_guint64 = va_arg (*va, guint64);
+ break;
+ default:
+ rettype = &ffi_type_pointer;
+ storage->_guint64 = 0;
+ g_warning ("va_to_ffi_type: Unsupported fundamental type: %s", g_type_name (type));
+ break;
+ }
+ return rettype;
+}
+
/**
* g_cclosure_marshal_generic:
* @closure: A #GClosure.
@@ -1177,6 +1418,123 @@ g_cclosure_marshal_generic (GClosure *closure,
value_from_ffi_type (return_gvalue, rvalue);
}
+void
+g_cclosure_marshal_generic_va (GClosure *closure,
+ GValue *return_value,
+ gpointer instance,
+ va_list args_list,
+ gpointer marshal_data,
+ int n_params,
+ GType *param_types)
+{
+ ffi_type *rtype;
+ void *rvalue;
+ int n_args;
+ ffi_type **atypes;
+ void **args;
+ va_arg_storage *storage;
+ int i;
+ ffi_cif cif;
+ GCClosure *cc = (GCClosure*) closure;
+ gint *enum_tmpval;
+ gboolean tmpval_used = FALSE;
+ va_list args_copy;
+
+ enum_tmpval = g_alloca (sizeof (gint));
+ if (return_value && G_VALUE_TYPE (return_value))
+ {
+ rtype = value_to_ffi_type (return_value, &rvalue, enum_tmpval, &tmpval_used);
+ }
+ else
+ {
+ rtype = &ffi_type_void;
+ }
+
+ rvalue = g_alloca (MAX (rtype->size, sizeof (ffi_arg)));
+
+ n_args = n_params + 2;
+ atypes = g_alloca (sizeof (ffi_type *) * n_args);
+ args = g_alloca (sizeof (gpointer) * n_args);
+ storage = g_alloca (sizeof (va_arg_storage) * n_params);
+
+ if (tmpval_used)
+ enum_tmpval = g_alloca (sizeof (gint));
+
+ if (G_CCLOSURE_SWAP_DATA (closure))
+ {
+ atypes[n_args-1] = &ffi_type_pointer;
+ args[n_args-1] = &instance;
+ atypes[0] = &ffi_type_pointer;
+ args[0] = &closure->data;
+ }
+ else
+ {
+ atypes[0] = &ffi_type_pointer;
+ args[0] = &instance;
+ atypes[n_args-1] = &ffi_type_pointer;
+ args[n_args-1] = &closure->data;
+ }
+
+ va_copy (args_copy, args_list);
+
+ /* Box non-primitive arguments */
+ for (i = 0; i < n_params; i++)
+ {
+ GType type = param_types[i] & ~G_SIGNAL_TYPE_STATIC_SCOPE;
+ GType fundamental = G_TYPE_FUNDAMENTAL (type);
+
+ atypes[i+1] = va_to_ffi_type (type,
+ &args_copy,
+ &storage[i]);
+ args[i+1] = &storage[i];
+
+ if ((param_types[i] & G_SIGNAL_TYPE_STATIC_SCOPE) == 0)
+ {
+ if (fundamental == G_TYPE_STRING && storage[i]._gpointer != NULL)
+ storage[i]._gpointer = g_strdup (storage[i]._gpointer);
+ else if (fundamental == G_TYPE_PARAM && storage[i]._gpointer != NULL)
+ storage[i]._gpointer = g_param_spec_ref (storage[i]._gpointer);
+ else if (fundamental == G_TYPE_BOXED && storage[i]._gpointer != NULL)
+ storage[i]._gpointer = g_boxed_copy (type, storage[i]._gpointer);
+ else if (fundamental == G_TYPE_VARIANT && storage[i]._gpointer != NULL)
+ storage[i]._gpointer = g_variant_ref_sink (storage[i]._gpointer);
+ }
+ if (fundamental == G_TYPE_OBJECT && storage[i]._gpointer != NULL)
+ storage[i]._gpointer = g_object_ref (storage[i]._gpointer);
+ }
+
+ va_end (args_copy);
+
+ 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);
+
+ /* Unbox non-primitive arguments */
+ for (i = 0; i < n_params; i++)
+ {
+ GType type = param_types[i] & ~G_SIGNAL_TYPE_STATIC_SCOPE;
+ GType fundamental = G_TYPE_FUNDAMENTAL (type);
+
+ if ((param_types[i] & G_SIGNAL_TYPE_STATIC_SCOPE) == 0)
+ {
+ if (fundamental == G_TYPE_STRING && storage[i]._gpointer != NULL)
+ g_free (storage[i]._gpointer);
+ else if (fundamental == G_TYPE_PARAM && storage[i]._gpointer != NULL)
+ g_param_spec_unref (storage[i]._gpointer);
+ else if (fundamental == G_TYPE_BOXED && storage[i]._gpointer != NULL)
+ g_boxed_free (type, storage[i]._gpointer);
+ else if (fundamental == G_TYPE_VARIANT && storage[i]._gpointer != NULL)
+ g_variant_unref (storage[i]._gpointer);
+ }
+ if (fundamental == G_TYPE_OBJECT && storage[i]._gpointer != NULL)
+ g_object_unref (storage[i]._gpointer);
+ }
+
+ if (return_value && G_VALUE_TYPE (return_value))
+ value_from_ffi_type (return_value, rvalue);
+}
+
/**
* g_cclosure_marshal_VOID__VOID:
* @closure: the #GClosure to which the marshaller belongs
diff --git a/gobject/gclosure.h b/gobject/gclosure.h
index 69a584d..fffac58 100644
--- a/gobject/gclosure.h
+++ b/gobject/gclosure.h
@@ -120,6 +120,15 @@ typedef void (*GClosureMarshal) (GClosure *closure,
const GValue *param_values,
gpointer invocation_hint,
gpointer marshal_data);
+
+typedef void (* GVaClosureMarshal) (GClosure *closure,
+ GValue *return_value,
+ gpointer instance,
+ va_list args,
+ gpointer marshal_data,
+ int n_params,
+ GType *param_types);
+
/**
* GCClosure:
* @closure: the #GClosure
@@ -258,6 +267,15 @@ void g_cclosure_marshal_generic (GClosure *closure,
gpointer invocation_hint,
gpointer marshal_data);
+void g_cclosure_marshal_generic_va (GClosure *closure,
+ GValue *return_value,
+ gpointer instance,
+ va_list args_list,
+ gpointer marshal_data,
+ int n_params,
+ GType *param_types);
+
+
G_END_DECLS
#endif /* __G_CLOSURE_H__ */
diff --git a/gobject/gtype-private.h b/gobject/gtype-private.h
index bccc9a6..9cbea77 100644
--- a/gobject/gtype-private.h
+++ b/gobject/gtype-private.h
@@ -33,6 +33,8 @@ struct _GRealClosure
{
GClosureMarshal meta_marshal;
gpointer meta_marshal_data;
+ GVaClosureMarshal va_meta_marshal;
+ GVaClosureMarshal va_marshal;
GClosure closure;
};
@@ -58,6 +60,17 @@ void _g_type_boxed_init (GType type,
GBoxedCopyFunc copy_func,
GBoxedFreeFunc free_func);
+gboolean _g_closure_supports_invoke_va (GClosure *closure);
+void _g_closure_set_va_marshal (GClosure *closure,
+ GVaClosureMarshal marshal);
+void _g_closure_invoke_va (GClosure *closure,
+ GValue /*out*/ *return_value,
+ gpointer instance,
+ va_list args,
+ int n_params,
+ GType *param_types);
+
+
G_END_DECLS
#endif /* __G_TYPE_PRIVATE_H__ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]