#include <string.h>
#include <asm/cachectl.h>
+#include <mono/metadata/abi-details.h>
#include <mono/metadata/appdomain.h>
#include <mono/metadata/debug-helpers.h>
#include <mono/utils/mono-mmap.h>
+#include <mono/utils/mono-hwcap-mips.h>
#include <mono/arch/mips/mips-codegen.h>
#include "ir-emit.h"
#define SAVE_FP_REGS 0
-#define SAVE_ALL_REGS 0
-#define EXTRA_STACK_SPACE 0 /* suppresses some s-reg corruption issues */
-#define SAVE_LMF 1
-#define ALWAYS_USE_FP 1
#define ALWAYS_SAVE_RA 1 /* call-handler & switch currently clobber ra */
#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 */
+#define USE_MUL 0 /* use mul instead of mult/mflo for multiply
+ remember to update cpu-mips.md if you change this */
/* Emit a call sequence to 'v', using 'D' as a scratch register if necessary */
#define mips_call(c,D,v) do { \
};
/* This mutex protects architecture specific caches */
-#define mono_mini_arch_lock() EnterCriticalSection (&mini_arch_mutex)
-#define mono_mini_arch_unlock() LeaveCriticalSection (&mini_arch_mutex)
-static CRITICAL_SECTION mini_arch_mutex;
+#define mono_mini_arch_lock() mono_mutex_lock (&mini_arch_mutex)
+#define mono_mini_arch_unlock() mono_mutex_unlock (&mini_arch_mutex)
+static mono_mutex_t mini_arch_mutex;
int mono_exc_esp_offset = 0;
static int tls_mode = TLS_MODE_DETECT;
static int lmf_pthread_key = -1;
static int monothread_key = -1;
-static int monodomain_key = -1;
/* Whenever the host is little-endian */
static int little_endian;
}
#endif
+static void mono_arch_compute_omit_fp (MonoCompile *cfg);
+
const char*
mono_arch_regname (int reg) {
#if _MIPS_SIM == _ABIO32
arg_info [0].size = frame_size;
for (k = 0; k < param_count; k++) {
- size = mini_type_stack_size_full (NULL, csig->params [k], &align, csig->pinvoke);
+ size = mini_type_stack_size_full (csig->params [k], &align, csig->pinvoke);
/* ignore alignment for now */
align = 1;
return frame_size;
}
-#define MAX_ARCH_DELEGATE_PARAMS 4
+/* The delegate object plus 3 params */
+#define MAX_ARCH_DELEGATE_PARAMS (4 - 1)
static gpointer
-get_delegate_invoke_impl (gboolean has_target, gboolean param_count, guint32 *code_size)
+get_delegate_invoke_impl (MonoTrampInfo **info, gboolean has_target, gboolean param_count)
{
guint8 *code, *start;
start = code = mono_global_codeman_reserve (16);
/* Replace the this argument with the target */
- mips_lw (code, mips_temp, mips_a0, G_STRUCT_OFFSET (MonoDelegate, method_ptr));
- mips_lw (code, mips_a0, mips_a0, G_STRUCT_OFFSET (MonoDelegate, target));
+ mips_lw (code, mips_temp, mips_a0, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr));
+ mips_lw (code, mips_a0, mips_a0, MONO_STRUCT_OFFSET (MonoDelegate, target));
mips_jr (code, mips_temp);
mips_nop (code);
size = 16 + param_count * 4;
start = code = mono_global_codeman_reserve (size);
- mips_lw (code, mips_temp, mips_a0, G_STRUCT_OFFSET (MonoDelegate, method_ptr));
+ mips_lw (code, mips_temp, mips_a0, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr));
/* slide down the arguments */
for (i = 0; i < param_count; ++i) {
mips_move (code, mips_a0 + i, mips_a0 + i + 1);
mono_arch_flush_icache (start, size);
}
- if (code_size)
- *code_size = code - start;
+ 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);
+ *info = mono_tramp_info_create (name, start, code - start, NULL, NULL);
+ g_free (name);
+ }
return start;
}
mono_arch_get_delegate_invoke_impls (void)
{
GSList *res = NULL;
- guint8 *code;
- guint32 code_len;
+ MonoTrampInfo *info;
int i;
- code = get_delegate_invoke_impl (TRUE, 0, &code_len);
- res = g_slist_prepend (res, mono_tramp_info_create (g_strdup ("delegate_invoke_impl_has_target"), code, code_len, NULL, NULL));
+ get_delegate_invoke_impl (&info, TRUE, 0);
+ res = g_slist_prepend (res, info);
for (i = 0; i <= MAX_ARCH_DELEGATE_PARAMS; ++i) {
- code = get_delegate_invoke_impl (FALSE, i, &code_len);
- res = g_slist_prepend (res, mono_tramp_info_create (g_strdup_printf ("delegate_invoke_impl_target_%d", i), code, code_len, NULL, NULL));
+ get_delegate_invoke_impl (&info, FALSE, i);
+ res = g_slist_prepend (res, info);
}
return res;
return cached;
}
- if (mono_aot_only)
+ if (mono_aot_only) {
start = mono_aot_get_trampoline ("delegate_invoke_impl_has_target");
- else
- start = get_delegate_invoke_impl (TRUE, 0, NULL);
+ } else {
+ MonoTrampInfo *info;
+ start = get_delegate_invoke_impl (&info, TRUE, 0);
+ mono_tramp_info_register (info, NULL);
+ }
cached = start;
mono_mini_arch_unlock ();
return cached;
start = mono_aot_get_trampoline (name);
g_free (name);
} else {
- start = get_delegate_invoke_impl (FALSE, sig->param_count, NULL);
+ MonoTrampInfo *info;
+ start = get_delegate_invoke_impl (&info, FALSE, sig->param_count);
+ mono_tramp_info_register (info, NULL);
}
cache [sig->param_count] = start;
mono_mini_arch_unlock ();
return NULL;
}
+gpointer
+mono_arch_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method, int offset, gboolean load_imt_reg)
+{
+ return NULL;
+}
+
gpointer
mono_arch_get_this_arg_from_call (mgreg_t *regs, guint8 *code)
{
void
mono_arch_init (void)
{
- InitializeCriticalSection (&mini_arch_mutex);
+ mono_mutex_init_recursive (&mini_arch_mutex);
ss_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT);
bp_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT);
void
mono_arch_cleanup (void)
{
- DeleteCriticalSection (&mini_arch_mutex);
+ mono_mutex_destroy (&mini_arch_mutex);
}
/*
* This function returns the optimizations supported on this cpu.
*/
guint32
-mono_arch_cpu_optimizazions (guint32 *exclude_mask)
+mono_arch_cpu_optimizations (guint32 *exclude_mask)
{
guint32 opts = 0;
return opts;
}
+/*
+ * This function test for all SIMD functions supported.
+ *
+ * Returns a bitmask corresponding to all supported versions.
+ *
+ */
+guint32
+mono_arch_cpu_enumerate_simd_versions (void)
+{
+ /* SIMD is currently unimplemented */
+ return 0;
+}
+
GList *
mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
{
#endif
static CallInfo*
-get_call_info (MonoGenericSharingContext *gsctx, MonoMemPool *mp, MonoMethodSignature *sig)
+get_call_info (MonoMemPool *mp, MonoMethodSignature *sig)
{
guint i;
int n = sig->hasthis + sig->param_count;
* are sometimes made using calli without sig->hasthis set, like in the delegate
* invoke wrappers.
*/
- if (cinfo->vtype_retaddr && !is_pinvoke && (sig->hasthis || (sig->param_count > 0 && MONO_TYPE_IS_REFERENCE (mini_type_get_underlying_type (NULL, sig->params [0]))))) {
+ if (cinfo->vtype_retaddr && !is_pinvoke && (sig->hasthis || (sig->param_count > 0 && MONO_TYPE_IS_REFERENCE (mini_get_underlying_type (sig->params [0]))))) {
if (sig->hasthis) {
add_int32_arg (cinfo, cinfo->args + n);
n ++;
add_int32_arg (cinfo, &cinfo->sig_cookie);
}
DEBUG(printf("param %d: ", i));
- simpletype = mini_type_get_underlying_type (NULL, sig->params [i]);
+ simpletype = mini_get_underlying_type (sig->params [i]);
switch (simpletype->type) {
case MONO_TYPE_BOOLEAN:
case MONO_TYPE_I1:
}
{
- simpletype = mono_type_get_underlying_type (sig->ret);
+ simpletype = mini_get_underlying_type (sig->ret);
switch (simpletype->type) {
case MONO_TYPE_BOOLEAN:
case MONO_TYPE_I1:
return cinfo;
}
+static gboolean
+debug_omit_fp (void)
+{
+#if 0
+ return mono_debug_count ();
+#else
+ return TRUE;
+#endif
+}
+
+/**
+ * mono_arch_compute_omit_fp:
+ *
+ * Determine whenever the frame pointer can be eliminated.
+ */
+static void
+mono_arch_compute_omit_fp (MonoCompile *cfg)
+{
+ MonoMethodSignature *sig;
+ MonoMethodHeader *header;
+ int i, locals_size;
+ CallInfo *cinfo;
+
+ if (cfg->arch.omit_fp_computed)
+ return;
+
+ header = cfg->header;
+
+ sig = mono_method_signature (cfg->method);
+
+ if (!cfg->arch.cinfo)
+ cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
+ cinfo = cfg->arch.cinfo;
+
+ /*
+ * FIXME: Remove some of the restrictions.
+ */
+ cfg->arch.omit_fp = TRUE;
+ cfg->arch.omit_fp_computed = TRUE;
+
+ if (cfg->disable_omit_fp)
+ cfg->arch.omit_fp = FALSE;
+ if (!debug_omit_fp ())
+ cfg->arch.omit_fp = FALSE;
+ if (cfg->method->save_lmf)
+ cfg->arch.omit_fp = FALSE;
+ if (cfg->flags & MONO_CFG_HAS_ALLOCA)
+ cfg->arch.omit_fp = FALSE;
+ if (header->num_clauses)
+ cfg->arch.omit_fp = FALSE;
+ if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG))
+ cfg->arch.omit_fp = FALSE;
+ if ((mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method)) ||
+ (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE))
+ cfg->arch.omit_fp = FALSE;
+ /*
+ * On MIPS, fp points to the bottom of the frame, so it can be eliminated even if
+ * there are stack arguments.
+ */
+ /*
+ if (cinfo->stack_usage)
+ cfg->arch.omit_fp = FALSE;
+ */
+
+ locals_size = 0;
+ for (i = cfg->locals_start; i < cfg->num_varinfo; i++) {
+ MonoInst *ins = cfg->varinfo [i];
+ int ialign;
+
+ locals_size += mono_type_size (ins->inst_vtype, &ialign);
+ }
+
+ //printf ("D: %s %d\n", cfg->method->name, cfg->arch.omit_fp);
+}
/*
* Set var information according to the calling convention. mips version.
sig = mono_method_signature (cfg->method);
if (!cfg->arch.cinfo)
- cfg->arch.cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig);
+ cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
cinfo = cfg->arch.cinfo;
+ mono_arch_compute_omit_fp (cfg);
+
/* spill down, we'll fix it in a separate pass */
// cfg->flags |= MONO_CFG_HAS_SPILLUP;
header = cfg->header;
- /*
- * We use the frame register also for any method that has
- * exception clauses. This way, when the handlers are called,
- * the code will reference local variables using the frame reg instead of
- * the stack pointer: if we had to restore the stack pointer, we'd
- * corrupt the method frames that are already on the stack (since
- * filters get called before stack unwinding happens) when the filter
- * code would call any method (this also applies to finally etc.).
- */
-
- if ((cfg->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses || ALWAYS_USE_FP)
+ if (cfg->arch.omit_fp)
+ frame_reg = mips_sp;
+ else
frame_reg = mips_fp;
cfg->frame_reg = frame_reg;
if (frame_reg != mips_sp) {
curinst = 0;
if (!MONO_TYPE_ISSTRUCT (sig->ret)) {
/* FIXME: handle long and FP values */
- switch (mono_type_get_underlying_type (sig->ret)->type) {
+ switch (mini_get_underlying_type (sig->ret)->type) {
case MONO_TYPE_VOID:
break;
case MONO_TYPE_R4:
if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
offset += 8;
- if (sig->call_convention == MONO_CALL_VARARG)
- cfg->sig_cookie = MIPS_STACK_PARAM_OFFSET;
-
/* Now handle the local variables */
curinst = cfg->locals_start;
}
/* Space for LMF (if needed) */
-#if SAVE_LMF
if (cfg->method->save_lmf) {
/* align the offset to 16 bytes */
offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
cfg->arch.lmf_offset = offset;
offset += sizeof (MonoLMF);
}
-#endif
if (sig->call_convention == MONO_CALL_VARARG) {
size = 4;
offset += size;
}
- /*
- * FIXME: - Saved S-regs seem to be getting clobbered by some calls with struct
- * args or return vals. Extra stack space avoids this in a lot of cases.
- */
- offset += EXTRA_STACK_SPACE;
offset += SIZEOF_REGISTER - 1;
offset &= ~(SIZEOF_REGISTER - 1);
/* Space for saved registers */
cfg->arch.iregs_offset = offset;
-#if SAVE_ALL_REGS
- iregs_to_save = MONO_ARCH_CALLEE_SAVED_REGS;
-#else
iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
-#endif
if (iregs_to_save) {
for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
if (iregs_to_save & (1 << i)) {
sig = call->signature;
n = sig->param_count + sig->hasthis;
- cinfo = get_call_info (NULL, cfg->mempool, sig);
+ cinfo = get_call_info (cfg->mempool, sig);
if (cinfo->struct_ret)
call->used_iregs |= 1 << cinfo->struct_ret;
t = sig->params [i - sig->hasthis];
else
t = &mono_defaults.int_class->byval_arg;
- t = mini_type_get_underlying_type (cfg->generic_sharing_context, t);
+ t = mini_get_underlying_type (t);
if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
/* Emit the signature cookie just before the implicit arguments */
size = mono_type_native_stack_size (&src->klass->byval_arg, NULL);
vtcopy->backend.is_pinvoke = 1;
} else {
- size = mini_type_stack_size (cfg->generic_sharing_context, &src->klass->byval_arg, NULL);
+ size = mini_type_stack_size (&src->klass->byval_arg, NULL);
}
if (size > 0)
g_assert (ovf_size > 0);
void
mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
{
- MonoType *ret = mini_type_get_underlying_type (cfg->generic_sharing_context,
- mono_method_signature (method)->ret);
+ MonoType *ret = mini_get_underlying_type (mono_method_signature (method)->ret);
if (!ret->byref) {
#if (SIZEOF_REGISTER == 4)
sig = mono_method_signature (method);
if (!cfg->arch.cinfo)
- cfg->arch.cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig);
+ cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
cinfo = cfg->arch.cinfo;
if (cinfo->struct_ret) {
if (ppc_is_imm16 (-size)) {
ppc_stwu (code, ppc_r0, -size, ppc_sp);
} else {
- ppc_load (code, ppc_r11, -size);
- ppc_stwux (code, ppc_r0, ppc_sp, ppc_r11);
+ ppc_load (code, ppc_r12, -size);
+ ppc_stwux (code, ppc_r0, ppc_sp, ppc_r12);
}
#endif
return code;
if (ppc_is_imm16 (size)) {
ppc_stwu (code, ppc_r0, size, ppc_sp);
} else {
- ppc_load (code, ppc_r11, size);
- ppc_stwux (code, ppc_r0, ppc_sp, ppc_r11);
+ ppc_load (code, ppc_r12, size);
+ ppc_stwux (code, ppc_r0, ppc_sp, ppc_r12);
}
#endif
return code;
case OP_NOT_REACHED:
case OP_NOT_NULL:
break;
+ case OP_IL_SEQ_POINT:
+ mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
+ break;
case OP_SEQ_POINT: {
if (ins->flags & MONO_INST_SINGLE_STEP_LOC) {
guint32 addr = (guint32)ss_trigger_page;
mips_mfhi (code, ins->dreg+1);
break;
case OP_MEMORY_BARRIER:
-#if 0
- ppc_sync (code);
-#endif
+ mips_sync (code, 0);
break;
case OP_STOREI1_MEMBASE_IMM:
mips_load_const (code, mips_temp, ins->inst_imm);
case OP_DIV_IMM:
g_assert_not_reached ();
#if 0
- ppc_load (code, ppc_r11, ins->inst_imm);
- ppc_divwod (code, ins->dreg, ins->sreg1, ppc_r11);
+ ppc_load (code, ppc_r12, ins->inst_imm);
+ ppc_divwod (code, ins->dreg, ins->sreg1, ppc_r12);
ppc_mfspr (code, ppc_r0, ppc_xer);
ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
/* FIXME: use OverflowException for 0x80000000/-1 */
mips_fmovd (code, ins->dreg, ins->sreg1);
}
break;
+ case OP_MOVE_F_TO_I4:
+ mips_cvtsd (code, mips_ftemp, ins->sreg1);
+ mips_mfc1 (code, ins->dreg, mips_ftemp);
+ break;
+ case OP_MOVE_I4_TO_F:
+ mips_mtc1 (code, ins->dreg, ins->sreg1);
+ mips_cvtds (code, ins->dreg, ins->dreg);
+ break;
case OP_MIPS_CVTSD:
/* Convert from double to float and leave it there */
mips_cvtsd (code, ins->dreg, ins->sreg1);
mips_addiu (code, ins->dreg, mips_sp, area_offset);
if (ins->flags & MONO_INST_INIT) {
+ guint32 *buf;
+
+ buf = (guint32*)(void*)code;
+ mips_beq (code, mips_at, mips_zero, 0);
+ mips_nop (code);
+
mips_move (code, mips_temp, ins->dreg);
mips_sb (code, mips_zero, mips_temp, 0);
mips_addiu (code, mips_at, mips_at, -1);
mips_bne (code, mips_at, mips_zero, -3);
mips_addiu (code, mips_temp, mips_temp, 1);
+
+ mips_patch (buf, (guint32)code);
}
break;
}
}
void
-mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, MonoCodeManager *dyn_code_mp, gboolean run_cctors)
+mono_arch_patch_code (MonoCompile *cfg, MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
{
MonoJumpInfo *patch_info;
}
}
-#if 0
-static
-void
-mono_trace_lmf_prolog (MonoLMF *new_lmf)
-{
-}
-
-static
-void
-mono_trace_lmf_epilog (MonoLMF *old_lmf)
-{
-}
-#endif
-
/*
* Allow tracing to work with this interface (with an optional argument)
*
mips_nop (code);
mips_nop (code);
- /* For N32, need to know for each stack slot if it's an integer
- * or float argument, and save/restore the appropriate register
- */
MIPS_SW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
MIPS_SW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
MIPS_SW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
MIPS_SW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
#if _MIPS_SIM == _ABIN32
+ NOT_IMPLEMENTED;
+ /* FIXME: Need a separate region for these */
MIPS_SW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
MIPS_SW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
MIPS_SW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
MIPS_SW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
+ */
#endif
mips_load_const (code, mips_a0, cfg->method);
mips_addiu (code, mips_a1, mips_sp, offset);
mips_call (code, mips_t9, func);
+ mips_nop (code);
MIPS_LW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
MIPS_LW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
MIPS_LW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
MIPS_LW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
#if _MIPS_SIM == _ABIN32
+ NOT_IMPLEMENTED;
+ /*
MIPS_LW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
MIPS_LW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
MIPS_LW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
MIPS_LW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
+ */
#endif
mips_nop (code);
break;
}
}
- if (((ins->opcode == OP_ADD_IMM) || (ins->opcode == OP_IADD_IMM)) && (ins->sreg1 == mips_fp))
+ if (((ins->opcode == OP_ADD_IMM) || (ins->opcode == OP_IADD_IMM)) && (ins->sreg1 == cfg->frame_reg))
adj_imm = 1;
if (adj_c0) {
if (ins->inst_c0 >= threshold) {
#if SAVE_FP_REGS
guint32 fregs_to_save = 0;
#endif
-#if SAVE_LMF
/* lmf_offset is the offset of the LMF from our stack pointer. */
guint32 lmf_offset = cfg->arch.lmf_offset;
-#endif
int cfa_offset = 0;
MonoBasicBlock *bb;
if (max_offset > 0xffff)
cfg->arch.long_branch = TRUE;
- if (tracing) {
-#if _MIPS_SIM == _ABIO32
- cfg->arch.tracing_offset = cfg->stack_offset;
-#elif _MIPS_SIM == _ABIN32
- /* no stack slots by default for argument regs, reserve a special block */
- cfg->arch.tracing_offset = cfg->stack_offset;
- cfg->stack_offset += 8 * SIZEOF_REGISTER;
-#endif
- }
-
/*
* Currently, fp points to the bottom of the frame on MIPS, unlike other platforms.
* This means that we have to adjust the offsets inside instructions which reference
alloc_size = cfg->stack_offset;
cfg->stack_usage = alloc_size;
-#if SAVE_ALL_REGS
- iregs_to_save = MONO_ARCH_CALLEE_SAVED_REGS;
-#else
iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
-#endif
#if SAVE_FP_REGS
#if 0
fregs_to_save = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
}
}
}
-#if SAVE_LMF
+
+ // FIXME: Don't save registers twice if there is an LMF
+ // s8 has to be special cased since it is overwritten with the updated value
+ // below
if (method->save_lmf) {
for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[i]);
g_assert (mips_is_imm16(offset));
- MIPS_SW (code, i, mips_sp, offset);
+ if (MIPS_LMF_IREGMASK & (1 << i))
+ MIPS_SW (code, i, mips_sp, offset);
}
}
-#endif
#if SAVE_FP_REGS
/* Save float registers */
}
}
}
-#if SAVE_LMF
+
if (method->save_lmf) {
for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, fregs[i]);
mips_swc1 (code, i, mips_sp, offset);
}
}
-#endif
+
#endif
if (cfg->frame_reg != mips_sp) {
MIPS_MOVE (code, cfg->frame_reg, mips_sp);
mono_emit_unwind_op_def_cfa (cfg, code, cfg->frame_reg, cfa_offset);
-#if SAVE_LMF
+
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
}
- /* Do instrumentation before assigning regvars to registers. Because they may be assigned
- * to the t* registers, which would be clobbered by the instrumentation calls.
- */
- if (tracing) {
- code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
- }
+ /* store runtime generic context */
+ if (cfg->rgctx_var) {
+ MonoInst *ins = cfg->rgctx_var;
+ g_assert (ins->opcode == OP_REGOFFSET);
+
+ g_assert (mips_is_imm16 (ins->inst_offset));
+ mips_sw (code, MONO_ARCH_RGCTX_REG, ins->inst_basereg, ins->inst_offset);
+ }
/* load arguments allocated to register from the stack */
pos = 0;
if (!cfg->arch.cinfo)
- cfg->arch.cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig);
+ cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
cinfo = cfg->arch.cinfo;
if (MONO_TYPE_ISSTRUCT (sig->ret)) {
g_print ("stack slot at %d of %d+%d\n",
inst->inst_offset, alloc_size, alloc2_size);
/* g_assert (inst->inst_offset >= alloc_size); */
- g_assert (inst->inst_basereg == mips_fp);
+ g_assert (inst->inst_basereg == cfg->frame_reg);
basereg_offset = inst->inst_offset - alloc2_size;
g_assert (mips_is_imm16 (basereg_offset));
switch (ainfo->size) {
pos++;
}
- if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
- mips_load_const (code, mips_a0, cfg->domain);
- mips_call (code, mips_t9, (gpointer)mono_jit_thread_attach);
- }
-
-#if SAVE_LMF
if (method->save_lmf) {
mips_load_const (code, mips_at, MIPS_LMF_MAGIC1);
mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, magic));
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 */
mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
mips_load_const (code, mips_at, 0x01010101);
mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, eip));
}
-#endif
+
if (alloc2_size) {
- /* The CFA is fp now, so this doesn't need unwind info */
if (mips_is_imm16 (-alloc2_size)) {
mips_addu (code, mips_sp, mips_sp, -alloc2_size);
}
mips_load_const (code, mips_at, -alloc2_size);
mips_addu (code, mips_sp, mips_sp, mips_at);
}
+ alloc_size += alloc2_size;
+ cfa_offset += alloc2_size;
if (cfg->frame_reg != mips_sp)
MIPS_MOVE (code, cfg->frame_reg, mips_sp);
- alloc_size += alloc2_size;
+ else
+ mono_emit_unwind_op_def_cfa_offset (cfg, code, cfa_offset);
+ }
+
+ if (tracing) {
+#if _MIPS_SIM == _ABIO32
+ cfg->arch.tracing_offset = cfg->stack_offset;
+#elif _MIPS_SIM == _ABIN32
+ /* no stack slots by default for argument regs, reserve a special block */
+ g_assert_not_reached ();
+#endif
+ code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
}
cfg->code_len = code - cfg->native_code;
int save_mode = SAVE_NONE;
int offset;
MonoMethod *method = cfg->method;
- int rtype = mono_type_get_underlying_type (mono_method_signature (method)->ret)->type;
+ int rtype = mini_get_underlying_type (mono_method_signature (method)->ret)->type;
int save_offset = MIPS_STACK_PARAM_OFFSET;
g_assert ((save_offset & (MIPS_STACK_ALIGNMENT-1)) == 0);
guint32 fregs_to_restore;
#endif
-#if SAVE_LMF
if (cfg->method->save_lmf)
max_epilog_size += 128;
-#endif
if (mono_jit_trace_calls != NULL)
max_epilog_size += 50;
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
iregs_to_restore = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
-#endif
if (iregs_to_restore) {
for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
if (iregs_to_restore & (1 << i)) {
}
}
#endif
-#if SAVE_LMF
+
/* Unlink the LMF if necessary */
if (method->save_lmf) {
int lmf_offset = cfg->arch.lmf_offset;
/* (*lmf_addr) = previous_lmf */
mips_sw (code, mips_temp, mips_t1, 0);
}
-#endif
+
#if 0
/* Restore the fp */
mips_lw (code, mips_fp, mips_sp, cfg->stack_usage + MIPS_FP_ADDR_OFFSET);
}
#endif
}
- if (monodomain_key == -1) {
- ptk = mono_domain_get_tls_key ();
- if (ptk < 1024)
- monodomain_key = ptk;
- }
if (lmf_pthread_key == -1) {
ptk = mono_jit_tls_id;
if (ptk < 1024) {
}
void
-mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
+mono_arch_finish_init (void)
{
setup_tls_access ();
}
/* add the this argument */
if (this_reg != -1) {
- MonoInst *this;
- MONO_INST_NEW (cfg, this, OP_MOVE);
- this->type = this_type;
- this->sreg1 = this_reg;
- this->dreg = mono_alloc_ireg (cfg);
- mono_bblock_add_inst (cfg->cbb, this);
- mono_call_inst_add_outarg_reg (cfg, inst, this->dreg, this_dreg, FALSE);
+ MonoInst *this_ins;
+ MONO_INST_NEW (cfg, this_ins, OP_MOVE);
+ this_ins->type = this_type;
+ this_ins->sreg1 = this_reg;
+ this_ins->dreg = mono_alloc_ireg (cfg);
+ mono_bblock_add_inst (cfg->cbb, this_ins);
+ mono_call_inst_add_outarg_reg (cfg, inst, this_ins->dreg, this_dreg, FALSE);
}
if (vt_reg != -1) {
return 0;
}
-MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
-{
- MonoInst* ins;
-
- setup_tls_access ();
- if (monodomain_key == -1)
- return NULL;
-
- MONO_INST_NEW (cfg, ins, OP_TLS_GET);
- ins->inst_offset = monodomain_key;
- return ins;
-}
-
mgreg_t
mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
{
return ctx->sc_regs [reg];
}
-#ifdef MONO_ARCH_HAVE_IMT
-
#define ENABLE_WRONG_METHOD_CHECK 0
#define MIPS_LOAD_SEQUENCE_LENGTH 8
mono_stats.imt_thunks_size += code - start;
g_assert (code - start <= size);
mono_arch_flush_icache (start, size);
+
+ mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, NULL), domain);
+
return start;
}
{
return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
}
-#endif
MonoVTable*
mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
{
- NOT_IMPLEMENTED;
return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG];
}
return NULL;
}
+void
+mono_arch_init_lmf_ext (MonoLMFExt *ext, gpointer prev_lmf)
+{
+ ext->lmf.previous_lmf = prev_lmf;
+ /* Mark that this is a MonoLMFExt */
+ ext->lmf.previous_lmf = (gpointer)(((gssize)ext->lmf.previous_lmf) | 2);
+ ext->lmf.iregs [mips_sp] = (gssize)ext;
+}
+
#endif /* MONO_ARCH_SOFT_DEBUG_SUPPORTED */
+
+gboolean
+mono_arch_opcode_supported (int opcode)
+{
+ return FALSE;
+}