Bug 1019304 - Part 1: Teach RematerializedFrame to rematerialize bailout frames. (r=jandem)
authorShu-yu Guo <shu@rfrn.org>
Fri, 20 Jun 2014 18:39:13 -0700
changeset 189890 feaac6c10dc6dd76e908bdc9185cc8849bbb8595
parent 189889 b3ebf7675c7bd1d85ed1b7290e1d2c3ae28a0490
child 189891 cd7125c3338572cbb59534ed03243a8a87fbc92c
push id45184
push usershu@rfrn.org
push dateSat, 21 Jun 2014 01:34:02 +0000
treeherdermozilla-inbound@a0fca95e6e0f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem
bugs1019304
milestone33.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 1019304 - Part 1: Teach RematerializedFrame to rematerialize bailout frames. (r=jandem)
js/src/jit/RematerializedFrame.cpp
js/src/jit/RematerializedFrame.h
js/src/vm/Stack.cpp
js/src/vm/Stack.h
--- a/js/src/jit/RematerializedFrame.cpp
+++ b/js/src/jit/RematerializedFrame.cpp
@@ -24,42 +24,76 @@ struct CopyValueToRematerializedFrame
     { }
 
     void operator()(const Value &v) {
         *slots++ = v;
     }
 };
 
 RematerializedFrame::RematerializedFrame(ThreadSafeContext *cx, uint8_t *top,
-                                         InlineFrameIterator &iter)
+                                         unsigned numActualArgs, InlineFrameIterator &iter)
   : prevUpToDate_(false),
     top_(top),
+    pc_(iter.pc()),
     frameNo_(iter.frameNo()),
-    numActualArgs_(iter.numActualArgs()),
+    numActualArgs_(numActualArgs),
     script_(iter.script())
 {
     CopyValueToRematerializedFrame op(slots_);
     iter.readFrameArgsAndLocals(cx, op, op, &scopeChain_, &returnValue_,
                                 &argsObj_, &thisValue_, ReadFrame_Actuals);
 }
 
 /* static */ RematerializedFrame *
 RematerializedFrame::New(ThreadSafeContext *cx, uint8_t *top, InlineFrameIterator &iter)
 {
     unsigned numFormals = iter.isFunctionFrame() ? iter.callee()->nargs() : 0;
+    unsigned numActualArgs = Max(numFormals, iter.numActualArgs());
     size_t numBytes = sizeof(RematerializedFrame) +
-        (Max(numFormals, iter.numActualArgs()) +
-         iter.script()->nfixed()) * sizeof(Value) -
+        (numActualArgs + iter.script()->nfixed()) * sizeof(Value) -
         sizeof(Value); // 1 Value included in sizeof(RematerializedFrame)
 
     void *buf = cx->calloc_(numBytes);
     if (!buf)
         return nullptr;
 
-    return new (buf) RematerializedFrame(cx, top, iter);
+    return new (buf) RematerializedFrame(cx, top, numActualArgs, iter);
+}
+
+/* static */ bool
+RematerializedFrame::RematerializeInlineFrames(ThreadSafeContext *cx, uint8_t *top,
+                                               InlineFrameIterator &iter,
+                                               Vector<RematerializedFrame *> &frames)
+{
+    if (!frames.resize(iter.frameCount()))
+        return false;
+
+    while (true) {
+        size_t frameNo = iter.frameNo();
+        frames[frameNo] = RematerializedFrame::New(cx, top, iter);
+        if (!frames[frameNo])
+            return false;
+
+        if (!iter.more())
+            break;
+        ++iter;
+    }
+
+    return true;
+}
+
+/* static */ void
+RematerializedFrame::FreeInVector(Vector<RematerializedFrame *> &frames)
+{
+    for (size_t i = 0; i < frames.length(); i++) {
+        RematerializedFrame *f = frames[i];
+        f->RematerializedFrame::~RematerializedFrame();
+        js_free(f);
+    }
+    frames.clear();
 }
 
 CallObject &
 RematerializedFrame::callObj() const
 {
     JS_ASSERT(hasCallObj());
 
     JSObject *scope = scopeChain();
@@ -77,45 +111,46 @@ RematerializedFrame::mark(JSTracer *trc)
     gc::MarkValueRoot(trc, &thisValue_, "remat ion frame this");
     gc::MarkValueRootRange(trc, slots_, slots_ + numActualArgs_ + script_->nfixed(),
                            "remat ion frame stack");
 }
 
 void
 RematerializedFrame::dump()
 {
-    fprintf(stderr, " Rematerialized Optimized Frame%s\n", inlined() ? " (inlined)" : "");
+    fprintf(stderr, " Rematerialized Ion Frame%s\n", inlined() ? " (inlined)" : "");
     if (isFunctionFrame()) {
         fprintf(stderr, "  callee fun: ");
 #ifdef DEBUG
-        js_DumpObject(callee());
+        js_DumpValue(ObjectValue(*callee()));
 #else
         fprintf(stderr, "?\n");
 #endif
     } else {
         fprintf(stderr, "  global frame, no callee\n");
     }
 
-    fprintf(stderr, "  file %s line %u\n",
-            script()->filename(), (unsigned) script()->lineno());
+    fprintf(stderr, "  file %s line %u offset %zu\n",
+            script()->filename(), (unsigned) script()->lineno(),
+            script()->pcToOffset(pc()));
 
     fprintf(stderr, "  script = %p\n", (void*) script());
 
     if (isFunctionFrame()) {
         fprintf(stderr, "  scope chain: ");
 #ifdef DEBUG
-        js_DumpObject(scopeChain());
+        js_DumpValue(ObjectValue(*scopeChain()));
 #else
         fprintf(stderr, "?\n");
 #endif
 
         if (hasArgsObj()) {
             fprintf(stderr, "  args obj: ");
 #ifdef DEBUG
-            js_DumpObject(&argsObj());
+            js_DumpValue(ObjectValue(argsObj()));
 #else
             fprintf(stderr, "?\n");
 #endif
         }
 
         fprintf(stderr, "  this: ");
 #ifdef DEBUG
         js_DumpValue(thisValue());
--- a/js/src/jit/RematerializedFrame.h
+++ b/js/src/jit/RematerializedFrame.h
@@ -25,43 +25,60 @@ namespace jit {
 class RematerializedFrame
 {
     // See DebugScopes::updateLiveScopes.
     bool prevUpToDate_;
 
     // The fp of the top frame associated with this possibly inlined frame.
     uint8_t *top_;
 
+    // The bytecode at the time of rematerialization.
+    jsbytecode *pc_;
+
     size_t frameNo_;
     unsigned numActualArgs_;
 
     JSScript *script_;
     JSObject *scopeChain_;
     ArgumentsObject *argsObj_;
 
     Value returnValue_;
     Value thisValue_;
     Value slots_[1];
 
-    RematerializedFrame(ThreadSafeContext *cx, uint8_t *top, InlineFrameIterator &iter);
+    RematerializedFrame(ThreadSafeContext *cx, uint8_t *top, unsigned numActualArgs,
+                        InlineFrameIterator &iter);
 
   public:
     static RematerializedFrame *New(ThreadSafeContext *cx, uint8_t *top,
                                     InlineFrameIterator &iter);
 
+    // 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(ThreadSafeContext *cx, uint8_t *top,
+                                          InlineFrameIterator &iter,
+                                          Vector<RematerializedFrame *> &frames);
+
+    // Free a vector of RematerializedFrames; takes care to call the
+    // destructor. Also clears the vector.
+    static void FreeInVector(Vector<RematerializedFrame *> &frames);
+
     bool prevUpToDate() const {
         return prevUpToDate_;
     }
     void setPrevUpToDate() {
         prevUpToDate_ = true;
     }
 
     uint8_t *top() const {
         return top_;
     }
+    jsbytecode *pc() const {
+        return pc_;
+    }
     size_t frameNo() const {
         return frameNo_;
     }
     bool inlined() const {
         return frameNo_ > 0;
     }
 
     JSObject *scopeChain() const {
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -1582,99 +1582,85 @@ jit::JitActivation::setActive(JSContext 
         cx->mainThread().jitTop = prevJitTop_;
         cx->mainThread().jitJSContext = prevJitJSContext_;
     }
 }
 
 #ifdef JS_ION
 
 void
-jit::JitActivation::freeRematerializedFramesInVector(RematerializedFrameVector &frames)
-{
-    for (size_t i = 0; i < frames.length(); i++) {
-        RematerializedFrame *f = frames[i];
-        f->RematerializedFrame::~RematerializedFrame();
-        js_free(f);
-    }
-    frames.clear();
-}
-
-void
 jit::JitActivation::removeRematerializedFrame(uint8_t *top)
 {
     if (!rematerializedFrames_)
         return;
 
     if (RematerializedFrameTable::Ptr p = rematerializedFrames_->lookup(top)) {
-        freeRematerializedFramesInVector(p->value());
+        RematerializedFrame::FreeInVector(p->value());
         rematerializedFrames_->remove(p);
     }
 }
 
 void
 jit::JitActivation::clearRematerializedFrames()
 {
     if (!rematerializedFrames_)
         return;
 
     for (RematerializedFrameTable::Enum e(*rematerializedFrames_); !e.empty(); e.popFront()) {
-        freeRematerializedFramesInVector(e.front().value());
+        RematerializedFrame::FreeInVector(e.front().value());
         e.removeFront();
     }
 }
 
+template <class T>
 jit::RematerializedFrame *
-jit::JitActivation::getRematerializedFrame(ThreadSafeContext *cx, JitFrameIterator &iter,
-                                           size_t inlineDepth)
+jit::JitActivation::getRematerializedFrame(ThreadSafeContext *cx, const T &iter, size_t inlineDepth)
 {
     // Only allow rematerializing from the same thread.
     MOZ_ASSERT(cx->perThreadData == cx_->perThreadData);
     MOZ_ASSERT(iter.activation() == this);
     MOZ_ASSERT(iter.isIonJS());
 
     if (!rematerializedFrames_) {
         rematerializedFrames_ = cx->new_<RematerializedFrameTable>(cx);
         if (!rematerializedFrames_ || !rematerializedFrames_->init()) {
             rematerializedFrames_ = nullptr;
             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.
-
     uint8_t *top = iter.fp();
     RematerializedFrameTable::AddPtr p = rematerializedFrames_->lookupForAdd(top);
     if (!p) {
         RematerializedFrameVector empty(cx);
         if (!rematerializedFrames_->add(p, top, Move(empty)))
             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 (!p->value().resize(inlineIter.frameCount()))
+        if (!RematerializedFrame::RematerializeInlineFrames(cx, top, inlineIter, p->value()))
             return nullptr;
-
-        while (true) {
-            size_t frameNo = inlineIter.frameNo();
-            p->value()[frameNo] = RematerializedFrame::New(cx, top, inlineIter);
-            if (!p->value()[frameNo])
-                return nullptr;
-
-            if (!inlineIter.more())
-                break;
-            ++inlineIter;
-        }
     }
 
     return p->value()[inlineDepth];
 }
 
+template jit::RematerializedFrame *
+jit::JitActivation::getRematerializedFrame<jit::JitFrameIterator>(ThreadSafeContext *cx,
+                                                                  const jit::JitFrameIterator &iter,
+                                                                  size_t inlineDepth);
+template jit::RematerializedFrame *
+jit::JitActivation::getRematerializedFrame<jit::IonBailoutIterator>(ThreadSafeContext *cx,
+                                                                    const jit::IonBailoutIterator &iter,
+                                                                    size_t inlineDepth);
+
 jit::RematerializedFrame *
 jit::JitActivation::lookupRematerializedFrame(uint8_t *top, size_t inlineDepth)
 {
     if (!rematerializedFrames_)
         return nullptr;
     if (RematerializedFrameTable::Ptr p = rematerializedFrames_->lookup(top))
         return inlineDepth < p->value().length() ? p->value()[inlineDepth] : nullptr;
     return nullptr;
--- a/js/src/vm/Stack.h
+++ b/js/src/vm/Stack.h
@@ -1333,21 +1333,20 @@ class JitActivation : public Activation
     bool active_;
 
 #ifdef JS_ION
     // Rematerialized Ion frames which has info copied out of snapshots. Maps
     // frame pointers (i.e. jitTop) to a vector of rematerializations of all
     // inline frames associated with that frame.
     //
     // This table is lazily initialized by calling getRematerializedFrame.
-    typedef Vector<RematerializedFrame *, 1> RematerializedFrameVector;
+    typedef Vector<RematerializedFrame *> RematerializedFrameVector;
     typedef HashMap<uint8_t *, RematerializedFrameVector> RematerializedFrameTable;
     RematerializedFrameTable *rematerializedFrames_;
 
-    void freeRematerializedFramesInVector(RematerializedFrameVector &frames);
     void clearRematerializedFrames();
 #endif
 
 #ifdef CHECK_OSIPOINT_REGISTERS
   protected:
     // Used to verify that live registers don't change between a VM call and
     // the OsiPoint that follows it. Protected to silence Clang warning.
     uint32_t checkRegs_;
@@ -1394,18 +1393,21 @@ class JitActivation : public Activation
 #endif
 
 #ifdef JS_ION
     // Look up a rematerialized frame keyed by the fp, rematerializing the
     // frame if one doesn't already exist. A frame can only be rematerialized
     // if an IonFrameIterator pointing to the nearest uninlined frame can be
     // provided, as values need to be read out of snapshots.
     //
+    // T is either JitFrameIterator or IonBailoutIterator.
+    //
     // The inlineDepth must be within bounds of the frame pointed to by iter.
-    RematerializedFrame *getRematerializedFrame(ThreadSafeContext *cx, JitFrameIterator &iter,
+    template <class T>
+    RematerializedFrame *getRematerializedFrame(ThreadSafeContext *cx, const T &iter,
                                                 size_t inlineDepth = 0);
 
     // Look up a rematerialized frame by the fp. If inlineDepth is out of
     // bounds of what has been rematerialized, nullptr is returned.
     RematerializedFrame *lookupRematerializedFrame(uint8_t *top, size_t inlineDepth = 0);
 
     bool hasRematerializedFrame(uint8_t *top, size_t inlineDepth = 0) {
         return !!lookupRematerializedFrame(top, inlineDepth);