Bug 1027885 - OdinMonkey: avoid passing JSContext to C++ functions that can instead use innermostAsmJSActivation (r=dougc)
authorLuke Wagner <luke@mozilla.com>
Mon, 21 Jul 2014 10:56:02 -0500
changeset 216974 2c7f189210ff4843422fd165da624923b6e3a1de
parent 216973 67f8f2319c7b2886f17b8b3a6cfeb16bd65c1777
child 216975 ddfd02b154601910b6598fd0ed68019c39765b42
push id3979
push userraliiev@mozilla.com
push dateMon, 13 Oct 2014 16:35:44 +0000
treeherdermozilla-beta@30f2cc610691 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdougc
bugs1027885
milestone33.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 1027885 - OdinMonkey: avoid passing JSContext to C++ functions that can instead use innermostAsmJSActivation (r=dougc)
js/src/jit/AsmJS.cpp
js/src/jit/AsmJSModule.cpp
js/src/jit/AsmJSSignalHandlers.cpp
js/src/jit/arm/Simulator-arm.cpp
js/src/jit/mips/Simulator-mips.cpp
js/src/vm/ArrayBufferObject.cpp
js/src/vm/Runtime.h
--- a/js/src/jit/AsmJS.cpp
+++ b/js/src/jit/AsmJS.cpp
@@ -5876,22 +5876,16 @@ LoadAsmJSActivationIntoRegister(MacroAss
     CodeOffsetLabel label = masm.movlWithPatch(PatchedAbsoluteAddress(), reg);
     masm.append(AsmJSGlobalAccess(label, AsmJSModule::activationGlobalDataOffset()));
 #else
     masm.loadPtr(Address(GlobalReg, AsmJSModule::activationGlobalDataOffset()), reg);
 #endif
 }
 
 static void
-LoadJSContextFromActivation(MacroAssembler &masm, Register activation, Register dest)
-{
-    masm.loadPtr(Address(activation, AsmJSActivation::offsetOfContext()), dest);
-}
-
-static void
 AssertStackAlignment(MacroAssembler &masm)
 {
     JS_ASSERT((AsmJSFrameSize + masm.framePushed()) % StackAlignment == 0);
 #ifdef DEBUG
     Label ok;
     JS_ASSERT(IsPowerOfTwo(StackAlignment));
     masm.branchTestPtr(Assembler::Zero, StackPointer, Imm32(StackAlignment - 1), &ok);
     masm.breakpoint();
@@ -6065,112 +6059,16 @@ GenerateEntry(ModuleCompiler &m, const A
 
     JS_ASSERT(masm.framePushed() == 0);
 
     masm.move32(Imm32(true), ReturnReg);
     masm.ret();
     return true;
 }
 
-// This function and InvokeFromAsmJS* functions all return int32_t rather than
-// bool to prevent the compiler from optimizing bits higher than what's
-// actually needed for a bool (as the result is tested in asm.js generated code
-// which the compiler isn't aware of).
-static inline int32_t
-TryEnablingIon(JSContext *cx, AsmJSModule &module, HandleFunction fun, uint32_t exitIndex,
-               int32_t argc, Value *argv)
-{
-    if (!fun->hasScript())
-        return true;
-
-    // Test if the function is Ion compiled
-    JSScript *script = fun->nonLazyScript();
-    if (!script->hasIonScript())
-        return true;
-
-    // Currently we can't rectify arguments. Therefore disabling if argc is too low.
-    if (fun->nargs() > size_t(argc))
-        return true;
-
-    // Normally the types should corresond, since we just ran with those types,
-    // but there are reports this is asserting. Therefore doing it as a check, instead of DEBUG only.
-    if (!types::TypeScript::ThisTypes(script)->hasType(types::Type::UndefinedType()))
-        return true;
-    for(uint32_t i = 0; i < fun->nargs(); i++) {
-        types::StackTypeSet *typeset = types::TypeScript::ArgTypes(script, i);
-        types::Type type = types::Type::DoubleType();
-        if (!argv[i].isDouble())
-            type = types::Type::PrimitiveType(argv[i].extractNonDoubleType());
-        if (!typeset->hasType(type))
-            return true;
-    }
-
-    // Enable
-    IonScript *ionScript = script->ionScript();
-    if (!ionScript->addDependentAsmJSModule(cx, DependentAsmJSModuleExit(&module, exitIndex)))
-        return false;
-
-    module.exitIndexToGlobalDatum(exitIndex).exit = module.ionExitTrampoline(module.exit(exitIndex));
-    return true;
-}
-
-namespace js {
-
-// See comment above TryEnablingIon.
-int32_t
-InvokeFromAsmJS(JSContext *cx, int32_t exitIndex, int32_t argc, Value *argv,
-                MutableHandleValue rval)
-{
-    AsmJSModule &module = cx->mainThread().asmJSActivationStackFromOwnerThread()->module();
-
-    RootedFunction fun(cx, module.exitIndexToGlobalDatum(exitIndex).fun);
-    RootedValue fval(cx, ObjectValue(*fun));
-    if (!Invoke(cx, UndefinedValue(), fval, argc, argv, rval))
-        return false;
-
-    return TryEnablingIon(cx, module, fun, exitIndex, argc, argv);
-}
-
-int32_t
-InvokeFromAsmJS_Ignore(JSContext *cx, int32_t exitIndex, int32_t argc, Value *argv)
-{
-    RootedValue rval(cx);
-    return InvokeFromAsmJS(cx, exitIndex, argc, argv, &rval);
-}
-
-int32_t
-InvokeFromAsmJS_ToInt32(JSContext *cx, int32_t exitIndex, int32_t argc, Value *argv)
-{
-    RootedValue rval(cx);
-    if (!InvokeFromAsmJS(cx, exitIndex, argc, argv, &rval))
-        return false;
-
-    int32_t i32;
-    if (!ToInt32(cx, rval, &i32))
-        return false;
-    argv[0] = Int32Value(i32);
-    return true;
-}
-
-int32_t
-InvokeFromAsmJS_ToNumber(JSContext *cx, int32_t exitIndex, int32_t argc, Value *argv)
-{
-    RootedValue rval(cx);
-    if (!InvokeFromAsmJS(cx, exitIndex, argc, argv, &rval))
-        return false;
-
-    double dbl;
-    if (!ToNumber(cx, rval, &dbl))
-        return false;
-    argv[0] = DoubleValue(dbl);
-    return true;
-}
-
-}  // namespace js
-
 static void
 FillArgumentArray(ModuleCompiler &m, const VarTypeVector &argTypes,
                   unsigned offsetToArgs, unsigned offsetToCallerStackArgs,
                   Register scratch)
 {
     MacroAssembler &masm = m.masm();
 
     for (ABIArgTypeIter i(argTypes); !i.done(); i++) {
@@ -6221,65 +6119,55 @@ GenerateFFIInterpreterExit(ModuleCompile
     masm.push(ra);
 #endif
 
     // Store the frame pointer in AsmJSActivation::exitFP for stack unwinding.
     Register activation = ABIArgGenerator::NonArgReturnVolatileReg0;
     LoadAsmJSActivationIntoRegister(masm, activation);
     masm.storePtr(StackPointer, Address(activation, AsmJSActivation::offsetOfExitFP()));
 
-    MIRType typeArray[] = { MIRType_Pointer,   // cx
-                            MIRType_Pointer,   // exitDatum
+    MIRType typeArray[] = { MIRType_Pointer,   // exitDatum
                             MIRType_Int32,     // argc
                             MIRType_Pointer }; // argv
     MIRTypeVector invokeArgTypes(m.cx());
     invokeArgTypes.infallibleAppend(typeArray, ArrayLength(typeArray));
 
     // At the point of the call, the stack layout shall be (sp grows to the left):
     //   | stack args | padding | Value argv[] | padding | retaddr | caller stack args |
-    // The padding between stack args and argv ensures that sp is aligned. The
-    // padding between argv and retaddr ensures that argv is aligned.
-    unsigned offsetToArgv = AlignBytes(StackArgBytes(invokeArgTypes), StackAlignment);
+    // The padding between stack args and argv ensures that argv is aligned. The
+    // padding between argv and retaddr ensures that sp is aligned.
+    unsigned offsetToArgv = AlignBytes(StackArgBytes(invokeArgTypes), sizeof(double));
     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 = AsmJSFrameSize + masm.framePushed();
     Register scratch = ABIArgGenerator::NonArgReturnVolatileReg1;
     FillArgumentArray(m, exit.sig().args(), offsetToArgv, offsetToCallerStackArgs, scratch);
 
     // Prepare the arguments for the call to InvokeFromAsmJS_*.
     ABIArgMIRTypeIter i(invokeArgTypes);
 
-    // argument 0: cx
-    if (i->kind() == ABIArg::GPR) {
-        LoadJSContextFromActivation(masm, activation, i->gpr());
-    } else {
-        LoadJSContextFromActivation(masm, activation, scratch);
-        masm.storePtr(scratch, Address(StackPointer, i->offsetFromArgBase()));
-    }
-    i++;
-
-    // argument 1: exitIndex
+    // argument 0: exitIndex
     if (i->kind() == ABIArg::GPR)
         masm.mov(ImmWord(exitIndex), i->gpr());
     else
         masm.store32(Imm32(exitIndex), Address(StackPointer, i->offsetFromArgBase()));
     i++;
 
-    // argument 2: argc
+    // argument 1: argc
     unsigned argc = exit.sig().args().length();
     if (i->kind() == ABIArg::GPR)
         masm.mov(ImmWord(argc), i->gpr());
     else
         masm.store32(Imm32(argc), Address(StackPointer, i->offsetFromArgBase()));
     i++;
 
-    // argument 3: argv
+    // argument 2: argv
     Address argv(StackPointer, offsetToArgv);
     if (i->kind() == ABIArg::GPR) {
         masm.computeEffectiveAddress(argv, i->gpr());
     } else {
         masm.computeEffectiveAddress(argv, scratch);
         masm.storePtr(scratch, Address(StackPointer, i->offsetFromArgBase()));
     }
     i++;
@@ -6366,35 +6254,36 @@ GenerateFFIIonExit(ModuleCompiler &m, co
 
     // The same stack frame is used for the call into Ion and (possibly) a call
     // into C++ to coerce the return type. To do this, we compute the amount of
     // space required for both calls and take the maximum. In both cases,
     // include space for savedRegBytes, since these go below the Ion/coerce.
 
     // Ion calls use the following stack layout (sp grows to the left):
     //   | return address | descriptor | callee | argc | this | arg1 | arg2 | ...
-    unsigned offsetToArgs = MaybeRetAddr;
-    unsigned argBytes = 3 * sizeof(size_t) + (1 + exit.sig().args().length()) * sizeof(Value);
-    unsigned totalIonBytes = offsetToArgs + argBytes + savedRegBytes;
+    unsigned offsetToIonArgs = MaybeRetAddr;
+    unsigned ionArgBytes = 3 * sizeof(size_t) + (1 + exit.sig().args().length()) * sizeof(Value);
+    unsigned totalIonBytes = offsetToIonArgs + ionArgBytes + savedRegBytes;
     unsigned ionFrameSize = StackDecrementForCall(masm, totalIonBytes);
 
     // Coercion calls use the following stack layout (sp grows to the left):
-    //   | stack args | Value argv[1] | ...
+    //   | stack args | padding | Value argv[1] | ...
+    // The padding between args and argv ensures that argv is aligned.
     MIRTypeVector coerceArgTypes(m.cx());
-    coerceArgTypes.infallibleAppend(MIRType_Pointer); // cx
     coerceArgTypes.infallibleAppend(MIRType_Pointer); // argv
-    unsigned bytesAfterArgs = sizeof(Value) + savedRegBytes;
-    unsigned coerceFrameSize = StackDecrementForCall(masm, coerceArgTypes, bytesAfterArgs);
+    unsigned offsetToCoerceArgv = AlignBytes(StackArgBytes(coerceArgTypes), sizeof(double));
+    unsigned totalCoerceBytes = offsetToCoerceArgv + sizeof(Value) + savedRegBytes;
+    unsigned coerceFrameSize = StackDecrementForCall(masm, totalCoerceBytes);
 
     // Allocate a frame large enough for both of the above calls.
     unsigned framePushed = Max(ionFrameSize, coerceFrameSize);
     masm.reserveStack(framePushed);
 
     // 1. Descriptor
-    size_t argOffset = offsetToArgs;
+    size_t argOffset = offsetToIonArgs;
     uint32_t descriptor = MakeFrameDescriptor(framePushed, JitFrame_Entry);
     masm.storePtr(ImmWord(uintptr_t(descriptor)), Address(StackPointer, argOffset));
     argOffset += sizeof(size_t);
 
     // 2. Callee
 
     // 2.1. Get ExitDatum
     unsigned globalDataOffset = m.module().exitIndexToGlobalDataOffset(exitIndex);
@@ -6425,17 +6314,17 @@ GenerateFFIIonExit(ModuleCompiler &m, co
     // 4. |this| value
     masm.storeValue(UndefinedValue(), Address(StackPointer, argOffset));
     argOffset += sizeof(Value);
 
     // 5. Fill the arguments
     unsigned offsetToCallerStackArgs = framePushed + AsmJSFrameSize;
     FillArgumentArray(m, exit.sig().args(), argOffset, offsetToCallerStackArgs, scratch);
     argOffset += exit.sig().args().length() * sizeof(Value);
-    JS_ASSERT(argOffset == offsetToArgs + argBytes);
+    JS_ASSERT(argOffset == offsetToIonArgs + ionArgBytes);
 
     // 6. Store asm.js pinned registers
 #if defined(JS_CODEGEN_X64)
     unsigned savedHeapOffset = framePushed - sizeof(void*);
     masm.storePtr(HeapReg, Address(StackPointer, savedHeapOffset));
 #elif defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS)
     unsigned savedHeapOffset = framePushed - 1 * sizeof(void*);
     unsigned savedGlobalOffset = framePushed - 2 * sizeof(void*);
@@ -6551,55 +6440,42 @@ GenerateFFIIonExit(ModuleCompiler &m, co
 
     masm.ret();
 
     if (oolConvert.used()) {
         masm.bind(&oolConvert);
         masm.setFramePushed(framePushed);
 
         // Store return value into argv[0]
-        unsigned offsetToArgv = StackArgBytes(coerceArgTypes);
-        JS_ASSERT(offsetToArgv % sizeof(Value) == 0);
-        masm.storeValue(JSReturnOperand, Address(StackPointer, offsetToArgv));
-
+        masm.storeValue(JSReturnOperand, Address(StackPointer, offsetToCoerceArgv));
+
+        // argument 0: argv
         ABIArgMIRTypeIter i(coerceArgTypes);
-
-        // argument 0: cx
-        LoadAsmJSActivationIntoRegister(masm, scratch);
-        if (i->kind() == ABIArg::GPR) {
-            LoadJSContextFromActivation(masm, scratch, i->gpr());
-        } else {
-            LoadJSContextFromActivation(masm, scratch, scratch);
-            masm.storePtr(scratch, Address(StackPointer, i->offsetFromArgBase()));
-        }
-        i++;
-
-        // argument 1: argv
-        Address argv(StackPointer, offsetToArgv);
+        Address argv(StackPointer, offsetToCoerceArgv);
         if (i->kind() == ABIArg::GPR) {
             masm.computeEffectiveAddress(argv, i->gpr());
         } else {
             masm.computeEffectiveAddress(argv, scratch);
             masm.storePtr(scratch, Address(StackPointer, i->offsetFromArgBase()));
         }
         i++;
         JS_ASSERT(i.done());
 
         // Call coercion function
         AssertStackAlignment(masm);
         switch (exit.sig().retType().which()) {
           case RetType::Signed:
             masm.call(AsmJSImmPtr(AsmJSImm_CoerceInPlace_ToInt32));
             masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, throwLabel);
-            masm.unboxInt32(Address(StackPointer, offsetToArgv), ReturnReg);
+            masm.unboxInt32(Address(StackPointer, offsetToCoerceArgv), ReturnReg);
             break;
           case RetType::Double:
             masm.call(AsmJSImmPtr(AsmJSImm_CoerceInPlace_ToNumber));
             masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, throwLabel);
-            masm.loadDouble(Address(StackPointer, offsetToArgv), ReturnDoubleReg);
+            masm.loadDouble(Address(StackPointer, offsetToCoerceArgv), ReturnDoubleReg);
             break;
           default:
             MOZ_ASSUME_UNREACHABLE("Unsupported convert type");
         }
 
         masm.jump(&done);
         masm.setFramePushed(0);
     }
@@ -6624,42 +6500,26 @@ GenerateFFIExit(ModuleCompiler &m, const
 // all the frames.
 static bool
 GenerateStackOverflowExit(ModuleCompiler &m, Label *throwLabel)
 {
     MacroAssembler &masm = m.masm();
     masm.align(CodeAlignment);
     masm.bind(&m.stackOverflowLabel());
 
-    // The stack-overflow is checked before bumping the stack.
+    // For the benefit of AssertStackAlignment.
     masm.setFramePushed(0);
 
     // Store the frame pointer in AsmJSActivation::exitFP for stack unwinding.
     Register activation = ABIArgGenerator::NonArgReturnVolatileReg0;
     LoadAsmJSActivationIntoRegister(masm, activation);
     masm.storePtr(StackPointer, Address(activation, AsmJSActivation::offsetOfExitFP()));
 
-    MIRTypeVector argTypes(m.cx());
-    argTypes.infallibleAppend(MIRType_Pointer); // cx
-
-    unsigned stackDec = StackDecrementForCall(masm, argTypes);
-    masm.reserveStack(stackDec);
-
-    ABIArgMIRTypeIter i(argTypes);
-
-    // argument 0: cx
-    if (i->kind() == ABIArg::GPR) {
-        LoadJSContextFromActivation(masm, activation, i->gpr());
-    } else {
-        LoadJSContextFromActivation(masm, activation, activation);
-        masm.storePtr(activation, Address(StackPointer, i->offsetFromArgBase()));
-    }
-    i++;
-
-    JS_ASSERT(i.done());
+    // Even without arguments, various platforms require stack adjustment.
+    masm.reserveStack(ComputeByteAlignment(AsmJSFrameSize + ShadowStackSpace, StackAlignment));
 
     AssertStackAlignment(masm);
     masm.call(AsmJSImmPtr(AsmJSImm_ReportOverRecursed));
 
     // Clear exitFP before the frame is destroyed.
     LoadAsmJSActivationIntoRegister(masm, activation);
     masm.storePtr(ImmWord(0), Address(activation, AsmJSActivation::offsetOfExitFP()));
 
@@ -6692,44 +6552,33 @@ GenerateAsyncInterruptExit(ModuleCompile
     // 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)
 
-    Register activation = ABIArgGenerator::NonArgReturnVolatileReg0;
-    Register scratch = ABIArgGenerator::NonArgReturnVolatileReg1;
+    Register scratch = ABIArgGenerator::NonArgReturnVolatileReg0;
 
     // Store resumePC into the reserved space.
-    LoadAsmJSActivationIntoRegister(masm, activation);
-    masm.loadPtr(Address(activation, AsmJSActivation::offsetOfResumePC()), scratch);
+    LoadAsmJSActivationIntoRegister(masm, scratch);
+    masm.loadPtr(Address(scratch, AsmJSActivation::offsetOfResumePC()), scratch);
     masm.storePtr(scratch, Address(StackPointer, masm.framePushed() + sizeof(void*)));
 
     // We know that StackPointer is word-aligned, but not necessarily
     // stack-aligned, so we need to align it dynamically.
     masm.mov(StackPointer, ABIArgGenerator::NonVolatileReg);
-#if defined(JS_CODEGEN_X86)
-    // Ensure that at least one slot is pushed for passing 'cx' below.
-    masm.push(Imm32(0));
-#endif
     masm.andPtr(Imm32(~(StackAlignment - 1)), StackPointer);
     if (ShadowStackSpace)
         masm.subPtr(Imm32(ShadowStackSpace), StackPointer);
 
-    // argument 0: cx
-#if defined(JS_CODEGEN_X86)
-    LoadJSContextFromActivation(masm, activation, scratch);
-    masm.storePtr(scratch, Address(StackPointer, 0));
-#elif defined(JS_CODEGEN_X64)
-    LoadJSContextFromActivation(masm, activation, IntArgReg0);
-#endif
-
+    AssertStackAlignment(masm);
     masm.call(AsmJSImmPtr(AsmJSImm_HandleExecutionInterrupt));
+
     masm.branchIfFalseBool(ReturnReg, throwLabel);
 
     // 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
@@ -6747,19 +6596,16 @@ GenerateAsyncInterruptExit(ModuleCompile
     // 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);
@@ -6786,19 +6632,16 @@ GenerateAsyncInterruptExit(ModuleCompile
     // Align the stack.
     masm.ma_and(Imm32(~7), sp, sp);
 
     // Store resumePC into the return PC stack slot.
     LoadAsmJSActivationIntoRegister(masm, IntArgReg0);
     masm.loadPtr(Address(IntArgReg0, AsmJSActivation::offsetOfResumePC()), IntArgReg1);
     masm.storePtr(IntArgReg1, Address(r6, 14 * sizeof(uint32_t*)));
 
-    // argument 0: cx
-    masm.loadPtr(Address(IntArgReg0, AsmJSActivation::offsetOfContext()), IntArgReg0);
-
     masm.PushRegsInMask(RegisterSet(GeneralRegisterSet(0), FloatRegisterSet(FloatRegisters::AllDoubleMask)));   // save all FP registers
     masm.call(AsmJSImm_HandleExecutionInterrupt);
     masm.branchIfFalseBool(ReturnReg, throwLabel);
 
     // Restore the machine state to before the interrupt. this will set the pc!
     masm.PopRegsInMask(RegisterSet(GeneralRegisterSet(0), FloatRegisterSet(FloatRegisters::AllDoubleMask)));   // restore all FP registers
     masm.mov(r6,sp);
     masm.as_vmsr(r5);
@@ -6837,49 +6680,33 @@ static bool
 GenerateSyncInterruptExit(ModuleCompiler &m, Label *throwLabel)
 {
     MacroAssembler &masm = m.masm();
 
     masm.setFramePushed(0);
     masm.align(CodeAlignment);
     masm.bind(&m.syncInterruptLabel());
 
-    MIRTypeVector argTypes(m.cx());
-    argTypes.infallibleAppend(MIRType_Pointer); // cx
-
     // See AsmJSFrameSize comment in Assembler-shared.h.
 #if defined(JS_CODEGEN_ARM)
     masm.push(lr);
 #elif defined(JS_CODEGEN_MIPS)
     masm.push(ra);
 #endif
 
     // Record sp in the AsmJSActivation for stack unwinding.
     Register activation = ABIArgGenerator::NonArgReturnVolatileReg0;
     LoadAsmJSActivationIntoRegister(masm, activation);
     masm.storePtr(StackPointer, Address(activation, AsmJSActivation::offsetOfExitFP()));
 
     masm.PushRegsInMask(VolatileRegs);
 
-    unsigned stackDec = StackDecrementForCall(masm, argTypes);
+    unsigned stackDec = StackDecrementForCall(masm, ShadowStackSpace);
     masm.reserveStack(stackDec);
 
-    ABIArgMIRTypeIter i(argTypes);
-
-    // argument 0: cx
-    if (i->kind() == ABIArg::GPR) {
-        LoadJSContextFromActivation(masm, activation, i->gpr());
-    } else {
-        LoadJSContextFromActivation(masm, activation, activation);
-        masm.storePtr(activation, Address(StackPointer, i->offsetFromArgBase()));
-    }
-    i++;
-
-    JS_ASSERT(i.done());
-
     AssertStackAlignment(masm);
     masm.call(AsmJSImmPtr(AsmJSImm_HandleExecutionInterrupt));
     masm.branchIfFalseBool(ReturnReg, throwLabel);
 
     masm.freeStack(stackDec);
     masm.PopRegsInMask(VolatileRegs);
 
     // Clear exitFP before the frame is destroyed.
--- a/js/src/jit/AsmJSModule.cpp
+++ b/js/src/jit/AsmJSModule.cpp
@@ -27,16 +27,17 @@
 
 #include "frontend/Parser.h"
 #include "jit/IonCode.h"
 #include "js/MemoryMetrics.h"
 
 #include "jsobjinlines.h"
 
 #include "frontend/ParseNode-inl.h"
+#include "vm/Stack-inl.h"
 
 using namespace js;
 using namespace jit;
 using namespace frontend;
 using mozilla::BinarySearch;
 using mozilla::PodCopy;
 using mozilla::PodEqual;
 using mozilla::Compression::LZ4;
@@ -443,51 +444,159 @@ AsmJSModule::finish(ExclusiveContext *cx
 
 void
 AsmJSModule::setAutoFlushICacheRange()
 {
     JS_ASSERT(isFinished());
     AutoFlushICache::setRange(uintptr_t(code_), pod.codeBytes_);
 }
 
+static void
+AsmJSReportOverRecursed()
+{
+    JSContext *cx = PerThreadData::innermostAsmJSActivation()->cx();
+    js_ReportOverRecursed(cx);
+}
+
+static void
+AsmJSHandleExecutionInterrupt()
+{
+    JSContext *cx = PerThreadData::innermostAsmJSActivation()->cx();
+    HandleExecutionInterrupt(cx);
+}
+
 static int32_t
-CoerceInPlace_ToInt32(JSContext *cx, MutableHandleValue val)
+CoerceInPlace_ToInt32(MutableHandleValue val)
 {
+    JSContext *cx = PerThreadData::innermostAsmJSActivation()->cx();
+
     int32_t i32;
     if (!ToInt32(cx, val, &i32))
         return false;
     val.set(Int32Value(i32));
 
     return true;
 }
 
 static int32_t
-CoerceInPlace_ToNumber(JSContext *cx, MutableHandleValue val)
+CoerceInPlace_ToNumber(MutableHandleValue val)
 {
+    JSContext *cx = PerThreadData::innermostAsmJSActivation()->cx();
+
     double dbl;
     if (!ToNumber(cx, val, &dbl))
         return false;
     val.set(DoubleValue(dbl));
 
     return true;
 }
 
-namespace js {
+static bool
+TryEnablingIon(JSContext *cx, AsmJSModule &module, HandleFunction fun, uint32_t exitIndex,
+               int32_t argc, Value *argv)
+{
+    if (!fun->hasScript())
+        return true;
+
+    // Test if the function is Ion compiled
+    JSScript *script = fun->nonLazyScript();
+    if (!script->hasIonScript())
+        return true;
+
+    // Currently we can't rectify arguments. Therefore disabling if argc is too low.
+    if (fun->nargs() > size_t(argc))
+        return true;
 
-// Defined in AsmJS.cpp:
+    // Normally the types should corresond, since we just ran with those types,
+    // but there are reports this is asserting. Therefore doing it as a check, instead of DEBUG only.
+    if (!types::TypeScript::ThisTypes(script)->hasType(types::Type::UndefinedType()))
+        return true;
+    for(uint32_t i = 0; i < fun->nargs(); i++) {
+        types::StackTypeSet *typeset = types::TypeScript::ArgTypes(script, i);
+        types::Type type = types::Type::DoubleType();
+        if (!argv[i].isDouble())
+            type = types::Type::PrimitiveType(argv[i].extractNonDoubleType());
+        if (!typeset->hasType(type))
+            return true;
+    }
 
-int32_t
-InvokeFromAsmJS_Ignore(JSContext *cx, int32_t exitIndex, int32_t argc, Value *argv);
+    // Enable
+    IonScript *ionScript = script->ionScript();
+    if (!ionScript->addDependentAsmJSModule(cx, DependentAsmJSModuleExit(&module, exitIndex)))
+        return false;
+
+    module.exitIndexToGlobalDatum(exitIndex).exit = module.ionExitTrampoline(module.exit(exitIndex));
+    return true;
+}
+
+static bool
+InvokeFromAsmJS(AsmJSActivation *activation, int32_t exitIndex, int32_t argc, Value *argv,
+                MutableHandleValue rval)
+{
+    JSContext *cx = activation->cx();
+    AsmJSModule &module = activation->module();
+
+    RootedFunction fun(cx, module.exitIndexToGlobalDatum(exitIndex).fun);
+    RootedValue fval(cx, ObjectValue(*fun));
+    if (!Invoke(cx, UndefinedValue(), fval, argc, argv, rval))
+        return false;
 
-int32_t
-InvokeFromAsmJS_ToInt32(JSContext *cx, int32_t exitIndex, int32_t argc, Value *argv);
+    return TryEnablingIon(cx, module, fun, exitIndex, argc, argv);
+}
+
+// Use an int32_t return type instead of bool since bool does not have a
+// specified width and the caller is assuming a word-sized return.
+static int32_t
+InvokeFromAsmJS_Ignore(int32_t exitIndex, int32_t argc, Value *argv)
+{
+    AsmJSActivation *activation = PerThreadData::innermostAsmJSActivation();
+    JSContext *cx = activation->cx();
+
+    RootedValue rval(cx);
+    return InvokeFromAsmJS(activation, exitIndex, argc, argv, &rval);
+}
+
+// Use an int32_t return type instead of bool since bool does not have a
+// specified width and the caller is assuming a word-sized return.
+static int32_t
+InvokeFromAsmJS_ToInt32(int32_t exitIndex, int32_t argc, Value *argv)
+{
+    AsmJSActivation *activation = PerThreadData::innermostAsmJSActivation();
+    JSContext *cx = activation->cx();
+
+    RootedValue rval(cx);
+    if (!InvokeFromAsmJS(activation, exitIndex, argc, argv, &rval))
+        return false;
 
-int32_t
-InvokeFromAsmJS_ToNumber(JSContext *cx, int32_t exitIndex, int32_t argc, Value *argv);
+    int32_t i32;
+    if (!ToInt32(cx, rval, &i32))
+        return false;
+
+    argv[0] = Int32Value(i32);
+    return true;
+}
 
+// Use an int32_t return type instead of bool since bool does not have a
+// specified width and the caller is assuming a word-sized return.
+static int32_t
+InvokeFromAsmJS_ToNumber(int32_t exitIndex, int32_t argc, Value *argv)
+{
+    AsmJSActivation *activation = PerThreadData::innermostAsmJSActivation();
+    JSContext *cx = activation->cx();
+
+    RootedValue rval(cx);
+    if (!InvokeFromAsmJS(activation, exitIndex, argc, argv, &rval))
+        return false;
+
+    double dbl;
+    if (!ToNumber(cx, rval, &dbl))
+        return false;
+
+    argv[0] = DoubleValue(dbl);
+    return true;
 }
 
 #if defined(JS_CODEGEN_ARM)
 extern "C" {
 
 extern MOZ_EXPORT int64_t
 __aeabi_idivmod(int, int);
 
@@ -519,29 +628,29 @@ AddressOf(AsmJSImmKind kind, ExclusiveCo
     switch (kind) {
       case AsmJSImm_Runtime:
         return cx->runtimeAddressForJit();
       case AsmJSImm_RuntimeInterrupt:
         return cx->runtimeAddressOfInterrupt();
       case AsmJSImm_StackLimit:
         return cx->stackLimitAddressForJitCode(StackForUntrustedScript);
       case AsmJSImm_ReportOverRecursed:
-        return RedirectCall(FuncCast<void (JSContext*)>(js_ReportOverRecursed), Args_General1);
+        return RedirectCall(FuncCast(AsmJSReportOverRecursed), Args_General0);
       case AsmJSImm_HandleExecutionInterrupt:
-        return RedirectCall(FuncCast(js::HandleExecutionInterrupt), Args_General1);
+        return RedirectCall(FuncCast(AsmJSHandleExecutionInterrupt), Args_General0);
       case AsmJSImm_InvokeFromAsmJS_Ignore:
-        return RedirectCall(FuncCast(InvokeFromAsmJS_Ignore), Args_General4);
+        return RedirectCall(FuncCast(InvokeFromAsmJS_Ignore), Args_General3);
       case AsmJSImm_InvokeFromAsmJS_ToInt32:
-        return RedirectCall(FuncCast(InvokeFromAsmJS_ToInt32), Args_General4);
+        return RedirectCall(FuncCast(InvokeFromAsmJS_ToInt32), Args_General3);
       case AsmJSImm_InvokeFromAsmJS_ToNumber:
-        return RedirectCall(FuncCast(InvokeFromAsmJS_ToNumber), Args_General4);
+        return RedirectCall(FuncCast(InvokeFromAsmJS_ToNumber), Args_General3);
       case AsmJSImm_CoerceInPlace_ToInt32:
-        return RedirectCall(FuncCast(CoerceInPlace_ToInt32), Args_General2);
+        return RedirectCall(FuncCast(CoerceInPlace_ToInt32), Args_General1);
       case AsmJSImm_CoerceInPlace_ToNumber:
-        return RedirectCall(FuncCast(CoerceInPlace_ToNumber), Args_General2);
+        return RedirectCall(FuncCast(CoerceInPlace_ToNumber), Args_General1);
       case AsmJSImm_ToInt32:
         return RedirectCall(FuncCast<int32_t (double)>(js::ToInt32), Args_Int_Double);
 #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
--- a/js/src/jit/AsmJSSignalHandlers.cpp
+++ b/js/src/jit/AsmJSSignalHandlers.cpp
@@ -145,26 +145,16 @@ using mozilla::DebugOnly;
 #else
 # error "Don't know how to read/write to the thread state via the mcontext_t."
 #endif
 
 // For platforms where the signal/exception handler runs on the same
 // thread/stack as the victim (Unix and Windows), we can use TLS to find any
 // currently executing asm.js code.
 #if !defined(XP_MACOSX)
-static AsmJSActivation *
-InnermostAsmJSActivation()
-{
-    PerThreadData *threadData = TlsPerThreadData.get();
-    if (!threadData)
-        return nullptr;
-
-    return threadData->asmJSActivationStackFromOwnerThread();
-}
-
 static JSRuntime *
 RuntimeForCurrentThread()
 {
     PerThreadData *threadData = TlsPerThreadData.get();
     if (!threadData)
         return nullptr;
 
     return threadData->runtimeIfOnOwnerThread();
@@ -446,17 +436,17 @@ HandleException(PEXCEPTION_POINTERS exce
     // Don't allow recursive handling of signals, see AutoSetHandlingSignal.
     if (!rt || rt->handlingSignal)
         return false;
     AutoSetHandlingSignal handling(rt);
 
     if (rt->jitRuntime() && rt->jitRuntime()->handleAccessViolation(rt, faultingAddress))
         return true;
 
-    AsmJSActivation *activation = InnermostAsmJSActivation();
+    AsmJSActivation *activation = PerThreadData::innermostAsmJSActivation();
     if (!activation)
         return false;
 
     const AsmJSModule &module = activation->module();
     if (!module.containsPC(pc))
         return false;
 
     // If we faulted trying to execute code in 'module', this must be an
@@ -643,17 +633,17 @@ HandleMachException(JSRuntime *rt, const
     if (request.body.exception != EXC_BAD_ACCESS || request.body.codeCnt != 2)
         return false;
 
     void *faultingAddress = (void*)request.body.code[1];
 
     if (rt->jitRuntime() && rt->jitRuntime()->handleAccessViolation(rt, faultingAddress))
         return true;
 
-    AsmJSActivation *activation = rt->mainThread.asmJSActivationStackFromAnyThread();
+    AsmJSActivation *activation = rt->mainThread.asmJSActivationStack();
     if (!activation)
         return false;
 
     const AsmJSModule &module = activation->module();
     if (HandleSimulatorInterrupt(rt, activation, faultingAddress)) {
         JSRuntime::AutoLockForInterrupt lock(rt);
         module.unprotectCode(rt);
         return true;
@@ -893,17 +883,17 @@ HandleSignal(int signum, siginfo_t *info
     // Don't allow recursive handling of signals, see AutoSetHandlingSignal.
     if (!rt || rt->handlingSignal)
         return false;
     AutoSetHandlingSignal handling(rt);
 
     if (rt->jitRuntime() && rt->jitRuntime()->handleAccessViolation(rt, faultingAddress))
         return true;
 
-    AsmJSActivation *activation = InnermostAsmJSActivation();
+    AsmJSActivation *activation = PerThreadData::innermostAsmJSActivation();
     if (!activation)
         return false;
 
     const AsmJSModule &module = activation->module();
     if (HandleSimulatorInterrupt(rt, activation, faultingAddress)) {
         JSRuntime::AutoLockForInterrupt lock(rt);
         module.unprotectCode(rt);
         return true;
@@ -1043,17 +1033,17 @@ js::RequestInterruptForAsmJSCode(JSRunti
       case JSRuntime::RequestInterruptAnyThreadDontStopIon:
       case JSRuntime::RequestInterruptAnyThreadForkJoin:
         // It is ok to wait for asm.js execution to complete; we aren't trying
         // to break an iloop or anything. Avoid the overhead of protecting all
         // the code and taking a fault.
         return;
     }
 
-    AsmJSActivation *activation = rt->mainThread.asmJSActivationStackFromAnyThread();
+    AsmJSActivation *activation = rt->mainThread.asmJSActivationStack();
     if (!activation)
         return;
 
     JS_ASSERT(rt->currentThreadOwnsInterruptLock());
     activation->module().protectCode(rt);
 }
 
 // This is not supported by clang-cl yet.
--- a/js/src/jit/arm/Simulator-arm.cpp
+++ b/js/src/jit/arm/Simulator-arm.cpp
@@ -4060,32 +4060,31 @@ Simulator::instructionDecode(SimInstruct
 
 template<bool EnableStopSimAt>
 void
 Simulator::execute()
 {
     // Get the PC to simulate. Cannot use the accessor here as we need the raw
     // PC value and not the one used as input to arithmetic instructions.
     int program_counter = get_pc();
-    AsmJSActivation *activation = TlsPerThreadData.get()->asmJSActivationStackFromOwnerThread();
 
     while (program_counter != end_sim_pc) {
         if (EnableStopSimAt && (icount_ == Simulator::StopSimAt)) {
             fprintf(stderr, "\nStopped simulation at icount %lld\n", icount_);
             ArmDebugger dbg(this);
             dbg.debug();
         } else {
             SimInstruction *instr = reinterpret_cast<SimInstruction *>(program_counter);
             instructionDecode(instr);
             icount_++;
 
             int32_t rpc = resume_pc_;
             if (MOZ_UNLIKELY(rpc != 0)) {
                 // AsmJS signal handler ran and we have to adjust the pc.
-                activation->setResumePC((void *)get_pc());
+                PerThreadData::innermostAsmJSActivation()->setResumePC((void *)get_pc());
                 set_pc(rpc);
                 resume_pc_ = 0;
             }
         }
         program_counter = get_pc();
     }
 }
 
--- a/js/src/jit/mips/Simulator-mips.cpp
+++ b/js/src/jit/mips/Simulator-mips.cpp
@@ -3305,17 +3305,17 @@ Simulator::branchDelayInstructionDecode(
 
 template<bool enableStopSimAt>
 void
 Simulator::execute()
 {
     // Get the PC to simulate. Cannot use the accessor here as we need the
     // raw PC value and not the one used as input to arithmetic instructions.
     int program_counter = get_pc();
-    AsmJSActivation *activation = TlsPerThreadData.get()->asmJSActivationStackFromOwnerThread();
+    AsmJSActivation *activation = TlsPerThreadData.get()->asmJSActivationStack();
 
     while (program_counter != end_sim_pc) {
         if (enableStopSimAt && (icount_ == Simulator::StopSimAt)) {
             MipsDebugger dbg(this);
             dbg.debug();
         } else {
             SimInstruction *instr = reinterpret_cast<SimInstruction *>(program_counter);
             instructionDecode(instr);
--- a/js/src/vm/ArrayBufferObject.cpp
+++ b/js/src/vm/ArrayBufferObject.cpp
@@ -543,17 +543,17 @@ ArrayBufferObject::releaseAsmJSArray(Fre
 }
 #endif
 
 bool
 ArrayBufferObject::canNeuterAsmJSArrayBuffer(JSContext *cx, ArrayBufferObject &buffer)
 {
     JS_ASSERT(!buffer.isSharedArrayBuffer());
 #ifdef JS_ION
-    AsmJSActivation *act = cx->mainThread().asmJSActivationStackFromOwnerThread();
+    AsmJSActivation *act = cx->mainThread().asmJSActivationStack();
     for (; act; act = act->prevAsmJS()) {
         if (act->module().maybeHeapBufferObject() == &buffer)
             break;
     }
     if (!act)
         return true;
 
     return false;
--- a/js/src/vm/Runtime.h
+++ b/js/src/vm/Runtime.h
@@ -586,21 +586,22 @@ class PerThreadData : public PerThreadDa
     }
     static unsigned offsetOfAsmJSActivationStackReadOnly() {
         return offsetof(PerThreadData, asmJSActivationStack_);
     }
     static unsigned offsetOfActivation() {
         return offsetof(PerThreadData, activation_);
     }
 
-    js::AsmJSActivation *asmJSActivationStackFromAnyThread() const {
+    js::AsmJSActivation *asmJSActivationStack() const {
         return asmJSActivationStack_;
     }
-    js::AsmJSActivation *asmJSActivationStackFromOwnerThread() const {
-        return asmJSActivationStack_;
+    static js::AsmJSActivation *innermostAsmJSActivation() {
+        PerThreadData *ptd = TlsPerThreadData.get();
+        return ptd ? ptd->asmJSActivationStack_ : nullptr;
     }
 
     js::Activation *activation() const {
         return activation_;
     }
 
     /* State used by jsdtoa.cpp. */
     DtoaState           *dtoaState;