Merge pull request #2003 from esdrubal/seq_test_fix2
[mono.git] / mono / mini / mini-amd64.c
index d90a17079390fa91997a845f391150840d9b0b5a..f0ca62d8d97a358f1e46b44e832fc73b5abcffb9 100644 (file)
@@ -65,9 +65,6 @@ static gboolean optimize_for_xen = TRUE;
 #define mono_mini_arch_unlock() mono_mutex_unlock (&mini_arch_mutex)
 static mono_mutex_t mini_arch_mutex;
 
-MonoBreakpointInfo
-mono_breakpoint_info [MONO_BREAKPOINT_ARRAY_SIZE];
-
 /*
  * The code generated for sequence points reads from this location, which is
  * made read-only when single stepping is enabled.
@@ -182,6 +179,15 @@ amd64_is_near_call (guint8 *code)
        return code [0] == 0xe8;
 }
 
+static inline gboolean
+amd64_use_imm32 (gint64 val)
+{
+       if (mini_get_debug_options()->single_imm_size)
+               return FALSE;
+
+       return amd64_is_imm32 (val);
+}
+
 #ifdef __native_client_codegen__
 
 /* Keep track of instruction "depth", that is, the level of sub-instruction */
@@ -591,12 +597,12 @@ typedef enum ArgumentClass {
 } ArgumentClass;
 
 static ArgumentClass
-merge_argument_class_from_type (MonoGenericSharingContext *gsctx, MonoType *type, ArgumentClass class1)
+merge_argument_class_from_type (MonoType *type, ArgumentClass class1)
 {
        ArgumentClass class2 = ARG_CLASS_NO_CLASS;
        MonoType *ptype;
 
-       ptype = mini_type_get_underlying_type (gsctx, type);
+       ptype = mini_get_underlying_type (type);
        switch (ptype->type) {
        case MONO_TYPE_I1:
        case MONO_TYPE_U1:
@@ -641,7 +647,7 @@ merge_argument_class_from_type (MonoGenericSharingContext *gsctx, MonoType *type
 
                for (i = 0; i < info->num_fields; ++i) {
                        class2 = class1;
-                       class2 = merge_argument_class_from_type (gsctx, info->fields [i].field->type, class2);
+                       class2 = merge_argument_class_from_type (info->fields [i].field->type, class2);
                }
                break;
        }
@@ -727,7 +733,7 @@ collect_field_info_nested (MonoClass *klass, MonoMarshalField *fields, int index
 }
 
 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, guint32 *fr, guint32 *stack_size)
 {
@@ -739,19 +745,10 @@ add_valuetype (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, ArgIn
        MonoMarshalType *info = NULL;
        MonoMarshalField *fields = NULL;
        MonoClass *klass;
-       MonoGenericSharingContext tmp_gsctx;
        gboolean pass_on_stack = FALSE;
-       
-       /* 
-        * The gsctx currently contains no data, it is only used for checking whenever
-        * open types are allowed, some callers like mono_arch_get_argument_info ()
-        * don't pass it to us, so work around that.
-        */
-       if (!gsctx)
-               gsctx = &tmp_gsctx;
 
        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);
 #ifndef TARGET_WIN32
        if (!sig->pinvoke && ((is_return && (size == 8)) || (!is_return && (size <= 16)))) {
                /* We pass and return vtypes of size 8 in a register */
@@ -792,6 +789,14 @@ add_valuetype (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, ArgIn
                }
        }
 
+#ifndef TARGET_WIN32
+       if (size == 0) {
+               ainfo->storage = ArgValuetypeInReg;
+               ainfo->pair_storage [0] = ainfo->pair_storage [1] = ArgNone;
+               return;
+       }
+#endif
+
        if (pass_on_stack) {
                /* Allways pass in memory */
                ainfo->offset = *stack_size;
@@ -832,7 +837,12 @@ add_valuetype (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, ArgIn
                 * the CLR.
                 */
                g_assert (info);
-               g_assert (fields);
+
+               if (!fields) {
+                       ainfo->storage = ArgValuetypeInReg;
+                       ainfo->pair_storage [0] = ainfo->pair_storage [1] = ArgNone;
+                       return;
+               }
 
 #ifndef TARGET_WIN32
                if (info->native_size > 16) {
@@ -903,7 +913,7 @@ add_valuetype (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, ArgIn
                                /* (8 is size of quad) */
                                quadsize [quad] = fields [i].offset + size - (quad * 8);
 
-                               class1 = merge_argument_class_from_type (gsctx, fields [i].field->type, class1);
+                               class1 = merge_argument_class_from_type (fields [i].field->type, class1);
                        }
                        g_assert (class1 != ARG_CLASS_NO_CLASS);
                        args [quad] = class1;
@@ -988,7 +998,7 @@ add_valuetype (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, ArgIn
  * Draft Version 0.23" document for more information.
  */
 static CallInfo*
-get_call_info (MonoGenericSharingContext *gsctx, MonoMemPool *mp, MonoMethodSignature *sig)
+get_call_info (MonoMemPool *mp, MonoMethodSignature *sig)
 {
        guint32 i, gr, fr, pstart;
        MonoType *ret_type;
@@ -1013,7 +1023,7 @@ get_call_info (MonoGenericSharingContext *gsctx, MonoMemPool *mp, MonoMethodSign
 #endif
 
        /* 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:
@@ -1059,7 +1069,7 @@ get_call_info (MonoGenericSharingContext *gsctx, MonoMemPool *mp, MonoMethodSign
        case MONO_TYPE_VALUETYPE: {
                guint32 tmp_gr = 0, tmp_fr = 0, tmp_stacksize = 0;
 
-               add_valuetype (gsctx, sig, &cinfo->ret, ret_type, TRUE, &tmp_gr, &tmp_fr, &tmp_stacksize);
+               add_valuetype (sig, &cinfo->ret, ret_type, TRUE, &tmp_gr, &tmp_fr, &tmp_stacksize);
                if (cinfo->ret.storage == ArgOnStack) {
                        cinfo->vtype_retaddr = TRUE;
                        /* The caller passes the address where the value is stored */
@@ -1086,7 +1096,7 @@ get_call_info (MonoGenericSharingContext *gsctx, MonoMemPool *mp, MonoMethodSign
         * 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, &stack_size, cinfo->args + 0);
                } else {
@@ -1137,7 +1147,7 @@ get_call_info (MonoGenericSharingContext *gsctx, MonoMemPool *mp, MonoMethodSign
                        add_general (&gr, &stack_size, &cinfo->sig_cookie);
                }
 
-               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:
@@ -1170,7 +1180,7 @@ get_call_info (MonoGenericSharingContext *gsctx, MonoMemPool *mp, MonoMethodSign
                        /* fall through */
                case MONO_TYPE_VALUETYPE:
                case MONO_TYPE_TYPEDBYREF:
-                       add_valuetype (gsctx, sig, ainfo, sig->params [i], FALSE, &gr, &fr, &stack_size);
+                       add_valuetype (sig, ainfo, sig->params [i], FALSE, &gr, &fr, &stack_size);
                        break;
                case MONO_TYPE_U8:
 
@@ -1214,10 +1224,10 @@ get_call_info (MonoGenericSharingContext *gsctx, MonoMemPool *mp, MonoMethodSign
  * Returns the size of the argument area on the stack.
  */
 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 k;
-       CallInfo *cinfo = get_call_info (NULL, NULL, csig);
+       CallInfo *cinfo = get_call_info (NULL, csig);
        guint32 args_size = cinfo->stack_usage;
 
        /* The arguments are saved to a stack area in mono_arch_instrument_prolog */
@@ -1243,10 +1253,10 @@ mono_arch_tail_call_supported (MonoCompile *cfg, MonoMethodSignature *caller_sig
        gboolean res;
        MonoType *callee_ret;
 
-       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);
        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;
@@ -1316,6 +1326,7 @@ mono_arch_init (void)
 
        mono_aot_register_jit_icall ("mono_amd64_throw_exception", mono_amd64_throw_exception);
        mono_aot_register_jit_icall ("mono_amd64_throw_corlib_exception", mono_amd64_throw_corlib_exception);
+       mono_aot_register_jit_icall ("mono_amd64_resume_unwind", mono_amd64_resume_unwind);
        mono_aot_register_jit_icall ("mono_amd64_get_original_ip", mono_amd64_get_original_ip);
 }
 
@@ -1445,7 +1456,7 @@ mono_arch_compute_omit_fp (MonoCompile *cfg)
        sig = mono_method_signature (cfg->method);
 
        if (!cfg->arch.cinfo)
-               cfg->arch.cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig);
+               cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
        cinfo = cfg->arch.cinfo;
 
        /*
@@ -1509,43 +1520,21 @@ mono_arch_get_global_int_regs (MonoCompile *cfg)
 
        mono_arch_compute_omit_fp (cfg);
 
-       if (cfg->globalra) {
-               if (cfg->arch.omit_fp)
-                       regs = g_list_prepend (regs, (gpointer)AMD64_RBP);
-               regs = g_list_prepend (regs, (gpointer)AMD64_RBX);
-               regs = g_list_prepend (regs, (gpointer)AMD64_R12);
-               regs = g_list_prepend (regs, (gpointer)AMD64_R13);
-               regs = g_list_prepend (regs, (gpointer)AMD64_R14);
-#ifndef __native_client_codegen__
-               regs = g_list_prepend (regs, (gpointer)AMD64_R15);
-#endif
-               regs = g_list_prepend (regs, (gpointer)AMD64_R10);
-               regs = g_list_prepend (regs, (gpointer)AMD64_R9);
-               regs = g_list_prepend (regs, (gpointer)AMD64_R8);
-               regs = g_list_prepend (regs, (gpointer)AMD64_RDI);
-               regs = g_list_prepend (regs, (gpointer)AMD64_RSI);
-               regs = g_list_prepend (regs, (gpointer)AMD64_RDX);
-               regs = g_list_prepend (regs, (gpointer)AMD64_RCX);
-               regs = g_list_prepend (regs, (gpointer)AMD64_RAX);
-       } else {
-               if (cfg->arch.omit_fp)
-                       regs = g_list_prepend (regs, (gpointer)AMD64_RBP);
+       if (cfg->arch.omit_fp)
+               regs = g_list_prepend (regs, (gpointer)AMD64_RBP);
 
-               /* We use the callee saved registers for global allocation */
-               regs = g_list_prepend (regs, (gpointer)AMD64_RBX);
-               regs = g_list_prepend (regs, (gpointer)AMD64_R12);
-               regs = g_list_prepend (regs, (gpointer)AMD64_R13);
-               regs = g_list_prepend (regs, (gpointer)AMD64_R14);
+       /* We use the callee saved registers for global allocation */
+       regs = g_list_prepend (regs, (gpointer)AMD64_RBX);
+       regs = g_list_prepend (regs, (gpointer)AMD64_R12);
+       regs = g_list_prepend (regs, (gpointer)AMD64_R13);
+       regs = g_list_prepend (regs, (gpointer)AMD64_R14);
 #ifndef __native_client_codegen__
-               regs = g_list_prepend (regs, (gpointer)AMD64_R15);
+       regs = g_list_prepend (regs, (gpointer)AMD64_R15);
 #endif
 #ifdef TARGET_WIN32
-               regs = g_list_prepend (regs, (gpointer)AMD64_RDI);
-               regs = g_list_prepend (regs, (gpointer)AMD64_RSI);
+       regs = g_list_prepend (regs, (gpointer)AMD64_RDI);
+       regs = g_list_prepend (regs, (gpointer)AMD64_RSI);
 #endif
-       }
 
        return regs;
 }
@@ -1652,7 +1641,7 @@ mono_arch_fill_argument_info (MonoCompile *cfg)
        sig = mono_method_signature (cfg->method);
 
        cinfo = cfg->arch.cinfo;
-       sig_ret = mini_get_underlying_type (cfg, sig->ret);
+       sig_ret = mini_get_underlying_type (sig->ret);
 
        /*
         * Contrary to mono_arch_allocate_vars (), the information should describe
@@ -1725,7 +1714,7 @@ mono_arch_allocate_vars (MonoCompile *cfg)
        sig = mono_method_signature (cfg->method);
 
        cinfo = cfg->arch.cinfo;
-       sig_ret = mini_get_underlying_type (cfg, sig->ret);
+       sig_ret = mini_get_underlying_type (sig->ret);
 
        mono_arch_compute_omit_fp (cfg);
 
@@ -1776,24 +1765,19 @@ mono_arch_allocate_vars (MonoCompile *cfg)
                case ArgInFloatSSEReg:
                case ArgInDoubleSSEReg:
                        if ((MONO_TYPE_ISSTRUCT (sig_ret) && !mono_class_from_mono_type (sig_ret)->enumtype) || ((sig_ret->type == MONO_TYPE_TYPEDBYREF) && cinfo->vtype_retaddr)) {
-                               if (cfg->globalra) {
-                                       cfg->vret_addr->opcode = OP_REGVAR;
-                                       cfg->vret_addr->inst_c0 = cinfo->ret.reg;
+                               /* The register is volatile */
+                               cfg->vret_addr->opcode = OP_REGOFFSET;
+                               cfg->vret_addr->inst_basereg = cfg->frame_reg;
+                               if (cfg->arch.omit_fp) {
+                                       cfg->vret_addr->inst_offset = offset;
+                                       offset += 8;
                                } else {
-                                       /* The register is volatile */
-                                       cfg->vret_addr->opcode = OP_REGOFFSET;
-                                       cfg->vret_addr->inst_basereg = cfg->frame_reg;
-                                       if (cfg->arch.omit_fp) {
-                                               cfg->vret_addr->inst_offset = offset;
-                                               offset += 8;
-                                       } else {
-                                               offset += 8;
-                                               cfg->vret_addr->inst_offset = -offset;
-                                       }
-                                       if (G_UNLIKELY (cfg->verbose_level > 1)) {
-                                               printf ("vret_addr =");
-                                               mono_print_ins (cfg->vret_addr);
-                                       }
+                                       offset += 8;
+                                       cfg->vret_addr->inst_offset = -offset;
+                               }
+                               if (G_UNLIKELY (cfg->verbose_level > 1)) {
+                                       printf ("vret_addr =");
+                                       mono_print_ins (cfg->vret_addr);
                                }
                        }
                        else {
@@ -1816,47 +1800,44 @@ mono_arch_allocate_vars (MonoCompile *cfg)
                default:
                        g_assert_not_reached ();
                }
-               if (!cfg->globalra)
-                       cfg->ret->dreg = cfg->ret->inst_c0;
+               cfg->ret->dreg = cfg->ret->inst_c0;
        }
 
        /* Allocate locals */
-       if (!cfg->globalra) {
-               offsets = mono_allocate_stack_slots (cfg, cfg->arch.omit_fp ? FALSE: TRUE, &locals_stack_size, &locals_stack_align);
-               if (locals_stack_size > MONO_ARCH_MAX_FRAME_SIZE) {
-                       char *mname = mono_method_full_name (cfg->method, TRUE);
-                       cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
-                       cfg->exception_message = g_strdup_printf ("Method %s stack is too big.", mname);
-                       g_free (mname);
-                       return;
-               }
+       offsets = mono_allocate_stack_slots (cfg, cfg->arch.omit_fp ? FALSE: TRUE, &locals_stack_size, &locals_stack_align);
+       if (locals_stack_size > MONO_ARCH_MAX_FRAME_SIZE) {
+               char *mname = mono_method_full_name (cfg->method, TRUE);
+               cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
+               cfg->exception_message = g_strdup_printf ("Method %s stack is too big.", mname);
+               g_free (mname);
+               return;
+       }
                
-               if (locals_stack_align) {
-                       offset += (locals_stack_align - 1);
-                       offset &= ~(locals_stack_align - 1);
-               }
-               if (cfg->arch.omit_fp) {
-                       cfg->locals_min_stack_offset = offset;
-                       cfg->locals_max_stack_offset = offset + locals_stack_size;
-               } else {
-                       cfg->locals_min_stack_offset = - (offset + locals_stack_size);
-                       cfg->locals_max_stack_offset = - offset;
-               }
+       if (locals_stack_align) {
+               offset += (locals_stack_align - 1);
+               offset &= ~(locals_stack_align - 1);
+       }
+       if (cfg->arch.omit_fp) {
+               cfg->locals_min_stack_offset = offset;
+               cfg->locals_max_stack_offset = offset + locals_stack_size;
+       } else {
+               cfg->locals_min_stack_offset = - (offset + locals_stack_size);
+               cfg->locals_max_stack_offset = - offset;
+       }
                
-               for (i = cfg->locals_start; i < cfg->num_varinfo; i++) {
-                       if (offsets [i] != -1) {
-                               MonoInst *ins = cfg->varinfo [i];
-                               ins->opcode = OP_REGOFFSET;
-                               ins->inst_basereg = cfg->frame_reg;
-                               if (cfg->arch.omit_fp)
-                                       ins->inst_offset = (offset + offsets [i]);
-                               else
-                                       ins->inst_offset = - (offset + offsets [i]);
-                               //printf ("allocated local %d to ", i); mono_print_tree_nl (ins);
-                       }
+       for (i = cfg->locals_start; i < cfg->num_varinfo; i++) {
+               if (offsets [i] != -1) {
+                       MonoInst *ins = cfg->varinfo [i];
+                       ins->opcode = OP_REGOFFSET;
+                       ins->inst_basereg = cfg->frame_reg;
+                       if (cfg->arch.omit_fp)
+                               ins->inst_offset = (offset + offsets [i]);
+                       else
+                               ins->inst_offset = - (offset + offsets [i]);
+                       //printf ("allocated local %d to ", i); mono_print_tree_nl (ins);
                }
-               offset += locals_stack_size;
        }
+       offset += locals_stack_size;
 
        if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG)) {
                g_assert (!cfg->arch.omit_fp);
@@ -1870,41 +1851,6 @@ mono_arch_allocate_vars (MonoCompile *cfg)
                        ArgInfo *ainfo = &cinfo->args [i];
                        gboolean inreg = TRUE;
 
-                       if (cfg->globalra) {
-                               /* The new allocator needs info about the original locations of the arguments */
-                               switch (ainfo->storage) {
-                               case ArgInIReg:
-                               case ArgInFloatSSEReg:
-                               case ArgInDoubleSSEReg:
-                                       ins->opcode = OP_REGVAR;
-                                       ins->inst_c0 = ainfo->reg;
-                                       break;
-                               case ArgOnStack:
-                                       g_assert (!cfg->arch.omit_fp);
-                                       ins->opcode = OP_REGOFFSET;
-                                       ins->inst_basereg = cfg->frame_reg;
-                                       ins->inst_offset = ainfo->offset + ARGS_OFFSET;
-                                       break;
-                               case ArgValuetypeInReg:
-                                       ins->opcode = OP_REGOFFSET;
-                                       ins->inst_basereg = cfg->frame_reg;
-                                       /* These arguments are saved to the stack in the prolog */
-                                       offset = ALIGN_TO (offset, sizeof(mgreg_t));
-                                       if (cfg->arch.omit_fp) {
-                                               ins->inst_offset = offset;
-                                               offset += (ainfo->storage == ArgValuetypeInReg) ? ainfo->nregs * sizeof (mgreg_t) : sizeof (mgreg_t);
-                                       } else {
-                                               offset += (ainfo->storage == ArgValuetypeInReg) ? ainfo->nregs * sizeof (mgreg_t) : sizeof (mgreg_t);
-                                               ins->inst_offset = - offset;
-                                       }
-                                       break;
-                               default:
-                                       g_assert_not_reached ();
-                               }
-
-                               continue;
-                       }
-
                        /* FIXME: Allocate volatile arguments to registers */
                        if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT))
                                inreg = FALSE;
@@ -1994,13 +1940,13 @@ mono_arch_create_vars (MonoCompile *cfg)
        sig = mono_method_signature (cfg->method);
 
        if (!cfg->arch.cinfo)
-               cfg->arch.cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig);
+               cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
        cinfo = cfg->arch.cinfo;
 
        if (cinfo->ret.storage == ArgValuetypeInReg)
                cfg->ret_var_is_local = TRUE;
 
-       sig_ret = mini_get_underlying_type (cfg, sig->ret);
+       sig_ret = mini_get_underlying_type (sig->ret);
        if ((cinfo->ret.storage != ArgValuetypeInReg) && MONO_TYPE_ISSTRUCT (sig_ret)) {
                cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
                if (G_UNLIKELY (cfg->verbose_level > 1)) {
@@ -2149,9 +2095,9 @@ mono_arch_get_llvm_call_info (MonoCompile *cfg, MonoMethodSignature *sig)
        MonoType *t, *sig_ret;
 
        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);
 
        linfo = mono_mempool_alloc0 (cfg->mempool, sizeof (LLVMCallInfo) + (sizeof (LLVMArgInfo) * n));
 
@@ -2245,7 +2191,7 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
        sig = call->signature;
        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;
 
@@ -2270,7 +2216,7 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
                else
                        t = sig->params [i - sig->hasthis];
 
-               t = mini_get_underlying_type (cfg, t);
+               t = mini_get_underlying_type (t);
                if (ainfo->storage == ArgOnStack && !MONO_TYPE_ISSTRUCT (t) && !call->tail_call) {
                        if (!t->byref) {
                                if (t->type == MONO_TYPE_R4)
@@ -2304,10 +2250,18 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
        }
 
        for (i = n - 1; i >= 0; --i) {
+               MonoType *t;
+
                ainfo = cinfo->args + i;
 
                in = call->args [i];
 
+               if (sig->hasthis && i == 0)
+                       t = &mono_defaults.object_class->byval_arg;
+               else
+                       t = sig->params [i - sig->hasthis];
+               t = mini_get_underlying_type (t);
+
                switch (ainfo->storage) {
                case ArgInIReg:
                        /* Already done */
@@ -2323,17 +2277,17 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
                                MonoInst *call_inst = (MonoInst*)call;
                                cfg->args [i]->flags |= MONO_INST_VOLATILE;
                                EMIT_NEW_ARGSTORE (cfg, call_inst, i, in);
-                       } else if ((i >= sig->hasthis) && (MONO_TYPE_ISSTRUCT(sig->params [i - sig->hasthis]))) {
+                       } else if ((i >= sig->hasthis) && (MONO_TYPE_ISSTRUCT(t))) {
                                guint32 align;
                                guint32 size;
 
-                               if (sig->params [i - sig->hasthis]->type == MONO_TYPE_TYPEDBYREF) {
+                               if (t->type == MONO_TYPE_TYPEDBYREF) {
                                        size = sizeof (MonoTypedRef);
                                        align = sizeof (gpointer);
                                }
                                else {
                                        if (sig->pinvoke)
-                                               size = mono_type_native_stack_size (&in->klass->byval_arg, &align);
+                                               size = mono_type_native_stack_size (t, &align);
                                        else {
                                                /* 
                                                 * Other backends use mono_type_stack_size (), but that
@@ -2341,7 +2295,7 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
                                                 * the source, leading to reads of invalid memory if the
                                                 * source is at the end of address space.
                                                 */
-                                               size = mono_class_value_size (in->klass, &align);
+                                               size = mono_class_value_size (mono_class_from_mono_type (t), &align);
                                        }
                                }
                                g_assert (in->klass);
@@ -2356,7 +2310,7 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
                                if (size > 0) {
                                        MONO_INST_NEW (cfg, arg, OP_OUTARG_VT);
                                        arg->sreg1 = in->dreg;
-                                       arg->klass = in->klass;
+                                       arg->klass = mono_class_from_mono_type (t);
                                        arg->backend.size = size;
                                        arg->inst_p0 = call;
                                        arg->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
@@ -2379,7 +2333,7 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
        if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos))
                emit_sig_cookie (cfg, call, cinfo);
 
-       sig_ret = mini_get_underlying_type (cfg, sig->ret);
+       sig_ret = mini_get_underlying_type (sig->ret);
        if (sig_ret && MONO_TYPE_ISSTRUCT (sig_ret)) {
                MonoInst *vtarg;
 
@@ -2514,7 +2468,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_get_underlying_type (cfg, mono_method_signature (method)->ret);
+       MonoType *ret = mini_get_underlying_type (mono_method_signature (method)->ret);
 
        if (ret->type == MONO_TYPE_R4) {
                if (COMPILE_LLVM (cfg))
@@ -2608,7 +2562,7 @@ mono_arch_dyn_call_prepare (MonoMethodSignature *sig)
        ArchDynCallInfo *info;
        CallInfo *cinfo;
 
-       cinfo = get_call_info (NULL, NULL, sig);
+       cinfo = get_call_info (NULL, sig);
 
        if (!dyn_call_supported (sig, cinfo)) {
                g_free (cinfo);
@@ -2687,7 +2641,7 @@ mono_arch_start_dyn_call (MonoDynCallInfo *info, gpointer **args, guint8 *ret, g
                p->regs [greg ++] = PTR_TO_GREG(ret);
 
        for (i = pindex; i < sig->param_count; i++) {
-               MonoType *t = mini_type_get_underlying_type (NULL, sig->params [i]);
+               MonoType *t = mini_get_underlying_type (sig->params [i]);
                gpointer *arg = args [arg_index ++];
 
                if (t->byref) {
@@ -2781,7 +2735,7 @@ mono_arch_finish_dyn_call (MonoDynCallInfo *info, guint8 *buf)
        MonoMethodSignature *sig = dinfo->sig;
        guint8 *ret = ((DynCallArgs*)buf)->ret;
        mgreg_t res = ((DynCallArgs*)buf)->res;
-       MonoType *sig_ret = mini_type_get_underlying_type (NULL, sig->ret);
+       MonoType *sig_ret = mini_get_underlying_type (sig->ret);
 
        switch (sig_ret->type) {
        case MONO_TYPE_VOID:
@@ -3237,7 +3191,7 @@ mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
                        break;
                case OP_COMPARE_IMM:
                case OP_LCOMPARE_IMM:
-                       if (!amd64_is_imm32 (ins->inst_imm)) {
+                       if (!amd64_use_imm32 (ins->inst_imm)) {
                                NEW_INS (cfg, ins, temp, OP_I8CONST);
                                temp->inst_c0 = ins->inst_imm;
                                temp->dreg = mono_alloc_ireg (cfg);
@@ -3252,7 +3206,7 @@ mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
 #ifndef __native_client_codegen__
                /*  Don't generate memindex opcodes (to simplify */
                /*  read sandboxing) */
-                       if (!amd64_is_imm32 (ins->inst_offset)) {
+                       if (!amd64_use_imm32 (ins->inst_offset)) {
                                NEW_INS (cfg, ins, temp, OP_I8CONST);
                                temp->inst_c0 = ins->inst_offset;
                                temp->dreg = mono_alloc_ireg (cfg);
@@ -3265,7 +3219,7 @@ mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
                case OP_STORE_MEMBASE_IMM:
 #endif
                case OP_STOREI8_MEMBASE_IMM:
-                       if (!amd64_is_imm32 (ins->inst_imm)) {
+                       if (!amd64_use_imm32 (ins->inst_imm)) {
                                NEW_INS (cfg, ins, temp, OP_I8CONST);
                                temp->inst_c0 = ins->inst_imm;
                                temp->dreg = mono_alloc_ireg (cfg);
@@ -3465,7 +3419,7 @@ emit_move_return_value (MonoCompile *cfg, MonoInst *ins, guint8 *code)
        case OP_FCALL:
        case OP_FCALL_REG:
        case OP_FCALL_MEMBASE: {
-               MonoType *rtype = mini_get_underlying_type (cfg, ((MonoCallInst*)ins)->signature->ret);
+               MonoType *rtype = mini_get_underlying_type (((MonoCallInst*)ins)->signature->ret);
                if (rtype->type == MONO_TYPE_R4) {
                        amd64_sse_cvtss2sd_reg_reg (code, ins->dreg, AMD64_XMM0);
                }
@@ -3487,7 +3441,7 @@ emit_move_return_value (MonoCompile *cfg, MonoInst *ins, guint8 *code)
        case OP_VCALL2:
        case OP_VCALL2_REG:
        case OP_VCALL2_MEMBASE:
-               cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, ((MonoCallInst*)ins)->signature);
+               cinfo = get_call_info (cfg->mempool, ((MonoCallInst*)ins)->signature);
                if (cinfo->ret.storage == ArgValuetypeInReg) {
                        MonoInst *loc = cfg->arch.vret_addr_loc;
 
@@ -3531,12 +3485,12 @@ mono_amd64_have_tls_get (void)
 #ifdef TARGET_MACH
        static gboolean have_tls_get = FALSE;
        static gboolean inited = FALSE;
-       guint8 *ins;
 
        if (inited)
                return have_tls_get;
 
-       ins = (guint8*)pthread_getspecific;
+#if MONO_HAVE_FAST_TLS
+       guint8 *ins = (guint8*)pthread_getspecific;
 
        /*
         * We're looking for these two instructions:
@@ -3554,9 +3508,10 @@ mono_amd64_have_tls_get (void)
                       ins [8] == 0x00 &&
                       ins [9] == 0xc3;
 
-       inited = TRUE;
-
        tls_gs_offset = ins[5];
+#endif
+
+       inited = TRUE;
 
        return have_tls_get;
 #elif defined(TARGET_ANDROID)
@@ -3897,10 +3852,10 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
 #endif
                case OP_LOADI8_MEM:
                        // FIXME: Decompose this earlier
-                       if (amd64_is_imm32 (ins->inst_imm))
+                       if (amd64_use_imm32 (ins->inst_imm))
                                amd64_mov_reg_mem (code, ins->dreg, ins->inst_imm, 8);
                        else {
-                               amd64_mov_reg_imm (code, ins->dreg, ins->inst_imm);
+                               amd64_mov_reg_imm_size (code, ins->dreg, ins->inst_imm, sizeof(gpointer));
                                amd64_mov_reg_membase (code, ins->dreg, ins->dreg, 0, 8);
                        }
                        break;
@@ -3910,10 +3865,10 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        break;
                case OP_LOADU4_MEM:
                        // FIXME: Decompose this earlier
-                       if (amd64_is_imm32 (ins->inst_imm))
+                       if (amd64_use_imm32 (ins->inst_imm))
                                amd64_mov_reg_mem (code, ins->dreg, ins->inst_imm, 4);
                        else {
-                               amd64_mov_reg_imm (code, ins->dreg, ins->inst_imm);
+                               amd64_mov_reg_imm_size (code, ins->dreg, ins->inst_imm, sizeof(gpointer));
                                amd64_mov_reg_membase (code, ins->dreg, ins->dreg, 0, 4);
                        }
                        break;
@@ -4644,7 +4599,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
 
                case OP_ICONST:
                case OP_I8CONST:
-                       if ((((guint64)ins->inst_c0) >> 32) == 0)
+                       if ((((guint64)ins->inst_c0) >> 32) == 0 && !mini_get_debug_options()->single_imm_size)
                                amd64_mov_reg_imm_size (code, ins->dreg, ins->inst_c0, 4);
                        else
                                amd64_mov_reg_imm_size (code, ins->dreg, ins->inst_c0, 8);
@@ -4896,6 +4851,28 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        amd64_pop_reg (code, AMD64_RDI);
                        break;
                }
+               case OP_GENERIC_CLASS_INIT: {
+                       static int byte_offset = -1;
+                       static guint8 bitmask;
+                       guint8 *jump;
+
+                       g_assert (ins->sreg1 == MONO_AMD64_ARG_REG1);
+
+                       if (byte_offset < 0)
+                               mono_marshal_find_bitfield_offset (MonoVTable, initialized, &byte_offset, &bitmask);
+
+                       amd64_test_membase_imm_size (code, ins->sreg1, byte_offset, bitmask, 1);
+                       jump = code;
+                       amd64_branch8 (code, X86_CC_NZ, -1, 1);
+
+                       code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD, "mono_generic_class_init", FALSE);
+                       ins->flags |= MONO_INST_GC_CALLSITE;
+                       ins->backend.pc_offset = code - cfg->native_code;
+
+                       x86_patch (jump, code);
+                       break;
+               }
+
                case OP_X86_LEA:
                        amd64_lea_memindex (code, ins->dreg, ins->sreg1, ins->inst_imm, ins->sreg2, ins->backend.shift_amount);
                        break;
@@ -6557,15 +6534,15 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        break;
                }
                case OP_GC_SAFE_POINT: {
-                       gpointer polling_func = NULL;
+                       const char *polling_func = NULL;
                        int compare_val = 0;
                        guint8 *br [1];
 
 #if defined (USE_COOP_GC)
-                       polling_func = (gpointer)mono_threads_state_poll;
+                       polling_func = "mono_threads_state_poll";
                        compare_val = 1;
 #elif defined(__native_client_codegen__) && defined(__native_client_gc__)
-                       polling_func = (gpointer)mono_nacl_gc;
+                       polling_func = "mono_nacl_gc";
                        compare_val = 0xFFFFFFFF;
 #endif
                        if (!polling_func)
@@ -6573,7 +6550,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
 
                        amd64_test_membase_imm_size (code, ins->sreg1, 0, compare_val, 4);
                        br[0] = code; x86_branch8 (code, X86_CC_EQ, 0, FALSE);
-                       code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, polling_func, TRUE);
+                       code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD, polling_func, FALSE);
                        amd64_patch (br[0], code);
                        break;
                }
@@ -6614,67 +6591,34 @@ mono_arch_register_lowlevel_calls (void)
 }
 
 void
-mono_arch_patch_code (MonoCompile *cfg, MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, MonoCodeManager *dyn_code_mp, gboolean run_cctors)
+mono_arch_patch_code_new (MonoCompile *cfg, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gpointer target)
 {
-       MonoJumpInfo *patch_info;
-       gboolean compile_aot = !run_cctors;
-
-       for (patch_info = ji; patch_info; patch_info = patch_info->next) {
-               unsigned char *ip = patch_info->ip.i + code;
-               unsigned char *target;
+       unsigned char *ip = ji->ip.i + code;
 
-               if (compile_aot) {
-                       switch (patch_info->type) {
-                       case MONO_PATCH_INFO_BB:
-                       case MONO_PATCH_INFO_LABEL:
+       /*
+        * Debug code to help track down problems where the target of a near call is
+        * is not valid.
+        */
+       if (amd64_is_near_call (ip)) {
+               gint64 disp = (guint8*)target - (guint8*)ip;
+
+               if (!amd64_is_imm32 (disp)) {
+                       printf ("TYPE: %d\n", ji->type);
+                       switch (ji->type) {
+                       case MONO_PATCH_INFO_INTERNAL_METHOD:
+                               printf ("V: %s\n", ji->data.name);
+                               break;
+                       case MONO_PATCH_INFO_METHOD_JUMP:
+                       case MONO_PATCH_INFO_METHOD:
+                               printf ("V: %s\n", ji->data.method->name);
                                break;
                        default:
-                               /* No need to patch these */
-                               continue;
-                       }
-               }
-
-               target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
-
-               switch (patch_info->type) {
-               case MONO_PATCH_INFO_NONE:
-                       continue;
-               case MONO_PATCH_INFO_METHOD_REL:
-               case MONO_PATCH_INFO_R8:
-               case MONO_PATCH_INFO_R4:
-                       g_assert_not_reached ();
-                       continue;
-               case MONO_PATCH_INFO_BB:
-                       break;
-               default:
-                       break;
-               }
-
-               /* 
-                * Debug code to help track down problems where the target of a near call is
-                * is not valid.
-                */
-               if (amd64_is_near_call (ip)) {
-                       gint64 disp = (guint8*)target - (guint8*)ip;
-
-                       if (!amd64_is_imm32 (disp)) {
-                               printf ("TYPE: %d\n", patch_info->type);
-                               switch (patch_info->type) {
-                               case MONO_PATCH_INFO_INTERNAL_METHOD:
-                                       printf ("V: %s\n", patch_info->data.name);
-                                       break;
-                               case MONO_PATCH_INFO_METHOD_JUMP:
-                               case MONO_PATCH_INFO_METHOD:
-                                       printf ("V: %s\n", patch_info->data.method->name);
-                                       break;
-                               default:
-                                       break;
-                               }
+                               break;
                        }
                }
-
-               amd64_patch (ip, (gpointer)target);
        }
+
+       amd64_patch (ip, (gpointer)target);
 }
 
 #ifndef DISABLE_JIT
@@ -7030,38 +6974,6 @@ mono_arch_emit_prolog (MonoCompile *cfg)
                        /* Unused arguments */
                        continue;
 
-               if (cfg->globalra) {
-                       /* All the other moves are done by the register allocator */
-                       switch (ainfo->storage) {
-                       case ArgInFloatSSEReg:
-                               amd64_sse_cvtss2sd_reg_reg (code, ainfo->reg, ainfo->reg);
-                               break;
-                       case ArgValuetypeInReg:
-                               for (quad = 0; quad < 2; quad ++) {
-                                       switch (ainfo->pair_storage [quad]) {
-                                       case ArgInIReg:
-                                               amd64_mov_membase_reg (code, ins->inst_basereg, ins->inst_offset + (quad * sizeof(mgreg_t)), ainfo->pair_regs [quad], sizeof(mgreg_t));
-                                               break;
-                                       case ArgInFloatSSEReg:
-                                               amd64_movss_membase_reg (code, ins->inst_basereg, ins->inst_offset + (quad * sizeof(mgreg_t)), ainfo->pair_regs [quad]);
-                                               break;
-                                       case ArgInDoubleSSEReg:
-                                               amd64_movsd_membase_reg (code, ins->inst_basereg, ins->inst_offset + (quad * sizeof(mgreg_t)), ainfo->pair_regs [quad]);
-                                               break;
-                                       case ArgNone:
-                                               break;
-                                       default:
-                                               g_assert_not_reached ();
-                                       }
-                               }
-                               break;
-                       default:
-                               break;
-                       }
-
-                       continue;
-               }
-
                /* Save volatile arguments to the stack */
                if (ins->opcode != OP_REGVAR) {
                        switch (ainfo->storage) {
@@ -7653,7 +7565,7 @@ mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolea
        guchar *code = p;
        int save_mode = SAVE_NONE;
        MonoMethod *method = cfg->method;
-       MonoType *ret_type = mini_get_underlying_type (cfg, mono_method_signature (method)->ret);
+       MonoType *ret_type = mini_get_underlying_type (mono_method_signature (method)->ret);
        int i;
        
        switch (ret_type->type) {
@@ -7773,7 +7685,7 @@ mono_arch_flush_register_windows (void)
 gboolean 
 mono_arch_is_inst_imm (gint64 imm)
 {
-       return amd64_is_imm32 (imm);
+       return amd64_use_imm32 (imm);
 }
 
 /*
@@ -7790,7 +7702,7 @@ mono_arch_is_int_overflow (void *sigctx, void *info)
 
        mono_sigctx_to_monoctx (sigctx, &ctx);
 
-       rip = (guint8*)ctx.rip;
+       rip = (guint8*)ctx.gregs [AMD64_RIP];
 
        if (IS_REX (rip [0])) {
                reg = amd64_rex_b (rip [0]);
@@ -7803,47 +7715,7 @@ mono_arch_is_int_overflow (void *sigctx, void *info)
                /* idiv REG */
                reg += x86_modrm_rm (rip [1]);
 
-               switch (reg) {
-               case AMD64_RAX:
-                       value = ctx.rax;
-                       break;
-               case AMD64_RBX:
-                       value = ctx.rbx;
-                       break;
-               case AMD64_RCX:
-                       value = ctx.rcx;
-                       break;
-               case AMD64_RDX:
-                       value = ctx.rdx;
-                       break;
-               case AMD64_RBP:
-                       value = ctx.rbp;
-                       break;
-               case AMD64_RSP:
-                       value = ctx.rsp;
-                       break;
-               case AMD64_RSI:
-                       value = ctx.rsi;
-                       break;
-               case AMD64_RDI:
-                       value = ctx.rdi;
-                       break;
-               case AMD64_R12:
-                       value = ctx.r12;
-                       break;
-               case AMD64_R13:
-                       value = ctx.r13;
-                       break;
-               case AMD64_R14:
-                       value = ctx.r14;
-                       break;
-               case AMD64_R15:
-                       value = ctx.r15;
-                       break;
-               default:
-                       g_assert_not_reached ();
-                       reg = -1;
-               }                       
+               value = ctx.gregs [reg];
 
                if (value == -1)
                        return TRUE;
@@ -7940,11 +7812,14 @@ 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;
+       GSList *unwind_ops = NULL;
        int i;
 
+       unwind_ops = mono_arch_get_cie_program ();
+
        if (has_target) {
                start = code = mono_global_codeman_reserve (64);
 
@@ -7981,8 +7856,13 @@ get_delegate_invoke_impl (gboolean has_target, guint32 param_count, guint32 *cod
        nacl_global_codeman_validate (&start, 64, &code);
        mono_arch_flush_icache (start, code - start);
 
-       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;
@@ -7999,6 +7879,47 @@ 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 = 20;
+       char *tramp_name;
+       GSList *unwind_ops;
+
+       if (offset / (int)sizeof (gpointer) > MAX_VIRTUAL_DELEGATE_OFFSET)
+               return NULL;
+
+       start = code = mono_global_codeman_reserve (size);
+
+       unwind_ops = mono_arch_get_cie_program ();
+
+       /* Replace the this argument with the target */
+       amd64_mov_reg_reg (code, AMD64_RAX, AMD64_ARG_REG1, 8);
+       amd64_mov_reg_membase (code, AMD64_ARG_REG1, AMD64_RAX, MONO_STRUCT_OFFSET (MonoDelegate, target), 8);
+
+       if (load_imt_reg) {
+               /* Load the IMT reg */
+               amd64_mov_reg_membase (code, MONO_ARCH_IMT_REG, AMD64_RAX, MONO_STRUCT_OFFSET (MonoDelegate, method), 8);
+       }
+
+       /* Load the vtable */
+       amd64_mov_reg_membase (code, AMD64_RAX, AMD64_ARG_REG1, MONO_STRUCT_OFFSET (MonoObject, vtable), 8);
+       amd64_jump_membase (code, AMD64_RAX, 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;
+}
+
 /*
  * mono_arch_get_delegate_invoke_impls:
  *
@@ -8009,19 +7930,23 @@ 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) {
+               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);
 
-       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);
+               get_delegate_virtual_invoke_impl (&info, FALSE, i * SIZEOF_VOID_P);
+               res = g_slist_prepend (res, info);
        }
 
        return res;
@@ -8037,7 +7962,7 @@ mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_targe
                return NULL;
 
        /* FIXME: Support more cases */
-       if (MONO_TYPE_ISSTRUCT (mini_replace_type (sig->ret)))
+       if (MONO_TYPE_ISSTRUCT (mini_get_underlying_type (sig->ret)))
                return NULL;
 
        if (has_target) {
@@ -8046,10 +7971,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 ();
 
@@ -8071,7 +7999,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 ();
@@ -8085,26 +8015,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 = 20;
+       MonoTrampInfo *info;
+       gpointer code;
 
-       start = code = mono_global_codeman_reserve (size);
-
-       /* Replace the this argument with the target */
-       amd64_mov_reg_reg (code, AMD64_RAX, AMD64_ARG_REG1, 8);
-       amd64_mov_reg_membase (code, AMD64_ARG_REG1, AMD64_RAX, MONO_STRUCT_OFFSET (MonoDelegate, target), 8);
-
-       if (load_imt_reg) {
-               /* Load the IMT reg */
-               amd64_mov_reg_membase (code, MONO_ARCH_IMT_REG, AMD64_RAX, MONO_STRUCT_OFFSET (MonoDelegate, method), 8);
-       }
-
-       /* Load the vtable */
-       amd64_mov_reg_membase (code, AMD64_RAX, AMD64_ARG_REG1, MONO_STRUCT_OFFSET (MonoObject, vtable), 8);
-       amd64_jump_membase (code, AMD64_RAX, offset);
-       mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_DELEGATE_INVOKE, NULL);
-
-       return start;
+       code = get_delegate_virtual_invoke_impl (&info, load_imt_reg, offset);
+       if (code)
+               mono_tramp_info_register (info, NULL);
+       return code;
 }
 
 void
@@ -8163,13 +8080,14 @@ mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckI
        int size = 0;
        guint8 *code, *start;
        gboolean vtable_is_32bit = ((gsize)(vtable) == (gsize)(int)(gsize)(vtable));
+       GSList *unwind_ops;
 
        for (i = 0; i < count; ++i) {
                MonoIMTCheckItem *item = imt_entries [i];
                if (item->is_equals) {
                        if (item->check_target_idx) {
                                if (!item->compare_done) {
-                                       if (amd64_is_imm32 (item->key))
+                                       if (amd64_use_imm32 ((gint64)item->key))
                                                item->chunk_size += CMP_SIZE;
                                        else
                                                item->chunk_size += MOV_REG_IMM_SIZE + CMP_REG_REG_SIZE;
@@ -8205,7 +8123,7 @@ mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckI
                                }
                        }
                } else {
-                       if (amd64_is_imm32 (item->key))
+                       if (amd64_use_imm32 ((gint64)item->key))
                                item->chunk_size += CMP_SIZE;
                        else
                                item->chunk_size += MOV_REG_IMM_SIZE + CMP_REG_REG_SIZE;
@@ -8225,6 +8143,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;
@@ -8233,10 +8154,10 @@ mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckI
 
                        if (item->check_target_idx || fail_case) {
                                if (!item->compare_done || fail_case) {
-                                       if (amd64_is_imm32 (item->key))
+                                       if (amd64_use_imm32 ((gint64)item->key))
                                                amd64_alu_reg_imm_size (code, X86_CMP, MONO_ARCH_IMT_REG, (guint32)(gssize)item->key, sizeof(gpointer));
                                        else {
-                                               amd64_mov_reg_imm (code, MONO_ARCH_IMT_SCRATCH_REG, item->key);
+                                               amd64_mov_reg_imm_size (code, MONO_ARCH_IMT_SCRATCH_REG, item->key, sizeof(gpointer));
                                                amd64_alu_reg_reg (code, X86_CMP, MONO_ARCH_IMT_REG, MONO_ARCH_IMT_SCRATCH_REG);
                                        }
                                }
@@ -8284,10 +8205,10 @@ mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckI
 #endif
                        }
                } else {
-                       if (amd64_is_imm32 (item->key))
+                       if (amd64_use_imm32 ((gint64)item->key))
                                amd64_alu_reg_imm_size (code, X86_CMP, MONO_ARCH_IMT_REG, (guint32)(gssize)item->key, sizeof (gpointer));
                        else {
-                               amd64_mov_reg_imm (code, MONO_ARCH_IMT_SCRATCH_REG, item->key);
+                               amd64_mov_reg_imm_size (code, MONO_ARCH_IMT_SCRATCH_REG, item->key, sizeof (gpointer));
                                amd64_alu_reg_reg (code, X86_CMP, MONO_ARCH_IMT_REG, MONO_ARCH_IMT_SCRATCH_REG);
                        }
                        item->jmp_code = code;
@@ -8315,6 +8236,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;
 }
 
@@ -8420,44 +8343,16 @@ mono_arch_print_tree (MonoInst *tree, int arity)
        return 0;
 }
 
-#define _CTX_REG(ctx,fld,i) ((&ctx->fld)[i])
-
 mgreg_t
 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
 {
-       switch (reg) {
-       case AMD64_RCX: return ctx->rcx;
-       case AMD64_RDX: return ctx->rdx;
-       case AMD64_RBX: return ctx->rbx;
-       case AMD64_RBP: return ctx->rbp;
-       case AMD64_RSP: return ctx->rsp;
-       default:
-               return _CTX_REG (ctx, rax, reg);
-       }
+       return ctx->gregs [reg];
 }
 
 void
 mono_arch_context_set_int_reg (MonoContext *ctx, int reg, mgreg_t val)
 {
-       switch (reg) {
-       case AMD64_RCX:
-               ctx->rcx = val;
-               break;
-       case AMD64_RDX: 
-               ctx->rdx = val;
-               break;
-       case AMD64_RBX:
-               ctx->rbx = val;
-               break;
-       case AMD64_RBP:
-               ctx->rbp = val;
-               break;
-       case AMD64_RSP:
-               ctx->rsp = val;
-               break;
-       default:
-               _CTX_REG (ctx, rax, reg) = val;
-       }
+       ctx->gregs [reg] = val;
 }
 
 gpointer