Bug 1032869 - Part 4: Add an auto-updated DebugModeOSRVolatileJitFrameIterator. (r=jandem)
authorShu-yu Guo <shu@rfrn.org>
Thu, 13 Nov 2014 14:39:41 -0800
changeset 215652 06d07689a043ede470605c5f75692f6bc100e153
parent 215651 96a2f59f6ce4f9230407e06c97b492f95ddbb091
child 215653 d65f01b9e6c6a57fb9a49fe246a8d378fa1e4369
push id51810
push usershu@rfrn.org
push dateThu, 13 Nov 2014 22:39:12 +0000
treeherdermozilla-inbound@d65f01b9e6c6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem
bugs1032869
milestone36.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 1032869 - Part 4: Add an auto-updated DebugModeOSRVolatileJitFrameIterator. (r=jandem)
js/src/jit/BaselineDebugModeOSR.cpp
js/src/jit/BaselineDebugModeOSR.h
js/src/jit/IonFrames.cpp
js/src/jscntxt.cpp
js/src/jscntxt.h
--- a/js/src/jit/BaselineDebugModeOSR.cpp
+++ b/js/src/jit/BaselineDebugModeOSR.cpp
@@ -375,16 +375,18 @@ PatchBaselineFramesForDebugMode(JSContex
                 // the baseline frame. The stub frame is patched below. For
                 // the baseline frame here, we resume right after the IC
                 // returns.
                 //
                 // Since we're using the same IC stub code, we can resume
                 // directly to the IC resume address.
                 uint8_t *retAddr = bl->returnAddressForIC(bl->icEntryFromPCOffset(pcOffset));
                 SpewPatchBaselineFrame(prev->returnAddress(), retAddr, script, kind, pc);
+                DebugModeOSRVolatileJitFrameIterator::forwardLiveIterators(
+                    cx, prev->returnAddress(), retAddr);
                 prev->setReturnAddress(retAddr);
                 entryIndex++;
                 break;
             }
 
             // Cases F and G above.
             //
             // We undo a previous recompile by handling cases B, C, D, and E
@@ -990,8 +992,19 @@ JitRuntime::generateBaselineDebugModeOSR
     *noFrameRegPopOffsetOut = noFrameRegPopOffset.offset();
 
 #ifdef JS_ION_PERF
     writePerfSpewerJitCodeProfile(code, "BaselineDebugModeOSRHandler");
 #endif
 
     return code;
 }
+
+/* static */ void
+DebugModeOSRVolatileJitFrameIterator::forwardLiveIterators(JSContext *cx,
+                                                           uint8_t *oldAddr, uint8_t *newAddr)
+{
+    DebugModeOSRVolatileJitFrameIterator *iter;
+    for (iter = cx->liveVolatileJitFrameIterators_; iter; iter = iter->prev) {
+        if (iter->returnAddressToFp_ == oldAddr)
+            iter->returnAddressToFp_ = newAddr;
+    }
+}
--- a/js/src/jit/BaselineDebugModeOSR.h
+++ b/js/src/jit/BaselineDebugModeOSR.h
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef jit_BaselineDebugModeOSR_h
 #define jit_BaselineDebugModeOSR_h
 
 #include "jit/BaselineFrame.h"
 #include "jit/BaselineIC.h"
 #include "jit/BaselineJIT.h"
+#include "jit/JitFrameIterator.h"
 
 #include "vm/Debugger.h"
 
 namespace js {
 namespace jit {
 
 // Note that this file and the corresponding .cpp implement debug mode
 // on-stack recompilation. This is to be distinguished from ordinary
@@ -63,16 +64,41 @@ class DebugModeOSRVolatileStub
     T &get() { MOZ_ASSERT(!invalid()); return stub_; }
     const T &get() const { MOZ_ASSERT(!invalid()); return stub_; }
 
     bool operator!=(const T &other) const { MOZ_ASSERT(!invalid()); return stub_ != other; }
     bool operator==(const T &other) const { MOZ_ASSERT(!invalid()); return stub_ == other; }
 };
 
 //
+// A JitFrameIterator that updates itself in case of recompilation of an
+// on-stack baseline script.
+//
+class DebugModeOSRVolatileJitFrameIterator : public JitFrameIterator
+{
+    DebugModeOSRVolatileJitFrameIterator **stack, *prev;
+
+  public:
+    explicit DebugModeOSRVolatileJitFrameIterator(JSContext *cx)
+      : JitFrameIterator(cx)
+    {
+        stack = &cx->liveVolatileJitFrameIterators_;
+        prev = *stack;
+        *stack = this;
+    }
+
+    ~DebugModeOSRVolatileJitFrameIterator() {
+        MOZ_ASSERT(*stack == this);
+        *stack = prev;
+    }
+
+    static void forwardLiveIterators(JSContext *cx, uint8_t *oldAddr, uint8_t *newAddr);
+};
+
+//
 // Auxiliary info to help the DebugModeOSRHandler fix up state.
 //
 struct BaselineDebugModeOSRInfo
 {
     uint8_t *resumeAddr;
     jsbytecode *pc;
     PCMappingSlotInfo slotInfo;
     ICEntry::Kind frameKind;
--- a/js/src/jit/IonFrames.cpp
+++ b/js/src/jit/IonFrames.cpp
@@ -703,17 +703,23 @@ HandleException(ResumeFromException *rfe
 
     // Clear any Ion return override that's been set.
     // This may happen if a callVM function causes an invalidation (setting the
     // override), and then fails, bypassing the bailout handlers that would
     // otherwise clear the return override.
     if (cx->runtime()->jitRuntime()->hasIonReturnOverride())
         cx->runtime()->jitRuntime()->takeIonReturnOverride();
 
-    JitFrameIterator iter(cx);
+    // The Debugger onExceptionUnwind hook (reachable via
+    // HandleExceptionBaseline below) may cause on-stack recompilation of
+    // baseline scripts, which may patch return addresses on the stack. Since
+    // JitFrameIterators cache the previous frame's return address when
+    // iterating, we need a variant here that is automatically updated should
+    // on-stack recompilation occur.
+    DebugModeOSRVolatileJitFrameIterator iter(cx);
     while (!iter.isEntry()) {
         bool overrecursed = false;
         if (iter.isIonJS()) {
             // Search each inlined frame for live iterator objects, and close
             // them.
             InlineFrameIterator frames(cx, &iter);
 
             // Invalidation state will be the same for all inlined scripts in the frame.
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -1006,16 +1006,17 @@ ThreadSafeContext::recoverFromOutOfMemor
 }
 
 JSContext::JSContext(JSRuntime *rt)
   : ExclusiveContext(rt, &rt->mainThread, Context_JS),
     throwing(false),
     unwrappedException_(UndefinedValue()),
     options_(),
     propagatingForcedReturn_(false),
+    liveVolatileJitFrameIterators_(nullptr),
     reportGranularity(JS_DEFAULT_JITREPORT_GRANULARITY),
     resolvingList(nullptr),
     generatingError(false),
     savedFrameChains_(),
     cycleDetectorSet(MOZ_THIS_IN_INITIALIZER_LIST()),
     data(nullptr),
     data2(nullptr),
     outstandingRequests(0),
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -30,16 +30,17 @@ js_ReportAllocationOverflow(js::ThreadSa
 extern void
 js_ReportOverRecursed(js::ThreadSafeContext *cx);
 
 namespace js {
 
 namespace jit {
 class IonContext;
 class CompileCompartment;
+class DebugModeOSRVolatileJitFrameIterator;
 }
 
 struct CallsiteCloneKey {
     /* The original function that we are cloning. */
     JSFunction *original;
 
     /* The script of the call. */
     JSScript *script;
@@ -416,29 +417,34 @@ struct JSContext : public js::ExclusiveC
     js::PerThreadData &mainThread() const { return runtime()->mainThread; }
 
     static size_t offsetOfRuntime() {
         return offsetof(JSContext, runtime_);
     }
 
     friend class js::ExclusiveContext;
     friend class JS::AutoSaveExceptionState;
+    friend class js::jit::DebugModeOSRVolatileJitFrameIterator;
 
   private:
     /* Exception state -- the exception member is a GC root by definition. */
     bool                throwing;            /* is there a pending exception? */
     js::Value           unwrappedException_; /* most-recently-thrown exception */
 
     /* Per-context options. */
     JS::ContextOptions  options_;
 
     // True if propagating a forced return from an interrupt handler during
     // debug mode.
     bool                propagatingForcedReturn_;
 
+    // A stack of live iterators that need to be updated in case of debug mode
+    // OSR.
+    js::jit::DebugModeOSRVolatileJitFrameIterator *liveVolatileJitFrameIterators_;
+
   public:
     int32_t             reportGranularity;  /* see vm/Probes.h */
 
     js::AutoResolving   *resolvingList;
 
     /* True if generating an error, to prevent runaway recursion. */
     bool                generatingError;