Bug 1286948 - Allows FrameIterator to return Instance and track actual fp. draft
authorYury Delendik <ydelendik@mozilla.com>
Fri, 07 Oct 2016 18:21:53 -0500
changeset 422587 2a3b0a0963aac68acef192a932e0974d1ac7156b
parent 422586 24d4e0ce0b9a0ed9129ec3f314c82fb42a3b4783
child 422588 2fc3b6d86569532b04815e63fd44c16bed74a0e6
push id31754
push userydelendik@mozilla.com
push dateFri, 07 Oct 2016 23:25:30 +0000
bugs1286948
milestone52.0a1
Bug 1286948 - Allows FrameIterator to return Instance and track actual fp. 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/asmjs/WasmFrameIterator.cpp
js/src/asmjs/WasmFrameIterator.h
js/src/asmjs/WasmInstance.cpp
js/src/vm/Stack.cpp
js/src/vm/Stack.h
--- a/js/src/asmjs/WasmFrameIterator.cpp
+++ b/js/src/asmjs/WasmFrameIterator.cpp
@@ -57,35 +57,35 @@ FrameIterator::FrameIterator()
 }
 
 FrameIterator::FrameIterator(const WasmActivation& activation)
   : activation_(&activation),
     code_(nullptr),
     callsite_(nullptr),
     codeRange_(nullptr),
     fp_(activation.fp()),
-    pc_(nullptr),
+    pc_((uint8_t*)activation.resumePC()),
     missingFrameMessage_(false)
 {
-    if (fp_) {
+    if (!pc_ && fp_) {
+        // The mode when pc is not set -- the fp_ points to the frame which
+        // points to the current frame and pc
         settle();
         return;
     }
 
-    void* pc = activation.resumePC();
-    if (!pc) {
+    if (!pc_) {
         MOZ_ASSERT(done());
         return;
     }
-    pc_ = (uint8_t*)pc;
 
-    code_ = activation_->compartment()->wasm.lookupCode(pc);
+    code_ = activation_->compartment()->wasm.lookupCode(pc_);
     MOZ_ASSERT(code_);
 
-    const CodeRange* codeRange = code_->lookupRange(pc);
+    const CodeRange* codeRange = code_->lookupRange(pc_);
     MOZ_ASSERT(codeRange);
 
     if (codeRange->kind() == CodeRange::Function)
         codeRange_ = codeRange;
     else
         missingFrameMessage_ = true;
 
     MOZ_ASSERT(!done());
@@ -97,19 +97,16 @@ FrameIterator::done() const
     return !codeRange_ && !missingFrameMessage_;
 }
 
 void
 FrameIterator::operator++()
 {
     MOZ_ASSERT(!done());
     if (fp_) {
-        DebugOnly<uint8_t*> oldfp = fp_;
-        fp_ += callsite_->stackDepth();
-        MOZ_ASSERT_IF(code_->profilingEnabled(), fp_ == CallerFPFromFP(oldfp));
         settle();
     } else if (codeRange_) {
         MOZ_ASSERT(codeRange_);
         codeRange_ = nullptr;
         missingFrameMessage_ = true;
     } else {
         MOZ_ASSERT(missingFrameMessage_);
         missingFrameMessage_ = false;
@@ -127,16 +124,21 @@ FrameIterator::settle()
     codeRange_ = code_->lookupRange(returnAddress);
     MOZ_ASSERT(codeRange_);
 
     switch (codeRange_->kind()) {
       case CodeRange::Function:
         pc_ = (uint8_t*)returnAddress;
         callsite_ = code_->lookupCallSite(returnAddress);
         MOZ_ASSERT(callsite_);
+        {
+            DebugOnly<uint8_t*> oldfp = fp_;
+            fp_ += callsite_->stackDepth();
+            MOZ_ASSERT_IF(code_->profilingEnabled(), fp_ == CallerFPFromFP(oldfp));
+        }
         break;
       case CodeRange::Entry:
         fp_ = nullptr;
         pc_ = nullptr;
         code_ = nullptr;
         codeRange_ = nullptr;
         MOZ_ASSERT(done());
         break;
@@ -202,16 +204,30 @@ 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());
+    return fp_ && instance()->code().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/asmjs/WasmFrameIterator.h
+++ b/js/src/asmjs/WasmFrameIterator.h
@@ -67,16 +67,18 @@ class FrameIterator
     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_; }
     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/asmjs/WasmInstance.cpp
+++ b/js/src/asmjs/WasmInstance.cpp
@@ -630,17 +630,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;
     }
 
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -1616,23 +1616,25 @@ jit::JitActivation::removeIonFrameRecove
 
 void
 jit::JitActivation::markIonRecovery(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
@@ -1654,34 +1655,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 asm.js code
     // in this activation.
     uint8_t* fp() const { return fp_; }
 
     // Returns the reason why asm.js code called out of asm.js 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_); }
@@ -1785,16 +1790,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;
@@ -2018,16 +2026,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