[gobject-introspection] Add g_vfunc_info_invoke and g_vfunc_info_get_address



commit 0c3a1d82f2543b74468d1806f87aa0cb258a925d
Author: Tomeu Vizoso <tomeu vizoso collabora co uk>
Date:   Mon Dec 13 13:53:55 2010 +0100

    Add g_vfunc_info_invoke and g_vfunc_info_get_address
    
    for calling the native implementation of a virtual function. Refactors
    the code common with g_function_info_invoke in _g_callable_info_invoke.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=637145

 girepository/gicallableinfo.c       |  172 +++++++++++++++++++++++++++++++++++
 girepository/gifunctioninfo.c       |  167 ++--------------------------------
 girepository/girepository-private.h |   11 ++
 girepository/givfuncinfo.c          |  119 ++++++++++++++++++++++++
 girepository/givfuncinfo.h          |   11 ++
 5 files changed, 323 insertions(+), 157 deletions(-)
---
diff --git a/girepository/gicallableinfo.c b/girepository/gicallableinfo.c
index 6b79e62..1d43968 100644
--- a/girepository/gicallableinfo.c
+++ b/girepository/gicallableinfo.c
@@ -26,6 +26,7 @@
 #include <girepository.h>
 #include "girepository-private.h"
 #include "gitypelib-internal.h"
+#include "girffi.h"
 
 /* GICallableInfo functions */
 
@@ -335,3 +336,174 @@ g_callable_info_iterate_return_attributes (GICallableInfo  *info,
 
   return TRUE;
 }
+
+gboolean
+_g_callable_info_invoke (GIFunctionInfo *info,
+                         gpointer          function,
+                         const GIArgument  *in_args,
+                         int               n_in_args,
+                         const GIArgument  *out_args,
+                         int               n_out_args,
+                         GIArgument        *return_value,
+                         gboolean          is_method,
+                         gboolean          throws,
+                         GError          **error)
+{
+  ffi_cif cif;
+  ffi_type *rtype;
+  ffi_type **atypes;
+  GITypeInfo *tinfo;
+  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;
+
+  tinfo = g_callable_info_get_return_type ((GICallableInfo *)info);
+  rtype = g_type_info_get_ffi_type (tinfo);
+  g_base_info_unref ((GIBaseInfo *)tinfo);
+
+  in_pos = 0;
+  out_pos = 0;
+
+  n_args = g_callable_info_get_n_args ((GICallableInfo *)info);
+  if (is_method)
+    {
+      if (n_in_args == 0)
+        {
+          g_set_error (error,
+                       G_INVOKE_ERROR,
+                       G_INVOKE_ERROR_ARGUMENT_MISMATCH,
+                       "Too few \"in\" arguments (handling this)");
+          goto out;
+        }
+      n_invoke_args = n_args+1;
+      in_pos++;
+    }
+  else
+    n_invoke_args = n_args;
+
+  if (throws)
+    /* Add an argument for the GError */
+    n_invoke_args ++;
+
+  atypes = g_alloca (sizeof (ffi_type*) * n_invoke_args);
+  args = g_alloca (sizeof (gpointer) * n_invoke_args);
+
+  if (is_method)
+    {
+      atypes[0] = &ffi_type_pointer;
+      args[0] = (gpointer) &in_args[0];
+    }
+  for (i = 0; i < n_args; i++)
+    {
+      int offset = (is_method ? 1 : 0);
+      ainfo = g_callable_info_get_arg ((GICallableInfo *)info, i);
+      switch (g_arg_info_get_direction (ainfo))
+        {
+        case GI_DIRECTION_IN:
+          tinfo = g_arg_info_get_type (ainfo);
+          atypes[i+offset] = g_type_info_get_ffi_type (tinfo);
+          g_base_info_unref ((GIBaseInfo *)tinfo);
+
+          if (in_pos >= n_in_args)
+            {
+              g_set_error (error,
+                           G_INVOKE_ERROR,
+                           G_INVOKE_ERROR_ARGUMENT_MISMATCH,
+                           "Too few \"in\" arguments (handling in)");
+              goto out;
+            }
+
+          args[i+offset] = (gpointer)&in_args[in_pos];
+          in_pos++;
+
+          break;
+        case GI_DIRECTION_OUT:
+          atypes[i+offset] = &ffi_type_pointer;
+
+          if (out_pos >= n_out_args)
+            {
+              g_set_error (error,
+                           G_INVOKE_ERROR,
+                           G_INVOKE_ERROR_ARGUMENT_MISMATCH,
+                           "Too few \"out\" arguments (handling out)");
+              goto out;
+            }
+
+          args[i+offset] = (gpointer)&out_args[out_pos];
+          out_pos++;
+          break;
+        case GI_DIRECTION_INOUT:
+          atypes[i+offset] = &ffi_type_pointer;
+
+          if (in_pos >= n_in_args)
+            {
+              g_set_error (error,
+                           G_INVOKE_ERROR,
+                           G_INVOKE_ERROR_ARGUMENT_MISMATCH,
+                           "Too few \"in\" arguments (handling inout)");
+              goto out;
+            }
+
+          if (out_pos >= n_out_args)
+            {
+              g_set_error (error,
+                           G_INVOKE_ERROR,
+                           G_INVOKE_ERROR_ARGUMENT_MISMATCH,
+                           "Too few \"out\" arguments (handling inout)");
+              goto out;
+            }
+
+          args[i+offset] = (gpointer)&in_args[in_pos];
+          in_pos++;
+          out_pos++;
+          break;
+        default:
+          g_assert_not_reached ();
+        }
+      g_base_info_unref ((GIBaseInfo *)ainfo);
+    }
+
+  if (throws)
+    {
+      args[n_invoke_args - 1] = &error_address;
+      atypes[n_invoke_args - 1] = &ffi_type_pointer;
+    }
+
+  if (in_pos < n_in_args)
+    {
+      g_set_error (error,
+                   G_INVOKE_ERROR,
+                   G_INVOKE_ERROR_ARGUMENT_MISMATCH,
+                   "Too many \"in\" arguments (at end)");
+      goto out;
+    }
+  if (out_pos < n_out_args)
+    {
+      g_set_error (error,
+                   G_INVOKE_ERROR,
+                   G_INVOKE_ERROR_ARGUMENT_MISMATCH,
+                   "Too many \"out\" arguments (at end)");
+      goto out;
+    }
+
+  if (ffi_prep_cif (&cif, FFI_DEFAULT_ABI, n_invoke_args, rtype, atypes) != FFI_OK)
+    goto out;
+
+  g_return_val_if_fail (return_value, FALSE);
+  ffi_call (&cif, function, return_value, args);
+
+  if (local_error)
+    {
+      g_propagate_error (error, local_error);
+      success = FALSE;
+    }
+  else
+    {
+      success = TRUE;
+    }
+ out:
+  return success;
+}
diff --git a/girepository/gifunctioninfo.c b/girepository/gifunctioninfo.c
index 2f8920d..2544cc3 100644
--- a/girepository/gifunctioninfo.c
+++ b/girepository/gifunctioninfo.c
@@ -26,7 +26,6 @@
 #include <girepository.h>
 #include "girepository-private.h"
 #include "gitypelib-internal.h"
-#include "girffi.h"
 
 /**
  * SECTION:gifunctioninfo
@@ -249,20 +248,10 @@ g_function_info_invoke (GIFunctionInfo *info,
 			GIArgument        *return_value,
 			GError          **error)
 {
-  ffi_cif cif;
-  ffi_type *rtype;
-  ffi_type **atypes;
   const gchar *symbol;
   gpointer func;
-  GITypeInfo *tinfo;
-  GIArgInfo *ainfo;
   gboolean is_method;
   gboolean throws;
-  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;
 
   symbol = g_function_info_get_symbol (info);
 
@@ -281,150 +270,14 @@ g_function_info_invoke (GIFunctionInfo *info,
     && (g_function_info_get_flags (info) & GI_FUNCTION_IS_CONSTRUCTOR) == 0;
   throws = g_function_info_get_flags (info) & GI_FUNCTION_THROWS;
 
-  tinfo = g_callable_info_get_return_type ((GICallableInfo *)info);
-  rtype = g_type_info_get_ffi_type (tinfo);
-  g_base_info_unref ((GIBaseInfo *)tinfo);
-
-  in_pos = 0;
-  out_pos = 0;
-
-  n_args = g_callable_info_get_n_args ((GICallableInfo *)info);
-  if (is_method)
-    {
-      if (n_in_args == 0)
-	{
-	  g_set_error (error,
-		       G_INVOKE_ERROR,
-		       G_INVOKE_ERROR_ARGUMENT_MISMATCH,
-		       "Too few \"in\" arguments (handling this)");
-	  goto out;
-	}
-      n_invoke_args = n_args+1;
-      in_pos++;
-    }
-  else
-    n_invoke_args = n_args;
-
-  if (throws)
-    /* Add an argument for the GError */
-    n_invoke_args ++;
-
-  atypes = g_alloca (sizeof (ffi_type*) * n_invoke_args);
-  args = g_alloca (sizeof (gpointer) * n_invoke_args);
-
-  if (is_method)
-    {
-      atypes[0] = &ffi_type_pointer;
-      args[0] = (gpointer) &in_args[0];
-    }
-  for (i = 0; i < n_args; i++)
-    {
-      int offset = (is_method ? 1 : 0);
-      ainfo = g_callable_info_get_arg ((GICallableInfo *)info, i);
-      switch (g_arg_info_get_direction (ainfo))
-	{
-	case GI_DIRECTION_IN:
-	  tinfo = g_arg_info_get_type (ainfo);
-	  atypes[i+offset] = g_type_info_get_ffi_type (tinfo);
-	  g_base_info_unref ((GIBaseInfo *)tinfo);
-
-	  if (in_pos >= n_in_args)
-	    {
-	      g_set_error (error,
-			   G_INVOKE_ERROR,
-			   G_INVOKE_ERROR_ARGUMENT_MISMATCH,
-			   "Too few \"in\" arguments (handling in)");
-	      goto out;
-	    }
-
-	  args[i+offset] = (gpointer)&in_args[in_pos];
-	  in_pos++;
-
-	  break;
-	case GI_DIRECTION_OUT:
-	  atypes[i+offset] = &ffi_type_pointer;
-
-	  if (out_pos >= n_out_args)
-	    {
-	      g_set_error (error,
-			   G_INVOKE_ERROR,
-			   G_INVOKE_ERROR_ARGUMENT_MISMATCH,
-			   "Too few \"out\" arguments (handling out)");
-	      goto out;
-	    }
-
-	  args[i+offset] = (gpointer)&out_args[out_pos];
-	  out_pos++;
-	  break;
-	case GI_DIRECTION_INOUT:
-	  atypes[i+offset] = &ffi_type_pointer;
-
-	  if (in_pos >= n_in_args)
-	    {
-	      g_set_error (error,
-			   G_INVOKE_ERROR,
-			   G_INVOKE_ERROR_ARGUMENT_MISMATCH,
-			   "Too few \"in\" arguments (handling inout)");
-	      goto out;
-	    }
-
-	  if (out_pos >= n_out_args)
-	    {
-	      g_set_error (error,
-			   G_INVOKE_ERROR,
-			   G_INVOKE_ERROR_ARGUMENT_MISMATCH,
-			   "Too few \"out\" arguments (handling inout)");
-	      goto out;
-	    }
-
-	  args[i+offset] = (gpointer)&in_args[in_pos];
-	  in_pos++;
-	  out_pos++;
-	  break;
-	default:
-	  g_assert_not_reached ();
-	}
-      g_base_info_unref ((GIBaseInfo *)ainfo);
-    }
-
-  if (throws)
-    {
-      args[n_invoke_args - 1] = &error_address;
-      atypes[n_invoke_args - 1] = &ffi_type_pointer;
-    }
-
-  if (in_pos < n_in_args)
-    {
-      g_set_error (error,
-		   G_INVOKE_ERROR,
-		   G_INVOKE_ERROR_ARGUMENT_MISMATCH,
-		   "Too many \"in\" arguments (at end)");
-      goto out;
-    }
-  if (out_pos < n_out_args)
-    {
-      g_set_error (error,
-		   G_INVOKE_ERROR,
-		   G_INVOKE_ERROR_ARGUMENT_MISMATCH,
-		   "Too many \"out\" arguments (at end)");
-      goto out;
-    }
-
-  if (ffi_prep_cif (&cif, FFI_DEFAULT_ABI, n_invoke_args, rtype, atypes) != FFI_OK)
-    goto out;
-
-  g_return_val_if_fail (return_value, FALSE);
-  ffi_call (&cif, func, return_value, args);
-
-  if (local_error)
-    {
-      g_propagate_error (error, local_error);
-      success = FALSE;
-    }
-  else
-    {
-      success = TRUE;
-    }
- out:
-  return success;
+  return _g_callable_info_invoke ((GICallableInfo*) info,
+                                  func,
+                                  in_args,
+                                  n_in_args,
+                                  out_args,
+                                  n_out_args,
+                                  return_value,
+                                  is_method,
+                                  throws,
+                                  error);
 }
diff --git a/girepository/girepository-private.h b/girepository/girepository-private.h
index 897c52c..52d65b2 100644
--- a/girepository/girepository-private.h
+++ b/girepository/girepository-private.h
@@ -108,6 +108,17 @@ GIVFuncInfo * _g_base_info_find_vfunc (GIRealInfo   *rinfo,
 				       gint          n_vfuncs,
 				       const gchar  *name);
 
+gboolean _g_callable_info_invoke (GICallableInfo   *info,
+                                  gpointer          function,
+                                  const GIArgument *in_args,
+                                  int               n_in_args,
+                                  const GIArgument *out_args,
+                                  int               n_out_args,
+                                  GIArgument       *return_value,
+                                  gboolean          is_method,
+                                  gboolean          throws,
+                                  GError          **error);
+
 extern ffi_status ffi_prep_closure_loc (ffi_closure *,
                                         ffi_cif *,
                                         void (*fun)(ffi_cif *, void *, void **, void *),
diff --git a/girepository/givfuncinfo.c b/girepository/givfuncinfo.c
index 98ac945..332655a 100644
--- a/girepository/givfuncinfo.c
+++ b/girepository/givfuncinfo.c
@@ -196,3 +196,122 @@ g_vfunc_info_get_invoker (GIVFuncInfo *info)
     g_assert_not_reached ();
 }
 
+/**
+ * g_vfunc_info_get_address:
+ * @info: a #GIVFuncInfo
+ * @implementor_gtype: #GType implementing this virtual function
+ * @error: return location for a #GError
+ *
+ * This method will look up where inside the type struct of @implementor_gtype
+ * is the implementation for @info.
+ *
+ * Returns: address to a function or %NULL if an error happened
+ */
+gpointer
+g_vfunc_info_get_address (GIVFuncInfo      *vfunc_info,
+                          GType             implementor_gtype,
+                          GError          **error)
+{
+  GIObjectInfo *object_info;
+  GIStructInfo *struct_info;
+  GIFieldInfo *field_info = NULL;
+  int length, i, offset;
+  gpointer implementor_vtable, func;
+
+  object_info = (GIObjectInfo *) g_base_info_get_container (vfunc_info);
+  struct_info = g_object_info_get_class_struct (object_info);
+
+  length = g_struct_info_get_n_fields (struct_info);
+  for (i = 0; i < length; i++)
+    {
+      field_info = g_struct_info_get_field (struct_info, i);
+
+      if (strcmp (g_base_info_get_name ( (GIBaseInfo*) field_info),
+                  g_base_info_get_name ( (GIBaseInfo*) vfunc_info)) != 0) {
+          g_base_info_unref (field_info);
+          field_info = NULL;
+          continue;
+      }
+
+      break;
+    }
+
+  if (field_info == NULL)
+    {
+      g_set_error (error,
+                   G_INVOKE_ERROR,
+                   G_INVOKE_ERROR_SYMBOL_NOT_FOUND,
+                   "Couldn't find struct field for this vfunc");
+      return NULL;
+    }
+
+  implementor_vtable = g_type_class_ref (implementor_gtype);
+  offset = g_field_info_get_offset (field_info);
+  func = *(gpointer*) G_STRUCT_MEMBER_P (implementor_vtable, offset);
+  g_type_class_unref (implementor_vtable);
+
+  if (func == NULL)
+    {
+      g_set_error (error,
+                   G_INVOKE_ERROR,
+                   G_INVOKE_ERROR_SYMBOL_NOT_FOUND,
+                   "Class %s doesn't implement %s",
+                   g_type_name (implementor_gtype),
+                   g_base_info_get_name ( (GIBaseInfo*) vfunc_info));
+      return NULL;
+    }
+
+  return func;
+}
+
+/**
+ * g_vfunc_info_invoke: (skip)
+ * @info: a #GIVFuncInfo describing the virtual function to invoke
+ * @implementor: #GType of the type that implements this virtual function
+ * @in_args: an array of #GIArgument<!-- -->s, one for each in
+ *    parameter of @info. If there are no in parameter, @in_args
+ *    can be %NULL
+ * @n_in_args: the length of the @in_args array
+ * @out_args: an array of #GIArgument<!-- -->s, one for each out
+ *    parameter of @info. If there are no out parameters, @out_args
+ *    may be %NULL
+ * @n_out_args: the length of the @out_args array
+ * @return_value: return location for the return value of the
+ *    function. If the function returns void, @return_value may be
+ *    %NULL
+ * @error: return location for detailed error information, or %NULL
+ *
+ * Invokes the function described in @info with the given
+ * arguments. Note that inout parameters must appear in both
+ * argument lists.
+ *
+ * Returns: %TRUE if the function has been invoked, %FALSE if an
+ *   error occurred.
+ */
+gboolean
+g_vfunc_info_invoke (GIVFuncInfo      *info,
+                     GType             implementor,
+                     const GIArgument *in_args,
+                     int               n_in_args,
+                     const GIArgument *out_args,
+                     int               n_out_args,
+                     GIArgument       *return_value,
+                     GError          **error)
+{
+  gpointer func;
+
+  func = g_vfunc_info_get_address (info, implementor, error);
+  if (*error != NULL)
+    return FALSE;
+
+  return _g_callable_info_invoke ((GICallableInfo*) info,
+                                  func,
+                                  in_args,
+                                  n_in_args,
+                                  out_args,
+                                  n_out_args,
+                                  return_value,
+                                  TRUE,
+                                  FALSE,
+                                  error);
+}
diff --git a/girepository/givfuncinfo.h b/girepository/givfuncinfo.h
index 6629cad..3c556cb 100644
--- a/girepository/givfuncinfo.h
+++ b/girepository/givfuncinfo.h
@@ -37,6 +37,17 @@ GIVFuncInfoFlags  g_vfunc_info_get_flags   (GIVFuncInfo *info);
 gint              g_vfunc_info_get_offset  (GIVFuncInfo *info);
 GISignalInfo *    g_vfunc_info_get_signal  (GIVFuncInfo *info);
 GIFunctionInfo *  g_vfunc_info_get_invoker (GIVFuncInfo *info);
+gpointer          g_vfunc_info_get_address (GIVFuncInfo *info,
+                                            GType        implementor_gtype,
+                                            GError     **error);
+gboolean          g_vfunc_info_invoke      (GIVFuncInfo      *info,
+                                            GType             implementor,
+                                            const GIArgument *in_args,
+                                            int               n_in_args,
+                                            const GIArgument *out_args,
+                                            int               n_out_args,
+                                            GIArgument       *return_value,
+                                            GError          **error);
 
 G_END_DECLS
 



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