Bug 1254893 - Connect wasm::BinaryToText with Debugger.Source (r=shu)
authorLuke Wagner <luke@mozilla.com>
Sat, 12 Mar 2016 02:27:15 -0600
changeset 288421 ba5dd6053cc4351e58ad407d8ef96a6dfcf344d4
parent 288420 a3a44b86faaa69c219b039d80ba26f143c9cd26b
child 288422 bd22586cac8283289b3440bfe74d7ef79e1ef2bf
push id30079
push userryanvm@gmail.com
push dateSat, 12 Mar 2016 20:24:19 +0000
treeherdermozilla-central@d1d47ba19ce9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersshu
bugs1254893
milestone48.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 1254893 - Connect wasm::BinaryToText with Debugger.Source (r=shu) MozReview-Commit-ID: 4vsMGU3wbwZ
js/src/asmjs/Wasm.cpp
js/src/asmjs/WasmBinaryToText.cpp
js/src/asmjs/WasmBinaryToText.h
js/src/asmjs/WasmModule.cpp
js/src/asmjs/WasmModule.h
js/src/builtin/TestingFunctions.cpp
js/src/vm/Debugger.cpp
--- a/js/src/asmjs/Wasm.cpp
+++ b/js/src/asmjs/Wasm.cpp
@@ -1586,23 +1586,32 @@ wasm::Eval(JSContext* cx, Handle<TypedAr
             ReportOutOfMemory(cx);
         return false;
     }
 
     Rooted<FunctionVector> imports(cx, FunctionVector(cx));
     if (!ImportFunctions(cx, importObj, importNames, &imports))
         return false;
 
+    Module& module = moduleObj->module();
+
     RootedObject exportObj(cx);
-    if (!moduleObj->module().dynamicallyLink(cx, moduleObj, heap, imports, *exportMap, &exportObj))
+    if (!module.dynamicallyLink(cx, moduleObj, heap, imports, *exportMap, &exportObj))
         return false;
 
     if (!CreateInstance(cx, exportObj, instance))
         return false;
 
+    if (cx->compartment()->debuggerObservesAsmJS()) {
+        Bytes source;
+        if (!source.append(bytes, length))
+            return false;
+        module.setSource(Move(source));
+    }
+
     Debugger::onNewWasmModule(cx, moduleObj);
     return true;
 }
 
 static bool
 InstantiateModule(JSContext* cx, unsigned argc, Value* vp)
 {
     MOZ_ASSERT(cx->runtime()->options().wasm());
--- a/js/src/asmjs/WasmBinaryToText.cpp
+++ b/js/src/asmjs/WasmBinaryToText.cpp
@@ -1667,35 +1667,20 @@ RenderModule(WasmRenderContext& c)
 
     return true;
 }
 
 /*****************************************************************************/
 // Top-level functions
 
 bool
-wasm::BinaryToText(JSContext* cx, Handle<TypedArrayObject*> code, StringBuffer& buffer)
+wasm::BinaryToText(JSContext* cx, const uint8_t* bytes, size_t length, StringBuffer& buffer)
 {
-    MOZ_ASSERT(!code->isSharedMemory());
-
-    if (!TypedArrayObject::ensureHasBuffer(cx, code))
-        return false;
+    Decoder d(bytes, bytes + length);
 
-    const uint8_t* bufferStart = code->bufferUnshared()->dataPointer();
-    const uint8_t* bytes = bufferStart + code->byteOffset();
-    uint32_t length = code->byteLength();
-
-    Vector<uint8_t> copy(cx);
-    if (code->bufferUnshared()->hasInlineData()) {
-        if (!copy.append(bytes, length))
-            return false;
-        bytes = copy.begin();
-    }
-
-    Decoder d(bytes, bytes + length);
     WasmRenderContext c(cx, d, buffer);
 
     if (!RenderModule(c)) {
         if (!cx->isExceptionPending())
             ReportOutOfMemory(cx);
         return false;
     }
 
--- a/js/src/asmjs/WasmBinaryToText.h
+++ b/js/src/asmjs/WasmBinaryToText.h
@@ -21,24 +21,23 @@
 
 #include "NamespaceImports.h"
 
 #include "gc/Rooting.h"
 #include "js/Class.h"
 
 namespace js {
 
-class TypedArrayObject;
 class StringBuffer;
 
 namespace wasm {
 
-// Translate the given binary representation of a wasm module (given by a
-// typed array) into the module's textual representation.
+// Translate the given binary representation of a wasm module into the module's textual
+// representation.
 
 bool
-BinaryToText(JSContext* cx, Handle<TypedArrayObject*> code, StringBuffer& buffer);
+BinaryToText(JSContext* cx, const uint8_t* bytes, size_t length, StringBuffer& buffer);
 
 }  // namespace wasm
 
 }  // namespace js
 
 #endif // namespace wasm_binary_to_text_h
--- a/js/src/asmjs/WasmModule.cpp
+++ b/js/src/asmjs/WasmModule.cpp
@@ -19,26 +19,28 @@
 #include "asmjs/WasmModule.h"
 
 #include "mozilla/BinarySearch.h"
 #include "mozilla/EnumeratedRange.h"
 #include "mozilla/PodOperations.h"
 
 #include "jsprf.h"
 
+#include "asmjs/WasmBinaryToText.h"
 #include "asmjs/WasmSerialize.h"
 #include "builtin/AtomicsObject.h"
 #include "builtin/SIMD.h"
 #ifdef JS_ION_PERF
 # include "jit/PerfSpewer.h"
 #endif
 #include "jit/BaselineJIT.h"
 #include "jit/ExecutableAllocator.h"
 #include "jit/JitCommon.h"
 #include "js/MemoryMetrics.h"
+#include "vm/StringBuffer.h"
 #ifdef MOZ_VTUNE
 # include "vtune/VTuneWrapper.h"
 #endif
 
 #include "jsobjinlines.h"
 
 #include "jit/MacroAssembler-inl.h"
 #include "vm/ArrayBufferObject-inl.h"
@@ -914,16 +916,17 @@ Module::readBarrier()
 /* virtual */ void
 Module::addSizeOfMisc(MallocSizeOf mallocSizeOf, size_t* code, size_t* data)
 {
     *code += codeBytes();
     *data += mallocSizeOf(this) +
              globalBytes() +
              mallocSizeOf(module_.get()) +
              module_->sizeOfExcludingThis(mallocSizeOf) +
+             source_.sizeOfExcludingThis(mallocSizeOf) +
              funcPtrTables_.sizeOfExcludingThis(mallocSizeOf) +
              SizeOfVectorExcludingThis(funcLabels_, mallocSizeOf);
 }
 
 /* virtual */ bool
 Module::mutedErrors() const
 {
     // WebAssembly code is always CORS-same-origin and so errors are never
@@ -1505,16 +1508,48 @@ Module::getFuncAtom(JSContext* cx, uint3
 
     JSAtom* atom = AtomizeUTF8Chars(cx, chars, strlen(chars));
     if (!atom)
         return nullptr;
 
     return atom;
 }
 
+const char experimentalWarning[] =
+    "Experimental\n"
+    ".--.      .--.   ____       .-'''-. ,---.    ,---.\n"
+    "|  |_     |  | .'  __ `.   / _     \\|    \\  /    |\n"
+    "| _( )_   |  |/   '  \\  \\ (`' )/`--'|  ,  \\/  ,  |\n"
+    "|(_ o _)  |  ||___|  /  |(_ o _).   |  |\\_   /|  |\n"
+    "| (_,_) \\ |  |   _.-`   | (_,_). '. |  _( )_/ |  |\n"
+    "|  |/    \\|  |.'   _    |.---.  \\  :| (_ o _) |  |\n"
+    "|  '  /\\  `  ||  _( )_  |\\    `-'  ||  (_,_)  |  |\n"
+    "|    /  \\    |\\ (_ o _) / \\       / |  |      |  |\n"
+    "`---'    `---` '.(_,_).'   `-...-'  '--'      '--'\n"
+    "text support (Work In Progress):\n\n";
+
+const char enabledMessage[] =
+    "Restart with debugger open to view WebAssembly source";
+
+JSString*
+Module::createText(JSContext* cx)
+{
+    StringBuffer buffer(cx);
+    if (!source_.empty()) {
+        if (!buffer.append(experimentalWarning))
+            return nullptr;
+        if (!BinaryToText(cx, source_.begin(), source_.length(), buffer))
+            return nullptr;
+    } else {
+        if (!buffer.append(enabledMessage))
+            return nullptr;
+    }
+    return buffer.finishString();
+}
+
 const char*
 Module::profilingLabel(uint32_t funcIndex) const
 {
     MOZ_ASSERT(dynamicallyLinked_);
     MOZ_ASSERT(profilingEnabled_);
     return funcLabels_[funcIndex].get();
 }
 
--- a/js/src/asmjs/WasmModule.h
+++ b/js/src/asmjs/WasmModule.h
@@ -465,16 +465,17 @@ class Module : public mozilla::LinkedLis
         explicit FuncPtrTable(const StaticLinkData::FuncPtrTable& table)
           : globalDataOffset(table.globalDataOffset),
             numElems(table.elemOffsets.length())
         {}
     };
     typedef Vector<FuncPtrTable, 0, SystemAllocPolicy> FuncPtrTableVector;
     typedef Vector<CacheableChars, 0, SystemAllocPolicy> FuncLabelVector;
     typedef RelocatablePtrArrayBufferObjectMaybeShared BufferPtr;
+    typedef HeapPtr<WasmModuleObject*> ModuleObjectPtr;
 
     // Initialized when constructed:
     const UniqueConstModuleData  module_;
 
     // Initialized during staticallyLink:
     bool                         staticallyLinked_;
     uint8_t*                     interrupt_;
     uint8_t*                     outOfBounds_;
@@ -484,17 +485,20 @@ class Module : public mozilla::LinkedLis
     bool                         dynamicallyLinked_;
     BufferPtr                    heap_;
 
     // Mutated after dynamicallyLink:
     bool                         profilingEnabled_;
     FuncLabelVector              funcLabels_;
 
     // Back pointer to the JS object.
-    HeapPtr<WasmModuleObject*> ownerObject_;
+    ModuleObjectPtr              ownerObject_;
+
+    // Possibly stored copy of the bytes from which this module was compiled.
+    Bytes                        source_;
 
     uint8_t* rawHeapPtr() const;
     uint8_t*& rawHeapPtr();
     WasmActivation*& activation();
     void specializeToHeap(ArrayBufferObjectMaybeShared* heap);
     void despecializeFromHeap(ArrayBufferObjectMaybeShared* heap);
     bool sendCodeRangesToProfiler(JSContext* cx);
     MOZ_WARN_UNUSED_RESULT bool setProfilingEnabled(JSContext* cx, bool enabled);
@@ -515,16 +519,18 @@ class Module : public mozilla::LinkedLis
     virtual ~Module();
     virtual void trace(JSTracer* trc);
     virtual void readBarrier();
     virtual void addSizeOfMisc(MallocSizeOf mallocSizeOf, size_t* code, size_t* data);
 
     void setOwner(WasmModuleObject* owner) { MOZ_ASSERT(!ownerObject_); ownerObject_ = owner; }
     inline const HeapPtr<WasmModuleObject*>& owner() const;
 
+    void setSource(Bytes&& source) { source_ = Move(source); }
+
     uint8_t* code() const { return module_->code.get(); }
     uint32_t codeBytes() const { return module_->codeBytes; }
     uint8_t* globalData() const { return code() + module_->codeBytes; }
     uint32_t globalBytes() const { return module_->globalBytes; }
     HeapUsage heapUsage() const { return module_->heapUsage; }
     bool usesHeap() const { return UsesHeap(module_->heapUsage); }
     bool hasSharedHeap() const { return module_->heapUsage == HeapUsage::Shared; }
     CompileArgs compileArgs() const { return module_->compileArgs; }
@@ -608,16 +614,21 @@ class Module : public mozilla::LinkedLis
     // Every function has an associated display atom which is either the pretty
     // name given by the asm.js function name or wasm symbols or something
     // generated from the function index.
 
     const char* prettyFuncName(uint32_t funcIndex) const;
     const char* getFuncName(JSContext* cx, uint32_t funcIndex, UniqueChars* owner) const;
     JSAtom* getFuncAtom(JSContext* cx, uint32_t funcIndex) const;
 
+    // If debuggerObservesAsmJS was true when the module was compiled, render
+    // the binary to a new source string.
+
+    JSString* createText(JSContext* cx);
+
     // Each Module has a profilingEnabled state which is updated to match
     // SPSProfiler::enabled() on the next Module::callExport when there are no
     // frames from the Module on the stack. The ProfilingFrameIterator only
     // shows frames for Module activations that have profilingEnabled.
 
     bool profilingEnabled() const { return profilingEnabled_; }
     const char* profilingLabel(uint32_t funcIndex) const;
 };
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -557,18 +557,29 @@ WasmBinaryToText(JSContext* cx, unsigned
     }
 
     Rooted<TypedArrayObject*> code(cx, &args[0].toObject().as<TypedArrayObject>());
     if (code->isSharedMemory()) {
         JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_BUF_ARG);
         return false;
     }
 
+    const uint8_t* bufferStart = code->bufferUnshared()->dataPointer();
+    const uint8_t* bytes = bufferStart + code->byteOffset();
+    uint32_t length = code->byteLength();
+
+    Vector<uint8_t> copy(cx);
+    if (code->bufferUnshared()->hasInlineData()) {
+        if (!copy.append(bytes, length))
+            return false;
+        bytes = copy.begin();
+    }
+
     StringBuffer buffer(cx);
-    if (!wasm::BinaryToText(cx, code, buffer)) {
+    if (!wasm::BinaryToText(cx, bytes, length, buffer)) {
         JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_TEXT_FAIL,
                              "print error");
         return false;
     }
 
     JSString* result = buffer.finishString();
     if (!result)
         return false;
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -6458,29 +6458,17 @@ class DebuggerSourceGetTextMatcher
         bool hasSourceData = ss->hasSourceData();
         if (!ss->hasSourceData() && !JSScript::loadSource(cx_, ss, &hasSourceData))
             return nullptr;
         return hasSourceData ? ss->substring(cx_, 0, ss->length())
                              : NewStringCopyZ<CanGC>(cx_, "[no source]");
     }
 
     ReturnType match(Handle<WasmModuleObject*> wasmModule) {
-        const char* placeholder =
-            "/*\n"
-            " * .--.      .--.   ____       .-'''-. ,---.    ,---.\n"
-            " * |  |_     |  | .'  __ `.   / _     \\|    \\  /    |\n"
-            " * | _( )_   |  |/   '  \\  \\ (`' )/`--'|  ,  \\/  ,  |\n"
-            " * |(_ o _)  |  ||___|  /  |(_ o _).   |  |\\_   /|  |\n"
-            " * | (_,_) \\ |  |   _.-`   | (_,_). '. |  _( )_/ |  |\n"
-            " * |  |/    \\|  |.'   _    |.---.  \\  :| (_ o _) |  |\n"
-            " * |  '  /\\  `  ||  _( )_  |\\    `-'  ||  (_,_)  |  |\n"
-            " * |    /  \\    |\\ (_ o _) / \\       / |  |      |  |\n"
-            " * `---'    `---` '.(_,_).'   `-...-'  '--'      '--'\n"
-            " */";
-        return NewStringCopyZ<CanGC>(cx_, placeholder);
+        return wasmModule->module().createText(cx_);
     }
 };
 
 static bool
 DebuggerSource_getText(JSContext* cx, unsigned argc, Value* vp)
 {
     THIS_DEBUGSOURCE_REFERENT(cx, argc, vp, "(get text)", args, obj, referent);
     Value textv = obj->getReservedSlot(JSSLOT_DEBUGSOURCE_TEXT);