get_delegate_invoke_impl (MonoTrampInfo **info, gboolean has_target, gboolean param_count)
{
guint8 *code, *start;
+ GSList *unwind_ops = mono_arch_get_cie_program ();
if (has_target) {
start = code = mono_global_codeman_reserve (12);
}
if (has_target) {
- *info = mono_tramp_info_create ("delegate_invoke_impl_has_target", start, code - start, NULL, NULL);
+ *info = mono_tramp_info_create ("delegate_invoke_impl_has_target", start, code - start, NULL, unwind_ops);
} else {
char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", param_count);
- *info = mono_tramp_info_create (name, start, code - start, NULL, NULL);
+ *info = mono_tramp_info_create (name, start, code - start, NULL, unwind_ops);
g_free (name);
}
cinfo->ret.reg = ARMREG_R0;
break;
}
- // FIXME: Only for variable types
- if (mini_is_gsharedvt_type (t)) {
+ if (mini_is_gsharedvt_variable_type (t)) {
cinfo->ret.storage = RegTypeStructByAddr;
break;
}
add_general (&gr, &stack_size, ainfo, TRUE);
break;
}
- if (mini_is_gsharedvt_type (t)) {
+ if (mini_is_gsharedvt_variable_type (t)) {
/* gsharedvt arguments are passed by ref */
g_assert (mini_is_gsharedvt_type (t));
add_general (&gr, &stack_size, ainfo, TRUE);
switch (ainfo->storage) {
case RegTypeGeneral:
- break;
case RegTypeIRegPair:
+ case RegTypeBaseGen:
break;
case RegTypeBase:
if (ainfo->offset >= (DYN_CALL_STACK_ARGS * sizeof (gpointer)))
ArgInfo *ainfo = &dinfo->cinfo->args [i + sig->hasthis];
int slot = -1;
- if (ainfo->storage == RegTypeGeneral || ainfo->storage == RegTypeIRegPair || ainfo->storage == RegTypeStructByVal)
+ if (ainfo->storage == RegTypeGeneral || ainfo->storage == RegTypeIRegPair || ainfo->storage == RegTypeStructByVal) {
slot = ainfo->reg;
- else if (ainfo->storage == RegTypeBase)
+ } else if (ainfo->storage == RegTypeBase) {
slot = PARAM_REGS + (ainfo->offset / 4);
- else
+ } else if (ainfo->storage == RegTypeBaseGen) {
+ /* slot + 1 is the first stack slot, so the code below will work */
+ slot = 3;
+ } else {
g_assert_not_reached ();
+ }
if (t->byref) {
p->regs [slot] = (mgreg_t)*arg;
/* Free entry */
target_thunk = p;
break;
+ } else if (((guint32*)p) [2] == (guint32)target) {
+ /* Thunk already points to target */
+ target_thunk = p;
+ break;
}
}
}
ins->backend.pc_offset = code - cfg->native_code;
bb->spill_slot_defs = g_slist_prepend_mempool (cfg->mempool, bb->spill_slot_defs, ins);
break;
+ case OP_GC_SAFE_POINT: {
+#if defined (USE_COOP_GC)
+ const char *polling_func = NULL;
+ guint8 *buf [1];
+
+ polling_func = "mono_threads_state_poll";
+ ARM_LDR_IMM (code, ARMREG_IP, ins->sreg1, 0);
+ ARM_CMP_REG_IMM (code, ARMREG_IP, 0, 0);
+ buf [0] = code;
+ ARM_B_COND (code, ARMCOND_EQ, 0);
+ mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, polling_func);
+ code = emit_call_seq (cfg, code);
+ arm_patch (buf [0], code);
+#endif
+ break;
+ }
default:
g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
if (mono_arm_have_fast_tls ()) {
mono_register_jit_icall (mono_fast_get_tls_key, "mono_get_tls_key", mono_create_icall_signature ("ptr ptr"), TRUE);
mono_register_jit_icall (mono_fast_set_tls_key, "mono_set_tls_key", mono_create_icall_signature ("void ptr ptr"), TRUE);
+
+ mono_tramp_info_register (
+ mono_tramp_info_create (
+ "mono_get_tls_key",
+ (guint8*)mono_fast_get_tls_key,
+ (guint8*)mono_fast_get_tls_key_end - (guint8*)mono_fast_get_tls_key,
+ NULL,
+ mono_arch_get_cie_program ()
+ ),
+ NULL
+ );
+ mono_tramp_info_register (
+ mono_tramp_info_create (
+ "mono_set_tls_key",
+ (guint8*)mono_fast_set_tls_key,
+ (guint8*)mono_fast_set_tls_key_end - (guint8*)mono_fast_set_tls_key,
+ NULL,
+ mono_arch_get_cie_program ()
+ ),
+ NULL
+ );
} else {
g_warning ("No fast tls on device. Using fallbacks.");
mono_register_jit_icall (mono_fallback_get_tls_key, "mono_get_tls_key", mono_create_icall_signature ("ptr ptr"), TRUE);
* 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);
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, ARMREG_SP, 0);
+
+ return l;
+}
+
/* #define ENABLE_WRONG_METHOD_CHECK 1 */
#define BASE_SIZE (6 * 4)
#define BSEARCH_ENTRY_SIZE (4 * 4)
#ifdef ENABLE_WRONG_METHOD_CHECK
char * cond;
#endif
+ GSList *unwind_ops;
size = BASE_SIZE;
#ifdef USE_JUMP_TABLES
code = mono_domain_code_reserve (domain, size);
start = code;
+ unwind_ops = mono_arch_get_cie_program ();
+
#ifdef DEBUG_IMT
g_print ("Building IMT thunk for class %s %s entries %d code size %d code at %p end %p vtable %p fail_tramp %p\n", vtable->klass->name_space, vtable->klass->name, count, size, start, ((guint8*)start) + size, vtable, fail_tramp);
for (i = 0; i < count; ++i) {
#ifdef USE_JUMP_TABLES
ARM_PUSH3 (code, ARMREG_R0, ARMREG_R1, ARMREG_R2);
+ mono_add_unwind_op_def_cfa_offset (unwind_ops, code, start, 3 * sizeof (mgreg_t));
#define VTABLE_JTI 0
#define IMT_METHOD_OFFSET 0
#define TARGET_CODE_OFFSET 1
ARM_LDR_IMM (code, ARMREG_IP, ARMREG_R2, VTABLE_JTI);
set_jumptable_element (jte, VTABLE_JTI, vtable);
#else
- if (large_offsets)
+ if (large_offsets) {
ARM_PUSH4 (code, ARMREG_R0, ARMREG_R1, ARMREG_IP, ARMREG_PC);
- else
+ mono_add_unwind_op_def_cfa_offset (unwind_ops, code, start, 4 * sizeof (mgreg_t));
+ } else {
ARM_PUSH2 (code, ARMREG_R0, ARMREG_R1);
+ mono_add_unwind_op_def_cfa_offset (unwind_ops, code, start, 2 * sizeof (mgreg_t));
+ }
ARM_LDR_IMM (code, ARMREG_R0, ARMREG_LR, -4);
vtable_target = code;
ARM_LDR_IMM (code, ARMREG_IP, ARMREG_PC, 0);
code = load_element_with_regbase_cond (code, ARMREG_R1, ARMREG_R2, target_code_jti, ARMCOND_AL);
/* Restore registers */
ARM_POP3 (code, ARMREG_R0, ARMREG_R1, ARMREG_R2);
+ mono_add_unwind_op_def_cfa_offset (unwind_ops, code, start, 0);
/* And branch */
ARM_BX (code, ARMREG_R1);
set_jumptable_element (jte, target_code_jti, item->value.target_code);
ARM_LDR_REG_REG (code, ARMREG_IP, ARMREG_IP, ARMREG_R1);
/* Restore registers and branch */
ARM_POP3 (code, ARMREG_R0, ARMREG_R1, ARMREG_R2);
+ mono_add_unwind_op_def_cfa_offset (unwind_ops, code, start, 0);
ARM_BX (code, ARMREG_IP);
#else
vtable_offset_ins = code;
#ifdef USE_JUMP_TABLES
ARM_LDR_IMM (code, ARMREG_IP, ARMREG_IP, vtable_offset);
ARM_POP3 (code, ARMREG_R0, ARMREG_R1, ARMREG_R2);
+ mono_add_unwind_op_def_cfa_offset (unwind_ops, code, start, 0);
ARM_BX (code, ARMREG_IP);
#else
ARM_POP2 (code, ARMREG_R0, ARMREG_R1);
- if (large_offsets)
+ if (large_offsets) {
+ mono_add_unwind_op_def_cfa_offset (unwind_ops, code, start, 2 * sizeof (mgreg_t));
ARM_ADD_REG_IMM8 (code, ARMREG_SP, ARMREG_SP, 2 * sizeof (gpointer));
+ }
+ mono_add_unwind_op_def_cfa_offset (unwind_ops, code, start, 0);
ARM_LDR_IMM (code, ARMREG_PC, ARMREG_IP, vtable_offset);
#endif
}
code = load_element_with_regbase_cond (code, ARMREG_R1, ARMREG_R2, target_code_jti, ARMCOND_AL);
/* Restore registers */
ARM_POP3 (code, ARMREG_R0, ARMREG_R1, ARMREG_R2);
+ mono_add_unwind_op_def_cfa_offset (unwind_ops, code, start, 0);
/* And branch */
ARM_BX (code, ARMREG_R1);
set_jumptable_element (jte, target_code_jti, fail_tramp);
g_assert (DISTANCE (start, code) <= size);
- mono_tramp_info_register (mono_tramp_info_create (NULL, (guint8*)start, DISTANCE (start, code), NULL, NULL), domain);
+ mono_tramp_info_register (mono_tramp_info_create (NULL, (guint8*)start, DISTANCE (start, code), NULL, unwind_ops), domain);
return start;
}