Bug 1029963 - Recover slots in RematerializedFrames. (r=nbp)
authorShu-yu Guo <shu@rfrn.org>
Fri, 09 Jan 2015 19:21:16 -0800
changeset 248931 4f1b2f93ae484bb16b10bde6a1272139ceb2abdd
parent 248930 8d48c34f44ed06ffe1257afc96b9615b0b26628f
child 248932 9d9610c574b4a78adb93c104c2c956d4f0f44241
push id4489
push userraliiev@mozilla.com
push dateMon, 23 Feb 2015 15:17:55 +0000
treeherdermozilla-beta@fd7c3dc24146 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnbp
bugs1029963
milestone37.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 1029963 - Recover slots in RematerializedFrames. (r=nbp)
js/src/jit-test/tests/debug/bug1118878.js
js/src/jit/JitFrameIterator.h
js/src/jit/RematerializedFrame.cpp
js/src/jit/RematerializedFrame.h
js/src/vm/Stack.cpp
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/bug1118878.js
@@ -0,0 +1,11 @@
+
+var evalInFrame = (function (global) {
+  var dbgGlobal = newGlobal();
+  var dbg = new dbgGlobal.Debugger();
+  return function evalInFrame(upCount, code) {
+    dbg.addDebuggee(global);
+    var frame = dbg.getNewestFrame().older;
+    var completion = frame.eval(code);
+  };
+})(this);
+evaluate("for (var k in 'xxx') (function g() { Math.atan2(42); evalInFrame((0), (''), true); })();", { noScriptRval : true, compileAndGo : true });
--- a/js/src/jit/JitFrameIterator.h
+++ b/js/src/jit/JitFrameIterator.h
@@ -647,18 +647,16 @@ class InlineFrameIterator
                                 ArgumentsObject **argsObj, Value *thisv,
                                 ReadFrameArgsBehavior behavior,
                                 MaybeReadFallback &fallback) const
     {
         SnapshotIterator s(si_);
 
         // Read the scope chain.
         if (scopeChain) {
-            MOZ_ASSERT(!fallback.canRecoverResults());
-            JS::AutoSuppressGCAnalysis nogc; // If we cannot recover then we cannot GC.
             Value scopeChainValue = s.maybeRead(fallback);
             *scopeChain = computeScopeChain(scopeChainValue, fallback, hasCallObj);
         } else {
             s.skip();
         }
 
         // Read return value.
         if (rval)
@@ -714,24 +712,18 @@ class InlineFrameIterator
                     for (unsigned i = nformal; i < nactual; i++)
                         argOp(argv[i]);
                 }
             }
         }
 
         // At this point we've read all the formals in s, and can read the
         // locals.
-        for (unsigned i = 0; i < script()->nfixed(); i++) {
-            // We have to use maybeRead here, some of these might be recover
-            // instructions, and currently InlineFrameIter does not support
-            // recovering slots.
-            //
-            // FIXME bug 1029963.
+        for (unsigned i = 0; i < script()->nfixed(); i++)
             localOp(s.maybeRead(fallback));
-        }
     }
 
     template <class Op>
     void unaliasedForEachActual(JSContext *cx, Op op,
                                 ReadFrameArgsBehavior behavior,
                                 MaybeReadFallback &fallback) const
     {
         Nop nop;
--- a/js/src/jit/RematerializedFrame.cpp
+++ b/js/src/jit/RematerializedFrame.cpp
@@ -24,66 +24,63 @@ struct CopyValueToRematerializedFrame
     { }
 
     void operator()(const Value &v) {
         *slots++ = v;
     }
 };
 
 RematerializedFrame::RematerializedFrame(JSContext *cx, uint8_t *top, unsigned numActualArgs,
-                                         InlineFrameIterator &iter)
+                                         InlineFrameIterator &iter, MaybeReadFallback &fallback)
   : prevUpToDate_(false),
     isDebuggee_(iter.script()->isDebuggee()),
     top_(top),
     pc_(iter.pc()),
     frameNo_(iter.frameNo()),
     numActualArgs_(numActualArgs),
     script_(iter.script())
 {
     CopyValueToRematerializedFrame op(slots_);
-    MaybeReadFallback fallback(MagicValue(JS_OPTIMIZED_OUT));
     iter.readFrameArgsAndLocals(cx, op, op, &scopeChain_, &hasCallObj_, &returnValue_,
                                 &argsObj_, &thisValue_, ReadFrame_Actuals,
                                 fallback);
 }
 
 /* static */ RematerializedFrame *
-RematerializedFrame::New(JSContext *cx, uint8_t *top, InlineFrameIterator &iter)
+RematerializedFrame::New(JSContext *cx, uint8_t *top, InlineFrameIterator &iter,
+                         MaybeReadFallback &fallback)
 {
     unsigned numFormals = iter.isFunctionFrame() ? iter.calleeTemplate()->nargs() : 0;
     unsigned argSlots = Max(numFormals, iter.numActualArgs());
     size_t numBytes = sizeof(RematerializedFrame) +
         (argSlots + iter.script()->nfixed()) * sizeof(Value) -
         sizeof(Value); // 1 Value included in sizeof(RematerializedFrame)
 
     void *buf = cx->pod_calloc<uint8_t>(numBytes);
     if (!buf)
         return nullptr;
 
-    return new (buf) RematerializedFrame(cx, top, iter.numActualArgs(), iter);
+    return new (buf) RematerializedFrame(cx, top, iter.numActualArgs(), iter, fallback);
 }
 
 /* static */ bool
 RematerializedFrame::RematerializeInlineFrames(JSContext *cx, uint8_t *top,
                                                InlineFrameIterator &iter,
+                                               MaybeReadFallback &fallback,
                                                Vector<RematerializedFrame *> &frames)
 {
     if (!frames.resize(iter.frameCount()))
         return false;
 
     while (true) {
         size_t frameNo = iter.frameNo();
-        RematerializedFrame *frame = RematerializedFrame::New(cx, top, iter);
+        RematerializedFrame *frame = RematerializedFrame::New(cx, top, iter, fallback);
         if (!frame)
             return false;
         if (frame->scopeChain()) {
-            // Frames are often rematerialized with the cx inside a Debugger's
-            // compartment. To create CallObjects, we need to be in that
-            // frame's compartment.
-            AutoCompartment ac(cx, frame->scopeChain());
             if (!EnsureHasScopeObjects(cx, frame))
                 return false;
         }
 
         frames[frameNo] = frame;
 
         if (!iter.more())
             break;
--- a/js/src/jit/RematerializedFrame.h
+++ b/js/src/jit/RematerializedFrame.h
@@ -45,25 +45,27 @@ class RematerializedFrame
     JSObject *scopeChain_;
     ArgumentsObject *argsObj_;
 
     Value returnValue_;
     Value thisValue_;
     Value slots_[1];
 
     RematerializedFrame(JSContext *cx, uint8_t *top, unsigned numActualArgs,
-                        InlineFrameIterator &iter);
+                        InlineFrameIterator &iter, MaybeReadFallback &fallback);
 
   public:
-    static RematerializedFrame *New(JSContext *cx, uint8_t *top, InlineFrameIterator &iter);
+    static RematerializedFrame *New(JSContext *cx, uint8_t *top, InlineFrameIterator &iter,
+                                    MaybeReadFallback &fallback);
 
     // Rematerialize all remaining frames pointed to by |iter| into |frames|
     // in older-to-younger order, e.g., frames[0] is the oldest frame.
     static bool RematerializeInlineFrames(JSContext *cx, uint8_t *top,
                                           InlineFrameIterator &iter,
+                                          MaybeReadFallback &fallback,
                                           Vector<RematerializedFrame *> &frames);
 
     // Free a vector of RematerializedFrames; takes care to call the
     // destructor. Also clears the vector.
     static void FreeInVector(Vector<RematerializedFrame *> &frames);
 
     // Mark a vector of RematerializedFrames.
     static void MarkInVector(JSTracer *trc, Vector<RematerializedFrame *> &frames);
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -1498,18 +1498,28 @@ jit::JitActivation::getRematerializedFra
             return nullptr;
 
         // The unit of rematerialization is an uninlined frame and its inlined
         // frames. Since inlined frames do not exist outside of snapshots, it
         // is impossible to synchronize their rematerialized copies to
         // preserve identity. Therefore, we always rematerialize an uninlined
         // frame and all its inlined frames at once.
         InlineFrameIterator inlineIter(cx, &iter);
-        if (!RematerializedFrame::RematerializeInlineFrames(cx, top, inlineIter, p->value()))
+        MaybeReadFallback recover(cx, this, &iter);
+
+        // Frames are often rematerialized with the cx inside a Debugger's
+        // compartment. To recover slots and to create CallObjects, we need to
+        // be in the activation's compartment.
+        AutoCompartment ac(cx, compartment_);
+
+        if (!RematerializedFrame::RematerializeInlineFrames(cx, top, inlineIter, recover,
+                                                            p->value()))
+        {
             return nullptr;
+        }
     }
 
     return p->value()[inlineDepth];
 }
 
 jit::RematerializedFrame *
 jit::JitActivation::lookupRematerializedFrame(uint8_t *top, size_t inlineDepth)
 {