Bug 1001346 - IonMonkey MIPS: Adding MIPS OdinMonkey code part 2 (shared code). r=luke
authorBranislav Rankov <branislav.rankov@imgtec.com>
Thu, 05 Jun 2014 12:56:57 +0200
changeset 206058 f7c59e556cc6df73c97f537867582daf99c6cb51
parent 206057 c69a670294fa6bc8d81f8a8bf46b03d7c4dfbe42
child 206059 b56930ff7e05d909c0b3932b21f7bd2a527237e7
push id3741
push userasasaki@mozilla.com
push dateMon, 21 Jul 2014 20:25:18 +0000
treeherdermozilla-beta@4d6f46f5af68 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersluke
bugs1001346
milestone32.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1001346 - IonMonkey MIPS: Adding MIPS OdinMonkey code part 2 (shared code). r=luke
js/src/jit/AsmJS.cpp
js/src/jit/AsmJSLink.cpp
js/src/jit/AsmJSModule.cpp
js/src/jit/AsmJSModule.h
js/src/jit/AsmJSSignalHandlers.cpp
js/src/jit/arm/Architecture-arm.cpp
js/src/jit/arm/Assembler-arm.h
js/src/jit/mips/Architecture-mips.h
js/src/jit/mips/Assembler-mips.cpp
js/src/jit/mips/Assembler-mips.h
js/src/jit/shared/Assembler-shared.h
js/src/jit/shared/Assembler-x86-shared.h
--- a/js/src/jit/AsmJS.cpp
+++ b/js/src/jit/AsmJS.cpp
@@ -1569,45 +1569,47 @@ class MOZ_STACK_CLASS ModuleCompiler
             CodeLabel src = masm_.codeLabel(i);
             int32_t labelOffset = src.dest()->offset();
             int32_t targetOffset = masm_.actualOffset(src.src()->offset());
             // The patched uses of a label embed a linked list where the
             // to-be-patched immediate is the offset of the next to-be-patched
             // instruction.
             while (labelOffset != LabelBase::INVALID_OFFSET) {
                 size_t patchAtOffset = masm_.labelOffsetToPatchOffset(labelOffset);
-                AsmJSModule::RelativeLink link;
+                AsmJSModule::RelativeLink link(AsmJSModule::RelativeLink::CodeLabel);
                 link.patchAtOffset = patchAtOffset;
                 link.targetOffset = targetOffset;
                 if (!module_->addRelativeLink(link))
                     return false;
-                labelOffset = *(uintptr_t *)(module_->codeBase() + patchAtOffset);
+
+                labelOffset = Assembler::extractCodeLabelOffset(module_->codeBase() +
+                                                                patchAtOffset);
             }
         }
 
         // Function-pointer-table entries
         for (unsigned tableIndex = 0; tableIndex < funcPtrTables_.length(); tableIndex++) {
             FuncPtrTable &table = funcPtrTables_[tableIndex];
             unsigned tableBaseOffset = module_->offsetOfGlobalData() + table.globalDataOffset();
             for (unsigned elemIndex = 0; elemIndex < table.numElems(); elemIndex++) {
-                AsmJSModule::RelativeLink link;
+                AsmJSModule::RelativeLink link(AsmJSModule::RelativeLink::RawPointer);
                 link.patchAtOffset = tableBaseOffset + elemIndex * sizeof(uint8_t*);
                 link.targetOffset = masm_.actualOffset(table.elem(elemIndex).code()->offset());
                 if (!module_->addRelativeLink(link))
                     return false;
             }
         }
 
 #if defined(JS_CODEGEN_X86)
         // Global data accesses in x86 need to be patched with the absolute
         // address of the global. Globals are allocated sequentially after the
         // code section so we can just use an RelativeLink.
         for (unsigned i = 0; i < masm_.numAsmJSGlobalAccesses(); i++) {
             AsmJSGlobalAccess a = masm_.asmJSGlobalAccess(i);
-            AsmJSModule::RelativeLink link;
+            AsmJSModule::RelativeLink link(AsmJSModule::RelativeLink::InstructionImmediate);
             link.patchAtOffset = masm_.labelOffsetToPatchOffset(a.patchAt.offset());
             link.targetOffset = module_->offsetOfGlobalData() + a.globalDataOffset;
             if (!module_->addRelativeLink(link))
                 return false;
         }
 #endif
 
 #if defined(JS_CODEGEN_X64)
@@ -1615,16 +1617,34 @@ class MOZ_STACK_CLASS ModuleCompiler
         // not need patching after deserialization.
         uint8_t *code = module_->codeBase();
         for (unsigned i = 0; i < masm_.numAsmJSGlobalAccesses(); i++) {
             AsmJSGlobalAccess a = masm_.asmJSGlobalAccess(i);
             masm_.patchAsmJSGlobalAccess(a.patchAt, code, module_->globalData(), a.globalDataOffset);
         }
 #endif
 
+#if defined(JS_CODEGEN_MIPS)
+        // On MIPS we need to update all the long jumps because they contain an
+        // absolute adress.
+        for (size_t i = 0; i < masm_.numLongJumps(); i++) {
+            uint32_t patchAtOffset = masm_.longJump(i);
+
+            AsmJSModule::RelativeLink link(AsmJSModule::RelativeLink::InstructionImmediate);
+            link.patchAtOffset = patchAtOffset;
+
+            InstImm *inst = (InstImm *)(module_->codeBase() + patchAtOffset);
+            link.targetOffset = Assembler::extractLuiOriValue(inst, inst->next()) -
+                                (uint32_t)module_->codeBase();
+
+            if (!module_->addRelativeLink(link))
+                return false;
+        }
+#endif
+
         // Absolute links
         for (size_t i = 0; i < masm_.numAsmJSAbsoluteLinks(); i++) {
             AsmJSAbsoluteLink src = masm_.asmJSAbsoluteLink(i);
             AsmJSModule::AbsoluteLink link;
             link.patchAt = CodeOffsetLabel(masm_.actualOffset(src.patchAt.offset()));
             link.target = src.target;
             if (!module_->addAbsoluteLink(link))
                 return false;
@@ -6050,24 +6070,32 @@ StackDecrementForCall(MacroAssembler &ma
 
 template <class VectorT>
 static unsigned
 StackDecrementForCall(MacroAssembler &masm, const VectorT &argTypes, unsigned extraBytes = 0)
 {
     return StackDecrementForCall(masm, StackArgBytes(argTypes) + extraBytes);
 }
 
+#if defined(JS_CODEGEN_MIPS)
+// Mips is using one more double slot due to stack alignment for double values.
+// Look at MacroAssembler::PushRegsInMask(RegisterSet set)
+static const unsigned FramePushedAfterSave = NonVolatileRegs.gprs().size() * sizeof(intptr_t) +
+                                             NonVolatileRegs.fpus().size() * sizeof(double) +
+                                             sizeof(double);
+#else
 static const unsigned FramePushedAfterSave = NonVolatileRegs.gprs().size() * sizeof(intptr_t) +
                                              NonVolatileRegs.fpus().size() * sizeof(double);
-
-// On arm, we need to include an extra word of space at the top of the stack so
-// we can explicitly store the return address before making the call to C++ or
-// Ion. On x86/x64, this isn't necessary since the call instruction pushes the
-// return address.
-#ifdef JS_CODEGEN_ARM
+#endif
+
+// On ARM/MIPS, we need to include an extra word of space at the top of the
+// stack so we can explicitly store the return address before making the call
+// to C++ or Ion. On x86/x64, this isn't necessary since the call instruction
+// pushes the return address.
+#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS)
 static const unsigned MaybeRetAddr = sizeof(void*);
 #else
 static const unsigned MaybeRetAddr = 0;
 #endif
 
 static bool
 GenerateEntry(ModuleCompiler &m, const AsmJSModule::ExportedFunction &exportedFunc)
 {
@@ -6082,39 +6110,42 @@ GenerateEntry(ModuleCompiler &m, const A
     masm.setFramePushed(0);
 
 #if defined(JS_CODEGEN_ARM)
     // Push lr without incrementing masm.framePushed since this push is
     // accounted for by AlignmentAtAsmJSPrologue. The masm.ret at the end will
     // pop.
     masm.push(lr);
 #endif // JS_CODEGEN_ARM
+#if defined(JS_CODEGEN_MIPS)
+    masm.push(ra);
+#endif
 
     masm.PushRegsInMask(NonVolatileRegs);
     JS_ASSERT(masm.framePushed() == FramePushedAfterSave);
 
     // Remember the stack pointer in the current AsmJSActivation. This will be
     // used by error exit paths to set the stack pointer back to what it was
     // right after the (C++) caller's non-volatile registers were saved so that
     // they can be restored.
     Register activation = ABIArgGenerator::NonArgReturnVolatileReg0;
     LoadAsmJSActivationIntoRegister(masm, activation);
     masm.storePtr(StackPointer, Address(activation, AsmJSActivation::offsetOfErrorRejoinSP()));
 
-    // ARM has a globally-pinned GlobalReg (x64 uses RIP-relative addressing,
-    // x86 uses immediates in effective addresses) and NaN register (used as
-    // part of the out-of-bounds handling in heap loads/stores).
-#if defined(JS_CODEGEN_ARM)
+    // ARM and MIPS have a globally-pinned GlobalReg (x64 uses RIP-relative
+    // addressing, x86 uses immediates in effective addresses) and NaN register
+    // (used as part of the out-of-bounds handling in heap loads/stores).
+#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS)
     masm.movePtr(IntArgReg1, GlobalReg);
-    masm.ma_vimm(GenericNaN(), NANReg);
+    masm.loadConstantDouble(GenericNaN(), NANReg);
 #endif
 
-    // ARM and x64 have a globally-pinned HeapReg (x86 uses immediates in
+    // ARM, MIPS and x64 have a globally-pinned HeapReg (x86 uses immediates in
     // effective addresses).
-#if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_ARM)
+#if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS)
     masm.loadPtr(Address(IntArgReg1, m.module().heapOffset()), HeapReg);
 #endif
 
     // Get 'argv' into a non-arg register and save it on the stack.
     Register argv = ABIArgGenerator::NonArgReturnVolatileReg0;
     Register scratch = ABIArgGenerator::NonArgReturnVolatileReg1;
 #if defined(JS_CODEGEN_X86)
     masm.loadPtr(Address(StackPointer, NativeFrameSize + masm.framePushed()), argv);
@@ -6340,33 +6371,38 @@ GenerateFFIInterpreterExit(ModuleCompile
     masm.setFramePushed(0);
 
 #if defined(JS_CODEGEN_ARM)
     // Push lr without incrementing masm.framePushed since this push is
     // accounted for by AlignmentAtAsmJSPrologue. The masm.ret at the end will
     // pop.
     masm.push(lr);
 #endif
+#if defined(JS_CODEGEN_MIPS)
+    masm.push(ra);
+#endif
 
     MIRType typeArray[] = { MIRType_Pointer,   // cx
                             MIRType_Pointer,   // exitDatum
                             MIRType_Int32,     // argc
                             MIRType_Pointer }; // argv
     MIRTypeVector invokeArgTypes(m.cx());
     invokeArgTypes.infallibleAppend(typeArray, ArrayLength(typeArray));
 
-    // The stack layout looks like:
-    // | return address | stack arguments | array of values |
-    unsigned arraySize = Max<size_t>(1, exit.sig().args().length()) * sizeof(Value);
-    unsigned stackDec = StackDecrementForCall(masm, invokeArgTypes, arraySize + MaybeRetAddr);
+    // At the point of the call, the stack layout shall be (sp grows to the left):
+    // | retaddr | stack args | padding | Value argv[] | padding | retaddr | caller stack args |
+    // The first padding ensures double-alignment of argv; the second ensures
+    // sp is aligned.
+    unsigned offsetToArgv = AlignBytes(StackArgBytes(invokeArgTypes) + MaybeRetAddr, StackAlignment);
+    unsigned argvBytes = Max<size_t>(1, exit.sig().args().length()) * sizeof(Value);
+    unsigned stackDec = StackDecrementForCall(masm, offsetToArgv + argvBytes);
     masm.reserveStack(stackDec);
 
     // Fill the argument array.
     unsigned offsetToCallerStackArgs = AlignmentAtAsmJSPrologue + masm.framePushed();
-    unsigned offsetToArgv = StackArgBytes(invokeArgTypes) + MaybeRetAddr;
     Register scratch = ABIArgGenerator::NonArgReturnVolatileReg0;
     FillArgumentArray(m, exit.sig().args(), offsetToArgv, offsetToCallerStackArgs, scratch);
 
     // Prepare the arguments for the call to InvokeFromAsmJS_*.
     ABIArgMIRTypeIter i(invokeArgTypes);
     Register activation = ABIArgGenerator::NonArgReturnVolatileReg1;
     LoadAsmJSActivationIntoRegister(masm, activation);
 
@@ -6518,16 +6554,19 @@ GenerateFFIIonExit(ModuleCompiler &m, co
     // pop.
     masm.push(lr);
 
     // The GlobalReg (r10) and HeapReg (r11) also need to be restored before
     // returning to asm.js code.
     // The NANReg also needs to be restored, but is a constant and is reloaded before
     // returning to asm.js code.
     masm.PushRegsInMask(GeneralRegisterSet((1<<GlobalReg.code()) | (1<<HeapReg.code())));
+#elif defined(JS_CODEGEN_MIPS)
+    masm.push(ra);
+    masm.PushRegsInMask(GeneralRegisterSet((1<<GlobalReg.code()) | (1<<HeapReg.code())));
 #endif
 
     // The stack frame is used for the call into Ion and also for calls into C for OOL
     // conversion of the result.  A frame large enough for both is allocated.
     //
     // Arguments to the Ion function are in the following order on the stack:
     // | return address | descriptor | callee | argc | this | arg1 | arg2 | ...
     unsigned argBytes = 3 * sizeof(size_t) + (1 + exit.sig().args().length()) * sizeof(Value);
@@ -6620,17 +6659,25 @@ GenerateFFIIonExit(ModuleCompiler &m, co
         Register reg0 = AsmJSIonExitRegE0;
         Register reg1 = AsmJSIonExitRegE1;
         Register reg2 = AsmJSIonExitRegE2;
         Register reg3 = AsmJSIonExitRegE3;
 
         LoadAsmJSActivationIntoRegister(masm, reg0);
 
         // Record sp in the AsmJSActivation for stack-walking.
+#if defined(JS_CODEGEN_MIPS)
+        // Add a flag to indicate to AsmJSFrameIterator that we are calling
+        // into Ion, since the offset from SP to the return address is
+        // different when calling Ion vs. the native ABI.
+        masm.ma_or(reg1, StackPointer, Imm32(0x1));
+        masm.storePtr(reg1, Address(reg0, AsmJSActivation::offsetOfExitSP()));
+#else
         masm.storePtr(StackPointer, Address(reg0, AsmJSActivation::offsetOfExitSP()));
+#endif
 
         // The following is inlined:
         //   JSContext *cx = activation->cx();
         //   Activation *act = cx->mainThread().activation();
         //   act.active_ = true;
         //   act.prevJitTop_ = cx->mainThread().jitTop;
         //   act.prevJitJSContext_ = cx->mainThread().jitJSContext;
         //   cx->mainThread().jitJSContext = cx;
@@ -6714,18 +6761,18 @@ GenerateFFIIonExit(ModuleCompiler &m, co
         break;
     }
 
     masm.bind(&done);
     masm.freeStack(stackDec);
 #if defined(JS_CODEGEN_X64)
     masm.Pop(HeapReg);
 #endif
-#if defined(JS_CODEGEN_ARM)
-    masm.ma_vimm(GenericNaN(), NANReg);
+#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS)
+    masm.loadConstantDouble(GenericNaN(), NANReg);
     masm.PopRegsInMask(GeneralRegisterSet((1<<GlobalReg.code()) | (1<<HeapReg.code())));
 #endif
     masm.ret();
     JS_ASSERT(masm.framePushed() == 0);
 
     // oolConvert
     if (oolConvert.used()) {
         masm.bind(&oolConvert);
@@ -6806,17 +6853,17 @@ GenerateStackOverflowExit(ModuleCompiler
 // stack so that it can be popped directly into PC.
 static bool
 GenerateInterruptExit(ModuleCompiler &m, Label *throwLabel)
 {
     MacroAssembler &masm = m.masm();
     masm.align(CodeAlignment);
     masm.bind(&m.interruptLabel());
 
-#ifndef JS_CODEGEN_ARM
+#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
     // Be very careful here not to perturb the machine state before saving it
     // to the stack. In particular, add/sub instructions may set conditions in
     // the flags register.
     masm.push(Imm32(0));            // space for resumePC
     masm.pushFlags();               // after this we are safe to use sub
     masm.setFramePushed(0);         // set to zero so we can use masm.framePushed() below
     masm.PushRegsInMask(AllRegsExceptSP); // save all GP/FP registers (except SP)
 
@@ -6852,17 +6899,57 @@ GenerateInterruptExit(ModuleCompiler &m,
 
     // Restore the StackPointer to it's position before the call.
     masm.mov(ABIArgGenerator::NonVolatileReg, StackPointer);
 
     // Restore the machine state to before the interrupt.
     masm.PopRegsInMask(AllRegsExceptSP); // restore all GP/FP registers (except SP)
     masm.popFlags();              // after this, nothing that sets conditions
     masm.ret();                   // pop resumePC into PC
-#else
+#elif defined(JS_CODEGEN_MIPS)
+    // Reserve space to store resumePC.
+    masm.subPtr(Imm32(sizeof(intptr_t)), StackPointer);
+    // set to zero so we can use masm.framePushed() below.
+    masm.setFramePushed(0);
+    // save all registers,except sp. After this stack is alligned.
+    masm.PushRegsInMask(AllRegsExceptSP);
+
+    // Save the stack pointer in a non-volatile register.
+    masm.movePtr(StackPointer, s0);
+    // Align the stack.
+    masm.ma_and(StackPointer, StackPointer, Imm32(~(StackAlignment - 1)));
+
+    // Store resumePC into the reserved space.
+    LoadAsmJSActivationIntoRegister(masm, IntArgReg0);
+    masm.loadPtr(Address(IntArgReg0, AsmJSActivation::offsetOfResumePC()), IntArgReg1);
+    masm.storePtr(IntArgReg1, Address(s0, masm.framePushed()));
+
+    // argument 0: cx
+    masm.loadPtr(Address(IntArgReg0, AsmJSActivation::offsetOfContext()), IntArgReg0);
+
+    // MIPS ABI requires rewserving stack for registes $a0 to $a3.
+    masm.subPtr(Imm32(4 * sizeof(intptr_t)), StackPointer);
+
+    masm.call(AsmJSImm_HandleExecutionInterrupt);
+
+    masm.addPtr(Imm32(4 * sizeof(intptr_t)), StackPointer);
+
+    masm.branchIfFalseBool(ReturnReg, throwLabel);
+
+    // This will restore stack to the address before the call.
+    masm.movePtr(s0, StackPointer);
+    masm.PopRegsInMask(AllRegsExceptSP);
+
+    // Pop resumePC into PC. Clobber HeapReg to make the jump and restore it
+    // during jump delay slot.
+    JS_ASSERT(Imm16::isInSignedRange(m.module().heapOffset()));
+    masm.pop(HeapReg);
+    masm.as_jr(HeapReg);
+    masm.loadPtr(Address(GlobalReg, m.module().heapOffset()), HeapReg);
+#elif defined(JS_CODEGEN_ARM)
     masm.setFramePushed(0);         // set to zero so we can use masm.framePushed() below
     masm.PushRegsInMask(RegisterSet(GeneralRegisterSet(Registers::AllMask & ~(1<<Registers::sp)), FloatRegisterSet(uint32_t(0))));   // save all GP registers,excep sp
 
     // Save both the APSR and FPSCR in non-volatile registers.
     masm.as_mrs(r4);
     masm.as_vmrs(r5);
     // Save the stack pointer in a non-volatile register.
     masm.mov(sp,r6);
@@ -6900,16 +6987,18 @@ GenerateInterruptExit(ModuleCompiler &m,
     masm.transferReg(r9);
     masm.transferReg(r10);
     masm.transferReg(r11);
     masm.transferReg(r12);
     masm.transferReg(lr);
     masm.finishDataTransfer();
     masm.ret();
 
+#else
+# error "Unknown architecture!"
 #endif
 
     return !masm.oom();
 }
 
 // If an exception is thrown, simply pop all frames (since asm.js does not
 // contain try/catch). To do this:
 //  1. Restore 'sp' to it's value right after the PushRegsInMask in GenerateEntry.
--- a/js/src/jit/AsmJSLink.cpp
+++ b/js/src/jit/AsmJSLink.cpp
@@ -47,23 +47,39 @@ AsmJSFrameIterator::AsmJSFrameIterator(c
     module_ = &activation->module();
     sp_ = activation->exitSP();
 
 #if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
     // For calls to Ion/C++ on x86/x64, the exitSP is the SP right before the call
     // to C++. Since the call instruction pushes the return address, we know
     // that the return address is 1 word below exitSP.
     returnAddress_ = *(uint8_t**)(sp_ - sizeof(void*));
-#else
+#elif defined(JS_CODEGEN_ARM)
     // For calls to Ion/C++ on ARM, the *caller* pushes the return address on
     // the stack. For Ion, this is just part of the ABI. For C++, the return
     // address is explicitly pushed before the call since we cannot expect the
     // callee to immediately push lr. This means that exitSP points to the
     // return address.
     returnAddress_ = *(uint8_t**)sp_;
+#elif defined(JS_CODEGEN_MIPS)
+    // On MIPS we have two cases. Exit to C++ will store return addres at
+    // sp + 16, While on exits to Ion, the return address will be stored at
+    // sp + 0. We indicate exits to ion by setting the lowest bit of stored sp.
+
+    // Check if this is the exit to Ion.
+    if (uint32_t(sp_) & 0x1) {
+        // Clear the low bit.
+        sp_ -= 0x1;
+        returnAddress_ = *(uint8_t**)sp_;
+    } else {
+        // This is exit to C++
+        returnAddress_ = *(uint8_t**)(sp_ + ShadowStackSpace);
+    }
+#else
+# error "Unknown architecture!"
 #endif
 
     settle();
 }
 
 struct GetCallSite
 {
     const AsmJSModule &module;
--- a/js/src/jit/AsmJSModule.cpp
+++ b/js/src/jit/AsmJSModule.cpp
@@ -308,17 +308,22 @@ void
 AsmJSModule::staticallyLink(ExclusiveContext *cx)
 {
     // Process staticLinkData_
 
     interruptExit_ = code_ + staticLinkData_.interruptExitOffset;
 
     for (size_t i = 0; i < staticLinkData_.relativeLinks.length(); i++) {
         RelativeLink link = staticLinkData_.relativeLinks[i];
-        *(void **)(code_ + link.patchAtOffset) = code_ + link.targetOffset;
+        uint8_t *patchAt = code_ + link.patchAtOffset;
+        uint8_t *target = code_ + link.targetOffset;
+        if (link.isRawPointerPatch())
+            *(uint8_t **)(patchAt) = target;
+        else
+            Assembler::patchInstructionImmediate(patchAt, PatchedImmPtr(target));
     }
 
     for (size_t i = 0; i < staticLinkData_.absoluteLinks.length(); i++) {
         AbsoluteLink link = staticLinkData_.absoluteLinks[i];
         Assembler::patchDataWithValueCheck(CodeLocationLabel(code_ + link.patchAt.offset()),
                                            PatchedImmPtr(AddressOf(link.target, cx)),
                                            PatchedImmPtr((void*)-1));
     }
@@ -1008,31 +1013,36 @@ AsmJSModule::codeIsProtected(JSRuntime *
 
 static bool
 GetCPUID(uint32_t *cpuId)
 {
     enum Arch {
         X86 = 0x1,
         X64 = 0x2,
         ARM = 0x3,
-        ARCH_BITS = 2
+        MIPS = 0x4,
+        ARCH_BITS = 3
     };
 
 #if defined(JS_CODEGEN_X86)
     JS_ASSERT(uint32_t(JSC::MacroAssembler::getSSEState()) <= (UINT32_MAX >> ARCH_BITS));
     *cpuId = X86 | (JSC::MacroAssembler::getSSEState() << ARCH_BITS);
     return true;
 #elif defined(JS_CODEGEN_X64)
     JS_ASSERT(uint32_t(JSC::MacroAssembler::getSSEState()) <= (UINT32_MAX >> ARCH_BITS));
     *cpuId = X64 | (JSC::MacroAssembler::getSSEState() << ARCH_BITS);
     return true;
 #elif defined(JS_CODEGEN_ARM)
     JS_ASSERT(GetARMFlags() <= (UINT32_MAX >> ARCH_BITS));
     *cpuId = ARM | (GetARMFlags() << ARCH_BITS);
     return true;
+#elif defined(JS_CODEGEN_MIPS)
+    JS_ASSERT(GetMIPSFlags() <= (UINT32_MAX >> ARCH_BITS));
+    *cpuId = MIPS | (GetMIPSFlags() << ARCH_BITS);
+    return true;
 #else
     return false;
 #endif
 }
 
 class MachineId
 {
     uint32_t cpuId_;
--- a/js/src/jit/AsmJSModule.h
+++ b/js/src/jit/AsmJSModule.h
@@ -365,16 +365,49 @@ class AsmJSModule
           : ProfiledFunction(copy.name, copy.pod.startCodeOffset, copy.pod.endCodeOffset),
             endInlineCodeOffset(copy.endInlineCodeOffset), blocks(mozilla::Move(copy.blocks))
         { }
     };
 #endif
 
     struct RelativeLink
     {
+        enum Kind
+        {
+            RawPointer,
+            CodeLabel,
+            InstructionImmediate
+        };
+
+        RelativeLink()
+        { }
+
+        RelativeLink(Kind kind)
+        {
+#if defined(JS_CODEGEN_MIPS)
+            kind_ = kind;
+#elif defined(JS_CODEGEN_ARM)
+            // On ARM, CodeLabels are only used to label raw pointers, so in
+            // all cases on ARM, a RelativePatch means patching a raw pointer.
+            JS_ASSERT(kind == CodeLabel || kind == RawPointer);
+#endif
+            // On X64 and X86, all RelativePatch-es are patched as raw pointers.
+        }
+
+        bool isRawPointerPatch() {
+#if defined(JS_CODEGEN_MIPS)
+            return kind_ == RawPointer;
+#else
+            return true;
+#endif
+        }
+
+#ifdef JS_CODEGEN_MIPS
+        Kind kind_;
+#endif
         uint32_t patchAtOffset;
         uint32_t targetOffset;
     };
 
     typedef Vector<RelativeLink, 0, SystemAllocPolicy> RelativeLinkVector;
 
     struct AbsoluteLink
     {
@@ -722,42 +755,43 @@ class AsmJSModule
         HeapPtrFunction fun;
     };
 
     // Global data section
     //
     // The global data section is placed after the executable code (i.e., at
     // offset codeBytes_) in the module's linear allocation. The global data
     // are laid out in this order:
-    //   0. a pointer/descriptor for the heap that was linked to the module
+    //   0. a pointer (padded up to 8 bytes to ensure double-alignment of
+    //      globals) for the heap that was linked to the module.
     //   1. global variable state (elements are sizeof(uint64_t))
     //   2. interleaved function-pointer tables and exits. These are allocated
     //      while type checking function bodies (as exits and uses of
     //      function-pointer tables are encountered).
     size_t offsetOfGlobalData() const {
         JS_ASSERT(code_);
         return pod.codeBytes_;
     }
     uint8_t *globalData() const {
         return code_ + offsetOfGlobalData();
     }
     size_t globalDataBytes() const {
-        return sizeof(void*) +
+        return sizeof(uint64_t) +
                pod.numGlobalVars_ * sizeof(uint64_t) +
                pod.funcPtrTableAndExitBytes_;
     }
     unsigned heapOffset() const {
         return 0;
     }
     uint8_t *&heapDatum() const {
         return *(uint8_t**)(globalData() + heapOffset());
     }
     unsigned globalVarIndexToGlobalDataOffset(unsigned i) const {
         JS_ASSERT(i < pod.numGlobalVars_);
-        return sizeof(void*) +
+        return sizeof(uint64_t) +
                i * sizeof(uint64_t);
     }
     void *globalVarIndexToGlobalDatum(unsigned i) const {
         return (void *)(globalData() + globalVarIndexToGlobalDataOffset(i));
     }
     uint8_t **globalDataOffsetToFuncPtrTable(unsigned globalDataOffset) const {
         JS_ASSERT(globalDataOffset < globalDataBytes());
         return (uint8_t **)(globalData() + globalDataOffset);
--- a/js/src/jit/AsmJSSignalHandlers.cpp
+++ b/js/src/jit/AsmJSSignalHandlers.cpp
@@ -81,16 +81,21 @@ using JS::GenericNaN;
 # define R12_sig(p) ((p)->uc_mcontext.gregs[REG_R12])
 # define R13_sig(p) ((p)->uc_mcontext.gregs[REG_R13])
 # define R14_sig(p) ((p)->uc_mcontext.gregs[REG_R14])
 # if defined(__linux__) && defined(__arm__)
 #  define R15_sig(p) ((p)->uc_mcontext.arm_pc)
 # else
 #  define R15_sig(p) ((p)->uc_mcontext.gregs[REG_R15])
 # endif
+# if defined(__linux__) && defined(__mips__)
+#  define EPC_sig(p) ((p)->uc_mcontext.pc)
+#  define RSP_sig(p) ((p)->uc_mcontext.gregs[29])
+#  define RFP_sig(p) ((p)->uc_mcontext.gregs[30])
+# endif
 #elif defined(__NetBSD__)
 # define XMM_sig(p,i) (((struct fxsave64 *)(p)->uc_mcontext.__fpregs)->fx_xmm[i])
 # define EIP_sig(p) ((p)->uc_mcontext.__gregs[_REG_EIP])
 # define RIP_sig(p) ((p)->uc_mcontext.__gregs[_REG_RIP])
 # define RAX_sig(p) ((p)->uc_mcontext.__gregs[_REG_RAX])
 # define RCX_sig(p) ((p)->uc_mcontext.__gregs[_REG_RCX])
 # define RDX_sig(p) ((p)->uc_mcontext.__gregs[_REG_RDX])
 # define RBX_sig(p) ((p)->uc_mcontext.__gregs[_REG_RBX])
@@ -277,16 +282,47 @@ typedef struct sigcontext mcontext_t;
 typedef struct ucontext {
     uint32_t uc_flags;
     struct ucontext* uc_link;
     stack_t uc_stack;
     mcontext_t uc_mcontext;
     // Other fields are not used so don't define them here.
 } ucontext_t;
 
+#  elif defined(__mips__)
+
+typedef struct {
+    uint32_t regmask;
+    uint32_t status;
+    uint64_t pc;
+    uint64_t gregs[32];
+    uint64_t fpregs[32];
+    uint32_t acx;
+    uint32_t fpc_csr;
+    uint32_t fpc_eir;
+    uint32_t used_math;
+    uint32_t dsp;
+    uint64_t mdhi;
+    uint64_t mdlo;
+    uint32_t hi1;
+    uint32_t lo1;
+    uint32_t hi2;
+    uint32_t lo2;
+    uint32_t hi3;
+    uint32_t lo3;
+} mcontext_t;
+
+typedef struct ucontext {
+    uint32_t uc_flags;
+    struct ucontext* uc_link;
+    stack_t uc_stack;
+    mcontext_t uc_mcontext;
+    // Other fields are not used so don't define them here.
+} ucontext_t;
+
 #  elif defined(__i386__)
 // x86 version for Android.
 typedef struct {
     uint32_t gregs[19];
     void* fpregs;
     uint32_t oldmask;
     uint32_t cr2;
 } mcontext_t;
@@ -321,16 +357,18 @@ static bool IsSignalHandlingBroken() { r
 #endif
 
 #if defined(JS_CPU_X64)
 # define PC_sig(p) RIP_sig(p)
 #elif defined(JS_CPU_X86)
 # define PC_sig(p) EIP_sig(p)
 #elif defined(JS_CPU_ARM)
 # define PC_sig(p) R15_sig(p)
+#elif defined(JS_CPU_MIPS)
+# define PC_sig(p) EPC_sig(p)
 #endif
 
 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
@@ -350,17 +388,16 @@ HandleSimulatorInterrupt(JSRuntime *rt, 
 #endif
     return false;
 }
 
 #if !defined(XP_MACOSX)
 static uint8_t **
 ContextToPC(CONTEXT *context)
 {
-    JS_STATIC_ASSERT(sizeof(PC_sig(context)) == sizeof(void*));
     return reinterpret_cast<uint8_t**>(&PC_sig(context));
 }
 
 # if defined(JS_CODEGEN_X64)
 static void
 SetRegisterToCoercedUndefined(CONTEXT *context, bool isFloat32, AnyRegister reg)
 {
     if (reg.isFloat()) {
--- a/js/src/jit/arm/Architecture-arm.cpp
+++ b/js/src/jit/arm/Architecture-arm.cpp
@@ -10,20 +10,20 @@
 #include <elf.h>
 #endif
 
 #include <fcntl.h>
 #include <unistd.h>
 
 #include "jit/arm/Assembler-arm.h"
 
-#define HWCAP_USE_HARDFP_ABI (1 << 28)
+#define HWCAP_USE_HARDFP_ABI (1 << 27)
 
 #if !(defined(ANDROID) || defined(MOZ_B2G)) && !defined(JS_ARM_SIMULATOR)
-#define HWCAP_ARMv7 (1 << 29)
+#define HWCAP_ARMv7 (1 << 28)
 #include <asm/hwcap.h>
 #else
 #define HWCAP_VFP      (1<<0)
 #define HWCAP_VFPv3    (1<<1)
 #define HWCAP_VFPv3D16 (1<<2)
 #define HWCAP_VFPv4    (1<<3)
 #define HWCAP_IDIVA    (1<<4)
 #define HWCAP_IDIVT    (1<<5)
--- a/js/src/jit/arm/Assembler-arm.h
+++ b/js/src/jit/arm/Assembler-arm.h
@@ -1793,29 +1793,38 @@ class Assembler : public AssemblerShared
     static uint32_t patchWrite_NearCallSize();
     static uint32_t nopSize() { return 4; }
     static void patchWrite_NearCall(CodeLocationLabel start, CodeLocationLabel toCall);
     static void patchDataWithValueCheck(CodeLocationLabel label, PatchedImmPtr newValue,
                                         PatchedImmPtr expectedValue);
     static void patchDataWithValueCheck(CodeLocationLabel label, ImmPtr newValue,
                                         ImmPtr expectedValue);
     static void patchWrite_Imm32(CodeLocationLabel label, Imm32 imm);
+
+    static void patchInstructionImmediate(uint8_t *code, PatchedImmPtr imm) {
+        MOZ_ASSUME_UNREACHABLE("Unused.");
+    }
+
     static uint32_t alignDoubleArg(uint32_t offset) {
         return (offset+1)&~1;
     }
     static uint8_t *nextInstruction(uint8_t *instruction, uint32_t *count = nullptr);
     // Toggle a jmp or cmp emitted by toggledJump().
 
     static void ToggleToJmp(CodeLocationLabel inst_);
     static void ToggleToCmp(CodeLocationLabel inst_);
 
     static void ToggleCall(CodeLocationLabel inst_, bool enabled);
 
     static void updateBoundsCheck(uint32_t logHeapSize, Instruction *inst);
     void processCodeLabels(uint8_t *rawCode);
+    static int32_t extractCodeLabelOffset(uint8_t *code) {
+        return *(uintptr_t *)code;
+    }
+
     bool bailed() {
         return m_buffer.bail();
     }
 }; // Assembler
 
 // An Instruction is a structure for both encoding and decoding any and all ARM instructions.
 // many classes have not been implemented thusfar.
 class Instruction
--- a/js/src/jit/mips/Architecture-mips.h
+++ b/js/src/jit/mips/Architecture-mips.h
@@ -23,17 +23,17 @@
 #else
 #error "Unsupported ABI"
 #endif
 
 namespace js {
 namespace jit {
 
 // Shadow stack space is not required on MIPS.
-static const uint32_t ShadowStackSpace = 0;
+static const uint32_t ShadowStackSpace = 4 * sizeof(uintptr_t);
 
 // These offsets are specific to nunboxing, and capture offsets into the
 // components of a js::Value.
 // Size of MIPS32 general purpose registers is 32 bits.
 static const int32_t NUNBOX32_TYPE_OFFSET = 4;
 static const int32_t NUNBOX32_PAYLOAD_OFFSET = 0;
 
 // Size of each bailout table entry.
--- a/js/src/jit/mips/Assembler-mips.cpp
+++ b/js/src/jit/mips/Assembler-mips.cpp
@@ -324,16 +324,22 @@ void
 Assembler::processCodeLabels(uint8_t *rawCode)
 {
     for (size_t i = 0; i < codeLabels_.length(); i++) {
         CodeLabel label = codeLabels_[i];
         Bind(rawCode, label.dest(), rawCode + actualOffset(label.src()->offset()));
     }
 }
 
+int32_t
+Assembler::extractCodeLabelOffset(uint8_t *code) {
+    InstImm *inst = (InstImm *)code;
+    return Assembler::extractLuiOriValue(inst, inst->next());
+}
+
 void
 Assembler::Bind(uint8_t *rawCode, AbsoluteLabel *label, const void *address)
 {
     if (label->used()) {
         int32_t src = label->offset();
         do {
             Instruction *inst = (Instruction *) (rawCode + src);
             uint32_t next = Assembler::extractLuiOriValue(inst, inst->next());
@@ -1445,16 +1451,23 @@ Assembler::patchWrite_Imm32(CodeLocation
 {
     // Raw is going to be the return address.
     uint32_t *raw = (uint32_t*)label.raw();
     // Overwrite the 4 bytes before the return address, which will
     // end up being the call instruction.
     *(raw - 1) = imm.value;
 }
 
+void
+Assembler::patchInstructionImmediate(uint8_t *code, PatchedImmPtr imm)
+{
+    InstImm *inst = (InstImm *)code;
+    Assembler::updateLuiOriValue(inst, inst->next(), (uint32_t)imm.value);
+}
+
 uint8_t *
 Assembler::nextInstruction(uint8_t *inst_, uint32_t *count)
 {
     Instruction *inst = reinterpret_cast<Instruction*>(inst_);
     if (count != nullptr)
         *count += sizeof(Instruction);
     return reinterpret_cast<uint8_t*>(inst->next());
 }
--- a/js/src/jit/mips/Assembler-mips.h
+++ b/js/src/jit/mips/Assembler-mips.h
@@ -84,17 +84,17 @@ class ABIArgGenerator
 
   public:
     ABIArgGenerator();
     ABIArg next(MIRType argType);
     ABIArg &current() { return current_; }
 
     uint32_t stackBytesConsumedSoFar() const {
         if (usedArgSlots_ <= 4)
-            return 4 * sizeof(intptr_t);
+            return ShadowStackSpace;
 
         return usedArgSlots_ * sizeof(intptr_t);
     }
 
     static const Register NonArgReturnVolatileReg0;
     static const Register NonArgReturnVolatileReg1;
 };
 
@@ -1028,29 +1028,33 @@ class Assembler : public AssemblerShared
                                         Register reg, uint32_t value);
 
     static void patchWrite_NearCall(CodeLocationLabel start, CodeLocationLabel toCall);
     static void patchDataWithValueCheck(CodeLocationLabel label, PatchedImmPtr newValue,
                                         PatchedImmPtr expectedValue);
     static void patchDataWithValueCheck(CodeLocationLabel label, ImmPtr newValue,
                                         ImmPtr expectedValue);
     static void patchWrite_Imm32(CodeLocationLabel label, Imm32 imm);
+
+    static void patchInstructionImmediate(uint8_t *code, PatchedImmPtr imm);
+
     static uint32_t alignDoubleArg(uint32_t offset) {
         return (offset + 1U) &~ 1U;
     }
 
     static uint8_t *nextInstruction(uint8_t *instruction, uint32_t *count = nullptr);
 
     static void ToggleToJmp(CodeLocationLabel inst_);
     static void ToggleToCmp(CodeLocationLabel inst_);
 
     static void ToggleCall(CodeLocationLabel inst_, bool enabled);
 
     static void updateBoundsCheck(uint32_t logHeapSize, Instruction *inst);
     void processCodeLabels(uint8_t *rawCode);
+    static int32_t extractCodeLabelOffset(uint8_t *code);
 
     bool bailed() {
         return m_buffer.bail();
     }
 }; // Assembler
 
 // sll zero, zero, 0
 const uint32_t NopInst = 0x00000000;
--- a/js/src/jit/shared/Assembler-shared.h
+++ b/js/src/jit/shared/Assembler-shared.h
@@ -686,17 +686,17 @@ class AsmJSHeapAccess
       : offset_(offset),
 # if defined(JS_CODEGEN_X86)
         cmpDelta_(cmp == UINT32_MAX ? 0 : offset - cmp),
 # endif
         opLength_(after - offset),
         isFloat32Load_(false),
         loadedReg_(UINT8_MAX)
     {}
-#elif defined(JS_CODEGEN_ARM)
+#elif defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS)
     explicit AsmJSHeapAccess(uint32_t offset)
       : offset_(offset)
     {}
 #endif
 
     uint32_t offset() const { return offset_; }
     void setOffset(uint32_t offset) { offset_ = offset; }
 #if defined(JS_CODEGEN_X86)
--- a/js/src/jit/shared/Assembler-x86-shared.h
+++ b/js/src/jit/shared/Assembler-x86-shared.h
@@ -283,16 +283,19 @@ class AssemblerX86Shared : public Assemb
     }
 
     void setPrinter(Sprinter *sp) {
         masm.setPrinter(sp);
     }
 
     void executableCopy(void *buffer);
     void processCodeLabels(uint8_t *rawCode);
+    static int32_t extractCodeLabelOffset(uint8_t *code) {
+        return *(uintptr_t *)code;
+    }
     void copyJumpRelocationTable(uint8_t *dest);
     void copyDataRelocationTable(uint8_t *dest);
     void copyPreBarrierTable(uint8_t *dest);
 
     bool addCodeLabel(CodeLabel label) {
         return codeLabels_.append(label);
     }
     size_t numCodeLabels() const {
@@ -1672,16 +1675,21 @@ class AssemblerX86Shared : public Assemb
         // The pointer given is a pointer to *after* the data.
         uintptr_t *ptr = ((uintptr_t *) data.raw()) - 1;
         JS_ASSERT(*ptr == (uintptr_t)expectedData.value);
         *ptr = (uintptr_t)newData.value;
     }
     static void patchDataWithValueCheck(CodeLocationLabel data, ImmPtr newData, ImmPtr expectedData) {
         patchDataWithValueCheck(data, PatchedImmPtr(newData.value), PatchedImmPtr(expectedData.value));
     }
+
+    static void patchInstructionImmediate(uint8_t *code, PatchedImmPtr imm) {
+        MOZ_ASSUME_UNREACHABLE("Unused.");
+    }
+
     static uint32_t nopSize() {
         return 1;
     }
     static uint8_t *nextInstruction(uint8_t *cur, uint32_t *count) {
         MOZ_ASSUME_UNREACHABLE("nextInstruction NYI on x86");
     }
 
     // Toggle a jmp or cmp emitted by toggledJump().