Index: m4/tls.m4
===================================================================
--- m4/tls.m4	(revision 0)
+++ m4/tls.m4	(revision 0)
@@ -0,0 +1,18 @@
+AC_DEFUN([CHECK_TLS], [
+  AC_CACHE_CHECK([whether the target supports thread-local storage],
+		 have_tls, [
+    AC_RUN_IFELSE([__thread int a; int b; int main() { return a = b; }],
+      [dnl If the test case passed with dynamic linking, try again with
+      dnl static linking.  This fails at least with some older Red Hat
+      dnl releases.
+      AC_RUN_IFELSE([__thread int a; int b; int main() { return a = b; }],
+		    [have_tls=yes], [have_tls=no], [])
+      ],
+      [have_tls=no],
+      [AC_COMPILE_IFELSE([__thread int foo;], [have_tls=yes], [have_tls=no])]
+    )])
+  if test "$have_tls" = "yes"; then
+    AC_DEFINE(HAVE_TLS, 1,
+	      [Define to 1 if the target supports thread-local storage.])
+  fi])
+
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 861)
+++ ChangeLog	(working copy)
@@ -1,3 +1,13 @@
+2008-11-03  Philip Van Hoof  <philip@codeminded.be>
+
+	* configure.ac: 
+	* m4/tls.m4: Check for TLS support
+
+	* girepository/ginfo.c:
+	* girepository/ginfo-priv.h:
+	* girepository/ginvoke.c: Store arguments and values in a TLS to avoid
+	a alloca per function call and cache 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)
@@ -116,6 +117,11 @@
   return rettype;
 }
 
+#ifdef HAVE_TLS
+static __thread  ffi_type *arg_types[200];
+static __thread  gpointer  arg_values[200];
+#endif
+
 /**
  * g_function_info_invoke:
  * @info: a #GIFunctionInfo describing the function to invoke
@@ -151,7 +157,6 @@
 			GArgument        *return_value,
 			GError          **error)
 {
-  ffi_cif cif;
   ffi_type *rtype;
   ffi_type **atypes;
   const gchar *symbol;
@@ -162,7 +167,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);
@@ -210,14 +215,36 @@
     /* 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);
-  
+  /* 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 (G_UNLIKELY (n_args == 0 || ((GIBaseInfo *)info)->cif.nargs != (unsigned int) n_args))
+      calc_cif = TRUE;
+
+#ifdef HAVE_TLS
+  if (G_LIKELY (n_invoke_args < 200)) 
+    {
+      if (G_UNLIKELY (calc_cif))
+        atypes = arg_types;
+      args = arg_values;
+    } 
+  else 
+    {
+#endif
+      if (G_UNLIKELY (calc_cif))
+        atypes = g_alloca (sizeof (ffi_type*) * n_invoke_args);
+      args = g_alloca (sizeof (gpointer) * n_invoke_args);
+#ifdef HAVE_TLS
+    }
+#endif
+ 
   if (is_method)
     {
-      atypes[0] = &ffi_type_pointer;
+      if (G_UNLIKELY (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 +252,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 (G_UNLIKELY (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 +274,10 @@
 	  
 	  break;
 	case GI_DIRECTION_OUT:
-	  atypes[i+offset] = &ffi_type_pointer;
 
+	  if (G_UNLIKELY (calc_cif))
+	    atypes[i+offset] = &ffi_type_pointer;
+
 	  if (out_pos >= n_out_args)
 	    {
 	      g_set_error (error,
@@ -258,8 +291,10 @@
 	  out_pos++;	  
 	  break;
 	case GI_DIRECTION_INOUT:
-	  atypes[i+offset] = &ffi_type_pointer;
 
+	  if (G_UNLIKELY (calc_cif))
+	    atypes[i+offset] = &ffi_type_pointer;
+
 	  if (in_pos >= n_in_args)
 	    {
 	      g_set_error (error,
@@ -293,7 +328,9 @@
     {
       gpointer address = &local_error;
       args[n_invoke_args - 1] = &address;
-      atypes[n_invoke_args - 1] = &ffi_type_pointer;
+
+      if (G_UNLIKELY (calc_cif))
+        atypes[n_invoke_args - 1] = &ffi_type_pointer;
     }
 
   if (in_pos < n_in_args)
@@ -313,10 +350,13 @@
       goto out;
     }
 
-  if (ffi_prep_cif (&cif, FFI_DEFAULT_ABI, n_invoke_args, rtype, atypes) != FFI_OK)
-    goto out;
+  if (G_UNLIKELY (calc_cif))
+    {
+      if (ffi_prep_cif (&(((GIBaseInfo *)info)->cif), FFI_DEFAULT_ABI, n_invoke_args, rtype, atypes) != FFI_OK)
+         goto out;
+    } 
 
-  ffi_call (&cif, func, return_value, args);
+  ffi_call (&(((GIBaseInfo *)info)->cif), func, return_value, args);
 
   if (local_error)
     {
Index: girepository/ginfo.c
===================================================================
--- girepository/ginfo.c	(revision 861)
+++ girepository/ginfo.c	(working copy)
@@ -27,15 +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
 {
@@ -47,16 +40,6 @@
   const gchar *namespace;
 };
 
-struct _GICallableInfo
-{
-  GIBaseInfo base;
-};
-
-struct _GIFunctionInfo
-{
-  GICallableInfo callable;
-};
-
 struct _GICallbackInfo
 {
   GICallableInfo callable;
Index: girepository/ginfo-priv.h
===================================================================
--- girepository/ginfo-priv.h	(revision 0)
+++ girepository/ginfo-priv.h	(revision 0)
@@ -0,0 +1,48 @@
+/* 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"
+
+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: configure.ac
===================================================================
--- configure.ac	(revision 861)
+++ configure.ac	(working copy)
@@ -168,6 +168,8 @@
 AC_CHECK_FUNCS([memchr strchr strspn strstr strtol strtoull])
 AC_CHECK_FUNCS([backtrace backtrace_symbols])
 
+CHECK_TLS
+
 # Python
 
 AC_MSG_CHECKING([whether Python support is requested])
