glib(win32) without libffi
- From: Hans Breuer <hans breuer org>
- To: gtk-devel-list gnome org
- Subject: glib(win32) without libffi
- Date: Sat, 28 Jul 2012 11:55:21 +0200
One of the showstoppers for the win32/msvc build of GLib since 2.29 is the
dependency to libffi, which barely builds with msvc. In fact I was not able
to produce any working version with/for msvc6 (finally clashing runtime
versions).
But the current usage of libffi is limited to just two functions, namely
g_cclosure_marshal_generic() and g_cclosure_marshal_generic_va().
Rewriting these functions for the !HAVE_FFI_H case was relatively easy.
And besides nine lines of inline assembly the code should even be be quite
portable.
The nice unit test gobject/tests/signals.c was a tremendous help in
debugging my code, so it now gives:
D:\Devel\from-git\glib\gobject\tests>signals
/gobject/signals/all-types: OK
/gobject/signals/variant: OK
/gobject/signals/generic-marshaller-1: OK
/gobject/signals/generic-marshaller-2: OK
/gobject/signals/generic-marshaller-enum-return-signed: OK
/gobject/signals/generic-marshaller-enum-return-unsigned: OK
/gobject/signals/generic-marshaller-int-return: OK
/gobject/signals/generic-marshaller-uint-return: OK
/gobject/signals/connect: OK
I've already done some tests with gtk+ master's testgtk and gtk-demo
and could not find any issues caused by my reimplementation of
g_cclosure_marshal_generic(_va). Of course there are other parts missing to
build the whole stack with msvc again, but that's for other mails.
Are there any objections to include the new fallback implementation with
standard GLib?
Thanks,
Hans
-------- Hans "at" Breuer "dot" Org -----------
Tell me what you need, and I'll tell you how to
get along without it. -- Dilbert
diff --git a/gobject/gclosure.c b/gobject/gclosure.c
index c027315..472bda0 100644
--- a/gobject/gclosure.c
+++ b/gobject/gclosure.c
@@ -26,8 +26,6 @@
#include <string.h>
-#include <ffi.h>
-
#include "gclosure.h"
#include "gboxed.h"
#include "gobject.h"
@@ -1124,6 +1122,8 @@ g_signal_type_cclosure_new (GType itype,
return closure;
}
+#ifdef HAVE_FFI_H
+
#include <ffi.h>
static ffi_type *
value_to_ffi_type (const GValue *gvalue,
@@ -1573,6 +1573,387 @@ g_cclosure_marshal_generic_va (GClosure *closure,
if (return_value && G_VALUE_TYPE (return_value))
value_from_ffi_type (return_value, rvalue);
}
+#else /* HAVE_FFI_H */
+
+static gint64
+_invoke_cdecl (gpointer args, gint arg_size, void *adr)
+{
+ /* copy given args, already correctly aligned to the
+ * stack and invoke the given function at 'adr'
+ */
+ __asm {
+ sub esp, arg_size
+ mov eax, esp
+ push arg_size
+ push args
+ push eax
+ call memcpy
+ add esp, 12
+ call adr
+ add esp, arg_size
+ }
+}
+
+static void
+value_from_xx_type (GValue *gvalue, gpointer *value)
+{
+ gint *int_val = (gint *)value;
+
+ switch (g_type_fundamental (G_VALUE_TYPE (gvalue)))
+ {
+ case G_TYPE_INT:
+ g_value_set_int (gvalue, (gint) *int_val);
+ 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) *int_val);
+ break;
+ case G_TYPE_STRING:
+ g_value_set_string (gvalue, *(gchar**)value);
+ break;
+ case G_TYPE_CHAR:
+ g_value_set_schar (gvalue, (gint8) *int_val);
+ break;
+ case G_TYPE_UCHAR:
+ g_value_set_uchar (gvalue, (guchar) *int_val);
+ break;
+ case G_TYPE_UINT:
+ g_value_set_uint (gvalue, (guint) *int_val);
+ break;
+ case G_TYPE_POINTER:
+ g_value_set_pointer (gvalue, *(gpointer*)value);
+ break;
+ case G_TYPE_LONG:
+ g_value_set_long (gvalue, (glong) *int_val);
+ break;
+ case G_TYPE_ULONG:
+ g_value_set_ulong (gvalue, (gulong) *int_val);
+ break;
+ case G_TYPE_INT64:
+ g_value_set_int64 (gvalue, (gint64) *int_val);
+ break;
+ case G_TYPE_UINT64:
+ g_value_set_uint64 (gvalue, (guint64) *int_val);
+ break;
+ case G_TYPE_BOXED:
+ g_value_set_boxed (gvalue, *(gpointer*)value);
+ break;
+ case G_TYPE_ENUM:
+ g_value_set_enum (gvalue, (gint) *int_val);
+ break;
+ case G_TYPE_FLAGS:
+ g_value_set_flags (gvalue, (guint) *int_val);
+ break;
+ case G_TYPE_PARAM:
+ g_value_set_param (gvalue, *(gpointer*)value);
+ break;
+ case G_TYPE_OBJECT:
+ g_value_set_object (gvalue, *(gpointer*)value);
+ break;
+ case G_TYPE_VARIANT:
+ g_value_set_variant (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))));
+ }
+}
+
+void
+g_cclosure_marshal_generic (GClosure *closure,
+ GValue *return_gvalue,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data)
+{
+ GCClosure *cc = (GCClosure*) closure;
+ gpointer args;
+ char *p; /* for parameter alignment on the 'stack' */
+ guint i, n_args = 0;
+ gint64 retval;
+
+ n_args = n_param_values + 1;
+ /* the array is created to be always big enough */
+ p = args = g_alloca (sizeof (gint64) * n_args);
+
+ if (G_CCLOSURE_SWAP_DATA (closure))
+ {
+ *(gpointer*)p = closure->data;
+ p += sizeof(gpointer);
+ }
+ /* pack further arguments */
+ for (i = 0; i < n_args - 1; i++)
+ {
+ GType type = g_type_fundamental (G_VALUE_TYPE (¶m_values[i]));
+ g_assert (type != G_TYPE_INVALID);
+
+ switch (type)
+ {
+ case G_TYPE_BOOLEAN:
+ case G_TYPE_CHAR:
+ case G_TYPE_INT:
+ case G_TYPE_ENUM:
+ *(guint*)p = param_values[i].data[0].v_int;
+ p += sizeof(guint);
+ break;
+ case G_TYPE_UCHAR:
+ case G_TYPE_UINT:
+ case G_TYPE_FLAGS:
+ *(guint*)p = param_values[i].data[0].v_uint;
+ p += sizeof(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:
+ *(gpointer*)p = param_values[i].data[0].v_pointer;
+ p += sizeof(gpointer);
+ break;
+ case G_TYPE_FLOAT:
+ *(float*)p = param_values[i].data[0].v_float;
+ p += sizeof(float);
+ break;
+ case G_TYPE_DOUBLE:
+ *(double*)p = param_values[i].data[0].v_double;
+ p += sizeof(double);
+ break;
+ case G_TYPE_LONG:
+ *(glong*)p = param_values[i].data[0].v_long;
+ p += sizeof(glong);
+ break;
+ case G_TYPE_ULONG:
+ *(gulong*)p = param_values[i].data[0].v_ulong;
+ p += sizeof(gulong);
+ break;
+ case G_TYPE_INT64:
+ *(gint64*)p = param_values[i].data[0].v_int64;
+ p += sizeof(gint64);
+ break;
+ case G_TYPE_UINT64:
+ *(guint64*)p = param_values[i].data[0].v_uint64;
+ p += sizeof(guint64);
+ break;
+ default:
+ *(gpointer*)p = NULL;
+ p += sizeof(gpointer);
+ g_warning (G_STRLOC "Unsupported fundamental type: %s", g_type_name (type));
+ break;
+ }
+ }
+ /* add final data */
+ if (!G_CCLOSURE_SWAP_DATA (closure))
+ {
+ *(gpointer*)p = closure->data;
+ p += sizeof(gpointer);
+ }
+ retval = _invoke_cdecl (args, p - (char*)args, marshal_data ? marshal_data : cc->callback);
+
+ if (return_gvalue && G_VALUE_TYPE (return_gvalue))
+ value_from_xx_type (return_gvalue, (gpointer)&retval);
+}
+
+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)
+{
+ int n_args;
+ gpointer args;
+ char *p; /* for parameter alignment on the 'stack' */
+ int i;
+ GCClosure *cc = (GCClosure*) closure;
+ gint64 retval;
+ va_list args_copy;
+
+ n_args = n_params + 2;
+ p = args = g_alloca (sizeof (gint64) * n_args);
+
+ if (G_CCLOSURE_SWAP_DATA (closure))
+ {
+ *(gpointer*)p = closure->data;
+ p += sizeof(gpointer);
+ }
+ else
+ {
+ *(gpointer*)p = instance;
+ p += sizeof(gpointer);
+ }
+
+ G_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);
+
+ switch (fundamental)
+ {
+ case G_TYPE_BOOLEAN:
+ case G_TYPE_CHAR:
+ case G_TYPE_INT:
+ case G_TYPE_ENUM:
+ *(gint*)p = (gint)va_arg (args_copy, gint);
+ p += sizeof(gint);
+ break;
+ case G_TYPE_UCHAR:
+ case G_TYPE_UINT:
+ case G_TYPE_FLAGS:
+ *(guint*)p = (guint)va_arg (args_copy, guint);
+ p += sizeof(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:
+ *(gpointer*)p = (gpointer)va_arg (args_copy, gpointer);
+ if ((param_types[i] & G_SIGNAL_TYPE_STATIC_SCOPE) == 0 && *(gpointer*)p != NULL)
+ {
+ if (fundamental == G_TYPE_STRING)
+ *(char **)p = g_strdup (*(char **)p);
+ else if (fundamental == G_TYPE_PARAM)
+ *(GParamSpec **)p = g_param_spec_ref (*(GParamSpec **)p);
+ else if (fundamental == G_TYPE_BOXED)
+ *(void **)p = g_boxed_copy (type, *(void **)p);
+ else if (fundamental == G_TYPE_VARIANT)
+ *(GVariant**)p = g_variant_ref_sink (*(GVariant**)p);
+ }
+ if (fundamental == G_TYPE_OBJECT && *(GObject**)p != NULL)
+ *(GObject**)p = g_object_ref (*(GObject**)p);
+ p += sizeof(gpointer);
+ break;
+ case G_TYPE_FLOAT:
+ /* Float args are passed as doubles in varargs */
+ *(float*)p = (float)va_arg (args_copy, double);
+ p += sizeof(float);
+ break;
+ case G_TYPE_DOUBLE:
+ *(double*)p = (double)va_arg (args_copy, double);
+ p += sizeof(double);
+ break;
+ case G_TYPE_LONG:
+ *(glong*)p = (glong)va_arg (args_copy, glong);
+ p += sizeof(glong);
+ break;
+ case G_TYPE_ULONG:
+ *(gulong*)p = (gulong)va_arg (args_copy, gulong);
+ p += sizeof(gulong);
+ break;
+ case G_TYPE_INT64:
+ *(gint64*)p = (gint64)va_arg (args_copy, gint64);
+ p += sizeof(gint64);
+ break;
+ case G_TYPE_UINT64:
+ *(guint64*)p = (guint64)va_arg (args_copy, guint64);
+ p += sizeof(guint64);
+ break;
+ default:
+ *(gpointer**)p = NULL;
+ p += sizeof(gpointer);
+ g_warning (G_STRLOC " va_to_xx_type: Unsupported fundamental type: %s", g_type_name (type));
+ }
+ }
+ va_end (args_copy);
+
+ /* add final data */
+ if (!G_CCLOSURE_SWAP_DATA (closure))
+ {
+ *(gpointer*)p = closure->data;
+ p += sizeof(gpointer);
+ }
+ else
+ {
+ *(gpointer*)p = instance;
+ p += sizeof(gpointer);
+ }
+ retval = _invoke_cdecl (args, p - (char*)args, marshal_data ? marshal_data : cc->callback);
+ /* Unbox non-primitive arguments */
+ p = args;
+ p += sizeof(gpointer);
+
+ for (i = 0; i < n_params; i++)
+ {
+ GType type = param_types[i] & ~G_SIGNAL_TYPE_STATIC_SCOPE;
+ GType fundamental = G_TYPE_FUNDAMENTAL (type);
+
+ switch (fundamental)
+ {
+ case G_TYPE_BOOLEAN:
+ case G_TYPE_CHAR:
+ case G_TYPE_INT:
+ case G_TYPE_ENUM:
+ p += sizeof(gint);
+ break;
+ case G_TYPE_UCHAR:
+ case G_TYPE_UINT:
+ case G_TYPE_FLAGS:
+ p += sizeof(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:
+ if ((param_types[i] & G_SIGNAL_TYPE_STATIC_SCOPE) == 0 && *(gpointer*)p != NULL)
+ {
+ if (fundamental == G_TYPE_STRING)
+ g_free (*(char **)p);
+ else if (fundamental == G_TYPE_PARAM)
+ g_param_spec_unref (*(GParamSpec **)p);
+ else if (fundamental == G_TYPE_BOXED)
+ g_boxed_free (type, *(void **)p);
+ else if (fundamental == G_TYPE_VARIANT)
+ g_variant_unref (*(GVariant**)p);
+ }
+ if (fundamental == G_TYPE_OBJECT && *(GObject**)p != NULL)
+ g_object_unref (*(GObject**)p);
+ p += sizeof(gpointer);
+ break;
+ case G_TYPE_FLOAT:
+ p += sizeof(float);
+ break;
+ case G_TYPE_DOUBLE:
+ p += sizeof(double);
+ break;
+ case G_TYPE_LONG:
+ p += sizeof(glong);
+ break;
+ case G_TYPE_ULONG:
+ p += sizeof(gulong);
+ break;
+ case G_TYPE_INT64:
+ p += sizeof(gint64);
+ break;
+ case G_TYPE_UINT64:
+ p += sizeof(guint64);
+ break;
+ default:
+ p += sizeof(gpointer);
+ g_warning (G_STRLOC "Unsupported fundamental type: %s", g_type_name (type));
+ }
+ }
+ if (return_value && G_VALUE_TYPE (return_value))
+ value_from_xx_type (return_value, (gpointer)&retval);
+}
+#endif /* HAVE_FFI_H */
/**
* g_cclosure_marshal_VOID__VOID:
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]