In metadata:
authorRobert Jordan <robertj@gmx.net>
Sat, 3 May 2008 17:51:37 +0000 (17:51 -0000)
committerRobert Jordan <robertj@gmx.net>
Sat, 3 May 2008 17:51:37 +0000 (17:51 -0000)
2008-05-03  Robert Jordan  <robertj@gmx.net>

* image.c, metadata-internals.h: add thunk_invoke_cache.

* marshal.c, marshal.h: implement
mono_marshal_get_thunk_invoke_wrapper ().

* object.c, object.h: implement mono_method_get_unmanaged_thunk ().

Code is contributed under MIT/X11 license.

In tests:
2008-05-03  Robert Jordan  <robertj@gmx.net>

* libtest.c, thunks.cs: tests for mono_method_get_unmanaged_thunk ().

* Makefile.am: add thunk.cs. link libtest with gmodule.

Code is contributed under MIT/X11 license.

svn path=/trunk/mono/; revision=102433

mono/metadata/ChangeLog
mono/metadata/image.c
mono/metadata/marshal.c
mono/metadata/marshal.h
mono/metadata/metadata-internals.h
mono/metadata/object.c
mono/metadata/object.h
mono/tests/ChangeLog
mono/tests/Makefile.am
mono/tests/libtest.c
mono/tests/thunks.cs [new file with mode: 0644]

index 802fece6bb2a249ded813a2fdcd61ba3d56abfab..204816ee67e563eab73446a8db0afd12c191409d 100644 (file)
@@ -1,3 +1,14 @@
+2008-05-03  Robert Jordan  <robertj@gmx.net>
+
+       * image.c, metadata-internals.h: add thunk_invoke_cache.
+
+       * marshal.c, marshal.h: implement
+       mono_marshal_get_thunk_invoke_wrapper ().
+
+       * object.c, object.h: implement mono_method_get_unmanaged_thunk ().
+
+       Code is contributed under MIT/X11 license.
+
 2008-05-02 Rodrigo Kumpera  <rkumpera@novell.com>
 
        * verify.c (do_leave): Empty the stack.
index a4b8075cfc2c2700ed1df3de26097d15e1ab130e..e138642eda9bffce24dfaa827ec0d759476deb87 100644 (file)
@@ -635,6 +635,7 @@ mono_image_init (MonoImage *image)
        image->isinst_cache = g_hash_table_new (mono_aligned_addr_hash, NULL);
        image->castclass_cache = g_hash_table_new (mono_aligned_addr_hash, NULL);
        image->proxy_isinst_cache = g_hash_table_new (mono_aligned_addr_hash, NULL);
+       image->thunk_invoke_cache = g_hash_table_new (mono_aligned_addr_hash, NULL);
 
        image->typespec_cache = g_hash_table_new (NULL, NULL);
        image->memberref_signatures = g_hash_table_new (NULL, NULL);
@@ -1437,6 +1438,7 @@ mono_image_close (MonoImage *image)
        g_hash_table_destroy (image->isinst_cache);
        g_hash_table_destroy (image->castclass_cache);
        g_hash_table_destroy (image->proxy_isinst_cache);
+       g_hash_table_destroy (image->thunk_invoke_cache);
        if (image->static_rgctx_invoke_cache)
                g_hash_table_destroy (image->static_rgctx_invoke_cache);
 
index fc0febbaeb2aa7bfc0f9063104a33353530a3aa1..671ac376622dd22e139b6dff29a57b125e6961ab 100644 (file)
@@ -12008,3 +12008,124 @@ mono_marshal_find_nonzero_bit_offset (guint8 *buf, int len, int *byte_offset, gu
        *byte_offset = i;
        *bitmask = buf [i];
 }
+
+MonoMethod *
+mono_marshal_get_thunk_invoke_wrapper (MonoMethod *method)
+{
+       MonoMethodBuilder *mb;
+       MonoMethodSignature *sig, *csig;
+       MonoExceptionClause *clause;
+       MonoMethodHeader *header;
+       MonoImage *image;
+       MonoClass *klass;
+       GHashTable *cache;
+       MonoMethod *res;
+       int i, param_count, sig_size, pos_leave;
+
+       g_assert (method);
+
+       klass = method->klass;
+       image = method->klass->image;
+       cache = image->thunk_invoke_cache;
+
+       if ((res = mono_marshal_find_in_cache (cache, method)))
+               return res;
+
+       sig = mono_method_signature (method);
+       mb = mono_mb_new (klass, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
+
+       /* add "this" and exception param */
+       param_count = sig->param_count + sig->hasthis + 1;
+
+       /* dup & extend signature */
+       csig = mono_metadata_signature_alloc (image, param_count);
+       sig_size = sizeof (MonoMethodSignature) + ((sig->param_count - MONO_ZERO_LEN_ARRAY) * sizeof (MonoType *));
+       memcpy (csig, sig, sig_size);
+       csig->param_count = param_count;
+       csig->hasthis = 0;
+       csig->pinvoke = 1;
+       csig->call_convention = MONO_CALL_DEFAULT;
+
+       if (sig->hasthis) {
+               /* "this" of value types is actually a ptr */
+               csig->params [0] = klass->valuetype
+                       ? &mono_ptr_class_get (&klass->byval_arg)->byval_arg
+                       : &klass->byval_arg;
+               /* shift params */
+               for (i = 0; i < sig->param_count; i++)
+                       csig->params [i + 1] = sig->params [i];
+       }
+
+       /* setup exception param as byref+[out] */
+       csig->params [param_count - 1] = mono_metadata_type_dup (image->mempool,
+                &mono_defaults.exception_class->byval_arg);
+       csig->params [param_count - 1]->byref = 1;
+       csig->params [param_count - 1]->attrs = PARAM_ATTRIBUTE_OUT;
+
+       /* local 0 (temp for exception object) */
+       mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
+
+       /* local 1 (temp for result) */
+       if (!MONO_TYPE_IS_VOID (sig->ret))
+               mono_mb_add_local (mb, sig->ret);
+
+       /* clear exception arg */
+       mono_mb_emit_ldarg (mb, param_count - 1);
+       mono_mb_emit_byte (mb, CEE_LDNULL);
+       mono_mb_emit_byte (mb, CEE_STIND_REF);
+
+       /* try */
+       mono_loader_lock ();
+       clause = mono_mempool_alloc0 (image->mempool, sizeof (MonoExceptionClause));
+       mono_loader_unlock ();
+       clause->try_offset = mono_mb_get_label (mb);
+
+       /* push method's args */
+       for (i = 0; i < param_count - 1; i++)
+               mono_mb_emit_ldarg (mb, i);
+
+       /* call */
+       if (method->flags & METHOD_ATTRIBUTE_VIRTUAL)
+               mono_mb_emit_op (mb, CEE_CALLVIRT, method);
+       else
+               mono_mb_emit_op (mb, CEE_CALL, method);
+
+       /* save result at local 1 */
+       if (!MONO_TYPE_IS_VOID (sig->ret))
+               mono_mb_emit_stloc (mb, 1);
+
+       pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE);
+
+       /* catch */
+       clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
+       clause->try_len = mono_mb_get_pos (mb) - clause->try_offset;
+       clause->data.catch_class = mono_defaults.object_class;
+
+       clause->handler_offset = mono_mb_get_label (mb);
+
+       /* store exception at local 0 */
+       mono_mb_emit_stloc (mb, 0);
+       mono_mb_emit_ldarg (mb, param_count - 1);
+       mono_mb_emit_ldloc (mb, 0);
+       mono_mb_emit_byte (mb, CEE_STIND_REF);
+       mono_mb_emit_branch (mb, CEE_LEAVE);
+
+       clause->handler_len = mono_mb_get_pos (mb) - clause->handler_offset;
+
+       mono_mb_patch_branch (mb, pos_leave);
+       /* end-try */
+
+       if (!MONO_TYPE_IS_VOID (sig->ret))
+               mono_mb_emit_ldloc (mb, 1);
+
+       mono_mb_emit_byte (mb, CEE_RET);
+
+       res = mono_mb_create_and_cache (cache, method, mb, csig, param_count + 16);
+       mono_mb_free (mb);
+
+       header = ((MonoMethodNormal *)res)->header;
+       header->num_clauses = 1;
+       header->clauses = clause;
+
+       return res;
+}
index 3959f0eb32542561ff12f015acf3ede7e918358b..46be4d2a9fcae416d4b592e2cf01c05b5e48f61a 100644 (file)
@@ -198,6 +198,9 @@ MonoMethod *
 mono_marshal_get_generic_array_helper (MonoClass *class, MonoClass *iface,
                                       gchar *name, MonoMethod *method) MONO_INTERNAL;
 
+MonoMethod *
+mono_marshal_get_thunk_invoke_wrapper (MonoMethod *method) MONO_INTERNAL;
+
 /* marshaling internal calls */
 
 void * 
index 1fdc40272ec9a6986776fba4f24fd481a71fabd2..db24d232c67e9e48cd4b7c92ab45735cf5a909c0 100644 (file)
@@ -194,6 +194,7 @@ struct _MonoImage {
        GHashTable *cominterop_invoke_cache;
        GHashTable *cominterop_wrapper_cache;
        GHashTable *static_rgctx_invoke_cache; /* LOCKING: marshal lock */
+       GHashTable *thunk_invoke_cache;
 
        /*
         * indexed by MonoClass pointers
index 599480f709d224d53387f51d24526f16fec27ff5..83fb97fb305c7d4db4a216ac784c9bbc1d26ab6b 100644 (file)
@@ -2089,6 +2089,53 @@ mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **
        return default_mono_runtime_invoke (method, obj, params, exc);
 }
 
+/**
+ * mono_method_get_unmanaged_thunk:
+ * @method: method to generate a thunk for.
+ *
+ * Returns an unmanaged->managed thunk that can be used to call
+ * a managed method directly from C.
+ *
+ * The thunk's C signature closely matches the managed signature:
+ *
+ * C#: public bool Equals (object obj);
+ * C:  typedef MonoBoolean (*Equals)(MonoObject *this,
+ *             MonoObject *obj, MonoException **ex);
+ *
+ * The "this" parameter must not be used with static methods:
+ *
+ * C#: public static bool ReferenceEquals (object a, object b);
+ * C:  typedef MonoBoolean (*ReferenceEquals)(MonoObject *a, MonoObject *b,
+ *             MonoException **ex);
+ *
+ * The last argument must be a non-null pointer of a MonoException* pointer.
+ * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
+ * exception has been thrown in managed code. Otherwise, it will point
+ * to the MonoException* caught by the thunk. In this case, the result of
+ * the thunk is undefined:
+ *
+ * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
+ * MonoException *ex = NULL;
+ * Equals func = mono_method_get_unmanaged_thunk (method);
+ * MonoBoolean res = func (thisObj, objToCompare, &ex);
+ * if (ex) {
+ *    // handle exception
+ * }
+ *
+ * The calling convention of the thunk matches the platform's default
+ * convention. This means that under Windows, C declarations must
+ * contain the __stdcall attribute:
+ *
+ * C:  typedef MonoBoolean (__stdcall *Equals)(MonoObject *this,
+ *             MonoObject *obj, MonoException **ex);
+ */
+gpointer
+mono_method_get_unmanaged_thunk (MonoMethod *method)
+{
+       method = mono_marshal_get_thunk_invoke_wrapper (method);
+       return mono_compile_method (method);
+}
+
 static void
 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
 {
index 1a93d7c179ca769e5f0051f08dee88fb6ca4222b..b92c498457c71f302fa28f9ab200fead2d9c57a0 100644 (file)
@@ -231,6 +231,9 @@ MonoObject*
 mono_runtime_invoke_array   (MonoMethod *method, void *obj, MonoArray *params,
                             MonoObject **exc);
 
+gpointer
+mono_method_get_unmanaged_thunk (MonoMethod *method);
+
 MonoArray*
 mono_runtime_get_main_args  (void);
 
index 2cca19a26c7156ef803a22de7ced09c1daf2288a..eb708a715e0538aaf91b8d9e8f0be2346e9097ea 100644 (file)
@@ -1,3 +1,11 @@
+2008-05-03  Robert Jordan  <robertj@gmx.net>
+
+       * libtest.c, thunks.cs: tests for mono_method_get_unmanaged_thunk ().
+
+       * Makefile.am: add thunk.cs. link libtest with gmodule.
+
+       Code is contributed under MIT/X11 license.
+
 2008-04-28  Mark Probst  <mark.probst@gmail.com>
 
        * generic-array-type.2.cs: Test case for type arguments in arrays.
index b420e75212da22bb1a964f8cd2a4aacf2da491ee..24b1259b94ec1e1fea1868bc2c1bb1d60e39b353 100644 (file)
@@ -277,7 +277,8 @@ BASE_TEST_CS_SRC=           \
        bug-322722_patch_bx.2.cs                \
        bug-348522.2.cs         \
        bug-340662_bug.cs       \
-       bug-322722_dyn_method_throw.2.cs
+       bug-322722_dyn_method_throw.2.cs        \
+       thunks.cs
 
 if AMD64
 TEST_CS_SRC = $(BASE_TEST_CS_SRC) async-exc-compilation.cs
@@ -710,7 +711,7 @@ patch-libtool:
 
 noinst_LTLIBRARIES = libtest.la
 
-INCLUDES = $(GLIB_CFLAGS)
+INCLUDES = $(GLIB_CFLAGS) $(GMODULE_CFLAGS)
 
 if PLATFORM_WIN32
 # gcc-3.4.4 emits incorrect code when making indirect calls to stdcall functions using a tail call
@@ -723,6 +724,6 @@ else
 libtest_la_LDFLAGS = -rpath `pwd`
 endif
 libtest_la_SOURCES = libtest.c
-libtest_la_LIBADD = $(GLIB_LIBS)
+libtest_la_LIBADD = $(GLIB_LIBS) $(GMODULE_LIBS)
 
 CLEANFILES = $(TESTSI_CS) $(TESTSI_IL) $(STRESS_TESTS) *.dll *.stdout *.exe stest.dat
index b27780acbb22f42b6cd9e5afdf0f3d2c002fb306..39773e3182b48854bc828b0c16882c28e48d7040 100644 (file)
@@ -2,8 +2,10 @@
 #include <stdlib.h>
 #include <string.h>
 #include <glib.h>
+#include <gmodule.h>
 #include <errno.h>
 #include <time.h>
+#include <math.h>
 
 #ifdef WIN32
 #include <windows.h>
@@ -2895,3 +2897,311 @@ mono_test_marshal_ccw_itest (MonoComObject *pUnk)
 
 
 #endif //NOT_YET
+
+
+/*
+ * mono_method_get_unmanaged_thunk tests
+ */
+
+/* thunks.cs:TestStruct */
+typedef struct _TestStruct {
+       int A;
+       double B;
+} TestStruct;
+
+/* Searches for mono symbols in all loaded modules */
+static gpointer
+lookup_mono_symbol (char *symbol_name)
+{
+       gpointer symbol;
+       if (g_module_symbol (g_module_open (NULL, G_MODULE_BIND_LAZY), symbol_name, &symbol))
+               return symbol;
+       else
+               return NULL;
+}
+
+/**
+ * test_method_thunk:
+ *
+ * @id: the method number
+ * @test_method_handle: MonoMethod* of the C# test method
+ * @create_object_method_handle: MonoMethod* of thunks.cs:Test.CreateObject
+ */
+STDCALL int 
+test_method_thunk (int id, gpointer test_method_handle, gpointer create_object_method_handle)
+{
+       gpointer (*mono_method_get_unmanaged_thunk)(gpointer)
+               = lookup_mono_symbol ("mono_method_get_unmanaged_thunk");
+
+       gpointer (*mono_string_new_wrapper)(char *)
+               = lookup_mono_symbol ("mono_string_new_wrapper");
+
+       char* (*mono_string_to_utf8)(gpointer)
+               = lookup_mono_symbol ("mono_string_to_utf8");
+
+       gpointer test_method, ex = NULL;
+       gpointer (STDCALL *CreateObject)(gpointer*);
+
+
+       if (!mono_method_get_unmanaged_thunk)
+               return 1;
+
+       test_method =  mono_method_get_unmanaged_thunk (test_method_handle);
+       if (!test_method)
+               return 2;
+
+       CreateObject = mono_method_get_unmanaged_thunk (create_object_method_handle);
+       if (!CreateObject)
+               return 3;
+
+
+       switch (id) {
+
+       case 0: {
+               /* thunks.cs:Test.Foo0 */
+               void (STDCALL *F)(gpointer*) = test_method;
+               F (&ex);
+               break;
+       }
+
+       case 1: {
+               /* thunks.cs:Test.Foo1 */
+               int (STDCALL *F)(gpointer*) = test_method;
+               if (F (&ex) != 42)
+                       return 4;
+               break;
+       }
+
+       case 2: {
+               /* thunks.cs:Test.Foo2 */
+               gpointer (STDCALL *F)(gpointer, gpointer*) = test_method;
+               gpointer str = mono_string_new_wrapper ("foo");
+               if (str != F (str, &ex))
+                       return 4;
+               break;
+       }
+
+       case 3: {
+               /* thunks.cs:Test.Foo3 */
+               gpointer (STDCALL *F)(gpointer, gpointer, gpointer*);
+               gpointer obj;
+               gpointer str;
+
+               F = test_method;
+               obj = CreateObject (&ex);
+               str = mono_string_new_wrapper ("bar");
+
+               if (str != F (obj, str, &ex))
+                       return 4;
+               break;
+       }
+
+       case 4: {
+               /* thunks.cs:Test.Foo4 */
+               int (STDCALL *F)(gpointer, gpointer, int, gpointer*);
+               gpointer obj;
+               gpointer str;
+
+               F = test_method;
+               obj = CreateObject (&ex);
+               str = mono_string_new_wrapper ("bar");
+
+               if (42 != F (obj, str, 42, &ex))
+                       return 4;
+
+               break;
+       }
+
+       case 5: {
+               /* thunks.cs:Test.Foo5 */
+               int (STDCALL *F)(gpointer, gpointer, int, gpointer*);
+               gpointer obj;
+               gpointer str;
+
+               F = test_method;
+               obj = CreateObject (&ex);
+               str = mono_string_new_wrapper ("bar");
+
+               F (obj, str, 42, &ex);
+               if (!ex)
+                   return 4;
+
+               break;
+       }
+
+       case 6: {
+               /* thunks.cs:Test.Foo6 */
+               int (STDCALL *F)(gpointer, guint8, gint16, gint32, gint64, float, double,
+                                gpointer, gpointer*);
+               gpointer obj;
+               gpointer str = mono_string_new_wrapper ("Foo6");
+               int res;
+
+               F = test_method;
+               obj = CreateObject (&ex);
+
+               res = F (obj, 254, 32700, -245378, 6789600, 3.1415, 3.1415, str, &ex);
+               if (ex)
+                       return 4;
+
+               if (!res)
+                       return 5;
+
+               break;
+       }
+
+       case 7: {
+               /* thunks.cs:Test.Foo7 */
+               gint64 (STDCALL *F)(gpointer*) = test_method;
+               if (F (&ex) != G_MAXINT64)
+                       return 4;
+               break;
+       }
+
+       case 8: {
+               /* thunks.cs:Test.Foo8 */
+               void (STDCALL *F)(guint8*, gint16*, gint32*, gint64*, float*, double*,
+                                gpointer*, gpointer*);
+
+               guint8 a1;
+               gint16 a2;
+               gint32 a3;
+               gint64 a4;
+               float a5;
+               double a6;
+               gpointer a7;
+
+               F = test_method;
+
+               F (&a1, &a2, &a3, &a4, &a5, &a6, &a7, &ex);
+               if (ex)
+                       return 4;
+
+               if (!(a1 == 254 &&
+                     a2 == 32700 &&
+                     a3 == -245378 &&
+                     a4 == 6789600 &&
+                     (fabs (a5 - 3.1415) < 0.001) &&
+                     (fabs (a6 - 3.1415) < 0.001) &&
+                     strcmp (mono_string_to_utf8 (a7), "Foo8") == 0))
+                       return 5;
+
+               break;
+       }
+
+       case 9: {
+               /* thunks.cs:Test.Foo9 */
+               void (STDCALL *F)(guint8*, gint16*, gint32*, gint64*, float*, double*,
+                                gpointer*, gpointer*);
+
+               guint8 a1;
+               gint16 a2;
+               gint32 a3;
+               gint64 a4;
+               float a5;
+               double a6;
+               gpointer a7;
+
+               F = test_method;
+
+               F (&a1, &a2, &a3, &a4, &a5, &a6, &a7, &ex);
+               if (!ex)
+                       return 4;
+
+               break;
+       }
+
+       case 10: {
+               /* thunks.cs:Test.Foo10 */
+               int (STDCALL *F)(TestStruct, gpointer*);
+
+               TestStruct a1;
+               int res;
+
+               a1.A = 42;
+               a1.B = 3.1415;
+
+               F = test_method;
+
+               res = F (a1, &ex);
+               if (ex)
+                       return 4;
+
+               if (!res)
+                       return 5;
+
+               break;
+       }
+
+       case 11: {
+               /* thunks.cs:Test.Foo11 */
+               void (STDCALL *F)(TestStruct*, gpointer*);
+
+               TestStruct a1;
+
+               F = test_method;
+
+               F (&a1, &ex);
+               if (ex)
+                       return 4;
+
+               if (!a1.A == 42)
+                       return 5;
+
+               if (!fabs (a1.B - 3.1415) < 0.001)
+                       return 6;
+
+               break;
+       }
+
+       case 12: {
+               /* thunks.cs:Test.Foo12 */
+               TestStruct (STDCALL *F)(gpointer*);
+
+               TestStruct a1;
+
+               F = test_method;
+
+               a1 = F (&ex);
+               if (ex)
+                       return 4;
+
+               if (!a1.A == 42)
+                       return 5;
+
+               if (!fabs (a1.B - 3.1415) < 0.001)
+                       return 6;
+
+               break;
+       }
+
+       case 13: {
+               /* thunks.cs:TestStruct.Foo13 */
+               void (STDCALL *F)(TestStruct*, gpointer*);
+
+               TestStruct a1;
+               a1.A = 42;
+               a1.B = 3.1415;
+
+               F = test_method;
+
+               F (&a1, &ex);
+               if (ex)
+                       return 4;
+
+               if (a1.A != 1)
+                       return 5;
+
+               if (a1.B != 17)
+                       return 6;
+
+               break;
+       }
+
+       default:
+               return 9;
+
+       }
+
+       return 0;
+}
diff --git a/mono/tests/thunks.cs b/mono/tests/thunks.cs
new file mode 100644 (file)
index 0000000..5ee054d
--- /dev/null
@@ -0,0 +1,144 @@
+using System;
+using System.Runtime.InteropServices;
+
+public class Test
+{
+       [DllImport ("libtest")]
+       public static extern int test_method_thunk (int id, IntPtr testMethodHandle,
+               IntPtr createObjectHandle);
+
+       static int test_method_thunk (int id, Type type)
+       {
+               string name = String.Format ("Foo{0}", id);
+               return test_method_thunk (
+                       id,
+                       type.GetMethod (name).MethodHandle.Value,
+                       type.GetMethod ("CreateObject").MethodHandle.Value);
+       }
+
+       public static int Main ()
+       {
+               const int MaxClassTests = 13;
+               const int MaxStructTests = 1;
+               
+               // tests of class "Test"
+               for (int i = 0; i < MaxClassTests; i++) {
+                       int res = test_method_thunk (i, typeof (Test));
+                       if (res != 0)
+                               return i*10 + res;
+               }
+
+               // tests of struct "TestStruct"
+               for (int i = 0; i < MaxStructTests; i++) {
+                       int res = test_method_thunk (MaxClassTests + i, typeof (TestStruct));
+                       if (res != 0)
+                               return i*10 + res;
+               }
+               
+               return 0;
+       }
+
+       public static object CreateObject ()
+       {
+               Test t = new Test ();
+               return t;
+       }
+
+       public static void Foo0 ()
+       {
+       }
+
+       public static int Foo1 ()
+       {
+               return 42;
+       }
+
+       public static string Foo2 (string s)
+       {
+               return s;
+       }
+
+       public string Foo3 (string a)
+       {
+               return a;
+       }
+
+       public int Foo4 (string a, int i)
+       {
+               return i;
+       }
+
+       public int Foo5 (string a, int i)
+       {
+               throw new NotImplementedException ();
+       }
+
+       public bool Foo6 (byte a1, short a2, int a3, long a4, float a5, double a6, string a7)
+       {
+               return  a1 == 254 &&
+                       a2 == 32700 &&
+                       a3 == -245378 &&
+                       a4 == 6789600 &&
+                       (Math.Abs (a5 - 3.1415) < 0.001) &&
+                       (Math.Abs (a6 - 3.1415) < 0.001) &&
+                       a7 == "Foo6";
+       }
+
+       public static long Foo7 ()
+       {
+               return Int64.MaxValue;
+       }
+
+       public static void Foo8 (ref byte a1, ref short a2, ref int a3, ref long a4, ref float a5, ref double a6, ref string a7)
+       {
+               a1 = 254;
+               a2 = 32700;
+               a3 = -245378;
+               a4 = 6789600;
+               a5 = 3.1415f;
+               a6 = 3.1415;
+               a7 = "Foo8";
+       }
+
+       public static void Foo9 (ref byte a1, ref short a2, ref int a3, ref long a4, ref float a5, ref double a6, ref string a7)
+       {
+               throw new NotImplementedException ();
+       }
+
+       public static bool Foo10 (TestStruct s)
+       {
+               return s.A == 42 && Math.Abs (s.B - 3.1415) < 0.001;
+       }
+
+       public static void Foo11 (ref TestStruct s)
+       {
+               s.A = 42;
+               s.B = 3.1415;
+       }
+
+       public static TestStruct Foo12 ()
+       {
+               TestStruct s = new TestStruct ();
+               s.A = 42;
+               s.B = 3.1415;
+               return s;
+       }
+}
+
+
+public struct TestStruct
+{
+       public int A;
+       public double B;
+
+       public static TestStruct CreateObject ()
+       {
+               return new TestStruct ();
+       }
+
+       public void Foo13 ()
+       {
+               A = 1;
+               B = 17;
+       }
+}