Merge pull request #1225 from strawd/bug22307
[mono.git] / mono / mini / mini-mips.c
index 5fe1a4a91b8278382c6970fbecfce254a3b296d9..362fa3a14bac36bfaf82a57b24611e83821e706b 100644 (file)
 #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 {  \
@@ -58,15 +57,14 @@ enum {
 };
 
 /* 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;
@@ -423,6 +421,8 @@ offsets_from_pthread_key (guint32 key, int *offset2)
 }
 #endif
 
+static void mono_arch_compute_omit_fp (MonoCompile *cfg);
+
 const char*
 mono_arch_regname (int reg) {
 #if _MIPS_SIM == _ABIO32
@@ -518,7 +518,7 @@ mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJit
        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;
@@ -540,10 +540,11 @@ mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJit
        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;
 
@@ -551,8 +552,8 @@ get_delegate_invoke_impl (gboolean has_target, gboolean param_count, guint32 *co
                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);
 
@@ -565,7 +566,7 @@ get_delegate_invoke_impl (gboolean has_target, gboolean param_count, guint32 *co
                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);
@@ -578,8 +579,13 @@ get_delegate_invoke_impl (gboolean has_target, gboolean param_count, guint32 *co
                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;
 }
@@ -594,16 +600,15 @@ GSList*
 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;
@@ -626,10 +631,13 @@ mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_targe
                        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;
@@ -655,7 +663,9 @@ mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_targe
                        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 ();
@@ -665,6 +675,12 @@ mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_targe
        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)
 {
@@ -697,7 +713,7 @@ mono_arch_cpu_init (void)
 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);
@@ -710,14 +726,14 @@ mono_arch_init (void)
 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;
 
@@ -726,6 +742,19 @@ mono_arch_cpu_optimizazions (guint32 *exclude_mask)
        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)
 {
@@ -1031,7 +1060,7 @@ add_float64_arg (CallInfo *info, ArgInfo *ainfo) {
 #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;
@@ -1073,7 +1102,7 @@ get_call_info (MonoGenericSharingContext *gsctx, MonoMemPool *mp, MonoMethodSign
         * 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 ++;
@@ -1108,7 +1137,7 @@ get_call_info (MonoGenericSharingContext *gsctx, MonoMemPool *mp, MonoMethodSign
                        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:
@@ -1255,7 +1284,7 @@ get_call_info (MonoGenericSharingContext *gsctx, MonoMemPool *mp, MonoMethodSign
        }
 
        {
-               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:
@@ -1308,6 +1337,80 @@ get_call_info (MonoGenericSharingContext *gsctx, MonoMemPool *mp, MonoMethodSign
        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.
@@ -1330,9 +1433,11 @@ mono_arch_allocate_vars (MonoCompile *cfg)
        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;
 
@@ -1358,17 +1463,9 @@ mono_arch_allocate_vars (MonoCompile *cfg)
 
        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) {
@@ -1379,7 +1476,7 @@ mono_arch_allocate_vars (MonoCompile *cfg)
        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:
@@ -1400,9 +1497,6 @@ mono_arch_allocate_vars (MonoCompile *cfg)
        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;
@@ -1429,14 +1523,12 @@ mono_arch_allocate_vars (MonoCompile *cfg)
        }
 
        /* 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;
@@ -1449,21 +1541,12 @@ mono_arch_allocate_vars (MonoCompile *cfg)
                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)) {
@@ -1628,7 +1711,7 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
        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;
 
@@ -1640,7 +1723,7 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
                        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 */
@@ -1858,7 +1941,7 @@ mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
                        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);
@@ -1876,8 +1959,7 @@ mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
 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)
@@ -3133,7 +3215,7 @@ emit_load_volatile_arguments(MonoCompile *cfg, guint8 *code)
        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) {
@@ -3228,8 +3310,8 @@ emit_reserve_param_area (MonoCompile *cfg, guint8 *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;
@@ -3250,8 +3332,8 @@ emit_unreserve_param_area (MonoCompile *cfg, guint8 *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;
@@ -3317,6 +3399,9 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                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;
@@ -3354,9 +3439,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        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);
@@ -3642,8 +3725,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                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 */
@@ -3835,6 +3918,14 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                                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);
@@ -3959,11 +4050,19 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        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;
                }
@@ -4569,7 +4668,7 @@ mono_arch_register_lowlevel_calls (void)
 }
 
 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;
 
@@ -4625,20 +4724,6 @@ mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, Mono
        }
 }
 
-#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)
  *
@@ -4657,33 +4742,37 @@ mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean ena
        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);
@@ -4783,7 +4872,7 @@ mips_adjust_stackframe(MonoCompile *cfg)
                                        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) {
@@ -4859,10 +4948,8 @@ mono_arch_emit_prolog (MonoCompile *cfg)
 #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;
 
@@ -4893,16 +4980,6 @@ mono_arch_emit_prolog (MonoCompile *cfg)
        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
@@ -4919,11 +4996,7 @@ mono_arch_emit_prolog (MonoCompile *cfg)
        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);
@@ -4973,15 +5046,18 @@ mono_arch_emit_prolog (MonoCompile *cfg)
                        }
                }
        }
-#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 */
@@ -4995,7 +5071,7 @@ mono_arch_emit_prolog (MonoCompile *cfg)
                        }
                }
        }
-#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]);
@@ -5003,33 +5079,34 @@ mono_arch_emit_prolog (MonoCompile *cfg)
                        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)) {
@@ -5093,7 +5170,7 @@ mono_arch_emit_prolog (MonoCompile *cfg)
                                        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) {
@@ -5179,12 +5256,6 @@ mono_arch_emit_prolog (MonoCompile *cfg)
                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));
@@ -5220,17 +5291,14 @@ mono_arch_emit_prolog (MonoCompile *cfg)
                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);
                }
@@ -5238,9 +5306,22 @@ mono_arch_emit_prolog (MonoCompile *cfg)
                        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;
@@ -5264,7 +5345,7 @@ mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolea
        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);
@@ -5374,10 +5455,8 @@ mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code)
        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;
@@ -5415,11 +5494,7 @@ mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code)
                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)) {
@@ -5448,7 +5523,7 @@ mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code)
                }
        }
 #endif
-#if SAVE_LMF
+
        /* Unlink the LMF if necessary */
        if (method->save_lmf) {
                int lmf_offset = cfg->arch.lmf_offset;
@@ -5462,7 +5537,7 @@ mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code)
                /* (*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);
@@ -5701,11 +5776,6 @@ setup_tls_access (void)
                }
 #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) {
@@ -5729,7 +5799,7 @@ setup_tls_access (void)
 }
 
 void
-mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
+mono_arch_finish_init (void)
 {
        setup_tls_access ();
 }
@@ -5749,13 +5819,13 @@ mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_re
 
        /* 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) {
@@ -5789,27 +5859,12 @@ mono_arch_print_tree (MonoInst *tree, int arity)
        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
@@ -5955,6 +6010,9 @@ mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckI
                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;
 }
 
@@ -5963,12 +6021,10 @@ mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
 {
        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];
 }
 
@@ -6097,4 +6153,19 @@ mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)
        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;
+}