[arm] Fix unwind info for managed methods
[mono.git] / mono / mini / mini-x86.c
index 9941b2387548d4d937b4be19597edfa4d0cb5471..e8136429549c9e2c15043556d3c2ba87fa3a506a 100644 (file)
@@ -300,7 +300,7 @@ add_float (guint32 *gr, guint32 *stack_size, ArgInfo *ainfo, gboolean is_double)
 
 
 static void
-add_valuetype (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, ArgInfo *ainfo, MonoType *type,
+add_valuetype (MonoMethodSignature *sig, ArgInfo *ainfo, MonoType *type,
               gboolean is_return,
               guint32 *gr, const guint32 *param_regs, guint32 *fr, guint32 *stack_size)
 {
@@ -308,7 +308,7 @@ add_valuetype (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, ArgIn
        MonoClass *klass;
 
        klass = mono_class_from_mono_type (type);
-       size = mini_type_stack_size_full (gsctx, &klass->byval_arg, NULL, sig->pinvoke);
+       size = mini_type_stack_size_full (&klass->byval_arg, NULL, sig->pinvoke);
 
 #ifdef SMALL_STRUCTS_IN_REGS
        if (sig->pinvoke && is_return) {
@@ -325,7 +325,7 @@ add_valuetype (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, ArgIn
 
                /* Special case structs with only a float member */
                if (info->num_fields == 1) {
-                       int ftype = mini_type_get_underlying_type (gsctx, info->fields [0].field->type)->type;
+                       int ftype = mini_get_underlying_type (info->fields [0].field->type)->type;
                        if ((info->native_size == 8) && (ftype == MONO_TYPE_R8)) {
                                ainfo->storage = ArgValuetypeInReg;
                                ainfo->pair_storage [0] = ArgOnDoubleFpStack;
@@ -374,7 +374,7 @@ add_valuetype (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, ArgIn
  * For x86 win32, see ???.
  */
 static CallInfo*
-get_call_info_internal (MonoGenericSharingContext *gsctx, CallInfo *cinfo, MonoMethodSignature *sig)
+get_call_info_internal (CallInfo *cinfo, MonoMethodSignature *sig)
 {
        guint32 i, gr, fr, pstart;
        const guint32 *param_regs;
@@ -391,7 +391,7 @@ get_call_info_internal (MonoGenericSharingContext *gsctx, CallInfo *cinfo, MonoM
 
        /* return value */
        {
-               ret_type = mini_type_get_underlying_type (gsctx, sig->ret);
+               ret_type = mini_get_underlying_type (sig->ret);
                switch (ret_type->type) {
                case MONO_TYPE_I1:
                case MONO_TYPE_U1:
@@ -429,7 +429,7 @@ get_call_info_internal (MonoGenericSharingContext *gsctx, CallInfo *cinfo, MonoM
                                cinfo->ret.reg = X86_EAX;
                                break;
                        }
-                       if (mini_is_gsharedvt_type_gsctx (gsctx, ret_type)) {
+                       if (mini_is_gsharedvt_type (ret_type)) {
                                cinfo->ret.storage = ArgOnStack;
                                cinfo->vtype_retaddr = TRUE;
                                break;
@@ -439,7 +439,7 @@ get_call_info_internal (MonoGenericSharingContext *gsctx, CallInfo *cinfo, MonoM
                case MONO_TYPE_TYPEDBYREF: {
                        guint32 tmp_gr = 0, tmp_fr = 0, tmp_stacksize = 0;
 
-                       add_valuetype (gsctx, sig, &cinfo->ret, ret_type, TRUE, &tmp_gr, NULL, &tmp_fr, &tmp_stacksize);
+                       add_valuetype (sig, &cinfo->ret, ret_type, TRUE, &tmp_gr, NULL, &tmp_fr, &tmp_stacksize);
                        if (cinfo->ret.storage == ArgOnStack) {
                                cinfo->vtype_retaddr = TRUE;
                                /* The caller passes the address where the value is stored */
@@ -448,7 +448,7 @@ get_call_info_internal (MonoGenericSharingContext *gsctx, CallInfo *cinfo, MonoM
                }
                case MONO_TYPE_VAR:
                case MONO_TYPE_MVAR:
-                       g_assert (mini_is_gsharedvt_type_gsctx (gsctx, ret_type));
+                       g_assert (mini_is_gsharedvt_type (ret_type));
                        cinfo->ret.storage = ArgOnStack;
                        cinfo->vtype_retaddr = TRUE;
                        break;
@@ -468,7 +468,7 @@ get_call_info_internal (MonoGenericSharingContext *gsctx, CallInfo *cinfo, MonoM
         * are sometimes made using calli without sig->hasthis set, like in the delegate
         * invoke wrappers.
         */
-       if (cinfo->vtype_retaddr && !is_pinvoke && (sig->hasthis || (sig->param_count > 0 && MONO_TYPE_IS_REFERENCE (mini_type_get_underlying_type (gsctx, sig->params [0]))))) {
+       if (cinfo->vtype_retaddr && !is_pinvoke && (sig->hasthis || (sig->param_count > 0 && MONO_TYPE_IS_REFERENCE (mini_get_underlying_type (sig->params [0]))))) {
                if (sig->hasthis) {
                        add_general (&gr, param_regs, &stack_size, cinfo->args + 0);
                } else {
@@ -514,7 +514,7 @@ get_call_info_internal (MonoGenericSharingContext *gsctx, CallInfo *cinfo, MonoM
                        add_general (&gr, param_regs, &stack_size, ainfo);
                        continue;
                }
-               ptype = mini_type_get_underlying_type (gsctx, sig->params [i]);
+               ptype = mini_get_underlying_type (sig->params [i]);
                switch (ptype->type) {
                case MONO_TYPE_I1:
                case MONO_TYPE_U1:
@@ -544,7 +544,7 @@ get_call_info_internal (MonoGenericSharingContext *gsctx, CallInfo *cinfo, MonoM
                                add_general (&gr, param_regs, &stack_size, ainfo);
                                break;
                        }
-                       if (mini_is_gsharedvt_type_gsctx (gsctx, ptype)) {
+                       if (mini_is_gsharedvt_type (ptype)) {
                                /* gsharedvt arguments are passed by ref */
                                add_general (&gr, param_regs, &stack_size, ainfo);
                                g_assert (ainfo->storage == ArgOnStack);
@@ -554,7 +554,7 @@ get_call_info_internal (MonoGenericSharingContext *gsctx, CallInfo *cinfo, MonoM
                        /* Fall through */
                case MONO_TYPE_VALUETYPE:
                case MONO_TYPE_TYPEDBYREF:
-                       add_valuetype (gsctx, sig, ainfo, ptype, FALSE, &gr, param_regs, &fr, &stack_size);
+                       add_valuetype (sig, ainfo, ptype, FALSE, &gr, param_regs, &fr, &stack_size);
                        break;
                case MONO_TYPE_U8:
                case MONO_TYPE_I8:
@@ -569,7 +569,7 @@ get_call_info_internal (MonoGenericSharingContext *gsctx, CallInfo *cinfo, MonoM
                case MONO_TYPE_VAR:
                case MONO_TYPE_MVAR:
                        /* gsharedvt arguments are passed by ref */
-                       g_assert (mini_is_gsharedvt_type_gsctx (gsctx, ptype));
+                       g_assert (mini_is_gsharedvt_type (ptype));
                        add_general (&gr, param_regs, &stack_size, ainfo);
                        g_assert (ainfo->storage == ArgOnStack);
                        ainfo->storage = ArgGSharedVt;
@@ -608,7 +608,7 @@ get_call_info_internal (MonoGenericSharingContext *gsctx, CallInfo *cinfo, MonoM
 }
 
 static CallInfo*
-get_call_info (MonoGenericSharingContext *gsctx, MonoMemPool *mp, MonoMethodSignature *sig)
+get_call_info (MonoMemPool *mp, MonoMethodSignature *sig)
 {
        int n = sig->hasthis + sig->param_count;
        CallInfo *cinfo;
@@ -618,7 +618,7 @@ get_call_info (MonoGenericSharingContext *gsctx, MonoMemPool *mp, MonoMethodSign
        else
                cinfo = g_malloc0 (sizeof (CallInfo) + (sizeof (ArgInfo) * n));
 
-       return get_call_info_internal (gsctx, cinfo, sig);
+       return get_call_info_internal (cinfo, sig);
 }
 
 /*
@@ -632,11 +632,11 @@ get_call_info (MonoGenericSharingContext *gsctx, MonoMemPool *mp, MonoMethodSign
  *
  * Returns the size of the argument area on the stack.
  * This should be signal safe, since it is called from
- * mono_arch_find_jit_info ().
+ * mono_arch_unwind_frame ().
  * FIXME: The metadata calls might not be signal safe.
  */
 int
-mono_arch_get_argument_info (MonoGenericSharingContext *gsctx, MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
+mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
 {
        int len, k, args_size = 0;
        int size, pad;
@@ -649,7 +649,7 @@ mono_arch_get_argument_info (MonoGenericSharingContext *gsctx, MonoMethodSignatu
        cinfo = (CallInfo*)g_newa (guint8*, len);
        memset (cinfo, 0, len);
 
-       cinfo = get_call_info_internal (gsctx, cinfo, csig);
+       cinfo = get_call_info_internal (cinfo, csig);
 
        arg_info [0].offset = offset;
 
@@ -672,7 +672,7 @@ mono_arch_get_argument_info (MonoGenericSharingContext *gsctx, MonoMethodSignatu
        arg_info [0].size = args_size;
 
        for (k = 0; k < param_count; k++) {
-               size = mini_type_stack_size_full (NULL, csig->params [k], &align, csig->pinvoke);
+               size = mini_type_stack_size_full (csig->params [k], &align, csig->pinvoke);
 
                /* ignore alignment for now */
                align = 1;
@@ -714,14 +714,14 @@ mono_arch_tail_call_supported (MonoCompile *cfg, MonoMethodSignature *caller_sig
                /* OP_TAILCALL doesn't work with AOT */
                return FALSE;
 
-       c1 = get_call_info (NULL, NULL, caller_sig);
-       c2 = get_call_info (NULL, NULL, callee_sig);
+       c1 = get_call_info (NULL, caller_sig);
+       c2 = get_call_info (NULL, callee_sig);
        /*
         * Tail calls with more callee stack usage than the caller cannot be supported, since
         * the extra stack space would be left on the stack after the tail call.
         */
        res = c1->stack_usage >= c2->stack_usage;
-       callee_ret = mini_get_underlying_type (cfg, callee_sig->ret);
+       callee_ret = mini_get_underlying_type (callee_sig->ret);
        if (callee_ret && MONO_TYPE_ISSTRUCT (callee_ret) && c2->ret.storage != ArgValuetypeInReg)
                /* An address on the callee's stack is passed as the first argument */
                res = FALSE;
@@ -1061,7 +1061,7 @@ mono_arch_allocate_vars (MonoCompile *cfg)
        header = cfg->header;
        sig = mono_method_signature (cfg->method);
 
-       cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig);
+       cinfo = get_call_info (cfg->mempool, sig);
 
        cfg->frame_reg = X86_EBP;
        offset = 0;
@@ -1208,12 +1208,12 @@ mono_arch_create_vars (MonoCompile *cfg)
 
        sig = mono_method_signature (cfg->method);
 
-       cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig);
-       sig_ret = mini_get_underlying_type (cfg, sig->ret);
+       cinfo = get_call_info (cfg->mempool, sig);
+       sig_ret = mini_get_underlying_type (sig->ret);
 
        if (cinfo->ret.storage == ArgValuetypeInReg)
                cfg->ret_var_is_local = TRUE;
-       if ((cinfo->ret.storage != ArgValuetypeInReg) && (MONO_TYPE_ISSTRUCT (sig_ret) || mini_is_gsharedvt_variable_type (cfg, sig_ret))) {
+       if ((cinfo->ret.storage != ArgValuetypeInReg) && (MONO_TYPE_ISSTRUCT (sig_ret) || mini_is_gsharedvt_variable_type (sig_ret))) {
                cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
        }
 
@@ -1244,7 +1244,7 @@ collect_fp_stack_space (MonoMethodSignature *sig, int start_arg, int *fp_arg_set
        MonoType *t;
 
        for (; start_arg < sig->param_count; ++start_arg) {
-               t = mini_replace_type (sig->params [start_arg]);
+               t = mini_get_underlying_type (sig->params [start_arg]);
                if (!t->byref && t->type == MONO_TYPE_R8) {
                        fp_space += sizeof (double);
                        *fp_arg_setup = start_arg;
@@ -1293,7 +1293,7 @@ mono_arch_get_llvm_call_info (MonoCompile *cfg, MonoMethodSignature *sig)
 
        n = sig->param_count + sig->hasthis;
 
-       cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig);
+       cinfo = get_call_info (cfg->mempool, sig);
        sig_ret = sig->ret;
 
        linfo = mono_mempool_alloc0 (cfg->mempool, sizeof (LLVMCallInfo) + (sizeof (LLVMArgInfo) * n));
@@ -1320,13 +1320,13 @@ mono_arch_get_llvm_call_info (MonoCompile *cfg, MonoMethodSignature *sig)
                */
        }
 
-       if (mini_type_is_vtype (cfg, sig_ret) && cinfo->ret.storage == ArgInIReg) {
+       if (mini_type_is_vtype (sig_ret) && cinfo->ret.storage == ArgInIReg) {
                /* Vtype returned using a hidden argument */
                linfo->ret.storage = LLVMArgVtypeRetAddr;
                linfo->vret_arg_index = cinfo->vret_arg_index;
        }
 
-       if (mini_type_is_vtype (cfg, sig_ret) && cinfo->ret.storage != ArgInIReg) {
+       if (mini_type_is_vtype (sig_ret) && cinfo->ret.storage != ArgInIReg) {
                // FIXME:
                cfg->exception_message = g_strdup ("vtype ret in call");
                cfg->disable_llvm = TRUE;
@@ -1351,7 +1351,7 @@ mono_arch_get_llvm_call_info (MonoCompile *cfg, MonoMethodSignature *sig)
                        linfo->args [i].storage = LLVMArgInFPReg;
                        break;
                case ArgOnStack:
-                       if (mini_type_is_vtype (cfg, t)) {
+                       if (mini_type_is_vtype (t)) {
                                if (mono_class_value_size (mono_class_from_mono_type (t), NULL) == 0)
                                /* LLVM seems to allocate argument space for empty structures too */
                                        linfo->args [i].storage = LLVMArgNone;
@@ -1424,9 +1424,9 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
 
        sig = call->signature;
        n = sig->param_count + sig->hasthis;
-       sig_ret = mini_get_underlying_type (cfg, sig->ret);
+       sig_ret = mini_get_underlying_type (sig->ret);
 
-       cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig);
+       cinfo = get_call_info (cfg->mempool, sig);
        call->call_info = cinfo;
 
        if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG))
@@ -1482,7 +1482,7 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
                else
                        t = &mono_defaults.int_class->byval_arg;
                orig_type = t;
-               t = mini_type_get_underlying_type (cfg->generic_sharing_context, t);
+               t = mini_get_underlying_type (t);
 
                MONO_INST_NEW (cfg, arg, OP_X86_PUSH);
 
@@ -1512,7 +1512,7 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
                                align = sizeof (gpointer);
                        }
                        else {
-                               size = mini_type_stack_size_full (cfg->generic_sharing_context, &in->klass->byval_arg, &align, sig->pinvoke);
+                               size = mini_type_stack_size_full (&in->klass->byval_arg, &align, sig->pinvoke);
                        }
 
                        if (size > 0) {
@@ -1641,7 +1641,7 @@ mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
                mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, FALSE);
        }
        else {
-               if (cfg->gsharedvt && mini_is_gsharedvt_klass (cfg, ins->klass)) {
+               if (cfg->gsharedvt && mini_is_gsharedvt_klass (ins->klass)) {
                        /* Pass by addr */
                        MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, X86_ESP, ainfo->offset, src->dreg);
                } else if (size <= 4) {
@@ -1660,7 +1660,7 @@ mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
 void
 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
 {
-       MonoType *ret = mini_type_get_underlying_type (cfg->generic_sharing_context, mono_method_signature (method)->ret);
+       MonoType *ret = mini_get_underlying_type (mono_method_signature (method)->ret);
 
        if (!ret->byref) {
                if (ret->type == MONO_TYPE_R4) {
@@ -1730,7 +1730,7 @@ mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolea
        guchar *code = p;
        int arg_size = 0, stack_usage = 0, save_mode = SAVE_NONE;
        MonoMethod *method = cfg->method;
-       MonoType *ret_type = mini_type_get_underlying_type (cfg->generic_sharing_context, mono_method_signature (method)->ret);
+       MonoType *ret_type = mini_get_underlying_type (mono_method_signature (method)->ret);
 
        switch (ret_type->type) {
        case MONO_TYPE_VOID:
@@ -2292,11 +2292,13 @@ mono_x86_have_tls_get (void)
 #ifdef TARGET_MACH
        static gboolean have_tls_get = FALSE;
        static gboolean inited = FALSE;
-       guint32 *ins;
 
        if (inited)
                return have_tls_get;
 
+#ifdef MONO_HAVE_FAST_TLS
+       guint32 *ins;
+
        ins = (guint32*)pthread_getspecific;
        /*
         * We're looking for these two instructions:
@@ -2306,6 +2308,7 @@ mono_x86_have_tls_get (void)
         */
        have_tls_get = ins [0] == 0x0424448b && ins [1] == 0x85048b65;
        tls_gs_offset = ins [2];
+#endif
 
        inited = TRUE;
 
@@ -5096,13 +5099,6 @@ mono_arch_patch_code_new (MonoCompile *cfg, MonoDomain *domain, guint8 *code, Mo
        case MONO_PATCH_INFO_IP:
                *((gconstpointer *)(ip)) = target;
                break;
-       case MONO_PATCH_INFO_CLASS_INIT: {
-               guint8 *code = ip;
-               /* Might already been changed to a nop */
-               x86_call_code (code, 0);
-               x86_patch (ip, (unsigned char*)target);
-               break;
-       }
        case MONO_PATCH_INFO_ABS:
        case MONO_PATCH_INFO_METHOD:
        case MONO_PATCH_INFO_METHOD_JUMP:
@@ -5110,7 +5106,6 @@ mono_arch_patch_code_new (MonoCompile *cfg, MonoDomain *domain, guint8 *code, Mo
        case MONO_PATCH_INFO_BB:
        case MONO_PATCH_INFO_LABEL:
        case MONO_PATCH_INFO_RGCTX_FETCH:
-       case MONO_PATCH_INFO_GENERIC_CLASS_INIT:
        case MONO_PATCH_INFO_MONITOR_ENTER:
        case MONO_PATCH_INFO_MONITOR_ENTER_V4:
        case MONO_PATCH_INFO_MONITOR_EXIT:
@@ -5464,7 +5459,7 @@ mono_arch_emit_epilog (MonoCompile *cfg)
                gboolean supported = FALSE;
 
                if (cfg->compile_aot) {
-#if defined(__APPLE__) || defined(__linux__)
+#if defined(MONO_HAVE_FAST_TLS)
                        supported = TRUE;
 #endif
                } else if (mono_get_jit_tls_offset () != -1) {
@@ -5537,7 +5532,7 @@ mono_arch_emit_epilog (MonoCompile *cfg)
        }
 
        /* Load returned vtypes into registers if needed */
-       cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig);
+       cinfo = get_call_info (cfg->mempool, sig);
        if (cinfo->ret.storage == ArgValuetypeInReg) {
                for (quad = 0; quad < 2; quad ++) {
                        switch (cinfo->ret.pair_storage [quad]) {
@@ -5564,7 +5559,7 @@ mono_arch_emit_epilog (MonoCompile *cfg)
        if (CALLCONV_IS_STDCALL (sig)) {
                MonoJitArgumentInfo *arg_info = alloca (sizeof (MonoJitArgumentInfo) * (sig->param_count + 1));
 
-               stack_to_pop = mono_arch_get_argument_info (NULL, sig, sig->param_count, arg_info);
+               stack_to_pop = mono_arch_get_argument_info (sig, sig->param_count, arg_info);
        } else if (cinfo->callee_stack_pop)
                stack_to_pop = cinfo->callee_stack_pop;
        else
@@ -5767,6 +5762,7 @@ mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckI
        int i;
        int size = 0;
        guint8 *code, *start;
+       GSList *unwind_ops;
 
        for (i = 0; i < count; ++i) {
                MonoIMTCheckItem *item = imt_entries [i];
@@ -5803,6 +5799,9 @@ mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckI
                code = mono_domain_code_reserve (domain, size);
 #endif
        start = code;
+
+       unwind_ops = mono_arch_get_cie_program ();
+
        for (i = 0; i < count; ++i) {
                MonoIMTCheckItem *item = imt_entries [i];
                item->code_target = code;
@@ -5889,6 +5888,8 @@ mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckI
        nacl_domain_code_validate (domain, &start, size, &code);
        mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_IMT_TRAMPOLINE, NULL);
 
+       mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, unwind_ops), domain);
+
        return start;
 }
 
@@ -6054,7 +6055,7 @@ mono_breakpoint_clean_code (guint8 *method_start, guint8 *code, int offset, guin
  * call.
  */
 guint32
-mono_x86_get_this_arg_offset (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig)
+mono_x86_get_this_arg_offset (MonoMethodSignature *sig)
 {
        return 0;
 }
@@ -6080,10 +6081,13 @@ mono_arch_get_this_arg_from_call (mgreg_t *regs, guint8 *code)
 #define MAX_ARCH_DELEGATE_PARAMS 10
 
 static gpointer
-get_delegate_invoke_impl (gboolean has_target, guint32 param_count, guint32 *code_len)
+get_delegate_invoke_impl (MonoTrampInfo **info, gboolean has_target, guint32 param_count)
 {
        guint8 *code, *start;
        int code_reserve = 64;
+       GSList *unwind_ops;
+
+       unwind_ops = mono_arch_get_cie_program ();
 
        /*
         * The stack contains:
@@ -6144,8 +6148,13 @@ get_delegate_invoke_impl (gboolean has_target, guint32 param_count, guint32 *cod
 
        nacl_global_codeman_validate (&start, code_reserve, &code);
 
-       if (code_len)
-               *code_len = code - start;
+       if (has_target) {
+               *info = mono_tramp_info_create ("delegate_invoke_impl_has_target", start, code - start, NULL, unwind_ops);
+       } else {
+               char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", param_count);
+               *info = mono_tramp_info_create (name, start, code - start, NULL, unwind_ops);
+               g_free (name);
+       }
 
        if (mono_jit_map_is_enabled ()) {
                char *buff;
@@ -6162,23 +6171,75 @@ get_delegate_invoke_impl (gboolean has_target, guint32 param_count, guint32 *cod
        return start;
 }
 
+#define MAX_VIRTUAL_DELEGATE_OFFSET 32
+
+static gpointer
+get_delegate_virtual_invoke_impl (MonoTrampInfo **info, gboolean load_imt_reg, int offset)
+{
+       guint8 *code, *start;
+       int size = 24;
+       char *tramp_name;
+       GSList *unwind_ops;
+
+       if (offset / (int)sizeof (gpointer) > MAX_VIRTUAL_DELEGATE_OFFSET)
+               return NULL;
+
+       /*
+        * The stack contains:
+        * <delegate>
+        * <return addr>
+        */
+       start = code = mono_global_codeman_reserve (size);
+
+       unwind_ops = mono_arch_get_cie_program ();
+
+       /* Replace the this argument with the target */
+       x86_mov_reg_membase (code, X86_EAX, X86_ESP, 4, 4);
+       x86_mov_reg_membase (code, X86_ECX, X86_EAX, MONO_STRUCT_OFFSET (MonoDelegate, target), 4);
+       x86_mov_membase_reg (code, X86_ESP, 4, X86_ECX, 4);
+
+       if (load_imt_reg) {
+               /* Load the IMT reg */
+               x86_mov_reg_membase (code, MONO_ARCH_IMT_REG, X86_EAX, MONO_STRUCT_OFFSET (MonoDelegate, method), 4);
+       }
+
+       /* Load the vtable */
+       x86_mov_reg_membase (code, X86_EAX, X86_ECX, MONO_STRUCT_OFFSET (MonoObject, vtable), 4);
+       x86_jump_membase (code, X86_EAX, offset);
+       mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_DELEGATE_INVOKE, NULL);
+
+       if (load_imt_reg)
+               tramp_name = g_strdup_printf ("delegate_virtual_invoke_imt_%d", - offset / sizeof (gpointer));
+       else
+               tramp_name = g_strdup_printf ("delegate_virtual_invoke_%d", offset / sizeof (gpointer));
+       *info = mono_tramp_info_create (tramp_name, start, code - start, NULL, unwind_ops);
+       g_free (tramp_name);
+
+
+       return start;
+}
+
 GSList*
 mono_arch_get_delegate_invoke_impls (void)
 {
        GSList *res = NULL;
-       guint8 *code;
-       guint32 code_len;
+       MonoTrampInfo *info;
        int i;
-       char *tramp_name;
 
-       code = get_delegate_invoke_impl (TRUE, 0, &code_len);
-       res = g_slist_prepend (res, mono_tramp_info_create ("delegate_invoke_impl_has_target", code, code_len, NULL, NULL));
+       get_delegate_invoke_impl (&info, TRUE, 0);
+       res = g_slist_prepend (res, info);
 
-       for (i = 0; i < MAX_ARCH_DELEGATE_PARAMS; ++i) {
-               code = get_delegate_invoke_impl (FALSE, i, &code_len);
-               tramp_name = g_strdup_printf ("delegate_invoke_impl_target_%d", i);
-               res = g_slist_prepend (res, mono_tramp_info_create (tramp_name, code, code_len, NULL, NULL));
-               g_free (tramp_name);
+       for (i = 0; i <= MAX_ARCH_DELEGATE_PARAMS; ++i) {
+               get_delegate_invoke_impl (&info, FALSE, i);
+               res = g_slist_prepend (res, info);
+       }
+
+       for (i = 0; i <= MAX_VIRTUAL_DELEGATE_OFFSET; ++i) {
+               get_delegate_virtual_invoke_impl (&info, TRUE, - i * SIZEOF_VOID_P);
+               res = g_slist_prepend (res, info);
+
+               get_delegate_virtual_invoke_impl (&info, FALSE, i * SIZEOF_VOID_P);
+               res = g_slist_prepend (res, info);
        }
 
        return res;
@@ -6207,10 +6268,13 @@ mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_targe
                if (cached)
                        return cached;
 
-               if (mono_aot_only)
+               if (mono_aot_only) {
                        start = mono_aot_get_trampoline ("delegate_invoke_impl_has_target");
-               else
-                       start = get_delegate_invoke_impl (TRUE, 0, NULL);
+               } else {
+                       MonoTrampInfo *info;
+                       start = get_delegate_invoke_impl (&info, TRUE, 0);
+                       mono_tramp_info_register (info, NULL);
+               }
 
                mono_memory_barrier ();
 
@@ -6232,7 +6296,9 @@ mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_targe
                        start = mono_aot_get_trampoline (name);
                        g_free (name);
                } else {
-                       start = get_delegate_invoke_impl (FALSE, sig->param_count, NULL);
+                       MonoTrampInfo *info;
+                       start = get_delegate_invoke_impl (&info, FALSE, sig->param_count);
+                       mono_tramp_info_register (info, NULL);
                }
 
                mono_memory_barrier ();
@@ -6246,32 +6312,13 @@ mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_targe
 gpointer
 mono_arch_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method, int offset, gboolean load_imt_reg)
 {
-       guint8 *code, *start;
-       int size = 24;
-
-       /*
-        * The stack contains:
-        * <delegate>
-        * <return addr>
-        */
-       start = code = mono_global_codeman_reserve (size);
-
-       /* Replace the this argument with the target */
-       x86_mov_reg_membase (code, X86_EAX, X86_ESP, 4, 4);
-       x86_mov_reg_membase (code, X86_ECX, X86_EAX, MONO_STRUCT_OFFSET (MonoDelegate, target), 4);
-       x86_mov_membase_reg (code, X86_ESP, 4, X86_ECX, 4);
-
-       if (load_imt_reg) {
-               /* Load the IMT reg */
-               x86_mov_reg_membase (code, MONO_ARCH_IMT_REG, X86_EAX, MONO_STRUCT_OFFSET (MonoDelegate, method), 4);
-       }
-
-       /* Load the vtable */
-       x86_mov_reg_membase (code, X86_EAX, X86_ECX, MONO_STRUCT_OFFSET (MonoObject, vtable), 4);
-       x86_jump_membase (code, X86_EAX, offset);
-       mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_DELEGATE_INVOKE, NULL);
+       MonoTrampInfo *info;
+       gpointer code;
 
-       return start;
+       code = get_delegate_virtual_invoke_impl (&info, load_imt_reg, offset);
+       if (code)
+               mono_tramp_info_register (info, NULL);
+       return code;
 }
 
 mgreg_t