/* D e f i n e s */
/*------------------------------------------------------------------*/
-#define MAX_ARCH_DELEGATE_PARAMS 7
+#define MAX_ARCH_DELEGATE_PARAMS 10
#define EMIT_COND_BRANCH(ins,cond) \
{ \
#define S390_TRACE_STACK_SIZE (5*sizeof(gpointer)+4*sizeof(gdouble))
-#define BREAKPOINT_SIZE sizeof(breakpoint_t)
-#define S390X_NOP_SIZE sizeof(RR_Format)
-
#define MAX(a, b) ((a) > (b) ? (a) : (b))
/*
gdouble fp[3]; /* F0-F2 */
} __attribute__ ((__packed__)) RegParm;
-/**
- * Breakpoint instruction sequence
- */
-typedef struct {
- RR_Format basr;
- RI_Format j;
- void *pTrigger;
- RXY_Format lg;
- RXY_Format trigger;
-} __attribute__ ((__packed__)) breakpoint_t;
-
/*========================= End of Typedefs ========================*/
/*------------------------------------------------------------------*/
/*------------------------------------------------------------------*/
/**
- * The code generated for sequence points reads from this location,
- * which is made read-only when single stepping is enabled.
+ * The single-step trampoline
*/
-static gpointer ss_trigger_page;
+static gpointer ss_trampoline;
/**
- * Enabled breakpoints read from this trigger page
+ * The breakpoint trampoline
*/
-static gpointer bp_trigger_page;
-
-breakpoint_t breakpointCode;
+static gpointer bp_trampoline;
/**
* Constants used in debugging - map general register names
"vr24", "vr25", "vr26", "vr27", "vr28", "vr29", "vr30", "vr31"
};
+#if 0
/**
* Constants used in debugging - ABI register types
*/
static const char *typeParm[] = { "General", "Base", "FPR8", "FPR4", "StructByVal",
"StructByValInFP", "ByAddr"};
+#endif
/*====================== End of Global Variables ===================*/
void
mono_arch_init (void)
{
- guint8 *code;
-
mono_set_partial_sharing_supported (FALSE);
- ss_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ, MONO_MEM_ACCOUNT_OTHER);
- bp_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ, MONO_MEM_ACCOUNT_OTHER);
- mono_mprotect (bp_trigger_page, mono_pagesize (), 0);
-
- code = (guint8 *) &breakpointCode;
- s390_basr(code, s390_r13, 0);
- s390_j(code, 6);
- s390_llong(code, 0);
- s390_lg(code, s390_r13, 0, s390_r13, 4);
- s390_lg(code, s390_r0, 0, s390_r13, 0);
+ if (!mono_aot_only)
+ bp_trampoline = mini_get_breakpoint_trampoline();
}
/*========================= End of Function ========================*/
void
mono_arch_cleanup (void)
{
- if (ss_trigger_page)
- mono_vfree (ss_trigger_page, mono_pagesize (), MONO_MEM_ACCOUNT_OTHER);
- if (bp_trigger_page)
- mono_vfree (bp_trigger_page, mono_pagesize (), MONO_MEM_ACCOUNT_OTHER);
}
/*========================= End of Function ========================*/
fr = 0;
gr = s390_r2;
- nParm = 0;
+ nParm = 0;
cinfo->struct_ret = 0;
- cinfo->sig = sig;
+ cinfo->sig = sig;
sz = &cinfo->sz;
sz->retStruct = 0;
sz->stack_size = S390_MINIMAL_STACK_SIZE;
sz->code_size = 0;
sz->parm_size = 0;
- align = 0;
- size = 0;
+ align = 0;
+ size = 0;
/*----------------------------------------------------------*/
/* We determine the size of the return code/stack in case we*/
mono_print_ins (cfg->vret_addr);
}
}
+
+ if (cfg->gen_sdb_seq_points) {
+ MonoInst *ins;
+
+ ins = mono_compile_create_var (cfg, mono_get_int_type (), OP_LOCAL);
+ ins->flags |= MONO_INST_VOLATILE;
+ cfg->arch.ss_tramp_var = ins;
+
+ ins = mono_compile_create_var (cfg, mono_get_int_type (), OP_LOCAL);
+ ins->flags |= MONO_INST_VOLATILE;
+ cfg->arch.bp_tramp_var = ins;
+ }
}
/*========================= End of Function ========================*/
case OP_TAILCALL_MEMBASE : {
MonoCallInst *call = (MonoCallInst *) ins;
- /*
- * Restore SP to caller's SP
- */
+ /*
+ * Restore SP to caller's SP
+ */
code = backUpStackPtr(cfg, code);
- /*
- * If the destination is specified as a register or membase then
- * save destination so it doesn't get overwritten by the restores
- */
- if (ins->opcode != OP_TAILCALL)
- s390_lgr (code, s390_r1, ins->sreg1);
-
- /*
- * If the IMT/RGCTX register is in use then don't restore over it
- */
- if ((call->used_iregs & (MONO_ARCH_RGCTX_REG << 1)) || (call->rgctx_reg))
- s390_lgr (code, s390_r0, MONO_ARCH_RGCTX_REG);
- /*
- * If R6 is used for a parameter then don't restore the other
- * parameter registers are volatile
- */
- if (call->used_iregs & (1 << 6))
- s390_lmg (code, s390_r7, s390_r14, STK_BASE, S390_NONPARM_SAVE_OFFSET);
- else
- s390_lmg (code, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET);
-
- if ((call->used_iregs & (MONO_ARCH_RGCTX_REG << 1)) || (call->rgctx_reg))
- s390_lgr (code, MONO_ARCH_RGCTX_REG, s390_r0);
-
- /*
- * Restore any FP registers that have been altered
- */
- if (cfg->arch.fpSize != 0) {
- int fpOffset = -cfg->arch.fpSize;
- for (int i = 8; i < 16; i++) {
- if (cfg->arch.used_fp_regs & (1 << i)) {
- s390_ldy (code, i, 0, STK_BASE, fpOffset);
- fpOffset += sizeof(double);
- }
- }
- }
-
- if (ins->opcode == OP_TAILCALL_REG) {
- s390_br (code, s390_r1);
- } else {
- if (ins->opcode == OP_TAILCALL_MEMBASE) {
- if (mono_hwcap_s390x_has_mie2) {
- s390_bi (code, 0, s390_r1, ins->inst_offset);
- } else {
- s390_lg (code, s390_r1, 0, s390_r1, ins->inst_offset);
- s390_br (code, s390_r1);
- }
- } else {
- mono_add_patch_info (cfg, code - cfg->native_code,
- MONO_PATCH_INFO_METHOD_JUMP,
- call->method);
- s390_jcl (code, S390_CC_UN, 0);
- }
- }
+ /*
+ * If the destination is specified as a register or membase then
+ * save destination so it doesn't get overwritten by the restores
+ */
+ if (ins->opcode != OP_TAILCALL)
+ s390_lgr (code, s390_r1, ins->sreg1);
+
+ /*
+ * If the IMT/RGCTX register is in use then don't restore over it
+ */
+ if ((call->used_iregs & (MONO_ARCH_RGCTX_REG << 1)) || (call->rgctx_reg))
+ s390_lgr (code, s390_r0, MONO_ARCH_RGCTX_REG);
+ /*
+ * If R6 is used for a parameter then don't restore the other
+ * parameter registers are volatile
+ */
+ if (call->used_iregs & (1 << 6))
+ s390_lmg (code, s390_r7, s390_r14, STK_BASE, S390_NONPARM_SAVE_OFFSET);
+ else
+ s390_lmg (code, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET);
+
+ if ((call->used_iregs & (MONO_ARCH_RGCTX_REG << 1)) || (call->rgctx_reg))
+ s390_lgr (code, MONO_ARCH_RGCTX_REG, s390_r0);
+
+ /*
+ * Restore any FP registers that have been altered
+ */
+ if (cfg->arch.fpSize != 0) {
+ int fpOffset = -cfg->arch.fpSize;
+ for (int i = 8; i < 16; i++) {
+ if (cfg->arch.used_fp_regs & (1 << i)) {
+ s390_ldy (code, i, 0, STK_BASE, fpOffset);
+ fpOffset += sizeof(double);
+ }
+ }
+ }
+
+ if (ins->opcode == OP_TAILCALL_REG) {
+ s390_br (code, s390_r1);
+ } else {
+ if (ins->opcode == OP_TAILCALL_MEMBASE) {
+ if (mono_hwcap_s390x_has_mie2) {
+ s390_bi (code, 0, s390_r1, ins->inst_offset);
+ } else {
+ s390_lg (code, s390_r1, 0, s390_r1, ins->inst_offset);
+ s390_br (code, s390_r1);
+ }
+ } else {
+ mono_add_patch_info (cfg, code - cfg->native_code,
+ MONO_PATCH_INFO_METHOD_JUMP,
+ call->method);
+ s390_jcl (code, S390_CC_UN, 0);
+ }
+ }
}
break;
case OP_CHECK_THIS: {
case OP_ARGLIST: {
const int offset = cfg->sig_cookie + cfg->stack_usage;
- S390_SET (code, s390_r0, offset);
- s390_agr (code, s390_r0, cfg->frame_reg);
- s390_stg (code, s390_r0, 0, ins->sreg1, 0);
+ S390_SET (code, s390_r0, offset);
+ s390_agr (code, s390_r0, cfg->frame_reg);
+ s390_stg (code, s390_r0, 0, ins->sreg1, 0);
}
break;
case OP_FCALL: {
mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
break;
case OP_SEQ_POINT: {
- int i;
+
+ MonoInst *var;
+ RI_Format *o[2];
+ guint16 displace;
if (cfg->compile_aot)
NOT_IMPLEMENTED;
+ if (ins->flags & MONO_INST_SINGLE_STEP_LOC) {
+ var = cfg->arch.ss_tramp_var;
+ s390_lg (code, s390_r1, 0, var->inst_basereg, var->inst_offset);
+ if (mono_hwcap_s390x_has_eif) {
+ s390_ltg (code, s390_r14, 0, s390_r1, 0);
+ } else {
+ s390_lg (code, s390_r14, 0, s390_r1, 0);
+ s390_ltgr (code, s390_r14, s390_r14);
+ }
+ o[0] = (RI_Format *) code;
+ s390_jz (code, 4);
+ s390_lgr (code, s390_r1, cfg->frame_reg);
+ s390_basr (code, s390_r14, s390_r14);
+ displace = ((uintptr_t) code - (uintptr_t) o[0]) / 2;
+ o[0]->i2 = displace;
+ }
+
/*
- * Read from the single stepping trigger page. This will cause a
- * SIGSEGV when single stepping is enabled.
- * We do this _before_ the breakpoint, so single stepping after
- * a breakpoint is hit will step to the next IL offset.
+ * This is the address which is saved in seq points,
*/
- if (ins->flags & MONO_INST_SINGLE_STEP_LOC) {
- breakpointCode.pTrigger = ss_trigger_page;
- memcpy(code, (void *) &breakpointCode, BREAKPOINT_SIZE);
- code += BREAKPOINT_SIZE;
- }
-
mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
- /*
- * A placeholder for a possible breakpoint inserted by
- * mono_arch_set_breakpoint ().
- */
- for (i = 0; i < (BREAKPOINT_SIZE / S390X_NOP_SIZE); ++i)
- s390_nop (code);
+ var = cfg->arch.bp_tramp_var;
+ s390_lghi (code, s390_r1, 0);
+ s390_ltgr (code, s390_r1, s390_r1);
+ o[0] = (RI_Format *) code;
+ s390_jz (code, 0);
+ s390_lg (code, s390_r1, 0, var->inst_basereg, var->inst_offset);
+ if (mono_hwcap_s390x_has_eif) {
+ s390_ltg (code, s390_r14, 0, s390_r1, 0);
+ } else {
+ s390_lg (code, s390_r1, 0, s390_r1, 0);
+ s390_ltgr (code, s390_r14, s390_r1);
+ }
+ o[1] = (RI_Format *) code;
+ s390_jz (code, 4);
+ s390_lgr (code, s390_r1, cfg->frame_reg);
+ s390_basr (code, s390_r14, s390_r14);
+ displace = ((uintptr_t) code - (uintptr_t) o[0]) / 2;
+ o[0]->i2 = displace;
+ displace = ((uintptr_t) code - (uintptr_t) o[1]) / 2;
+ o[1]->i2 = displace;
/*
* Add an additional nop so skipping the bp doesn't cause the ip to point
/* floating point opcodes */
case OP_R8CONST: {
- if (*((double *) ins->inst_p0) == 0) {
+ double d = *(double *) ins->inst_p0;
+ if (d == 0) {
s390_lzdr (code, ins->dreg);
+ if (mono_signbit (d) != 0)
+ s390_lndbr (code, ins->dreg, ins->dreg);
} else {
S390_SET (code, s390_r13, ins->inst_p0);
s390_ld (code, ins->dreg, 0, s390_r13, 0);
}
break;
case OP_R4CONST: {
- if (*((float *) ins->inst_p0) == 0) {
- if (cfg->r4fp)
+ float f = *(float *) ins->inst_p0;
+ if (f == 0) {
+ if (cfg->r4fp) {
s390_lzer (code, ins->dreg);
- else
+ if (mono_signbit (f) != 0)
+ s390_lnebr (code, ins->dreg, ins->dreg);
+ } else {
s390_lzdr (code, ins->dreg);
+ if (mono_signbit (f) != 0)
+ s390_lndbr (code, ins->dreg, ins->dreg);
+ }
} else {
- S390_SET (code, s390_r13, ins->inst_p0);
+ S390_SET (code, s390_r13, ins->inst_p0);
s390_le (code, ins->dreg, 0, s390_r13, 0);
if (!cfg->r4fp) {
s390_ldebr (code, ins->dreg, ins->dreg);
break;
case OP_ATOMIC_ADD_I8: {
if (mono_hwcap_s390x_has_ia) {
- s390_laag (code, ins->dreg, ins->sreg2, ins->inst_basereg, ins->inst_offset);
- s390_agr (code, ins->dreg, ins->sreg2);
+ s390_laag(code, s390_r0, ins->sreg2, ins->inst_basereg, ins->inst_offset);
+ s390_lg (code, ins->dreg, 0, ins->inst_basereg, ins->inst_offset);
} else {
s390_lgr (code, s390_r1, ins->sreg2);
s390_lg (code, s390_r0, 0, ins->inst_basereg, ins->inst_offset);
break;
case OP_ATOMIC_ADD_I4: {
if (mono_hwcap_s390x_has_ia) {
- s390_laa (code, ins->dreg, ins->sreg2, ins->inst_basereg, ins->inst_offset);
- s390_ar (code, ins->dreg, ins->sreg2);
+ s390_laa (code, s390_r0, ins->sreg2, ins->inst_basereg, ins->inst_offset);
+ s390_lgf (code, ins->dreg, 0, ins->inst_basereg, ins->inst_offset);
} else {
s390_lgfr(code, s390_r1, ins->sreg2);
s390_lgf (code, s390_r0, 0, ins->inst_basereg, ins->inst_offset);
*/
mono_emit_unwind_op_def_cfa (cfg, code, STK_BASE, 0);
emit_unwind_regs(cfg, code, s390_r6, s390_r14, S390_REG_SAVE_OFFSET);
- s390_stmg (code, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET);
mono_emit_unwind_op_offset (cfg, code, s390_r14, S390_RET_ADDR_OFFSET);
+ s390_stmg (code, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET);
mini_gc_set_slot_type_from_cfa (cfg, S390_RET_ADDR_OFFSET, SLOT_NOREF);
if (cfg->arch.bkchain_reg != -1)
s390_lgr (code, cfg->arch.bkchain_reg, STK_BASE);
#if 0
printf("ns: %s k: %s m: %s\n",method->klass->name_space,method->klass->name,method->name);fflush(stdout);
-// Tests:test_9_tail_call_vret_by_val
+// Tests:set_ip
if ((strcmp(method->klass->name_space,"") == 0) &&
(strcmp(method->klass->name,"Tests") == 0) &&
- (strcmp(method->name, "test_9_tail_call_vret_by_val") == 0)) {
+ (strcmp(method->name, "set_ip") == 0)) {
// (strcmp("CancellationToken,TaskCreationOptions,TaskContinuationOptions,TaskScheduler",mono_signature_get_desc(method->signature, FALSE)) != 0)) {
printf("SIGNATURE: %s\n",mono_signature_get_desc(method->signature, FALSE)); fflush(stdout);
s390_j (code, 0);
}
}
+ if (cfg->gen_sdb_seq_points) {
+ MonoInst *seq;
+
+ /* Initialize ss_tramp_var */
+ seq = cfg->arch.ss_tramp_var;
+ g_assert (seq->opcode == OP_REGOFFSET);
+
+ S390_SET (code, s390_r1, (guint64) &ss_trampoline);
+ s390_stg (code, s390_r1, 0, seq->inst_basereg, seq->inst_offset);
+
+ /* Initialize bp_tramp_var */
+ seq = cfg->arch.bp_tramp_var;
+ g_assert (seq->opcode == OP_REGOFFSET);
+
+ S390_SET (code, s390_r1, (guint64) &bp_trampoline);
+ s390_stg (code, s390_r1, 0, seq->inst_basereg, seq->inst_offset);
+ }
+
set_code_cursor (cfg, code);
return code;
{
MonoMethod *method = cfg->method;
guint8 *code;
- int max_epilog_size = 96;
+ int max_epilog_size = 96, i;
int fpOffset = 0;
if (cfg->method->save_lmf)
code = realloc_code (cfg, max_epilog_size);
+ cfg->has_unwind_info_for_epilog = TRUE;
+
+ /* Mark the start of the epilog */
+ mono_emit_unwind_op_mark_loc (cfg, code, 0);
+
+ /* Save the uwind state which is needed by the out-of-line code */
+ mono_emit_unwind_op_remember_state (cfg, code);
+
if (method->save_lmf)
restoreLMF(code, cfg->frame_reg, cfg->stack_usage);
code = backUpStackPtr(cfg, code);
+ mono_emit_unwind_op_def_cfa (cfg, code, STK_BASE, 0);
if (cfg->arch.fpSize != 0) {
fpOffset = -cfg->arch.fpSize;
}
s390_lmg (code, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET);
+ for (i = s390_r6; i < s390_r15; i++)
+ mono_emit_unwind_op_same_value (cfg, code, i);
s390_br (code, s390_r14);
+ /* Restore the unwind state to be the same as before the epilog */
+ mono_emit_unwind_op_restore_state (cfg, code);
+
set_code_cursor (cfg, code);
}
*/
static guint8 *
-get_delegate_invoke_impl (MonoTrampInfo **info, gboolean has_target, guint32 param_count, gboolean aot)
+get_delegate_invoke_impl (MonoTrampInfo **info, gboolean has_target, MonoMethodSignature *sig, gboolean aot)
{
guint8 *code, *start;
mono_arch_flush_icache (start, size);
MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_DELEGATE_INVOKE, NULL));
} else {
- int size, i;
+ int size, i, offset = S390_MINIMAL_STACK_SIZE, iReg = s390_r2;
+ CallInfo *cinfo = get_call_info (NULL, sig);
- size = 32 + param_count * 8;
+ size = 32 + sig->param_count * 8;
start = code = mono_global_codeman_reserve (size);
- s390_lg (code, s390_r1, 0, s390_r2, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr));
+ s390_lg (code, s390_r1, 0, s390_r2, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr));
/* slide down the arguments */
- for (i = 0; i < param_count; ++i) {
- s390_lgr (code, (s390_r2 + i), (s390_r2 + i + 1));
+ for (i = 0; i < sig->param_count; ++i) {
+ switch(cinfo->args[i].regtype) {
+ case RegTypeGeneral :
+ if (iReg < S390_LAST_ARG_REG) {
+ s390_lgr (code, iReg, (iReg + 1));
+ } else {
+ s390_lg (code, iReg, 0, STK_BASE, offset);
+ }
+ iReg++;
+ break;
+ default :
+ s390_mvc (code, sizeof(uintptr_t), STK_BASE, offset, STK_BASE, offset+sizeof(uintptr_t));
+ offset += sizeof(uintptr_t);
+ }
}
- s390_br (code, s390_r1);
+ s390_br (code, s390_r1);
+
+ g_free (cinfo);
g_assert ((code - start) <= size);
if (has_target) {
*info = mono_tramp_info_create ("delegate_invoke_impl_has_target", start, code - start, NULL, NULL);
} else {
- char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", param_count);
+ char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", sig->param_count);
*info = mono_tramp_info_create (name, start, code - start, NULL, NULL);
g_free (name);
}
{
GSList *res = NULL;
MonoTrampInfo *info;
- int i;
get_delegate_invoke_impl (&info, TRUE, 0, TRUE);
res = g_slist_prepend (res, info);
- for (i = 0; i <= MAX_ARCH_DELEGATE_PARAMS; ++i) {
- get_delegate_invoke_impl (&info, FALSE, i, TRUE);
+#if 0
+ for (int i = 0; i <= MAX_ARCH_DELEGATE_PARAMS; ++i) {
+ get_delegate_invoke_impl (&info, FALSE, NULL, TRUE);
res = g_slist_prepend (res, info);
}
+#endif
return res;
}
{
guint8 *code, *start;
+ if (sig->param_count > MAX_ARCH_DELEGATE_PARAMS)
+ return NULL;
+
/* FIXME: Support more cases */
- if (MONO_TYPE_ISSTRUCT (sig->ret))
+ if (MONO_TYPE_ISSTRUCT (mini_get_underlying_type (sig->ret)))
return NULL;
if (has_target) {
start = mono_aot_get_trampoline ("delegate_invoke_impl_has_target");
} else {
MonoTrampInfo *info;
- start = get_delegate_invoke_impl (&info, TRUE, 0, FALSE);
+ start = get_delegate_invoke_impl (&info, TRUE, sig, FALSE);
mono_tramp_info_register (info, NULL);
}
if (!mono_is_regsize_var (sig->params [i]))
return NULL;
-
code = cache [sig->param_count];
if (code)
return code;
g_free (name);
} else {
MonoTrampInfo *info;
- start = get_delegate_invoke_impl (&info, FALSE, sig->param_count, FALSE);
+ start = get_delegate_invoke_impl (&info, FALSE, sig, FALSE);
mono_tramp_info_register (info, NULL);
}
void
mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
{
- guint8 *code = ip;
+ guint8 *bp = ip;
- breakpointCode.pTrigger = bp_trigger_page;
- memcpy(code, (void *) &breakpointCode, BREAKPOINT_SIZE);
- code += BREAKPOINT_SIZE;
+ /* IP should point to a LGHI R1,0 */
+ g_assert (bp[0] == 0xa7);
+
+ /* Replace it with a LGHI R1,1 */
+ s390_lghi (bp, s390_r1, 1);
}
/*========================= End of Function ========================*/
void
mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
{
- guint8 *code = ip;
- int i;
+ guint8 *bp = ip;
- for (i = 0; i < (BREAKPOINT_SIZE / S390X_NOP_SIZE); i++)
- s390_nop(code);
+ /* IP should point to a LGHI R1,1 */
+ g_assert (bp[0] == 0xa7);
+
+ /* Replace it with a LGHI R1,0 */
+ s390_lghi (bp, s390_r1, 0);
}
/*========================= End of Function ========================*/
* @param[in] @sigctx - Signal context
* @returns True if this is a breakpoint event
*
- * Check if the breakpoint has occurred within the breakpoint area
+ * We use soft breakpoints so always return FALSE
*/
gboolean
mono_arch_is_breakpoint_event (void *info, void *sigctx)
{
- siginfo_t* sinfo = (siginfo_t*) info;
-
- /*
- * Sometimes the address is off by 4
- */
- if (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128)
- return TRUE;
- else
- return FALSE;
+ /* We use soft breakpoints on s390x */
+ return FALSE;
}
/*========================= End of Function ========================*/
* @param[in] @ctx - Mono Context
* @param[in] @ji - Mono JIT information
*
- * Modify the CTX so the IP is placed after the breakpoint instruction, so
- * when we resume, the instruction is not executed again.
+ * We use soft breakpoints so this is a no-op
*/
void
mono_arch_skip_breakpoint (MonoContext *ctx, MonoJitInfo *ji)
{
- MONO_CONTEXT_SET_IP (ctx, ((guint8*)MONO_CONTEXT_GET_IP (ctx) + sizeof(RXY_Format)));
+ g_assert_not_reached ();
}
/*========================= End of Function ========================*/
void
mono_arch_start_single_stepping (void)
{
- mono_mprotect (ss_trigger_page, mono_pagesize (), 0);
+ ss_trampoline = mini_get_single_step_trampoline();
}
/*========================= End of Function ========================*/
void
mono_arch_stop_single_stepping (void)
{
- mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ);
+ ss_trampoline = NULL;
}
/*========================= End of Function ========================*/
* @returns True if this is a single stepping event
*
* Return whether the machine state in sigctx corresponds to a single step event.
+ * On s390x we use soft breakpoints so return FALSE
*/
gboolean
mono_arch_is_single_step_event (void *info, void *sigctx)
{
- siginfo_t* sinfo = (siginfo_t*) info;
-
- /*
- * Sometimes the address is off by 4
- */
- if (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128)
- return TRUE;
- else
- return FALSE;
+ /* We use soft breakpoints on s390x */
+ return FALSE;
}
/*========================= End of Function ========================*/
*
* Modify the ctx so the IP is placed after the single step trigger
* instruction, so that the instruction is not executed again.
+ * On s390x we use soft breakpoints so we shouldn't get here
*/
void
mono_arch_skip_single_step (MonoContext *ctx)
{
- MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + BREAKPOINT_SIZE);
+ g_assert_not_reached();
}
/*========================= End of Function ========================*/
SeqPointInfo *
mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)
{
- NOT_IMPLEMENTED;
- return NULL;
+ SeqPointInfo *info;
+ MonoJitInfo *ji;
+
+ mono_domain_lock (domain);
+ info = (SeqPointInfo *)g_hash_table_lookup (domain_jit_info (domain)->arch_seq_points, code);
+ mono_domain_unlock (domain);
+
+ if (!info) {
+ ji = mono_jit_info_table_find (domain, code);
+ g_assert (ji);
+
+ // FIXME: Optimize the size
+ info = (SeqPointInfo *)g_malloc0 (sizeof (SeqPointInfo) + (ji->code_size * sizeof (gpointer)));
+
+ info->ss_tramp_addr = &ss_trampoline;
+
+ mono_domain_lock (domain);
+ g_hash_table_insert (domain_jit_info(domain)->arch_seq_points, code, info);
+ mono_domain_unlock (domain);
+ }
+
+ return info;
+
}
/*========================= End of Function ========================*/
/**
- * \file
- * Function - JIT trampoline code for S/390.
+ * @file
+ *
+ * @author Neale Ferguson <neale@sinenomine.net>
*
- * Name - Neale Ferguson (Neale.Ferguson@SoftwareAG-usa.com)
+ * @section description
+ *
+ * Function - JIT trampoline code for S/390.
*
* Date - January, 2004
*
- * Derivation - From exceptions-x86 & exceptions-ppc
+ * Derivation - From tramp-x86 & tramp-ppc
* Paolo Molaro (lupus@ximian.com)
* Dietmar Maurer (dietmar@ximian.com)
*
#include "mini-runtime.h"
#include "support-s390x.h"
#include "jit-icalls.h"
+#include "debugger-agent.h"
#include "mono/utils/mono-tls-inline.h"
/*========================= End of Includes ========================*/
/*====================== End of Global Variables ===================*/
-/*------------------------------------------------------------------*/
-/* */
-/* Name - mono_arch_get_unbox_trampoline */
-/* */
-/* Function - Return a pointer to a trampoline which does the */
-/* unboxing before calling the method. */
-/* */
-/* When value type methods are called through the */
-/* vtable we need to unbox the 'this' argument. */
-/* */
-/* Parameters - method - Methd pointer */
-/* addr - Pointer to native code for method */
-/* */
-/*------------------------------------------------------------------*/
+/**
+ *
+ * @brief Build the unbox trampoline
+ *
+ * @param[in] Method pointer
+ * @param[in] Pointer to native code for method
+ *
+ * Return a pointer to a trampoline which does the unboxing before
+ * calling the method.
+ *
+ * When value type methods are called through the
+ * vtable we need to unbox the 'this' argument.
+ */
gpointer
mono_arch_get_unbox_trampoline (MonoMethod *method, gpointer addr)
/*========================= End of Function ========================*/
+/**
+ *
+ * @brief Build the SDB trampoline
+ *
+ * @param[in] Type of trampoline (ss or bp)
+ * @param[in] MonoTrampInfo
+ * @param[in] Ahead of time indicator
+ *
+ * Return a trampoline which captures the current context, passes it to
+ * mono_debugger_agent_single_step_from_context ()/mono_debugger_agent_breakpoint_from_context (),
+ * then restores the (potentially changed) context.
+ */
+
+guint8 *
+mono_arch_create_sdb_trampoline (gboolean single_step, MonoTrampInfo **info, gboolean aot)
+{
+ int tramp_size = 512;
+ int i, framesize, ctx_offset,
+ gr_offset, fp_offset, ip_offset,
+ sp_offset;
+ guint8 *code, *buf;
+ void *ep;
+ GSList *unwind_ops = NULL;
+ MonoJumpInfo *ji = NULL;
+
+ code = buf = (guint8 *)mono_global_codeman_reserve (tramp_size);
+
+ framesize = S390_MINIMAL_STACK_SIZE;
+
+ ctx_offset = framesize;
+ framesize += sizeof (MonoContext);
+
+ framesize = ALIGN_TO (framesize, MONO_ARCH_FRAME_ALIGNMENT);
+
+ /**
+ * Create unwind information - On entry s390_r1 has value of method's frame reg
+ */
+ mono_add_unwind_op_def_cfa (unwind_ops, code, buf, STK_BASE, 0);
+ s390_stmg (code, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET);
+ gr_offset = S390_REG_SAVE_OFFSET;
+ for (i = s390_r6; i < s390_r15; i++) {
+ mono_add_unwind_op_offset (unwind_ops, code, buf, i, gr_offset);
+ gr_offset += sizeof(uintptr_t);
+ }
+
+ s390_lgr (code, s390_r0, STK_BASE);
+ s390_aghi (code, STK_BASE, -framesize);
+ mono_add_unwind_op_def_cfa_offset (unwind_ops, code, buf, framesize);
+ mono_add_unwind_op_fp_alloc (unwind_ops, code, buf, STK_BASE, 0);
+ s390_stg (code, s390_r0, 0, STK_BASE, 0);
+
+ gr_offset = ctx_offset + G_STRUCT_OFFSET(MonoContext, uc_mcontext.gregs);
+ sp_offset = ctx_offset + G_STRUCT_OFFSET(MonoContext, uc_mcontext.gregs[15]);
+ ip_offset = ctx_offset + G_STRUCT_OFFSET(MonoContext, uc_mcontext.psw.addr);
+
+ /* Initialize a MonoContext structure on the stack */
+ s390_stmg (code, s390_r0, s390_r14, STK_BASE, gr_offset);
+ s390_stg (code, s390_r1, 0, STK_BASE, sp_offset);
+ sp_offset = ctx_offset + G_STRUCT_OFFSET(MonoContext, uc_stack.ss_sp);
+ s390_stg (code, s390_r1, 0, STK_BASE, sp_offset);
+ s390_stg (code, s390_r14, 0, STK_BASE, ip_offset);
+
+ fp_offset = ctx_offset + G_STRUCT_OFFSET(MonoContext, uc_mcontext.fpregs.fprs);
+ for (i = s390_f0; i < s390_f15; ++i) {
+ s390_std (code, i, 0, STK_BASE, fp_offset);
+ fp_offset += sizeof(double);
+ }
+
+ /*
+ * Call the single step/breakpoint function in sdb using
+ * the context address as the parameter
+ */
+ s390_la (code, s390_r2, 0, STK_BASE, ctx_offset);
+
+ if (single_step)
+ ep = (mini_get_dbg_callbacks())->single_step_from_context;
+ else
+ ep = (mini_get_dbg_callbacks())->breakpoint_from_context;
+
+ S390_SET (code, s390_r1, ep);
+ s390_basr (code, s390_r14, s390_r1);
+
+ /*
+ * Restore volatiles
+ */
+ s390_lmg (code, s390_r0, s390_r5, STK_BASE, gr_offset);
+
+ /*
+ * Restore FP registers
+ */
+ fp_offset = ctx_offset + G_STRUCT_OFFSET(MonoContext, uc_mcontext.fpregs.fprs);
+ for (i = s390_f0; i < s390_f15; ++i) {
+ s390_ld (code, i, 0, STK_BASE, fp_offset);
+ fp_offset += sizeof(double);
+ }
+
+ /*
+ * Load the IP from the context to pick up any SET_IP command results
+ */
+ s390_lg (code, s390_r14, 0, STK_BASE, ip_offset);
+
+ /*
+ * Restore everything else from the on-entry values
+ */
+ s390_aghi (code, STK_BASE, framesize);
+ mono_add_unwind_op_def_cfa_offset (unwind_ops, code, buf, -framesize);
+ s390_lmg (code, s390_r6, s390_r13, STK_BASE, S390_REG_SAVE_OFFSET);
+ s390_br (code, s390_r14);
+
+ g_assertf ((code - buf) <= tramp_size, "%d %d", (int)(code - buf), tramp_size);
+ mono_arch_flush_icache (code, code - buf);
+
+ MONO_PROFILER_RAISE (jit_code_buffer, (buf, code - buf, MONO_PROFILER_CODE_BUFFER_HELPER, NULL));
+ g_assert (code - buf <= tramp_size);
+
+ const char *tramp_name = single_step ? "sdb_single_step_trampoline" : "sdb_breakpoint_trampoline";
+ *info = mono_tramp_info_create (tramp_name, buf, code - buf, ji, unwind_ops);
+
+ return buf;
+}
+
/*------------------------------------------------------------------*/
/* */
/* Name - mono_arch_patch_callsite */
stack size big enough to save our registers.
-----------------------------------------------------------*/
+ mono_add_unwind_op_def_cfa (unwind_ops, code, buf, STK_BASE, 0);
s390_stmg (buf, s390_r6, s390_r15, STK_BASE, S390_REG_SAVE_OFFSET);
+ offset = S390_REG_SAVE_OFFSET;
+ for (i = s390_r6; i < s390_r15; i++) {
+ mono_add_unwind_op_offset (unwind_ops, code, buf, i, offset);
+ offset += sizeof(uintptr_t);
+ }
+
s390_lgr (buf, s390_r11, s390_r15);
s390_aghi (buf, STK_BASE, -sizeof(trampStack_t));
+ mono_add_unwind_op_def_cfa_offset (unwind_ops, code, buf, sizeof(trampStack_t));
s390_stg (buf, s390_r11, 0, STK_BASE, 0);
/*---------------------------------------------------------------*/
* R14 contains the return address to our caller
*/
s390_lgr (buf, STK_BASE, s390_r11);
+ // mono_add_unwind_op_def_cfa_offset (unwind_ops, code, buf, -sizeof(trampStack_t));
s390_lmg (buf, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET);
if (MONO_TRAMPOLINE_TYPE_MUST_RETURN(tramp_type)) {