Index: ChangeLog
===================================================================
--- ChangeLog	(revision 861)
+++ ChangeLog	(working copy)
@@ -1,3 +1,9 @@
+2008-11-03  Philip Van Hoof  <philip@codeminded.be>
+
+	* girepository/ginfo.c: 
+	* girepository/ginfo-priv.h:
+	* girepository/ginvoke.c: Caching the ffi_cifs in GIFunctionInfo
+
 2008-11-01  Owen Taylor  <otaylor@redhat.com>
 
 	Bug 558848 giparser.py: shared library should be optional
Index: girepository/ginvoke.c
===================================================================
--- girepository/ginvoke.c	(revision 861)
+++ girepository/ginvoke.c	(working copy)
@@ -25,8 +25,10 @@
 
 #include "girepository.h"
 #include "gtypelib.h"
+#include "ginfo-priv.h"
 #include "config.h"
 
+
 GQuark
 g_invoke_error_quark (void)
 {
@@ -36,7 +38,6 @@
   return quark;
 }
 
-#include "ffi.h"
 
 static ffi_type *
 get_ffi_type (GITypeInfo *info)
@@ -151,7 +152,6 @@
 			GArgument        *return_value,
 			GError          **error)
 {
-  ffi_cif cif;
   ffi_type *rtype;
   ffi_type **atypes;
   const gchar *symbol;
@@ -162,7 +162,7 @@
   gboolean throws;
   gint n_args, n_invoke_args, in_pos, out_pos, i;
   gpointer *args;
-  gboolean success = FALSE;
+  gboolean success = FALSE, calc_cif = FALSE;
   GError *local_error;
 
   symbol = g_function_info_get_symbol (info);
@@ -182,10 +182,6 @@
     && (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 = get_ffi_type (tinfo);
-  g_base_info_unref ((GIBaseInfo *)tinfo);
-
   in_pos = 0;
   out_pos = 0;
 
@@ -210,14 +206,34 @@
     /* Add an argument for the GError */
     n_invoke_args ++;
 
-  atypes = g_alloca (sizeof (ffi_type*) * n_invoke_args);
+  /* We alloc with g_new0, so in case of 0 we just don't know if we have to 
+   * recreate or not the cif (g_info_new). In that case we always recreate it */
+
+  if (n_args == 0 || ((GIBaseInfo *)info)->cif.nargs != (unsigned int) n_args) 
+    {
+      /* We only need rtype once, being in this case */
+      tinfo = g_callable_info_get_return_type ((GICallableInfo *)info);
+      rtype = get_ffi_type (tinfo);
+      g_base_info_unref ((GIBaseInfo *)tinfo);
+
+      /* The types array. We only need this once, being in this case
+       * We clean this up at g_base_info_unref in ginfo.c */
+      atypes = g_malloc (sizeof (ffi_type*) * n_invoke_args); 
+
+      calc_cif = TRUE;
+    }
+
+  /* The values array */
   args = g_alloca (sizeof (gpointer) * n_invoke_args);
-  
+
   if (is_method)
     {
-      atypes[0] = &ffi_type_pointer;
+      if (calc_cif)
+        atypes[0] = &ffi_type_pointer;
+
       args[0] = (gpointer) &in_args[0];
     }
+
   for (i = 0; i < n_args; i++)
     {
       int offset = (is_method ? 1 : 0);
@@ -225,10 +241,14 @@
       switch (g_arg_info_get_direction (ainfo))
 	{
 	case GI_DIRECTION_IN:
-	  tinfo = g_arg_info_get_type (ainfo);
-	  atypes[i+offset] = get_ffi_type (tinfo);
-	  g_base_info_unref ((GIBaseInfo *)tinfo);
 
+	  if (calc_cif)
+	    {
+	      tinfo = g_arg_info_get_type (ainfo);
+	      atypes[i+offset] = get_ffi_type (tinfo);
+	      g_base_info_unref ((GIBaseInfo *)tinfo);
+	    }
+
 	  if (in_pos >= n_in_args)
 	    {
 	      g_set_error (error,
@@ -243,8 +263,10 @@
 	  
 	  break;
 	case GI_DIRECTION_OUT:
-	  atypes[i+offset] = &ffi_type_pointer;
 
+	  if (calc_cif)
+	    atypes[i+offset] = &ffi_type_pointer;
+
 	  if (out_pos >= n_out_args)
 	    {
 	      g_set_error (error,
@@ -258,8 +280,10 @@
 	  out_pos++;	  
 	  break;
 	case GI_DIRECTION_INOUT:
-	  atypes[i+offset] = &ffi_type_pointer;
 
+	  if (calc_cif)
+	    atypes[i+offset] = &ffi_type_pointer;
+
 	  if (in_pos >= n_in_args)
 	    {
 	      g_set_error (error,
@@ -293,7 +317,9 @@
     {
       gpointer address = &local_error;
       args[n_invoke_args - 1] = &address;
-      atypes[n_invoke_args - 1] = &ffi_type_pointer;
+
+      if (calc_cif)
+        atypes[n_invoke_args - 1] = &ffi_type_pointer;
     }
 
   if (in_pos < n_in_args)
@@ -313,11 +339,19 @@
       goto out;
     }
 
-  if (ffi_prep_cif (&cif, FFI_DEFAULT_ABI, n_invoke_args, rtype, atypes) != FFI_OK)
-    goto out;
+  if (calc_cif)
+    {
+      /* This copies the ptr atypes to cif.arg_types, which we free at 
+       * g_base_info_unref in ginfo.c. atypes is a ptr to heap allocation.
+       * See above for the malloc. */
 
-  ffi_call (&cif, func, return_value, args);
+      if (ffi_prep_cif (&(((GIBaseInfo *)info)->cif), FFI_DEFAULT_ABI, 
+                        n_invoke_args, rtype, atypes) != FFI_OK)
+         goto out;
+    } 
 
+  ffi_call (&(((GIBaseInfo *)info)->cif), func, return_value, args);
+
   if (local_error)
     {
       g_propagate_error (error, local_error);
@@ -330,3 +364,4 @@
  out:
   return success;
 }
+
Index: girepository/ginfo.c
===================================================================
--- girepository/ginfo.c	(revision 861)
+++ girepository/ginfo.c	(working copy)
@@ -27,16 +27,8 @@
 #include "girepository.h"
 #include "gtypelib.h"
 
-struct _GIBaseInfo 
-{
-  gint type;
-  gint ref_count;
-  GIBaseInfo *container;
+#include "ginfo-priv.h"
 
-  GTypelib *typelib;
-  guint32 offset;
-};
-
 struct _GIUnresolvedInfo
 {
   gint type;
@@ -47,16 +39,6 @@
   const gchar *namespace;
 };
 
-struct _GICallableInfo
-{
-  GIBaseInfo base;
-};
-
-struct _GIFunctionInfo
-{
-  GICallableInfo callable;
-};
-
 struct _GICallbackInfo
 {
   GICallableInfo callable;
@@ -149,6 +131,7 @@
 
   info->typelib = typelib;
   info->offset = offset;
+  info->cif.arg_types = NULL;
 
   if (container)
     info->container = g_base_info_ref (container);
@@ -213,6 +196,12 @@
       if (info->container)
 	g_base_info_unref (info->container);
 
+      /* Only for a GIFunctionInfo which once got g_function_info_invoke'd
+       * will this be non-NULL. When we didn't use stack for atypes we made
+       * ffi_prep_cif() copy its to-heap pointer to cif.arg_types. */
+
+      g_free (info->cif.arg_types);
+
       g_free (info);
     }
 }
Index: girepository/ginfo-priv.h
===================================================================
--- girepository/ginfo-priv.h	(revision 0)
+++ girepository/ginfo-priv.h	(revision 0)
@@ -0,0 +1,51 @@
+/* GObject introspection: Repository
+ *
+ * Copyright (C) 2008 Philip Van Hoof
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __G_INFO_PRIV_H__
+#define __G_INFO_PRIV_H__
+
+#include "ffi.h"
+
+/* baseinfo and unresolvedinfo have to yield the same sizeof() in order for the
+ * crazy code at g_info_from_entry to work with gslice. */
+
+struct _GIBaseInfo 
+{
+  gint type;
+  gint ref_count;
+  GIBaseInfo *container;
+
+  GTypelib *typelib;
+  guint32 offset;
+  ffi_cif cif;
+};
+
+struct _GICallableInfo
+{
+  GIBaseInfo base;
+};
+
+struct _GIFunctionInfo
+{
+  GICallableInfo callable;
+};
+
+#endif
+
Index: tests/invoke/invoke.c
===================================================================
--- tests/invoke/invoke.c	(revision 861)
+++ tests/invoke/invoke.c	(working copy)
@@ -28,7 +28,8 @@
   GError *error = NULL;
   const gchar *name;
   TestStruct *s;
-  
+  GTimer *t1;
+
   g_type_init ();
 
   rep = g_irepository_get_default ();
@@ -66,6 +67,33 @@
   g_assert (retval.v_int == 8);
   g_base_info_unref (info);
   
+  t1 = g_timer_new ();
+  info = g_irepository_find_by_name (rep, "test", "test1");  
+  g_assert (g_base_info_get_type (info) == GI_INFO_TYPE_FUNCTION);
+  function = (GIFunctionInfo *)info;
+
+  retval.v_int = 0;
+  in_args[0].v_int = 4;
+
+  g_timer_start (t1);
+
+  for (len = 0; len < 1000000; len++) 
+    {
+      if (!g_function_info_invoke (function, in_args, 1, NULL, 0, &retval, &error))
+        g_print ("Invokation of %s failed: %s\n",
+	         g_base_info_get_name (info),
+	         error->message);
+    }
+
+  g_timer_stop (t1);
+
+  g_print ("Performance test: %f for 1000000 invocations of test1\n", g_timer_elapsed (t1, NULL));
+
+  g_timer_destroy (t1);
+
+  g_assert (retval.v_int == 8);
+  g_base_info_unref (info);
+
   /* test2 calculates x + 4, 
    * taking x as an in parameter
    * and storing the result in an out parameter
