Bug 1288483 - Baldr: replace the mutable WasmActivation* in global data with an immutable JSContext* (r=bbouvier)
authorLuke Wagner <luke@mozilla.com>
Mon, 01 Aug 2016 08:26:40 -0500
changeset 307551 83b64a0c1eb4726f21f841fc31f249f7fc01cf42
parent 307550 3585d9eed1fa07d65cc68a2e2ff48f2cabee1c3b
child 307552 da7179ab387341e441844a7d2bc69826a22bf46e
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)
reviewersbbouvier
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: replace the mutable WasmActivation* in global data with an immutable JSContext* (r=bbouvier) MozReview-Commit-ID: ESQ5RhdlcLA
js/src/asmjs/WasmFrameIterator.cpp
js/src/asmjs/WasmInstance.cpp
js/src/asmjs/WasmInstance.h
js/src/asmjs/WasmTypes.h
js/src/jit/MacroAssembler.h
js/src/jscntxt.h
js/src/vm/Stack.cpp
js/src/vm/Stack.h
--- a/js/src/asmjs/WasmFrameIterator.cpp
+++ b/js/src/asmjs/WasmFrameIterator.cpp
@@ -182,39 +182,39 @@ FrameIterator::lineOrBytecode() const
 // These constants reflect statically-determined offsets in the profiling
 // prologue/epilogue. The offsets are dynamically asserted during code
 // generation.
 #if defined(JS_CODEGEN_X64)
 # if defined(DEBUG)
 static const unsigned PushedRetAddr = 0;
 static const unsigned PostStorePrePopFP = 0;
 # endif
-static const unsigned PushedFP = 13;
-static const unsigned StoredFP = 20;
+static const unsigned PushedFP = 20;
+static const unsigned StoredFP = 27;
 #elif defined(JS_CODEGEN_X86)
 # if defined(DEBUG)
 static const unsigned PushedRetAddr = 0;
 static const unsigned PostStorePrePopFP = 0;
 # endif
-static const unsigned PushedFP = 8;
-static const unsigned StoredFP = 11;
+static const unsigned PushedFP = 14;
+static const unsigned StoredFP = 17;
 #elif defined(JS_CODEGEN_ARM)
 static const unsigned PushedRetAddr = 4;
-static const unsigned PushedFP = 16;
-static const unsigned StoredFP = 20;
+static const unsigned PushedFP = 20;
+static const unsigned StoredFP = 24;
 static const unsigned PostStorePrePopFP = 4;
 #elif defined(JS_CODEGEN_ARM64)
 static const unsigned PushedRetAddr = 0;
 static const unsigned PushedFP = 0;
 static const unsigned StoredFP = 0;
 static const unsigned PostStorePrePopFP = 0;
 #elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
 static const unsigned PushedRetAddr = 8;
-static const unsigned PushedFP = 24;
-static const unsigned StoredFP = 28;
+static const unsigned PushedFP = 28;
+static const unsigned StoredFP = 32;
 static const unsigned PostStorePrePopFP = 4;
 #elif defined(JS_CODEGEN_NONE)
 # if defined(DEBUG)
 static const unsigned PushedRetAddr = 0;
 static const unsigned PostStorePrePopFP = 0;
 # endif
 static const unsigned PushedFP = 1;
 static const unsigned StoredFP = 1;
@@ -245,17 +245,17 @@ GenerateProfilingPrologue(MacroAssembler
 
     // ProfilingFrameIterator needs to know the offsets of several key
     // instructions from entry. To save space, we make these offsets static
     // constants and assert that they match the actual codegen below. On ARM,
     // this requires AutoForbidPools to prevent a constant pool from being
     // randomly inserted between two instructions.
     {
 #if defined(JS_CODEGEN_ARM)
-        AutoForbidPools afp(&masm, /* number of instructions in scope = */ 5);
+        AutoForbidPools afp(&masm, /* number of instructions in scope = */ 6);
 #endif
 
         offsets->begin = masm.currentOffset();
 
         PushRetAddr(masm);
         MOZ_ASSERT_IF(!masm.oom(), PushedRetAddr == masm.currentOffset() - offsets->begin);
 
         masm.loadWasmActivation(scratch);
--- a/js/src/asmjs/WasmInstance.cpp
+++ b/js/src/asmjs/WasmInstance.cpp
@@ -89,16 +89,22 @@ class SigIdSet
             js_delete(p->key());
             map_.remove(p);
         }
     }
 };
 
 ExclusiveData<SigIdSet> sigIdSet;
 
+JSContext**
+Instance::addressOfContextPtr() const
+{
+    return (JSContext**)(codeSegment_->globalData() + ContextPtrGlobalDataOffset);
+}
+
 uint8_t**
 Instance::addressOfMemoryBase() const
 {
     return (uint8_t**)(codeSegment_->globalData() + HeapGlobalDataOffset);
 }
 
 void**
 Instance::addressOfTableBase(size_t tableIndex) const
@@ -116,22 +122,16 @@ Instance::addressOfSigId(const SigIdDesc
 
 FuncImportExit&
 Instance::funcImportToExit(const FuncImport& fi)
 {
     MOZ_ASSERT(fi.exitGlobalDataOffset() >= InitialGlobalDataBytes);
     return *(FuncImportExit*)(codeSegment_->globalData() + fi.exitGlobalDataOffset());
 }
 
-WasmActivation*&
-Instance::activation()
-{
-    return *(WasmActivation**)(codeSegment_->globalData() + ActivationGlobalDataOffset);
-}
-
 bool
 Instance::ensureProfilingState(JSContext* cx, bool newProfilingEnabled)
 {
     if (profilingEnabled_ == newProfilingEnabled)
         return true;
 
     // When enabled, generate profiling labels for every name in funcNames_
     // that is the name of some Function CodeRange. This involves malloc() so
@@ -390,16 +390,18 @@ Instance::Instance(JSContext* cx,
     maybeBytecode_(maybeBytecode),
     memory_(memory),
     tables_(Move(tables)),
     profilingEnabled_(false)
 {
     MOZ_ASSERT(funcImports.length() == metadata.funcImports.length());
     MOZ_ASSERT(tables_.length() == metadata.tables.length());
 
+    *addressOfContextPtr() = cx;
+
     for (size_t i = 0; i < metadata.funcImports.length(); i++) {
         const FuncImport& fi = metadata.funcImports[i];
         FuncImportExit& exit = funcImportToExit(fi);
         exit.code = codeSegment_->code() + fi.interpExitCodeOffset();
         exit.fun = funcImports[i];
         exit.baselineScript = nullptr;
     }
 
--- a/js/src/asmjs/WasmInstance.h
+++ b/js/src/asmjs/WasmInstance.h
@@ -54,29 +54,25 @@ class Instance
     UniquePtr<GeneratedSourceMap>        maybeSourceMap_;
 
     // Thread-local data for code running in this instance.
     // When threading is supported, we need a TlsData object per thread per
     // instance.
     TlsData                              tlsData_;
 
     // Internal helpers:
+    JSContext** addressOfContextPtr() const;
     uint8_t** addressOfMemoryBase() const;
     void** addressOfTableBase(size_t tableIndex) const;
     const void** addressOfSigId(const SigIdDesc& sigId) const;
     FuncImportExit& funcImportToExit(const FuncImport& fi);
 
     // Get this instance's TLS data pointer for the current thread.
     TlsData* tlsData() { return &tlsData_; }
 
-    // An instance keeps track of its innermost WasmActivation. A WasmActivation
-    // is pushed for the duration of each call of an export.
-    friend class js::WasmActivation;
-    WasmActivation*& activation();
-
     // Import call slow paths which are called directly from wasm code.
     friend void* AddressOf(SymbolicAddress, ExclusiveContext*);
     bool callImport(JSContext* cx, uint32_t funcImportIndex, unsigned argc, const uint64_t* argv,
                     MutableHandleValue rval);
     static int32_t callImport_void(int32_t importIndex, int32_t argc, uint64_t* argv);
     static int32_t callImport_i32(int32_t importIndex, int32_t argc, uint64_t* argv);
     static int32_t callImport_i64(int32_t importIndex, int32_t argc, uint64_t* argv);
     static int32_t callImport_f64(int32_t importIndex, int32_t argc, uint64_t* argv);
--- a/js/src/asmjs/WasmTypes.h
+++ b/js/src/asmjs/WasmTypes.h
@@ -1058,18 +1058,18 @@ typedef int32_t (*ExportFuncPtr)(ExportA
 // requires linear memory to always be a multiple of 64KiB.
 static const unsigned PageSize = 64 * 1024;
 
 #ifdef ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB
 static const uint64_t Uint32Range = uint64_t(UINT32_MAX) + 1;
 static const uint64_t MappedSize = 2 * Uint32Range + PageSize;
 #endif
 
-static const unsigned ActivationGlobalDataOffset = 0;
-static const unsigned HeapGlobalDataOffset       = ActivationGlobalDataOffset + sizeof(void*);
+static const unsigned ContextPtrGlobalDataOffset = 0;
+static const unsigned HeapGlobalDataOffset       = ContextPtrGlobalDataOffset + sizeof(void*);
 static const unsigned NaN64GlobalDataOffset      = HeapGlobalDataOffset + sizeof(void*);
 static const unsigned NaN32GlobalDataOffset      = NaN64GlobalDataOffset + sizeof(double);
 static const unsigned InitialGlobalDataBytes     = NaN32GlobalDataOffset + sizeof(float);
 
 static const unsigned MaxSigs                    =        4 * 1024;
 static const unsigned MaxFuncs                   =      512 * 1024;
 static const unsigned MaxGlobals                 =        4 * 1024;
 static const unsigned MaxLocals                  =       64 * 1024;
--- a/js/src/jit/MacroAssembler.h
+++ b/js/src/jit/MacroAssembler.h
@@ -1366,17 +1366,18 @@ class MacroAssembler : public MacroAssem
 
     void loadJSContext(Register dest) {
         movePtr(ImmPtr(GetJitContext()->runtime->getJSContext()), dest);
     }
     void loadJitActivation(Register dest) {
         loadPtr(AbsoluteAddress(GetJitContext()->runtime->addressOfActivation()), dest);
     }
     void loadWasmActivation(Register dest) {
-        loadWasmGlobalPtr(wasm::ActivationGlobalDataOffset, dest);
+        loadWasmGlobalPtr(wasm::ContextPtrGlobalDataOffset, dest);
+        loadPtr(Address(dest, JSContext::offsetOfWasmActivation()), dest);
     }
 
     template<typename T>
     void loadTypedOrValue(const T& src, TypedOrValueRegister dest) {
         if (dest.hasValue())
             loadValue(src, dest.valueReg());
         else
             loadUnboxedValue(src, dest.type(), dest.typedReg());
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -335,16 +335,19 @@ struct JSContext : public js::ExclusiveC
     using ExclusiveContext::wellKnownSymbols;
 
     JSRuntime* runtime() { return this; }
     js::PerThreadData& mainThread() { return this->JSRuntime::mainThread; }
 
     static size_t offsetOfActivation() {
         return offsetof(JSContext, activation_);
     }
+    static size_t offsetOfWasmActivation() {
+        return offsetof(JSContext, wasmActivationStack_);
+    }
     static size_t offsetOfProfilingActivation() {
         return offsetof(JSContext, profilingActivation_);
      }
     static size_t offsetOfCompartment() {
         return offsetof(JSContext, compartment_);
     }
 
     friend class js::ExclusiveContext;
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -1626,20 +1626,17 @@ jit::JitActivation::markIonRecovery(JSTr
 WasmActivation::WasmActivation(JSContext* cx, wasm::Instance& instance)
   : Activation(cx, Wasm),
     instance_(instance),
     entrySP_(nullptr),
     resumePC_(nullptr),
     fp_(nullptr),
     exitReason_(wasm::ExitReason::None)
 {
-    (void) entrySP_;  // squelch GCC warning
-
-    prevWasmForInstance_ = instance.activation();
-    instance.activation() = this;
+    (void) entrySP_;  // silence "unused private member" warning
 
     prevWasm_ = cx->runtime()->wasmActivationStack_;
     cx->runtime()->wasmActivationStack_ = this;
 
     cx->compartment()->wasm.activationCount_++;
 
     // Now that the WasmActivation is fully initialized, make it visible to
     // asynchronous profiling.
@@ -1648,21 +1645,17 @@ WasmActivation::WasmActivation(JSContext
 
 WasmActivation::~WasmActivation()
 {
     // Hide this activation from the profiler before is is destroyed.
     unregisterProfiling();
 
     MOZ_ASSERT(fp_ == nullptr);
 
-    MOZ_ASSERT(instance_.activation() == this);
-    instance_.activation() = prevWasmForInstance_;
-
     MOZ_ASSERT(cx_->runtime()->wasmActivationStack_ == this);
-
     cx_->runtime()->wasmActivationStack_ = prevWasm_;
 
     MOZ_ASSERT(cx_->compartment()->wasm.activationCount_ > 0);
     cx_->compartment()->wasm.activationCount_--;
 }
 
 InterpreterFrameIterator&
 InterpreterFrameIterator::operator++()
--- a/js/src/vm/Stack.h
+++ b/js/src/vm/Stack.h
@@ -1660,17 +1660,16 @@ class InterpreterFrameIterator
 // An eventual goal is to remove WasmActivation and to run asm code in a
 // JitActivation interleaved with Ion/Baseline jit code. This would allow
 // efficient calls back and forth but requires that we can walk the stack for
 // all kinds of jit code.
 class WasmActivation : public Activation
 {
     wasm::Instance& instance_;
     WasmActivation* prevWasm_;
-    WasmActivation* prevWasmForInstance_;
     void* entrySP_;
     void* resumePC_;
     uint8_t* fp_;
     wasm::ExitReason exitReason_;
 
   public:
     WasmActivation(JSContext* cx, wasm::Instance& instance);
     ~WasmActivation();