[perl-Glib-Object-Introspection] Add support for caller-allocated out arguments



commit f174df0cf295fe35000138a9acabebddd6c5810b
Author: Torsten SchÃnfeld <kaffeetisch gmx de>
Date:   Sat Aug 20 19:35:54 2011 +0200

    Add support for caller-allocated out arguments

 GObjectIntrospection.xs |   87 ++++++++++++++++++++++++++++++++++++++++------
 1 files changed, 75 insertions(+), 12 deletions(-)
---
diff --git a/GObjectIntrospection.xs b/GObjectIntrospection.xs
index 368c5dc..580fa96 100644
--- a/GObjectIntrospection.xs
+++ b/GObjectIntrospection.xs
@@ -2245,13 +2245,14 @@ prepare_invocation_info (GPerlI11nInvocationInfo *iinfo,
 	 * we'll only use as much as we need.  since function argument lists
 	 * are typically small, this shouldn't be a big problem. */
 	if (iinfo->n_invoke_args) {
-		iinfo->in_args = gperl_alloc_temp (sizeof (GIArgument) * iinfo->n_invoke_args);
-		iinfo->out_args = gperl_alloc_temp (sizeof (GIArgument) * iinfo->n_invoke_args);
-		iinfo->out_arg_infos = gperl_alloc_temp (sizeof (GITypeInfo*) * iinfo->n_invoke_args);
-		iinfo->arg_types = gperl_alloc_temp (sizeof (ffi_type *) * iinfo->n_invoke_args);
-		iinfo->args = gperl_alloc_temp (sizeof (gpointer) * iinfo->n_invoke_args);
-		iinfo->aux_args = gperl_alloc_temp (sizeof (GIArgument) * iinfo->n_invoke_args);
-		iinfo->is_automatic_arg = gperl_alloc_temp (sizeof (gboolean) * iinfo->n_invoke_args);
+		gint n = iinfo->n_invoke_args;
+		iinfo->in_args = gperl_alloc_temp (sizeof (GIArgument) * n);
+		iinfo->out_args = gperl_alloc_temp (sizeof (GIArgument) * n);
+		iinfo->out_arg_infos = gperl_alloc_temp (sizeof (GITypeInfo*) * n);
+		iinfo->arg_types = gperl_alloc_temp (sizeof (ffi_type *) * n);
+		iinfo->args = gperl_alloc_temp (sizeof (gpointer) * n);
+		iinfo->aux_args = gperl_alloc_temp (sizeof (GIArgument) * n);
+		iinfo->is_automatic_arg = gperl_alloc_temp (sizeof (gboolean) * n);
 	}
 
 	iinfo->method_offset = iinfo->is_method ? 1 : 0;
@@ -2322,6 +2323,52 @@ clear_invocation_info (GPerlI11nInvocationInfo *iinfo)
 
 /* ------------------------------------------------------------------------- */
 
+static gpointer
+allocate_out_mem (GITypeInfo *arg_type)
+{
+	GIBaseInfo *interface_info;
+	GIInfoType type;
+
+	interface_info = g_type_info_get_interface (arg_type);
+	g_assert (interface_info);
+	type = g_base_info_get_type (interface_info);
+	g_base_info_unref (interface_info);
+
+	switch (type) {
+	    case GI_INFO_TYPE_STRUCT:
+	    {
+		gsize size = g_struct_info_get_size (interface_info);
+		return g_malloc0 (size);
+	    }
+	    default:
+		g_assert_not_reached ();
+		return NULL;
+	}
+}
+
+static void
+free_out_mem (GITypeInfo *arg_type, gpointer mem)
+{
+	GIBaseInfo *interface_info;
+	GIInfoType type;
+
+	interface_info = g_type_info_get_interface (arg_type);
+	g_assert (interface_info);
+	type = g_base_info_get_type (interface_info);
+	g_base_info_unref (interface_info);
+
+	switch (type) {
+	    case GI_INFO_TYPE_STRUCT:
+	    {
+		return g_free (mem);
+	    }
+	    default:
+		g_assert_not_reached ();
+	}
+}
+
+/* ------------------------------------------------------------------------- */
+
 MODULE = Glib::Object::Introspection	PACKAGE = Glib::Object::Introspection
 
 void
@@ -2611,14 +2658,13 @@ _invoke (class, basename, namespace, method, ...)
 		 * point. */
 		iinfo.current_pos = i; /* + method_offset; */
 
-		dwarn ("  arg %d, tag: %d (%s), is_automatic: %d\n",
+		dwarn ("  arg %d, tag: %d (%s), is_pointer: %d, is_automatic: %d\n",
 		       i,
 		       g_type_info_get_tag (arg_type),
 		       g_type_tag_to_string (g_type_info_get_tag (arg_type)),
+		       g_type_info_is_pointer (arg_type),
 		       iinfo.is_automatic_arg[i]);
 
-		/* FIXME: Check g_arg_info_is_caller_allocates. */
-
 		/* FIXME: Check that i+method_offset+stack_offset<items before
 		 * calling ST, and generate a usage message otherwise. */
 		switch (g_arg_info_get_direction (arg_info)) {
@@ -2641,10 +2687,17 @@ _invoke (class, basename, namespace, method, ...)
 			break;
 
 		    case GI_DIRECTION_OUT:
-			iinfo.out_args[i].v_pointer = &iinfo.aux_args[i];
+			if (g_arg_info_is_caller_allocates (arg_info)) {
+				iinfo.aux_args[i].v_pointer =
+					allocate_out_mem (arg_type);
+				iinfo.out_args[i].v_pointer = &iinfo.aux_args[i];
+				iinfo.args[ffi_stack_pos] = &iinfo.aux_args[i];
+			} else {
+				iinfo.out_args[i].v_pointer = &iinfo.aux_args[i];
+				iinfo.args[ffi_stack_pos] = &iinfo.out_args[i];
+			}
 			iinfo.out_arg_infos[i] = arg_type;
 			iinfo.arg_types[ffi_stack_pos] = &ffi_type_pointer;
-			iinfo.args[ffi_stack_pos] = &iinfo.out_args[i];
 			/* Adjust the dynamic stack offset so that this out
 			 * argument doesn't inadvertedly eat up an in argument. */
 			iinfo.dynamic_stack_offset--;
@@ -2770,6 +2823,16 @@ _invoke (class, basename, namespace, method, ...)
 				XPUSHs (sv_2mortal (sv));
 				n_return_values++;
 			}
+			/* if we own the thing, then arg_to_sv has already
+			 * taken care of the memory. */
+			if (g_arg_info_is_caller_allocates (arg_info) &&
+			    transfer == GI_TRANSFER_NOTHING)
+			{
+				GITypeInfo *arg_type =
+					g_arg_info_get_type (arg_info);
+				free_out_mem (arg_type, iinfo.aux_args[i].v_pointer);
+				g_base_info_unref (arg_type);
+			}
 			g_base_info_unref ((GIBaseInfo*) iinfo.out_arg_infos[i]);
 			break;
 		    }



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]