Backed out changesets 37e7cae3d8c8 and 3ccbb670a699 (bug 898963) for Windows debug bustage.
authorRyan VanderMeulen <ryanvm@gmail.com>
Tue, 15 Apr 2014 13:39:38 -0400
changeset 197184 6e5d5104b3ea4967fd4b28ca6ba0a18f59bc008a
parent 197183 1dbade92ce0a37b9a5db2373b68dd81bf2cca210
child 197185 4680398c96512b494781ec1ef620f09421103b59
push id3624
push userasasaki@mozilla.com
push dateMon, 09 Jun 2014 21:49:01 +0000
treeherdermozilla-beta@b1a5da15899a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs898963
milestone31.0a1
backs out37e7cae3d8c8f8dbef17b1774ced7ddb11cedb36
3ccbb670a6990112aa12c76c4c46f9a870ff9f0e
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
Backed out changesets 37e7cae3d8c8 and 3ccbb670a699 (bug 898963) for Windows debug bustage. CLOSED TREE
js/src/jit/AsmJS.cpp
js/src/jit/AsmJSModule.cpp
js/src/jit/arm/Assembler-arm.h
js/src/jit/shared/Assembler-shared.h
js/src/jit/x64/Assembler-x64.h
js/src/jit/x86/Assembler-x86.h
js/src/jscntxt.h
js/src/vm/Runtime.h
js/src/vm/Stack.cpp
js/src/vm/Stack.h
--- a/js/src/jit/AsmJS.cpp
+++ b/js/src/jit/AsmJS.cpp
@@ -6019,30 +6019,25 @@ static unsigned
 StackArgBytes(const VectorT &argTypes)
 {
     ABIArgIter<VectorT> iter(argTypes);
     while (!iter.done())
         iter++;
     return iter.stackBytesConsumedSoFar();
 }
 
-static unsigned
-StackDecrementForCall(MacroAssembler &masm, unsigned bytesToPush)
-{
-    // Include extra padding so that, after pushing the bytesToPush,
-    // the stack is aligned for a call instruction.
-    unsigned alreadyPushed = AlignmentAtPrologue + masm.framePushed();
-    return AlignBytes(alreadyPushed + bytesToPush, StackAlignment) - alreadyPushed;
-}
-
 template <class VectorT>
 static unsigned
 StackDecrementForCall(MacroAssembler &masm, const VectorT &argTypes, unsigned extraBytes = 0)
 {
-    return StackDecrementForCall(masm, StackArgBytes(argTypes) + extraBytes);
+    // Include extra padding so that, after pushing the arguments and
+    // extraBytes, the stack is aligned for a call instruction.
+    unsigned argBytes = StackArgBytes(argTypes);
+    unsigned alreadyPushed = AlignmentAtPrologue + masm.framePushed();
+    return AlignBytes(alreadyPushed + extraBytes + argBytes, StackAlignment) - alreadyPushed;
 }
 
 static const unsigned FramePushedAfterSave = NonVolatileRegs.gprs().size() * sizeof(intptr_t) +
                                              NonVolatileRegs.fpus().size() * sizeof(double);
 
 static bool
 GenerateEntry(ModuleCompiler &m, const AsmJSModule::ExportedFunction &exportedFunc)
 {
@@ -6300,35 +6295,33 @@ FillArgumentArray(ModuleCompiler &m, con
 static void
 GenerateFFIInterpreterExit(ModuleCompiler &m, const ModuleCompiler::ExitDescriptor &exit,
                            unsigned exitIndex, Label *throwLabel)
 {
     MacroAssembler &masm = m.masm();
     masm.align(CodeAlignment);
     m.setInterpExitOffset(exitIndex);
     masm.setFramePushed(0);
-#if defined(JS_CODEGEN_ARM)
-    masm.Push(lr);
-#endif
-
+
+#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
     MIRType typeArray[] = { MIRType_Pointer,   // cx
                             MIRType_Pointer,   // exitDatum
                             MIRType_Int32,     // argc
                             MIRType_Pointer }; // argv
     MIRTypeVector invokeArgTypes(m.cx());
     invokeArgTypes.infallibleAppend(typeArray, ArrayLength(typeArray));
 
     // Reserve space for a call to InvokeFromAsmJS_* and an array of values
     // passed to this FFI call.
     unsigned arraySize = Max<size_t>(1, exit.sig().args().length()) * sizeof(Value);
     unsigned stackDec = StackDecrementForCall(masm, invokeArgTypes, arraySize);
     masm.reserveStack(stackDec);
 
     // Fill the argument array.
-    unsigned offsetToCallerStackArgs = AlignmentAtPrologue + masm.framePushed();
+    unsigned offsetToCallerStackArgs = NativeFrameSize + masm.framePushed();
     unsigned offsetToArgv = StackArgBytes(invokeArgTypes);
     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);
@@ -6389,30 +6382,86 @@ GenerateFFIInterpreterExit(ModuleCompile
         MOZ_ASSUME_UNREACHABLE("Float32 shouldn't be returned from a FFI");
         break;
     }
 
     // Note: the caller is IonMonkey code which means there are no non-volatile
     // registers to restore.
     masm.freeStack(stackDec);
     masm.ret();
+#else
+    const unsigned arrayLength = Max<size_t>(1, exit.sig().args().length());
+    const unsigned arraySize = arrayLength * sizeof(Value);
+    const unsigned reserveSize = AlignBytes(arraySize, StackAlignment) +
+        ShadowStackSpace;
+    const unsigned callerArgsOffset = reserveSize + NativeFrameSize + sizeof(int32_t);
+    masm.setFramePushed(0);
+    masm.Push(lr);
+    masm.reserveStack(reserveSize + sizeof(int32_t));
+
+    // Store arguments
+    FillArgumentArray(m, exit.sig().args(), ShadowStackSpace, callerArgsOffset, IntArgReg0);
+
+    // argument 0: cx
+    Register activation = IntArgReg3;
+    LoadAsmJSActivationIntoRegister(masm, activation);
+
+    LoadJSContextFromActivation(masm, activation, IntArgReg0);
+
+    // argument 1: exitIndex
+    masm.mov(ImmWord(exitIndex), IntArgReg1);
+
+    // argument 2: argc
+    masm.mov(ImmWord(exit.sig().args().length()), IntArgReg2);
+
+    // argument 3: argv
+    Address argv(StackPointer, ShadowStackSpace);
+    masm.lea(Operand(argv), IntArgReg3);
+
+    AssertStackAlignment(masm);
+    switch (exit.sig().retType().which()) {
+      case RetType::Void:
+        masm.call(AsmJSImm_InvokeFromAsmJS_Ignore);
+        masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, throwLabel);
+        break;
+      case RetType::Signed:
+        masm.call(AsmJSImm_InvokeFromAsmJS_ToInt32);
+        masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, throwLabel);
+        masm.unboxInt32(argv, ReturnReg);
+        break;
+      case RetType::Double:
+        masm.call(AsmJSImm_InvokeFromAsmJS_ToNumber);
+        masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, throwLabel);
+        masm.loadDouble(argv, ReturnFloatReg);
+        break;
+      case RetType::Float:
+        MOZ_ASSUME_UNREACHABLE("Float32 shouldn't be returned from a FFI");
+        break;
+    }
+
+    masm.freeStack(reserveSize + sizeof(int32_t));
+    masm.ret();
+#endif
 }
 
 static void
 GenerateOOLConvert(ModuleCompiler &m, RetType retType, Label *throwLabel)
 {
     MacroAssembler &masm = m.masm();
 
     MIRType typeArray[] = { MIRType_Pointer,   // cx
                             MIRType_Pointer }; // argv
     MIRTypeVector callArgTypes(m.cx());
     callArgTypes.infallibleAppend(typeArray, ArrayLength(typeArray));
 
-    // The stack is assumed to be aligned.  The frame is allocated by GenerateFFIIonExit and
-    // the stack usage here needs to kept in sync with GenerateFFIIonExit.
+    // Reserve space for a call to InvokeFromAsmJS_* and an array of values
+    // passed to this FFI call.
+    unsigned arraySize = sizeof(Value);
+    unsigned stackDec = StackDecrementForCall(masm, callArgTypes, arraySize);
+    masm.reserveStack(stackDec);
 
     // Store value
     unsigned offsetToArgv = StackArgBytes(callArgTypes);
     masm.storeValue(JSReturnOperand, Address(StackPointer, offsetToArgv));
 
     // Store real arguments
     ABIArgMIRTypeIter i(callArgTypes);
     Register scratch = ABIArgGenerator::NonArgReturnVolatileReg0;
@@ -6450,78 +6499,52 @@ GenerateOOLConvert(ModuleCompiler &m, Re
       case RetType::Double:
           masm.call(AsmJSImm_CoerceInPlace_ToNumber);
           masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, throwLabel);
           masm.loadDouble(Address(StackPointer, offsetToArgv), ReturnFloatReg);
           break;
       default:
           MOZ_ASSUME_UNREACHABLE("Unsupported convert type");
     }
+
+    masm.freeStack(stackDec);
 }
 
 static void
 GenerateFFIIonExit(ModuleCompiler &m, const ModuleCompiler::ExitDescriptor &exit,
                          unsigned exitIndex, Label *throwLabel)
 {
     MacroAssembler &masm = m.masm();
     masm.align(CodeAlignment);
     m.setIonExitOffset(exitIndex);
     masm.setFramePushed(0);
 
-#if defined(JS_CODEGEN_X64)
-    masm.Push(HeapReg);
-#elif defined(JS_CODEGEN_ARM)
-    // The lr register holds the return address and needs to be saved.  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(RegisterSet(GeneralRegisterSet((1<<GlobalReg.code()) |
-                                                       (1<<HeapReg.code()) |
-                                                       (1<<lr.code())),
-                                    FloatRegisterSet(uint32_t(0))));
+    RegisterSet restoreSet = RegisterSet::Intersect(RegisterSet::All(),
+                                                    RegisterSet::Not(RegisterSet::Volatile()));
+#if defined(JS_CODEGEN_ARM)
+    masm.Push(lr);
 #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:
+    masm.PushRegsInMask(restoreSet);
+
+    // Arguments are in the following order on the stack:
     // descriptor | callee | argc | this | arg1 | arg2 | ...
+
+    // Reserve and align space for the arguments
+    MIRTypeVector emptyVector(m.cx());
     unsigned argBytes = 3 * sizeof(size_t) + (1 + exit.sig().args().length()) * sizeof(Value);
-
-    // On ARM, we call with ma_callIonNoPush which, following the Ion calling convention,
-    // stores the return address into *sp. This means we need to include an extra word of
-    // space before the arguments in the stack allocation. (On x86/x64, the call
-    // instruction does the push itself and the ABI just requires us to be aligned before
-    // the call instruction.)
-    unsigned offsetToArgs = 0;
+    unsigned extraBytes = 0;
 #if defined(JS_CODEGEN_ARM)
-    offsetToArgs += sizeof(size_t);
+    extraBytes += sizeof(size_t);
 #endif
-
-    unsigned stackDecForIonCall = StackDecrementForCall(masm, argBytes + offsetToArgs);
-
-    // Reserve space for a call to AsmJSImm_CoerceInPlace_* and an array of values used by
-    // OOLConvert which reuses the same frame. This code needs to be kept in sync with the
-    // stack usage in GenerateOOLConvert.
-    MIRType typeArray[] = { MIRType_Pointer, MIRType_Pointer }; // cx, argv
-    MIRTypeVector callArgTypes(m.cx());
-    callArgTypes.infallibleAppend(typeArray, ArrayLength(typeArray));
-    unsigned stackDecForOOLCall = StackDecrementForCall(masm, callArgTypes, sizeof(Value));
-
-    // Allocate a frame large enough for both of the above calls.
-    unsigned stackDec = Max(stackDecForIonCall, stackDecForOOLCall);
-
-    masm.reserveStack(stackDec);
-    AssertStackAlignment(masm);
+    unsigned stackDec = StackDecrementForCall(masm, emptyVector, argBytes + extraBytes);
+    masm.reserveStack(stackDec - extraBytes);
 
     // 1. Descriptor
-    size_t argOffset = offsetToArgs;
-    uint32_t descriptor = MakeFrameDescriptor(masm.framePushed(), JitFrame_Entry);
-    masm.storePtr(ImmWord(uintptr_t(descriptor)), Address(StackPointer, argOffset));
-    argOffset += sizeof(size_t);
+    uint32_t descriptor = MakeFrameDescriptor(masm.framePushed() + extraBytes, JitFrame_Entry);
+    masm.storePtr(ImmWord(uintptr_t(descriptor)), Address(StackPointer, 0));
 
     // 2. Callee
     Register callee = ABIArgGenerator::NonArgReturnVolatileReg0;
     Register scratch = ABIArgGenerator::NonArgReturnVolatileReg1;
 
     // 2.1. Get ExitDatum
     unsigned globalDataOffset = m.module().exitIndexToGlobalDataOffset(exitIndex);
 #if defined(JS_CODEGEN_X64)
@@ -6533,135 +6556,75 @@ GenerateFFIIonExit(ModuleCompiler &m, co
 #else
     masm.lea(Operand(GlobalReg, globalDataOffset), callee);
 #endif
 
     // 2.2. Get callee
     masm.loadPtr(Address(callee, offsetof(AsmJSModule::ExitDatum, fun)), callee);
 
     // 2.3. Save callee
-    masm.storePtr(callee, Address(StackPointer, argOffset));
-    argOffset += sizeof(size_t);
+    masm.storePtr(callee, Address(StackPointer, sizeof(size_t)));
 
     // 3. Argc
     unsigned argc = exit.sig().args().length();
-    masm.storePtr(ImmWord(uintptr_t(argc)), Address(StackPointer, argOffset));
-    argOffset += sizeof(size_t);
+    masm.storePtr(ImmWord(uintptr_t(argc)), Address(StackPointer, 2 * sizeof(size_t)));
 
     // 4. |this| value
-    masm.storeValue(UndefinedValue(), Address(StackPointer, argOffset));
-    argOffset += sizeof(Value);
+    masm.storeValue(UndefinedValue(), Address(StackPointer, 3 * sizeof(size_t)));
 
     // 5. Fill the arguments
+    unsigned offsetToArgs = 3 * sizeof(size_t) + sizeof(Value);
     unsigned offsetToCallerStackArgs = masm.framePushed();
 #if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
     offsetToCallerStackArgs += NativeFrameSize;
+#else
+    offsetToCallerStackArgs += ShadowStackSpace;
 #endif
-    FillArgumentArray(m, exit.sig().args(), argOffset, offsetToCallerStackArgs, scratch);
-    argOffset += exit.sig().args().length() * sizeof(Value);
-    JS_ASSERT(argOffset == offsetToArgs + argBytes);
+    FillArgumentArray(m, exit.sig().args(), offsetToArgs, offsetToCallerStackArgs, scratch);
 
     // Get the pointer to the ion code
     Label done, oolConvert;
     Label *maybeDebugBreakpoint = nullptr;
 
 #ifdef DEBUG
     Label ionFailed;
     maybeDebugBreakpoint = &ionFailed;
     masm.branchIfFunctionHasNoScript(callee, &ionFailed);
 #endif
 
-    masm.loadPtr(Address(callee, JSFunction::offsetOfNativeOrScript()), callee);
-    masm.loadBaselineOrIonNoArgCheck(callee, callee, SequentialExecution, maybeDebugBreakpoint);
-
-    AssertStackAlignment(masm);
-
-    {
-        // Enable Activation.
-        //
-        // This sequence requires four registers, and needs to preserve the 'callee'
-        // register, so there are five live registers.
-        JS_ASSERT(callee == AsmJSIonExitRegCallee);
-        Register reg0 = AsmJSIonExitRegE0;
-        Register reg1 = AsmJSIonExitRegE1;
-        Register reg2 = AsmJSIonExitRegE2;
-        Register reg3 = AsmJSIonExitRegE3;
-
-        LoadAsmJSActivationIntoRegister(masm, reg0);
-
-        // The following is inlined:
-        //   JSContext *cx = activation->cx();
-        //   Activation *act = cx->mainThread().activation();
-        //   act.active_ = true;
-        //   act.prevIonTop_ = cx->mainThread().ionTop;
-        //   act.prevJitJSContext_ = cx->mainThread().jitJSContext;
-        //   cx->mainThread().jitJSContext = cx;
-        // On the ARM store8() uses the secondScratchReg (lr) as a temp.
-        size_t offsetOfActivation = offsetof(JSRuntime, mainThread) +
-                                    PerThreadData::offsetOfActivation();
-        size_t offsetOfIonTop = offsetof(JSRuntime, mainThread) + offsetof(PerThreadData, ionTop);
-        size_t offsetOfJitJSContext = offsetof(JSRuntime, mainThread) +
-                                      offsetof(PerThreadData, jitJSContext);
-        masm.loadPtr(Address(reg0, AsmJSActivation::offsetOfContext()), reg3);
-        masm.loadPtr(Address(reg3, JSContext::offsetOfRuntime()), reg0);
-        masm.loadPtr(Address(reg0, offsetOfActivation), reg1);
-        masm.store8(Imm32(1), Address(reg1, JitActivation::offsetOfActiveUint8()));
-        masm.loadPtr(Address(reg0, offsetOfIonTop), reg2);
-        masm.storePtr(reg2, Address(reg1, JitActivation::offsetOfPrevIonTop()));
-        masm.loadPtr(Address(reg0, offsetOfJitJSContext), reg2);
-        masm.storePtr(reg2, Address(reg1, JitActivation::offsetOfPrevJitJSContext()));
-        masm.storePtr(reg3, Address(reg0, offsetOfJitJSContext));
-    }
+    masm.loadPtr(Address(callee, JSFunction::offsetOfNativeOrScript()), scratch);
+    masm.loadBaselineOrIonNoArgCheck(scratch, scratch, SequentialExecution, maybeDebugBreakpoint);
+
+    LoadAsmJSActivationIntoRegister(masm, callee);
+    masm.push(scratch);
+    masm.setupUnalignedABICall(1, scratch);
+    masm.passABIArg(callee);
+    masm.callWithABI(AsmJSImm_EnableActivationFromAsmJS);
+    masm.pop(scratch);
 
     // 2. Call
-    AssertStackAlignment(masm);
-#if defined(JS_CODEGEN_ARM)
-    masm.ma_callIonNoPush(callee);
-    // The return address has been popped from the stack, so adjust the stack
-    // without changing the frame-pushed counter to keep the stack aligned.
-    masm.subPtr(Imm32(4), sp);
-#else
-    masm.callIon(callee);
+#if defined(JS_CODEGEN_ARM) && defined(DEBUG)
+    // ARM still needs to push, before stack is aligned
+    masm.Push(scratch);
 #endif
     AssertStackAlignment(masm);
-
-    {
-        // Disable Activation.
-        //
-        // This sequence needs three registers, and must preserve the JSReturnReg_Data and
-        // JSReturnReg_Type, so there are five live registers.
-        JS_ASSERT(JSReturnReg_Data == AsmJSIonExitRegReturnData);
-        JS_ASSERT(JSReturnReg_Type == AsmJSIonExitRegReturnType);
-        Register reg0 = AsmJSIonExitRegD0;
-        Register reg1 = AsmJSIonExitRegD1;
-        Register reg2 = AsmJSIonExitRegD2;
-
-        LoadAsmJSActivationIntoRegister(masm, reg0);
-
-        // The following is inlined:
-        //   JSContext *cx = activation->cx();
-        //   Activation *act = cx->mainThread().activation();
-        //   act.active_ = false;
-        //   cx->mainThread().ionTop = prevIonTop_;
-        //   cx->mainThread().jitJSContext = prevJitJSContext_;
-        // On the ARM store8() uses the secondScratchReg (lr) as a temp.
-        size_t offsetOfActivation = offsetof(JSRuntime, mainThread) +
-                                    PerThreadData::offsetOfActivation();
-        size_t offsetOfIonTop = offsetof(JSRuntime, mainThread) + offsetof(PerThreadData, ionTop);
-        size_t offsetOfJitJSContext = offsetof(JSRuntime, mainThread) +
-                                      offsetof(PerThreadData, jitJSContext);
-        masm.loadPtr(Address(reg0, AsmJSActivation::offsetOfContext()), reg0);
-        masm.loadPtr(Address(reg0, JSContext::offsetOfRuntime()), reg0);
-        masm.loadPtr(Address(reg0, offsetOfActivation), reg1);
-        masm.store8(Imm32(0), Address(reg1, JitActivation::offsetOfActiveUint8()));
-        masm.loadPtr(Address(reg1, JitActivation::offsetOfPrevIonTop()), reg2);
-        masm.storePtr(reg2, Address(reg0, offsetOfIonTop));
-        masm.loadPtr(Address(reg1, JitActivation::offsetOfPrevJitJSContext()), reg2);
-        masm.storePtr(reg2, Address(reg0, offsetOfJitJSContext));
-    }
+#if defined(JS_CODEGEN_ARM) && defined(DEBUG)
+    masm.freeStack(sizeof(size_t));
+#endif
+    masm.callIon(scratch);
+    masm.freeStack(stackDec - extraBytes);
+
+    masm.push(JSReturnReg_Type);
+    masm.push(JSReturnReg_Data);
+    LoadAsmJSActivationIntoRegister(masm, callee);
+    masm.setupUnalignedABICall(1, scratch);
+    masm.passABIArg(callee);
+    masm.callWithABI(AsmJSImm_DisableActivationFromAsmJS);
+    masm.pop(JSReturnReg_Data);
+    masm.pop(JSReturnReg_Type);
 
 #ifdef DEBUG
     masm.branchTestMagicValue(Assembler::Equal, JSReturnOperand, JS_ION_ERROR, throwLabel);
     masm.branchTestMagic(Assembler::Equal, JSReturnOperand, &ionFailed);
 #else
     masm.branchTestMagic(Assembler::Equal, JSReturnOperand, throwLabel);
 #endif
 
@@ -6677,30 +6640,18 @@ GenerateFFIIonExit(ModuleCompiler &m, co
         masm.convertValueToDouble(JSReturnOperand, ReturnFloatReg, &oolConvert);
         break;
       case RetType::Float:
         MOZ_ASSUME_UNREACHABLE("Float shouldn't be returned from a FFI");
         break;
     }
 
     masm.bind(&done);
-    masm.freeStack(stackDec);
-#if defined(JS_CODEGEN_ARM)
-    masm.ma_vimm(GenericNaN(), NANReg);
-    masm.PopRegsInMask(RegisterSet(GeneralRegisterSet((1<<GlobalReg.code()) |
-                                                      (1<<HeapReg.code()) |
-                                                      (1<<pc.code())),
-                                   FloatRegisterSet(uint32_t(0))));
-#else
-# if defined(JS_CODEGEN_X64)
-    masm.Pop(HeapReg);
-# endif
+    masm.PopRegsInMask(restoreSet);
     masm.ret();
-#endif
-    JS_ASSERT(masm.framePushed() == 0);
 
     // oolConvert
     if (oolConvert.used()) {
         masm.bind(&oolConvert);
         masm.setFramePushed(oolConvertFramePushed);
         GenerateOOLConvert(m, exit.sig().retType(), throwLabel);
         masm.setFramePushed(0);
         masm.jump(&done);
--- a/js/src/jit/AsmJSModule.cpp
+++ b/js/src/jit/AsmJSModule.cpp
@@ -144,16 +144,34 @@ CoerceInPlace_ToNumber(JSContext *cx, Mu
     double dbl;
     if (!ToNumber(cx, val, &dbl))
         return false;
     val.set(DoubleValue(dbl));
 
     return true;
 }
 
+static void
+EnableActivationFromAsmJS(AsmJSActivation *activation)
+{
+    JSContext *cx = activation->cx();
+    Activation *act = cx->mainThread().activation();
+    JS_ASSERT(act->isJit());
+    act->asJit()->setActive(cx);
+}
+
+static void
+DisableActivationFromAsmJS(AsmJSActivation *activation)
+{
+    JSContext *cx = activation->cx();
+    Activation *act = cx->mainThread().activation();
+    JS_ASSERT(act->isJit());
+    act->asJit()->setActive(cx, false);
+}
+
 namespace js {
 
 // Defined in AsmJS.cpp:
 
 int32_t
 InvokeFromAsmJS_Ignore(JSContext *cx, int32_t exitIndex, int32_t argc, Value *argv);
 
 int32_t
@@ -219,16 +237,20 @@ AddressOf(AsmJSImmKind kind, ExclusiveCo
       case AsmJSImm_InvokeFromAsmJS_ToNumber:
         return RedirectCall(FuncCast(InvokeFromAsmJS_ToNumber), Args_General4);
       case AsmJSImm_CoerceInPlace_ToInt32:
         return RedirectCall(FuncCast(CoerceInPlace_ToInt32), Args_General2);
       case AsmJSImm_CoerceInPlace_ToNumber:
         return RedirectCall(FuncCast(CoerceInPlace_ToNumber), Args_General2);
       case AsmJSImm_ToInt32:
         return RedirectCall(FuncCast<int32_t (double)>(js::ToInt32), Args_Int_Double);
+      case AsmJSImm_EnableActivationFromAsmJS:
+        return RedirectCall(FuncCast(EnableActivationFromAsmJS), Args_General1);
+      case AsmJSImm_DisableActivationFromAsmJS:
+        return RedirectCall(FuncCast(DisableActivationFromAsmJS), Args_General1);
 #if defined(JS_CODEGEN_ARM)
       case AsmJSImm_aeabi_idivmod:
         return RedirectCall(FuncCast(__aeabi_idivmod), Args_General2);
       case AsmJSImm_aeabi_uidivmod:
         return RedirectCall(FuncCast(__aeabi_uidivmod), Args_General2);
 #endif
       case AsmJSImm_ModD:
         return RedirectCall(FuncCast(NumberMod), Args_Double_DoubleDouble);
--- a/js/src/jit/arm/Assembler-arm.h
+++ b/js/src/jit/arm/Assembler-arm.h
@@ -75,16 +75,17 @@ class ABIArgGenerator
 
   public:
     ABIArgGenerator();
     ABIArg next(MIRType argType);
     ABIArg &current() { return current_; }
     uint32_t stackBytesConsumedSoFar() const { return stackOffset_; }
     static const Register NonArgReturnVolatileReg0;
     static const Register NonArgReturnVolatileReg1;
+
 };
 
 static MOZ_CONSTEXPR_VAR Register PreBarrierReg = r1;
 
 static MOZ_CONSTEXPR_VAR Register InvalidReg = { Registers::invalid_reg };
 static MOZ_CONSTEXPR_VAR FloatRegister InvalidFloatReg = { FloatRegisters::invalid_freg };
 
 static MOZ_CONSTEXPR_VAR Register JSReturnReg_Type = r3;
@@ -92,32 +93,16 @@ static MOZ_CONSTEXPR_VAR Register JSRetu
 static MOZ_CONSTEXPR_VAR Register StackPointer = sp;
 static MOZ_CONSTEXPR_VAR Register FramePointer = InvalidReg;
 static MOZ_CONSTEXPR_VAR Register ReturnReg = r0;
 static MOZ_CONSTEXPR_VAR FloatRegister ReturnFloatReg = { FloatRegisters::d0 };
 static MOZ_CONSTEXPR_VAR FloatRegister ScratchFloatReg = { FloatRegisters::d15 };
 
 static MOZ_CONSTEXPR_VAR FloatRegister NANReg = { FloatRegisters::d14 };
 
-// Registers used in the GenerateFFIIonExit Enable Activation block.
-static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegCallee = r4;
-static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegE0 = r0;
-static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegE1 = r1;
-static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegE2 = r2;
-static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegE3 = r3;
-
-// Registers used in the GenerateFFIIonExit Disable Activation block.
-// None of these may be the second scratch register (lr).
-static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegReturnData = r2;
-static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegReturnType = r3;
-static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegD0 = r0;
-static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegD1 = r1;
-static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegD2 = r4;
-
-
 static MOZ_CONSTEXPR_VAR FloatRegister d0  = {FloatRegisters::d0};
 static MOZ_CONSTEXPR_VAR FloatRegister d1  = {FloatRegisters::d1};
 static MOZ_CONSTEXPR_VAR FloatRegister d2  = {FloatRegisters::d2};
 static MOZ_CONSTEXPR_VAR FloatRegister d3  = {FloatRegisters::d3};
 static MOZ_CONSTEXPR_VAR FloatRegister d4  = {FloatRegisters::d4};
 static MOZ_CONSTEXPR_VAR FloatRegister d5  = {FloatRegisters::d5};
 static MOZ_CONSTEXPR_VAR FloatRegister d6  = {FloatRegisters::d6};
 static MOZ_CONSTEXPR_VAR FloatRegister d7  = {FloatRegisters::d7};
--- a/js/src/jit/shared/Assembler-shared.h
+++ b/js/src/jit/shared/Assembler-shared.h
@@ -685,16 +685,18 @@ enum AsmJSImmKind
     AsmJSImm_ReportOverRecursed,
     AsmJSImm_HandleExecutionInterrupt,
     AsmJSImm_InvokeFromAsmJS_Ignore,
     AsmJSImm_InvokeFromAsmJS_ToInt32,
     AsmJSImm_InvokeFromAsmJS_ToNumber,
     AsmJSImm_CoerceInPlace_ToInt32,
     AsmJSImm_CoerceInPlace_ToNumber,
     AsmJSImm_ToInt32,
+    AsmJSImm_EnableActivationFromAsmJS,
+    AsmJSImm_DisableActivationFromAsmJS,
 #if defined(JS_CODEGEN_ARM)
     AsmJSImm_aeabi_idivmod,
     AsmJSImm_aeabi_uidivmod,
 #endif
     AsmJSImm_ModD,
     AsmJSImm_SinD,
     AsmJSImm_CosD,
     AsmJSImm_TanD,
--- a/js/src/jit/x64/Assembler-x64.h
+++ b/js/src/jit/x64/Assembler-x64.h
@@ -131,30 +131,16 @@ static MOZ_CONSTEXPR_VAR FloatRegister F
 
 // The convention used by the ForkJoinGetSlice stub. None of these can be rax
 // or rdx, which the stub also needs for cmpxchg and div, respectively.
 static MOZ_CONSTEXPR_VAR Register ForkJoinGetSliceReg_cx = rdi;
 static MOZ_CONSTEXPR_VAR Register ForkJoinGetSliceReg_temp0 = rbx;
 static MOZ_CONSTEXPR_VAR Register ForkJoinGetSliceReg_temp1 = rcx;
 static MOZ_CONSTEXPR_VAR Register ForkJoinGetSliceReg_output = rsi;
 
-// Registers used in the GenerateFFIIonExit Enable Activation block.
-static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegCallee = r10;
-static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegE0 = rax;
-static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegE1 = rdi;
-static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegE2 = rbx;
-static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegE3 = rsi;
-
-// Registers used in the GenerateFFIIonExit Disable Activation block.
-static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegReturnData = ecx;
-static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegReturnType = ecx;
-static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegD0 = rax;
-static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegD1 = rdi;
-static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegD2 = rbx;
-
 class ABIArgGenerator
 {
 #if defined(XP_WIN)
     unsigned regIndex_;
 #else
     unsigned intRegIndex_;
     unsigned floatRegIndex_;
 #endif
--- a/js/src/jit/x86/Assembler-x86.h
+++ b/js/src/jit/x86/Assembler-x86.h
@@ -82,30 +82,16 @@ class ABIArgGenerator
     static const Register NonArgReturnVolatileReg0;
     static const Register NonArgReturnVolatileReg1;
     static const Register NonVolatileReg;
 };
 
 static MOZ_CONSTEXPR_VAR Register OsrFrameReg = edx;
 static MOZ_CONSTEXPR_VAR Register PreBarrierReg = edx;
 
-// Registers used in the GenerateFFIIonExit Enable Activation block.
-static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegCallee = ecx;
-static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegE0 = edi;
-static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegE1 = eax;
-static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegE2 = ebx;
-static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegE3 = edx;
-
-// Registers used in the GenerateFFIIonExit Disable Activation block.
-static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegReturnData = edx;
-static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegReturnType = ecx;
-static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegD0 = edi;
-static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegD1 = eax;
-static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegD2 = esi;
-
 // GCC stack is aligned on 16 bytes, but we don't maintain the invariant in
 // jitted code.
 #if defined(__GNUC__)
 static const uint32_t StackAlignment = 16;
 #else
 static const uint32_t StackAlignment = 4;
 #endif
 static const bool StackKeptAligned = false;
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -403,20 +403,16 @@ struct JSContext : public js::ExclusiveC
                    public mozilla::LinkedListElement<JSContext>
 {
     explicit JSContext(JSRuntime *rt);
     ~JSContext();
 
     JSRuntime *runtime() const { return runtime_; }
     js::PerThreadData &mainThread() const { return runtime()->mainThread; }
 
-    static size_t offsetOfRuntime() {
-        return offsetof(JSContext, runtime_);
-    }
-
     friend class js::ExclusiveContext;
     friend class JS::AutoSaveExceptionState;
 
   private:
     /* Exception state -- the exception member is a GC root by definition. */
     bool                throwing;            /* is there a pending exception? */
     js::Value           unwrappedException_; /* most-recently-thrown exception */
 
--- a/js/src/vm/Runtime.h
+++ b/js/src/vm/Runtime.h
@@ -578,19 +578,16 @@ class PerThreadData : public PerThreadDa
 
   public:
     js::Activation *const *addressOfActivation() const {
         return &activation_;
     }
     static unsigned offsetOfAsmJSActivationStackReadOnly() {
         return offsetof(PerThreadData, asmJSActivationStack_);
     }
-    static unsigned offsetOfActivation() {
-        return offsetof(PerThreadData, activation_);
-    }
 
     js::AsmJSActivation *asmJSActivationStackFromAnyThread() const {
         return asmJSActivationStack_;
     }
     js::AsmJSActivation *asmJSActivationStackFromOwnerThread() const {
         return asmJSActivationStack_;
     }
 
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -1511,19 +1511,16 @@ jit::JitActivation::JitActivation(JSCont
 jit::JitActivation::~JitActivation()
 {
     if (active_) {
         cx_->mainThread().ionTop = prevIonTop_;
         cx_->mainThread().jitJSContext = prevJitJSContext_;
     }
 }
 
-// setActive() is inlined in GenerateFFIIonExit() with explicit masm instructions so
-// changes to the logic here need to be reflected in GenerateFFIIonExit() in the enable
-// and disable activation instruction sequences.
 void
 jit::JitActivation::setActive(JSContext *cx, bool active)
 {
     // Only allowed to deactivate/activate if activation is top.
     // (Not tested and will probably fail in other situations.)
     JS_ASSERT(cx->mainThread().activation_ == this);
     JS_ASSERT(active != active_);
     active_ = active;
--- a/js/src/vm/Stack.h
+++ b/js/src/vm/Stack.h
@@ -1330,26 +1330,16 @@ class JitActivation : public Activation
         return prevIonTop_;
     }
     JSCompartment *compartment() const {
         return compartment_;
     }
     bool firstFrameIsConstructing() const {
         return firstFrameIsConstructing_;
     }
-    static size_t offsetOfPrevIonTop() {
-        return offsetof(JitActivation, prevIonTop_);
-    }
-    static size_t offsetOfPrevJitJSContext() {
-        return offsetof(JitActivation, prevJitJSContext_);
-    }
-    static size_t offsetOfActiveUint8() {
-        JS_ASSERT(sizeof(active_) == 1);
-        return offsetof(JitActivation, active_);
-    }
 
 #ifdef CHECK_OSIPOINT_REGISTERS
     void setCheckRegs(bool check) {
         checkRegs_ = check;
     }
     static size_t offsetOfCheckRegs() {
         return offsetof(JitActivation, checkRegs_);
     }