Bug 1364615 - Baldr: remove bytecode from wasm::Code (r=lth)
authorLuke Wagner <luke@mozilla.com>
Mon, 15 May 2017 14:30:21 -0500
changeset 406650 2e27f56d21b48c52075cac851b24d8948b95517b
parent 406649 4901d885b1a4ae5248345bb2a740d0135c0d1216
child 406651 08e52e63564d5fae25227c2c14555198758f345b
push id7391
push usermtabara@mozilla.com
push dateMon, 12 Jun 2017 13:08:53 +0000
treeherdermozilla-beta@2191d7f87e2e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerslth
bugs1364615
milestone55.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 1364615 - Baldr: remove bytecode from wasm::Code (r=lth) MozReview-Commit-ID: 10FncpKzcFR
js/src/wasm/WasmCode.cpp
js/src/wasm/WasmCode.h
js/src/wasm/WasmCompartment.cpp
js/src/wasm/WasmDebug.cpp
js/src/wasm/WasmDebug.h
js/src/wasm/WasmFrameIterator.cpp
js/src/wasm/WasmGenerator.cpp
js/src/wasm/WasmInstance.cpp
js/src/wasm/WasmInstance.h
js/src/wasm/WasmJS.cpp
js/src/wasm/WasmModule.cpp
--- a/js/src/wasm/WasmCode.cpp
+++ b/js/src/wasm/WasmCode.cpp
@@ -567,25 +567,21 @@ Metadata::getFuncName(const Bytes* maybe
     const char* funcIndexStr = NumberToCString(nullptr, &cbuf, funcIndex);
     MOZ_ASSERT(funcIndexStr);
 
     return name->append(beforeFuncIndex, strlen(beforeFuncIndex)) &&
            name->append(funcIndexStr, strlen(funcIndexStr)) &&
            name->append(afterFuncIndex, strlen(afterFuncIndex));
 }
 
-Code::Code(UniqueConstCodeSegment segment,
-           const Metadata& metadata,
-           const ShareableBytes* maybeBytecode)
+Code::Code(UniqueConstCodeSegment segment, const Metadata& metadata)
   : segment_(Move(segment)),
     metadata_(&metadata),
-    maybeBytecode_(maybeBytecode),
     profilingLabels_(mutexid::WasmCodeProfilingLabels, CacheableCharsVector())
 {
-    MOZ_ASSERT_IF(metadata_->debugEnabled, maybeBytecode);
 }
 
 Code::Code()
   : profilingLabels_(mutexid::WasmCodeProfilingLabels, CacheableCharsVector())
 {
 }
 
 struct CallSiteRetAddrOffset
@@ -633,23 +629,18 @@ Code::deserialize(const uint8_t* cursor,
     UniqueCodeSegment codeSegment = js::MakeUnique<CodeSegment>();
     if (!codeSegment)
         return nullptr;
 
     cursor = codeSegment->deserialize(cursor, *bytecode, linkData, *metadata);
     if (!cursor)
         return nullptr;
 
-    const ShareableBytes* maybeBytecode = nullptr;
-    if (metadata->debugEnabled || !metadata->funcNames.empty())
-        maybeBytecode = bytecode.get();
-
     segment_ = UniqueConstCodeSegment(codeSegment.release());
     metadata_ = metadata;
-    maybeBytecode_ = maybeBytecode;
 
     return cursor;
 }
 
 const CallSite*
 Code::lookupCallSite(void* returnAddress) const
 {
     uint32_t target = ((uint8_t*)returnAddress) - segment_->base();
@@ -690,39 +681,22 @@ Code::lookupMemoryAccess(void* pc) const
 
     size_t match;
     if (!BinarySearch(MemoryAccessOffset(metadata().memoryAccesses), lowerBound, upperBound, target, &match))
         return nullptr;
 
     return &metadata().memoryAccesses[match];
 }
 
-bool
-Code::getFuncName(uint32_t funcIndex, UTF8Bytes* name) const
-{
-    const Bytes* maybeBytecode = maybeBytecode_ ? &maybeBytecode_.get()->bytes : nullptr;
-    return metadata().getFuncName(maybeBytecode, funcIndex, name);
-}
-
-JSAtom*
-Code::getFuncAtom(JSContext* cx, uint32_t funcIndex) const
-{
-    UTF8Bytes name;
-    if (!getFuncName(funcIndex, &name))
-        return nullptr;
-
-    return AtomizeUTF8Chars(cx, name.begin(), name.length());
-}
-
 // When enabled, generate profiling labels for every name in funcNames_ that is
 // the name of some Function CodeRange. This involves malloc() so do it now
 // since, once we start sampling, we'll be in a signal-handing context where we
 // cannot malloc.
 void
-Code::ensureProfilingLabels(bool profilingEnabled) const
+Code::ensureProfilingLabels(const Bytes* maybeBytecode, bool profilingEnabled) const
 {
     auto labels = profilingLabels_.lock();
 
     if (!profilingEnabled) {
         labels->clear();
         return;
     }
 
@@ -733,17 +707,19 @@ Code::ensureProfilingLabels(bool profili
         if (!codeRange.isFunction())
             continue;
 
         ToCStringBuf cbuf;
         const char* bytecodeStr = NumberToCString(nullptr, &cbuf, codeRange.funcLineOrBytecode());
         MOZ_ASSERT(bytecodeStr);
 
         UTF8Bytes name;
-        if (!getFuncName(codeRange.funcIndex(), &name) || !name.append(" (", 2))
+        if (!metadata_->getFuncName(maybeBytecode, codeRange.funcIndex(), &name))
+            return;
+        if (!name.append(" (", 2))
             return;
 
         if (const char* filename = metadata().filename.get()) {
             if (!name.append(filename, strlen(filename)))
                 return;
         } else {
             if (!name.append('?'))
                 return;
@@ -777,28 +753,24 @@ Code::profilingLabel(uint32_t funcIndex)
     if (funcIndex >= labels->length() || !((CacheableCharsVector&)labels)[funcIndex])
         return "?";
     return ((CacheableCharsVector&)labels)[funcIndex].get();
 }
 
 void
 Code::addSizeOfMiscIfNotSeen(MallocSizeOf mallocSizeOf,
                              Metadata::SeenSet* seenMetadata,
-                             ShareableBytes::SeenSet* seenBytes,
                              Code::SeenSet* seenCode,
                              size_t* code,
                              size_t* data) const
 {
     auto p = seenCode->lookupForAdd(this);
     if (p)
         return;
     bool ok = seenCode->add(p, this);
     (void)ok;  // oh well
 
     *data += mallocSizeOf(this) +
              metadata().sizeOfIncludingThisIfNotSeen(mallocSizeOf, seenMetadata) +
              profilingLabels_.lock()->sizeOfExcludingThis(mallocSizeOf);
 
     segment_->addSizeOfMisc(mallocSizeOf, code, data);
-
-    if (maybeBytecode_)
-        *data += maybeBytecode_->sizeOfIncludingThisIfNotSeen(mallocSizeOf, seenBytes);
 }
--- a/js/src/wasm/WasmCode.h
+++ b/js/src/wasm/WasmCode.h
@@ -394,52 +394,42 @@ typedef RefPtr<const Metadata> SharedMet
 // object will be shared between a module and all its instances.
 //
 // profilingLabels_ is lazily initialized, but behind a lock.
 
 class Code : public ShareableBase<Code>
 {
     UniqueConstCodeSegment              segment_;
     SharedMetadata                      metadata_;
-    SharedBytes                         maybeBytecode_;
     ExclusiveData<CacheableCharsVector> profilingLabels_;
 
   public:
     Code();
 
-    Code(UniqueConstCodeSegment segment,
-         const Metadata& metadata,
-         const ShareableBytes* maybeBytecode);
+    Code(UniqueConstCodeSegment segment, const Metadata& metadata);
 
     const CodeSegment& segment() const { return *segment_; }
     const Metadata& metadata() const { return *metadata_; }
 
     // Frame iterator support:
 
     const CallSite* lookupCallSite(void* returnAddress) const;
     const CodeRange* lookupRange(void* pc) const;
     const MemoryAccess* lookupMemoryAccess(void* pc) const;
 
-    // Return the name associated with a given function index, or generate one
-    // if none was given by the module.
-
-    bool getFuncName(uint32_t funcIndex, UTF8Bytes* name) const;
-    JSAtom* getFuncAtom(JSContext* cx, uint32_t funcIndex) const;
-
     // To save memory, profilingLabels_ are generated lazily when profiling mode
     // is enabled.
 
-    void ensureProfilingLabels(bool profilingEnabled) const;
+    void ensureProfilingLabels(const Bytes* maybeBytecode, bool profilingEnabled) const;
     const char* profilingLabel(uint32_t funcIndex) const;
 
     // about:memory reporting:
 
     void addSizeOfMiscIfNotSeen(MallocSizeOf mallocSizeOf,
                                 Metadata::SeenSet* seenMetadata,
-                                ShareableBytes::SeenSet* seenBytes,
                                 Code::SeenSet* seenCode,
                                 size_t* code,
                                 size_t* data) const;
 
     // A Code object is serialized as the length and bytes of the machine code
     // after statically unlinking it; the Code is then later recreated from the
     // machine code and other parts.
 
--- a/js/src/wasm/WasmCompartment.cpp
+++ b/js/src/wasm/WasmCompartment.cpp
@@ -57,17 +57,17 @@ struct InstanceComparator
 };
 
 bool
 Compartment::registerInstance(JSContext* cx, HandleWasmInstanceObject instanceObj)
 {
     Instance& instance = instanceObj->instance();
     MOZ_ASSERT(this == &instance.compartment()->wasm);
 
-    instance.code().ensureProfilingLabels(cx->runtime()->geckoProfiler().enabled());
+    instance.ensureProfilingLabels(cx->runtime()->geckoProfiler().enabled());
 
     if (instance.debugEnabled() &&
         instance.compartment()->debuggerObservesAllExecution())
     {
         instance.ensureEnterFrameTrapsState(cx, true);
     }
 
     size_t index;
@@ -125,16 +125,16 @@ Compartment::lookupCode(const void* pc) 
 
     return &instances_[index]->code();
 }
 
 void
 Compartment::ensureProfilingLabels(bool profilingEnabled)
 {
     for (Instance* instance : instances_)
-        instance->code().ensureProfilingLabels(profilingEnabled);
+        instance->ensureProfilingLabels(profilingEnabled);
 }
 
 void
 Compartment::addSizeOfExcludingThis(MallocSizeOf mallocSizeOf, size_t* compartmentTables)
 {
     *compartmentTables += instances_.sizeOfExcludingThis(mallocSizeOf);
 }
--- a/js/src/wasm/WasmDebug.cpp
+++ b/js/src/wasm/WasmDebug.cpp
@@ -525,14 +525,14 @@ DebugState::debugDisplayURL(JSContext* c
 void
 DebugState::addSizeOfMisc(MallocSizeOf mallocSizeOf,
                           Metadata::SeenSet* seenMetadata,
                           ShareableBytes::SeenSet* seenBytes,
                           Code::SeenSet* seenCode,
                           size_t* code,
                           size_t* data) const
 {
-    code_->addSizeOfMiscIfNotSeen(mallocSizeOf, seenMetadata, seenBytes, seenCode, code, data);
+    code_->addSizeOfMiscIfNotSeen(mallocSizeOf, seenMetadata, seenCode, code, data);
     if (maybeSourceMap_)
         *data += maybeSourceMap_->sizeOfExcludingThis(mallocSizeOf);
     if (maybeBytecode_)
         *data += maybeBytecode_->sizeOfIncludingThisIfNotSeen(mallocSizeOf, seenBytes);
 }
--- a/js/src/wasm/WasmDebug.h
+++ b/js/src/wasm/WasmDebug.h
@@ -92,18 +92,19 @@ class DebugState
     uint32_t                 enterAndLeaveFrameTrapsCounter_;
     WasmBreakpointSiteMap    breakpointSites_;
     StepModeCounters         stepModeCounters_;
 
     void toggleDebugTrap(uint32_t offset, bool enabled);
     bool ensureSourceMap(JSContext* cx);
 
   public:
-    DebugState(SharedCode code,
-               const ShareableBytes* maybeBytecode);
+    DebugState(SharedCode code, const ShareableBytes* maybeBytecode);
+
+    const Bytes* maybeBytecode() const { return maybeBytecode_ ? &maybeBytecode_->bytes : nullptr; }
 
     // If the source bytecode was saved when this Code was constructed, this
     // method will render the binary as text. Otherwise, a diagnostic string
     // will be returned.
 
     JSString* createText(JSContext* cx);
     bool getLineOffsets(JSContext* cx, size_t lineno, Vector<uint32_t>* offsets);
     bool getOffsetLocation(JSContext* cx, uint32_t offset, bool* found, size_t* lineno, size_t* column);
--- a/js/src/wasm/WasmFrameIterator.cpp
+++ b/js/src/wasm/WasmFrameIterator.cpp
@@ -169,17 +169,17 @@ FrameIterator::mutedErrors() const
 }
 
 JSAtom*
 FrameIterator::functionDisplayAtom() const
 {
     MOZ_ASSERT(!done());
 
     JSContext* cx = activation_->cx();
-    JSAtom* atom = code_->getFuncAtom(cx, codeRange_->funcIndex());
+    JSAtom* atom = instance()->getFuncAtom(cx, codeRange_->funcIndex());
     if (!atom) {
         cx->clearPendingException();
         return cx->names().empty;
     }
 
     return atom;
 }
 
--- a/js/src/wasm/WasmGenerator.cpp
+++ b/js/src/wasm/WasmGenerator.cpp
@@ -1193,21 +1193,17 @@ ModuleGenerator::finish(const ShareableB
         if (!bytes.resize(masm_.bytesNeeded()))
             return nullptr;
         masm_.executableCopy(bytes.begin(), /* flushICache = */ false);
         maybeDebuggingBytes = js::MakeUnique<Bytes>(Move(bytes));
         if (!maybeDebuggingBytes)
             return nullptr;
     }
 
-    const ShareableBytes* maybeBytecode = nullptr;
-    if (metadata_->debugEnabled || !metadata_->funcNames.empty())
-        maybeBytecode = &bytecode;
-
-    SharedCode code = js_new<Code>(Move(codeSegment), *metadata_, maybeBytecode);
+    SharedCode code = js_new<Code>(Move(codeSegment), *metadata_);
     if (!code)
         return nullptr;
 
     return SharedModule(js_new<Module>(Move(assumptions_),
                                        *code,
                                        Move(maybeDebuggingBytes),
                                        Move(linkData_),
                                        Move(env_->imports),
--- a/js/src/wasm/WasmInstance.cpp
+++ b/js/src/wasm/WasmInstance.cpp
@@ -753,16 +753,38 @@ Instance::callExport(JSContext* cx, uint
     }
 
     if (retObj)
         args.rval().set(ObjectValue(*retObj));
 
     return true;
 }
 
+bool
+Instance::getFuncName(uint32_t funcIndex, UTF8Bytes* name) const
+{
+    return metadata().getFuncName(debug_->maybeBytecode(), funcIndex, name);
+}
+
+JSAtom*
+Instance::getFuncAtom(JSContext* cx, uint32_t funcIndex) const
+{
+    UTF8Bytes name;
+    if (!getFuncName(funcIndex, &name))
+        return nullptr;
+
+    return AtomizeUTF8Chars(cx, name.begin(), name.length());
+}
+
+void
+Instance::ensureProfilingLabels(bool profilingEnabled) const
+{
+    return code_->ensureProfilingLabels(debug_->maybeBytecode(), profilingEnabled);
+}
+
 void
 Instance::onMovingGrowMemory(uint8_t* prevMemoryBase)
 {
     MOZ_ASSERT(!isAsmJS());
     ArrayBufferObject& buffer = memory_->buffer().as<ArrayBufferObject>();
     tlsData()->memoryBase = buffer.dataPointer();
 #ifndef WASM_HUGE_MEMORY
     tlsData()->boundsCheckLimit = buffer.wasmBoundsCheckLimit();
@@ -803,22 +825,22 @@ Instance::addSizeOfMisc(MallocSizeOf mal
                         Metadata::SeenSet* seenMetadata,
                         ShareableBytes::SeenSet* seenBytes,
                         Code::SeenSet* seenCode,
                         Table::SeenSet* seenTables,
                         size_t* code,
                         size_t* data) const
 {
     *data += mallocSizeOf(this) + globals_->sizeOfMisc(mallocSizeOf);
-    debug_->addSizeOfMisc(mallocSizeOf, seenMetadata, seenBytes, seenCode, code, data);
-
-    code_->addSizeOfMiscIfNotSeen(mallocSizeOf, seenMetadata, seenBytes, seenCode, code, data);
 
     for (const SharedTable& table : tables_)
          *data += table->sizeOfIncludingThisIfNotSeen(mallocSizeOf, seenTables);
+
+    debug_->addSizeOfMisc(mallocSizeOf, seenMetadata, seenBytes, seenCode, code, data);
+    code_->addSizeOfMiscIfNotSeen(mallocSizeOf, seenMetadata, seenCode, code, data);
 }
 
 /* static */ UniqueGlobalSegment
 GlobalSegment::create(uint32_t globalDataLength)
 {
     MOZ_ASSERT(globalDataLength % gc::SystemPageSize() == 0);
 
     auto gs = MakeUnique<GlobalSegment>();
--- a/js/src/wasm/WasmInstance.h
+++ b/js/src/wasm/WasmInstance.h
@@ -129,16 +129,23 @@ class Instance
     WasmInstanceObject* object() const;
     WasmInstanceObject* objectUnbarriered() const;
 
     // Execute the given export given the JS call arguments, storing the return
     // value in args.rval.
 
     MOZ_MUST_USE bool callExport(JSContext* cx, uint32_t funcIndex, CallArgs args);
 
+    // Return the name associated with a given function index, or generate one
+    // if none was given by the module.
+
+    bool getFuncName(uint32_t funcIndex, UTF8Bytes* name) const;
+    JSAtom* getFuncAtom(JSContext* cx, uint32_t funcIndex) const;
+    void ensureProfilingLabels(bool profilingEnabled) const;
+
     // Initially, calls to imports in wasm code call out through the generic
     // callImport method. If the imported callee gets JIT compiled and the types
     // match up, callImport will patch the code to instead call through a thunk
     // directly into the JIT code. If the JIT code is released, the Instance must
     // be notified so it can go back to the generic callImport.
 
     void deoptimizeImportExit(uint32_t funcImportIndex);
 
@@ -148,16 +155,17 @@ class Instance
     bool memoryAccessWouldFault(uint8_t* addr, unsigned numBytes);
 
     // Called by Wasm(Memory|Table)Object when a moving resize occurs:
 
     void onMovingGrowMemory(uint8_t* prevMemoryBase);
     void onMovingGrowTable();
 
     // Debug support:
+
     bool debugEnabled() const { return code_->metadata().debugEnabled; }
     bool enterFrameTrapsEnabled() const { return enterFrameTrapsEnabled_; }
     void ensureEnterFrameTrapsState(JSContext* cx, bool enabled);
 
     // about:memory reporting:
 
     void addSizeOfMisc(MallocSizeOf mallocSizeOf,
                        Metadata::SeenSet* seenMetadata,
--- a/js/src/wasm/WasmJS.cpp
+++ b/js/src/wasm/WasmJS.cpp
@@ -1127,17 +1127,17 @@ WasmInstanceObject::getExportedFunction(
     }
 
     const Instance& instance = instanceObj->instance();
     unsigned numArgs = instance.metadata().lookupFuncExport(funcIndex).sig().args().length();
 
     // asm.js needs to act like a normal JS function which means having the name
     // from the original source and being callable as a constructor.
     if (instance.isAsmJS()) {
-        RootedAtom name(cx, instance.code().getFuncAtom(cx, funcIndex));
+        RootedAtom name(cx, instance.getFuncAtom(cx, funcIndex));
         if (!name)
             return false;
 
         fun.set(NewNativeConstructor(cx, WasmCall, numArgs, name, gc::AllocKind::FUNCTION_EXTENDED,
                                      SingletonObject, JSFunction::ASMJS_CTOR));
         if (!fun)
             return false;
     } else {
--- a/js/src/wasm/WasmModule.cpp
+++ b/js/src/wasm/WasmModule.cpp
@@ -362,17 +362,17 @@ wasm::DeserializeModule(PRFileDesc* byte
 /* virtual */ void
 Module::addSizeOfMisc(MallocSizeOf mallocSizeOf,
                       Metadata::SeenSet* seenMetadata,
                       ShareableBytes::SeenSet* seenBytes,
                       Code::SeenSet* seenCode,
                       size_t* code,
                       size_t* data) const
 {
-    code_->addSizeOfMiscIfNotSeen(mallocSizeOf, seenMetadata, seenBytes, seenCode, code, data);
+    code_->addSizeOfMiscIfNotSeen(mallocSizeOf, seenMetadata, seenCode, code, data);
     *data += mallocSizeOf(this) +
              assumptions_.sizeOfExcludingThis(mallocSizeOf) +
              linkData_.sizeOfExcludingThis(mallocSizeOf) +
              SizeOfVectorExcludingThis(imports_, mallocSizeOf) +
              SizeOfVectorExcludingThis(exports_, mallocSizeOf) +
              dataSegments_.sizeOfExcludingThis(mallocSizeOf) +
              SizeOfVectorExcludingThis(elemSegments_, mallocSizeOf) +
              bytecode_->sizeOfIncludingThisIfNotSeen(mallocSizeOf, seenBytes);
@@ -876,22 +876,22 @@ Module::instantiate(JSContext* cx,
     SharedCode code(code_);
 
     if (metadata().debugEnabled) {
         // The first time through, use the pre-linked code in the module but
         // mark it as busy. Subsequently, instantiate the copy of the code
         // bytes that we keep around for debugging instead, because the debugger
         // may patch the pre-linked code at any time.
         if (!codeIsBusy_.compareExchange(false, true)) {
-            UniqueConstCodeSegment codeSegment = CodeSegment::create(*unlinkedCodeForDebugging_,
-                                                                     *bytecode_, linkData_,
-                                                                     metadata());
+            auto codeSegment = CodeSegment::create(*unlinkedCodeForDebugging_, *bytecode_,
+                                                   linkData_, metadata());
             if (!codeSegment)
                 return false;
-            code = js_new<Code>(Move(codeSegment), metadata(), bytecode_);
+
+            code = js_new<Code>(Move(codeSegment), metadata());
             if (!code)
                 return false;
         }
     }
 
     // To support viewing the source of an instance (Instance::createText), the
     // instance must hold onto a ref of the bytecode (keeping it alive). This
     // wastes memory for most users, so we try to only save the source when a