glib(win32) without libffi



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 (&param_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]