Bug 1288483 - Baldr: stop using activation global pointer in JIT exit stub (r=h4writer)
authorLuke Wagner <luke@mozilla.com>
Thu, 21 Jul 2016 21:19:49 -0500
changeset 307549 75fbd8a856889d5a228ac7fd5237205a8efce488
parent 307548 7b84e80af381c13daa698ef81e9ddf8bdda223cd
child 307550 3585d9eed1fa07d65cc68a2e2ff48f2cabee1c3b
push id80123
push userlwagner@mozilla.com
push dateMon, 01 Aug 2016 13:31:24 +0000
treeherdermozilla-inbound@bc217e3f030d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersh4writer
bugs1288483
milestone50.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 1288483 - Baldr: stop using activation global pointer in JIT exit stub (r=h4writer) MozReview-Commit-ID: KpHJ2ijMn8x
js/src/asmjs/WasmStubs.cpp
js/src/asmjs/WasmTypes.cpp
js/src/asmjs/WasmTypes.h
js/src/jit/CodeGenerator.cpp
js/src/jit/arm/Assembler-arm.h
js/src/jit/arm64/Assembler-arm64.h
js/src/jit/mips-shared/Assembler-mips-shared.h
js/src/jit/none/MacroAssembler-none.h
js/src/jit/x64/Assembler-x64.h
js/src/jit/x86/Assembler-x86.h
js/src/jscntxt.h
js/src/vm/Stack.cpp
--- a/js/src/asmjs/WasmStubs.cpp
+++ b/js/src/asmjs/WasmStubs.cpp
@@ -641,104 +641,69 @@ wasm::GenerateJitExit(MacroAssembler& ma
 #if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
     static_assert(MaybeSavedGlobalReg == sizeof(void*), "stack frame accounting");
     masm.storePtr(GlobalReg, Address(masm.getStackPointer(), jitFrameBytes));
 #endif
 
     {
         // Enable Activation.
         //
-        // This sequence requires three registers, and needs to preserve the 'callee'
-        // register, so there are four live registers.
+        // This sequence requires two registers, and needs to preserve the
+        // 'callee' register, so there are three live registers.
         MOZ_ASSERT(callee == AsmJSIonExitRegCallee);
-        Register reg0 = AsmJSIonExitRegE0;
-        Register reg1 = AsmJSIonExitRegE1;
-        Register reg2 = AsmJSIonExitRegE2;
+        Register cx = AsmJSIonExitRegE0;
+        Register act = AsmJSIonExitRegE1;
 
-        // The following is inlined:
-        //   JSContext* cx = activation->cx();
-        //   Activation* act = cx->activation();
-        //   act.active_ = true;
-        //   act.prevJitTop_ = cx->jitTop;
-        //   act.prevJitActivation_ = cx->jitActivation;
-        //   cx->jitActivation = act;
-        //   act.prevProfilingActivation_ = cx->profilingActivation;
-        //   cx->profilingActivation_ = act;
-        // On the ARM store8() uses the secondScratchReg (lr) as a temp.
-        size_t offsetOfActivation = JSContext::offsetOfActivation();
-        size_t offsetOfJitTop = offsetof(JSContext, jitTop);
-        size_t offsetOfJitActivation = offsetof(JSContext, jitActivation);
-        size_t offsetOfProfilingActivation = JSContext::offsetOfProfilingActivation();
-        masm.loadWasmActivation(reg0);
-        masm.loadPtr(Address(reg0, WasmActivation::offsetOfContext()), reg0);
-        masm.loadPtr(Address(reg0, offsetOfActivation), reg1);
+        // JitActivation* act = cx->activation();
+        masm.movePtr(SymbolicAddress::Context, cx);
+        masm.loadPtr(Address(cx, JSContext::offsetOfActivation()), act);
 
-        //   act.active_ = true;
-        masm.store8(Imm32(1), Address(reg1, JitActivation::offsetOfActiveUint8()));
-
-        //   act.prevJitTop_ = cx->jitTop;
-        masm.loadPtr(Address(reg0, offsetOfJitTop), reg2);
-        masm.storePtr(reg2, Address(reg1, JitActivation::offsetOfPrevJitTop()));
+        // act.active_ = true;
+        masm.store8(Imm32(1), Address(act, JitActivation::offsetOfActiveUint8()));
 
-        //   act.prevJitActivation_ = cx->jitActivation;
-        masm.loadPtr(Address(reg0, offsetOfJitActivation), reg2);
-        masm.storePtr(reg2, Address(reg1, JitActivation::offsetOfPrevJitActivation()));
-        //   cx->jitActivation = act;
-        masm.storePtr(reg1, Address(reg0, offsetOfJitActivation));
+        // cx->jitActivation = act;
+        masm.storePtr(act, Address(cx, offsetof(JSContext, jitActivation)));
 
-        //   act.prevProfilingActivation_ = cx->profilingActivation;
-        masm.loadPtr(Address(reg0, offsetOfProfilingActivation), reg2);
-        masm.storePtr(reg2, Address(reg1, Activation::offsetOfPrevProfiling()));
-        //   cx->profilingActivation_ = act;
-        masm.storePtr(reg1, Address(reg0, offsetOfProfilingActivation));
+        // cx->profilingActivation_ = act;
+        masm.storePtr(act, Address(cx, JSContext::offsetOfProfilingActivation()));
     }
 
     AssertStackAlignment(masm, JitStackAlignment, sizeOfRetAddr);
     masm.callJitNoProfiler(callee);
     AssertStackAlignment(masm, JitStackAlignment, sizeOfRetAddr);
 
     {
         // Disable Activation.
         //
         // This sequence needs three registers, and must preserve the JSReturnReg_Data and
         // JSReturnReg_Type, so there are five live registers.
         MOZ_ASSERT(JSReturnReg_Data == AsmJSIonExitRegReturnData);
         MOZ_ASSERT(JSReturnReg_Type == AsmJSIonExitRegReturnType);
-        Register reg0 = AsmJSIonExitRegD0;
-        Register reg1 = AsmJSIonExitRegD1;
-        Register reg2 = AsmJSIonExitRegD2;
+        Register cx = AsmJSIonExitRegD0;
+        Register act = AsmJSIonExitRegD1;
+        Register tmp = AsmJSIonExitRegD2;
 
-        // The following is inlined:
-        //   rt->profilingActivation = prevProfilingActivation_;
-        //   rt->activation()->active_ = false;
-        //   rt->jitTop = prevJitTop_;
-        //   rt->jitActivation = prevJitActivation_;
-        // On the ARM store8() uses the secondScratchReg (lr) as a temp.
-        size_t offsetOfActivation = JSRuntime::offsetOfActivation();
-        size_t offsetOfJitTop = offsetof(JSRuntime, jitTop);
-        size_t offsetOfJitActivation = offsetof(JSRuntime, jitActivation);
-        size_t offsetOfProfilingActivation = JSRuntime::offsetOfProfilingActivation();
+        // JitActivation* act = cx->activation();
+        masm.movePtr(SymbolicAddress::Context, cx);
+        masm.loadPtr(Address(cx, JSContext::offsetOfActivation()), act);
 
-        masm.movePtr(SymbolicAddress::Runtime, reg0);
-        masm.loadPtr(Address(reg0, offsetOfActivation), reg1);
-
-        //   rt->jitTop = prevJitTop_;
-        masm.loadPtr(Address(reg1, JitActivation::offsetOfPrevJitTop()), reg2);
-        masm.storePtr(reg2, Address(reg0, offsetOfJitTop));
+        // cx->jitTop = act->prevJitTop_;
+        masm.loadPtr(Address(act, JitActivation::offsetOfPrevJitTop()), tmp);
+        masm.storePtr(tmp, Address(cx, offsetof(JSContext, jitTop)));
 
-        //   rt->profilingActivation = rt->activation()->prevProfiling_;
-        masm.loadPtr(Address(reg1, Activation::offsetOfPrevProfiling()), reg2);
-        masm.storePtr(reg2, Address(reg0, offsetOfProfilingActivation));
+        // cx->jitActivation = act->prevJitActivation_;
+        masm.loadPtr(Address(act, JitActivation::offsetOfPrevJitActivation()), tmp);
+        masm.storePtr(tmp, Address(cx, offsetof(JSContext, jitActivation)));
 
-        //   rt->activation()->active_ = false;
-        masm.store8(Imm32(0), Address(reg1, JitActivation::offsetOfActiveUint8()));
+        // cx->profilingActivation = act->prevProfilingActivation_;
+        masm.loadPtr(Address(act, Activation::offsetOfPrevProfiling()), tmp);
+        masm.storePtr(tmp, Address(cx, JSContext::offsetOfProfilingActivation()));
 
-        //   rt->jitActivation = prevJitActivation_;
-        masm.loadPtr(Address(reg1, JitActivation::offsetOfPrevJitActivation()), reg2);
-        masm.storePtr(reg2, Address(reg0, offsetOfJitActivation));
+        // act->active_ = false;
+        masm.store8(Imm32(0), Address(act, JitActivation::offsetOfActiveUint8()));
     }
 
     // Reload the global register since JIT code can clobber any register.
 #if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
     static_assert(MaybeSavedGlobalReg == sizeof(void*), "stack frame accounting");
     masm.loadPtr(Address(masm.getStackPointer(), jitFrameBytes), GlobalReg);
 #endif
 
--- a/js/src/asmjs/WasmTypes.cpp
+++ b/js/src/asmjs/WasmTypes.cpp
@@ -248,19 +248,19 @@ FuncCast(F* pf, ABIFunctionType type)
 #endif
     return pv;
 }
 
 void*
 wasm::AddressOf(SymbolicAddress imm, ExclusiveContext* cx)
 {
     switch (imm) {
-      case SymbolicAddress::Runtime:
-        return cx->runtimeAddressForJit();
-      case SymbolicAddress::RuntimeInterruptUint32:
+      case SymbolicAddress::Context:
+        return cx->contextAddressForJit();
+      case SymbolicAddress::InterruptUint32:
         return cx->runtimeAddressOfInterruptUint32();
       case SymbolicAddress::ReportOverRecursed:
         return FuncCast(WasmReportOverRecursed, Args_General0);
       case SymbolicAddress::HandleExecutionInterrupt:
         return FuncCast(WasmHandleExecutionInterrupt, Args_General0);
       case SymbolicAddress::HandleTrap:
         return FuncCast(HandleTrap, Args_General1);
       case SymbolicAddress::CallImport_Void:
--- a/js/src/asmjs/WasmTypes.h
+++ b/js/src/asmjs/WasmTypes.h
@@ -881,18 +881,18 @@ enum class SymbolicAddress
     TruncD,
     TruncF,
     NearbyIntD,
     NearbyIntF,
     ExpD,
     LogD,
     PowD,
     ATan2D,
-    Runtime,
-    RuntimeInterruptUint32,
+    Context,
+    InterruptUint32,
     ReportOverRecursed,
     HandleExecutionInterrupt,
     HandleTrap,
     CallImport_Void,
     CallImport_I32,
     CallImport_I64,
     CallImport_F64,
     CoerceInPlace_ToInt32,
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -11457,20 +11457,17 @@ CodeGenerator::visitInterruptCheck(LInte
     masm.branch32(Assembler::NotEqual, interruptAddr, Imm32(0), ool->entry());
     masm.bind(ool->rejoin());
 }
 
 void
 CodeGenerator::visitAsmJSInterruptCheck(LAsmJSInterruptCheck* lir)
 {
     Label rejoin;
-    masm.branch32(Assembler::Equal,
-                  wasm::SymbolicAddress::RuntimeInterruptUint32,
-                  Imm32(0),
-                  &rejoin);
+    masm.branch32(Assembler::Equal, wasm::SymbolicAddress::InterruptUint32, Imm32(0), &rejoin);
 
     MOZ_ASSERT((sizeof(AsmJSFrame) + masm.framePushed()) % ABIStackAlignment == 0);
     masm.call(wasm::SymbolicAddress::HandleExecutionInterrupt);
     masm.branchIfFalseBool(ReturnReg, wasm::JumpTarget::Throw);
 
     masm.bind(&rejoin);
 }
 
--- a/js/src/jit/arm/Assembler-arm.h
+++ b/js/src/jit/arm/Assembler-arm.h
@@ -155,17 +155,16 @@ struct ScratchDoubleScope : public AutoF
 // negative immediate offsets which doubles the range of global data that can be
 // accessed with a single instruction.
 static const int32_t AsmJSGlobalRegBias = 1024;
 
 // Registers used in the GenerateFFIIonExit Enable Activation block.
 static constexpr Register AsmJSIonExitRegCallee = r4;
 static constexpr Register AsmJSIonExitRegE0 = r0;
 static constexpr Register AsmJSIonExitRegE1 = r1;
-static constexpr Register AsmJSIonExitRegE2 = r2;
 
 // Registers used in the GenerateFFIIonExit Disable Activation block.
 // None of these may be the second scratch register (lr).
 static constexpr Register AsmJSIonExitRegReturnData = r2;
 static constexpr Register AsmJSIonExitRegReturnType = r3;
 static constexpr Register AsmJSIonExitRegD0 = r0;
 static constexpr Register AsmJSIonExitRegD1 = r1;
 static constexpr Register AsmJSIonExitRegD2 = r4;
--- a/js/src/jit/arm64/Assembler-arm64.h
+++ b/js/src/jit/arm64/Assembler-arm64.h
@@ -123,17 +123,16 @@ REGISTER_CODE_LIST(IMPORT_VIXL_VREGISTER
 #undef IMPORT_VIXL_VREGISTERS
 
 static constexpr ValueOperand JSReturnOperand = ValueOperand(JSReturnReg);
 
 // Registers used in the GenerateFFIIonExit Enable Activation block.
 static constexpr Register AsmJSIonExitRegCallee = r8;
 static constexpr Register AsmJSIonExitRegE0 = r0;
 static constexpr Register AsmJSIonExitRegE1 = r1;
-static constexpr Register AsmJSIonExitRegE2 = r2;
 
 // Registers used in the GenerateFFIIonExit Disable Activation block.
 // None of these may be the second scratch register.
 static constexpr Register AsmJSIonExitRegReturnData = r2;
 static constexpr Register AsmJSIonExitRegReturnType = r3;
 static constexpr Register AsmJSIonExitRegD0 = r0;
 static constexpr Register AsmJSIonExitRegD1 = r1;
 static constexpr Register AsmJSIonExitRegD2 = r4;
--- a/js/src/jit/mips-shared/Assembler-mips-shared.h
+++ b/js/src/jit/mips-shared/Assembler-mips-shared.h
@@ -116,17 +116,16 @@ static constexpr Register WasmTlsReg = s
 // negative immediate offsets which doubles the range of global data that can be
 // accessed with a single instruction.
 static const int32_t AsmJSGlobalRegBias = 32768;
 
 // Registers used in the GenerateFFIIonExit Enable Activation block.
 static constexpr Register AsmJSIonExitRegCallee = t0;
 static constexpr Register AsmJSIonExitRegE0 = a0;
 static constexpr Register AsmJSIonExitRegE1 = a1;
-static constexpr Register AsmJSIonExitRegE2 = a2;
 
 // Registers used in the GenerateFFIIonExit Disable Activation block.
 // None of these may be the second scratch register (t8).
 static constexpr Register AsmJSIonExitRegD0 = a0;
 static constexpr Register AsmJSIonExitRegD1 = a1;
 static constexpr Register AsmJSIonExitRegD2 = t0;
 
 // Registerd used in RegExpMatcher instruction (do not use JSReturnOperand).
--- a/js/src/jit/none/MacroAssembler-none.h
+++ b/js/src/jit/none/MacroAssembler-none.h
@@ -41,17 +41,16 @@ static constexpr Register IntArgReg1 = {
 static constexpr Register IntArgReg2 = { Registers::invalid_reg };
 static constexpr Register IntArgReg3 = { Registers::invalid_reg };
 static constexpr Register GlobalReg = { Registers::invalid_reg };
 static constexpr Register HeapReg = { Registers::invalid_reg };
 
 static constexpr Register AsmJSIonExitRegCallee = { Registers::invalid_reg };
 static constexpr Register AsmJSIonExitRegE0 = { Registers::invalid_reg };
 static constexpr Register AsmJSIonExitRegE1 = { Registers::invalid_reg };
-static constexpr Register AsmJSIonExitRegE2 = { Registers::invalid_reg };
 
 static constexpr Register AsmJSIonExitRegReturnData = { Registers::invalid_reg };
 static constexpr Register AsmJSIonExitRegReturnType = { Registers::invalid_reg };
 static constexpr Register AsmJSIonExitRegD0 = { Registers::invalid_reg };
 static constexpr Register AsmJSIonExitRegD1 = { Registers::invalid_reg };
 static constexpr Register AsmJSIonExitRegD2 = { Registers::invalid_reg };
 
 static constexpr Register RegExpTesterRegExpReg = { Registers::invalid_reg };
--- a/js/src/jit/x64/Assembler-x64.h
+++ b/js/src/jit/x64/Assembler-x64.h
@@ -153,17 +153,16 @@ static constexpr FloatRegister FloatArgR
 // any other register used for passing function arguments or return values.
 // Preserved by WebAssembly functions.
 static constexpr Register WasmTlsReg = r14;
 
 // Registers used in the GenerateFFIIonExit Enable Activation block.
 static constexpr Register AsmJSIonExitRegCallee = r10;
 static constexpr Register AsmJSIonExitRegE0 = rax;
 static constexpr Register AsmJSIonExitRegE1 = rdi;
-static constexpr Register AsmJSIonExitRegE2 = rbx;
 
 // Registers used in the GenerateFFIIonExit Disable Activation block.
 static constexpr Register AsmJSIonExitRegReturnData = ecx;
 static constexpr Register AsmJSIonExitRegReturnType = ecx;
 static constexpr Register AsmJSIonExitRegD0 = rax;
 static constexpr Register AsmJSIonExitRegD1 = rdi;
 static constexpr Register AsmJSIonExitRegD2 = rbx;
 
--- a/js/src/jit/x86/Assembler-x86.h
+++ b/js/src/jit/x86/Assembler-x86.h
@@ -101,17 +101,16 @@ static constexpr Register WasmTableCallS
 
 static constexpr Register OsrFrameReg = edx;
 static constexpr Register PreBarrierReg = edx;
 
 // Registers used in the GenerateFFIIonExit Enable Activation block.
 static constexpr Register AsmJSIonExitRegCallee = ecx;
 static constexpr Register AsmJSIonExitRegE0 = edi;
 static constexpr Register AsmJSIonExitRegE1 = eax;
-static constexpr Register AsmJSIonExitRegE2 = ebx;
 
 // Registers used in the GenerateFFIIonExit Disable Activation block.
 static constexpr Register AsmJSIonExitRegReturnData = edx;
 static constexpr Register AsmJSIonExitRegReturnType = ecx;
 static constexpr Register AsmJSIonExitRegD0 = edi;
 static constexpr Register AsmJSIonExitRegD1 = eax;
 static constexpr Register AsmJSIonExitRegD2 = esi;
 
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -207,17 +207,17 @@ class ExclusiveContext : public ContextF
     }
     bool isPermanentAtomsInitialized() { return !!runtime_->permanentAtoms; }
     FrozenAtomSet& permanentAtoms() { return *runtime_->permanentAtoms; }
     WellKnownSymbols& wellKnownSymbols() { return *runtime_->wellKnownSymbols; }
     JS::BuildIdOp buildIdOp() { return runtime_->buildIdOp; }
     const JS::AsmJSCacheOps& asmJSCacheOps() { return runtime_->asmJSCacheOps; }
     PropertyName* emptyString() { return runtime_->emptyString; }
     FreeOp* defaultFreeOp() { return runtime_->defaultFreeOp(); }
-    void* runtimeAddressForJit() { return runtime_; }
+    void* contextAddressForJit() { return runtime_->unsafeContextFromAnyThread(); }
     void* runtimeAddressOfInterruptUint32() { return runtime_->addressOfInterruptUint32(); }
     void* stackLimitAddress(StackKind kind) { return &runtime_->mainThread.nativeStackLimit[kind]; }
     void* stackLimitAddressForJitCode(StackKind kind);
     uintptr_t stackLimit(StackKind kind) { return runtime_->mainThread.nativeStackLimit[kind]; }
     size_t gcSystemPageSize() { return gc::SystemPageSize(); }
     bool jitSupportsFloatingPoint() const { return runtime_->jitSupportsFloatingPoint; }
     bool jitSupportsUnalignedAccesses() const { return runtime_->jitSupportsUnalignedAccesses; }
     bool jitSupportsSimd() const { return runtime_->jitSupportsSimd; }
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -1381,43 +1381,42 @@ ActivationEntryMonitor::ActivationEntryM
             entryMonitor_->Entry(cx_, jit::CalleeTokenToScript(entryToken), stack, asyncCause);
     }
 }
 
 /*****************************************************************************/
 
 jit::JitActivation::JitActivation(JSContext* cx, bool active)
   : Activation(cx, Jit),
+    prevJitTop_(cx->runtime()->jitTop),
+    prevJitActivation_(cx->runtime()->jitActivation),
     active_(active),
     rematerializedFrames_(nullptr),
     ionRecovery_(cx),
     bailoutData_(nullptr),
     lastProfilingFrame_(nullptr),
     lastProfilingCallSite_(nullptr)
 {
     if (active) {
-        prevJitTop_ = cx->runtime()->jitTop;
-        prevJitActivation_ = cx->runtime()->jitActivation;
         cx->runtime()->jitActivation = this;
-
         registerProfiling();
-    } else {
-        prevJitTop_ = nullptr;
-        prevJitActivation_ = nullptr;
     }
 }
 
 jit::JitActivation::~JitActivation()
 {
     if (active_) {
         if (isProfiling())
             unregisterProfiling();
 
         cx_->runtime()->jitTop = prevJitTop_;
         cx_->runtime()->jitActivation = prevJitActivation_;
+    } else {
+        MOZ_ASSERT(cx_->runtime()->jitTop == prevJitTop_);
+        MOZ_ASSERT(cx_->runtime()->jitActivation == prevJitActivation_);
     }
 
     // All reocvered value are taken from activation during the bailout.
     MOZ_ASSERT(ionRecovery_.empty());
 
     // The BailoutFrameInfo should have unregistered itself from the
     // JitActivations.
     MOZ_ASSERT(!bailoutData_);
@@ -1442,31 +1441,31 @@ jit::JitActivation::setBailoutData(jit::
 
 void
 jit::JitActivation::cleanBailoutData()
 {
     MOZ_ASSERT(bailoutData_);
     bailoutData_ = nullptr;
 }
 
-// setActive() is inlined in GenerateFFIIonExit() with explicit masm instructions so
-// changes to the logic here need to be reflected in GenerateFFIIonExit() in the enable
+// setActive() is inlined in GenerateJitExit() with explicit masm instructions so
+// changes to the logic here need to be reflected in GenerateJitExit() 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.)
     MOZ_ASSERT(cx->runtime()->activation_ == this);
     MOZ_ASSERT(active != active_);
 
     if (active) {
         *((volatile bool*) active_) = true;
-        prevJitTop_ = cx->runtime()->jitTop;
-        prevJitActivation_ = cx->runtime()->jitActivation;
+        MOZ_ASSERT(prevJitTop_ == cx->runtime()->jitTop);
+        MOZ_ASSERT(prevJitActivation_ == cx->runtime()->jitActivation);
         cx->runtime()->jitActivation = this;
 
         registerProfiling();
 
     } else {
         unregisterProfiling();
 
         cx->runtime()->jitTop = prevJitTop_;