summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--girepository/gicallableinfo.c103
-rw-r--r--girepository/ginvoke.c142
2 files changed, 203 insertions, 42 deletions
diff --git a/girepository/gicallableinfo.c b/girepository/gicallableinfo.c
index 28043fa5..fec77b82 100644
--- a/girepository/gicallableinfo.c
+++ b/girepository/gicallableinfo.c
@@ -360,6 +360,79 @@ g_callable_info_iterate_return_attributes (GICallableInfo *info,
return TRUE;
}
+/* Extract the correct bits from an ffi_arg return value into
+ * GIArgument: https://bugzilla.gnome.org/show_bug.cgi?id=665152
+ *
+ * Also see the ffi_call man page - the storage requirements for return
+ * values are "special".
+ */
+typedef GIArgument GIFFIReturnValue;
+
+static void
+set_gargument_from_ffi_return_value (GITypeInfo *return_info,
+ GIArgument *arg,
+ GIFFIReturnValue *ffi_value)
+{
+ switch (g_type_info_get_tag (return_info)) {
+ case GI_TYPE_TAG_INT8:
+ arg->v_int8 = (gint8) ffi_value->v_long;
+ break;
+ case GI_TYPE_TAG_UINT8:
+ arg->v_uint8 = (guint8) ffi_value->v_ulong;
+ break;
+ case GI_TYPE_TAG_INT16:
+ arg->v_int16 = (gint16) ffi_value->v_long;
+ break;
+ case GI_TYPE_TAG_UINT16:
+ arg->v_uint16 = (guint16) ffi_value->v_ulong;
+ break;
+ case GI_TYPE_TAG_INT32:
+ arg->v_int32 = (gint32) ffi_value->v_long;
+ break;
+ case GI_TYPE_TAG_UINT32:
+ case GI_TYPE_TAG_BOOLEAN:
+ case GI_TYPE_TAG_UNICHAR:
+ arg->v_uint32 = (guint32) ffi_value->v_ulong;
+ break;
+ case GI_TYPE_TAG_INT64:
+ arg->v_int64 = (gint64) ffi_value->v_int64;
+ break;
+ case GI_TYPE_TAG_UINT64:
+ arg->v_uint64 = (guint64) ffi_value->v_uint64;
+ break;
+ case GI_TYPE_TAG_FLOAT:
+ arg->v_float = ffi_value->v_float;
+ break;
+ case GI_TYPE_TAG_DOUBLE:
+ arg->v_double = ffi_value->v_double;
+ break;
+ case GI_TYPE_TAG_INTERFACE:
+ {
+ GIBaseInfo* interface_info;
+ GIInfoType interface_type;
+
+ interface_info = g_type_info_get_interface(return_info);
+ interface_type = g_base_info_get_type(interface_info);
+
+ switch(interface_type) {
+ case GI_INFO_TYPE_ENUM:
+ case GI_INFO_TYPE_FLAGS:
+ arg->v_int32 = (gint32) ffi_value->v_long;
+ break;
+ default:
+ arg->v_pointer = (gpointer) ffi_value->v_ulong;
+ break;
+ }
+
+ g_base_info_unref(interface_info);
+ }
+ break;
+ default:
+ arg->v_pointer = (gpointer) ffi_value->v_ulong;
+ break;
+ }
+}
+
gboolean
_g_callable_info_invoke (GIFunctionInfo *info,
gpointer function,
@@ -376,16 +449,20 @@ _g_callable_info_invoke (GIFunctionInfo *info,
ffi_type *rtype;
ffi_type **atypes;
GITypeInfo *tinfo;
+ GITypeInfo *rinfo;
+ GITypeTag rtag;
GIArgInfo *ainfo;
gint n_args, n_invoke_args, in_pos, out_pos, i;
gpointer *args;
gboolean success = FALSE;
GError *local_error = NULL;
gpointer error_address = &local_error;
+ GIFFIReturnValue ffi_return_value;
+ gpointer return_value_p; /* Will point inside the union return_value */
- tinfo = g_callable_info_get_return_type ((GICallableInfo *)info);
- rtype = g_type_info_get_ffi_type (tinfo);
- g_base_info_unref ((GIBaseInfo *)tinfo);
+ rinfo = g_callable_info_get_return_type ((GICallableInfo *)info);
+ rtype = g_type_info_get_ffi_type (rinfo);
+ rtag = g_type_info_get_tag(rinfo);
in_pos = 0;
out_pos = 0;
@@ -516,7 +593,23 @@ _g_callable_info_invoke (GIFunctionInfo *info,
goto out;
g_return_val_if_fail (return_value, FALSE);
- ffi_call (&cif, function, return_value, args);
+ /* See comment for GIFFIReturnValue above */
+ switch (rtag)
+ {
+ case GI_TYPE_TAG_FLOAT:
+ return_value_p = &ffi_return_value.v_float;
+ break;
+ case GI_TYPE_TAG_DOUBLE:
+ return_value_p = &ffi_return_value.v_double;
+ break;
+ case GI_TYPE_TAG_INT64:
+ case GI_TYPE_TAG_UINT64:
+ return_value_p = &ffi_return_value.v_uint64;
+ break;
+ default:
+ return_value_p = &ffi_return_value.v_long;
+ }
+ ffi_call (&cif, function, return_value_p, args);
if (local_error)
{
@@ -525,8 +618,10 @@ _g_callable_info_invoke (GIFunctionInfo *info,
}
else
{
+ set_gargument_from_ffi_return_value(rinfo, return_value, &ffi_return_value);
success = TRUE;
}
out:
+ g_base_info_unref ((GIBaseInfo *)rinfo);
return success;
}
diff --git a/girepository/ginvoke.c b/girepository/ginvoke.c
index 84e1e748..581956a3 100644
--- a/girepository/ginvoke.c
+++ b/girepository/ginvoke.c
@@ -88,57 +88,121 @@ value_to_ffi_type (const GValue *gvalue, gpointer *value)
return rettype;
}
+/* See comment aboe set_gargument_from_ffi_return_value() */
+static ffi_type *
+g_value_to_ffi_return_type (const GValue *gvalue,
+ const GIArgument *ffi_value,
+ gpointer *value)
+{
+ ffi_type *rettype = NULL;
+ GType type = g_type_fundamental (G_VALUE_TYPE (gvalue));
+ g_assert (type != G_TYPE_INVALID);
+
+ *value = (gpointer)&(ffi_value->v_long);
+
+ switch (type) {
+ case G_TYPE_CHAR:
+ rettype = &ffi_type_sint8;
+ break;
+ case G_TYPE_UCHAR:
+ rettype = &ffi_type_uint8;
+ break;
+ case G_TYPE_BOOLEAN:
+ case G_TYPE_INT:
+ rettype = &ffi_type_sint;
+ break;
+ case G_TYPE_UINT:
+ rettype = &ffi_type_uint;
+ break;
+ case G_TYPE_STRING:
+ case G_TYPE_OBJECT:
+ case G_TYPE_BOXED:
+ case G_TYPE_POINTER:
+ rettype = &ffi_type_pointer;
+ break;
+ case G_TYPE_FLOAT:
+ rettype = &ffi_type_float;
+ *value = (gpointer)&(ffi_value->v_float);
+ break;
+ case G_TYPE_DOUBLE:
+ rettype = &ffi_type_double;
+ *value = (gpointer)&(ffi_value->v_double);
+ break;
+ case G_TYPE_LONG:
+ rettype = &ffi_type_slong;
+ break;
+ case G_TYPE_ULONG:
+ rettype = &ffi_type_ulong;
+ break;
+ case G_TYPE_INT64:
+ rettype = &ffi_type_sint64;
+ *value = (gpointer)&(ffi_value->v_int64);
+ break;
+ case G_TYPE_UINT64:
+ rettype = &ffi_type_uint64;
+ *value = (gpointer)&(ffi_value->v_uint64);
+ break;
+ default:
+ rettype = &ffi_type_pointer;
+ *value = NULL;
+ g_warning ("Unsupported fundamental type: %s", g_type_name (type));
+ break;
+ }
+ return rettype;
+}
+
static void
-value_from_ffi_type (GValue *gvalue, gpointer *value)
+g_value_from_ffi_value (GValue *gvalue,
+ const GIArgument *value)
{
- switch (g_type_fundamental (G_VALUE_TYPE (gvalue)))
- {
- case G_TYPE_INT:
- g_value_set_int (gvalue, *(gint*)value);
+ switch (g_type_fundamental (G_VALUE_TYPE (gvalue))) {
+ case G_TYPE_INT:
+ g_value_set_int (gvalue, (gint)value->v_long);
break;
- case G_TYPE_FLOAT:
- g_value_set_float (gvalue, *(gfloat*)value);
+ case G_TYPE_FLOAT:
+ g_value_set_float (gvalue, (gfloat)value->v_float);
break;
- case G_TYPE_DOUBLE:
- g_value_set_double (gvalue, *(gdouble*)value);
+ case G_TYPE_DOUBLE:
+ g_value_set_double (gvalue, (gdouble)value->v_double);
break;
- case G_TYPE_BOOLEAN:
- g_value_set_boolean (gvalue, *(gboolean*)value);
+ case G_TYPE_BOOLEAN:
+ g_value_set_boolean (gvalue, (gboolean)value->v_long);
break;
- case G_TYPE_STRING:
- g_value_set_string (gvalue, *(gchar**)value);
+ case G_TYPE_STRING:
+ g_value_set_string (gvalue, (gchar*)value->v_pointer);
break;
- case G_TYPE_CHAR:
- g_value_set_char (gvalue, *(gchar*)value);
+ case G_TYPE_CHAR:
+ g_value_set_char (gvalue, (gchar)value->v_long);
break;
- case G_TYPE_UCHAR:
- g_value_set_uchar (gvalue, *(guchar*)value);
+ case G_TYPE_UCHAR:
+ g_value_set_uchar (gvalue, (guchar)value->v_ulong);
break;
- case G_TYPE_UINT:
- g_value_set_uint (gvalue, *(guint*)value);
+ case G_TYPE_UINT:
+ g_value_set_uint (gvalue, (guint)value->v_ulong);
break;
- case G_TYPE_POINTER:
- g_value_set_pointer (gvalue, *(gpointer*)value);
+ case G_TYPE_POINTER:
+ g_value_set_pointer (gvalue, (gpointer)value->v_pointer);
break;
- case G_TYPE_LONG:
- g_value_set_long (gvalue, *(glong*)value);
+ case G_TYPE_LONG:
+ g_value_set_long (gvalue, (glong)value->v_long);
break;
- case G_TYPE_ULONG:
- g_value_set_ulong (gvalue, *(gulong*)value);
+ case G_TYPE_ULONG:
+ g_value_set_ulong (gvalue, (gulong)value->v_ulong);
break;
- case G_TYPE_INT64:
- g_value_set_int64 (gvalue, *(gint64*)value);
+ case G_TYPE_INT64:
+ g_value_set_int64 (gvalue, (gint64)value->v_int64);
break;
- case G_TYPE_UINT64:
- g_value_set_uint64 (gvalue, *(guint64*)value);
+ case G_TYPE_UINT64:
+ g_value_set_uint64 (gvalue, (guint64)value->v_uint64);
break;
- case G_TYPE_BOXED:
- g_value_set_boxed (gvalue, *(gpointer*)value);
+ case G_TYPE_BOXED:
+ g_value_set_boxed (gvalue, (gpointer)value->v_pointer);
break;
- default:
- g_warning ("Unsupported fundamental type: %s",
- g_type_name (g_type_fundamental (G_VALUE_TYPE (gvalue))));
- }
+ default:
+ g_warning ("Unsupported fundamental type: %s",
+ g_type_name (g_type_fundamental (G_VALUE_TYPE (gvalue))));
+ }
+
}
void
@@ -149,6 +213,7 @@ gi_cclosure_marshal_generic (GClosure *closure,
gpointer invocation_hint,
gpointer marshal_data)
{
+ GIArgument return_ffi_value;
ffi_type *rtype;
void *rvalue;
int n_args;
@@ -160,15 +225,16 @@ gi_cclosure_marshal_generic (GClosure *closure,
if (return_gvalue && G_VALUE_TYPE (return_gvalue))
{
+ rtype = g_value_to_ffi_return_type (return_gvalue, &return_ffi_value,
+ &rvalue);
rtype = value_to_ffi_type (return_gvalue, &rvalue);
}
else
{
rtype = &ffi_type_void;
+ rvalue = &return_ffi_value.v_long;
}
- 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);
@@ -204,5 +270,5 @@ gi_cclosure_marshal_generic (GClosure *closure,
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_value_from_ffi_value (return_gvalue, &return_ffi_value);
}