static CRITICAL_SECTION mini_arch_mutex;
static int v5_supported = 0;
+static int v6_supported = 0;
static int v7_supported = 0;
static int thumb_supported = 0;
/*
return code;
}
+/*
+ * emit_save_lmf:
+ *
+ * Emit code to push an LMF structure on the LMF stack.
+ * On arm, this is intermixed with the initialization of other fields of the structure.
+ */
+static guint8*
+emit_save_lmf (MonoCompile *cfg, guint8 *code, gint32 lmf_offset)
+{
+ gboolean get_lmf_fast = FALSE;
+
+#ifdef HAVE_AEABI_READ_TP
+ gint32 lmf_addr_tls_offset = mono_get_lmf_addr_tls_offset ();
+
+ if (lmf_addr_tls_offset != -1) {
+ get_lmf_fast = TRUE;
+
+ mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
+ (gpointer)"__aeabi_read_tp");
+ code = emit_call_seq (cfg, code);
+
+ ARM_LDR_IMM (code, ARMREG_R0, ARMREG_R0, lmf_addr_tls_offset);
+ get_lmf_fast = TRUE;
+ }
+#endif
+ if (!get_lmf_fast) {
+ mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
+ (gpointer)"mono_get_lmf_addr");
+ code = emit_call_seq (cfg, code);
+ }
+ /* we build the MonoLMF structure on the stack - see mini-arm.h */
+ /* lmf_offset is the offset from the previous stack pointer,
+ * alloc_size is the total stack space allocated, so the offset
+ * of MonoLMF from the current stack ptr is alloc_size - lmf_offset.
+ * The pointer to the struct is put in r1 (new_lmf).
+ * ip is used as scratch
+ * The callee-saved registers are already in the MonoLMF structure
+ */
+ code = emit_big_add (code, ARMREG_R1, ARMREG_SP, lmf_offset);
+ /* r0 is the result from mono_get_lmf_addr () */
+ ARM_STR_IMM (code, ARMREG_R0, ARMREG_R1, G_STRUCT_OFFSET (MonoLMF, lmf_addr));
+ /* new_lmf->previous_lmf = *lmf_addr */
+ ARM_LDR_IMM (code, ARMREG_IP, ARMREG_R0, G_STRUCT_OFFSET (MonoLMF, previous_lmf));
+ ARM_STR_IMM (code, ARMREG_IP, ARMREG_R1, G_STRUCT_OFFSET (MonoLMF, previous_lmf));
+ /* *(lmf_addr) = r1 */
+ ARM_STR_IMM (code, ARMREG_R1, ARMREG_R0, G_STRUCT_OFFSET (MonoLMF, previous_lmf));
+ /* Skip method (only needed for trampoline LMF frames) */
+ ARM_STR_IMM (code, ARMREG_SP, ARMREG_R1, G_STRUCT_OFFSET (MonoLMF, esp));
+ /* save the current IP */
+ ARM_MOV_REG_REG (code, ARMREG_IP, ARMREG_PC);
+ ARM_STR_IMM (code, ARMREG_IP, ARMREG_R1, G_STRUCT_OFFSET (MonoLMF, eip));
+
+ return code;
+}
+
+/*
+ * emit_save_lmf:
+ *
+ * Emit code to pop an LMF structure from the LMF stack.
+ */
+static guint8*
+emit_restore_lmf (MonoCompile *cfg, guint8 *code, gint32 lmf_offset)
+{
+ int basereg, offset;
+
+ if (lmf_offset < 32) {
+ basereg = cfg->frame_reg;
+ offset = lmf_offset;
+ } else {
+ basereg = ARMREG_R2;
+ offset = 0;
+ code = emit_big_add (code, ARMREG_R2, cfg->frame_reg, lmf_offset);
+ }
+
+ /* ip = previous_lmf */
+ ARM_LDR_IMM (code, ARMREG_IP, basereg, offset + G_STRUCT_OFFSET (MonoLMF, previous_lmf));
+ /* lr = lmf_addr */
+ ARM_LDR_IMM (code, ARMREG_LR, basereg, offset + G_STRUCT_OFFSET (MonoLMF, lmf_addr));
+ /* *(lmf_addr) = previous_lmf */
+ ARM_STR_IMM (code, ARMREG_IP, ARMREG_LR, G_STRUCT_OFFSET (MonoLMF, previous_lmf));
+
+ return code;
+}
+
#endif /* #ifndef DISABLE_JIT */
/*
thumb_supported = strstr (cpu_arch, "thumb") != NULL;
if (strncmp (cpu_arch, "armv", 4) == 0) {
v5_supported = cpu_arch [4] >= '5';
+ v6_supported = cpu_arch [4] >= '6';
v7_supported = cpu_arch [4] >= '7';
}
} else {
char *ver = strstr (line, "(v");
if (ver && (ver [2] == '5' || ver [2] == '6' || ver [2] == '7'))
v5_supported = TRUE;
+ if (ver && (ver [2] == '6' || ver [2] == '7'))
+ v6_supported = TRUE;
if (ver && (ver [2] == '7'))
v7_supported = TRUE;
continue;
guint16 vtsize; /* in param area */
guint8 reg;
ArgStorage storage;
+ gint32 struct_size;
guint8 size : 4; /* 1, 2, 4, 8, or regs used by RegTypeStructByVal */
} ArgInfo;
align_size &= ~(sizeof (gpointer) - 1);
nwords = (align_size + sizeof (gpointer) -1 ) / sizeof (gpointer);
cinfo->args [n].storage = RegTypeStructByVal;
+ cinfo->args [n].struct_size = size;
/* FIXME: align stack_size if needed */
if (eabi_supported) {
if (align >= 8 && (gr & 1))
header = cfg->header;
+ /* See mono_arch_get_global_int_regs () */
+ if (cfg->flags & MONO_CFG_HAS_CALLS)
+ cfg->uses_rgctx_reg = TRUE;
+
if (cfg->frame_reg != ARMREG_SP)
cfg->used_int_regs |= 1 << cfg->frame_reg;
ins->inst_p0 = call;
ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
+ mono_call_inst_add_outarg_vt (cfg, call, ins);
MONO_ADD_INS (cfg->cbb, ins);
break;
case RegTypeBase:
ArgInfo *ainfo = ins->inst_p1;
int ovf_size = ainfo->vtsize;
int doffset = ainfo->offset;
- int i, soffset, dreg;
+ int struct_size = ainfo->struct_size;
+ int i, soffset, dreg, tmpreg;
soffset = 0;
for (i = 0; i < ainfo->size; ++i) {
dreg = mono_alloc_ireg (cfg);
- MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
+ switch (struct_size) {
+ case 1:
+ MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, dreg, src->dreg, soffset);
+ break;
+ case 2:
+ MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, dreg, src->dreg, soffset);
+ break;
+ case 3:
+ tmpreg = mono_alloc_ireg (cfg);
+ MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, dreg, src->dreg, soffset);
+ MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, tmpreg, src->dreg, soffset + 1);
+ MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, tmpreg, tmpreg, 8);
+ MONO_EMIT_NEW_BIALU (cfg, OP_IOR, dreg, dreg, tmpreg);
+ MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, tmpreg, src->dreg, soffset + 2);
+ MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, tmpreg, tmpreg, 16);
+ MONO_EMIT_NEW_BIALU (cfg, OP_IOR, dreg, dreg, tmpreg);
+ break;
+ default:
+ MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
+ break;
+ }
mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg + i, FALSE);
soffset += sizeof (gpointer);
+ struct_size -= sizeof (gpointer);
}
//g_print ("vt size: %d at R%d + %d\n", doffset, vt->inst_basereg, vt->inst_offset);
if (ovf_size != 0)
- mini_emit_memcpy (cfg, ARMREG_SP, doffset, src->dreg, soffset, ovf_size * sizeof (gpointer), 0);
+ mini_emit_memcpy (cfg, ARMREG_SP, doffset, src->dreg, soffset, MIN (ovf_size * sizeof (gpointer), struct_size), struct_size < 4 ? 1 : 4);
}
void
{
ArchDynCallInfo *dinfo = (ArchDynCallInfo*)info;
DynCallArgs *p = (DynCallArgs*)buf;
- int arg_index, greg, i, j;
+ int arg_index, greg, i, j, pindex;
MonoMethodSignature *sig = dinfo->sig;
g_assert (buf_len >= sizeof (DynCallArgs));
arg_index = 0;
greg = 0;
+ pindex = 0;
+
+ if (sig->hasthis || dinfo->cinfo->vret_arg_index == 1) {
+ p->regs [greg ++] = (mgreg_t)*(args [arg_index ++]);
+ if (!sig->hasthis)
+ pindex = 1;
+ }
if (dinfo->cinfo->vtype_retaddr)
p->regs [greg ++] = (mgreg_t)ret;
- if (sig->hasthis)
- p->regs [greg ++] = (mgreg_t)*(args [arg_index ++]);
-
- for (i = 0; i < sig->param_count; i++) {
+ for (i = pindex; i < sig->param_count; i++) {
MonoType *t = mono_type_get_underlying_type (sig->params [i]);
gpointer *arg = args [arg_index ++];
ArgInfo *ainfo = &dinfo->cinfo->args [i + sig->hasthis];
}
static void
-handle_thunk (MonoDomain *domain, int absolute, guchar *code, const guchar *target)
+handle_thunk (MonoDomain *domain, int absolute, guchar *code, const guchar *target, MonoCodeManager *dyn_code_mp)
{
PatchData pdata;
pdata.absolute = absolute;
pdata.found = 0;
- mono_domain_lock (domain);
- mono_domain_code_foreach (domain, search_thunk_slot, &pdata);
+ if (dyn_code_mp) {
+ mono_code_manager_foreach (dyn_code_mp, search_thunk_slot, &pdata);
+ }
- if (!pdata.found) {
- /* this uses the first available slot */
- pdata.found = 2;
+ if (pdata.found != 1) {
+ mono_domain_lock (domain);
mono_domain_code_foreach (domain, search_thunk_slot, &pdata);
+
+ if (!pdata.found) {
+ /* this uses the first available slot */
+ pdata.found = 2;
+ mono_domain_code_foreach (domain, search_thunk_slot, &pdata);
+ }
+ mono_domain_unlock (domain);
}
- mono_domain_unlock (domain);
+ if (pdata.found != 1) {
+ GHashTable *hash;
+ GHashTableIter iter;
+ MonoJitDynamicMethodInfo *ji;
+
+ /*
+ * This might be a dynamic method, search its code manager. We can only
+ * use the dynamic method containing CODE, since the others might be freed later.
+ */
+ pdata.found = 0;
+
+ mono_domain_lock (domain);
+ hash = domain_jit_info (domain)->dynamic_code_hash;
+ if (hash) {
+ /* FIXME: Speed this up */
+ g_hash_table_iter_init (&iter, hash);
+ while (g_hash_table_iter_next (&iter, NULL, (gpointer*)&ji)) {
+ mono_code_manager_foreach (ji->code_mp, search_thunk_slot, &pdata);
+ if (pdata.found == 1)
+ break;
+ }
+ }
+ mono_domain_unlock (domain);
+ }
if (pdata.found != 1)
g_print ("thunk failed for %p from %p\n", target, code);
g_assert (pdata.found == 1);
}
static void
-arm_patch_general (MonoDomain *domain, guchar *code, const guchar *target)
+arm_patch_general (MonoDomain *domain, guchar *code, const guchar *target, MonoCodeManager *dyn_code_mp)
{
guint32 *code32 = (void*)code;
guint32 ins = *code32;
}
}
- handle_thunk (domain, TRUE, code, target);
+ handle_thunk (domain, TRUE, code, target, dyn_code_mp);
return;
}
void
arm_patch (guchar *code, const guchar *target)
{
- arm_patch_general (NULL, code, target);
+ arm_patch_general (NULL, code, target, NULL);
}
/*
switch (ins->opcode) {
case OP_MEMORY_BARRIER:
+ if (v6_supported) {
+ ARM_MOV_REG_IMM8 (code, ARMREG_R0, 0);
+ ARM_MCR (code, 15, 0, ARMREG_R0, 7, 10, 5);
+ }
break;
case OP_TLS_GET:
#ifdef HAVE_AEABI_READ_TP
break;
case OP_CHECK_THIS:
/* ensure ins->sreg1 is not NULL */
- ARM_LDR_IMM (code, ARMREG_LR, ins->sreg1, 0);
+ ARM_LDRB_IMM (code, ARMREG_LR, ins->sreg1, 0);
break;
case OP_ARGLIST: {
g_assert (cfg->sig_cookie < 128);
} while (0)
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;
gboolean compile_aot = !run_cctors;
default:
break;
}
- arm_patch_general (domain, ip, target);
+ arm_patch_general (domain, ip, target, dyn_code_mp);
}
}
code = emit_call_seq (cfg, code);
}
- if (method->save_lmf) {
- gboolean get_lmf_fast = FALSE;
-
-#ifdef HAVE_AEABI_READ_TP
- gint32 lmf_addr_tls_offset = mono_get_lmf_addr_tls_offset ();
-
- if (lmf_addr_tls_offset != -1) {
- get_lmf_fast = TRUE;
-
- mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
- (gpointer)"__aeabi_read_tp");
- code = emit_call_seq (cfg, code);
-
- ARM_LDR_IMM (code, ARMREG_R0, ARMREG_R0, lmf_addr_tls_offset);
- get_lmf_fast = TRUE;
- }
-#endif
- if (!get_lmf_fast) {
- mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
- (gpointer)"mono_get_lmf_addr");
- code = emit_call_seq (cfg, code);
- }
- /* we build the MonoLMF structure on the stack - see mini-arm.h */
- /* lmf_offset is the offset from the previous stack pointer,
- * alloc_size is the total stack space allocated, so the offset
- * of MonoLMF from the current stack ptr is alloc_size - lmf_offset.
- * The pointer to the struct is put in r1 (new_lmf).
- * r2 is used as scratch
- * The callee-saved registers are already in the MonoLMF structure
- */
- code = emit_big_add (code, ARMREG_R1, ARMREG_SP, alloc_size - lmf_offset);
- /* r0 is the result from mono_get_lmf_addr () */
- ARM_STR_IMM (code, ARMREG_R0, ARMREG_R1, G_STRUCT_OFFSET (MonoLMF, lmf_addr));
- /* new_lmf->previous_lmf = *lmf_addr */
- ARM_LDR_IMM (code, ARMREG_R2, ARMREG_R0, G_STRUCT_OFFSET (MonoLMF, previous_lmf));
- ARM_STR_IMM (code, ARMREG_R2, ARMREG_R1, G_STRUCT_OFFSET (MonoLMF, previous_lmf));
- /* *(lmf_addr) = r1 */
- ARM_STR_IMM (code, ARMREG_R1, ARMREG_R0, G_STRUCT_OFFSET (MonoLMF, previous_lmf));
- /* Skip method (only needed for trampoline LMF frames) */
- ARM_STR_IMM (code, ARMREG_SP, ARMREG_R1, G_STRUCT_OFFSET (MonoLMF, esp));
- /* save the current IP */
- ARM_MOV_REG_REG (code, ARMREG_R2, ARMREG_PC);
- ARM_STR_IMM (code, ARMREG_R2, ARMREG_R1, G_STRUCT_OFFSET (MonoLMF, eip));
- }
+ if (method->save_lmf)
+ code = emit_save_lmf (cfg, code, alloc_size - lmf_offset);
if (tracing)
code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
cfg->code_size *= 2;
cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
- mono_jit_stats.code_reallocs++;
+ cfg->stat_code_reallocs++;
}
/*
/* all but r0-r3, sp and pc */
pos += sizeof (MonoLMF) - (MONO_ARM_NUM_SAVED_REGS * sizeof (mgreg_t));
lmf_offset = pos;
- /* r2 contains the pointer to the current LMF */
- code = emit_big_add (code, ARMREG_R2, cfg->frame_reg, cfg->stack_usage - lmf_offset);
- /* ip = previous_lmf */
- ARM_LDR_IMM (code, ARMREG_IP, ARMREG_R2, G_STRUCT_OFFSET (MonoLMF, previous_lmf));
- /* lr = lmf_addr */
- ARM_LDR_IMM (code, ARMREG_LR, ARMREG_R2, G_STRUCT_OFFSET (MonoLMF, lmf_addr));
- /* *(lmf_addr) = previous_lmf */
- ARM_STR_IMM (code, ARMREG_IP, ARMREG_LR, G_STRUCT_OFFSET (MonoLMF, previous_lmf));
+
+ code = emit_restore_lmf (cfg, code, cfg->stack_usage - lmf_offset);
+
/* This points to r4 inside MonoLMF->iregs */
sp_adj = (sizeof (MonoLMF) - MONO_ARM_NUM_SAVED_REGS * sizeof (mgreg_t));
reg = ARMREG_R4;
reg ++;
}
/* point sp at the registers to restore: 10 is 14 -4, because we skip r0-r3 */
- ARM_ADD_REG_IMM8 (code, ARMREG_SP, ARMREG_R2, sp_adj);
+ code = emit_big_add (code, ARMREG_SP, cfg->frame_reg, cfg->stack_usage - lmf_offset + sp_adj);
/* restore iregs */
ARM_POP (code, regmask);
} else {
while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
cfg->code_size *= 2;
cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
- mono_jit_stats.code_reallocs++;
+ cfg->stat_code_reallocs++;
}
code = cfg->native_code + cfg->code_len;
#endif
-gpointer
+mgreg_t
mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
{
if (reg == ARMREG_SP)
- return (gpointer)ctx->esp;
+ return ctx->esp;
else
- return (gpointer)ctx->regs [reg];
+ return ctx->regs [reg];
+}
+
+void
+mono_arch_context_set_int_reg (MonoContext *ctx, int reg, mgreg_t val)
+{
+ if (reg == ARMREG_SP)
+ ctx->esp = val;
+ else
+ ctx->regs [reg] = val;
}
/*
mono_arch_set_target (char *mtriple)
{
/* The GNU target triple format is not very well documented */
- if (strstr (mtriple, "armv7"))
+ if (strstr (mtriple, "armv7")) {
+ v6_supported = TRUE;
v7_supported = TRUE;
+ }
+ if (strstr (mtriple, "armv6")) {
+ v6_supported = TRUE;
+ }
if (strstr (mtriple, "darwin")) {
v5_supported = TRUE;
thumb_supported = TRUE;