[arm] Fix unwind info for managed methods
[mono.git] / mono / mini / mini-x86.c
index 474ea72c771723c0e372bb5b8547a8aff42d9dd0..e8136429549c9e2c15043556d3c2ba87fa3a506a 100644 (file)
@@ -29,6 +29,7 @@
 #include <mono/utils/mono-mmap.h>
 #include <mono/utils/mono-memory-model.h>
 #include <mono/utils/mono-hwcap-x86.h>
+#include <mono/utils/mono-threads.h>
 
 #include "trace.h"
 #include "mini-x86.h"
@@ -299,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)
 {
@@ -307,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) {
@@ -324,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;
@@ -373,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;
@@ -390,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:
@@ -428,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;
@@ -438,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 */
@@ -447,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;
@@ -467,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 {
@@ -513,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:
@@ -543,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);
@@ -553,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:
@@ -568,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;
@@ -607,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;
@@ -617,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);
 }
 
 /*
@@ -631,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;
@@ -648,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;
 
@@ -671,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;
@@ -713,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;
@@ -1060,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;
@@ -1207,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);
        }
 
@@ -1243,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;
@@ -1292,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));
@@ -1319,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;
@@ -1350,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;
@@ -1423,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))
@@ -1481,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);
 
@@ -1511,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) {
@@ -1640,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) {
@@ -1659,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) {
@@ -1729,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:
@@ -2291,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:
@@ -2305,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;
 
@@ -3382,6 +3386,10 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        x86_ret (code);
                        break;
                }
+               case OP_GET_EX_OBJ:
+                       if (ins->dreg != X86_EAX)
+                               x86_mov_reg_reg (code, ins->dreg, X86_EAX, sizeof (gpointer));
+                       break;
 
                case OP_LABEL:
                        ins->inst_c0 = code - cfg->native_code;
@@ -5019,19 +5027,26 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        MONO_VARINFO (cfg, ins->inst_c0)->live_range_end = code - cfg->native_code;
                        break;
                }
-               case OP_NACL_GC_SAFE_POINT: {
-#if defined(__native_client_codegen__) && defined(__native_client_gc__)
-                       if (cfg->compile_aot)
-                               code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, (gpointer)mono_nacl_gc);
-                       else {
-                               guint8 *br [1];
-
-                               x86_test_mem_imm8 (code, (gpointer)&__nacl_thread_suspension_needed, 0xFFFFFFFF);
-                               br[0] = code; x86_branch8 (code, X86_CC_EQ, 0, FALSE);
-                               code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, (gpointer)mono_nacl_gc);
-                               x86_patch (br[0], code);
-                       }
+               case OP_GC_SAFE_POINT: {
+                       const char *polling_func = NULL;
+                       int compare_val = 0;
+                       guint8 *br [1];
+
+#if defined (USE_COOP_GC)
+                       polling_func = "mono_threads_state_poll";
+                       compare_val = 1;
+#elif defined(__native_client_codegen__) && defined(__native_client_gc__)
+                       polling_func = "mono_nacl_gc";
+                       compare_val = 0xFFFFFFFF;
 #endif
+                       if (!polling_func)
+                               break;
+
+                       x86_test_membase_imm (code, ins->sreg1, 0, compare_val);
+                       br[0] = code; x86_branch8 (code, X86_CC_EQ, 0, FALSE);
+                       code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD, polling_func);
+                       x86_patch (br [0], code);
+
                        break;
                }
                case OP_GC_LIVENESS_DEF:
@@ -5076,94 +5091,67 @@ mono_arch_register_lowlevel_calls (void)
 }
 
 void
-mono_arch_patch_code (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;
-               const 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:
-                               break;
-                       default:
-                               /* No need to patch these */
-                               continue;
-                       }
+       switch (ji->type) {
+       case MONO_PATCH_INFO_IP:
+               *((gconstpointer *)(ip)) = target;
+               break;
+       case MONO_PATCH_INFO_ABS:
+       case MONO_PATCH_INFO_METHOD:
+       case MONO_PATCH_INFO_METHOD_JUMP:
+       case MONO_PATCH_INFO_INTERNAL_METHOD:
+       case MONO_PATCH_INFO_BB:
+       case MONO_PATCH_INFO_LABEL:
+       case MONO_PATCH_INFO_RGCTX_FETCH:
+       case MONO_PATCH_INFO_MONITOR_ENTER:
+       case MONO_PATCH_INFO_MONITOR_ENTER_V4:
+       case MONO_PATCH_INFO_MONITOR_EXIT:
+       case MONO_PATCH_INFO_JIT_ICALL_ADDR:
+#if defined(__native_client_codegen__) && defined(__native_client__)
+               if (nacl_is_code_address (code)) {
+                       /* For tail calls, code is patched after being installed */
+                       /* but not through the normal "patch callsite" method.   */
+                       unsigned char buf[kNaClAlignment];
+                       unsigned char *aligned_code = (uintptr_t)code & ~kNaClAlignmentMask;
+                       unsigned char *_target = target;
+                       int ret;
+                       /* All patch targets modified in x86_patch */
+                       /* are IP relative.                        */
+                       _target = _target + (uintptr_t)buf - (uintptr_t)aligned_code;
+                       memcpy (buf, aligned_code, kNaClAlignment);
+                       /* Patch a temp buffer of bundle size, */
+                       /* then install to actual location.    */
+                       x86_patch (buf + ((uintptr_t)code - (uintptr_t)aligned_code), _target);
+                       ret = nacl_dyncode_modify (aligned_code, buf, kNaClAlignment);
+                       g_assert (ret == 0);
                }
-
-               target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
-
-               switch (patch_info->type) {
-               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, target);
-                       break;
+               else {
+                       x86_patch (ip, (unsigned char*)target);
                }
-               case MONO_PATCH_INFO_ABS:
-               case MONO_PATCH_INFO_METHOD:
-               case MONO_PATCH_INFO_METHOD_JUMP:
-               case MONO_PATCH_INFO_INTERNAL_METHOD:
-               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:
-               case MONO_PATCH_INFO_JIT_ICALL_ADDR:
-#if defined(__native_client_codegen__) && defined(__native_client__)
-                       if (nacl_is_code_address (code)) {
-                               /* For tail calls, code is patched after being installed */
-                               /* but not through the normal "patch callsite" method.   */
-                               unsigned char buf[kNaClAlignment];
-                               unsigned char *aligned_code = (uintptr_t)code & ~kNaClAlignmentMask;
-                               unsigned char *_target = target;
-                               int ret;
-                               /* All patch targets modified in x86_patch */
-                               /* are IP relative.                        */
-                               _target = _target + (uintptr_t)buf - (uintptr_t)aligned_code;
-                               memcpy (buf, aligned_code, kNaClAlignment);
-                               /* Patch a temp buffer of bundle size, */
-                               /* then install to actual location.    */
-                               x86_patch (buf + ((uintptr_t)code - (uintptr_t)aligned_code), _target);
-                               ret = nacl_dyncode_modify (aligned_code, buf, kNaClAlignment);
-                               g_assert (ret == 0);
-                       }
-                       else {
-                               x86_patch (ip, target);
-                       }
 #else
-                       x86_patch (ip, target);
+               x86_patch (ip, (unsigned char*)target);
 #endif
-                       break;
-               case MONO_PATCH_INFO_NONE:
-                       break;
-               case MONO_PATCH_INFO_R4:
-               case MONO_PATCH_INFO_R8: {
-                       guint32 offset = mono_arch_get_patch_offset (ip);
-                       *((gconstpointer *)(ip + offset)) = target;
-                       break;
-               }
-               default: {
-                       guint32 offset = mono_arch_get_patch_offset (ip);
+               break;
+       case MONO_PATCH_INFO_NONE:
+               break;
+       case MONO_PATCH_INFO_R4:
+       case MONO_PATCH_INFO_R8: {
+               guint32 offset = mono_arch_get_patch_offset (ip);
+               *((gconstpointer *)(ip + offset)) = target;
+               break;
+       }
+       default: {
+               guint32 offset = mono_arch_get_patch_offset (ip);
 #if !defined(__native_client__)
-                       *((gconstpointer *)(ip + offset)) = target;
+               *((gconstpointer *)(ip + offset)) = target;
 #else
-                       *((gconstpointer *)(ip + offset)) = nacl_modify_patch_target (target);
+               *((gconstpointer *)(ip + offset)) = nacl_modify_patch_target (target);
 #endif
-                       break;
-               }
-               }
+               break;
+       }
        }
 }
 
@@ -5471,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) {
@@ -5544,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]) {
@@ -5571,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
@@ -5774,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];
@@ -5810,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;
@@ -5896,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;
 }
 
@@ -6061,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;
 }
@@ -6087,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:
@@ -6151,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;
@@ -6169,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) {
+               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;
@@ -6214,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 ();
 
@@ -6239,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 ();
@@ -6253,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