Bug 716647 - Part 5 1/2: Support rematerialized frames in DebugScopes::updateLiveScope. (r=jimb)
authorShu-yu Guo <shu@rfrn.org>
Thu, 24 Apr 2014 01:59:38 -0700
changeset 180267 0e61e88866ceacf80007481e37a23427e6b1efa4
parent 180266 c92f83e9a8640d2db1f0db49879caad5a937055a
child 180268 a49c8cdf14c43d0b69993be83eff5df5e8de36e4
push id272
push userpvanderbeken@mozilla.com
push dateMon, 05 May 2014 16:31:18 +0000
reviewersjimb
bugs716647
milestone31.0a1
Bug 716647 - Part 5 1/2: Support rematerialized frames in DebugScopes::updateLiveScope. (r=jimb)
js/src/jit-test/tests/debug/Environment-getVariable-13.js
js/src/jit/RematerializedFrame.cpp
js/src/jit/RematerializedFrame.h
js/src/vm/ScopeObject.cpp
js/src/vm/Stack-inl.h
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Environment-getVariable-13.js
@@ -0,0 +1,47 @@
+// Tests that we can use debug scopes with Ion frames.
+//
+// Unfortunately these tests are brittle. They depend on opaque JIT heuristics
+// kicking in.
+
+load(libdir + "jitopts.js");
+
+if (!jitTogglesMatch(Opts_Ion2NoParallelCompilation))
+  quit(0);
+
+withJitOptions(Opts_Ion2NoParallelCompilation, function () {
+  var g = newGlobal();
+  var dbg = new Debugger;
+
+  // Note that this *depends* on CCW scripted functions being opaque to Ion
+  // optimization and not deoptimizing the frames below the call to toggle.
+  g.toggle = function toggle(d) {
+    if (d) {
+      dbg.addDebuggee(g);
+      var frame = dbg.getNewestFrame();
+      assertEq(frame.implementation, "ion");
+      // g is heavyweight but its call object is optimized out, because its
+      // arguments and locals are unaliased.
+      //
+      // Calling frame.environment here should make a fake debug scope that
+      // gets things directly from the frame. Calling frame.arguments doesn't
+      // go through the scope object and reads directly off the frame. Assert
+      // that the two are equal.
+      assertEq(frame.environment.getVariable("x"), frame.arguments[1]);
+    }
+  };
+
+  g.eval("" + function f(d, x) { g(d, x); });
+  g.eval("" + function g(d, x) {
+    for (var i = 0; i < 200; i++);
+    function inner() { i = 42; };
+    toggle(d);
+    // Use x so it doesn't get optimized out.
+    x++;
+  });
+
+  g.eval("(" + function test() {
+    for (i = 0; i < 5; i++)
+      f(false, 42);
+    f(true, 42);
+  } + ")();");
+});
--- a/js/src/jit/RematerializedFrame.cpp
+++ b/js/src/jit/RematerializedFrame.cpp
@@ -24,17 +24,18 @@ struct CopyValueToRematerializedFrame
     { }
 
     void operator()(const Value &v) {
         *slots++ = v;
     }
 };
 
 RematerializedFrame::RematerializedFrame(JSContext *cx, uint8_t *top, InlineFrameIterator &iter)
-  : top_(top),
+  : prevUpToDate_(false),
+    top_(top),
     frameNo_(iter.frameNo()),
     numActualArgs_(iter.numActualArgs()),
     script_(iter.script())
 {
     CopyValueToRematerializedFrame op(slots_);
     iter.readFrameArgsAndLocals(cx, op, op, &scopeChain_, &returnValue_,
                                 &argsObj_, &thisValue_, ReadFrame_Actuals);
 }
--- a/js/src/jit/RematerializedFrame.h
+++ b/js/src/jit/RematerializedFrame.h
@@ -19,16 +19,19 @@ namespace js {
 namespace jit {
 
 //
 // An optimized frame that has been rematerialized with values read out of
 // Snapshots.
 //
 class RematerializedFrame
 {
+    // See DebugScopes::updateLiveScopes.
+    bool prevUpToDate_;
+
     // The fp of the top frame associated with this possibly inlined frame.
     uint8_t *top_;
 
     size_t frameNo_;
     unsigned numActualArgs_;
 
     JSScript *script_;
     JSObject *scopeChain_;
@@ -38,16 +41,23 @@ class RematerializedFrame
     Value thisValue_;
     Value slots_[1];
 
     RematerializedFrame(JSContext *cx, uint8_t *top, InlineFrameIterator &iter);
 
   public:
     static RematerializedFrame *New(JSContext *cx, uint8_t *top, InlineFrameIterator &iter);
 
+    bool prevUpToDate() const {
+        return prevUpToDate_;
+    }
+    void setPrevUpToDate() {
+        prevUpToDate_ = true;
+    }
+
     uint8_t *top() const {
         return top_;
     }
     size_t frameNo() const {
         return frameNo_;
     }
     bool inlined() const {
         return frameNo_ > 0;
--- a/js/src/vm/ScopeObject.cpp
+++ b/js/src/vm/ScopeObject.cpp
@@ -2012,21 +2012,17 @@ DebugScopes::updateLiveScopes(JSContext 
      * flag indicates whether the scopes of frames older than fp are already
      * included in liveScopes. It might seem simpler to have fp instead carry a
      * flag indicating whether fp itself is accurately described, but then we
      * would need to clear that flag whenever fp ran code. By storing the 'up
      * to date' bit for fp->prev() in fp, simply popping fp effectively clears
      * the flag for us, at exactly the time when execution resumes fp->prev().
      */
     for (AllFramesIter i(cx); !i.done(); ++i) {
-        /*
-         * Debug-mode currently disables Ion compilation in the compartment of
-         * the debuggee.
-         */
-        if (i.isIon())
+        if (!i.hasUsableAbstractFramePtr())
             continue;
 
         AbstractFramePtr frame = i.abstractFramePtr();
         if (frame.scopeChain()->compartment() != cx->compartment())
             continue;
 
         if (frame.isFunctionFrame() && frame.callee()->isGenerator())
             continue;
--- a/js/src/vm/Stack-inl.h
+++ b/js/src/vm/Stack-inl.h
@@ -818,30 +818,36 @@ AbstractFramePtr::copyRawFrameSlots(Auto
 }
 
 inline bool
 AbstractFramePtr::prevUpToDate() const
 {
     if (isInterpreterFrame())
         return asInterpreterFrame()->prevUpToDate();
 #ifdef JS_ION
-    return asBaselineFrame()->prevUpToDate();
+    if (isBaselineFrame())
+        return asBaselineFrame()->prevUpToDate();
+    return asRematerializedFrame()->prevUpToDate();
 #else
     MOZ_ASSUME_UNREACHABLE("Invalid frame");
 #endif
 }
 inline void
 AbstractFramePtr::setPrevUpToDate() const
 {
     if (isInterpreterFrame()) {
         asInterpreterFrame()->setPrevUpToDate();
         return;
     }
 #ifdef JS_ION
-    asBaselineFrame()->setPrevUpToDate();
+    if (isBaselineFrame()) {
+        asBaselineFrame()->setPrevUpToDate();
+        return;
+    }
+    asRematerializedFrame()->setPrevUpToDate();
 #else
     MOZ_ASSUME_UNREACHABLE("Invalid frame");
 #endif
 }
 
 inline Value &
 AbstractFramePtr::thisValue() const
 {