#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>
#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))
#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*
if (*gr >= FLOAT_PARAM_REGS) {
ainfo->storage = ArgOnStack;
- (*stack_size) += sizeof (gpointer);
+ (*stack_size) += is_double ? 8 : 4;
}
else {
/* A double register */
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);
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
* 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;
/* 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;
}
}
}
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;
}
} \
}
-/* 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 { \
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);
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:
}
case OP_LCONV_TO_OVF_I: {
guint8 *br [3], *label [1];
+ MonoInst *tins;
/*
* Valid ints: 0xffffffff:8000000 to 00000000:0x7f000000
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 */
if (method->save_lmf) {
gint32 prev_lmf_reg;
+ gint32 lmf_offset = -sizeof (MonoLMF);
/* Find a spare register */
switch (sig->ret->type) {
}
/* 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 */
{
}
-#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.
#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) {
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)
}
#endif
} else if (cmethod->klass == mono_defaults.thread_class &&
- strcmp (cmethod->name, "MemoryBarrier")) {
+ 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) &&