2010-06-23 Miguel de Icaza <miguel@novell.com>
[mono.git] / mono / mini / mini-x86.c
index 31e84791f5305a9bd9e865729f127e9f4ed9c5d8..f702cc9eaff5c8428d7c2b88060ba7b1a9f242a1 100644 (file)
@@ -140,6 +140,11 @@ mono_arch_xregname (int reg)
        }
 }
 
+void 
+mono_x86_patch (unsigned char* code, gpointer target)
+{
+       x86_patch (code, (unsigned char*)target);
+}
 
 typedef enum {
        ArgInIReg,
@@ -169,6 +174,9 @@ typedef struct {
        guint32 freg_usage;
        gboolean need_stack_align;
        guint32 stack_align_amount;
+       gboolean vtype_retaddr;
+       /* The index of the vret arg in the argument list */
+       int vret_arg_index;
        ArgInfo ret;
        ArgInfo sig_cookie;
        ArgInfo args [1];
@@ -298,7 +306,7 @@ add_valuetype (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, ArgIn
 static CallInfo*
 get_call_info_internal (MonoGenericSharingContext *gsctx, CallInfo *cinfo, MonoMethodSignature *sig, gboolean is_pinvoke)
 {
-       guint32 i, gr, fr;
+       guint32 i, gr, fr, pstart;
        MonoType *ret_type;
        int n = sig->hasthis + sig->param_count;
        guint32 stack_size = 0;
@@ -352,15 +360,15 @@ get_call_info_internal (MonoGenericSharingContext *gsctx, CallInfo *cinfo, MonoM
                        guint32 tmp_gr = 0, tmp_fr = 0, tmp_stacksize = 0;
 
                        add_valuetype (gsctx, sig, &cinfo->ret, sig->ret, TRUE, &tmp_gr, &tmp_fr, &tmp_stacksize);
-                       if (cinfo->ret.storage == ArgOnStack)
+                       if (cinfo->ret.storage == ArgOnStack) {
+                               cinfo->vtype_retaddr = TRUE;
                                /* The caller passes the address where the value is stored */
-                               add_general (&gr, &stack_size, &cinfo->ret);
+                       }
                        break;
                }
                case MONO_TYPE_TYPEDBYREF:
-                       /* Same as a valuetype with size 24 */
-                       add_general (&gr, &stack_size, &cinfo->ret);
-                       ;
+                       /* Same as a valuetype with size 12 */
+                       cinfo->vtype_retaddr = TRUE;
                        break;
                case MONO_TYPE_VOID:
                        cinfo->ret.storage = ArgNone;
@@ -370,9 +378,31 @@ get_call_info_internal (MonoGenericSharingContext *gsctx, CallInfo *cinfo, MonoM
                }
        }
 
-       /* this */
-       if (sig->hasthis)
-               add_general (&gr, &stack_size, cinfo->args + 0);
+       pstart = 0;
+       /*
+        * To simplify get_this_arg_reg () and LLVM integration, emit the vret arg after
+        * the first argument, allowing 'this' to be always passed in the first arg reg.
+        * Also do this if the first argument is a reference type, since virtual calls
+        * 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 (sig->params [0])))) {
+               if (sig->hasthis) {
+                       add_general (&gr, &stack_size, cinfo->args + 0);
+               } else {
+                       add_general (&gr, &stack_size, &cinfo->args [sig->hasthis + 0]);
+                       pstart = 1;
+               }
+               add_general (&gr, &stack_size, &cinfo->ret);
+               cinfo->vret_arg_index = 1;
+       } else {
+               /* this */
+               if (sig->hasthis)
+                       add_general (&gr, &stack_size, cinfo->args + 0);
+
+               if (cinfo->vtype_retaddr)
+                       add_general (&gr, &stack_size, &cinfo->ret);
+       }
 
        if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == 0)) {
                gr = PARAM_REGS;
@@ -382,7 +412,7 @@ get_call_info_internal (MonoGenericSharingContext *gsctx, CallInfo *cinfo, MonoM
                add_general (&gr, &stack_size, &cinfo->sig_cookie);
        }
 
-       for (i = 0; i < sig->param_count; ++i) {
+       for (i = pstart; i < sig->param_count; ++i) {
                ArgInfo *ainfo = &cinfo->args [sig->hasthis + i];
                MonoType *ptype;
 
@@ -521,14 +551,14 @@ mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJit
 
        cinfo = get_call_info_internal (NULL, cinfo, csig, FALSE);
 
-       if (MONO_TYPE_ISSTRUCT (csig->ret) && (cinfo->ret.storage == ArgOnStack)) {
+       arg_info [0].offset = offset;
+
+       if (csig->hasthis) {
                args_size += sizeof (gpointer);
                offset += 4;
        }
 
-       arg_info [0].offset = offset;
-
-       if (csig->hasthis) {
+       if (MONO_TYPE_ISSTRUCT (csig->ret) && (cinfo->ret.storage == ArgOnStack)) {
                args_size += sizeof (gpointer);
                offset += 4;
        }
@@ -674,6 +704,9 @@ mono_arch_init (void)
        ss_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ);
        bp_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT);
        mono_mprotect (bp_trigger_page, mono_pagesize (), 0);
+
+       mono_aot_register_jit_icall ("mono_x86_throw_exception", mono_x86_throw_exception);
+       mono_aot_register_jit_icall ("mono_x86_throw_corlib_exception", mono_x86_throw_corlib_exception);
 }
 
 /*
@@ -695,6 +728,11 @@ mono_arch_cpu_optimizazions (guint32 *exclude_mask)
        guint32 opts = 0;
        
        *exclude_mask = 0;
+
+       if (mono_aot_only)
+               /* The cpuid function allocates from the global codeman */
+               return opts;
+
        /* Feature Flags function, flags returned in EDX. */
        if (cpuid (1, &eax, &ebx, &ecx, &edx)) {
                if (edx & (1 << 15)) {
@@ -731,19 +769,23 @@ mono_arch_cpu_enumerate_simd_versions (void)
        int eax, ebx, ecx, edx;
        guint32 sse_opts = 0;
 
+       if (mono_aot_only)
+               /* The cpuid function allocates from the global codeman */
+               return sse_opts;
+
        if (cpuid (1, &eax, &ebx, &ecx, &edx)) {
                if (edx & (1 << 25))
-                       sse_opts |= 1 << SIMD_VERSION_SSE1;
+                       sse_opts |= SIMD_VERSION_SSE1;
                if (edx & (1 << 26))
-                       sse_opts |= 1 << SIMD_VERSION_SSE2;
+                       sse_opts |= SIMD_VERSION_SSE2;
                if (ecx & (1 << 0))
-                       sse_opts |= 1 << SIMD_VERSION_SSE3;
+                       sse_opts |= SIMD_VERSION_SSE3;
                if (ecx & (1 << 9))
-                       sse_opts |= 1 << SIMD_VERSION_SSSE3;
+                       sse_opts |= SIMD_VERSION_SSSE3;
                if (ecx & (1 << 19))
-                       sse_opts |= 1 << SIMD_VERSION_SSE41;
+                       sse_opts |= SIMD_VERSION_SSE41;
                if (ecx & (1 << 20))
-                       sse_opts |= 1 << SIMD_VERSION_SSE42;
+                       sse_opts |= SIMD_VERSION_SSE42;
        }
 
        /* Yes, all this needs to be done to check for sse4a.
@@ -754,7 +796,7 @@ mono_arch_cpu_enumerate_simd_versions (void)
                if ((((unsigned int) eax) >= 0x80000001) && (ebx == 0x68747541) && (ecx == 0x444D4163) && (edx == 0x69746E65)) {
                        cpuid (0x80000001, &eax, &ebx, &ecx, &edx);
                        if (ecx & (1 << 6))
-                               sse_opts |= 1 << SIMD_VERSION_SSE4a;
+                               sse_opts |= SIMD_VERSION_SSE4a;
                }
        }
 
@@ -1163,6 +1205,7 @@ mono_arch_get_llvm_call_info (MonoCompile *cfg, MonoMethodSignature *sig)
        CallInfo *cinfo;
        ArgInfo *ainfo;
        LLVMCallInfo *linfo;
+       MonoType *t;
 
        n = sig->param_count + sig->hasthis;
 
@@ -1195,6 +1238,7 @@ mono_arch_get_llvm_call_info (MonoCompile *cfg, MonoMethodSignature *sig)
        if (MONO_TYPE_ISSTRUCT (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 (MONO_TYPE_ISSTRUCT (sig->ret) && cinfo->ret.storage != ArgInIReg) {
@@ -1206,6 +1250,11 @@ mono_arch_get_llvm_call_info (MonoCompile *cfg, MonoMethodSignature *sig)
        for (i = 0; i < n; ++i) {
                ainfo = cinfo->args + i;
 
+               if (i >= sig->hasthis)
+                       t = sig->params [i - sig->hasthis];
+               else
+                       t = &mono_defaults.int_class->byval_arg;
+
                linfo->args [i].storage = LLVMArgNone;
 
                switch (ainfo->storage) {
@@ -1217,16 +1266,19 @@ mono_arch_get_llvm_call_info (MonoCompile *cfg, MonoMethodSignature *sig)
                        linfo->args [i].storage = LLVMArgInFPReg;
                        break;
                case ArgOnStack:
-                       if ((i >= sig->hasthis) && (MONO_TYPE_ISSTRUCT(sig->params [i - sig->hasthis]))) {
-                               linfo->args [i].storage = LLVMArgVtypeByVal;
+                       if (MONO_TYPE_ISSTRUCT (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;
+                               else
+                                       linfo->args [i].storage = LLVMArgVtypeByVal;
                        } else {
                                linfo->args [i].storage = LLVMArgInIReg;
-                               if (!sig->params [i - sig->hasthis]->byref) {
-                                       if (sig->params [i - sig->hasthis]->type == MONO_TYPE_R4) {
+                               if (t->byref) {
+                                       if (t->type == MONO_TYPE_R4)
                                                linfo->args [i].storage = LLVMArgInFPReg;
-                                       } else if (sig->params [i - sig->hasthis]->type == MONO_TYPE_R8) {
+                                       else if (t->type == MONO_TYPE_R8)
                                                linfo->args [i].storage = LLVMArgInFPReg;
-                                       }
                                }
                        }
                        break;
@@ -1304,6 +1356,15 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
                ArgInfo *ainfo = cinfo->args + i;
                MonoType *t;
 
+               if (cinfo->vtype_retaddr && cinfo->vret_arg_index == 1 && i == 0) {
+                       /* Push the vret arg before the first argument */
+                       MonoInst *vtarg;
+                       MONO_INST_NEW (cfg, vtarg, OP_X86_PUSH);
+                       vtarg->type = STACK_MP;
+                       vtarg->sreg1 = call->vret_var->dreg;
+                       MONO_ADD_INS (cfg->cbb, vtarg);
+               }
+
                if (i >= sig->hasthis)
                        t = sig->params [i - sig->hasthis];
                else
@@ -1391,7 +1452,7 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
                        MONO_ADD_INS (cfg->cbb, vtarg);
                                
                        mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->ret.reg, FALSE);
-               } else {
+               } else if (cinfo->vtype_retaddr && cinfo->vret_arg_index == 0) {
                        MonoInst *vtarg;
                        MONO_INST_NEW (cfg, vtarg, OP_X86_PUSH);
                        vtarg->type = STACK_MP;
@@ -2029,6 +2090,23 @@ emit_move_return_value (MonoCompile *cfg, MonoInst *ins, guint8 *code)
        return code;
 }
 
+gboolean
+mono_x86_have_tls_get (void)
+{
+#ifdef __APPLE__
+       guint32 *ins = (guint32*)pthread_getspecific;
+       /*
+        * We're looking for these two instructions:
+        *
+        * mov    0x4(%esp),%eax
+        * mov    %gs:0x48(,%eax,4),%eax
+        */
+       return ins [0] == 0x0424448b && ins [1] == 0x85048b65 && ins [2] == 0x00000048;
+#else
+       return TRUE;
+#endif
+}
+
 /*
  * mono_x86_emit_tls_get:
  * @code: buffer to store code to
@@ -2044,7 +2122,10 @@ emit_move_return_value (MonoCompile *cfg, MonoInst *ins, guint8 *code)
 guint8*
 mono_x86_emit_tls_get (guint8* code, int dreg, int tls_offset)
 {
-#ifdef TARGET_WIN32
+#if defined(__APPLE__)
+       x86_prefix (code, X86_GS_PREFIX);
+       x86_mov_reg_mem (code, dreg, 0x48 + tls_offset * 4, 4);
+#elif defined(TARGET_WIN32)
        /* 
         * See the Under the Hood article in the May 1996 issue of Microsoft Systems 
         * Journal and/or a disassembly of the TlsGet () function.
@@ -2751,14 +2832,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        x86_mov_reg_imm (code, ins->dreg, 0);
                        break;
                case OP_LOAD_GOTADDR:
-                       x86_call_imm (code, 0);
-                       /* 
-                        * The patch needs to point to the pop, since the GOT offset needs 
-                        * to be added to that address.
-                        */
-                       mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_GOT_OFFSET, NULL);
-                       x86_pop_reg (code, ins->dreg);
-                       x86_alu_reg_imm (code, X86_ADD, ins->dreg, 0xf0f0f0f0);
+                       g_assert (ins->dreg == MONO_ARCH_GOT_REG);
+                       code = mono_arch_emit_load_got_addr (cfg->native_code, code, cfg, NULL);
                        break;
                case OP_GOT_ENTRY:
                        mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_right->inst_i1, ins->inst_right->inst_p0);
@@ -2981,6 +3056,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        x86_alu_reg_imm (code, X86_SUB, X86_ESP, MONO_ARCH_FRAME_ALIGNMENT - 4);
                        mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
                        x86_call_imm (code, 0);
+                       mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb);
                        x86_alu_reg_imm (code, X86_ADD, X86_ESP, MONO_ARCH_FRAME_ALIGNMENT - 4);
                        break;
                case OP_START_HANDLER: {
@@ -4536,22 +4612,35 @@ mono_arch_emit_prolog (MonoCompile *cfg)
 #endif
                }
                else {
-                       g_assert (!cfg->compile_aot);
-                       x86_push_imm (code, cfg->domain);
+                       if (cfg->compile_aot) {
+                               /* 
+                                * This goes before the saving of callee saved regs, so save the got reg
+                                * ourselves.
+                                */
+                               x86_push_reg (code, MONO_ARCH_GOT_REG);
+                               code = mono_arch_emit_load_got_addr (cfg->native_code, code, cfg, NULL);
+                               x86_push_imm (code, 0);
+                       } else {
+                               x86_push_imm (code, cfg->domain);
+                       }
                        code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_jit_thread_attach");
                        x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
+                       if (cfg->compile_aot)
+                               x86_pop_reg (code, MONO_ARCH_GOT_REG);
                }
        }
 
        if (method->save_lmf) {
                pos += sizeof (MonoLMF);
 
-               if (cfg->compile_aot)
-                       cfg->disable_aot = TRUE;
-
                /* save the current IP */
-               mono_add_patch_info (cfg, code + 1 - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
-               x86_push_imm_template (code);
+               if (cfg->compile_aot) {
+                       /* This pushes the current ip */
+                       x86_call_imm (code, 0);
+               } else {
+                       mono_add_patch_info (cfg, code + 1 - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
+                       x86_push_imm_template (code);
+               }
                cfa_offset += sizeof (gpointer);
 
                /* save all caller saved regs */
@@ -4598,6 +4687,8 @@ mono_arch_emit_prolog (MonoCompile *cfg)
                                x86_alu_reg_imm (code, X86_ADD, X86_EAX, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
 #endif
                        } else {
+                               if (cfg->compile_aot)
+                                       code = mono_arch_emit_load_got_addr (cfg->native_code, code, cfg, NULL);
                                code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_get_lmf_addr");
                        }
 
@@ -5236,6 +5327,17 @@ mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
        return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG];
 }
 
+GSList*
+mono_arch_get_cie_program (void)
+{
+       GSList *l = NULL;
+
+       mono_add_unwind_op_def_cfa (l, (guint8*)NULL, (guint8*)NULL, X86_ESP, 4);
+       mono_add_unwind_op_offset (l, (guint8*)NULL, (guint8*)NULL, X86_NREG, -4);
+
+       return l;
+}
+
 MonoInst*
 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
 {
@@ -5455,18 +5557,7 @@ mono_arch_get_vcall_slot (guint8 *code, mgreg_t *regs, int *displacement)
 guint32
 mono_x86_get_this_arg_offset (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig)
 {
-       CallInfo *cinfo = NULL;
-       int offset;
-
-       if (MONO_TYPE_ISSTRUCT (sig->ret)) {
-               cinfo = get_call_info (gsctx, NULL, sig, FALSE);
-
-               offset = cinfo->args [0].offset;
-       } else {
-               offset = 0;
-       }
-
-       return offset;
+       return 0;
 }
 
 gpointer
@@ -5478,25 +5569,12 @@ mono_arch_get_this_arg_from_call (MonoGenericSharingContext *gsctx, MonoMethodSi
        gpointer res;
        int offset;
 
-       /* 
-        * Avoid expensive calls to get_generic_context_from_code () + get_call_info 
-        * if possible.
-        */
-       if (MONO_TYPE_ISSTRUCT (sig->ret)) {
-               if (!gsctx && code)
-                       gsctx = mono_get_generic_context_from_code (code);
-               cinfo = get_call_info (gsctx, NULL, sig, FALSE);
-
-               offset = cinfo->args [0].offset;
-       } else {
-               offset = 0;
-       }
+       offset = 0;
 
        /*
         * The stack looks like:
         * <other args>
         * <this=delegate>
-        * <possible vtype return address>
         * <return addr>
         * <4 pointers pushed by mono_arch_create_trampoline_code ()>
         */
@@ -5508,18 +5586,11 @@ mono_arch_get_this_arg_from_call (MonoGenericSharingContext *gsctx, MonoMethodSi
 
 #define MAX_ARCH_DELEGATE_PARAMS 10
 
-gpointer
-mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
+static gpointer
+get_delegate_invoke_impl (gboolean has_target, guint32 param_count, guint32 *code_len)
 {
        guint8 *code, *start;
 
-       if (sig->param_count > MAX_ARCH_DELEGATE_PARAMS)
-               return NULL;
-
-       /* FIXME: Support more cases */
-       if (MONO_TYPE_ISSTRUCT (sig->ret))
-               return NULL;
-
        /*
         * The stack contains:
         * <delegate>
@@ -5527,10 +5598,6 @@ mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_targe
         */
 
        if (has_target) {
-               static guint8* cached = NULL;
-               if (cached)
-                       return cached;
-               
                start = code = mono_global_codeman_reserve (64);
 
                /* Replace the this argument with the target */
@@ -5540,25 +5607,10 @@ mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_targe
                x86_jump_membase (code, X86_EAX, G_STRUCT_OFFSET (MonoDelegate, method_ptr));
 
                g_assert ((code - start) < 64);
-
-               mono_debug_add_delegate_trampoline (start, code - start);
-
-               mono_memory_barrier ();
-
-               cached = start;
        } else {
-               static guint8* cache [MAX_ARCH_DELEGATE_PARAMS + 1] = {NULL};
                int i = 0;
                /* 8 for mov_reg and jump, plus 8 for each parameter */
-               int code_reserve = 8 + (sig->param_count * 8);
-
-               for (i = 0; i < sig->param_count; ++i)
-                       if (!mono_is_regsize_var (sig->params [i]))
-                               return NULL;
-
-               code = cache [sig->param_count];
-               if (code)
-                       return code;
+               int code_reserve = 8 + (param_count * 8);
 
                /*
                 * The stack contains:
@@ -5582,7 +5634,7 @@ mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_targe
                x86_mov_reg_membase (code, X86_ECX, X86_ESP, 4, 4);
 
                /* move args up */
-               for (i = 0; i < sig->param_count; ++i) {
+               for (i = 0; i < param_count; ++i) {
                        x86_mov_reg_membase (code, X86_EAX, X86_ESP, (i+2)*4, 4);
                        x86_mov_membase_reg (code, X86_ESP, (i+1)*4, X86_EAX, 4);
                }
@@ -5590,8 +5642,85 @@ mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_targe
                x86_jump_membase (code, X86_ECX, G_STRUCT_OFFSET (MonoDelegate, method_ptr));
 
                g_assert ((code - start) < code_reserve);
+       }
+
+       mono_debug_add_delegate_trampoline (start, code - start);
+
+       if (code_len)
+               *code_len = code - start;
+
+       return start;
+}
+
+GSList*
+mono_arch_get_delegate_invoke_impls (void)
+{
+       GSList *res = NULL;
+       guint8 *code;
+       guint32 code_len;
+       int i;
+
+       code = get_delegate_invoke_impl (TRUE, 0, &code_len);
+       res = g_slist_prepend (res, mono_tramp_info_create (g_strdup ("delegate_invoke_impl_has_target"), code, code_len, NULL, NULL));
+
+       for (i = 0; i < MAX_ARCH_DELEGATE_PARAMS; ++i) {
+               code = get_delegate_invoke_impl (FALSE, i, &code_len);
+               res = g_slist_prepend (res, mono_tramp_info_create (g_strdup_printf ("delegate_invoke_impl_target_%d", i), code, code_len, NULL, NULL));
+       }
+
+       return res;
+}
+
+gpointer
+mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
+{
+       guint8 *code, *start;
+
+       if (sig->param_count > MAX_ARCH_DELEGATE_PARAMS)
+               return NULL;
 
-               mono_debug_add_delegate_trampoline (start, code - start);
+       /* FIXME: Support more cases */
+       if (MONO_TYPE_ISSTRUCT (sig->ret))
+               return NULL;
+
+       /*
+        * The stack contains:
+        * <delegate>
+        * <return addr>
+        */
+
+       if (has_target) {
+               static guint8* cached = NULL;
+               if (cached)
+                       return cached;
+
+               if (mono_aot_only)
+                       start = mono_aot_get_trampoline ("delegate_invoke_impl_has_target");
+               else
+                       start = get_delegate_invoke_impl (TRUE, 0, NULL);
+
+               mono_memory_barrier ();
+
+               cached = start;
+       } else {
+               static guint8* cache [MAX_ARCH_DELEGATE_PARAMS + 1] = {NULL};
+               int i = 0;
+
+               for (i = 0; i < sig->param_count; ++i)
+                       if (!mono_is_regsize_var (sig->params [i]))
+                               return NULL;
+
+               code = cache [sig->param_count];
+               if (code)
+                       return code;
+
+               if (mono_aot_only) {
+                       char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", sig->param_count);
+                       start = mono_aot_get_trampoline (name);
+                       g_free (name);
+               } else {
+                       start = get_delegate_invoke_impl (FALSE, sig->param_count, NULL);
+               }
 
                mono_memory_barrier ();
 
@@ -5783,6 +5912,112 @@ mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *long_ins)
 #endif /* MONO_ARCH_SIMD_INTRINSICS */
 }
 
+/*MONO_ARCH_HAVE_HANDLER_BLOCK_GUARD*/
+gpointer
+mono_arch_install_handler_block_guard (MonoJitInfo *ji, MonoJitExceptionInfo *clause, MonoContext *ctx, gpointer new_value)
+{
+       int offset;
+       gpointer *sp, old_value;
+       char *bp;
+       const unsigned char *handler;
+
+       /*Decode the first instruction to figure out where did we store the spvar*/
+       /*Our jit MUST generate the following:
+        mov %esp, -?(%ebp)
+        Which is encoded as: 0x89 mod_rm.
+        mod_rm (esp, ebp, imm) which can be: (imm will never be zero)
+               mod (reg + imm8):  01 reg(esp): 100 rm(ebp): 101 -> 01100101 (0x65)
+               mod (reg + imm32): 10 reg(esp): 100 rm(ebp): 101 -> 10100101 (0xA5)
+       */
+       handler = clause->handler_start;
+
+       if (*handler != 0x89)
+               return NULL;
+
+       ++handler;
+
+       if (*handler == 0x65)
+               offset = *(signed char*)(handler + 1);
+       else if (*handler == 0xA5)
+               offset = *(int*)(handler + 1);
+       else
+               return NULL;
+
+       /*Load the spvar*/
+       bp = MONO_CONTEXT_GET_BP (ctx);
+       sp = *(gpointer*)(bp + offset);
+
+       old_value = *sp;
+       if (old_value < ji->code_start || (char*)old_value > ((char*)ji->code_start + ji->code_size))
+               return old_value;
+
+       *sp = new_value;
+
+       return old_value;
+}
+
+/*
+ * mono_aot_emit_load_got_addr:
+ *
+ *   Emit code to load the got address.
+ * On x86, the result is placed into EBX.
+ */
+guint8*
+mono_arch_emit_load_got_addr (guint8 *start, guint8 *code, MonoCompile *cfg, MonoJumpInfo **ji)
+{
+       x86_call_imm (code, 0);
+       /* 
+        * The patch needs to point to the pop, since the GOT offset needs 
+        * to be added to that address.
+        */
+       if (cfg)
+               mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_GOT_OFFSET, NULL);
+       else
+               *ji = mono_patch_info_list_prepend (*ji, code - start, MONO_PATCH_INFO_GOT_OFFSET, NULL);
+       x86_pop_reg (code, MONO_ARCH_GOT_REG);
+       x86_alu_reg_imm (code, X86_ADD, MONO_ARCH_GOT_REG, 0xf0f0f0f0);
+
+       return code;
+}
+
+/*
+ * mono_ppc_emit_load_aotconst:
+ *
+ *   Emit code to load the contents of the GOT slot identified by TRAMP_TYPE and
+ * TARGET from the mscorlib GOT in full-aot code.
+ * On x86, the GOT address is assumed to be in EBX, and the result is placed into 
+ * EAX.
+ */
+guint8*
+mono_arch_emit_load_aotconst (guint8 *start, guint8 *code, MonoJumpInfo **ji, int tramp_type, gconstpointer target)
+{
+       /* Load the mscorlib got address */
+       x86_mov_reg_membase (code, X86_EAX, MONO_ARCH_GOT_REG, sizeof (gpointer), 4);
+       *ji = mono_patch_info_list_prepend (*ji, code - start, tramp_type, target);
+       /* arch_emit_got_access () patches this */
+       x86_mov_reg_membase (code, X86_EAX, X86_EAX, 0xf0f0f0f0, 4);
+
+       return code;
+}
+
+/* Can't put this into mini-x86.h */
+gpointer
+mono_x86_get_signal_exception_trampoline (MonoTrampInfo **info, gboolean aot);
+
+GSList *
+mono_arch_get_trampolines (gboolean aot)
+{
+       MonoTrampInfo *info;
+       GSList *tramps = NULL;
+
+       mono_x86_get_signal_exception_trampoline (&info, aot);
+
+       tramps = g_slist_append (tramps, info);
+
+       return tramps;
+}
+
+
 #if __APPLE__
 #define DBG_SIGNAL SIGBUS
 #else