Bug 996561 - MIPS Simulator support in the common code. r=jandem
authorSvetozar Janjic <svetozar.janjic@imgtec.com>
Tue, 06 May 2014 15:37:45 +0200
changeset 183015 9e098b366105b6c0f27a965c30963a9ab71e56ff
parent 183014 6695b0b1a4fe4518386644d03c17eecc29fff548
child 183016 f26c0a596097ea1b40680ccbce49b80f16b703eb
push id6785
push userkwierso@gmail.com
push dateWed, 14 May 2014 02:00:10 +0000
treeherderfx-team@c0efb7fe87e3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem
bugs996561
milestone32.0a1
Bug 996561 - MIPS Simulator support in the common code. r=jandem
js/src/assembler/jit/ExecutableAllocator.h
js/src/assembler/wtf/Platform.h
js/src/gc/RootMarking.cpp
js/src/jit/AsmJSModule.cpp
js/src/jit/AsmJSSignalHandlers.cpp
js/src/jit/BaselineBailouts.cpp
js/src/jit/BaselineIC.cpp
js/src/jit/BaselineIC.h
js/src/jit/JitCommon.h
js/src/jit/ParallelFunctions.cpp
js/src/jit/VMFunctions.cpp
js/src/jsapi.cpp
js/src/jscntxt.cpp
js/src/shell/js.cpp
js/src/vm/ForkJoin.cpp
js/src/vm/Runtime.cpp
js/src/vm/Runtime.h
--- a/js/src/assembler/jit/ExecutableAllocator.h
+++ b/js/src/assembler/jit/ExecutableAllocator.h
@@ -28,16 +28,17 @@
 
 #include <stddef.h> // for ptrdiff_t
 #include <limits>
 
 #include "jsalloc.h"
 
 #include "assembler/wtf/Platform.h"
 #include "jit/arm/Simulator-arm.h"
+#include "jit/mips/Simulator-mips.h"
 #include "js/HashTable.h"
 #include "js/Vector.h"
 
 #if WTF_CPU_SPARC
 #ifdef linux  // bugzilla 502369
 static void sync_instruction_memory(caddr_t v, u_int len)
 {
     caddr_t end = v + len;
@@ -56,17 +57,17 @@ extern  "C" void sync_instruction_memory
 #include <libkern/OSCacheControl.h>
 #include <sys/mman.h>
 #endif
 
 #if WTF_OS_SYMBIAN
 #include <e32std.h>
 #endif
 
-#if WTF_CPU_MIPS && WTF_OS_LINUX
+#if WTF_CPU_MIPS && WTF_OS_LINUX && !JS_MIPS_SIMULATOR
 #include <sys/cachectl.h>
 #endif
 
 #if ENABLE_ASSEMBLER_WX_EXCLUSIVE
 #define PROTECTION_FLAGS_RW (PROT_READ | PROT_WRITE)
 #define PROTECTION_FLAGS_RX (PROT_READ | PROT_EXEC)
 #define INITIAL_PROTECTION_FLAGS PROTECTION_FLAGS_RX
 #else
@@ -413,17 +414,17 @@ public:
     static void makeExecutable(void*, size_t) {}
 #endif
 
 
 #if WTF_CPU_X86 || WTF_CPU_X86_64
     static void cacheFlush(void*, size_t)
     {
     }
-#elif defined(JS_ARM_SIMULATOR)
+#elif defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
     static void cacheFlush(void *code, size_t size)
     {
         js::jit::Simulator::FlushICache(code, size);
     }
 #elif WTF_CPU_MIPS
     static void cacheFlush(void* code, size_t size)
     {
 #if WTF_COMPILER_GCC && (GCC_VERSION >= 40300)
--- a/js/src/assembler/wtf/Platform.h
+++ b/js/src/assembler/wtf/Platform.h
@@ -152,16 +152,26 @@
 #define WTF_MIPS_ARCH_REV __mips_isa_rev
 #define WTF_MIPS_ISA_REV(v) (defined WTF_MIPS_ARCH_REV && WTF_MIPS_ARCH_REV == v)
 #define WTF_MIPS_DOUBLE_FLOAT (defined __mips_hard_float && !defined __mips_single_float)
 #define WTF_MIPS_FP64 (defined __mips_fpr && __mips_fpr == 64)
 /* MIPS requires allocators to use aligned memory */
 #define WTF_USE_ARENA_ALLOC_ALIGNMENT_INTEGER 1
 #endif /* MIPS */
 
+#if defined(JS_MIPS_SIMULATOR)
+#define WTF_MIPS_ARCH 32
+#define WTF_MIPS_ISA(v) (defined WTF_MIPS_ARCH && WTF_MIPS_ARCH == v)
+#define WTF_MIPS_ISA_AT_LEAST(v) (defined WTF_MIPS_ARCH && WTF_MIPS_ARCH >= v)
+#define WTF_MIPS_ARCH_REV 2
+#define WTF_MIPS_ISA_REV(v) (defined WTF_MIPS_ARCH_REV && WTF_MIPS_ARCH_REV == v)
+#define WTF_MIPS_DOUBLE_FLOAT 1
+#undef WTF_MIPS_FP64
+#endif
+
 /* WTF_CPU_PPC - PowerPC 32-bit */
 #if   defined(__ppc__)     \
     || defined(__PPC__)     \
     || defined(__powerpc__) \
     || defined(__powerpc)   \
     || defined(__POWERPC__) \
     || defined(_M_PPC)      \
     || defined(__PPC)
@@ -374,16 +384,22 @@
 
 #if defined(JS_ARM_SIMULATOR)
 #  undef WTF_CPU_X86
 #  undef WTF_CPU_X64
 #  define WTF_CPU_ARM_TRADITIONAL 1
 #  define WTF_CPU_ARM 1
 #endif
 
+#if defined(JS_MIPS_SIMULATOR)
+#  undef WTF_CPU_X86
+#  undef WTF_CPU_X64
+#  define WTF_CPU_MIPS 1
+#endif
+
 #if WTF_CPU_ARM || WTF_CPU_MIPS
 #define WTF_CPU_NEEDS_ALIGNED_ACCESS 1
 #endif
 
 /* ==== OS() - underlying operating system; only to be used for mandated low-level services like
    virtual memory, not to choose a GUI toolkit ==== */
 
 /* WTF_OS_ANDROID - Android */
--- a/js/src/gc/RootMarking.cpp
+++ b/js/src/gc/RootMarking.cpp
@@ -257,24 +257,24 @@ MarkRangeConservatively(JSTracer *trc, c
         MarkWordConservatively(trc, *i);
 }
 
 static void
 MarkRangeConservativelyAndSkipIon(JSTracer *trc, JSRuntime *rt, const uintptr_t *begin, const uintptr_t *end)
 {
     const uintptr_t *i = begin;
 
-#if JS_STACK_GROWTH_DIRECTION < 0 && defined(JS_ION) && !defined(JS_ARM_SIMULATOR)
+#if JS_STACK_GROWTH_DIRECTION < 0 && defined(JS_ION) && !defined(JS_ARM_SIMULATOR) && !defined(JS_MIPS_SIMULATOR)
     // Walk only regions in between JIT activations. Note that non-volatile
     // registers are spilled to the stack before the entry frame, ensuring
     // that the conservative scanner will still see them.
     //
-    // If the ARM simulator is enabled, JIT activations are not on the native
-    // stack but on the simulator stack, so we don't have to skip JIT regions
-    // in this case.
+    // If the ARM or MIPS simulator is enabled, JIT activations are not on
+    // the native stack but on the simulator stack, so we don't have to skip
+    // JIT regions in this case.
     for (jit::JitActivationIterator iter(rt); !iter.done(); ++iter) {
         uintptr_t *jitMin, *jitEnd;
         iter.jitStackRange(jitMin, jitEnd);
 
         MarkRangeConservatively(trc, i, jitMin);
         i = jitEnd;
     }
 #endif
--- a/js/src/jit/AsmJSModule.cpp
+++ b/js/src/jit/AsmJSModule.cpp
@@ -53,17 +53,17 @@ AsmJSModule::initHeap(Handle<ArrayBuffer
         const jit::AsmJSHeapAccess &access = heapAccesses_[i];
         if (access.hasLengthCheck())
             JSC::X86Assembler::setPointer(access.patchLengthAt(code_), heapLength);
         void *addr = access.patchOffsetAt(code_);
         uint32_t disp = reinterpret_cast<uint32_t>(JSC::X86Assembler::getPointer(addr));
         JS_ASSERT(disp <= INT32_MAX);
         JSC::X86Assembler::setPointer(addr, (void *)(heapOffset + disp));
     }
-#elif defined(JS_CODEGEN_ARM)
+#elif defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS)
     uint32_t heapLength = heap->byteLength();
     for (unsigned i = 0; i < heapAccesses_.length(); i++) {
         jit::Assembler::updateBoundsCheck(heapLength,
                                           (jit::Instruction*)(heapAccesses_[i].offset() + code_));
     }
     // We already know the exact extent of areas that need to be patched, just make sure we
     // flush all of them at once.
     jit::AutoFlushCache::updateTop(uintptr_t(code_), pod.codeBytes_);
@@ -181,17 +181,17 @@ static inline void *
 FuncCast(F *pf)
 {
     return JS_FUNC_TO_DATA_PTR(void *, pf);
 }
 
 static void *
 RedirectCall(void *fun, ABIFunctionType type)
 {
-#ifdef JS_ARM_SIMULATOR
+#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
     fun = Simulator::RedirectNativeFunction(fun, type);
 #endif
     return fun;
 }
 
 #ifdef DEBUG
 static void
 AssumeUnreachable()
--- a/js/src/jit/AsmJSSignalHandlers.cpp
+++ b/js/src/jit/AsmJSSignalHandlers.cpp
@@ -332,17 +332,17 @@ static bool
 HandleSimulatorInterrupt(JSRuntime *rt, AsmJSActivation *activation, void *faultingAddress)
 {
     // If the ARM simulator is enabled, the pc is in the simulator C++ code and
     // not in the generated code, so we check the simulator's pc manually. Also
     // note that we can't simply use simulator->set_pc() here because the
     // simulator could be in the middle of an instruction. On ARM, the signal
     // handlers are currently only used for Odin code, see bug 964258.
 
-#ifdef JS_ARM_SIMULATOR
+#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
     const AsmJSModule &module = activation->module();
     if (module.containsPC((void *)rt->mainThread.simulator()->get_pc()) &&
         module.containsPC(faultingAddress))
     {
         activation->setInterrupted(nullptr);
         int32_t nextpc = int32_t(module.interruptExit());
         rt->mainThread.simulator()->set_resume_pc(nextpc);
         return true;
--- a/js/src/jit/BaselineBailouts.cpp
+++ b/js/src/jit/BaselineBailouts.cpp
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "jsprf.h"
 #include "jit/arm/Simulator-arm.h"
 #include "jit/BaselineIC.h"
 #include "jit/BaselineJIT.h"
 #include "jit/CompileInfo.h"
 #include "jit/IonSpewer.h"
+#include "jit/mips/Simulator-mips.h"
 #include "jit/Recover.h"
 #include "jit/RematerializedFrame.h"
 
 #include "vm/ArgumentsObject.h"
 #include "vm/Debugger.h"
 #include "vm/TraceLogging.h"
 
 #include "jsscriptinlines.h"
@@ -1440,17 +1441,17 @@ jit::BailoutIonToBaseline(JSContext *cx,
         Value *argv = builder.startFrame()->argv() + 1; // +1 to skip |this|.
         mozilla::PodCopy(argv, startFrameFormals.begin(), startFrameFormals.length());
     }
 
     // Do stack check.
     bool overRecursed = false;
     BaselineBailoutInfo *info = builder.info();
     uint8_t *newsp = info->incomingStack - (info->copyStackTop - info->copyStackBottom);
-#ifdef JS_ARM_SIMULATOR
+#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
     if (Simulator::Current()->overRecursed(uintptr_t(newsp)))
         overRecursed = true;
 #else
     JS_CHECK_RECURSION_WITH_SP_DONT_REPORT(cx, newsp, overRecursed = true);
 #endif
     if (overRecursed) {
         IonSpew(IonSpew_BaselineBailouts, "  Overrecursion check failed!");
         return BAILOUT_RETURN_OVERRECURSED;
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -8801,17 +8801,17 @@ ICCall_Native::Compiler::generateStubCod
 
     // Execute call.
     masm.setupUnalignedABICall(3, scratch);
     masm.loadJSContext(scratch);
     masm.passABIArg(scratch);
     masm.passABIArg(argcReg);
     masm.passABIArg(vpReg);
 
-#ifdef JS_ARM_SIMULATOR
+#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
     // The simulator requires VM calls to be redirected to a special swi
     // instruction to handle them, so we store the redirected pointer in the
     // stub and use that instead of the original one.
     masm.callWithABI(Address(BaselineStubReg, ICCall_Native::offsetOfNative()));
 #else
     masm.callWithABI(Address(callee, JSFunction::offsetOfNativeOrScript()));
 #endif
 
@@ -10186,17 +10186,17 @@ ICCall_AnyScripted::Clone(JSContext *, I
 ICCall_Native::ICCall_Native(JitCode *stubCode, ICStub *firstMonitorStub,
                              HandleFunction callee, HandleObject templateObject,
                              uint32_t pcOffset)
   : ICMonitoredStub(ICStub::Call_Native, stubCode, firstMonitorStub),
     callee_(callee),
     templateObject_(templateObject),
     pcOffset_(pcOffset)
 {
-#ifdef JS_ARM_SIMULATOR
+#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
     // The simulator requires VM calls to be redirected to a special swi
     // instruction to handle them. To make this work, we store the redirected
     // pointer in the stub.
     native_ = Simulator::RedirectNativeFunction(JS_FUNC_TO_DATA_PTR(void *, callee->native()),
                                                 Args_General3);
 #endif
 }
 
--- a/js/src/jit/BaselineIC.h
+++ b/js/src/jit/BaselineIC.h
@@ -5605,17 +5605,17 @@ class ICCall_Native : public ICMonitored
 {
     friend class ICStubSpace;
 
   protected:
     HeapPtrFunction callee_;
     HeapPtrObject templateObject_;
     uint32_t pcOffset_;
 
-#ifdef JS_ARM_SIMULATOR
+#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
     void *native_;
 #endif
 
     ICCall_Native(JitCode *stubCode, ICStub *firstMonitorStub,
                   HandleFunction callee, HandleObject templateObject,
                   uint32_t pcOffset);
 
   public:
@@ -5641,17 +5641,17 @@ class ICCall_Native : public ICMonitored
 
     static size_t offsetOfCallee() {
         return offsetof(ICCall_Native, callee_);
     }
     static size_t offsetOfPCOffset() {
         return offsetof(ICCall_Native, pcOffset_);
     }
 
-#ifdef JS_ARM_SIMULATOR
+#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
     static size_t offsetOfNative() {
         return offsetof(ICCall_Native, native_);
     }
 #endif
 
     // Compiler for this stub kind.
     class Compiler : public ICCallStubCompiler {
       protected:
--- a/js/src/jit/JitCommon.h
+++ b/js/src/jit/JitCommon.h
@@ -4,19 +4,23 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef jit_JitCommon_h
 #define jit_JitCommon_h
 
 // Various macros used by all JITs, including YARR.
 
-#ifdef JS_ARM_SIMULATOR
+#if defined(JS_ARM_SIMULATOR)
 #include "jit/arm/Simulator-arm.h"
+#elif defined(JS_MIPS_SIMULATOR)
+#include "jit/mips/Simulator-mips.h"
+#endif
 
+#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
 // Call into cross-jitted code by following the ABI of the simulated architecture.
 #define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4, p5, p6, p7)     \
     (js::jit::Simulator::Current()->call(                              \
         JS_FUNC_TO_DATA_PTR(uint8_t *, entry), 8, p0, p1, p2, p3, p4, p5, p6, p7) & 0xffffffff)
 
 #define CALL_GENERATED_YARR_CODE3(entry, p0, p1, p2)     \
     js::jit::Simulator::Current()->call(JS_FUNC_TO_DATA_PTR(uint8_t *, entry), 3, p0, p1, p2)
 
--- a/js/src/jit/ParallelFunctions.cpp
+++ b/js/src/jit/ParallelFunctions.cpp
@@ -3,16 +3,17 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "jit/ParallelFunctions.h"
 
 #include "builtin/TypedObject.h"
 #include "jit/arm/Simulator-arm.h"
+#include "jit/mips/Simulator-mips.h"
 #include "vm/ArrayObject.h"
 
 #include "jsgcinlines.h"
 #include "jsobjinlines.h"
 
 using namespace js;
 using namespace jit;
 
@@ -185,17 +186,17 @@ jit::CheckOverRecursedPar(ForkJoinContex
     // overwritten with a sentinel value that brings us here.
     // Therefore, we must check whether this is really a stack overrun
     // and, if not, check whether an interrupt was requested.
     //
     // When not on the main thread, we don't overwrite the stack
     // limit, but we do still call into this routine if the interrupt
     // flag is set, so we still need to double check.
 
-#ifdef JS_ARM_SIMULATOR
+#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
     if (Simulator::Current()->overRecursed()) {
         cx->bailoutRecord->setCause(ParallelBailoutOverRecursed);
         return false;
     }
 #endif
 
     uintptr_t realStackLimit;
     if (cx->isMainThread())
--- a/js/src/jit/VMFunctions.cpp
+++ b/js/src/jit/VMFunctions.cpp
@@ -7,16 +7,17 @@
 #include "jit/VMFunctions.h"
 
 #include "builtin/TypedObject.h"
 #include "frontend/BytecodeCompiler.h"
 #include "jit/arm/Simulator-arm.h"
 #include "jit/BaselineIC.h"
 #include "jit/IonFrames.h"
 #include "jit/JitCompartment.h"
+#include "jit/mips/Simulator-mips.h"
 #include "vm/ArrayObject.h"
 #include "vm/Debugger.h"
 #include "vm/Interpreter.h"
 
 #include "jsinferinlines.h"
 
 #include "jit/BaselineFrame-inl.h"
 #include "jit/IonFrames-inl.h"
@@ -115,17 +116,17 @@ CheckOverRecursed(JSContext *cx)
     // There are two states we're concerned about here:
     //   (1) The interrupt bit is set, and we need to fire the interrupt callback.
     //   (2) The stack limit has been exceeded, and we need to throw an error.
     //
     // Note that we can reach here if jitStackLimit is MAXADDR, but interrupt
     // has not yet been set to 1. That's okay; it will be set to 1 very shortly,
     // and in the interim we might just fire a few useless calls to
     // CheckOverRecursed.
-#ifdef JS_ARM_SIMULATOR
+#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
     JS_CHECK_SIMULATOR_RECURSION_WITH_EXTRA(cx, 0, return false);
 #else
     JS_CHECK_RECURSION(cx, return false);
 #endif
 
     if (cx->runtime()->interrupt)
         return InterruptCheck(cx);
 
@@ -148,31 +149,31 @@ CheckOverRecursedWithExtra(JSContext *cx
     JS_ASSERT_IF(earlyCheck, !frame->overRecursed());
 
     // See |CheckOverRecursed| above.  This is a variant of that function which
     // accepts an argument holding the extra stack space needed for the Baseline
     // frame that's about to be pushed.
     uint8_t spDummy;
     uint8_t *checkSp = (&spDummy) - extra;
     if (earlyCheck) {
-#ifdef JS_ARM_SIMULATOR
+#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
         (void)checkSp;
         JS_CHECK_SIMULATOR_RECURSION_WITH_EXTRA(cx, extra, frame->setOverRecursed());
 #else
         JS_CHECK_RECURSION_WITH_SP(cx, checkSp, frame->setOverRecursed());
 #endif
         return true;
     }
 
     // The OVERRECURSED flag may have already been set on the frame by an
     // early over-recursed check.  If so, throw immediately.
     if (frame->overRecursed())
         return false;
 
-#ifdef JS_ARM_SIMULATOR
+#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
     JS_CHECK_SIMULATOR_RECURSION_WITH_EXTRA(cx, extra, return false);
 #else
     JS_CHECK_RECURSION_WITH_SP(cx, checkSp, return false);
 #endif
 
     if (cx->runtime()->interrupt)
         return InterruptCheck(cx);
 
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -2159,17 +2159,17 @@ js::RecomputeStackLimit(JSRuntime *rt, S
     // Note that, for now, we use the untrusted limit for ion. This is fine,
     // because it's the most conservative limit, and if we hit it, we'll bail
     // out of ion into the interpeter, which will do a proper recursion check.
 #ifdef JS_ION
     if (kind == StackForUntrustedScript) {
         JSRuntime::AutoLockForInterrupt lock(rt);
         if (rt->mainThread.jitStackLimit != uintptr_t(-1)) {
             rt->mainThread.jitStackLimit = rt->mainThread.nativeStackLimit[kind];
-#ifdef JS_ARM_SIMULATOR
+#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
             rt->mainThread.jitStackLimit = jit::Simulator::StackLimit();
 #endif
         }
     }
 #endif
 }
 
 JS_PUBLIC_API(void)
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -1317,17 +1317,17 @@ JSContext::mark(JSTracer *trc)
     TraceCycleDetectionSet(trc, cycleDetectorSet);
 
     MarkValueRoot(trc, &iterValue, "iterValue");
 }
 
 void *
 ThreadSafeContext::stackLimitAddressForJitCode(StackKind kind)
 {
-#ifdef JS_ARM_SIMULATOR
+#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
     return runtime_->mainThread.addressOfSimulatorStackLimit();
 #endif
     return stackLimitAddress(kind);
 }
 
 JSVersion
 JSContext::findVersion() const
 {
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -5980,23 +5980,30 @@ SetRuntimeOptions(JSRuntime *rt, const O
             return OptionFailure("ion-parallel-compile", str);
     }
 #ifdef JS_THREADSAFE
     rt->setParallelIonCompilationEnabled(parallelCompilation);
 #endif
 
 #endif // JS_ION
 
-#ifdef JS_ARM_SIMULATOR
+#if defined(JS_ARM_SIMULATOR)
     if (op.getBoolOption("arm-sim-icache-checks"))
         jit::Simulator::ICacheCheckingEnabled = true;
 
     int32_t stopAt = op.getIntOption("arm-sim-stop-at");
     if (stopAt >= 0)
         jit::Simulator::StopSimAt = stopAt;
+#elif defined(JS_MIPS_SIMULATOR)
+    if (op.getBoolOption("mips-sim-icache-checks"))
+        jit::Simulator::ICacheCheckingEnabled = true;
+
+    int32_t stopAt = op.getIntOption("mips-sim-stop-at");
+    if (stopAt >= 0)
+        jit::Simulator::StopSimAt = stopAt;
 #endif
 
     reportWarnings = op.getBoolOption('w');
     compileOnly = op.getBoolOption('c');
     printTiming = op.getBoolOption('b');
     rt->profilingScripts = enableDisassemblyDumps = op.getBoolOption('D');
 
     jsCacheDir = op.getStringOption("js-cache");
@@ -6198,21 +6205,26 @@ main(int argc, char **argv, char **envp)
         || !op.addBoolOption('\0', "dump-entrained-variables", "Print variables which are "
                              "unnecessarily entrained by inner functions")
 #endif
 #ifdef JSGC_GENERATIONAL
         || !op.addBoolOption('\0', "no-ggc", "Disable Generational GC")
 #endif
         || !op.addIntOption('\0', "available-memory", "SIZE",
                             "Select GC settings based on available memory (MB)", 0)
-#ifdef JS_ARM_SIMULATOR
+#if defined(JS_ARM_SIMULATOR)
         || !op.addBoolOption('\0', "arm-sim-icache-checks", "Enable icache flush checks in the ARM "
                              "simulator.")
         || !op.addIntOption('\0', "arm-sim-stop-at", "NUMBER", "Stop the ARM simulator after the given "
                             "NUMBER of instructions.", -1)
+#elif defined(JS_MIPS_SIMULATOR)
+	|| !op.addBoolOption('\0', "mips-sim-icache-checks", "Enable icache flush checks in the MIPS "
+                             "simulator.")
+        || !op.addIntOption('\0', "mips-sim-stop-at", "NUMBER", "Stop the MIPS simulator after the given "
+                            "NUMBER of instructions.", -1)
 #endif
     )
     {
         return EXIT_FAILURE;
     }
 
     op.setArgTerminatesOptions("script", true);
     op.setArgCapturesRest("scriptArgs");
--- a/js/src/vm/ForkJoin.cpp
+++ b/js/src/vm/ForkJoin.cpp
@@ -1472,17 +1472,17 @@ ForkJoinShared::executeFromWorker(Thread
 {
     PerThreadData thisThread(cx_->runtime());
     if (!thisThread.init()) {
         setAbortFlagAndRequestInterrupt(true);
         return false;
     }
     TlsPerThreadData.set(&thisThread);
 
-#ifdef JS_ARM_SIMULATOR
+#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
     stackLimit = Simulator::StackLimit();
 #endif
 
     // Don't use setIonStackLimit() because that acquires the ionStackLimitLock, and the
     // lock has not been initialized in these cases.
     thisThread.jitStackLimit = stackLimit;
     executePortion(&thisThread, worker);
     TlsPerThreadData.set(nullptr);
--- a/js/src/vm/Runtime.cpp
+++ b/js/src/vm/Runtime.cpp
@@ -30,16 +30,17 @@
 #include "jswrapper.h"
 
 #if defined(JS_ION)
 # include "assembler/assembler/MacroAssembler.h"
 #endif
 #include "jit/arm/Simulator-arm.h"
 #include "jit/AsmJSSignalHandlers.h"
 #include "jit/JitCompartment.h"
+#include "jit/mips/Simulator-mips.h"
 #include "jit/PcScriptCache.h"
 #include "js/MemoryMetrics.h"
 #include "js/SliceBudget.h"
 #include "yarr/BumpPointerAllocator.h"
 
 #include "jscntxtinlines.h"
 #include "jsgcinlines.h"
 
@@ -72,31 +73,31 @@ PerThreadData::PerThreadData(JSRuntime *
     jitTop(nullptr),
     jitJSContext(nullptr),
     jitStackLimit(0),
 #ifdef JS_TRACE_LOGGING
     traceLogger(nullptr),
 #endif
     activation_(nullptr),
     asmJSActivationStack_(nullptr),
-#ifdef JS_ARM_SIMULATOR
+#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
     simulator_(nullptr),
     simulatorStackLimit_(0),
 #endif
     dtoaState(nullptr),
     suppressGC(0),
     activeCompilations(0)
 {}
 
 PerThreadData::~PerThreadData()
 {
     if (dtoaState)
         js_DestroyDtoaState(dtoaState);
 
-#ifdef JS_ARM_SIMULATOR
+#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
     js_delete(simulator_);
 #endif
 }
 
 bool
 PerThreadData::init()
 {
     dtoaState = js_NewDtoaState();
@@ -162,17 +163,17 @@ JSRuntime::JSRuntime(JSRuntime *parentRu
     checkRequestDepth(0),
 # endif
 #endif
 #ifdef DEBUG
     activeContext(nullptr),
 #endif
     gc(thisFromCtor()),
     gcInitialized(false),
-#ifdef JS_ARM_SIMULATOR
+#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
     simulatorRuntime_(nullptr),
 #endif
     NaNValue(DoubleNaNValue()),
     negativeInfinityValue(DoubleValue(NegativeInfinity<double>())),
     positiveInfinityValue(DoubleValue(PositiveInfinity<double>())),
     emptyString(nullptr),
     debugMode(false),
     spsProfiler(thisFromCtor()),
@@ -314,17 +315,17 @@ JSRuntime::init(uint32_t maxbytes)
     /* The garbage collector depends on everything before this point being initialized. */
     gcInitialized = true;
 
     if (!InitRuntimeNumberState(this))
         return false;
 
     dateTimeInfo.updateTimeZoneAdjustment();
 
-#ifdef JS_ARM_SIMULATOR
+#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
     simulatorRuntime_ = js::jit::CreateSimulatorRuntime();
     if (!simulatorRuntime_)
         return false;
 #endif
 
     nativeStackBase = GetNativeStackBase();
 
     jitSupportsFloatingPoint = JitSupportsFloatingPoint();
@@ -444,17 +445,17 @@ JSRuntime::~JSRuntime()
 
     js_delete(ionPcScriptCache);
 
 #ifdef JSGC_GENERATIONAL
     gc.storeBuffer.disable();
     gc.nursery.disable();
 #endif
 
-#ifdef JS_ARM_SIMULATOR
+#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
     js::jit::DestroySimulatorRuntime(simulatorRuntime_);
 #endif
 
     DebugOnly<size_t> oldCount = liveRuntimesCount--;
     JS_ASSERT(oldCount > 0);
 
 #ifdef JS_THREADSAFE
     js::TlsPerThreadData.set(nullptr);
@@ -477,17 +478,17 @@ NewObjectCache::clearNurseryObjects(JSRu
 }
 
 void
 JSRuntime::resetJitStackLimit()
 {
     AutoLockForInterrupt lock(this);
     mainThread.setJitStackLimit(mainThread.nativeStackLimit[js::StackForUntrustedScript]);
 
-#ifdef JS_ARM_SIMULATOR
+#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
     mainThread.setJitStackLimit(js::jit::Simulator::StackLimit());
 #endif
  }
 
 void
 JSRuntime::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::RuntimeSizes *rtSizes)
 {
     // Several tables in the runtime enumerated below can be used off thread.
--- a/js/src/vm/Runtime.h
+++ b/js/src/vm/Runtime.h
@@ -518,17 +518,17 @@ class PerThreadData : public PerThreadDa
      * Points to the most recent activation running on the thread.
      * See Activation comment in vm/Stack.h.
      */
     js::Activation *activation_;
 
     /* See AsmJSActivation comment. Protected by rt->interruptLock. */
     js::AsmJSActivation *asmJSActivationStack_;
 
-#ifdef JS_ARM_SIMULATOR
+#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
     js::jit::Simulator *simulator_;
     uintptr_t simulatorStackLimit_;
 #endif
 
   public:
     js::Activation *const *addressOfActivation() const {
         return &activation_;
     }
@@ -593,17 +593,17 @@ class PerThreadData : public PerThreadDa
             pt->runtime_ = rt;
         }
 
         ~AutoEnterRuntime() {
             pt->runtime_ = nullptr;
         }
     };
 
-#ifdef JS_ARM_SIMULATOR
+#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
     js::jit::Simulator *simulator() const;
     void setSimulator(js::jit::Simulator *sim);
     js::jit::SimulatorRuntime *simulatorRuntime() const;
     uintptr_t *addressOfSimulatorStackLimit();
 #endif
 };
 
 class AutoLockForExclusiveAccess;
@@ -970,26 +970,26 @@ struct JSRuntime : public JS::shadow::Ru
     void unlockGC() {
 #ifdef JS_THREADSAFE
         JS_ASSERT(gc.lockOwner == PR_GetCurrentThread());
         gc.lockOwner = nullptr;
         PR_Unlock(gc.lock);
 #endif
     }
 
-#ifdef JS_ARM_SIMULATOR
+#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
     js::jit::SimulatorRuntime *simulatorRuntime_;
 #endif
 
   public:
     void setNeedsBarrier(bool needs) {
         needsBarrier_ = needs;
     }
 
-#ifdef JS_ARM_SIMULATOR
+#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
     js::jit::SimulatorRuntime *simulatorRuntime() const;
     void setSimulatorRuntime(js::jit::SimulatorRuntime *srt);
 #endif
 
     /* Well-known numbers held for use by this runtime's contexts. */
     const js::Value     NaNValue;
     const js::Value     negativeInfinityValue;
     const js::Value     positiveInfinityValue;