Merge pull request #1991 from esdrubal/seq_test_fix
[mono.git] / mono / mini / mini-trampolines.c
index 7dc0b105666e78a3e6f8f22b59c935f53c5a4634..d4af8df57a08e4065f746f834cfc369e426a6a9c 100644 (file)
@@ -23,7 +23,6 @@
  */
 guint8* mono_trampoline_code [MONO_TRAMPOLINE_NUM];
 
-static GHashTable *class_init_hash_addr;
 static GHashTable *rgctx_lazy_fetch_trampoline_hash;
 static GHashTable *rgctx_lazy_fetch_trampoline_hash_addr;
 static guint32 trampoline_calls, jit_trampolines, unbox_trampolines, static_rgctx_trampolines;
@@ -139,106 +138,108 @@ mono_create_static_rgctx_trampoline (MonoMethod *m, gpointer addr)
 }
 #endif
 
+#if 0
+#define DEBUG_IMT(stmt) do { stmt; } while (0)
+#else
+#define DEBUG_IMT(stmt) do { } while (0)
+#endif
+
 /*
- * Either IMPL_METHOD or AOT_ADDR will be set on return.
+ * mini_resolve_imt_method:
  *
- * MONO_NEVER_INLINE :
- * This works against problems when compiling with gcc 4.6 on arm. The 'then' part of
- * this line gets executed, even when the condition is false:
- *             if (impl && mono_method_needs_static_rgctx_invoke (impl, FALSE))
- *                     *need_rgctx_tramp = TRUE;
+ *   Resolve the actual method called when making an IMT call through VTABLE_SLOT with IMT_METHOD as the interface method.
+ *
+ * Either IMPL_METHOD or OUT_AOT_ADDR will be set on return.
  */
-static MONO_NEVER_INLINE gpointer*
-mono_convert_imt_slot_to_vtable_slot (gpointer* slot, mgreg_t *regs, guint8 *code, MonoMethod *method, gboolean lookup_aot, MonoMethod **impl_method, gboolean *need_rgctx_tramp, gboolean *variance_used, gpointer *aot_addr)
+gpointer*
+mini_resolve_imt_method (MonoVTable *vt, gpointer *vtable_slot, MonoMethod *imt_method, MonoMethod **impl_method, gpointer *out_aot_addr, gboolean *out_need_rgctx_tramp, MonoMethod **variant_iface)
 {
-       MonoObject *this_argument = mono_arch_get_this_arg_from_call (regs, code);
-       MonoVTable *vt = this_argument->vtable;
-       int displacement = slot - ((gpointer*)vt);
-
-       if (displacement > 0) {
-               /* slot is in the vtable, not in the IMT */
-#if DEBUG_IMT
-               printf ("mono_convert_imt_slot_to_vtable_slot: slot %p is in the vtable, not in the IMT\n", slot);
-#endif
-               return slot;
-       } else {
-               MonoMethod *imt_method = mono_arch_find_imt_method (regs, code);
-               MonoMethod *impl;
-               int interface_offset;
-               int imt_slot = MONO_IMT_SIZE + displacement;
-
-               /*This has to be variance aware since imt_method can be from an interface that vt->klass doesn't directly implement*/
-               interface_offset = mono_class_interface_offset_with_variance (vt->klass, imt_method->klass, variance_used);
-
-               if (interface_offset < 0) {
-                       g_error ("%s doesn't implement interface %s\n", mono_type_get_name_full (&vt->klass->byval_arg, 0), mono_type_get_name_full (&imt_method->klass->byval_arg, 0));
-               }
-               mono_vtable_build_imt_slot (vt, mono_method_get_imt_slot (imt_method));
+       MonoMethod *impl = NULL, *generic_virtual = NULL;
+       gboolean lookup_aot, variance_used = FALSE, need_rgctx_tramp = FALSE;
+       gpointer addr;
+       guint8 *aot_addr = NULL;
+       int displacement = vtable_slot - ((gpointer*)vt);
+       int interface_offset;
+       int imt_slot = MONO_IMT_SIZE + displacement;
+
+       g_assert (imt_slot < MONO_IMT_SIZE);
+
+       /* This has to be variance aware since imt_method can be from an interface that vt->klass doesn't directly implement */
+       interface_offset = mono_class_interface_offset_with_variance (vt->klass, imt_method->klass, &variance_used);
+       if (interface_offset < 0)
+               g_error ("%s doesn't implement interface %s\n", mono_type_get_name_full (&vt->klass->byval_arg, 0), mono_type_get_name_full (&imt_method->klass->byval_arg, 0));
+
+       *variant_iface = NULL;
+       if (imt_method->is_inflated && ((MonoMethodInflated*)imt_method)->context.method_inst) {
+               /* Generic virtual method */
+               generic_virtual = imt_method;
+               need_rgctx_tramp = TRUE;
+       } else if (variance_used && mono_class_has_variant_generic_params (imt_method->klass)) {
+               *variant_iface = imt_method;
+       }
 
-               if (imt_method->is_inflated && ((MonoMethodInflated*)imt_method)->context.method_inst) {
-                       MonoError error;
-                       MonoGenericContext context = { NULL, NULL };
+       addr = NULL;
+       /* We can only use the AOT compiled code if we don't require further processing */
+       lookup_aot = !generic_virtual & !variant_iface;
 
-                       /* 
-                        * Generic virtual method, imt_method contains the inflated interface 
-                        * method, need to get the inflated impl method.
-                        */
-                       /* imt_method->slot might not be set */
-                       impl = mono_class_get_vtable_entry (vt->klass, interface_offset + mono_method_get_declaring_generic_method (imt_method)->slot);
+       mono_vtable_build_imt_slot (vt, mono_method_get_imt_slot (imt_method));
 
-                       if (impl->klass->generic_class)
-                               context.class_inst = impl->klass->generic_class->context.class_inst;
-                       context.method_inst = ((MonoMethodInflated*)imt_method)->context.method_inst;
-                       impl = mono_class_inflate_generic_method_checked (impl, &context, &error);
-                       g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
-               } else {
-                       /* Avoid loading metadata or creating a generic vtable if possible */
-                       if (lookup_aot && !vt->klass->valuetype)
-                               *aot_addr = mono_aot_get_method_from_vt_slot (mono_domain_get (), vt, interface_offset + mono_method_get_vtable_slot (imt_method));
-                       else
-                               *aot_addr = NULL;
-                       if (*aot_addr)
-                               impl = NULL;
-                       else
-                               impl = mono_class_get_vtable_entry (vt->klass, interface_offset + mono_method_get_vtable_slot (imt_method));
-               }
+       if (imt_method->is_inflated && ((MonoMethodInflated*)imt_method)->context.method_inst) {
+               MonoError error;
+               MonoGenericContext context = { NULL, NULL };
 
-               if (impl && mono_method_needs_static_rgctx_invoke (impl, FALSE))
-                       *need_rgctx_tramp = TRUE;
-               if (impl && impl->wrapper_type == MONO_WRAPPER_MANAGED_TO_MANAGED) {
-                       WrapperInfo *info = mono_marshal_get_wrapper_info (impl);
+               /*
+                * Generic virtual method, imt_method contains the inflated interface
+                * method, need to get the inflated impl method.
+                */
+               /* imt_method->slot might not be set */
+               impl = mono_class_get_vtable_entry (vt->klass, interface_offset + mono_method_get_declaring_generic_method (imt_method)->slot);
 
-                       if (info && info->subtype == WRAPPER_SUBTYPE_GENERIC_ARRAY_HELPER) {
-                               *need_rgctx_tramp = TRUE;
-                       }
-               }
+               if (impl->klass->generic_class)
+                       context.class_inst = impl->klass->generic_class->context.class_inst;
+               context.method_inst = ((MonoMethodInflated*)imt_method)->context.method_inst;
+               impl = mono_class_inflate_generic_method_checked (impl, &context, &error);
+               g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
+       } else {
+               /* Avoid loading metadata or creating a generic vtable if possible */
+               if (lookup_aot && !vt->klass->valuetype)
+                       aot_addr = mono_aot_get_method_from_vt_slot (mono_domain_get (), vt, interface_offset + mono_method_get_vtable_slot (imt_method));
+               else
+                       aot_addr = NULL;
+               if (aot_addr)
+                       impl = NULL;
+               else
+                       impl = mono_class_get_vtable_entry (vt->klass, interface_offset + mono_method_get_vtable_slot (imt_method));
+       }
 
-               *impl_method = impl;
-#if DEBUG_IMT
-               printf ("mono_convert_imt_slot_to_vtable_slot: method = %s.%s.%s, imt_method = %s.%s.%s\n",
-                               method->klass->name_space, method->klass->name, method->name, 
-                               imt_method->klass->name_space, imt_method->klass->name, imt_method->name);
-#endif
+       if (impl && mono_method_needs_static_rgctx_invoke (impl, FALSE))
+               need_rgctx_tramp = TRUE;
+       if (impl && impl->wrapper_type == MONO_WRAPPER_MANAGED_TO_MANAGED) {
+               WrapperInfo *info = mono_marshal_get_wrapper_info (impl);
 
-               g_assert (imt_slot < MONO_IMT_SIZE);
-               if (vt->imt_collisions_bitmap & (1 << imt_slot)) {
-                       int slot = mono_method_get_vtable_index (imt_method);
-                       int vtable_offset;
-                       gpointer *vtable_slot;
-
-                       g_assert (slot != -1);
-                       vtable_offset = interface_offset + slot;
-                       vtable_slot = & (vt->vtable [vtable_offset]);
-#if DEBUG_IMT
-                       printf ("mono_convert_imt_slot_to_vtable_slot: slot %p[%d] is in the IMT, and colliding becomes %p[%d] (interface_offset = %d, method->slot = %d)\n", slot, imt_slot, vtable_slot, vtable_offset, interface_offset, imt_method->slot);
-#endif
-                       return vtable_slot;
-               } else {
-#if DEBUG_IMT
-                       printf ("mono_convert_imt_slot_to_vtable_slot: slot %p[%d] is in the IMT, but not colliding\n", slot, imt_slot);
-#endif
-                       return slot;
-               }
+               if (info && info->subtype == WRAPPER_SUBTYPE_GENERIC_ARRAY_HELPER)
+                       need_rgctx_tramp = TRUE;
+       }
+       *impl_method = impl;
+       *out_need_rgctx_tramp = need_rgctx_tramp;
+       *out_aot_addr = aot_addr;
+
+       DEBUG_IMT (printf ("mono_convert_imt_slot_to_vtable_slot: method = %s.%s.%s, imt_method = %s.%s.%s\n",
+                                          method->klass->name_space, method->klass->name, method->name,
+                                          imt_method->klass->name_space, imt_method->klass->name, imt_method->name));
+
+       if (vt->imt_collisions_bitmap & (1 << imt_slot)) {
+               int slot = mono_method_get_vtable_index (imt_method);
+               int vtable_offset;
+
+               g_assert (slot != -1);
+               vtable_offset = interface_offset + slot;
+               vtable_slot = & (vt->vtable [vtable_offset]);
+               DEBUG_IMT (printf ("mono_convert_imt_slot_to_vtable_slot: slot %p[%d] is in the IMT, and colliding becomes %p[%d] (interface_offset = %d, method->slot = %d)\n", slot, imt_slot, vtable_slot, vtable_offset, interface_offset, imt_method->slot));
+               return vtable_slot;
+       } else {
+               DEBUG_IMT (printf ("mono_convert_imt_slot_to_vtable_slot: slot %p[%d] is in the IMT, but not colliding\n", slot, imt_slot));
+               return vtable_slot;
        }
 }
 
@@ -269,8 +270,7 @@ is_generic_method_definition (MonoMethod *m)
 gboolean
 mini_jit_info_is_gsharedvt (MonoJitInfo *ji)
 {
-       if (ji && ji->has_generic_jit_info && (mono_jit_info_get_generic_sharing_context (ji)->var_is_vt ||
-                                                                                  mono_jit_info_get_generic_sharing_context (ji)->mvar_is_vt))
+       if (ji && ji->has_generic_jit_info && (mono_jit_info_get_generic_sharing_context (ji)->is_gsharedvt))
                return TRUE;
        else
                return FALSE;
@@ -278,7 +278,6 @@ mini_jit_info_is_gsharedvt (MonoJitInfo *ji)
 
 /**
  * mini_add_method_trampoline:
- * @orig_method: the method the caller originally called i.e. an iface method, or NULL.
  * @m: 
  * @compiled_method:
  * @add_static_rgctx_tramp: adds a static rgctx trampoline
@@ -291,7 +290,7 @@ mini_jit_info_is_gsharedvt (MonoJitInfo *ji)
  * is needed.
  */
 gpointer
-mini_add_method_trampoline (MonoMethod *orig_method, MonoMethod *m, gpointer compiled_method, gboolean add_static_rgctx_tramp, gboolean add_unbox_tramp)
+mini_add_method_trampoline (MonoMethod *m, gpointer compiled_method, gboolean add_static_rgctx_tramp, gboolean add_unbox_tramp)
 {
        gpointer addr = compiled_method;
        gboolean callee_gsharedvt, callee_array_helper;
@@ -323,9 +322,6 @@ mini_add_method_trampoline (MonoMethod *orig_method, MonoMethod *m, gpointer com
                }
        }
 
-       if (!orig_method)
-               orig_method = m;
-
        if (callee_gsharedvt)
                g_assert (m->is_inflated);
 
@@ -344,21 +340,18 @@ mini_add_method_trampoline (MonoMethod *orig_method, MonoMethod *m, gpointer com
                }
        }
 
-       if (ji)
+       if (ji && !ji->is_trampoline)
                jmethod = jinfo_get_method (ji);
        if (callee_gsharedvt && mini_is_gsharedvt_variable_signature (mono_method_signature (jmethod))) {
-               MonoGenericSharingContext *gsctx;
                MonoMethodSignature *sig, *gsig;
 
                /* Here m is a generic instance, while ji->method is the gsharedvt method implementing it */
 
                /* Call from normal/gshared code to gsharedvt code with variable signature */
-               gsctx = mono_jit_info_get_generic_sharing_context (ji);
-
                sig = mono_method_signature (m);
                gsig = mono_method_signature (jmethod);
 
-               addr = mini_get_gsharedvt_wrapper (TRUE, addr, sig, gsig, gsctx, -1, FALSE);
+               addr = mini_get_gsharedvt_wrapper (TRUE, addr, sig, gsig, -1, FALSE);
 
                //printf ("IN: %s\n", mono_method_full_name (m, TRUE));
        }
@@ -386,66 +379,56 @@ mini_add_method_trampoline (MonoMethod *orig_method, MonoMethod *m, gpointer com
  * from JITted and LLVM compiled code.
  */
 static gpointer
-common_call_trampoline (mgreg_t *regs, guint8 *code, MonoMethod *m, guint8* tramp, MonoVTable *vt, gpointer *vtable_slot, gboolean need_rgctx_tramp)
+common_call_trampoline_inner (mgreg_t *regs, guint8 *code, MonoMethod *m, MonoVTable *vt, gpointer *vtable_slot)
 {
        gpointer addr, compiled_method;
        gboolean generic_shared = FALSE;
        gboolean need_unbox_tramp = FALSE;
+       gboolean need_rgctx_tramp = FALSE;
        MonoMethod *declaring = NULL;
-       MonoMethod *generic_virtual = NULL, *variant_iface = NULL, *orig_method = NULL;
+       MonoMethod *generic_virtual = NULL, *variant_iface = NULL;
        int context_used;
-       gboolean virtual, variance_used = FALSE;
+       gboolean imt_call, virtual;
        gpointer *orig_vtable_slot, *vtable_slot_to_patch = NULL;
        MonoJitInfo *ji = NULL;
 
-       virtual = (gpointer)vtable_slot > (gpointer)vt;
+       virtual = vt && (gpointer)vtable_slot > (gpointer)vt;
+       imt_call = vt && (gpointer)vtable_slot < (gpointer)vt;
+
+       /*
+        * rgctx trampolines are needed when the call is indirect so the caller can't pass
+        * the rgctx argument needed by the callee.
+        */
+       if (virtual && m)
+               need_rgctx_tramp = mono_method_needs_static_rgctx_invoke (m, FALSE);
 
        orig_vtable_slot = vtable_slot;
        vtable_slot_to_patch = vtable_slot;
 
        /* IMT call */
-       if (vt && (gpointer)vtable_slot < (gpointer)vt) {
-               MonoMethod *impl_method = NULL;
+       if (imt_call) {
+               MonoMethod *imt_method = NULL, *impl_method = NULL;
                MonoObject *this_arg;
 
-               /* we get the interface method because mono_convert_imt_slot_to_vtable_slot ()
-                * needs the signature to be able to find the this argument
-                */
-               m = mono_arch_find_imt_method (regs, code);
-               vtable_slot = orig_vtable_slot;
                g_assert (vtable_slot);
 
-               orig_method = m;
-
+               imt_method = mono_arch_find_imt_method (regs, code);
                this_arg = mono_arch_get_this_arg_from_call (regs, code);
 
                if (mono_object_is_transparent_proxy (this_arg)) {
                        /* Use the slow path for now */
-                   m = mono_object_get_virtual_method (this_arg, m);
+                   m = mono_object_get_virtual_method (this_arg, imt_method);
                        vtable_slot_to_patch = NULL;
                } else {
-                       gboolean lookup_aot;
-
-                       mono_class_interface_offset_with_variance (vt->klass, m->klass, &variance_used);
-
-                       if (m->is_inflated && ((MonoMethodInflated*)m)->context.method_inst) {
+                       if (imt_method->is_inflated && ((MonoMethodInflated*)imt_method)->context.method_inst) {
                                /* Generic virtual method */
-                               generic_virtual = m;
+                               generic_virtual = imt_method;
                                need_rgctx_tramp = TRUE;
-                       } else if (variance_used && mono_class_has_variant_generic_params (m->klass)) {
-                               variant_iface = m;
                        }
 
-                       addr = NULL;
-                       /* We can only use the AOT compiled code if we don't require further processing */
-                       lookup_aot = !generic_virtual & !variant_iface;
-                       vtable_slot = mono_convert_imt_slot_to_vtable_slot (vtable_slot, regs, code, m, lookup_aot, &impl_method, &need_rgctx_tramp, &variance_used, &addr);
+                       vtable_slot = mini_resolve_imt_method (vt, vtable_slot, imt_method, &impl_method, &addr, &need_rgctx_tramp, &variant_iface);
                        /* This is the vcall slot which gets called through the IMT thunk */
                        vtable_slot_to_patch = vtable_slot;
-                       /* mono_convert_imt_slot_to_vtable_slot () also gives us the method that is supposed
-                        * to be called, so we compile it and go ahead as usual.
-                        */
-                       /*g_print ("imt found method %p (%s) at %p\n", impl_method, impl_method->name, code);*/
 
                        if (addr) {
                                /*
@@ -481,10 +464,9 @@ common_call_trampoline (mgreg_t *regs, guint8 *code, MonoMethod *m, guint8* tram
                        g_assert (!m->klass->generic_container);
 
                generic_virtual = mono_arch_find_imt_method (regs, code);
-               if (generic_virtual) {
-                       g_assert (generic_virtual->is_inflated);
-                       context.method_inst = ((MonoMethodInflated*)generic_virtual)->context.method_inst;
-               }
+               g_assert (generic_virtual);
+               g_assert (generic_virtual->is_inflated);
+               context.method_inst = ((MonoMethodInflated*)generic_virtual)->context.method_inst;
 
                m = mono_class_inflate_generic_method_checked (declaring, &context, &error);
                g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
@@ -501,23 +483,18 @@ common_call_trampoline (mgreg_t *regs, guint8 *code, MonoMethod *m, guint8* tram
 
                g_assert (code);
 
+               /*
+                * The caller is gshared code, compute the actual method to call from M and this/rgctx.
+                */
                if (m->is_inflated && mono_method_get_context (m)->method_inst) {
-#ifdef MONO_ARCH_RGCTX_REG
                        MonoMethodRuntimeGenericContext *mrgctx = (MonoMethodRuntimeGenericContext*)mono_arch_find_static_call_vtable (regs, code);
 
                        klass = mrgctx->class_vtable->klass;
                        method_inst = mrgctx->method_inst;
-#else
-                       g_assert_not_reached ();
-#endif
                } else if ((m->flags & METHOD_ATTRIBUTE_STATIC) || m->klass->valuetype) {
-#ifdef MONO_ARCH_RGCTX_REG
                        MonoVTable *vtable = mono_arch_find_static_call_vtable (regs, code);
 
                        klass = vtable->klass;
-#else
-                       g_assert_not_reached ();
-#endif
                } else {
                        MonoObject *this_argument = mono_arch_get_this_arg_from_call (regs, code);
 
@@ -525,7 +502,6 @@ common_call_trampoline (mgreg_t *regs, guint8 *code, MonoMethod *m, guint8* tram
                        vtable_slot = orig_vtable_slot;
 
                        g_assert (this_argument->vtable->klass->inited);
-                       //mono_class_init (this_argument->vtable->klass);
 
                        if (!vtable_slot) {
                                mono_class_setup_supertypes (this_argument->vtable->klass);
@@ -598,7 +574,7 @@ common_call_trampoline (mgreg_t *regs, guint8 *code, MonoMethod *m, guint8* tram
                        need_unbox_tramp = TRUE;
        }
 
-       addr = mini_add_method_trampoline (orig_method, m, compiled_method, need_rgctx_tramp, need_unbox_tramp);
+       addr = mini_add_method_trampoline (m, compiled_method, need_rgctx_tramp, need_unbox_tramp);
 
        if (generic_virtual || variant_iface) {
                MonoMethod *target = generic_virtual ? generic_virtual : variant_iface;
@@ -648,8 +624,7 @@ common_call_trampoline (mgreg_t *regs, guint8 *code, MonoMethod *m, guint8* tram
                        g_assert (*vtable_slot_to_patch);
                        *vtable_slot_to_patch = mono_get_addr_from_ftnptr (addr);
                }
-       }
-       else {
+       } else {
                guint8 *plt_entry = mono_aot_get_plt_entry (code);
                gboolean no_patch = FALSE;
                MonoJitInfo *target_ji;
@@ -697,6 +672,16 @@ common_call_trampoline (mgreg_t *regs, guint8 *code, MonoMethod *m, guint8* tram
        return addr;
 }
 
+static gpointer
+common_call_trampoline (mgreg_t *regs, guint8 *code, MonoMethod *m, MonoVTable *vt, gpointer *vtable_slot)
+{
+       gpointer res;
+       MONO_PREPARE_RESET_BLOCKING;
+       res = common_call_trampoline_inner (regs, code, m, vt, vtable_slot);
+       MONO_FINISH_RESET_BLOCKING;
+       return res;
+}
+
 /**
  * mono_magic_trampoline:
  *
@@ -707,7 +692,7 @@ mono_magic_trampoline (mgreg_t *regs, guint8 *code, gpointer arg, guint8* tramp)
 {
        trampoline_calls ++;
 
-       return common_call_trampoline (regs, code, arg, tramp, NULL, NULL, FALSE);
+       return common_call_trampoline (regs, code, arg, NULL, NULL);
 }
 
 /**
@@ -718,11 +703,10 @@ mono_magic_trampoline (mgreg_t *regs, guint8 *code, gpointer arg, guint8* tramp)
 static gpointer
 mono_vcall_trampoline (mgreg_t *regs, guint8 *code, int slot, guint8 *tramp)
 {
-       MonoObject *this;
+       MonoObject *this_arg;
        MonoVTable *vt;
        gpointer *vtable_slot;
        MonoMethod *m;
-       gboolean need_rgctx_tramp = FALSE;
        gpointer addr;
 
        trampoline_calls ++;
@@ -738,10 +722,10 @@ mono_vcall_trampoline (mgreg_t *regs, guint8 *code, int slot, guint8 *tramp)
        /*
         * Obtain the vtable from the 'this' arg.
         */
-       this = mono_arch_get_this_arg_from_call (regs, code);
-       g_assert (this);
+       this_arg = mono_arch_get_this_arg_from_call (regs, code);
+       g_assert (this_arg);
 
-       vt = this->vtable;
+       vt = this_arg->vtable;
 
        if (slot >= 0) {
                /* Normal virtual call */
@@ -770,17 +754,14 @@ mono_vcall_trampoline (mgreg_t *regs, guint8 *code, int slot, guint8 *tramp)
                 * trustworthy.
                 */
                m = mono_class_get_vtable_entry (vt->klass, slot);
-
-               need_rgctx_tramp = mono_method_needs_static_rgctx_invoke (m, 0);
        } else {
                /* IMT call */
                vtable_slot = &(((gpointer*)vt) [slot]);
 
                m = NULL;
-               need_rgctx_tramp = FALSE;
        }
 
-       return common_call_trampoline (regs, code, m, tramp, vt, vtable_slot, need_rgctx_tramp);
+       return common_call_trampoline (regs, code, m, vt, vtable_slot);
 }
 
 #ifndef DISABLE_REMOTING
@@ -889,47 +870,9 @@ mono_aot_plt_trampoline (mgreg_t *regs, guint8 *code, guint8 *aot_module,
 }
 #endif
 
-/**
- * mono_class_init_trampoline:
- *
- * This method calls mono_runtime_class_init () to run the static constructor
- * for the type, then patches the caller code so it is not called again.
- */
-void
-mono_class_init_trampoline (mgreg_t *regs, guint8 *code, MonoVTable *vtable, guint8 *tramp)
-{
-       guint8 *plt_entry = mono_aot_get_plt_entry (code);
-
-       trampoline_calls ++;
-
-       mono_runtime_class_init (vtable);
-
-       if (vtable->initialized) {
-               if (plt_entry)
-                       mono_aot_patch_plt_entry (code, plt_entry, NULL, regs, mini_get_nullified_class_init_trampoline ());
-               else
-                       mono_arch_nullify_class_init_trampoline (code, regs);
-       }
-}
-
-/**
- * mono_generic_class_init_trampoline:
- *
- * This method calls mono_runtime_class_init () to run the static constructor
- * for the type.
- */
-void
-mono_generic_class_init_trampoline (mgreg_t *regs, guint8 *code, MonoVTable *vtable, guint8 *tramp)
-{
-       trampoline_calls ++;
-
-       mono_runtime_class_init (vtable);
-}
-
 static gpointer
 mono_rgctx_lazy_fetch_trampoline (mgreg_t *regs, guint8 *code, gpointer data, guint8 *tramp)
 {
-#ifdef MONO_ARCH_VTABLE_REG
        static gboolean inited = FALSE;
        static int num_lookups = 0;
        guint32 slot = GPOINTER_TO_UINT (data);
@@ -948,39 +891,11 @@ mono_rgctx_lazy_fetch_trampoline (mgreg_t *regs, guint8 *code, gpointer data, gu
        num_lookups++;
 
        if (mrgctx)
-               return mono_method_fill_runtime_generic_context (arg, code, index);
+               return mono_method_fill_runtime_generic_context (arg, index);
        else
-               return mono_class_fill_runtime_generic_context (arg, code, index);
-#else
-       g_assert_not_reached ();
-#endif
+               return mono_class_fill_runtime_generic_context (arg, index);
 }
 
-void
-mono_monitor_enter_trampoline (mgreg_t *regs, guint8 *code, MonoObject *obj, guint8 *tramp)
-{
-       mono_monitor_enter (obj);
-}
-
-void
-mono_monitor_enter_v4_trampoline (mgreg_t *regs, guint8 *code, MonoObject *obj, guint8 *tramp)
-{
-#ifdef MONO_ARCH_MONITOR_LOCK_TAKEN_REG
-       char *lock_taken = (char*)regs [MONO_ARCH_MONITOR_LOCK_TAKEN_REG];
-       mono_monitor_enter_v4 (obj, lock_taken);
-#else
-       g_assert_not_reached ();
-#endif
-}
-
-void
-mono_monitor_exit_trampoline (mgreg_t *regs, guint8 *code, MonoObject *obj, guint8 *tramp)
-{
-       mono_monitor_exit (obj);
-}
-
-#ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
-
 /*
  * Precompute data to speed up mono_delegate_trampoline ().
  * METHOD might be NULL.
@@ -1042,6 +957,7 @@ mono_delegate_trampoline (mgreg_t *regs, guint8 *code, gpointer *arg, guint8* tr
 
        /* Obtain the delegate object according to the calling convention */
        delegate = mono_arch_get_this_arg_from_call (regs, code);
+       g_assert (mono_class_has_parent (mono_object_class (delegate), mono_defaults.multicastdelegate_class));
 
        if (delegate->method) {
                method = delegate->method;
@@ -1073,13 +989,23 @@ mono_delegate_trampoline (mgreg_t *regs, guint8 *code, gpointer *arg, guint8* tr
                        }
 
                        if (sig->hasthis && method->klass->valuetype) {
-                               if (mono_aot_only)
-                                       need_unbox_tramp = TRUE;
-                               else
-                                       method = mono_marshal_get_unbox_wrapper (method);
+                               gboolean need_unbox = TRUE;
+
+                               if (tramp_info->invoke_sig->param_count > sig->param_count && tramp_info->invoke_sig->params [0]->byref)
+                                       need_unbox = FALSE;
+
+                               if (need_unbox) {
+                                       if (mono_aot_only)
+                                               need_unbox_tramp = TRUE;
+                                       else
+                                               method = mono_marshal_get_unbox_wrapper (method);
+                               }
                        }
                }
-       } else {
+       // If "delegate->method_ptr" is null mono_get_addr_from_ftnptr will fail if
+       // ftnptrs are being used.  "method" would end up null on archtitectures without
+       // ftnptrs so we can just skip this.
+       } else if (delegate->method_ptr) {
                ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (delegate->method_ptr));
                if (ji)
                        method = jinfo_get_method (ji);
@@ -1141,7 +1067,7 @@ mono_delegate_trampoline (mgreg_t *regs, guint8 *code, gpointer *arg, guint8* tr
                        delegate->method_ptr = *delegate->method_code;
                } else {
                        compiled_method = addr = mono_compile_method (method);
-                       addr = mini_add_method_trampoline (NULL, method, compiled_method, need_rgctx_tramp, need_unbox_tramp);
+                       addr = mini_add_method_trampoline (method, compiled_method, need_rgctx_tramp, need_unbox_tramp);
                        delegate->method_ptr = addr;
                        if (enable_caching && delegate->method_code)
                                *delegate->method_code = delegate->method_ptr;
@@ -1154,7 +1080,7 @@ mono_delegate_trampoline (mgreg_t *regs, guint8 *code, gpointer *arg, guint8* tr
        /* Necessary for !code condition to fallback to slow path */
        code = NULL;
 
-       multicast = ((MonoMulticastDelegate*)delegate)->prev != NULL;
+       multicast = ((MonoMulticastDelegate*)delegate)->delegates != NULL;
        if (!multicast && !callvirt) {
                if (method && (method->flags & METHOD_ATTRIBUTE_STATIC) && mono_method_signature (method)->param_count == mono_method_signature (invoke)->param_count + 1)
                        /* Closed static delegate */
@@ -1167,7 +1093,7 @@ mono_delegate_trampoline (mgreg_t *regs, guint8 *code, gpointer *arg, guint8* tr
                /* The general, unoptimized case */
                m = mono_marshal_get_delegate_invoke (invoke, delegate);
                code = mono_compile_method (m);
-               code = mini_add_method_trampoline (NULL, m, code, mono_method_needs_static_rgctx_invoke (m, FALSE), FALSE);
+               code = mini_add_method_trampoline (m, code, mono_method_needs_static_rgctx_invoke (m, FALSE), FALSE);
        }
 
        delegate->invoke_impl = mono_get_addr_from_ftnptr (code);
@@ -1179,8 +1105,6 @@ mono_delegate_trampoline (mgreg_t *regs, guint8 *code, gpointer *arg, guint8* tr
        return code;
 }
 
-#endif
-
 #ifdef MONO_ARCH_HAVE_HANDLER_BLOCK_GUARD
 static gpointer
 mono_handler_block_guard_trampoline (mgreg_t *regs, guint8 *code, gpointer *tramp_info, guint8* tramp)
@@ -1227,7 +1151,7 @@ mono_create_handler_block_trampoline (void)
                gpointer tmp;
 
                tmp = mono_arch_create_handler_block_trampoline (&info, FALSE);
-               mono_tramp_info_register (info);
+               mono_tramp_info_register (info, NULL);
                mono_memory_barrier ();
                code = tmp;
        }
@@ -1250,10 +1174,6 @@ mono_get_trampoline_func (MonoTrampolineType tramp_type)
        case MONO_TRAMPOLINE_JIT:
        case MONO_TRAMPOLINE_JUMP:
                return mono_magic_trampoline;
-       case MONO_TRAMPOLINE_CLASS_INIT:
-               return mono_class_init_trampoline;
-       case MONO_TRAMPOLINE_GENERIC_CLASS_INIT:
-               return mono_generic_class_init_trampoline;
        case MONO_TRAMPOLINE_RGCTX_LAZY_FETCH:
                return mono_rgctx_lazy_fetch_trampoline;
 #ifdef MONO_ARCH_AOT_SUPPORTED
@@ -1262,22 +1182,14 @@ mono_get_trampoline_func (MonoTrampolineType tramp_type)
        case MONO_TRAMPOLINE_AOT_PLT:
                return mono_aot_plt_trampoline;
 #endif
-#ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
        case MONO_TRAMPOLINE_DELEGATE:
                return mono_delegate_trampoline;
-#endif
        case MONO_TRAMPOLINE_RESTORE_STACK_PROT:
                return mono_altstack_restore_prot;
 #ifndef DISABLE_REMOTING
        case MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING:
                return mono_generic_virtual_remoting_trampoline;
 #endif
-       case MONO_TRAMPOLINE_MONITOR_ENTER:
-               return mono_monitor_enter_trampoline;
-       case MONO_TRAMPOLINE_MONITOR_ENTER_V4:
-               return mono_monitor_enter_v4_trampoline;
-       case MONO_TRAMPOLINE_MONITOR_EXIT:
-               return mono_monitor_exit_trampoline;
        case MONO_TRAMPOLINE_VCALL:
                return mono_vcall_trampoline;
 #ifdef MONO_ARCH_HAVE_HANDLER_BLOCK_GUARD
@@ -1297,7 +1209,7 @@ create_trampoline_code (MonoTrampolineType tramp_type)
        guchar *code;
 
        code = mono_arch_create_generic_trampoline (tramp_type, &info, FALSE);
-       mono_tramp_info_register (info);
+       mono_tramp_info_register (info, NULL);
 
        return code;
 }
@@ -1312,23 +1224,16 @@ mono_trampolines_init (void)
 
        mono_trampoline_code [MONO_TRAMPOLINE_JIT] = create_trampoline_code (MONO_TRAMPOLINE_JIT);
        mono_trampoline_code [MONO_TRAMPOLINE_JUMP] = create_trampoline_code (MONO_TRAMPOLINE_JUMP);
-       mono_trampoline_code [MONO_TRAMPOLINE_CLASS_INIT] = create_trampoline_code (MONO_TRAMPOLINE_CLASS_INIT);
-       mono_trampoline_code [MONO_TRAMPOLINE_GENERIC_CLASS_INIT] = create_trampoline_code (MONO_TRAMPOLINE_GENERIC_CLASS_INIT);
        mono_trampoline_code [MONO_TRAMPOLINE_RGCTX_LAZY_FETCH] = create_trampoline_code (MONO_TRAMPOLINE_RGCTX_LAZY_FETCH);
 #ifdef MONO_ARCH_AOT_SUPPORTED
        mono_trampoline_code [MONO_TRAMPOLINE_AOT] = create_trampoline_code (MONO_TRAMPOLINE_AOT);
        mono_trampoline_code [MONO_TRAMPOLINE_AOT_PLT] = create_trampoline_code (MONO_TRAMPOLINE_AOT_PLT);
 #endif
-#ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
        mono_trampoline_code [MONO_TRAMPOLINE_DELEGATE] = create_trampoline_code (MONO_TRAMPOLINE_DELEGATE);
-#endif
        mono_trampoline_code [MONO_TRAMPOLINE_RESTORE_STACK_PROT] = create_trampoline_code (MONO_TRAMPOLINE_RESTORE_STACK_PROT);
 #ifndef DISABLE_REMOTING
        mono_trampoline_code [MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING] = create_trampoline_code (MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING);
 #endif
-       mono_trampoline_code [MONO_TRAMPOLINE_MONITOR_ENTER] = create_trampoline_code (MONO_TRAMPOLINE_MONITOR_ENTER);
-       mono_trampoline_code [MONO_TRAMPOLINE_MONITOR_ENTER_V4] = create_trampoline_code (MONO_TRAMPOLINE_MONITOR_ENTER_V4);
-       mono_trampoline_code [MONO_TRAMPOLINE_MONITOR_EXIT] = create_trampoline_code (MONO_TRAMPOLINE_MONITOR_EXIT);
        mono_trampoline_code [MONO_TRAMPOLINE_VCALL] = create_trampoline_code (MONO_TRAMPOLINE_VCALL);
 #ifdef MONO_ARCH_HAVE_HANDLER_BLOCK_GUARD
        mono_trampoline_code [MONO_TRAMPOLINE_HANDLER_BLOCK_GUARD] = create_trampoline_code (MONO_TRAMPOLINE_HANDLER_BLOCK_GUARD);
@@ -1344,8 +1249,6 @@ mono_trampolines_init (void)
 void
 mono_trampolines_cleanup (void)
 {
-       if (class_init_hash_addr)
-               g_hash_table_destroy (class_init_hash_addr);
        if (rgctx_lazy_fetch_trampoline_hash)
                g_hash_table_destroy (rgctx_lazy_fetch_trampoline_hash);
        if (rgctx_lazy_fetch_trampoline_hash_addr)
@@ -1371,69 +1274,6 @@ mono_create_specific_trampoline (gpointer arg1, MonoTrampolineType tramp_type, M
                return mono_arch_create_specific_trampoline (arg1, tramp_type, domain, code_len);
 }
 
-gpointer
-mono_create_class_init_trampoline (MonoVTable *vtable)
-{
-       gpointer code, ptr;
-       MonoDomain *domain = vtable->domain;
-
-       g_assert (!vtable->klass->generic_container);
-
-       /* previously created trampoline code */
-       mono_domain_lock (domain);
-       ptr = 
-               g_hash_table_lookup (domain_jit_info (domain)->class_init_trampoline_hash,
-                                                                 vtable);
-       mono_domain_unlock (domain);
-       if (ptr)
-               return ptr;
-
-       code = mono_create_specific_trampoline (vtable, MONO_TRAMPOLINE_CLASS_INIT, domain, NULL);
-
-       ptr = mono_create_ftnptr (domain, code);
-
-       /* store trampoline address */
-       mono_domain_lock (domain);
-       g_hash_table_insert (domain_jit_info (domain)->class_init_trampoline_hash,
-                                                         vtable, ptr);
-       mono_domain_unlock (domain);
-
-       mono_trampolines_lock ();
-       if (!class_init_hash_addr)
-               class_init_hash_addr = g_hash_table_new (NULL, NULL);
-       g_hash_table_insert (class_init_hash_addr, ptr, vtable);
-       mono_trampolines_unlock ();
-
-       return ptr;
-}
-
-gpointer
-mono_create_generic_class_init_trampoline (void)
-{
-#ifdef MONO_ARCH_VTABLE_REG
-       static gpointer code;
-       MonoTrampInfo *info;
-
-       mono_trampolines_lock ();
-
-       if (!code) {
-               if (mono_aot_only)
-                       /* get_named_code () might return an ftnptr, but our caller expects a direct pointer */
-                       code = mono_get_addr_from_ftnptr (mono_aot_get_trampoline ("generic_class_init_trampoline"));
-               else {
-                       code = mono_arch_create_generic_class_init_trampoline (&info, FALSE);
-                       mono_tramp_info_register (info);
-               }
-       }
-
-       mono_trampolines_unlock ();
-
-       return code;
-#else
-       g_assert_not_reached ();
-#endif
-}
-
 gpointer
 mono_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
 {
@@ -1545,7 +1385,6 @@ mono_create_jit_trampoline_from_token (MonoImage *image, guint32 token)
 MonoDelegateTrampInfo*
 mono_create_delegate_trampoline_info (MonoDomain *domain, MonoClass *klass, MonoMethod *method)
 {
-#ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
        MonoDelegateTrampInfo *tramp_info;
        MonoClassMethodPair pair, *dpair;
        guint32 code_size = 0;
@@ -1572,32 +1411,21 @@ mono_create_delegate_trampoline_info (MonoDomain *domain, MonoClass *klass, Mono
        mono_domain_unlock (domain);
 
        return tramp_info;
-#else
-       return NULL;
-#endif
 }
 
 gpointer
 mono_create_delegate_trampoline (MonoDomain *domain, MonoClass *klass)
 {
-#ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
        return mono_create_delegate_trampoline_info (domain, klass, NULL)->invoke_impl;
-#else
-       return NULL;
-#endif
 }
 
 gpointer
 mono_create_delegate_virtual_trampoline (MonoDomain *domain, MonoClass *klass, MonoMethod *method)
 {
-#ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
        MonoMethod *invoke = mono_get_delegate_invoke (klass);
        g_assert (invoke);
 
        return mono_get_delegate_virtual_invoke_impl (mono_method_signature (invoke), method);
-#else
-       return NULL;
-#endif
 }
 
 gpointer
@@ -1622,7 +1450,7 @@ mono_create_rgctx_lazy_fetch_trampoline (guint32 offset)
                ptr = mono_aot_get_lazy_fetch_trampoline (offset);
        } else {
                tramp = mono_arch_create_rgctx_lazy_fetch_trampoline (offset, &info, FALSE);
-               mono_tramp_info_register (info);
+               mono_tramp_info_register (info, NULL);
                ptr = mono_create_ftnptr (mono_get_root_domain (), tramp);
        }
 
@@ -1645,95 +1473,6 @@ mono_create_rgctx_lazy_fetch_trampoline (guint32 offset)
 
        return ptr;
 }
-
-gpointer
-mono_create_monitor_enter_trampoline (void)
-{
-       static gpointer code;
-
-       if (mono_aot_only) {
-               if (!code)
-                       code = mono_aot_get_trampoline ("monitor_enter_trampoline");
-               return code;
-       }
-
-#ifdef MONO_ARCH_MONITOR_OBJECT_REG
-       mono_trampolines_lock ();
-
-       if (!code) {
-               MonoTrampInfo *info;
-
-               code = mono_arch_create_monitor_enter_trampoline (&info, FALSE, FALSE);
-               mono_tramp_info_register (info);
-       }
-
-       mono_trampolines_unlock ();
-#else
-       code = NULL;
-       g_assert_not_reached ();
-#endif
-
-       return code;
-}
-
-gpointer
-mono_create_monitor_enter_v4_trampoline (void)
-{
-       static gpointer code;
-
-       if (mono_aot_only) {
-               if (!code)
-                       code = mono_aot_get_trampoline ("monitor_enter_v4_trampoline");
-               return code;
-       }
-
-#if defined(MONO_ARCH_MONITOR_OBJECT_REG) && defined(MONO_ARCH_MONITOR_LOCK_TAKEN_REG)
-       mono_trampolines_lock ();
-
-       if (!code) {
-               MonoTrampInfo *info;
-
-               code = mono_arch_create_monitor_enter_trampoline (&info, TRUE, FALSE);
-               mono_tramp_info_register (info);
-       }
-
-       mono_trampolines_unlock ();
-#else
-       code = NULL;
-       g_assert_not_reached ();
-#endif
-
-       return code;
-}
-
-gpointer
-mono_create_monitor_exit_trampoline (void)
-{
-       static gpointer code;
-
-       if (mono_aot_only) {
-               if (!code)
-                       code = mono_aot_get_trampoline ("monitor_exit_trampoline");
-               return code;
-       }
-
-#ifdef MONO_ARCH_MONITOR_OBJECT_REG
-       mono_trampolines_lock ();
-
-       if (!code) {
-               MonoTrampInfo *info;
-
-               code = mono_arch_create_monitor_exit_trampoline (&info, FALSE);
-               mono_tramp_info_register (info);
-       }
-
-       mono_trampolines_unlock ();
-#else
-       code = NULL;
-       g_assert_not_reached ();
-#endif
-       return code;
-}
  
 #ifdef MONO_ARCH_LLVM_SUPPORTED
 /*
@@ -1755,20 +1494,6 @@ mono_create_llvm_imt_trampoline (MonoDomain *domain, MonoMethod *m, int vt_offse
 }
 #endif
 
-MonoVTable*
-mono_find_class_init_trampoline_by_addr (gconstpointer addr)
-{
-       MonoVTable *res;
-
-       mono_trampolines_lock ();
-       if (class_init_hash_addr)
-               res = g_hash_table_lookup (class_init_hash_addr, addr);
-       else
-               res = NULL;
-       mono_trampolines_unlock ();
-       return res;
-}
-
 guint32
 mono_find_rgctx_lazy_fetch_trampoline_by_addr (gconstpointer addr)
 {
@@ -1792,17 +1517,12 @@ mono_find_rgctx_lazy_fetch_trampoline_by_addr (gconstpointer addr)
 static const char*tramp_names [MONO_TRAMPOLINE_NUM] = {
        "jit",
        "jump",
-       "class_init",
-       "generic_class_init",
        "rgctx_lazy_fetch",
        "aot",
        "aot_plt",
        "delegate",
        "restore_stack_prot",
        "generic_virtual_remoting",
-       "monitor_enter",
-       "monitor_enter_v4",
-       "monitor_exit",
        "vcall",
        "handler_block_guard"
 };
@@ -1845,28 +1565,6 @@ mono_get_rgctx_fetch_trampoline_name (int slot)
        return g_strdup_printf ("rgctx_fetch_trampoline_%s_%d", mrgctx ? "mrgctx" : "rgctx", index);
 }
 
-gpointer
-mini_get_nullified_class_init_trampoline (void)
-{
-       static gpointer nullified_class_init_trampoline;
-
-       if (!nullified_class_init_trampoline) {
-               gpointer tramp;
-               MonoTrampInfo *info;
-
-               if (mono_aot_only) {
-                       tramp = mono_aot_get_trampoline ("nullified_class_init_trampoline");
-               } else {
-                       tramp = mono_arch_get_nullified_class_init_trampoline (&info);
-                       mono_tramp_info_register (info);
-               }
-               mono_memory_barrier ();
-               nullified_class_init_trampoline = tramp;
-       }
-
-       return nullified_class_init_trampoline;
-}
-
 /*
  * mini_get_single_step_trampoline:
  *
@@ -1886,7 +1584,7 @@ mini_get_single_step_trampoline (void)
 #ifdef MONO_ARCH_HAVE_SDB_TRAMPOLINES
                        MonoTrampInfo *info;
                        tramp = mono_arch_create_sdb_trampoline (TRUE, &info, FALSE);
-                       mono_tramp_info_register (info);
+                       mono_tramp_info_register (info, NULL);
 #else
                        tramp = NULL;
                        g_assert_not_reached ();
@@ -1918,7 +1616,7 @@ mini_get_breakpoint_trampoline (void)
 #ifdef MONO_ARCH_HAVE_SDB_TRAMPOLINES
                        MonoTrampInfo *info;
                        tramp = mono_arch_create_sdb_trampoline (FALSE, &info, FALSE);
-                       mono_tramp_info_register (info);
+                       mono_tramp_info_register (info, NULL);
 #else
                        tramp = NULL;
                        g_assert_not_reached ();