#define SAVE_FP_REGS 0
#define SAVE_ALL_REGS 0
#define EXTRA_STACK_SPACE 0 /* suppresses some s-reg corruption issues */
-#define LONG_BRANCH 1 /* needed for yyparse in mcs */
#define SAVE_LMF 1
#define ALWAYS_USE_FP 1
#define PROMOTE_R4_TO_R8 1 /* promote single values in registers to doubles */
#define USE_MUL 1 /* use mul instead of mult/mflo for multiply */
+/* Emit a call sequence to 'v', using 'D' as a scratch register if necessary */
+#define mips_call(c,D,v) do { \
+ guint32 _target = (guint32)(v); \
+ if (1 || !(v) || ((_target & 0xfc000000) != (((guint32)(c)) & 0xfc000000))) { \
+ mips_load_const (c, D, _target); \
+ mips_jalr (c, D, mips_ra); \
+ } \
+ else { \
+ mips_jumpl (c, _target >> 2); \
+ } \
+ mips_nop (c); \
+ } while (0)
+
enum {
TLS_MODE_DETECT,
TLS_MODE_FAILED,
mips_load_const (code, mips_a0, exc_class->type_token);
addr = (guint32) mono_get_throw_corlib_exception ();
- mips_load_const (code, mips_t9, addr);
- mips_jalr (code, mips_t9, mips_ra);
- mips_nop (code);
-
+ mips_call (code, mips_t9, addr);
return code;
}
guint8 *
mips_emit_cond_branch (MonoCompile *cfg, guint8 *code, int op, MonoInst *ins)
{
-#if LONG_BRANCH
- int br_offset = 5;
-#endif
-
g_assert (ins);
-#if LONG_BRANCH
- /* Invert test and emit branch around jump */
- switch (op) {
- case OP_MIPS_BEQ:
- mips_bne (code, ins->sreg1, ins->sreg2, br_offset);
- mips_nop (code);
- break;
- case OP_MIPS_BNE:
- mips_beq (code, ins->sreg1, ins->sreg2, br_offset);
- mips_nop (code);
- break;
- case OP_MIPS_BGEZ:
- mips_bltz (code, ins->sreg1, br_offset);
- mips_nop (code);
- break;
- case OP_MIPS_BGTZ:
- mips_blez (code, ins->sreg1, br_offset);
- mips_nop (code);
- break;
- case OP_MIPS_BLEZ:
- mips_bgtz (code, ins->sreg1, br_offset);
- mips_nop (code);
- break;
- case OP_MIPS_BLTZ:
- mips_bgez (code, ins->sreg1, br_offset);
+ if (cfg->arch.long_branch) {
+ int br_offset = 5;
+
+ /* Invert test and emit branch around jump */
+ switch (op) {
+ case OP_MIPS_BEQ:
+ mips_bne (code, ins->sreg1, ins->sreg2, br_offset);
+ mips_nop (code);
+ break;
+ case OP_MIPS_BNE:
+ mips_beq (code, ins->sreg1, ins->sreg2, br_offset);
+ mips_nop (code);
+ break;
+ case OP_MIPS_BGEZ:
+ mips_bltz (code, ins->sreg1, br_offset);
+ mips_nop (code);
+ break;
+ case OP_MIPS_BGTZ:
+ mips_blez (code, ins->sreg1, br_offset);
+ mips_nop (code);
+ break;
+ case OP_MIPS_BLEZ:
+ mips_bgtz (code, ins->sreg1, br_offset);
+ mips_nop (code);
+ break;
+ case OP_MIPS_BLTZ:
+ mips_bgez (code, ins->sreg1, br_offset);
+ mips_nop (code);
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+ mono_add_patch_info (cfg, code - cfg->native_code,
+ MONO_PATCH_INFO_BB, ins->inst_true_bb);
+ mips_lui (code, mips_at, mips_zero, 0);
+ mips_addiu (code, mips_at, mips_at, 0);
+ mips_jr (code, mips_at);
mips_nop (code);
- break;
- default:
- g_assert_not_reached ();
}
- mono_add_patch_info (cfg, code - cfg->native_code,
- MONO_PATCH_INFO_BB, ins->inst_true_bb);
- mips_lui (code, mips_at, mips_zero, 0);
- mips_addiu (code, mips_at, mips_at, 0);
- mips_jr (code, mips_at);
- mips_nop (code);
-#else
- mono_add_patch_info (cfg, code - cfg->native_code,
- MONO_PATCH_INFO_BB, ins->inst_true_bb);
- switch (op) {
- case OP_MIPS_BEQ:
- mips_beq (code, ins->sreg1, ins->sreg2, 0);
- mips_nop (code);
- break;
- case OP_MIPS_BNE:
- mips_bne (code, ins->sreg1, ins->sreg2, 0);
- mips_nop (code);
- break;
- case OP_MIPS_BGEZ:
- mips_bgez (code, ins->sreg1, 0);
- mips_nop (code);
- break;
- case OP_MIPS_BGTZ:
- mips_bgtz (code, ins->sreg1, 0);
- mips_nop (code);
- break;
- case OP_MIPS_BLEZ:
- mips_blez (code, ins->sreg1, 0);
- mips_nop (code);
- break;
- case OP_MIPS_BLTZ:
- mips_bltz (code, ins->sreg1, 0);
- mips_nop (code);
- break;
- default:
- g_assert_not_reached ();
+ else {
+ mono_add_patch_info (cfg, code - cfg->native_code,
+ MONO_PATCH_INFO_BB, ins->inst_true_bb);
+ switch (op) {
+ case OP_MIPS_BEQ:
+ mips_beq (code, ins->sreg1, ins->sreg2, 0);
+ mips_nop (code);
+ break;
+ case OP_MIPS_BNE:
+ mips_bne (code, ins->sreg1, ins->sreg2, 0);
+ mips_nop (code);
+ break;
+ case OP_MIPS_BGEZ:
+ mips_bgez (code, ins->sreg1, 0);
+ mips_nop (code);
+ break;
+ case OP_MIPS_BGTZ:
+ mips_bgtz (code, ins->sreg1, 0);
+ mips_nop (code);
+ break;
+ case OP_MIPS_BLEZ:
+ mips_blez (code, ins->sreg1, 0);
+ mips_nop (code);
+ break;
+ case OP_MIPS_BLTZ:
+ mips_bltz (code, ins->sreg1, 0);
+ mips_nop (code);
+ break;
+ default:
+ g_assert_not_reached ();
+ }
}
-#endif
return (code);
}
gpointer
-mono_arch_get_this_arg_from_call (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, mgreg_t *regs, guint8 *code)
+mono_arch_get_this_arg_from_call (mgreg_t *regs, guint8 *code)
{
- /* FIXME: handle returning a struct */
g_assert(regs);
- if (sig && MONO_TYPE_ISSTRUCT (sig->ret))
- return (gpointer)regs [mips_a1];
return (gpointer)regs [mips_a0];
}
case OP_LOAD_MEMBASE:
case OP_LOADI4_MEMBASE:
case OP_LOADU4_MEMBASE:
+ g_assert (ins->dreg != -1);
if (mips_is_imm16 (ins->inst_offset)) {
mips_lw (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
} else {
case OP_IDIV:
case OP_IREM: {
guint32 *divisor_is_m1;
+ guint32 *dividend_is_minvalue;
guint32 *divisor_is_zero;
- /* */
- mips_addiu (code, mips_at, mips_zero, 0xffff);
+ mips_load_const (code, mips_at, -1);
divisor_is_m1 = (guint32 *)(void *)code;
mips_bne (code, ins->sreg2, mips_at, 0);
+ mips_lui (code, mips_at, mips_zero, 0x8000);
+ dividend_is_minvalue = (guint32 *)(void *)code;
+ mips_bne (code, ins->sreg1, mips_at, 0);
mips_nop (code);
- /* Divide by -1 -- throw exception */
- EMIT_SYSTEM_EXCEPTION_NAME("ArithmeticException");
+ /* Divide Int32.MinValue by -1 -- throw exception */
+ EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
mips_patch (divisor_is_m1, (guint32)code);
+ mips_patch (dividend_is_minvalue, (guint32)code);
/* Put divide in branch delay slot (NOT YET) */
divisor_is_zero = (guint32 *)(void *)code;
mono_add_patch_info (cfg, (guint8*) code - cfg->native_code,
MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
-#if LONG_BRANCH
- mips_lui (code, mips_t9, mips_zero, 0);
- mips_addiu (code, mips_t9, mips_t9, 0);
- mips_jr (code, mips_t9);
- mips_nop (code);
-#else
- mips_beq (code, mips_zero, mips_zero, 0);
- mips_nop (code);
-#endif
+ if (cfg->arch.long_branch) {
+ mips_lui (code, mips_t9, mips_zero, 0);
+ mips_addiu (code, mips_t9, mips_t9, 0);
+ mips_jr (code, mips_t9);
+ mips_nop (code);
+ }
+ else {
+ mips_beq (code, mips_zero, mips_zero, 0);
+ mips_nop (code);
+ }
break;
case OP_CHECK_THIS:
/* ensure ins->sreg1 is not NULL */
case OP_VCALL2:
case OP_VOIDCALL:
case OP_CALL:
- if (ins->flags & MONO_INST_HAS_METHOD)
+ if (ins->flags & MONO_INST_HAS_METHOD) {
mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
- else
+ mips_call (code, mips_t9, call->method);
+ }
+ else {
mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
- mips_lui (code, mips_t9, mips_zero, 0);
- mips_addiu (code, mips_t9, mips_t9, 0);
+ mips_call (code, mips_t9, call->fptr);
+ }
break;
case OP_FCALL_REG:
case OP_LCALL_REG:
case OP_VOIDCALL_REG:
case OP_CALL_REG:
MIPS_MOVE (code, mips_t9, ins->sreg1);
+ mips_jalr (code, mips_t9, mips_ra);
+ mips_nop (code);
break;
case OP_FCALL_MEMBASE:
case OP_LCALL_MEMBASE:
case OP_VOIDCALL_MEMBASE:
case OP_CALL_MEMBASE:
mips_lw (code, mips_t9, ins->sreg1, ins->inst_offset);
+ mips_jalr (code, mips_t9, mips_ra);
+ mips_nop (code);
break;
}
- mips_jalr (code, mips_t9, mips_ra);
- mips_nop (code);
#if PROMOTE_R4_TO_R8
/* returned an FP R4 (single), promote to R8 (double) in place */
if ((ins->opcode == OP_FCALL ||
case OP_THROW: {
gpointer addr = mono_arch_get_throw_exception(NULL, FALSE);
mips_move (code, mips_a0, ins->sreg1);
- mips_load_const (code, mips_t9, addr);
- mips_jalr (code, mips_t9, mips_ra);
- mips_nop (code);
+ mips_call (code, mips_t9, addr);
mips_break (code, 0xfc);
break;
}
case OP_RETHROW: {
gpointer addr = mono_arch_get_rethrow_exception(NULL, FALSE);
mips_move (code, mips_a0, ins->sreg1);
- mips_load_const (code, mips_t9, addr);
- mips_jalr (code, mips_t9, mips_ra);
- mips_nop (code);
+ mips_call (code, mips_t9, addr);
mips_break (code, 0xfb);
break;
}
break;
case OP_BR:
mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
-#if LONG_BRANCH
- mips_lui (code, mips_at, mips_zero, 0);
- mips_addiu (code, mips_at, mips_at, 0);
- mips_jr (code, mips_at);
- mips_nop (code);
-#else
- mips_beq (code, mips_zero, mips_zero, 0);
- mips_nop (code);
-#endif
+ if (cfg->arch.long_branch) {
+ mips_lui (code, mips_at, mips_zero, 0);
+ mips_addiu (code, mips_at, mips_at, 0);
+ mips_jr (code, mips_at);
+ mips_nop (code);
+ }
+ else {
+ mips_beq (code, mips_zero, mips_zero, 0);
+ mips_nop (code);
+ }
break;
case OP_BR_REG:
mips_jr (code, ins->sreg1);
break;
case OP_MIPS_COND_EXC_LE_UN:
- mips_subu (code, mips_at, ins->sreg1, ins->sreg2);
+ mips_sltu (code, mips_at, ins->sreg2, ins->sreg1);
throw = (guint32 *)(void *)code;
- mips_blez (code, mips_at, 0);
+ mips_beq (code, mips_at, mips_zero, 0);
mips_nop (code);
break;
#endif
break;
case OP_LOADR4_MEMINDEX:
- mips_addiu (code, mips_at, ins->inst_basereg, ins->sreg2);
+ mips_addu (code, mips_at, ins->inst_basereg, ins->sreg2);
mips_lwc1 (code, ins->dreg, mips_at, 0);
break;
case OP_LOADR8_MEMINDEX:
- mips_addiu (code, mips_at, ins->inst_basereg, ins->sreg2);
+ mips_addu (code, mips_at, ins->inst_basereg, ins->sreg2);
#if _MIPS_SIM == _ABIO32
mips_lwc1 (code, ins->dreg, mips_at, 0);
mips_lwc1 (code, ins->dreg+1, mips_at, 4);
#endif
break;
case OP_STORER4_MEMINDEX:
- mips_addiu (code, mips_at, ins->inst_basereg, ins->sreg2);
+ mips_addu (code, mips_at, ins->inst_destbasereg, ins->sreg2);
#if PROMOTE_R4_TO_R8
/* Need to convert ins->sreg1 to single-precision first */
mips_cvtsd (code, mips_ftemp, ins->sreg1);
#endif
break;
case OP_STORER8_MEMINDEX:
- mips_addiu (code, mips_at, ins->inst_basereg, ins->sreg2);
+ mips_addu (code, mips_at, ins->inst_destbasereg, ins->sreg2);
#if _MIPS_SIM == _ABIO32
mips_swc1 (code, ins->sreg1, mips_at, 0);
mips_swc1 (code, ins->sreg1+1, mips_at, 4);
}
void
-mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
+mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, MonoCodeManager *dyn_code_mp, gboolean run_cctors)
{
MonoJumpInfo *patch_info;
mips_load_const (code, mips_a0, cfg->method);
mips_addiu (code, mips_a1, mips_sp, offset);
- mips_load_const (code, mips_t9, func);
- mips_jalr (code, mips_t9, mips_ra);
- mips_nop (code);
+ mips_call (code, mips_t9, func);
MIPS_LW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
MIPS_LW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
MonoMethodSignature *sig;
MonoInst *inst;
int alloc_size, pos, i;
+ int alloc2_size = 0;
guint8 *code;
CallInfo *cinfo;
int tracing = 0;
fregs_to_save |= (fregs_to_save << 1);
#endif
#endif
+ /* If the stack size is too big, save 1024 bytes to start with
+ * so the prologue can use imm16(reg) addressing, then allocate
+ * the rest of the frame.
+ */
+ if (alloc_size > ((1 << 15) - 1024)) {
+ alloc2_size = alloc_size - 1024;
+ alloc_size = 1024;
+ }
if (alloc_size) {
- if (mips_is_imm16 (-alloc_size)) {
- mips_addiu (code, mips_sp, mips_sp, -alloc_size);
- } else {
- mips_load_const (code, mips_at, -alloc_size);
- mips_addu (code, mips_sp, mips_sp, mips_at);
- }
+ g_assert (mips_is_imm16 (-alloc_size));
+ mips_addiu (code, mips_sp, mips_sp, -alloc_size);
}
- if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA)
- mips_sw (code, mips_ra, mips_sp, alloc_size + MIPS_RET_ADDR_OFFSET);
+ if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
+ int offset = alloc_size + MIPS_RET_ADDR_OFFSET;
+ if (mips_is_imm16(offset))
+ mips_sw (code, mips_ra, mips_sp, offset);
+ else {
+ g_assert_not_reached ();
+ }
+ }
/* XXX - optimize this later to not save all regs if LMF constructed */
+ pos = cfg->arch.iregs_offset - alloc2_size;
if (iregs_to_save) {
/* save used registers in own stack frame (at pos) */
- pos = cfg->arch.iregs_offset;
for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
if (iregs_to_save & (1 << i)) {
g_assert (pos < cfg->stack_usage - sizeof(gpointer));
+ g_assert (mips_is_imm16(pos));
MIPS_SW (code, i, mips_sp, pos);
pos += SIZEOF_REGISTER;
}
#if SAVE_LMF
if (method->save_lmf) {
for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
- MIPS_SW (code, i, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[i]));
+ int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[i]);
+ g_assert (mips_is_imm16(offset));
+ MIPS_SW (code, i, mips_sp, offset);
}
}
#endif
for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
if (fregs_to_save & (1 << i)) {
g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
+ g_assert (mips_is_imm16(pos));
mips_swc1 (code, i, mips_sp, pos);
pos += sizeof (gulong);
}
#if SAVE_LMF
if (method->save_lmf) {
for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
- mips_swc1 (code, i, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, fregs[i]));
+ int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, fregs[i]);
+ g_assert (mips_is_imm16(offset));
+ mips_swc1 (code, i, mips_sp, offset);
}
}
#endif
if (cfg->frame_reg != mips_sp) {
MIPS_MOVE (code, cfg->frame_reg, mips_sp);
#if SAVE_LMF
- if (method->save_lmf)
- MIPS_SW (code, cfg->frame_reg, mips_sp,
- lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[cfg->frame_reg]));
+ if (method->save_lmf) {
+ int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[cfg->frame_reg]);
+ g_assert (mips_is_imm16(offset));
+ MIPS_SW (code, cfg->frame_reg, mips_sp, offset);
+ }
#endif
}
#endif
}
else if (ainfo->regtype == RegTypeBase) {
- mips_lw (code, inst->dreg, mips_sp, cfg->stack_usage + ainfo->offset);
+ int offset = cfg->stack_usage + ainfo->offset;
+ g_assert (mips_is_imm16(offset));
+ mips_lw (code, inst->dreg, mips_sp, offset);
} else
g_assert_not_reached ();
}
} else if (ainfo->regtype == RegTypeFP) {
g_assert (mips_is_imm16 (inst->inst_offset));
+ g_assert (mips_is_imm16 (inst->inst_offset+4));
if (ainfo->size == 8) {
#if _MIPS_SIM == _ABIO32
mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset+4);
g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
/* Push the argument registers into their stack slots */
for (i = 0; i < ainfo->size; ++i) {
+ g_assert (mips_is_imm16(doffset));
MIPS_SW (code, ainfo->reg + i, inst->inst_basereg, doffset);
doffset += SIZEOF_REGISTER;
}
if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
mips_load_const (code, mips_a0, cfg->domain);
- mips_load_const (code, mips_t9, (gpointer)mono_jit_thread_attach);
- mips_jalr (code, mips_t9, mips_ra);
- mips_nop (code);
+ mips_call (code, mips_t9, (gpointer)mono_jit_thread_attach);
}
#if SAVE_LMF
#if 0
emit_tls_access (code, mips_temp, lmf_pthread_key);
#endif
- if (G_STRUCT_OFFSET (MonoJitTlsData, lmf))
- mips_addiu (code, mips_a0, mips_temp, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
+ if (G_STRUCT_OFFSET (MonoJitTlsData, lmf)) {
+ int offset = G_STRUCT_OFFSET (MonoJitTlsData, lmf);
+ g_assert (mips_is_imm16(offset));
+ mips_addiu (code, mips_a0, mips_temp, offset);
+ }
} else {
-#if 0
- mips_addiu (code, mips_a0, mips_sp, lmf_offset);
- mips_load_const (code, mips_t9, (gpointer)mono_trace_lmf_prolog);
- mips_jalr (code, mips_t9, mips_ra);
- mips_nop (code);
-#endif
/* This can/will clobber the a0-a3 registers */
- mips_load_const (code, mips_t9, (gpointer)mono_get_lmf_addr);
- mips_jalr (code, mips_t9, mips_ra);
- mips_nop (code);
+ mips_call (code, mips_t9, (gpointer)mono_get_lmf_addr);
}
/* mips_v0 is the result from mono_get_lmf_addr () (MonoLMF **) */
+ g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
mips_sw (code, mips_v0, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
/* new_lmf->previous_lmf = *lmf_addr */
mips_lw (code, mips_at, mips_v0, 0);
+ g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
/* *(lmf_addr) = sp + lmf_offset */
+ g_assert (mips_is_imm16(lmf_offset));
mips_addiu (code, mips_at, mips_sp, lmf_offset);
mips_sw (code, mips_at, mips_v0, 0);
/* save method info */
mips_load_const (code, mips_at, method);
+ g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, method)));
mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, method));
+ g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, ebp)));
MIPS_SW (code, mips_sp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, ebp));
/* save the current IP */
mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, eip));
}
#endif
+ if (alloc2_size) {
+ if (mips_is_imm16 (-alloc2_size)) {
+ mips_addu (code, mips_sp, mips_sp, -alloc2_size);
+ }
+ else {
+ mips_load_const (code, mips_at, -alloc2_size);
+ mips_addu (code, mips_sp, mips_sp, mips_at);
+ }
+ if (cfg->frame_reg != mips_sp)
+ MIPS_MOVE (code, cfg->frame_reg, mips_sp);
+ alloc_size += alloc2_size;
+ }
cfg->code_len = code - cfg->native_code;
g_assert (cfg->code_len < cfg->code_size);
}
mips_addiu (code, mips_sp, mips_sp, -32);
+ g_assert (mips_is_imm16(save_offset));
switch (save_mode) {
case SAVE_TWO:
mips_sw (code, mips_v0, mips_sp, save_offset);
+ g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
mips_sw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
if (enable_arguments) {
MIPS_MOVE (code, mips_a1, mips_v0);
mips_sdc1 (code, mips_f0, mips_sp, save_offset);
mips_ldc1 (code, mips_f12, mips_sp, save_offset);
mips_lw (code, mips_a0, mips_sp, save_offset);
+ g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
mips_lw (code, mips_a1, mips_sp, save_offset + SIZEOF_REGISTER);
break;
case SAVE_STRUCT:
break;
}
mips_load_const (code, mips_a0, cfg->method);
- mips_load_const (code, mips_t9, func);
- mips_jalr (code, mips_t9, mips_ra);
- mips_nop (code);
+ mips_call (code, mips_t9, func);
switch (save_mode) {
case SAVE_TWO:
mips_lw (code, mips_v0, mips_sp, save_offset);
+ g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
mips_lw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
break;
case SAVE_ONE:
MonoMethod *method = cfg->method;
int pos = 0, i;
int max_epilog_size = 16 + 20*4;
+ int alloc2_size = 0;
guint32 iregs_to_restore;
#if SAVE_FP_REGS
guint32 fregs_to_restore;
if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
}
- pos = cfg->arch.iregs_offset;
if (cfg->frame_reg != mips_sp) {
MIPS_MOVE (code, mips_sp, cfg->frame_reg);
}
+ /* If the stack frame is really large, deconstruct it in two steps */
+ if (cfg->stack_usage > ((1 << 15) - 1024)) {
+ alloc2_size = cfg->stack_usage - 1024;
+ /* partially deconstruct the stack */
+ mips_load_const (code, mips_at, alloc2_size);
+ mips_addu (code, mips_sp, mips_sp, mips_at);
+ }
+ pos = cfg->arch.iregs_offset - alloc2_size;
#if SAVE_ALL_REGS
iregs_to_restore = MONO_ARCH_CALLEE_SAVED_REGS;
#else
if (iregs_to_restore) {
for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
if (iregs_to_restore & (1 << i)) {
+ g_assert (mips_is_imm16(pos));
MIPS_LW (code, i, mips_sp, pos);
pos += SIZEOF_REGISTER;
}
for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
if (fregs_to_restore & (1 << i)) {
g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
+ g_assert (mips_is_imm16(pos));
mips_lwc1 (code, i, mips_sp, pos);
pos += FREG_SIZE
}
int lmf_offset = cfg->arch.lmf_offset;
/* t0 = current_lmf->previous_lmf */
+ g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
mips_lw (code, mips_temp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
/* t1 = lmf_addr */
+ g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
mips_lw (code, mips_t1, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
/* (*lmf_addr) = previous_lmf */
mips_sw (code, mips_temp, mips_t1, 0);
/* Restore the fp */
mips_lw (code, mips_fp, mips_sp, cfg->stack_usage + MIPS_FP_ADDR_OFFSET);
#endif
- /* Correct the stack pointer */
- if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA)
- mips_lw (code, mips_ra, mips_sp, cfg->stack_usage + MIPS_RET_ADDR_OFFSET);
- mips_addiu (code, mips_sp, mips_sp, cfg->stack_usage);
+ /* Restore ra */
+ if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
+ g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET));
+ mips_lw (code, mips_ra, mips_sp, cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET);
+ }
+ /* Restore the stack pointer */
+ g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size));
+ mips_addiu (code, mips_sp, mips_sp, cfg->stack_usage - alloc2_size);
/* Caller will emit either return or tail-call sequence */
return MONO_EXC_NULL_REF;
if (strcmp (name, "ArrayTypeMismatchException") == 0)
return MONO_EXC_ARRAY_TYPE_MISMATCH;
+ if (strcmp (name, "ArgumentException") == 0)
+ return MONO_EXC_ARGUMENT;
g_error ("Unknown intrinsic exception %s\n", name);
return 0;
}
MonoIMTCheckItem *item = imt_entries [i];
item->code_target = code;
- mips_load_const (code, mips_temp, (gsize)item->key);
if (item->is_equals) {
if (item->check_target_idx) {
+ mips_load_const (code, mips_temp, (gsize)item->key);
item->jmp_code = code;
mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
mips_nop (code);
mips_nop (code);
} else {
if (fail_tramp) {
+ mips_load_const (code, mips_temp, (gsize)item->key);
patch = code;
mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
mips_nop (code);
}
} else {
mips_load_const (code, mips_temp, (gulong)item->key);
- mips_slt (code, mips_temp, mips_temp, MONO_ARCH_IMT_REG);
+ mips_slt (code, mips_temp, MONO_ARCH_IMT_REG, mips_temp);
item->jmp_code = code;
- mips_bne (code, mips_temp, mips_zero, 0);
+ mips_beq (code, mips_temp, mips_zero, 0);
mips_nop (code);
}
}