Bug 1286948 - Allows FrameIterator to return Instance and track actual fp. r?luke draft
authorYury Delendik <ydelendik@mozilla.com>
Tue, 13 Dec 2016 15:00:50 -0600
changeset 449568 d887578560c40230d7b01df385a37fcad9a8db53
parent 449567 8c4bb1d6cbfc236aa66afe2100b69681dd7bcf36
child 449569 5024603c7552be99ef50f0326595f59e6a3ca8c5
push id38610
push userydelendik@mozilla.com
push dateWed, 14 Dec 2016 15:18:16 +0000
reviewersluke
bugs1286948
milestone53.0a1
Bug 1286948 - Allows FrameIterator to return Instance and track actual fp. r?luke Improves wasm::FrameIterator so it can contain reference to wasm::Instance that is stored at WasmActivation. Also allows to track actial frame pointer (instead of previous) and start iteration by using fp and pc. MozReview-Commit-ID: EETUQhSU5fl
js/src/vm/Stack.cpp
js/src/vm/Stack.h
js/src/wasm/WasmFrameIterator.cpp
js/src/wasm/WasmFrameIterator.h
js/src/wasm/WasmInstance.cpp
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -1613,23 +1613,25 @@ jit::JitActivation::removeIonFrameRecove
 
 void
 jit::JitActivation::traceIonRecovery(JSTracer* trc)
 {
     for (RInstructionResults* it = ionRecovery_.begin(); it != ionRecovery_.end(); it++)
         it->trace(trc);
 }
 
-WasmActivation::WasmActivation(JSContext* cx)
+WasmActivation::WasmActivation(JSContext* cx, const wasm::TlsData* tlsData)
   : Activation(cx, Wasm),
     entrySP_(nullptr),
     resumePC_(nullptr),
     fp_(nullptr),
-    exitReason_(wasm::ExitReason::None)
+    exitReason_(wasm::ExitReason::None),
+    tlsData_(tlsData)
 {
+    MOZ_ASSERT(tlsData_);
     (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
--- a/js/src/vm/Stack.h
+++ b/js/src/vm/Stack.h
@@ -49,16 +49,17 @@ class EnvironmentCoordinate;
 
 class SavedFrame;
 
 namespace jit {
 class CommonFrameLayout;
 }
 namespace wasm {
 class Instance;
+struct TlsData;
 }
 
 // VM stack layout
 //
 // A JSRuntime's stack consists of a linked list of activations. Every activation
 // contains a number of scripted frames that are either running in the interpreter
 // (InterpreterActivation) or JIT code (JitActivation). The frames inside a single
 // activation are contiguous: whenever C++ calls back into JS, a new activation is
@@ -1661,34 +1662,38 @@ class InterpreterFrameIterator
 // all kinds of jit code.
 class WasmActivation : public Activation
 {
     WasmActivation* prevWasm_;
     void* entrySP_;
     void* resumePC_;
     uint8_t* fp_;
     wasm::ExitReason exitReason_;
+    const wasm::TlsData* tlsData_;
 
   public:
-    explicit WasmActivation(JSContext* cx);
+    explicit WasmActivation(JSContext* cx, const wasm::TlsData* tlsData);
     ~WasmActivation();
 
     WasmActivation* prevWasm() const { return prevWasm_; }
 
     bool isProfiling() const {
         return true;
     }
 
     // Returns a pointer to the base of the innermost stack frame of wasm code
     // in this activation.
     uint8_t* fp() const { return fp_; }
 
     // Returns the reason why wasm code called out of wasm code.
     wasm::ExitReason exitReason() const { return exitReason_; }
 
+    // Returns the current thread's TlsData.
+    const wasm::TlsData* tlsData() const { return tlsData_; }
+
     // Read by JIT code:
     static unsigned offsetOfContext() { return offsetof(WasmActivation, cx_); }
     static unsigned offsetOfResumePC() { return offsetof(WasmActivation, resumePC_); }
 
     // Written by JIT code:
     static unsigned offsetOfEntrySP() { return offsetof(WasmActivation, entrySP_); }
     static unsigned offsetOfFP() { return offsetof(WasmActivation, fp_); }
     static unsigned offsetOfExitReason() { return offsetof(WasmActivation, exitReason_); }
@@ -1792,16 +1797,19 @@ class FrameIter
     // -----------------------------------------------------------
 
     inline JSScript* script() const;
 
     bool        isConstructing() const;
     jsbytecode* pc() const { MOZ_ASSERT(!done()); return data_.pc_; }
     void        updatePcQuadratic();
 
+    //  The following functions can only be called when isWasm().
+    inline wasm::Instance* wasmInstance() const;
+
     // The function |calleeTemplate()| returns either the function from which
     // the current |callee| was cloned or the |callee| if it can be read. As
     // long as we do not have to investigate the environment chain or build a
     // new frame, we should prefer to use |calleeTemplate| instead of
     // |callee|, as requesting the |callee| might cause the invalidation of
     // the frame. (see js::Lambda)
     JSFunction* calleeTemplate() const;
     JSFunction* callee(JSContext* cx) const;
@@ -2025,16 +2033,24 @@ FrameIter::script() const
     if (data_.state_ == INTERP)
         return interpFrame()->script();
     MOZ_ASSERT(data_.state_ == JIT);
     if (data_.jitFrames_.isIonJS())
         return ionInlineFrames_.script();
     return data_.jitFrames_.script();
 }
 
+inline wasm::Instance*
+FrameIter::wasmInstance() const
+{
+    MOZ_ASSERT(!done());
+    MOZ_ASSERT(data_.state_ == WASM);
+    return data_.wasmFrames_.instance();
+}
+
 inline bool
 FrameIter::isIon() const
 {
     return isJit() && data_.jitFrames_.isIonJS();
 }
 
 inline bool
 FrameIter::isBaseline() const
--- a/js/src/wasm/WasmFrameIterator.cpp
+++ b/js/src/wasm/WasmFrameIterator.cpp
@@ -70,17 +70,16 @@ FrameIterator::FrameIterator(const WasmA
         return;
     }
 
     void* pc = activation.resumePC();
     if (!pc) {
         MOZ_ASSERT(done());
         return;
     }
-    pc_ = (uint8_t*)pc;
 
     code_ = activation_->compartment()->wasm.lookupCode(pc);
     MOZ_ASSERT(code_);
 
     const CodeRange* codeRange = code_->lookupRange(pc);
     MOZ_ASSERT(codeRange);
 
     if (codeRange->kind() == CodeRange::Function)
@@ -111,16 +110,29 @@ FrameIterator::operator++()
         codeRange_ = nullptr;
         missingFrameMessage_ = true;
     } else {
         MOZ_ASSERT(missingFrameMessage_);
         missingFrameMessage_ = false;
     }
 }
 
+void*
+FrameIterator::fp() const
+{
+    return fp_ + callsite()->stackDepth();
+}
+
+const CallSite*
+FrameIterator::callsite() const
+{
+    MOZ_ASSERT(codeRange_->kind() == CodeRange::Function);
+    return callsite_;
+}
+
 void
 FrameIterator::settle()
 {
     void* returnAddress = ReturnAddressFromFP(fp_);
 
     code_ = activation_->compartment()->wasm.lookupCode(returnAddress);
     MOZ_ASSERT(code_);
 
@@ -203,16 +215,31 @@ FrameIterator::functionDisplayAtom() con
 unsigned
 FrameIterator::lineOrBytecode() const
 {
     MOZ_ASSERT(!done());
     return callsite_ ? callsite_->lineOrBytecode()
                      : (codeRange_ ? codeRange_->funcLineOrBytecode() : 0);
 }
 
+Instance*
+FrameIterator::instance() const
+{
+    MOZ_ASSERT(!done());
+    return activation_->tlsData()->instance;
+}
+
+bool
+FrameIterator::isDebuggee() const
+{
+    MOZ_ASSERT(!done());
+    MOZ_ASSERT_IF(!missingFrameMessage_, codeRange_->kind() == CodeRange::Function);
+    return instance()->code().metadata().debugEnabled;
+}
+
 /*****************************************************************************/
 // Prologue/epilogue code generation
 
 // 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)
--- a/js/src/wasm/WasmFrameIterator.h
+++ b/js/src/wasm/WasmFrameIterator.h
@@ -28,16 +28,17 @@ namespace js {
 class WasmActivation;
 namespace jit { class MacroAssembler; }
 
 namespace wasm {
 
 class CallSite;
 class Code;
 class CodeRange;
+class Instance;
 class SigIdDesc;
 struct CallThunk;
 struct FuncOffsets;
 struct ProfilingOffsets;
 struct TrapOffset;
 
 // Iterates over the frames of a single WasmActivation, called synchronously
 // from C++ in the thread of the asm.js.
@@ -64,18 +65,21 @@ class FrameIterator
     explicit FrameIterator(const WasmActivation& activation);
     void operator++();
     bool done() const;
     const char* filename() const;
     const char16_t* displayURL() const;
     bool mutedErrors() const;
     JSAtom* functionDisplayAtom() const;
     unsigned lineOrBytecode() const;
-    inline void* fp() const { return fp_; }
+    void* fp() const;
+    const CallSite* callsite() const;
     inline uint8_t* pc() const { return pc_; }
+    Instance* instance() const;
+    bool isDebuggee() const;
 };
 
 // An ExitReason describes the possible reasons for leaving compiled wasm code
 // or the state of not having left compiled wasm code (ExitReason::None).
 enum class ExitReason : uint32_t
 {
     None,          // default state, the pc is in wasm code
     ImportJit,     // fast-path call directly into JIT code
--- a/js/src/wasm/WasmInstance.cpp
+++ b/js/src/wasm/WasmInstance.cpp
@@ -642,17 +642,17 @@ Instance::callExport(JSContext* cx, uint
     }
 
     {
         // Push a WasmActivation to describe the wasm frames we're about to push
         // when running this module. Additionally, push a JitActivation so that
         // the optimized wasm-to-Ion FFI call path (which we want to be very
         // fast) can avoid doing so. The JitActivation is marked as inactive so
         // stack iteration will skip over it.
-        WasmActivation activation(cx);
+        WasmActivation activation(cx, &tlsData_);
         JitActivation jitActivation(cx, /* active */ false);
 
         // Call the per-exported-function trampoline created by GenerateEntry.
         auto funcPtr = JS_DATA_TO_FUNC_PTR(ExportFuncPtr, codeBase() + func.entryOffset());
         if (!CALL_GENERATED_2(funcPtr, exportArgs.begin(), &tlsData_))
             return false;
     }