* FIXME: Optimize this.
*/
ARM_PUSH (code, (1 << ARMREG_R7) | (1 << ARMREG_LR));
- ARM_MOV_REG_REG (code, ARMREG_R7, ARMREG_SP);
prev_sp_offset += 8; /* r7 and lr */
mono_emit_unwind_op_def_cfa_offset (cfg, code, prev_sp_offset);
mono_emit_unwind_op_offset (cfg, code, ARMREG_R7, (- prev_sp_offset) + 0);
+ ARM_MOV_REG_REG (code, ARMREG_R7, ARMREG_SP);
}
if (!method->save_lmf) {
*/
code = cfg->native_code + cfg->code_len;
+ /* Save the uwind state which is needed by the out-of-line code */
+ mono_emit_unwind_op_remember_state (cfg, code);
+
if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
}
}
if (method->save_lmf) {
- int lmf_offset, reg, sp_adj, regmask;
+ int lmf_offset, reg, sp_adj, regmask, nused_int_regs = 0;
/* all but r0-r3, sp and pc */
pos += sizeof (MonoLMF) - (MONO_ARM_NUM_SAVED_REGS * sizeof (mgreg_t));
lmf_offset = pos;
regmask &= ~(1 << ARMREG_PC);
/* point sp at the registers to restore: 10 is 14 -4, because we skip r0-r3 */
code = emit_big_add (code, ARMREG_SP, cfg->frame_reg, cfg->stack_usage - lmf_offset + sp_adj);
+ for (i = 0; i < 16; i++) {
+ if (regmask & (1 << i))
+ nused_int_regs ++;
+ }
+ mono_emit_unwind_op_def_cfa (cfg, code, ARMREG_SP, ((iphone_abi ? 3 : 0) + nused_int_regs) * 4);
/* restore iregs */
ARM_POP (code, regmask);
if (iphone_abi) {
+ for (i = 0; i < 16; i++) {
+ if (regmask & (1 << i))
+ mono_emit_unwind_op_same_value (cfg, code, i);
+ }
/* Restore saved r7, restore LR to PC */
/* Skip lr from the lmf */
+ mono_emit_unwind_op_def_cfa_offset (cfg, code, 3 * 4);
ARM_ADD_REG_IMM (code, ARMREG_SP, ARMREG_SP, sizeof (gpointer), 0);
+ mono_emit_unwind_op_def_cfa_offset (cfg, code, 2 * 4);
ARM_POP (code, (1 << ARMREG_R7) | (1 << ARMREG_PC));
}
} else {
+ int i, nused_int_regs = 0;
+
+ for (i = 0; i < 16; i++) {
+ if (cfg->used_int_regs & (1 << i))
+ nused_int_regs ++;
+ }
+
if ((i = mono_arm_is_rotated_imm8 (cfg->stack_usage, &rot_amount)) >= 0) {
ARM_ADD_REG_IMM (code, ARMREG_SP, cfg->frame_reg, i, rot_amount);
} else {
ARM_ADD_REG_REG (code, ARMREG_SP, cfg->frame_reg, ARMREG_IP);
}
+ if (cfg->frame_reg != ARMREG_SP) {
+ mono_emit_unwind_op_def_cfa_reg (cfg, code, ARMREG_SP);
+ }
+
if (iphone_abi) {
/* Restore saved gregs */
- if (cfg->used_int_regs)
+ if (cfg->used_int_regs) {
+ mono_emit_unwind_op_def_cfa_offset (cfg, code, (2 + nused_int_regs) * 4);
ARM_POP (code, cfg->used_int_regs);
+ for (i = 0; i < 16; i++) {
+ if (cfg->used_int_regs & (1 << i))
+ mono_emit_unwind_op_same_value (cfg, code, i);
+ }
+ }
+ mono_emit_unwind_op_def_cfa_offset (cfg, code, 2 * 4);
/* Restore saved r7, restore LR to PC */
ARM_POP (code, (1 << ARMREG_R7) | (1 << ARMREG_PC));
} else {
+ mono_emit_unwind_op_def_cfa_offset (cfg, code, (nused_int_regs + 1) * 4);
ARM_POP (code, cfg->used_int_regs | (1 << ARMREG_PC));
}
}
+ /* Restore the unwind state to be the same as before the epilog */
+ mono_emit_unwind_op_restore_state (cfg, code);
+
cfg->code_len = code - cfg->native_code;
g_assert (cfg->code_len < cfg->code_size);