Merge pull request #1936 from esdrubal/DotNetRelativeOrAbsolute
[mono.git] / mono / metadata / marshal.c
index bbaa745266baa7b543c614707ae6c3b855ddd5c0..4c6ae67820d24b42774f5805cb50cda488060a20 100644 (file)
@@ -25,9 +25,9 @@
 #include "metadata/appdomain.h"
 #include "mono/metadata/abi-details.h"
 #include "mono/metadata/debug-helpers.h"
-#include "mono/metadata/threadpool.h"
 #include "mono/metadata/threads.h"
 #include "mono/metadata/monitor.h"
+#include "mono/metadata/class-internals.h"
 #include "mono/metadata/metadata-internals.h"
 #include "mono/metadata/domain-internals.h"
 #include "mono/metadata/gc-internal.h"
@@ -38,6 +38,7 @@
 #include "mono/metadata/cominterop.h"
 #include "mono/metadata/remoting.h"
 #include "mono/metadata/reflection-internals.h"
+#include "mono/metadata/threadpool-ms.h"
 #include "mono/utils/mono-counters.h"
 #include "mono/utils/mono-tls.h"
 #include "mono/utils/mono-memory-model.h"
@@ -133,6 +134,9 @@ mono_delegate_end_invoke (MonoDelegate *delegate, gpointer *params);
 static void
 mono_marshal_set_last_error_windows (int error);
 
+static MonoObject *
+mono_marshal_isinst_with_cache (MonoObject *obj, MonoClass *klass, uintptr_t *cache);
+
 static void init_safe_handle (void);
 
 /* MonoMethod pointers to SafeHandle::DangerousAddRef and ::DangerousRelease */
@@ -157,25 +161,12 @@ register_icall (gpointer func, const char *name, const char *sigstr, gboolean sa
        mono_register_jit_icall (func, name, sig, save);
 }
 
-static MonoMethodSignature*
-signature_dup (MonoImage *image, MonoMethodSignature *sig)
-{
-       MonoMethodSignature *res;
-       int sigsize;
-
-       res = mono_metadata_signature_alloc (image, sig->param_count);
-       sigsize = MONO_SIZEOF_METHOD_SIGNATURE + sig->param_count * sizeof (MonoType *);
-       memcpy (res, sig, sigsize);
-
-       return res;
-}
-
 MonoMethodSignature*
 mono_signature_no_pinvoke (MonoMethod *method)
 {
        MonoMethodSignature *sig = mono_method_signature (method);
        if (sig->pinvoke) {
-               sig = signature_dup (method->klass->image, sig);
+               sig = mono_metadata_signature_dup_full (method->klass->image, sig);
                sig->pinvoke = FALSE;
        }
        
@@ -245,6 +236,7 @@ mono_marshal_init (void)
                register_icall (mono_context_set, "mono_context_set", "void object", FALSE);
                register_icall (mono_gc_wbarrier_generic_nostore, "wb_generic", "void ptr", FALSE);
                register_icall (mono_gchandle_get_target, "mono_gchandle_get_target", "object int32", TRUE);
+               register_icall (mono_marshal_isinst_with_cache, "mono_marshal_isinst_with_cache", "object object ptr ptr", FALSE);
 
                mono_cominterop_init ();
                mono_remoting_init ();
@@ -252,8 +244,8 @@ mono_marshal_init (void)
 #ifdef USE_COOP_GC
                register_icall (mono_threads_prepare_blocking, "mono_threads_prepare_blocking", "int", FALSE);
                register_icall (mono_threads_finish_blocking, "mono_threads_finish_blocking", "void int", FALSE);
-               register_icall (mono_threads_reset_blocking_start, "mono_threads_reset_blocking_start","int", FALSE);
-               register_icall (mono_threads_reset_blocking_end, "mono_threads_reset_blocking_end","void int", FALSE);
+               register_icall (mono_threads_reset_blocking_start, "mono_threads_reset_blocking_start","int", TRUE);
+               register_icall (mono_threads_reset_blocking_end, "mono_threads_reset_blocking_end","void int", TRUE);
 #endif
        }
 }
@@ -454,12 +446,12 @@ mono_ftnptr_to_delegate (MonoClass *klass, gpointer ftn)
                MonoMarshalSpec **mspecs;
                MonoMethod *invoke = mono_get_delegate_invoke (klass);
                MonoMethodPInvoke piinfo;
-               MonoObject *this;
+               MonoObject *this_obj;
                int i;
 
                if (use_aot_wrappers) {
                        wrapper = mono_marshal_get_native_func_wrapper_aot (klass);
-                       this = mono_value_box (mono_domain_get (), mono_defaults.int_class, &ftn);
+                       this_obj = mono_value_box (mono_domain_get (), mono_defaults.int_class, &ftn);
                } else {
                        memset (&piinfo, 0, sizeof (piinfo));
                        parse_unmanaged_function_pointer_attr (klass, &piinfo);
@@ -471,7 +463,7 @@ mono_ftnptr_to_delegate (MonoClass *klass, gpointer ftn)
                        sig->hasthis = 0;
 
                        wrapper = mono_marshal_get_native_func_wrapper (klass->image, sig, &piinfo, mspecs, ftn);
-                       this = NULL;
+                       this_obj = NULL;
 
                        for (i = mono_method_signature (invoke)->param_count; i >= 0; i--)
                                if (mspecs [i])
@@ -481,7 +473,7 @@ mono_ftnptr_to_delegate (MonoClass *klass, gpointer ftn)
                }
 
                d = (MonoDelegate*)mono_object_new (mono_domain_get (), klass);
-               mono_delegate_ctor_with_method ((MonoObject*)d, this, mono_compile_method (wrapper), wrapper);
+               mono_delegate_ctor_with_method ((MonoObject*)d, this_obj, mono_compile_method (wrapper), wrapper);
        }
 
        if (d->object.vtable->domain != mono_domain_get ())
@@ -714,29 +706,32 @@ mono_string_builder_new (int starting_string_length)
        if (initial_len < 0)
                initial_len = 0;
 
-       if (!string_builder_class) {
+       if (!sb_ctor) {
                MonoMethodDesc *desc;
+               MonoMethod *m;
 
                string_builder_class = mono_class_from_name (mono_defaults.corlib, "System.Text", "StringBuilder");
                g_assert (string_builder_class);
                desc = mono_method_desc_new (":.ctor(int)", FALSE);
-               sb_ctor = mono_method_desc_search_in_class (desc, string_builder_class);
-               g_assert (sb_ctor);
+               m = mono_method_desc_search_in_class (desc, string_builder_class);
+               g_assert (m);
                mono_method_desc_free (desc);
-
-               // We make a new array in the _to_builder function, so this
-               // array will always be garbage collected.
-               args [0] = &initial_len;
+               mono_memory_barrier ();
+               sb_ctor = m;
        }
 
+       // We make a new array in the _to_builder function, so this
+       // array will always be garbage collected.
+       args [0] = &initial_len;
+
        MonoStringBuilder *sb = (MonoStringBuilder*)mono_object_new (mono_domain_get (), string_builder_class);
        MonoObject *exc;
        g_assert (sb);
 
        mono_runtime_invoke (sb_ctor, sb, args, &exc);
+       g_assert (!exc);
 
        g_assert (sb->chunkChars->max_length >= initial_len);
-       g_assert (!exc);
 
        return sb;
 }
@@ -2052,17 +2047,13 @@ mono_marshal_emit_thread_force_interrupt_checkpoint (MonoMethodBuilder *mb)
 static MonoAsyncResult *
 mono_delegate_begin_invoke (MonoDelegate *delegate, gpointer *params)
 {
-       MonoMethodMessage *msg;
-       MonoDelegate *async_callback;
        MonoMulticastDelegate *mcast_delegate;
-       MonoObject *state;
-       MonoMethod *im;
        MonoClass *klass;
-       MonoMethod *method = NULL, *method2 = NULL;
+       MonoMethod *method;
 
        g_assert (delegate);
        mcast_delegate = (MonoMulticastDelegate *) delegate;
-       if (mcast_delegate->prev != NULL)
+       if (mcast_delegate->delegates != NULL)
                mono_raise_exception (mono_get_exception_argument (NULL, "The delegate must have only one target"));
 
 #ifndef DISABLE_REMOTING
@@ -2074,6 +2065,9 @@ mono_delegate_begin_invoke (MonoDelegate *delegate, gpointer *params)
                        /* If the target is a proxy, make a direct call. Is proxy's work
                        // to make the call asynchronous.
                        */
+                       MonoMethodMessage *msg;
+                       MonoDelegate *async_callback;
+                       MonoObject *state;
                        MonoAsyncResult *ares;
                        MonoObject *exc;
                        MonoArray *out_args;
@@ -2097,16 +2091,12 @@ mono_delegate_begin_invoke (MonoDelegate *delegate, gpointer *params)
 
        klass = delegate->object.vtable->klass;
 
-       method = mono_get_delegate_invoke (klass);
-       method2 = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
-       if (method2)
-               method = method2;
-       g_assert (method != NULL);
-
-       im = mono_get_delegate_invoke (method->klass);
-       msg = mono_method_call_message_new (method, params, im, &async_callback, &state);
+       method = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
+       if (!method)
+               method = mono_get_delegate_invoke (klass);
+       g_assert (method);
 
-       return mono_thread_pool_add ((MonoObject *)delegate, msg, async_callback, state);
+       return mono_threadpool_ms_begin_invoke (mono_domain_get (), (MonoObject*) delegate, method, params);
 }
 
 #ifndef DISABLE_JIT
@@ -2725,12 +2715,12 @@ mono_marshal_get_delegate_begin_invoke (MonoMethod *method)
         * Check cache
         */
        if (ctx) {
-               cache = get_cache (&method->klass->image->delegate_begin_invoke_generic_cache, mono_aligned_addr_hash, NULL);
+               cache = get_cache (&((MonoMethodInflated*)orig_method)->owner->wrapper_caches.delegate_begin_invoke_cache, mono_aligned_addr_hash, NULL);
                res = check_generic_delegate_wrapper_cache (cache, orig_method, method, ctx);
                if (res)
                        return res;
        } else {
-               cache = get_cache (&method->klass->image->delegate_begin_invoke_cache,
+               cache = get_cache (&method->klass->image->wrapper_caches.delegate_begin_invoke_cache,
                                                   (GHashFunc)mono_signature_hash, 
                                                   (GCompareFunc)mono_metadata_signature_equal);
                if ((res = mono_marshal_find_in_cache (cache, sig)))
@@ -2821,7 +2811,7 @@ mono_delegate_end_invoke (MonoDelegate *delegate, gpointer *params)
        } else
 #endif
        {
-               res = mono_thread_pool_finish (ares, &out_args, &exc);
+               res = mono_threadpool_ms_end_invoke (ares, &out_args, &exc);
        }
 
        if (exc) {
@@ -2935,12 +2925,12 @@ mono_marshal_get_delegate_end_invoke (MonoMethod *method)
         * Check cache
         */
        if (ctx) {
-               cache = get_cache (&method->klass->image->delegate_end_invoke_generic_cache, mono_aligned_addr_hash, NULL);
+               cache = get_cache (&((MonoMethodInflated*)orig_method)->owner->wrapper_caches.delegate_end_invoke_cache, mono_aligned_addr_hash, NULL);
                res = check_generic_delegate_wrapper_cache (cache, orig_method, method, ctx);
                if (res)
                        return res;
        } else {
-               cache = get_cache (&method->klass->image->delegate_end_invoke_cache,
+               cache = get_cache (&method->klass->image->wrapper_caches.delegate_end_invoke_cache,
                                                   (GHashFunc)mono_signature_hash, 
                                                   (GCompareFunc)mono_metadata_signature_equal);
                if ((res = mono_marshal_find_in_cache (cache, sig)))
@@ -3018,7 +3008,7 @@ free_signature_pointer_pair (SignaturePointerPair *pair)
        g_free (pair);
 }
 
-static MonoMethod *
+MonoMethod *
 mono_marshal_get_delegate_invoke_internal (MonoMethod *method, gboolean callvirt, gboolean static_method_with_first_arg_bound, MonoMethod *target_method)
 {
        MonoMethodSignature *sig, *static_sig, *invoke_sig;
@@ -3029,8 +3019,8 @@ mono_marshal_get_delegate_invoke_internal (MonoMethod *method, gboolean callvirt
        gpointer cache_key = NULL;
        SignaturePointerPair key;
        SignaturePointerPair *new_key;
-       int local_prev, local_target;
-       int pos0;
+       int local_i, local_len, local_delegates, local_d, local_target, local_res;
+       int pos0, pos1, pos2;
        char *name;
        MonoClass *target_class = NULL;
        gboolean closed_over_null = FALSE;
@@ -3040,6 +3030,7 @@ mono_marshal_get_delegate_invoke_internal (MonoMethod *method, gboolean callvirt
        WrapperInfo *info;
        WrapperSubtype subtype = WRAPPER_SUBTYPE_NONE;
        gboolean found;
+       gboolean void_ret;
 
        g_assert (method && method->klass->parent == mono_defaults.multicastdelegate_class &&
                  !strcmp (method->name, "Invoke"));
@@ -3093,7 +3084,7 @@ mono_marshal_get_delegate_invoke_internal (MonoMethod *method, gboolean callvirt
         * Check cache
         */
        if (ctx) {
-               cache = get_cache (&method->klass->image->delegate_invoke_generic_cache, mono_aligned_addr_hash, NULL);
+               cache = get_cache (&((MonoMethodInflated*)orig_method)->owner->wrapper_caches.delegate_invoke_cache, mono_aligned_addr_hash, NULL);
                res = check_generic_delegate_wrapper_cache (cache, orig_method, method, ctx);
                if (res)
                        return res;
@@ -3112,7 +3103,7 @@ mono_marshal_get_delegate_invoke_internal (MonoMethod *method, gboolean callvirt
        } else if (callvirt) {
                GHashTable **cache_ptr;
 
-               cache_ptr = &method->klass->image->delegate_abstract_invoke_cache;
+               cache_ptr = &mono_method_get_wrapper_cache (method)->delegate_abstract_invoke_cache;
 
                /* We need to cache the signature+method pair */
                mono_marshal_lock ();
@@ -3126,7 +3117,9 @@ mono_marshal_get_delegate_invoke_internal (MonoMethod *method, gboolean callvirt
                if (res)
                        return res;
        } else {
-               cache = get_cache (&method->klass->image->delegate_invoke_cache,
+               // Inflated methods should not be in this cache because it's not stored on the imageset.
+               g_assert (!method->is_inflated);
+               cache = get_cache (&method->klass->image->wrapper_caches.delegate_invoke_cache,
                                                   (GHashFunc)mono_signature_hash, 
                                                   (GCompareFunc)mono_metadata_signature_equal);
                res = mono_marshal_find_in_cache (cache, sig);
@@ -3135,7 +3128,7 @@ mono_marshal_get_delegate_invoke_internal (MonoMethod *method, gboolean callvirt
                cache_key = sig;
        }
 
-       static_sig = signature_dup (method->klass->image, sig);
+       static_sig = mono_metadata_signature_dup_full (method->klass->image, sig);
        static_sig->hasthis = 0;
        if (!static_method_with_first_arg_bound)
                invoke_sig = static_sig;
@@ -3155,53 +3148,50 @@ mono_marshal_get_delegate_invoke_internal (MonoMethod *method, gboolean callvirt
        g_free (name);
 
 #ifndef DISABLE_JIT
+       void_ret = sig->ret->type == MONO_TYPE_VOID && !method->string_ctor;
+
        /* allocate local 0 (object) */
+       local_i = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
+       local_len = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
+       local_delegates = mono_mb_add_local (mb, &mono_defaults.array_class->byval_arg);
+       local_d = mono_mb_add_local (mb, &mono_defaults.multicastdelegate_class->byval_arg);
        local_target = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
-       local_prev = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
+
+       if (!void_ret)
+               local_res = mono_mb_add_local (mb, &mono_class_from_mono_type (sig->ret)->byval_arg);
 
        g_assert (sig->hasthis);
-       
+
        /*
-        * if (prev != null)
-         *     prev.Invoke( args .. );
-        * return this.<target>( args .. );
-         */
-       
+        * {type: sig->ret} res;
+        * if (delegates == null) {
+        *     return this.<target> ( args .. );
+        * } else {
+        *     int i = 0, len = this.delegates.Length;
+        *     do {
+        *         res = this.delegates [i].Invoke ( args .. );
+        *     } while (++i < len);
+        *     return res;
+        * }
+        */
+
        /* this wrapper can be used in unmanaged-managed transitions */
        emit_thread_interrupt_checkpoint (mb);
-       
-       /* get this->prev */
+
+       /* delegates = this.delegates */
        mono_mb_emit_ldarg (mb, 0);
-       mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoMulticastDelegate, prev));
+       mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoMulticastDelegate, delegates));
        mono_mb_emit_byte (mb, CEE_LDIND_REF);
-       mono_mb_emit_stloc (mb, local_prev);
-       mono_mb_emit_ldloc (mb, local_prev);
+       mono_mb_emit_stloc (mb, local_delegates);
 
-       /* if prev != null */
-       pos0 = mono_mb_emit_branch (mb, CEE_BRFALSE);
 
-       /* then recurse */
+       /* if (delegates == null) */
+       mono_mb_emit_ldloc (mb, local_delegates);
+       pos2 = mono_mb_emit_branch (mb, CEE_BRTRUE);
 
-       mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
-       mono_mb_emit_byte (mb, CEE_MONO_NOT_TAKEN);
+       /* return target.<target_method|method_ptr> ( args .. ); */
 
-       mono_mb_emit_ldloc (mb, local_prev);
-       for (i = 0; i < sig->param_count; i++)
-               mono_mb_emit_ldarg (mb, i + 1);
-       if (ctx) {
-               MonoError error;
-               mono_mb_emit_op (mb, CEE_CALLVIRT, mono_class_inflate_generic_method_checked (method, &container->context, &error));
-               g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
-       } else {
-               mono_mb_emit_op (mb, CEE_CALLVIRT, method);
-       }
-       if (sig->ret->type != MONO_TYPE_VOID)
-               mono_mb_emit_byte (mb, CEE_POP);
-
-       /* continued or prev == null */
-       mono_mb_patch_branch (mb, pos0);
-
-       /* get this->target */
+       /* target = d.target; */
        mono_mb_emit_ldarg (mb, 0);
        mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoDelegate, target));
        mono_mb_emit_byte (mb, CEE_LDIND_REF);
@@ -3235,11 +3225,18 @@ mono_marshal_get_delegate_invoke_internal (MonoMethod *method, gboolean callvirt
 
        if (callvirt) {
                if (!closed_over_null) {
-                       mono_mb_emit_ldarg (mb, 1);
-                       mono_mb_emit_op (mb, CEE_CASTCLASS, target_class);
-                       for (i = 1; i < sig->param_count; ++i)
-                               mono_mb_emit_ldarg (mb, i + 1);
-                       mono_mb_emit_op (mb, CEE_CALLVIRT, target_method);
+                       if (target_class->valuetype) {
+                               mono_mb_emit_ldarg (mb, 1);
+                               for (i = 1; i < sig->param_count; ++i)
+                                       mono_mb_emit_ldarg (mb, i + 1);
+                               mono_mb_emit_op (mb, CEE_CALL, target_method);
+                       } else {
+                               mono_mb_emit_ldarg (mb, 1);
+                               mono_mb_emit_op (mb, CEE_CASTCLASS, target_class);
+                               for (i = 1; i < sig->param_count; ++i)
+                                       mono_mb_emit_ldarg (mb, i + 1);
+                               mono_mb_emit_op (mb, CEE_CALLVIRT, target_method);
+                       }
                } else {
                        mono_mb_emit_byte (mb, CEE_LDNULL);
                        for (i = 0; i < sig->param_count; ++i)
@@ -3262,6 +3259,54 @@ mono_marshal_get_delegate_invoke_internal (MonoMethod *method, gboolean callvirt
 
        mono_mb_emit_byte (mb, CEE_RET);
 
+       /* else [delegates != null] */
+       mono_mb_patch_branch (mb, pos2);
+
+       /* len = delegates.Length; */
+       mono_mb_emit_ldloc (mb, local_delegates);
+       mono_mb_emit_byte (mb, CEE_LDLEN);
+       mono_mb_emit_byte (mb, CEE_CONV_I4);
+       mono_mb_emit_stloc (mb, local_len);
+
+       /* i = 0; */
+       mono_mb_emit_icon (mb, 0);
+       mono_mb_emit_stloc (mb, local_i);
+
+       pos1 = mono_mb_get_label (mb);
+
+       /* d = delegates [i]; */
+       mono_mb_emit_ldloc (mb, local_delegates);
+       mono_mb_emit_ldloc (mb, local_i);
+       mono_mb_emit_byte (mb, CEE_LDELEM_REF);
+       mono_mb_emit_stloc (mb, local_d);
+
+       /* res = d.Invoke ( args .. ); */
+       mono_mb_emit_ldloc (mb, local_d);
+       for (i = 0; i < sig->param_count; i++)
+               mono_mb_emit_ldarg (mb, i + 1);
+       if (!ctx) {
+               mono_mb_emit_op (mb, CEE_CALLVIRT, method);
+       } else {
+               MonoError error;
+               mono_mb_emit_op (mb, CEE_CALLVIRT, mono_class_inflate_generic_method_checked (method, &container->context, &error));
+               g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
+       }
+       if (!void_ret)
+               mono_mb_emit_stloc (mb, local_res);
+
+       /* i += 1 */
+       mono_mb_emit_add_to_local (mb, local_i, 1);
+
+       /* i < l */
+       mono_mb_emit_ldloc (mb, local_i);
+       mono_mb_emit_ldloc (mb, local_len);
+       mono_mb_emit_branch_label (mb, CEE_BLT, pos1);
+
+       /* return res */
+       if (!void_ret)
+               mono_mb_emit_ldloc (mb, local_res);
+       mono_mb_emit_byte (mb, CEE_RET);
+
        mb->skip_visibility = 1;
 #endif /* DISABLE_JIT */
 
@@ -3286,6 +3331,8 @@ mono_marshal_get_delegate_invoke_internal (MonoMethod *method, gboolean callvirt
        }
        mono_mb_free (mb);
 
+       /* mono_method_print_code (res); */
+
        return res;     
 }
 
@@ -3315,28 +3362,6 @@ mono_marshal_get_delegate_invoke (MonoMethod *method, MonoDelegate *del)
        return mono_marshal_get_delegate_invoke_internal (method, callvirt, static_method_with_first_arg_bound, target_method);
 }
 
-/*
- * signature_dup_add_this:
- *
- *  Make a copy of @sig, adding an explicit this argument.
- */
-static MonoMethodSignature*
-signature_dup_add_this (MonoImage *image, MonoMethodSignature *sig, MonoClass *klass)
-{
-       MonoMethodSignature *res;
-       int i;
-
-       res = mono_metadata_signature_alloc (image, sig->param_count + 1);
-       memcpy (res, sig, MONO_SIZEOF_METHOD_SIGNATURE);
-       res->param_count = sig->param_count + 1;
-       res->hasthis = FALSE;
-       for (i = sig->param_count - 1; i >= 0; i --)
-               res->params [i + 1] = sig->params [i];
-       res->params [0] = klass->valuetype ? &klass->this_arg : &klass->byval_arg;
-
-       return res;
-}
-
 typedef struct {
        MonoMethodSignature *ctor_sig;
        MonoMethodSignature *sig;
@@ -3374,7 +3399,7 @@ add_string_ctor_signature (MonoMethod *method)
        MonoMethodSignature *callsig;
        CtorSigPair *cs;
 
-       callsig = signature_dup (method->klass->image, mono_method_signature (method));
+       callsig = mono_metadata_signature_dup_full (method->klass->image, mono_method_signature (method));
        callsig->ret = &mono_defaults.string_class->byval_arg;
        cs = g_new (CtorSigPair, 1);
        cs->sig = callsig;
@@ -3809,7 +3834,8 @@ mono_marshal_get_runtime_invoke (MonoMethod *method, gboolean virtual)
        if (virtual)
                cache = get_cache (&method->klass->image->runtime_invoke_vcall_cache, mono_aligned_addr_hash, NULL);
        else
-               cache = get_cache (&method->klass->image->runtime_invoke_direct_cache, mono_aligned_addr_hash, NULL);
+               cache = get_cache (&mono_method_get_wrapper_cache (method)->runtime_invoke_direct_cache, mono_aligned_addr_hash, NULL);
+
        res = mono_marshal_find_in_cache (cache, method);
        if (res)
                return res;
@@ -3831,7 +3857,7 @@ mono_marshal_get_runtime_invoke (MonoMethod *method, gboolean virtual)
                need_direct_wrapper = TRUE;
        } else {
                if (method_is_dynamic (method))
-                       callsig = signature_dup (method->klass->image, mono_method_signature (method));
+                       callsig = mono_metadata_signature_dup_full (method->klass->image, mono_method_signature (method));
                else
                        callsig = mono_method_signature (method);
        }
@@ -3853,15 +3879,14 @@ mono_marshal_get_runtime_invoke (MonoMethod *method, gboolean virtual)
                MonoMethodSignature *tmp_sig;
 
                callsig = mono_marshal_get_runtime_invoke_sig (callsig);
+               GHashTable **cache_table = NULL;
 
                if (method->klass->valuetype && mono_method_signature (method)->hasthis)
-                       /* These have a different csig */
-                       cache = get_cache (&target_klass->image->runtime_invoke_vtype_cache,
-                                                          (GHashFunc)mono_signature_hash,
-                                                          (GCompareFunc)runtime_invoke_signature_equal);
+                       cache_table = &mono_method_get_wrapper_cache (method)->runtime_invoke_vtype_cache;
                else
-                       cache = get_cache (&target_klass->image->runtime_invoke_cache,
-                                                          (GHashFunc)mono_signature_hash,
+                       cache_table = &mono_method_get_wrapper_cache (method)->runtime_invoke_cache;
+
+               cache = get_cache (cache_table, (GHashFunc)mono_signature_hash,
                                                           (GCompareFunc)runtime_invoke_signature_equal);
 
                /* from mono_marshal_find_in_cache */
@@ -3936,10 +3961,13 @@ mono_marshal_get_runtime_invoke (MonoMethod *method, gboolean virtual)
                        mono_marshal_lock ();
                        res = g_hash_table_lookup (cache, callsig);
                        if (!res) {
+                               GHashTable *direct_cache;
                                res = newm;
                                g_hash_table_insert (cache, callsig, res);
                                /* Can't insert it into wrapper_hash since the key is a signature */
-                               g_hash_table_insert (method->klass->image->runtime_invoke_direct_cache, method, res);
+                               direct_cache = mono_method_get_wrapper_cache (method)->runtime_invoke_direct_cache;
+
+                               g_hash_table_insert (direct_cache, method, res);
                        } else {
                                mono_free_method (newm);
                        }
@@ -4114,9 +4142,9 @@ mono_marshal_get_icall_wrapper (MonoMethodSignature *sig, const char *name, gcon
 
        /* Add an explicit this argument */
        if (sig->hasthis)
-               csig2 = signature_dup_add_this (mono_defaults.corlib, sig, mono_defaults.object_class);
+               csig2 = mono_metadata_signature_dup_add_this (mono_defaults.corlib, sig, mono_defaults.object_class);
        else
-               csig2 = signature_dup (mono_defaults.corlib, sig);
+               csig2 = mono_metadata_signature_dup_full (mono_defaults.corlib, sig);
 
 #ifndef DISABLE_JIT
        if (sig->hasthis)
@@ -4133,7 +4161,7 @@ mono_marshal_get_icall_wrapper (MonoMethodSignature *sig, const char *name, gcon
        mono_mb_emit_byte (mb, CEE_RET);
 #endif
 
-       csig = signature_dup (mono_defaults.corlib, sig);
+       csig = mono_metadata_signature_dup_full (mono_defaults.corlib, sig);
        csig->pinvoke = 0;
        if (csig->call_convention == MONO_CALL_VARARG)
                csig->call_convention = 0;
@@ -5623,6 +5651,8 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t,
                        emit_struct_conv (mb, klass, FALSE);
 
                        mono_mb_patch_branch (mb, pos2);
+               } else if (klass == mono_defaults.stringbuilder_class) {
+                       // FIXME: What to do here ?
                } else {
                        /* byval [Out] marshalling */
 
@@ -6964,7 +6994,7 @@ mono_marshal_emit_native_wrapper (MonoImage *image, MonoMethodBuilder *mb, MonoM
                g_assert (!sig->hasthis);
                param_shift += 1;
        }
-       csig = signature_dup (mb->method->klass->image, sig);
+       csig = mono_metadata_signature_dup_full (mb->method->klass->image, sig);
        csig->pinvoke = 1;
        m.csig = csig;
        m.image = image;
@@ -7170,13 +7200,6 @@ mono_marshal_emit_native_wrapper (MonoImage *image, MonoMethodBuilder *mb, MonoM
 }
 #endif /* DISABLE_JIT */
 
-
-G_GNUC_UNUSED static void
-code_for (MonoMethod *method) {
-       MonoMethodHeader *header = mono_method_get_header (method);
-       printf ("CODE FOR %s: \n%s.\n", mono_method_full_name (method, TRUE), mono_disasm_code (0, method, header->code, header->code + header->code_size));
-}
-
 /**
  * mono_marshal_get_native_wrapper:
  * @method: The MonoMethod to wrap.
@@ -7205,10 +7228,22 @@ mono_marshal_get_native_wrapper (MonoMethod *method, gboolean check_exceptions,
        g_assert (method != NULL);
        g_assert (mono_method_signature (method)->pinvoke);
 
-       if (aot)
-               cache = get_cache (&method->klass->image->native_wrapper_aot_cache, mono_aligned_addr_hash, NULL);
-       else
-               cache = get_cache (&method->klass->image->native_wrapper_cache, mono_aligned_addr_hash, NULL);
+       GHashTable **cache_ptr;
+
+       if (aot) {
+               if (check_exceptions)
+                       cache_ptr = &mono_method_get_wrapper_cache (method)->native_wrapper_aot_check_cache;
+               else
+                       cache_ptr = &mono_method_get_wrapper_cache (method)->native_wrapper_aot_cache;
+       } else {
+               if (check_exceptions)
+                       cache_ptr = &mono_method_get_wrapper_cache (method)->native_wrapper_check_cache;
+               else
+                       cache_ptr = &mono_method_get_wrapper_cache (method)->native_wrapper_cache;
+       }
+
+       cache = get_cache (cache_ptr, mono_aligned_addr_hash, NULL);
+
        if ((res = mono_marshal_find_in_cache (cache, method)))
                return res;
 
@@ -7247,7 +7282,7 @@ mono_marshal_get_native_wrapper (MonoMethod *method, gboolean check_exceptions,
                g_assert (sig->hasthis);
 
                /* CreateString returns a value */
-               csig = signature_dup (method->klass->image, sig);
+               csig = mono_metadata_signature_dup_full (method->klass->image, sig);
                csig->ret = &mono_defaults.string_class->byval_arg;
                csig->pinvoke = 0;
 
@@ -7303,7 +7338,7 @@ mono_marshal_get_native_wrapper (MonoMethod *method, gboolean check_exceptions,
                info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_NONE);
                info->d.managed_to_native.method = method;
 
-               csig = signature_dup (method->klass->image, sig);
+               csig = mono_metadata_signature_dup_full (method->klass->image, sig);
                csig->pinvoke = 0;
                res = mono_mb_create_and_cache_full (cache, method, mb, csig,
                                                                                         csig->param_count + 16, info, NULL);
@@ -7315,9 +7350,9 @@ mono_marshal_get_native_wrapper (MonoMethod *method, gboolean check_exceptions,
        /* internal calls: we simply push all arguments and call the method (no conversions) */
        if (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
                if (sig->hasthis)
-                       csig = signature_dup_add_this (method->klass->image, sig, method->klass);
+                       csig = mono_metadata_signature_dup_add_this (method->klass->image, sig, method->klass);
                else
-                       csig = signature_dup (method->klass->image, sig);
+                       csig = mono_metadata_signature_dup_full (method->klass->image, sig);
 
                /* hack - string constructors returns a value */
                if (method->string_ctor)
@@ -7357,7 +7392,7 @@ mono_marshal_get_native_wrapper (MonoMethod *method, gboolean check_exceptions,
                info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_NONE);
                info->d.managed_to_native.method = method;
 
-               csig = signature_dup (method->klass->image, csig);
+               csig = mono_metadata_signature_dup_full (method->klass->image, csig);
                csig->pinvoke = 0;
                res = mono_mb_create_and_cache_full (cache, method, mb, csig, csig->param_count + 16,
                                                                                         info, NULL);
@@ -7379,7 +7414,7 @@ mono_marshal_get_native_wrapper (MonoMethod *method, gboolean check_exceptions,
        info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_PINVOKE);
        info->d.managed_to_native.method = method;
 
-       csig = signature_dup (method->klass->image, sig);
+       csig = mono_metadata_signature_dup_full (method->klass->image, sig);
        csig->pinvoke = 0;
        res = mono_mb_create_and_cache_full (cache, method, mb, csig, csig->param_count + 16,
                                                                                 info, NULL);
@@ -7392,7 +7427,7 @@ mono_marshal_get_native_wrapper (MonoMethod *method, gboolean check_exceptions,
        g_free (mspecs);
 #endif
 
-       /* code_for (res); */
+       /* mono_method_print_code (res); */
 
        return res;
 }
@@ -7422,6 +7457,9 @@ mono_marshal_get_native_func_wrapper (MonoImage *image, MonoMethodSignature *sig
        key.sig = sig;
        key.pointer = func;
 
+       // Generic types are not safe to place in MonoImage caches.
+       g_assert (!sig->is_inflated);
+
        cache = get_cache (&image->native_func_wrapper_cache, signature_pointer_pair_hash, signature_pointer_pair_equal);
        if ((res = mono_marshal_find_in_cache (cache, &key)))
                return res;
@@ -7434,7 +7472,7 @@ mono_marshal_get_native_func_wrapper (MonoImage *image, MonoMethodSignature *sig
        mono_marshal_emit_native_wrapper (image, mb, sig, piinfo, mspecs, func, FALSE, TRUE, FALSE);
 #endif
 
-       csig = signature_dup (image, sig);
+       csig = mono_metadata_signature_dup_full (image, sig);
        csig->pinvoke = 0;
 
        new_key = g_new (SignaturePointerPair,1);
@@ -7477,7 +7515,8 @@ mono_marshal_get_native_func_wrapper_aot (MonoClass *klass)
        /*
         * The wrapper is associated with the delegate type, to pick up the marshalling info etc.
         */
-       cache = get_cache (&image->native_func_wrapper_aot_cache, mono_aligned_addr_hash, NULL);
+       cache = get_cache (&mono_method_get_wrapper_cache (invoke)->native_func_wrapper_aot_cache, mono_aligned_addr_hash, NULL);
+
        if ((res = mono_marshal_find_in_cache (cache, invoke)))
                return res;
 
@@ -7502,7 +7541,7 @@ mono_marshal_get_native_func_wrapper_aot (MonoClass *klass)
        info->d.managed_to_native.method = invoke;
 
        g_assert (!sig->hasthis);
-       csig = signature_dup_add_this (image, sig, mono_defaults.int_class);
+       csig = mono_metadata_signature_dup_add_this (image, sig, mono_defaults.object_class);
        csig->pinvoke = 0;
        res = mono_mb_create_and_cache_full (cache, invoke,
                                                                                 mb, csig, csig->param_count + 16,
@@ -7596,7 +7635,7 @@ mono_marshal_emit_managed_wrapper (MonoMethodBuilder *mb, MonoMethodSignature *i
 #ifdef USE_COOP_GC
        /* local 4, the local to be used when calling the reset_blocking funcs */
        /* tons of code hardcode 3 to be the return var */
-       coop_gc_var = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
+       coop_gc_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
 #endif
 
        mono_mb_emit_icon (mb, 0);
@@ -7830,7 +7869,8 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass,
         * could be called with different delegates, thus different marshalling
         * options.
         */
-       cache = get_cache (&method->klass->image->managed_wrapper_cache, mono_aligned_addr_hash, NULL);
+       cache = get_cache (&mono_method_get_wrapper_cache (method)->managed_wrapper_cache, mono_aligned_addr_hash, NULL);
+
        if (!target_handle && (res = mono_marshal_find_in_cache (cache, method)))
                return res;
 
@@ -7852,7 +7892,7 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass,
                /* Need to free this later */
                csig = mono_metadata_signature_dup (invoke_sig);
        else
-               csig = signature_dup (method->klass->image, invoke_sig);
+               csig = mono_metadata_signature_dup_full (method->klass->image, invoke_sig);
        csig->hasthis = 0;
        csig->pinvoke = 1;
 
@@ -7956,7 +7996,7 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass,
                                                                                         info, NULL);
        } else {
 #ifndef DISABLE_JIT
-               mb->dynamic = 1;
+               mb->dynamic = TRUE;
 #endif
                res = mono_mb_create (mb, csig, sig->param_count + 16, NULL);
        }
@@ -7967,7 +8007,7 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass,
                        mono_metadata_free_marshal_spec (mspecs [i]);
        g_free (mspecs);
 
-       /* code_for (res); */
+       /* mono_method_print_code (res); */
 
        return res;
 }
@@ -7997,7 +8037,7 @@ mono_marshal_get_vtfixup_ftnptr (MonoImage *image, guint32 token, guint16 type)
                mono_method_get_marshal_info (method, mspecs);
 
                mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
-               csig = signature_dup (image, sig);
+               csig = mono_metadata_signature_dup_full (image, sig);
                csig->hasthis = 0;
                csig->pinvoke = 1;
 
@@ -8016,7 +8056,7 @@ mono_marshal_get_vtfixup_ftnptr (MonoImage *image, guint32 token, guint16 type)
                mono_marshal_emit_managed_wrapper (mb, sig, mspecs, &m, method, 0);
 
 #ifndef DISABLE_JIT
-               mb->dynamic = 1;
+               mb->dynamic = TRUE;
 #endif
                method = mono_mb_create (mb, csig, sig->param_count + 16, NULL);
                mono_mb_free (mb);
@@ -8043,7 +8083,7 @@ mono_marshal_get_vtfixup_ftnptr (MonoImage *image, guint32 token, guint16 type)
                mono_mb_emit_op (mb, CEE_CALL, method);
        mono_mb_emit_byte (mb, CEE_RET);
 
-       mb->dynamic = 1;
+       mb->dynamic = TRUE;
 #endif
 
        method = mono_mb_create (mb, sig, param_count, NULL);
@@ -8052,6 +8092,71 @@ mono_marshal_get_vtfixup_ftnptr (MonoImage *image, guint32 token, guint16 type)
        return mono_compile_method (method);
 }
 
+#ifndef DISABLE_JIT
+
+/*
+ * The code directly following this is the cache hit, value positive branch
+ *
+ * This function takes a new method builder with 0 locals and adds two locals
+ * to create multiple out-branches and the fall through state of having the object
+ * on the stack after a cache miss
+ */
+static void
+generate_check_cache (int obj_arg_position, int class_arg_position, int cache_arg_position, // In-parameters
+                                                                                       int *null_obj, int *cache_hit_neg, int *cache_hit_pos, // Out-parameters
+                                                                                       MonoMethodBuilder *mb)
+{
+       int cache_miss_pos;
+
+       /* allocate local 0 (pointer) obj_vtable */
+       mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+       /* allocate local 1 (pointer) cached_vtable */
+       mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+
+       /*if (!obj)*/
+       mono_mb_emit_ldarg (mb, obj_arg_position);
+       *null_obj = mono_mb_emit_branch (mb, CEE_BRFALSE);
+
+       /*obj_vtable = obj->vtable;*/
+       mono_mb_emit_ldarg (mb, obj_arg_position);
+       mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoObject, vtable));
+       mono_mb_emit_byte (mb, CEE_LDIND_I);
+       mono_mb_emit_stloc (mb, 0);
+
+       /* cached_vtable = *cache*/
+       mono_mb_emit_ldarg (mb, cache_arg_position);
+       mono_mb_emit_byte (mb, CEE_LDIND_I);
+       mono_mb_emit_stloc (mb, 1);
+
+       mono_mb_emit_ldloc (mb, 1);
+       mono_mb_emit_byte (mb, CEE_LDC_I4);
+       mono_mb_emit_i4 (mb, ~0x1);
+       mono_mb_emit_byte (mb, CEE_CONV_I);
+       mono_mb_emit_byte (mb, CEE_AND);
+       mono_mb_emit_ldloc (mb, 0);
+       /*if ((cached_vtable & ~0x1)== obj_vtable)*/
+       cache_miss_pos = mono_mb_emit_branch (mb, CEE_BNE_UN);
+
+       /*return (cached_vtable & 0x1) ? NULL : obj;*/
+       mono_mb_emit_ldloc (mb, 1);
+       mono_mb_emit_byte(mb, CEE_LDC_I4_1);
+       mono_mb_emit_byte (mb, CEE_CONV_U);
+       mono_mb_emit_byte (mb, CEE_AND);
+       *cache_hit_neg = mono_mb_emit_branch (mb, CEE_BRTRUE);
+       *cache_hit_pos = mono_mb_emit_branch (mb, CEE_BR);
+
+       // slow path
+       mono_mb_patch_branch (mb, cache_miss_pos);
+
+       // if isinst
+       mono_mb_emit_ldarg (mb, obj_arg_position);
+       mono_mb_emit_ldarg (mb, class_arg_position);
+       mono_mb_emit_ldarg (mb, cache_arg_position);
+       mono_mb_emit_icall (mb, mono_marshal_isinst_with_cache);
+}
+
+#endif /* DISABLE_JIT */
+
 /*
  * This does the equivalent of mono_object_castclass_with_cache.
  * The wrapper info for the wrapper is a WrapperInfo structure.
@@ -8063,63 +8168,36 @@ mono_marshal_get_castclass_with_cache (void)
        MonoMethod *res;
        MonoMethodBuilder *mb;
        MonoMethodSignature *sig;
-       int return_null_pos, cache_miss_pos, invalid_cast_pos;
+       int return_null_pos, positive_cache_hit_pos, negative_cache_hit_pos, invalid_cast_pos;
        WrapperInfo *info;
 
+       const int obj_arg_position = 0;
+       const int class_arg_position = 1;
+       const int cache_arg_position = 2;
+
        if (cached)
                return cached;
 
        mb = mono_mb_new (mono_defaults.object_class, "__castclass_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;
-       sig->params [2] = &mono_defaults.int_class->byval_arg;
+       sig->params [obj_arg_position] = &mono_defaults.object_class->byval_arg;
+       sig->params [class_arg_position] = &mono_defaults.int_class->byval_arg;
+       sig->params [cache_arg_position] = &mono_defaults.int_class->byval_arg;
        sig->ret = &mono_defaults.object_class->byval_arg;
        sig->pinvoke = 0;
 
 #ifndef DISABLE_JIT
-       /* allocate local 0 (pointer) obj_vtable */
-       mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
-
-       /*if (!obj)*/
-       mono_mb_emit_ldarg (mb, 0);
-       return_null_pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
-
-       /*obj_vtable = obj->vtable;*/
-       mono_mb_emit_ldarg (mb, 0);
-       mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoObject, vtable));
-       mono_mb_emit_byte (mb, CEE_LDIND_I);
-       mono_mb_emit_stloc (mb, 0);
-
-       /* *cache */
-       mono_mb_emit_ldarg (mb, 2);
-       mono_mb_emit_byte (mb, CEE_LDIND_I);
-       mono_mb_emit_ldloc (mb, 0);
-
-       /*if (*cache == obj_vtable)*/
-       cache_miss_pos = mono_mb_emit_branch (mb, CEE_BNE_UN);
-
-       /*return obj;*/
-       mono_mb_emit_ldarg (mb, 0);
-       mono_mb_emit_byte (mb, CEE_RET);
-
-       mono_mb_patch_branch (mb, cache_miss_pos);
-       /*if (mono_object_isinst (obj, klass)) */
-       mono_mb_emit_ldarg (mb, 0);
-       mono_mb_emit_ldarg (mb, 1);
-       mono_mb_emit_icall (mb, mono_object_isinst);
+       generate_check_cache (obj_arg_position, class_arg_position, cache_arg_position, 
+                                                                                               &return_null_pos, &negative_cache_hit_pos, &positive_cache_hit_pos, mb);
        invalid_cast_pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
 
-       /**cache = obj_vtable;*/
-       mono_mb_emit_ldarg (mb, 2);
-       mono_mb_emit_ldloc (mb, 0);
-       mono_mb_emit_byte (mb, CEE_STIND_I);
-
        /*return obj;*/
-       mono_mb_emit_ldarg (mb, 0);
+       mono_mb_patch_branch (mb, positive_cache_hit_pos);
+       mono_mb_emit_ldarg (mb, obj_arg_position);
        mono_mb_emit_byte (mb, CEE_RET);
 
        /*fails*/
+       mono_mb_patch_branch (mb, negative_cache_hit_pos);
        mono_mb_patch_branch (mb, invalid_cast_pos);
        mono_mb_emit_exception (mb, "InvalidCastException", NULL);
 
@@ -8142,6 +8220,25 @@ mono_marshal_get_castclass_with_cache (void)
        return cached;
 }
 
+static MonoObject *
+mono_marshal_isinst_with_cache (MonoObject *obj, MonoClass *klass, uintptr_t *cache)
+{
+       MonoObject *isinst = mono_object_isinst (obj, klass);
+
+#ifndef DISABLE_REMOTING
+       if (obj->vtable->klass == mono_defaults.transparent_proxy_class)
+               return isinst;
+#endif
+
+       uintptr_t cache_update = (uintptr_t)obj->vtable;
+       if (!isinst)
+               cache_update = cache_update | 0x1;
+
+       *cache = cache_update;
+
+       return isinst;
+}
+
 /*
  * This does the equivalent of mono_object_isinst_with_cache.
  * The wrapper info for the wrapper is a WrapperInfo structure.
@@ -8153,101 +8250,43 @@ mono_marshal_get_isinst_with_cache (void)
        MonoMethod *res;
        MonoMethodBuilder *mb;
        MonoMethodSignature *sig;
-       int return_null_pos, cache_miss_pos, cache_hit_pos, not_an_instance_pos, negative_cache_hit_pos;
+       int return_null_pos, positive_cache_hit_pos, negative_cache_hit_pos;
        WrapperInfo *info;
 
+       const int obj_arg_position = 0;
+       const int class_arg_position = 1;
+       const int cache_arg_position = 2;
+
        if (cached)
                return cached;
 
        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;
-       sig->params [2] = &mono_defaults.int_class->byval_arg;
+       // The object
+       sig->params [obj_arg_position] = &mono_defaults.object_class->byval_arg;
+       // The class
+       sig->params [class_arg_position] = &mono_defaults.int_class->byval_arg;
+       // The cache
+       sig->params [cache_arg_position] = &mono_defaults.int_class->byval_arg;
        sig->ret = &mono_defaults.object_class->byval_arg;
        sig->pinvoke = 0;
 
 #ifndef DISABLE_JIT
-       /* allocate local 0 (pointer) obj_vtable */
-       mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
-       /* allocate local 1 (pointer) cached_vtable */
-       mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
-
-       /*if (!obj)*/
-       mono_mb_emit_ldarg (mb, 0);
-       return_null_pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
-
-       /*obj_vtable = obj->vtable;*/
-       mono_mb_emit_ldarg (mb, 0);
-       mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoObject, vtable));
-       mono_mb_emit_byte (mb, CEE_LDIND_I);
-       mono_mb_emit_stloc (mb, 0);
-
-       /* cached_vtable = *cache*/
-       mono_mb_emit_ldarg (mb, 2);
-       mono_mb_emit_byte (mb, CEE_LDIND_I);
-       mono_mb_emit_stloc (mb, 1);
-
-       mono_mb_emit_ldloc (mb, 1);
-       mono_mb_emit_byte (mb, CEE_LDC_I4);
-       mono_mb_emit_i4 (mb, ~0x1);
-       mono_mb_emit_byte (mb, CEE_CONV_I);
-       mono_mb_emit_byte (mb, CEE_AND);
-       mono_mb_emit_ldloc (mb, 0);
-       /*if ((cached_vtable & ~0x1)== obj_vtable)*/
-       cache_miss_pos = mono_mb_emit_branch (mb, CEE_BNE_UN);
-
-       /*return (cached_vtable & 0x1) ? NULL : obj;*/
-       mono_mb_emit_ldloc (mb, 1);
-       mono_mb_emit_byte(mb, CEE_LDC_I4_1);
-       mono_mb_emit_byte (mb, CEE_CONV_U);
-       mono_mb_emit_byte (mb, CEE_AND);
-       negative_cache_hit_pos = mono_mb_emit_branch (mb, CEE_BRTRUE);
-
-       /*obj*/
-       mono_mb_emit_ldarg (mb, 0);
-       cache_hit_pos = mono_mb_emit_branch (mb, CEE_BR);
+       generate_check_cache (obj_arg_position, class_arg_position, cache_arg_position, 
+               &return_null_pos, &negative_cache_hit_pos, &positive_cache_hit_pos, mb);
+       // Return the object gotten via the slow path.
+       mono_mb_emit_byte (mb, CEE_RET);
 
-       /*NULL*/
+       // return NULL;
        mono_mb_patch_branch (mb, negative_cache_hit_pos);
+       mono_mb_patch_branch (mb, return_null_pos);
        mono_mb_emit_byte (mb, CEE_LDNULL);
-
-       mono_mb_patch_branch (mb, cache_hit_pos);
        mono_mb_emit_byte (mb, CEE_RET);
 
-       mono_mb_patch_branch (mb, cache_miss_pos);
-       /*if (mono_object_isinst (obj, klass)) */
-       mono_mb_emit_ldarg (mb, 0);
-       mono_mb_emit_ldarg (mb, 1);
-       mono_mb_emit_icall (mb, mono_object_isinst);
-       not_an_instance_pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
-
-       /**cache = obj_vtable;*/
-       mono_mb_emit_ldarg (mb, 2);
-       mono_mb_emit_ldloc (mb, 0);
-       mono_mb_emit_byte (mb, CEE_STIND_I);
-
-       /*return obj;*/
+       // return obj
+       mono_mb_patch_branch (mb, positive_cache_hit_pos);
        mono_mb_emit_ldarg (mb, 0);
        mono_mb_emit_byte (mb, CEE_RET);
-
-       /*not an instance*/
-       mono_mb_patch_branch (mb, not_an_instance_pos);
-       /* *cache = (gpointer)(obj_vtable | 0x1);*/
-       mono_mb_emit_ldarg (mb, 2);
-       /*obj_vtable | 0x1*/
-       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);
-
-       /* *cache = ... */
-       mono_mb_emit_byte (mb, CEE_STIND_I);
-
-       /*return null*/
-       mono_mb_patch_branch (mb, return_null_pos);
-       mono_mb_emit_byte (mb, CEE_LDNULL);
-       mono_mb_emit_byte (mb, CEE_RET);
 #endif
 
        info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_ISINST_WITH_CACHE);
@@ -8555,7 +8594,7 @@ mono_marshal_get_ptr_to_struct (MonoClass *klass)
                          static void PtrToStructure (IntPtr ptr, object structure);
                   defined in class/corlib/System.Runtime.InteropServices/Marshal.cs */
                sig = mono_create_icall_signature ("void ptr object");
-               sig = signature_dup (mono_defaults.corlib, sig);
+               sig = mono_metadata_signature_dup_full (mono_defaults.corlib, sig);
                sig->pinvoke = 0;
                mono_memory_barrier ();
                ptostr = sig;
@@ -8631,7 +8670,7 @@ mono_marshal_get_synchronized_inner_wrapper (MonoMethod *method)
        mono_mb_emit_exception_full (mb, "System", "ExecutionEngineException", "Shouldn't be called.");
        mono_mb_emit_byte (mb, CEE_RET);
 #endif
-       sig = signature_dup (method->klass->image, mono_method_signature (method));
+       sig = mono_metadata_signature_dup_full (method->klass->image, mono_method_signature (method));
 
        info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_SYNCHRONIZED_INNER);
        info->d.synchronized_inner.method = method;
@@ -8658,7 +8697,7 @@ mono_marshal_get_synchronized_wrapper (MonoMethod *method)
        MonoMethodBuilder *mb;
        MonoMethod *res;
        GHashTable *cache;
-       int i, pos, this_local, ret_local = 0;
+       int i, pos, pos2, this_local, taken_local, ret_local = 0;
        MonoGenericContext *ctx = NULL;
        MonoMethod *orig_method = NULL;
        MonoGenericContainer *container = NULL;
@@ -8683,22 +8722,23 @@ mono_marshal_get_synchronized_wrapper (MonoMethod *method)
         * Check cache
         */
        if (ctx) {
-               cache = get_cache (&method->klass->image->synchronized_generic_cache, mono_aligned_addr_hash, NULL);
+               cache = get_cache (&((MonoMethodInflated*)orig_method)->owner->wrapper_caches.synchronized_cache, mono_aligned_addr_hash, NULL);
                res = check_generic_wrapper_cache (cache, orig_method, orig_method, method);
                if (res)
                        return res;
        } else {
-               cache = get_cache (&method->klass->image->synchronized_cache, mono_aligned_addr_hash, NULL);
+               cache = get_cache (&method->klass->image->wrapper_caches.synchronized_cache, mono_aligned_addr_hash, NULL);
                if ((res = mono_marshal_find_in_cache (cache, method)))
                        return res;
        }
 
-       sig = signature_dup (method->klass->image, mono_method_signature (method));
+       sig = mono_metadata_signature_dup_full (method->klass->image, mono_method_signature (method));
        sig->pinvoke = 0;
 
        mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_SYNCHRONIZED);
 
 #ifndef DISABLE_JIT
+       mb->skip_visibility = 1;
        /* result */
        if (!MONO_TYPE_IS_VOID (sig->ret))
                ret_local = mono_mb_add_local (mb, sig->ret);
@@ -8727,6 +8767,7 @@ mono_marshal_get_synchronized_wrapper (MonoMethod *method)
 #ifndef DISABLE_JIT
        /* this */
        this_local = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
+       taken_local = mono_mb_add_local (mb, &mono_defaults.boolean_class->byval_arg);
 
        clause = mono_image_alloc0 (method->klass->image, sizeof (MonoExceptionClause));
        clause->flags = MONO_EXCEPTION_CLAUSE_FINALLY;
@@ -8737,7 +8778,7 @@ mono_marshal_get_synchronized_wrapper (MonoMethod *method)
        if (!enter_method) {
                MonoMethodDesc *desc;
 
-               desc = mono_method_desc_new ("Monitor:Enter", FALSE);
+               desc = mono_method_desc_new ("Monitor:enter_with_atomic_var(object,bool&)", FALSE);
                enter_method = mono_method_desc_search_in_class (desc, mono_defaults.monitor_class);
                g_assert (enter_method);
                mono_method_desc_free (desc);
@@ -8772,6 +8813,7 @@ mono_marshal_get_synchronized_wrapper (MonoMethod *method)
 
        /* Call Monitor::Enter() */
        mono_mb_emit_ldloc (mb, this_local);
+       mono_mb_emit_ldloc_addr (mb, taken_local);
        mono_mb_emit_managed_call (mb, enter_method, NULL);
 
        clause->try_offset = mono_mb_get_label (mb);
@@ -8798,9 +8840,12 @@ mono_marshal_get_synchronized_wrapper (MonoMethod *method)
        clause->try_len = mono_mb_get_pos (mb) - clause->try_offset;
        clause->handler_offset = mono_mb_get_label (mb);
 
-       /* Call Monitor::Exit() */
+       /* Call Monitor::Exit() if needed */
+       mono_mb_emit_ldloc (mb, taken_local);
+       pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE);
        mono_mb_emit_ldloc (mb, this_local);
        mono_mb_emit_managed_call (mb, exit_method, NULL);
+       mono_mb_patch_branch (mb, pos2);
        mono_mb_emit_byte (mb, CEE_ENDFINALLY);
 
        clause->handler_len = mono_mb_get_pos (mb) - clause->handler_offset;
@@ -8839,7 +8884,8 @@ mono_marshal_get_unbox_wrapper (MonoMethod *method)
        MonoMethod *res;
        GHashTable *cache;
 
-       cache = get_cache (&method->klass->image->unbox_wrapper_cache, mono_aligned_addr_hash, NULL);
+       cache = get_cache (&mono_method_get_wrapper_cache (method)->unbox_wrapper_cache, mono_aligned_addr_hash, NULL);
+
        if ((res = mono_marshal_find_in_cache (cache, method)))
                return res;
 
@@ -8861,7 +8907,7 @@ mono_marshal_get_unbox_wrapper (MonoMethod *method)
                                                                                 mb, sig, sig->param_count + 16);
        mono_mb_free (mb);
 
-       /* code_for (res); */
+       /* mono_method_print_code (res); */
 
        return res;     
 }
@@ -9818,7 +9864,7 @@ mono_marshal_get_array_accessor_wrapper (MonoMethod *method)
                        return res;
        }
 
-       sig = signature_dup (method->klass->image, mono_method_signature (method));
+       sig = mono_metadata_signature_dup_full (method->klass->image, mono_method_signature (method));
        sig->pinvoke = 0;
 
        mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_UNKNOWN);
@@ -10973,7 +11019,7 @@ mono_marshal_get_generic_array_helper (MonoClass *class, MonoClass *iface, gchar
                METHOD_ATTRIBUTE_NEW_SLOT | METHOD_ATTRIBUTE_HIDE_BY_SIG | METHOD_ATTRIBUTE_FINAL;
 
        sig = mono_method_signature (method);
-       csig = signature_dup (method->klass->image, sig);
+       csig = mono_metadata_signature_dup_full (method->klass->image, sig);
        csig->generic_param_count = 0;
 
 #ifndef DISABLE_JIT
@@ -11066,12 +11112,17 @@ mono_marshal_get_thunk_invoke_wrapper (MonoMethod *method)
        GHashTable *cache;
        MonoMethod *res;
        int i, param_count, sig_size, pos_leave;
+#ifdef USE_COOP_GC
+       int coop_gc_var;
+#endif
 
        g_assert (method);
 
        klass = method->klass;
        image = method->klass->image;
-       cache = get_cache (&image->thunk_invoke_cache, mono_aligned_addr_hash, NULL);
+
+       cache = get_cache (&mono_method_get_wrapper_cache (method)->thunk_invoke_cache, mono_aligned_addr_hash, NULL);
+
 
        if ((res = mono_marshal_find_in_cache (cache, method)))
                return res;
@@ -11117,11 +11168,23 @@ mono_marshal_get_thunk_invoke_wrapper (MonoMethod *method)
        if (!MONO_TYPE_IS_VOID (sig->ret))
                mono_mb_add_local (mb, sig->ret);
 
+#ifdef USE_COOP_GC
+       /* local 4, the local to be used when calling the reset_blocking funcs */
+       /* tons of code hardcode 3 to be the return var */
+       coop_gc_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+#endif
+
        /* 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);
 
+#ifdef USE_COOP_GC
+       /* FIXME this is technically wrong as the callback itself must be executed in gc unsafe context. */
+       mono_mb_emit_icall (mb, mono_threads_reset_blocking_start);
+       mono_mb_emit_stloc (mb, coop_gc_var);
+#endif
+
        /* try */
        clause = mono_image_alloc0 (image, sizeof (MonoExceptionClause));
        clause->try_offset = mono_mb_get_label (mb);
@@ -11191,6 +11254,12 @@ mono_marshal_get_thunk_invoke_wrapper (MonoMethod *method)
                        mono_mb_emit_op (mb, CEE_BOX, mono_class_from_mono_type (sig->ret));
        }
 
+#ifdef USE_COOP_GC
+       /* XXX merge reset_blocking_end with detach */
+       mono_mb_emit_ldloc (mb, coop_gc_var);
+       mono_mb_emit_icall (mb, mono_threads_reset_blocking_end);
+#endif
+
        mono_mb_emit_byte (mb, CEE_RET);
 #endif
 
@@ -11219,10 +11288,10 @@ mono_marshal_free_dynamic_wrappers (MonoMethod *method)
         * FIXME: We currently leak the wrappers. Freeing them would be tricky as
         * they could be shared with other methods ?
         */
-       if (image->runtime_invoke_direct_cache)
-               g_hash_table_remove (image->runtime_invoke_direct_cache, method);
-       if (image->delegate_abstract_invoke_cache)
-               g_hash_table_foreach_remove (image->delegate_abstract_invoke_cache, signature_pointer_pair_matches_pointer, method);
+       if (image->wrapper_caches.runtime_invoke_direct_cache)
+               g_hash_table_remove (image->wrapper_caches.runtime_invoke_direct_cache, method);
+       if (image->wrapper_caches.delegate_abstract_invoke_cache)
+               g_hash_table_foreach_remove (image->wrapper_caches.delegate_abstract_invoke_cache, signature_pointer_pair_matches_pointer, method);
        // FIXME: Need to clear the caches in other images as well
        if (image->delegate_bound_static_invoke_cache)
                g_hash_table_remove (image->delegate_bound_static_invoke_cache, mono_method_signature (method));
@@ -11230,83 +11299,3 @@ mono_marshal_free_dynamic_wrappers (MonoMethod *method)
        if (marshal_mutex_initialized)
                mono_marshal_unlock ();
 }
-
-static gboolean
-signature_pointer_pair_matches_signature (gpointer key, gpointer value, gpointer user_data)
-{
-       SignaturePointerPair *pair = (SignaturePointerPair*)key;
-       MonoMethodSignature *sig = (MonoMethodSignature*)user_data;
-
-       return mono_metadata_signature_equal (pair->sig, sig);
-}
-
-/*
- * mono_marshal_free_inflated_wrappers:
- *
- *   Free wrappers of the inflated method METHOD.
- */
-void
-mono_marshal_free_inflated_wrappers (MonoMethod *method)
-{
-       MonoMethodSignature *sig = method->signature;
-
-       g_assert (method->is_inflated);
-
-       /* Ignore calls occuring late during cleanup.  */
-       if (!marshal_mutex_initialized)
-               return;
-
-       mono_marshal_lock ();
-       /*
-        * FIXME: We currently leak the wrappers. Freeing them would be tricky as
-        * they could be shared with other methods ?
-        */
-
-        /*
-         * indexed by MonoMethodSignature
-         */
-          /* FIXME: This could remove unrelated wrappers as well */
-       if (sig && method->klass->image->delegate_begin_invoke_cache)
-               g_hash_table_remove (method->klass->image->delegate_begin_invoke_cache, sig);
-       if (sig && method->klass->image->delegate_end_invoke_cache)
-               g_hash_table_remove (method->klass->image->delegate_end_invoke_cache, sig);
-       if (sig && method->klass->image->delegate_invoke_cache)
-               g_hash_table_remove (method->klass->image->delegate_invoke_cache, sig);
-       if (sig && method->klass->image->runtime_invoke_cache)
-               g_hash_table_remove (method->klass->image->runtime_invoke_cache, sig);
-       if (sig && method->klass->image->runtime_invoke_vtype_cache)
-               g_hash_table_remove (method->klass->image->runtime_invoke_vtype_cache, sig);
-
-        /*
-         * indexed by SignaturePointerPair
-         */
-       if (sig && method->klass->image->delegate_abstract_invoke_cache)
-               g_hash_table_foreach_remove (method->klass->image->delegate_abstract_invoke_cache,
-                                            signature_pointer_pair_matches_signature, (gpointer)sig);
-
-        /*
-         * indexed by MonoMethod pointers
-         */
-       if (method->klass->image->runtime_invoke_direct_cache)
-               g_hash_table_remove (method->klass->image->runtime_invoke_direct_cache, method);
-       if (method->klass->image->managed_wrapper_cache)
-               g_hash_table_remove (method->klass->image->managed_wrapper_cache, method);
-       if (method->klass->image->native_wrapper_cache)
-               g_hash_table_remove (method->klass->image->native_wrapper_cache, method);
-       if (method->klass->image->remoting_invoke_cache)
-               g_hash_table_remove (method->klass->image->remoting_invoke_cache, method);
-       if (method->klass->image->synchronized_cache)
-               g_hash_table_remove (method->klass->image->synchronized_cache, method);
-       if (method->klass->image->unbox_wrapper_cache)
-               g_hash_table_remove (method->klass->image->unbox_wrapper_cache, method);
-       if (method->klass->image->cominterop_invoke_cache)
-               g_hash_table_remove (method->klass->image->cominterop_invoke_cache, method);
-       if (method->klass->image->cominterop_wrapper_cache)
-               g_hash_table_remove (method->klass->image->cominterop_wrapper_cache, method);
-       if (method->klass->image->thunk_invoke_cache)
-               g_hash_table_remove (method->klass->image->thunk_invoke_cache, method);
-       if (method->klass->image->native_func_wrapper_aot_cache)
-               g_hash_table_remove (method->klass->image->native_func_wrapper_aot_cache, method);
-
-       mono_marshal_unlock ();
-}