Initial sgen mips port.
[mono.git] / mono / metadata / marshal.c
index c99407d2765336fb2191a5e8485fae0d6823a322..ed60cb7234a585f18c1362181c75e6f16dcbaebf 100644 (file)
@@ -6,6 +6,7 @@
  *
  * Copyright 2002-2003 Ximian, Inc (http://www.ximian.com)
  * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
+ * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
  *
  */
 
@@ -35,6 +36,8 @@
 #include "mono/metadata/gc-internal.h"
 #include "mono/metadata/cominterop.h"
 #include "mono/utils/mono-counters.h"
+#include "mono/utils/mono-tls.h"
+#include "mono/utils/mono-memory-model.h"
 #include <string.h>
 #include <errno.h>
 
@@ -76,9 +79,9 @@ typedef struct _MonoRemotingMethods MonoRemotingMethods;
 static CRITICAL_SECTION marshal_mutex;
 static gboolean marshal_mutex_initialized;
 
-static guint32 last_error_tls_id;
+static MonoNativeTlsKey last_error_tls_id;
 
-static guint32 load_type_info_tls_id;
+static MonoNativeTlsKey load_type_info_tls_id;
 
 static void
 delegate_hash_table_add (MonoDelegate *d);
@@ -86,6 +89,9 @@ delegate_hash_table_add (MonoDelegate *d);
 static void
 emit_struct_conv (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object);
 
+static void
+emit_struct_conv_full (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object, MonoMarshalNative string_encoding);
+
 static void 
 mono_struct_delete_old (MonoClass *klass, char *ptr);
 
@@ -104,6 +110,9 @@ mono_string_utf8_to_builder2 (char *text);
 static MonoStringBuilder *
 mono_string_utf16_to_builder2 (gunichar2 *text);
 
+static MonoString*
+mono_string_new_len_wrapper (const char *text, guint length);
+
 static void
 mono_byvalarray_to_array (MonoArray *arr, gpointer native_arr, MonoClass *eltype, guint32 elnum);
 
@@ -195,8 +204,8 @@ mono_marshal_init (void)
                module_initialized = TRUE;
                InitializeCriticalSection (&marshal_mutex);
                marshal_mutex_initialized = TRUE;
-               last_error_tls_id = TlsAlloc ();
-               load_type_info_tls_id = TlsAlloc ();
+               mono_native_tls_alloc (&last_error_tls_id, NULL);
+               mono_native_tls_alloc (&load_type_info_tls_id, NULL);
 
                register_icall (ves_icall_System_Threading_Thread_ResetAbort, "ves_icall_System_Threading_Thread_ResetAbort", "void", TRUE);
                register_icall (mono_marshal_string_to_utf16, "mono_marshal_string_to_utf16", "ptr obj", FALSE);
@@ -204,6 +213,7 @@ mono_marshal_init (void)
                register_icall (mono_string_to_utf16, "mono_string_to_utf16", "ptr obj", FALSE);
                register_icall (mono_string_from_utf16, "mono_string_from_utf16", "obj ptr", FALSE);
                register_icall (mono_string_new_wrapper, "mono_string_new_wrapper", "obj ptr", FALSE);
+               register_icall (mono_string_new_len_wrapper, "mono_string_new_len_wrapper", "obj ptr int", FALSE);
                register_icall (mono_string_to_utf8, "mono_string_to_utf8", "ptr obj", FALSE);
                register_icall (mono_string_to_lpstr, "mono_string_to_lpstr", "ptr obj", FALSE);
                register_icall (mono_string_to_ansibstr, "mono_string_to_ansibstr", "ptr object", FALSE);
@@ -256,8 +266,8 @@ mono_marshal_cleanup (void)
 {
        mono_cominterop_cleanup ();
 
-       TlsFree (load_type_info_tls_id);
-       TlsFree (last_error_tls_id);
+       mono_native_tls_free (load_type_info_tls_id);
+       mono_native_tls_free (last_error_tls_id);
        DeleteCriticalSection (&marshal_mutex);
        marshal_mutex_initialized = FALSE;
 }
@@ -968,6 +978,12 @@ mono_string_to_byvalwstr (gpointer dst, MonoString *src, int size)
        *((gunichar2 *) dst + len) = 0;
 }
 
+static MonoString*
+mono_string_new_len_wrapper (const char *text, guint length)
+{
+       return mono_string_new_len (mono_domain_get (), text, length);
+}
+
 static int
 mono_mb_emit_proxy_check (MonoMethodBuilder *mb, int branch_code)
 {
@@ -1018,10 +1034,23 @@ mono_mb_emit_contextbound_check (MonoMethodBuilder *mb, int branch_code)
        return mono_mb_emit_branch (mb, branch_code);
 }
 
+/*
+ * mono_mb_emit_exception_marshal_directive:
+ *
+ *   This function assumes ownership of MSG, which should be malloc-ed.
+ */
 static void
-mono_mb_emit_exception_marshal_directive (MonoMethodBuilder *mb, const char *msg)
+mono_mb_emit_exception_marshal_directive (MonoMethodBuilder *mb, char *msg)
 {
-       mono_mb_emit_exception_full (mb, "System.Runtime.InteropServices", "MarshalDirectiveException", msg);
+       char *s;
+
+       if (!mb->dynamic) {
+               s = mono_image_strdup (mb->method->klass->image, msg);
+               g_free (msg);
+       } else {
+               s = g_strdup (msg);
+       }
+       mono_mb_emit_exception_full (mb, "System.Runtime.InteropServices", "MarshalDirectiveException", s);
 }
 
 guint
@@ -1398,7 +1427,6 @@ emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv
                char *msg = g_strdup_printf ("marshaling conversion %d not implemented", conv);
 
                mono_mb_emit_exception_marshal_directive (mb, msg);
-               g_free (msg);
                break;
        }
        }
@@ -1412,6 +1440,12 @@ conv_to_icall (MonoMarshalConv conv)
                return mono_marshal_string_to_utf16;            
        case MONO_MARSHAL_CONV_LPWSTR_STR:
                return mono_string_from_utf16;
+       case MONO_MARSHAL_CONV_LPTSTR_STR:
+#ifdef TARGET_WIN32
+               return mono_string_from_utf16;
+#else
+               return mono_string_new_wrapper;
+#endif
        case MONO_MARSHAL_CONV_LPSTR_STR:
                return mono_string_new_wrapper;
        case MONO_MARSHAL_CONV_STR_LPTSTR:
@@ -1740,7 +1774,8 @@ emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv
 }
 
 static void
-emit_struct_conv (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object)
+emit_struct_conv_full (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object,
+                                          MonoMarshalNative string_encoding)
 {
        MonoMarshalType *info;
        int i;
@@ -1843,8 +1878,18 @@ emit_struct_conv (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object)
                        case MONO_TYPE_R8:
                                mono_mb_emit_ldloc (mb, 1);
                                mono_mb_emit_ldloc (mb, 0);
-                               mono_mb_emit_byte (mb, mono_type_to_ldind (ftype));
-                               mono_mb_emit_byte (mb, mono_type_to_stind (ftype));
+                               if (t == MONO_TYPE_CHAR && ntype == MONO_NATIVE_U1 && string_encoding != MONO_NATIVE_LPWSTR) {
+                                       if (to_object) {
+                                               mono_mb_emit_byte (mb, CEE_LDIND_U1);
+                                               mono_mb_emit_byte (mb, CEE_STIND_I2);
+                                       } else {
+                                               mono_mb_emit_byte (mb, CEE_LDIND_U2);
+                                               mono_mb_emit_byte (mb, CEE_STIND_I1);
+                                       }
+                               } else {
+                                       mono_mb_emit_byte (mb, mono_type_to_ldind (ftype));
+                                       mono_mb_emit_byte (mb, mono_type_to_stind (ftype));
+                               }
                                break;
                        case MONO_TYPE_VALUETYPE: {
                                int src_var, dst_var;
@@ -1949,6 +1994,12 @@ emit_struct_conv (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object)
        }
 }
 
+static void
+emit_struct_conv (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object)
+{
+       emit_struct_conv_full (mb, klass, to_object, -1);
+}
+
 static void
 emit_struct_free (MonoMethodBuilder *mb, MonoClass *klass, int struct_var)
 {
@@ -2171,6 +2222,7 @@ mono_marshal_get_string_to_ptr_conv (MonoMethodPInvoke *piinfo, MonoMarshalSpec
        case MONO_NATIVE_LPWSTR:
                return MONO_MARSHAL_CONV_STR_LPWSTR;
        case MONO_NATIVE_LPSTR:
+       case MONO_NATIVE_VBBYREFSTR:
                return MONO_MARSHAL_CONV_STR_LPSTR;
        case MONO_NATIVE_LPTSTR:
                return MONO_MARSHAL_CONV_STR_LPTSTR;
@@ -2213,6 +2265,7 @@ mono_marshal_get_ptr_to_string_conv (MonoMethodPInvoke *piinfo, MonoMarshalSpec
                *need_free = FALSE;
                return MONO_MARSHAL_CONV_LPWSTR_STR;
        case MONO_NATIVE_LPSTR:
+       case MONO_NATIVE_VBBYREFSTR:
                return MONO_MARSHAL_CONV_LPSTR_STR;
        case MONO_NATIVE_LPTSTR:
                return MONO_MARSHAL_CONV_LPTSTR_STR;
@@ -2298,6 +2351,22 @@ get_cache (GHashTable **var, GHashFunc hash_func, GCompareFunc equal_func)
        return *var;
 }
 
+static GHashTable*
+get_cache_full (GHashTable **var, GHashFunc hash_func, GCompareFunc equal_func, GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func)
+{
+       if (!(*var)) {
+               mono_marshal_lock ();
+               if (!(*var)) {
+                       GHashTable *cache = 
+                               g_hash_table_new_full (hash_func, equal_func, key_destroy_func, value_destroy_func);
+                       mono_memory_barrier ();
+                       *var = cache;
+               }
+               mono_marshal_unlock ();
+       }
+       return *var;
+}
+
 GHashTable*
 mono_marshal_get_cache (GHashTable **var, GHashFunc hash_func, GCompareFunc equal_func)
 {
@@ -2382,7 +2451,7 @@ mono_remoting_mb_create_and_cache (MonoMethod *key, MonoMethodBuilder *mb,
 {
        MonoMethod **res = NULL;
        MonoRemotingMethods *wrps;
-       GHashTable *cache = get_cache (&key->klass->image->remoting_invoke_cache, mono_aligned_addr_hash, NULL);
+       GHashTable *cache = get_cache_full (&key->klass->image->remoting_invoke_cache, mono_aligned_addr_hash, NULL, NULL, g_free);
 
        mono_marshal_lock ();
        wrps = g_hash_table_lookup (cache, key);
@@ -3959,6 +4028,8 @@ mono_marshal_get_delegate_invoke (MonoMethod *method, MonoDelegate *del)
                        res = newm;
                        new_key = g_new0 (SignatureMethodPair, 1);
                        *new_key = key;
+                       if (static_method_with_first_arg_bound)
+                               new_key->sig = signature_dup (del->method->klass->image, key.sig);
                        g_hash_table_insert (cache, new_key, res);
                        mono_marshal_set_wrapper_info (res, new_key);
                        mono_marshal_unlock ();
@@ -3992,7 +4063,7 @@ signature_dup_add_this (MonoMethodSignature *sig, MonoClass *klass)
        res->hasthis = FALSE;
        for (i = sig->param_count - 1; i >= 0; i --)
                res->params [i + 1] = sig->params [i];
-       res->params [0] = &mono_ptr_class_get (&klass->byval_arg)->byval_arg;
+       res->params [0] = klass->valuetype ? &klass->this_arg : &klass->byval_arg;
 
        return res;
 }
@@ -4428,6 +4499,7 @@ mono_marshal_get_runtime_invoke (MonoMethod *method, gboolean virtual)
        static MonoMethodSignature *cctor_signature = NULL;
        static MonoMethodSignature *finalize_signature = NULL;
        char *name;
+       const char *param_names [16];
        gboolean need_direct_wrapper = FALSE;
 
        g_assert (method);
@@ -4539,11 +4611,22 @@ mono_marshal_get_runtime_invoke (MonoMethod *method, gboolean virtual)
        csig->params [1] = &mono_defaults.int_class->byval_arg;
        csig->params [2] = &mono_defaults.int_class->byval_arg;
        csig->params [3] = &mono_defaults.int_class->byval_arg;
+       csig->pinvoke = 1;
+#if TARGET_WIN32
+       /* This is called from runtime code so it has to be cdecl */
+       csig->call_convention = MONO_CALL_C;
+#endif
 
        name = mono_signature_to_name (callsig, virtual ? "runtime_invoke_virtual" : "runtime_invoke");
        mb = mono_mb_new (target_klass, name,  MONO_WRAPPER_RUNTIME_INVOKE);
        g_free (name);
 
+       param_names [0] = "this";
+       param_names [1] = "params";
+       param_names [2] = "exc";
+       param_names [3] = "method";
+       mono_mb_set_param_names (mb, param_names);
+
        emit_runtime_invoke_body (mb, target_klass, method, sig, callsig, virtual, need_direct_wrapper);
 
        if (need_direct_wrapper) {
@@ -5313,7 +5396,7 @@ emit_marshal_custom (EmitMarshalContext *m, int argnum, MonoType *t,
        static MonoClass *ICustomMarshaler = NULL;
        static MonoMethod *cleanup_native, *cleanup_managed;
        static MonoMethod *marshal_managed_to_native, *marshal_native_to_managed;
-       MonoMethod *get_instance;
+       MonoMethod *get_instance = NULL;
        MonoMethodBuilder *mb = m->mb;
        char *exception_msg = NULL;
        guint32 loc1;
@@ -5321,7 +5404,10 @@ emit_marshal_custom (EmitMarshalContext *m, int argnum, MonoType *t,
 
        if (!ICustomMarshaler) {
                ICustomMarshaler = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "ICustomMarshaler");
-               g_assert (ICustomMarshaler);
+               if (!ICustomMarshaler) {
+                       exception_msg = g_strdup ("Current profile doesn't support ICustomMarshaler");
+                       goto handle_exception;
+               }
 
                cleanup_native = mono_class_get_method_from_name (ICustomMarshaler, "CleanUpNativeData", 1);
                g_assert (cleanup_native);
@@ -5353,6 +5439,7 @@ emit_marshal_custom (EmitMarshalContext *m, int argnum, MonoType *t,
        if (!get_instance)
                exception_msg = g_strdup_printf ("Custom marshaler '%s' does not implement a static GetInstance method that takes a single string parameter and returns an ICustomMarshaler.", mklass->name);
 
+handle_exception:
        /* Throw exception and emit compensation code if neccesary */
        if (exception_msg) {
                switch (action) {
@@ -5977,7 +6064,27 @@ emit_marshal_string (EmitMarshalContext *m, int argnum, MonoType *t,
                        break;
                }
 
-               if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT)) {
+               if (encoding == MONO_NATIVE_VBBYREFSTR) {
+                       static MonoMethod *m;
+
+                       if (!m) {
+                               m = mono_class_get_method_from_name_flags (mono_defaults.string_class, "get_Length", -1, 0);
+                               g_assert (m);
+                       }
+
+                       /* 
+                        * Have to allocate a new string with the same length as the original, and
+                        * copy the contents of the buffer pointed to by CONV_ARG into it.
+                        */
+                       g_assert (t->byref);
+                       mono_mb_emit_ldarg (mb, argnum);
+                       mono_mb_emit_ldloc (mb, conv_arg);
+                       mono_mb_emit_ldarg (mb, argnum);
+                       mono_mb_emit_byte (mb, CEE_LDIND_I);                            
+                       mono_mb_emit_managed_call (mb, m, NULL);
+                       mono_mb_emit_icall (mb, mono_string_new_len_wrapper);
+                       mono_mb_emit_byte (mb, CEE_STIND_REF);
+               } else if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT)) {
                        mono_mb_emit_ldarg (mb, argnum);
                        mono_mb_emit_ldloc (mb, conv_arg);
                        mono_mb_emit_icall (mb, conv_to_icall (conv));
@@ -5994,7 +6101,7 @@ emit_marshal_string (EmitMarshalContext *m, int argnum, MonoType *t,
                break;
 
        case MARSHAL_ACTION_PUSH:
-               if (t->byref)
+               if (t->byref && encoding != MONO_NATIVE_VBBYREFSTR)
                        mono_mb_emit_ldloc_addr (mb, conv_arg);
                else
                        mono_mb_emit_ldloc (mb, conv_arg);
@@ -6183,7 +6290,7 @@ emit_marshal_safehandle (EmitMarshalContext *m, int argnum, MonoType *t,
                
                if (t->data.klass->flags & TYPE_ATTRIBUTE_ABSTRACT){
                        mono_mb_emit_byte (mb, CEE_POP);
-                       mono_mb_emit_exception_marshal_directive (mb, "Returned SafeHandles should not be abstract");
+                       mono_mb_emit_exception_marshal_directive (mb, g_strdup ("Returned SafeHandles should not be abstract"));
                        break;
                }
 
@@ -6243,8 +6350,8 @@ emit_marshal_handleref (EmitMarshalContext *m, int argnum, MonoType *t,
                *conv_arg_type = intptr_type;
 
                if (t->byref){
-                       mono_mb_emit_exception_marshal_directive (mb,
-                               "HandleRefs can not be returned from unmanaged code (or passed by ref)");
+                       char *msg = g_strdup ("HandleRefs can not be returned from unmanaged code (or passed by ref)");
+                       mono_mb_emit_exception_marshal_directive (mb, msg);
                        break;
                } 
                mono_mb_emit_ldarg_addr (mb, argnum);
@@ -6265,8 +6372,8 @@ emit_marshal_handleref (EmitMarshalContext *m, int argnum, MonoType *t,
        }
                
        case MARSHAL_ACTION_CONV_RESULT: {
-               mono_mb_emit_exception_marshal_directive (mb,
-                       "HandleRefs can not be returned from unmanaged code (or passed by ref)");
+               char *msg = g_strdup ("HandleRefs can not be returned from unmanaged code (or passed by ref)");
+               mono_mb_emit_exception_marshal_directive (mb, msg);
                break;
        }
                
@@ -6522,7 +6629,7 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t,
                                }
 
                                mono_mb_emit_ldloc (mb, conv_arg);
-                               mono_mb_emit_icall (mb, g_free);
+                               mono_mb_emit_icall (mb, mono_marshal_free);
 
                                mono_mb_patch_branch (mb, pos2);
                        }
@@ -6584,7 +6691,7 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t,
        
                        /* Free the pointer allocated by unmanaged code */
                        mono_mb_emit_ldloc (mb, loc);
-                       mono_mb_emit_icall (mb, g_free);
+                       mono_mb_emit_icall (mb, mono_marshal_free);
                        mono_mb_patch_branch (mb, pos);
                }
                break;
@@ -6882,6 +6989,24 @@ emit_marshal_variant (EmitMarshalContext *m, int argnum, MonoType *t,
        return conv_arg;
 }
 
+static gboolean
+mono_pinvoke_is_unicode (MonoMethodPInvoke *piinfo)
+{
+       switch (piinfo->piflags & PINVOKE_ATTRIBUTE_CHAR_SET_MASK) {
+       case PINVOKE_ATTRIBUTE_CHAR_SET_ANSI:
+               return FALSE;
+       case PINVOKE_ATTRIBUTE_CHAR_SET_UNICODE:
+               return TRUE;
+       case PINVOKE_ATTRIBUTE_CHAR_SET_AUTO:
+       default:
+#ifdef TARGET_WIN32
+               return TRUE;
+#else
+               return FALSE;
+#endif
+       }
+}
+
 static int
 emit_marshal_array (EmitMarshalContext *m, int argnum, MonoType *t,
                                        MonoMarshalSpec *spec, 
@@ -6952,6 +7077,8 @@ emit_marshal_array (EmitMarshalContext *m, int argnum, MonoType *t,
 
                        if (is_string)
                                esize = sizeof (gpointer);
+                       else if (eklass == mono_defaults.char_class) /*can't call mono_marshal_type_size since it causes all sorts of asserts*/
+                               esize = mono_pinvoke_is_unicode (m->piinfo) ? 2 : 1;
                        else
                                esize = mono_class_native_size (eklass, NULL);
 
@@ -7004,7 +7131,7 @@ emit_marshal_array (EmitMarshalContext *m, int argnum, MonoType *t,
                                mono_mb_emit_stloc (mb, 1);
 
                                /* emit valuetype conversion code */
-                               emit_struct_conv (mb, eklass, FALSE);
+                               emit_struct_conv_full (mb, eklass, FALSE, eklass == mono_defaults.char_class ? encoding : -1);
                        }
 
                        mono_mb_emit_add_to_local (mb, index_var, 1);
@@ -7041,6 +7168,8 @@ emit_marshal_array (EmitMarshalContext *m, int argnum, MonoType *t,
                        eklass = klass->element_class;
                        if ((eklass == mono_defaults.stringbuilder_class) || (eklass == mono_defaults.string_class))
                                esize = sizeof (gpointer);
+                       else if (eklass == mono_defaults.char_class)
+                               esize = mono_pinvoke_is_unicode (m->piinfo) ? 2 : 1;
                        else
                                esize = mono_class_native_size (eklass, NULL);
                        src_ptr = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
@@ -7120,7 +7249,7 @@ emit_marshal_array (EmitMarshalContext *m, int argnum, MonoType *t,
                                        mono_mb_emit_stloc (mb, 1);
 
                                        /* emit valuetype conversion code */
-                                       emit_struct_conv (mb, eklass, TRUE);
+                                       emit_struct_conv_full (mb, eklass, TRUE, eklass == mono_defaults.char_class ? encoding : -1);
                                }
 
                                if (need_free) {
@@ -7484,6 +7613,8 @@ emit_marshal_array (EmitMarshalContext *m, int argnum, MonoType *t,
 
                if (is_string)
                        esize = sizeof (gpointer);
+               else if (eklass == mono_defaults.char_class)
+                       esize = mono_pinvoke_is_unicode (m->piinfo) ? 2 : 1;
                else
                        esize = mono_class_native_size (eklass, NULL);
 
@@ -7758,10 +7889,13 @@ emit_marshal_ptr (EmitMarshalContext *m, int argnum, MonoType *t,
 
        switch (action) {
        case MARSHAL_ACTION_CONV_IN:
+               /* MS seems to allow this in some cases, ie. bxc #158 */
+               /*
                if (MONO_TYPE_ISSTRUCT (t->data.type) && !mono_class_from_mono_type (t->data.type)->blittable) {
                        char *msg = g_strdup_printf ("Can not marshal 'parameter #%d': Pointers can not reference marshaled structures. Use byref instead.", argnum + 1);
                        mono_mb_emit_exception_marshal_directive (m->mb, msg);
                }
+               */
                break;
 
        case MARSHAL_ACTION_PUSH:
@@ -8577,6 +8711,7 @@ mono_marshal_set_callconv_from_modopt (MonoMethod *method, MonoMethodSignature *
 
 /*
  * generates IL code to call managed methods from unmanaged code 
+ * If target_handle==0, the wrapper info will be a NativeToManagedWrapperInfo structure.
  */
 MonoMethod *
 mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass, uint32_t target_handle)
@@ -8711,10 +8846,17 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass,
 
        mono_marshal_emit_managed_wrapper (mb, invoke_sig, mspecs, &m, method, target_handle);
 
-       if (!target_handle)
+       if (!target_handle) {
+               NativeToManagedWrapperInfo *info;
+
                res = mono_mb_create_and_cache (cache, method,
                                                                                         mb, csig, sig->param_count + 16);
-       else {
+               // FIXME: Associate it with the method+delegate_klass pair
+               info = mono_image_alloc0 (method->klass->image, sizeof (NativeToManagedWrapperInfo));
+               info->method = method;
+               info->klass = delegate_klass;
+               mono_marshal_set_wrapper_info (res, info);
+       } else {
                mb->dynamic = 1;
                res = mono_mb_create_method (mb, csig, sig->param_count + 16);
        }
@@ -8817,7 +8959,7 @@ type_from_handle (MonoType *handle)
 }
 
 /*
- * This does the equivalent of mono_object_variant_castclass.
+ * This does the equivalent of mono_object_castclass_with_cache.
  */
 MonoMethod *
 mono_marshal_get_castclass_with_cache (void)
@@ -8853,7 +8995,7 @@ mono_marshal_get_castclass_with_cache (void)
        mono_mb_emit_stloc (mb, 0);
 
        /* *cache */
-       mono_mb_emit_ldarg (mb, 1);
+       mono_mb_emit_ldarg (mb, 2);
        mono_mb_emit_byte (mb, CEE_LDIND_I);
        mono_mb_emit_ldloc (mb, 0);
 
@@ -8872,7 +9014,7 @@ mono_marshal_get_castclass_with_cache (void)
        invalid_cast_pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
 
        /**cache = obj_vtable;*/
-       mono_mb_emit_ldarg (mb, 1);
+       mono_mb_emit_ldarg (mb, 2);
        mono_mb_emit_ldloc (mb, 0);
        mono_mb_emit_byte (mb, CEE_STIND_I);
 
@@ -8890,6 +9032,8 @@ mono_marshal_get_castclass_with_cache (void)
        mono_mb_emit_byte (mb, CEE_RET);
 
        res = mono_mb_create_method (mb, sig, 8);
+       STORE_STORE_FENCE;
+
        if (InterlockedCompareExchangePointer ((volatile gpointer *)&cached, res, NULL)) {
                mono_free_method (res);
                mono_metadata_free_method_signature (sig);
@@ -8900,7 +9044,7 @@ mono_marshal_get_castclass_with_cache (void)
 }
 
 /*
- * This does the equivalent of mono_object_variant_isinst.
+ * This does the equivalent of mono_object_isinst_with_cache.
  */
 MonoMethod *
 mono_marshal_get_isinst_with_cache (void)
@@ -8914,7 +9058,7 @@ mono_marshal_get_isinst_with_cache (void)
        if (cached)
                return cached;
 
-       mb = mono_mb_new (mono_defaults.object_class, "__isisnt_with_cache", MONO_WRAPPER_CASTCLASS);
+       mb = mono_mb_new (mono_defaults.object_class, "__isinst_with_cache", MONO_WRAPPER_CASTCLASS);
        sig = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
        sig->params [0] = &mono_defaults.object_class->byval_arg;
        sig->params [1] = &mono_defaults.int_class->byval_arg;
@@ -8938,7 +9082,7 @@ mono_marshal_get_isinst_with_cache (void)
        mono_mb_emit_stloc (mb, 0);
 
        /* cached_vtable = *cache*/
-       mono_mb_emit_ldarg (mb, 1);
+       mono_mb_emit_ldarg (mb, 2);
        mono_mb_emit_byte (mb, CEE_LDIND_I);
        mono_mb_emit_stloc (mb, 1);
 
@@ -8977,7 +9121,7 @@ mono_marshal_get_isinst_with_cache (void)
        not_an_instance_pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
 
        /**cache = obj_vtable;*/
-       mono_mb_emit_ldarg (mb, 1);
+       mono_mb_emit_ldarg (mb, 2);
        mono_mb_emit_ldloc (mb, 0);
        mono_mb_emit_byte (mb, CEE_STIND_I);
 
@@ -8988,9 +9132,9 @@ mono_marshal_get_isinst_with_cache (void)
        /*not an instance*/
        mono_mb_patch_branch (mb, not_an_instance_pos);
        /* *cache = (gpointer)(obj_vtable | 0x1);*/
-       mono_mb_emit_ldarg (mb, 1);
+       mono_mb_emit_ldarg (mb, 2);
        /*obj_vtable | 0x1*/
-       mono_mb_emit_ldloc (mb, 1);
+       mono_mb_emit_ldloc (mb, 0);
        mono_mb_emit_byte(mb, CEE_LDC_I4_1);
        mono_mb_emit_byte (mb, CEE_CONV_U);
        mono_mb_emit_byte (mb, CEE_OR);
@@ -9004,6 +9148,8 @@ mono_marshal_get_isinst_with_cache (void)
        mono_mb_emit_byte (mb, CEE_RET);
 
        res = mono_mb_create_method (mb, sig, 8);
+       STORE_STORE_FENCE;
+
        if (InterlockedCompareExchangePointer ((volatile gpointer *)&cached, res, NULL)) {
                mono_free_method (res);
                mono_metadata_free_method_signature (sig);
@@ -9174,7 +9320,7 @@ mono_marshal_get_proxy_cancast (MonoClass *klass)
        GHashTable *cache;
        MonoMethod *res;
        int pos_failed, pos_end;
-       char *name;
+       char *name, *klass_name;
        MonoMethod *can_cast_to;
        MonoMethodDesc *desc;
        MonoMethodBuilder *mb;
@@ -9189,9 +9335,11 @@ mono_marshal_get_proxy_cancast (MonoClass *klass)
                isint_sig->ret = &mono_defaults.object_class->byval_arg;
                isint_sig->pinvoke = 0;
        }
-       
-       name = g_strdup_printf ("__proxy_isinst_wrapper_%s", klass->name); 
+
+       klass_name = mono_type_full_name (&klass->byval_arg);
+       name = g_strdup_printf ("__proxy_isinst_wrapper_%s", klass_name); 
        mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_PROXY_ISINST);
+       g_free (klass_name);
        g_free (name);
        
        mb->method->save_lmf = 1;
@@ -9593,8 +9741,13 @@ get_virtual_stelemref_kind (MonoClass *element_class)
                return STELEMREF_OBJECT;
        if (is_monomorphic_array (element_class))
                return STELEMREF_SEALED_CLASS;
+       /* Compressed interface bitmaps require code that is quite complex, so don't optimize for it. */
        if (MONO_CLASS_IS_INTERFACE (element_class) && !mono_class_has_variant_generic_params (element_class))
+#ifdef COMPRESSED_INTERFACE_BITMAP
+               return STELEMREF_COMPLEX;
+#else
                return STELEMREF_INTERFACE;
+#endif
        /*Arrays are sealed but are covariant on their element type, We can't use any of the fast paths.*/
        if (element_class->marshalbyref || element_class->rank || mono_class_has_variant_generic_params (element_class))
                return STELEMREF_COMPLEX;
@@ -9662,7 +9815,8 @@ mono_marshal_get_virtual_stelemref (MonoClass *array_class)
        MonoMethodBuilder *mb;
        MonoMethod *res;
        int kind;
-
+       char *name;
+       const char *param_names [16];
        guint32 b1, b2, b3;
        int aklass, vklass, vtable, uiid;
        int array_slot_addr;
@@ -9673,7 +9827,13 @@ mono_marshal_get_virtual_stelemref (MonoClass *array_class)
        if (cached_methods [kind])
                return cached_methods [kind];
 
-       mb = mono_mb_new_no_dup_name (mono_defaults.object_class, g_strdup_printf ("virt_stelemref_%s", strelemref_wrapper_name [kind]), MONO_WRAPPER_STELEMREF);
+       name = g_strdup_printf ("virt_stelemref_%s", strelemref_wrapper_name [kind]);
+       mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_STELEMREF);
+       g_free (name);
+
+       param_names [0] = "index";
+       param_names [1] = "value";
+       mono_mb_set_param_names (mb, param_names);
 
        if (!signature) {
                MonoMethodSignature *sig = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
@@ -9957,7 +10117,7 @@ mono_marshal_get_virtual_stelemref (MonoClass *array_class)
                mono_mb_emit_ldloc (mb, uiid);
                mono_mb_emit_ldloc (mb, vtable);
                mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoVTable, max_interface_id));
-               mono_mb_emit_byte (mb, CEE_LDIND_I);
+               mono_mb_emit_byte (mb, CEE_LDIND_U2);
                b2 = mono_mb_emit_branch (mb, CEE_BGT_UN);
 
                /* if (!(vt->interface_bitmap [(uiid) >> 3] & (1 << ((uiid)&7)))) */
@@ -10012,10 +10172,18 @@ mono_marshal_get_virtual_stelemref (MonoClass *array_class)
        res = mono_mb_create_method (mb, signature, 4);
        res->flags |= METHOD_ATTRIBUTE_VIRTUAL;
        mono_marshal_set_wrapper_info (res, GUINT_TO_POINTER (kind + 1));
-       cached_methods [kind] = res;
+
+       mono_marshal_lock ();
+       if (!cached_methods [kind]) {
+               cached_methods [kind] = res;
+               mono_marshal_unlock ();
+       } else {
+               mono_marshal_unlock ();
+               mono_free_method (res);
+       }
 
        mono_mb_free (mb);
-       return res;
+       return cached_methods [kind];
 }
 
 MonoMethod*
@@ -10322,6 +10490,7 @@ mono_marshal_get_array_address (int rank, int elem_size)
                elem_addr_cache [elem_addr_cache_next].rank = rank;
                elem_addr_cache [elem_addr_cache_next].elem_size = elem_size;
                elem_addr_cache [elem_addr_cache_next].method = ret;
+               elem_addr_cache_next ++;
 
                info = mono_image_alloc0 (mono_defaults.corlib, sizeof (ElementAddrWrapperInfo));
                info->rank = rank;
@@ -10400,9 +10569,9 @@ void
 mono_marshal_set_last_error (void)
 {
 #ifdef WIN32
-       TlsSetValue (last_error_tls_id, GINT_TO_POINTER (GetLastError ()));
+       mono_native_tls_set_value (last_error_tls_id, GINT_TO_POINTER (GetLastError ()));
 #else
-       TlsSetValue (last_error_tls_id, GINT_TO_POINTER (errno));
+       mono_native_tls_set_value (last_error_tls_id, GINT_TO_POINTER (errno));
 #endif
 }
 
@@ -10410,7 +10579,7 @@ static void
 mono_marshal_set_last_error_windows (int error)
 {
 #ifdef WIN32
-       TlsSetValue (last_error_tls_id, GINT_TO_POINTER (error));
+       mono_native_tls_set_value (last_error_tls_id, GINT_TO_POINTER (error));
 #endif
 }
 
@@ -10652,7 +10821,7 @@ ves_icall_System_Runtime_InteropServices_Marshal_GetLastWin32Error (void)
 {
        MONO_ARCH_SAVE_REGS;
 
-       return (GPOINTER_TO_INT (TlsGetValue (last_error_tls_id)));
+       return (GPOINTER_TO_INT (mono_native_tls_get_value (last_error_tls_id)));
 }
 
 guint32 
@@ -11052,7 +11221,7 @@ ves_icall_System_Runtime_InteropServices_Marshal_GetDelegateForFunctionPointerIn
 static gboolean
 mono_marshal_is_loading_type_info (MonoClass *klass)
 {
-       GSList *loads_list = TlsGetValue (load_type_info_tls_id);
+       GSList *loads_list = mono_native_tls_get_value (load_type_info_tls_id);
 
        return g_slist_find (loads_list, klass) != NULL;
 }
@@ -11097,9 +11266,9 @@ mono_marshal_load_type_info (MonoClass* klass)
         * under initialization in a TLS list.
         */
        g_assert (!mono_marshal_is_loading_type_info (klass));
-       loads_list = TlsGetValue (load_type_info_tls_id);
+       loads_list = mono_native_tls_get_value (load_type_info_tls_id);
        loads_list = g_slist_prepend (loads_list, klass);
-       TlsSetValue (load_type_info_tls_id, loads_list);
+       mono_native_tls_set_value (load_type_info_tls_id, loads_list);
        
        iter = NULL;
        while ((field = mono_class_get_fields (klass, &iter))) {
@@ -11201,9 +11370,9 @@ mono_marshal_load_type_info (MonoClass* klass)
                mono_marshal_load_type_info (klass->element_class);
        }
 
-       loads_list = TlsGetValue (load_type_info_tls_id);
+       loads_list = mono_native_tls_get_value (load_type_info_tls_id);
        loads_list = g_slist_remove (loads_list, klass);
-       TlsSetValue (load_type_info_tls_id, loads_list);
+       mono_native_tls_set_value (load_type_info_tls_id, loads_list);
 
        /*We do double-checking locking on marshal_info */
        mono_memory_barrier ();