2006-01-03 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / mini / mini-x86.c
index b847659773cf0dc7f3798df395b5e98175ca83c2..dad57f61a21a8ab5a7b3ac90d56ffd0f0a76ef5d 100644 (file)
 #include <string.h>
 #include <math.h>
 
-#ifndef PLATFORM_WIN32
-#include <unistd.h>
-#include <sys/mman.h>
-#endif
-
 #include <mono/metadata/appdomain.h>
 #include <mono/metadata/debug-helpers.h>
 #include <mono/metadata/threads.h>
@@ -35,6 +30,8 @@ static gint thread_tls_offset = -1;
 
 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
 
+#define ARGS_OFFSET 8
+
 #ifdef PLATFORM_WIN32
 /* Under windows, the default pinvoke calling convention is stdcall */
 #define CALLCONV_IS_STDCALL(sig) ((((sig)->call_convention) == MONO_CALL_STDCALL) || ((sig)->pinvoke && ((sig)->call_convention) == MONO_CALL_DEFAULT))
@@ -42,8 +39,6 @@ static gint thread_tls_offset = -1;
 #define CALLCONV_IS_STDCALL(sig) (((sig)->call_convention) == MONO_CALL_STDCALL)
 #endif
 
-#define SIGNAL_STACK_SIZE (64 * 1024)
-
 #define NOT_IMPLEMENTED g_assert_not_reached ()
 
 const char*
@@ -141,7 +136,7 @@ add_float (guint32 *gr, guint32 *stack_size, ArgInfo *ainfo, gboolean is_double)
 
     if (*gr >= FLOAT_PARAM_REGS) {
                ainfo->storage = ArgOnStack;
-               (*stack_size) += sizeof (gpointer);
+               (*stack_size) += is_double ? 8 : 4;
     }
     else {
                /* A double register */
@@ -730,72 +725,19 @@ mono_arch_allocate_vars (MonoCompile *cfg)
        MonoMethodHeader *header;
        MonoInst *inst;
        guint32 locals_stack_size, locals_stack_align;
-       int i, offset, curinst, size, align;
+       int i, offset;
        gint32 *offsets;
        CallInfo *cinfo;
 
        header = mono_method_get_header (cfg->method);
        sig = mono_method_signature (cfg->method);
 
-       offset = 8;
-       curinst = 0;
-
        cinfo = get_call_info (sig, FALSE);
 
-       switch (cinfo->ret.storage) {
-       case ArgOnStack:
-               cfg->ret->opcode = OP_REGOFFSET;
-               cfg->ret->inst_basereg = X86_EBP;
-               cfg->ret->inst_offset = offset;
-               offset += sizeof (gpointer);
-               break;
-       case ArgValuetypeInReg:
-               break;
-       case ArgInIReg:
-               cfg->ret->opcode = OP_REGVAR;
-               cfg->ret->inst_c0 = cinfo->ret.reg;
-               break;
-       case ArgNone:
-       case ArgOnFloatFpStack:
-       case ArgOnDoubleFpStack:
-               break;
-       default:
-               g_assert_not_reached ();
-       }
-
-       if (sig->hasthis) {
-               inst = cfg->varinfo [curinst];
-               if (inst->opcode != OP_REGVAR) {
-                       inst->opcode = OP_REGOFFSET;
-                       inst->inst_basereg = X86_EBP;
-               }
-               inst->inst_offset = offset;
-               offset += sizeof (gpointer);
-               curinst++;
-       }
-
-       if (sig->call_convention == MONO_CALL_VARARG) {
-               cfg->sig_cookie = offset;
-               offset += sizeof (gpointer);
-       }
-
-       for (i = 0; i < sig->param_count; ++i) {
-               inst = cfg->varinfo [curinst];
-               if (inst->opcode != OP_REGVAR) {
-                       inst->opcode = OP_REGOFFSET;
-                       inst->inst_basereg = X86_EBP;
-               }
-               inst->inst_offset = offset;
-               size = mono_type_size (sig->params [i], &align);
-               size += 4 - 1;
-               size &= ~(4 - 1);
-               offset += size;
-               curinst++;
-       }
-
+       cfg->frame_reg = MONO_ARCH_BASEREG;
        offset = 0;
 
-       /* reserve space to save LMF and caller saved registers */
+       /* Reserve space to save LMF and caller saved registers */
 
        if (cfg->method->save_lmf) {
                offset += sizeof (MonoLMF);
@@ -843,14 +785,52 @@ mono_arch_allocate_vars (MonoCompile *cfg)
        g_free (offsets);
        offset += locals_stack_size;
 
-       offset += (MONO_ARCH_FRAME_ALIGNMENT - 1);
-       offset &= ~(MONO_ARCH_FRAME_ALIGNMENT - 1);
 
-       g_free (cinfo);
+       /*
+        * Allocate arguments+return value
+        */
 
-       cfg->frame_reg = MONO_ARCH_BASEREG;
+       switch (cinfo->ret.storage) {
+       case ArgOnStack:
+               cfg->ret->opcode = OP_REGOFFSET;
+               cfg->ret->inst_basereg = X86_EBP;
+               cfg->ret->inst_offset = cinfo->ret.offset + ARGS_OFFSET;
+               break;
+       case ArgValuetypeInReg:
+               break;
+       case ArgInIReg:
+               cfg->ret->opcode = OP_REGVAR;
+               cfg->ret->inst_c0 = cinfo->ret.reg;
+               break;
+       case ArgNone:
+       case ArgOnFloatFpStack:
+       case ArgOnDoubleFpStack:
+               break;
+       default:
+               g_assert_not_reached ();
+       }
+
+       if (sig->call_convention == MONO_CALL_VARARG) {
+               g_assert (cinfo->sig_cookie.storage == ArgOnStack);
+               cfg->sig_cookie = cinfo->sig_cookie.offset + ARGS_OFFSET;
+       }
+
+       for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
+               ArgInfo *ainfo = &cinfo->args [i];
+               inst = cfg->varinfo [i];
+               if (inst->opcode != OP_REGVAR) {
+                       inst->opcode = OP_REGOFFSET;
+                       inst->inst_basereg = X86_EBP;
+               }
+               inst->inst_offset = ainfo->offset + ARGS_OFFSET;
+       }
+
+       offset += (MONO_ARCH_FRAME_ALIGNMENT - 1);
+       offset &= ~(MONO_ARCH_FRAME_ALIGNMENT - 1);
 
        cfg->stack_offset = offset;
+
+       g_free (cinfo);
 }
 
 void
@@ -878,48 +858,68 @@ mono_arch_create_vars (MonoCompile *cfg)
  * instructions to properly call the function in call.
  * This includes pushing, moving arguments to the right register
  * etc.
- * Issue: who does the spilling if needed, and when?
  */
 MonoCallInst*
 mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call, int is_virtual) {
        MonoInst *arg, *in;
        MonoMethodSignature *sig;
-       int i, n, stack_size, type;
-       MonoType *ptype;
+       int i, n;
        CallInfo *cinfo;
+       int sentinelpos;
 
-       stack_size = 0;
-       /* add the vararg cookie before the non-implicit args */
-       if (call->signature->call_convention == MONO_CALL_VARARG) {
-               MonoInst *sig_arg;
-               /* FIXME: Add support for signature tokens to AOT */
-               cfg->disable_aot = TRUE;
-               MONO_INST_NEW (cfg, arg, OP_OUTARG);
-               MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
-               sig_arg->inst_p0 = call->signature;
-               arg->inst_left = sig_arg;
-               arg->type = STACK_PTR;
-               /* prepend, so they get reversed */
-               arg->next = call->out_args;
-               call->out_args = arg;
-               stack_size += sizeof (gpointer);
-       }
        sig = call->signature;
        n = sig->param_count + sig->hasthis;
 
        cinfo = get_call_info (sig, FALSE);
 
-       if (sig->ret && MONO_TYPE_ISSTRUCT (sig->ret)) {
-               if (cinfo->ret.storage == ArgOnStack)
-                       stack_size += sizeof (gpointer);
-       }
+       if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG))
+               sentinelpos = sig->sentinelpos + (is_virtual ? 1 : 0);
 
        for (i = 0; i < n; ++i) {
+               ArgInfo *ainfo = cinfo->args + i;
+
+               /* Emit the signature cookie just before the implicit arguments */
+               if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sentinelpos)) {
+                       MonoMethodSignature *tmp_sig;
+                       MonoInst *sig_arg;
+
+                       /* FIXME: Add support for signature tokens to AOT */
+                       cfg->disable_aot = TRUE;
+                       MONO_INST_NEW (cfg, arg, OP_OUTARG);
+
+                       /*
+                        * mono_ArgIterator_Setup assumes the signature cookie is 
+                        * passed first and all the arguments which were before it are
+                        * passed on the stack after the signature. So compensate by 
+                        * passing a different signature.
+                        */
+                       tmp_sig = mono_metadata_signature_dup (call->signature);
+                       tmp_sig->param_count -= call->signature->sentinelpos;
+                       tmp_sig->sentinelpos = 0;
+                       memcpy (tmp_sig->params, call->signature->params + call->signature->sentinelpos, tmp_sig->param_count * sizeof (MonoType*));
+
+                       MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
+                       sig_arg->inst_p0 = tmp_sig;
+
+                       arg->inst_left = sig_arg;
+                       arg->type = STACK_PTR;
+                       /* prepend, so they get reversed */
+                       arg->next = call->out_args;
+                       call->out_args = arg;
+               }
+
                if (is_virtual && i == 0) {
                        /* the argument will be attached to the call instrucion */
                        in = call->args [i];
-                       stack_size += 4;
                } else {
+                       MonoType *t;
+
+                       if (i >= sig->hasthis)
+                               t = sig->params [i - sig->hasthis];
+                       else
+                               t = &mono_defaults.int_class->byval_arg;
+                       t = mono_type_get_underlying_type (t);
+
                        MONO_INST_NEW (cfg, arg, OP_OUTARG);
                        in = call->args [i];
                        arg->cil_code = in->cil_code;
@@ -928,73 +928,40 @@ mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call,
                        /* prepend, so they get reversed */
                        arg->next = call->out_args;
                        call->out_args = arg;
-                       if (i >= sig->hasthis) {
-                               MonoType *t = sig->params [i - sig->hasthis];
-                               ptype = mono_type_get_underlying_type (t);
-                               if (t->byref)
-                                       type = MONO_TYPE_U;
-                               else
-                                       type = ptype->type;
-                               /* FIXME: validate arguments... */
-                               switch (type) {
-                               case MONO_TYPE_I:
-                               case MONO_TYPE_U:
-                               case MONO_TYPE_BOOLEAN:
-                               case MONO_TYPE_CHAR:
-                               case MONO_TYPE_I1:
-                               case MONO_TYPE_U1:
-                               case MONO_TYPE_I2:
-                               case MONO_TYPE_U2:
-                               case MONO_TYPE_I4:
-                               case MONO_TYPE_U4:
-                               case MONO_TYPE_STRING:
-                               case MONO_TYPE_CLASS:
-                               case MONO_TYPE_OBJECT:
-                               case MONO_TYPE_PTR:
-                               case MONO_TYPE_FNPTR:
-                               case MONO_TYPE_ARRAY:
-                               case MONO_TYPE_SZARRAY:
-                                       stack_size += 4;
-                                       break;
-                               case MONO_TYPE_I8:
-                               case MONO_TYPE_U8:
-                                       stack_size += 8;
-                                       break;
-                               case MONO_TYPE_R4:
-                                       stack_size += 4;
-                                       arg->opcode = OP_OUTARG_R4;
-                                       break;
-                               case MONO_TYPE_R8:
-                                       stack_size += 8;
-                                       arg->opcode = OP_OUTARG_R8;
-                                       break;
-                               case MONO_TYPE_VALUETYPE: {
-                                       int size;
-                                       if (sig->pinvoke) 
-                                               size = mono_type_native_stack_size (&in->klass->byval_arg, NULL);
-                                       else 
-                                               size = mono_type_stack_size (&in->klass->byval_arg, NULL);
 
-                                       stack_size += size;
-                                       arg->opcode = OP_OUTARG_VT;
-                                       arg->klass = in->klass;
-                                       arg->unused = sig->pinvoke;
-                                       arg->inst_imm = size; 
-                                       break;
+                       if ((i >= sig->hasthis) && (MONO_TYPE_ISSTRUCT(t))) {
+                               gint align;
+                               guint32 size;
+
+                               if (t->type == MONO_TYPE_TYPEDBYREF) {
+                                       size = sizeof (MonoTypedRef);
+                                       align = sizeof (gpointer);
                                }
-                               case MONO_TYPE_TYPEDBYREF:
-                                       stack_size += sizeof (MonoTypedRef);
-                                       arg->opcode = OP_OUTARG_VT;
-                                       arg->klass = in->klass;
-                                       arg->unused = sig->pinvoke;
-                                       arg->inst_imm = sizeof (MonoTypedRef); 
+                               else
+                                       if (sig->pinvoke)
+                                               size = mono_type_native_stack_size (&in->klass->byval_arg, &align);
+                                       else
+                                               size = mono_type_stack_size (&in->klass->byval_arg, &align);
+                               arg->opcode = OP_OUTARG_VT;
+                               arg->klass = in->klass;
+                               arg->unused = sig->pinvoke;
+                               arg->inst_imm = size; 
+                       }
+                       else {
+                               switch (ainfo->storage) {
+                               case ArgOnStack:
+                                       arg->opcode = OP_OUTARG;
+                                       if (!t->byref) {
+                                               if (t->type == MONO_TYPE_R4)
+                                                       arg->opcode = OP_OUTARG_R4;
+                                               else
+                                                       if (t->type == MONO_TYPE_R8)
+                                                               arg->opcode = OP_OUTARG_R8;
+                                       }
                                        break;
                                default:
-                                       g_error ("unknown type 0x%02x in mono_arch_call_opcode\n", type);
+                                       g_assert_not_reached ();
                                }
-                       } else {
-                               /* the this argument */
-                               stack_size += 4;
                        }
                }
        }
@@ -1021,17 +988,12 @@ mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call,
                else
                        /* if the function returns a struct, the called method already does a ret $0x4 */
                        if (sig->ret && MONO_TYPE_ISSTRUCT (sig->ret))
-                               stack_size -= 4;
+                               cinfo->stack_usage -= 4;
        }
 
-       call->stack_usage = stack_size;
+       call->stack_usage = cinfo->stack_usage;
        g_free (cinfo);
 
-       /* 
-        * should set more info in call, such as the stack space
-        * used by the args that needs to be added back to esp
-        */
-
        return call;
 }
 
@@ -1194,12 +1156,20 @@ if (ins->flags & MONO_INST_BRLABEL) { \
         } \
 }
 
-/* emit an exception if condition is fail */
+/*  
+ *     Emit an exception if condition is fail and
+ *  if possible do a directly branch to target 
+ */
 #define EMIT_COND_SYSTEM_EXCEPTION(cond,signed,exc_name)            \
-        do {                                                        \
-               mono_add_patch_info (cfg, code - cfg->native_code,   \
-                                   MONO_PATCH_INFO_EXC, exc_name);  \
-               x86_branch32 (code, cond, 0, signed);               \
+       do {                                                        \
+               MonoInst *tins = mono_branch_optimize_exception_target (cfg, bb, exc_name); \
+               if (tins == NULL) {                                                                             \
+                       mono_add_patch_info (cfg, code - cfg->native_code,   \
+                                       MONO_PATCH_INFO_EXC, exc_name);  \
+                       x86_branch32 (code, cond, 0, signed);               \
+               } else {        \
+                       EMIT_COND_BRANCH (tins, cond, signed);  \
+               }                       \
        } while (0); 
 
 #define EMIT_FPCOMPARE(code) do { \
@@ -2060,7 +2030,62 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        x86_imul_reg_reg (code, ins->sreg1, ins->sreg2);
                        break;
                case OP_MUL_IMM:
-                       x86_imul_reg_reg_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
+                       switch (ins->inst_imm) {
+                       case 2:
+                               /* MOV r1, r2 */
+                               /* ADD r1, r1 */
+                               if (ins->dreg != ins->sreg1)
+                                       x86_mov_reg_reg (code, ins->dreg, ins->sreg1, 4);
+                               x86_alu_reg_reg (code, X86_ADD, ins->dreg, ins->dreg);
+                               break;
+                       case 3:
+                               /* LEA r1, [r2 + r2*2] */
+                               x86_lea_memindex (code, ins->dreg, ins->sreg1, 0, ins->sreg1, 1);
+                               break;
+                       case 5:
+                               /* LEA r1, [r2 + r2*4] */
+                               x86_lea_memindex (code, ins->dreg, ins->sreg1, 0, ins->sreg1, 2);
+                               break;
+                       case 6:
+                               /* LEA r1, [r2 + r2*2] */
+                               /* ADD r1, r1          */
+                               x86_lea_memindex (code, ins->dreg, ins->sreg1, 0, ins->sreg1, 1);
+                               x86_alu_reg_reg (code, X86_ADD, ins->dreg, ins->dreg);
+                               break;
+                       case 9:
+                               /* LEA r1, [r2 + r2*8] */
+                               x86_lea_memindex (code, ins->dreg, ins->sreg1, 0, ins->sreg1, 3);
+                               break;
+                       case 10:
+                               /* LEA r1, [r2 + r2*4] */
+                               /* ADD r1, r1          */
+                               x86_lea_memindex (code, ins->dreg, ins->sreg1, 0, ins->sreg1, 2);
+                               x86_alu_reg_reg (code, X86_ADD, ins->dreg, ins->dreg);
+                               break;
+                       case 12:
+                               /* LEA r1, [r2 + r2*2] */
+                               /* SHL r1, 2           */
+                               x86_lea_memindex (code, ins->dreg, ins->sreg1, 0, ins->sreg1, 1);
+                               x86_shift_reg_imm (code, X86_SHL, ins->dreg, 2);
+                               break;
+                       case 25:
+                               /* LEA r1, [r2 + r2*4] */
+                               /* LEA r1, [r1 + r1*4] */
+                               x86_lea_memindex (code, ins->dreg, ins->sreg1, 0, ins->sreg1, 2);
+                               x86_lea_memindex (code, ins->dreg, ins->dreg, 0, ins->dreg, 2);
+                               break;
+                       case 100:
+                               /* LEA r1, [r2 + r2*4] */
+                               /* SHL r1, 2           */
+                               /* LEA r1, [r1 + r1*4] */
+                               x86_lea_memindex (code, ins->dreg, ins->sreg1, 0, ins->sreg1, 2);
+                               x86_shift_reg_imm (code, X86_SHL, ins->dreg, 2);
+                               x86_lea_memindex (code, ins->dreg, ins->dreg, 0, ins->dreg, 2);
+                               break;
+                       default:
+                               x86_imul_reg_reg_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
+                               break;
+                       }
                        break;
                case CEE_MUL_OVF:
                        x86_imul_reg_reg (code, ins->sreg1, ins->sreg2);
@@ -2388,8 +2413,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                case OP_COND_EXC_NO:
                case OP_COND_EXC_C:
                case OP_COND_EXC_NC:
-                       EMIT_COND_SYSTEM_EXCEPTION (branch_cc_table [ins->opcode - OP_COND_EXC_EQ], 
-                                                   (ins->opcode < OP_COND_EXC_NE_UN), ins->inst_p1);
+                       EMIT_COND_SYSTEM_EXCEPTION (branch_cc_table [ins->opcode - OP_COND_EXC_EQ], (ins->opcode < OP_COND_EXC_NE_UN), ins->inst_p1);
                        break;
                case CEE_BEQ:
                case CEE_BNE_UN:
@@ -2537,6 +2561,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                }
                case OP_LCONV_TO_OVF_I: {
                        guint8 *br [3], *label [1];
+                       MonoInst *tins;
 
                        /* 
                         * Valid ints: 0xffffffff:8000000 to 00000000:0x7f000000
@@ -2551,8 +2576,18 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        label [0] = code;
 
                        /* throw exception */
-                       mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC, "OverflowException");
-                       x86_jump32 (code, 0);
+                       tins = mono_branch_optimize_exception_target (cfg, bb, "OverflowException");
+                       if (tins) {
+                               mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, tins->inst_true_bb);
+                               if ((cfg->opt & MONO_OPT_BRANCH) && x86_is_imm8 (tins->inst_true_bb->max_offset - cpos))
+                                       x86_jump8 (code, 0);
+                               else
+                                       x86_jump32 (code, 0);
+                       } else {
+                               mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC, "OverflowException");
+                               x86_jump32 (code, 0);
+                       }
+       
        
                        x86_patch (br [0], code);
                        /* our top bit is set, check that top word is 0xfffffff */
@@ -2928,6 +2963,10 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        code = emit_tls_get (code, ins->dreg, ins->inst_offset);
                        break;
                }
+               case OP_MEMORY_BARRIER: {
+                       /* Not needed on x86 */
+                       break;
+               }
                case OP_ATOMIC_ADD_I4: {
                        int dreg = ins->dreg;
 
@@ -3327,6 +3366,7 @@ mono_arch_emit_epilog (MonoCompile *cfg)
        
        if (method->save_lmf) {
                gint32 prev_lmf_reg;
+               gint32 lmf_offset = -sizeof (MonoLMF);
 
                /* Find a spare register */
                switch (sig->ret->type) {
@@ -3341,24 +3381,24 @@ mono_arch_emit_epilog (MonoCompile *cfg)
                }
 
                /* reg = previous_lmf */
-               x86_mov_reg_membase (code, prev_lmf_reg, X86_EBP, -32, 4);
+               x86_mov_reg_membase (code, prev_lmf_reg, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, previous_lmf), 4);
 
                /* ecx = lmf */
-               x86_mov_reg_membase (code, X86_ECX, X86_EBP, -28, 4);
+               x86_mov_reg_membase (code, X86_ECX, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, lmf_addr), 4);
 
                /* *(lmf) = previous_lmf */
                x86_mov_membase_reg (code, X86_ECX, 0, prev_lmf_reg, 4);
 
                /* restore caller saved regs */
                if (cfg->used_int_regs & (1 << X86_EBX)) {
-                       x86_mov_reg_membase (code, X86_EBX, X86_EBP, -20, 4);
+                       x86_mov_reg_membase (code, X86_EBX, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, ebx), 4);
                }
 
                if (cfg->used_int_regs & (1 << X86_EDI)) {
-                       x86_mov_reg_membase (code, X86_EDI, X86_EBP, -16, 4);
+                       x86_mov_reg_membase (code, X86_EDI, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, edi), 4);
                }
                if (cfg->used_int_regs & (1 << X86_ESI)) {
-                       x86_mov_reg_membase (code, X86_ESI, X86_EBP, -12, 4);
+                       x86_mov_reg_membase (code, X86_ESI, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, esi), 4);
                }
 
                /* EBP is restored by LEAVE */
@@ -3579,66 +3619,6 @@ mono_arch_flush_register_windows (void)
 {
 }
 
-#ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
-
-static void
-setup_stack (MonoJitTlsData *tls)
-{
-       pthread_t self = pthread_self();
-       pthread_attr_t attr;
-       size_t stsize = 0;
-       struct sigaltstack sa;
-       guint8 *staddr = NULL;
-       guint8 *current = (guint8*)&staddr;
-
-       if (mono_running_on_valgrind ())
-               return;
-
-       /* Determine stack boundaries */
-       pthread_attr_init( &attr );
-#ifdef HAVE_PTHREAD_GETATTR_NP
-       pthread_getattr_np( self, &attr );
-#else
-#ifdef HAVE_PTHREAD_ATTR_GET_NP
-       pthread_attr_get_np( self, &attr );
-#elif defined(sun)
-       pthread_attr_getstacksize( &attr, &stsize );
-#else
-#error "Not implemented"
-#endif
-#endif
-#ifndef sun
-       pthread_attr_getstack( &attr, (void**)&staddr, &stsize );
-#endif
-
-       g_assert (staddr);
-
-       g_assert ((current > staddr) && (current < staddr + stsize));
-
-       tls->end_of_stack = staddr + stsize;
-
-       /*
-        * threads created by nptl does not seem to have a guard page, and
-        * since the main thread is not created by us, we can't even set one.
-        * Increasing stsize fools the SIGSEGV signal handler into thinking this
-        * is a stack overflow exception.
-        */
-       tls->stack_size = stsize + getpagesize ();
-
-       /* Setup an alternate signal stack */
-       tls->signal_stack = mmap (0, SIGNAL_STACK_SIZE, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
-       tls->signal_stack_size = SIGNAL_STACK_SIZE;
-
-       g_assert (tls->signal_stack);
-
-       sa.ss_sp = tls->signal_stack;
-       sa.ss_size = SIGNAL_STACK_SIZE;
-       sa.ss_flags = SS_ONSTACK;
-       sigaltstack (&sa, NULL);
-}
-
-#endif
-
 /*
  * Support for fast access to the thread-local lmf structure using the GS
  * segment register on NPTL + kernel 2.6.x.
@@ -3675,43 +3655,41 @@ mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
 #endif
                }
        }               
-
-#ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
-       setup_stack (tls);
-#endif
 }
 
 void
 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
 {
-#ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
-       struct sigaltstack sa;
-
-       sa.ss_sp = tls->signal_stack;
-       sa.ss_size = SIGNAL_STACK_SIZE;
-       sa.ss_flags = SS_DISABLE;
-       sigaltstack  (&sa, NULL);
-
-       if (tls->signal_stack)
-               munmap (tls->signal_stack, SIGNAL_STACK_SIZE);
-#endif
 }
 
 void
 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
 {
+       MonoCallInst *call = (MonoCallInst*)inst;
+       CallInfo *cinfo = get_call_info (inst->signature, FALSE);
 
        /* add the this argument */
        if (this_reg != -1) {
-               MonoInst *this;
-               MONO_INST_NEW (cfg, this, OP_OUTARG);
-               this->type = this_type;
-               this->sreg1 = this_reg;
-               mono_bblock_add_inst (cfg->cbb, this);
+               if (cinfo->args [0].storage == ArgInIReg) {
+                       MonoInst *this;
+                       MONO_INST_NEW (cfg, this, OP_MOVE);
+                       this->type = this_type;
+                       this->sreg1 = this_reg;
+                       this->dreg = mono_regstate_next_int (cfg->rs);
+                       mono_bblock_add_inst (cfg->cbb, this);
+
+                       mono_call_inst_add_outarg_reg (call, this->dreg, cinfo->args [0].reg, FALSE);
+               }
+               else {
+                       MonoInst *this;
+                       MONO_INST_NEW (cfg, this, OP_OUTARG);
+                       this->type = this_type;
+                       this->sreg1 = this_reg;
+                       mono_bblock_add_inst (cfg->cbb, this);
+               }
        }
 
        if (vt_reg != -1) {
-               CallInfo * cinfo = get_call_info (inst->signature, FALSE);
                MonoInst *vtarg;
 
                if (cinfo->ret.storage == ArgValuetypeInReg) {
@@ -3726,18 +3704,25 @@ mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_re
                        vtarg->sreg1 = vt_reg;
                        mono_bblock_add_inst (cfg->cbb, vtarg);
                }
-               else {
+               else if (cinfo->ret.storage == ArgInIReg) {
+                       /* The return address is passed in a register */
+                       MONO_INST_NEW (cfg, vtarg, OP_MOVE);
+                       vtarg->sreg1 = vt_reg;
+                       vtarg->dreg = mono_regstate_next_int (cfg->rs);
+                       mono_bblock_add_inst (cfg->cbb, vtarg);
+
+                       mono_call_inst_add_outarg_reg (call, vtarg->dreg, cinfo->ret.reg, FALSE);
+               } else {
                        MonoInst *vtarg;
                        MONO_INST_NEW (cfg, vtarg, OP_OUTARG);
                        vtarg->type = STACK_MP;
                        vtarg->sreg1 = vt_reg;
                        mono_bblock_add_inst (cfg->cbb, vtarg);
                }
-
-               g_free (cinfo);
        }
-}
 
+       g_free (cinfo);
+}
 
 MonoInst*
 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
@@ -3772,6 +3757,9 @@ mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethod
                        ins->inst_i1 = args [1];
                }
 #endif
+       } else if (cmethod->klass == mono_defaults.thread_class &&
+                          strcmp (cmethod->name, "MemoryBarrier") == 0) {
+               MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
        } else if(cmethod->klass->image == mono_defaults.corlib &&
                           (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
                           (strcmp (cmethod->klass->name, "Interlocked") == 0)) {