Bug 846363 - Fix SPS Profiler frame adjustment when bailing from Ion to Baseline. r=jandem
authorKannan Vijayan <kvijayan@mozilla.com>
Fri, 22 Mar 2013 17:00:40 -0400
changeset 127439 f035cd0ee56ea287483fb3b96ab266ac54f87353
parent 127438 0eaefffce290dd72593e4e6048c1a23b0d0b4774
child 127441 63c079713c45354b16cfef357446ffca523ee809
push id24503
push userjandemooij@gmail.com
push dateWed, 03 Apr 2013 15:43:00 +0000
treeherdermozilla-central@b5cb88ccd907 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem
bugs846363
milestone22.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 846363 - Fix SPS Profiler frame adjustment when bailing from Ion to Baseline. r=jandem
js/src/ion/BaselineBailouts.cpp
--- a/js/src/ion/BaselineBailouts.cpp
+++ b/js/src/ion/BaselineBailouts.cpp
@@ -438,18 +438,20 @@ struct BaselineStackBuilder
 //         |            |  CalleeToken  |
 //         |            +---------------+
 //         +------------|  Descr(Rect)  |
 //                      +---------------+
 //                      |  ReturnAddr   | <-- return into ArgumentsRectifier after call
 //                      +===============+
 //
 static bool
-InitFromBailout(JSContext *cx, HandleFunction fun, HandleScript script, SnapshotIterator &iter,
-                bool invalidate, BaselineStackBuilder &builder, MutableHandleFunction nextCallee)
+InitFromBailout(JSContext *cx, HandleScript caller, jsbytecode *callerPC,
+                HandleFunction fun, HandleScript script, SnapshotIterator &iter,
+                bool invalidate, BaselineStackBuilder &builder,
+                MutableHandleFunction nextCallee, jsbytecode **callPC)
 {
     uint32_t exprStackSlots = iter.slots() - (script->nfixed + CountArgSlots(fun));
 
     builder.resetFramePushed();
 
     // Build first baseline frame:
     // +===============+
     // | PrevFramePtr  |
@@ -504,17 +506,18 @@ InitFromBailout(JSContext *cx, HandleFun
     // that will be fixed later.
     if (cx->runtime->spsProfiler.enabled()) {
         IonSpew(IonSpew_BaselineBailouts, "      Setting SPS flag on frame!");
         flags |= BaselineFrame::HAS_PUSHED_SPS_FRAME;
     }
 
     // Initialize BaselineFrame::scopeChain
     JSObject *scopeChain = NULL;
-    if (iter.bailoutKind() == Bailout_ArgumentCheck) {
+    BailoutKind bailoutKind = iter.bailoutKind();
+    if (bailoutKind == Bailout_ArgumentCheck) {
         // Temporary hack -- skip the (unused) scopeChain, because it could be
         // bogus (we can fail before the scope chain slot is set). Strip the
         // hasScopeChain flag and we'll check this later to run prologue().
         IonSpew(IonSpew_BaselineBailouts, "      Bailout_ArgumentCheck! (no valid scopeChain)");
         iter.skip();
     } else {
         Value v = iter.read();
         if (v.isObject()) {
@@ -637,21 +640,24 @@ InitFromBailout(JSContext *cx, HandleFun
                                                       resumeAfter ? GetNextPc(pc) : pc);
     JS_ASSERT_IF(op != JSOP_FUNAPPLY || !iter.moreFrames() || resumeAfter,
                  exprStackSlots == expectedDepth);
 
     IonSpew(IonSpew_BaselineBailouts, "      Resuming %s pc offset %d (op %s) (line %d) of %s:%d",
                 resumeAfter ? "after" : "at", (int) pcOff, js_CodeName[op],
                 PCToLineNumber(script, pc), script->filename(), (int) script->lineno);
     IonSpew(IonSpew_BaselineBailouts, "      Bailout kind: %s",
-            BailoutKindString(iter.bailoutKind()));
+            BailoutKindString(bailoutKind));
 #endif
 
     // If this was the last inline frame, then unpacking is almost done.
     if (!iter.moreFrames()) {
+        // Last frame, so PC for call to next frame is set to NULL.
+        *callPC = NULL;
+
         // If the bailout was a resumeAfter, and the opcode is monitored,
         // then the bailed out state should be in a position to enter
         // into the ICTypeMonitor chain for the op.
         bool enterMonitorChain = false;
         if (resumeAfter && (js_CodeSpec[op].format & JOF_TYPESET)) {
             // Not every monitored op has a monitored fallback stub, e.g.
             // JSOP_GETINTRINSIC will always return the same value so does
             // not need a monitor chain.
@@ -747,26 +753,54 @@ InitFromBailout(JSContext *cx, HandleFun
                 // resume into the prologue for function scripts.
                 JS_ASSERT(fun);
                 JS_ASSERT(numUnsynced == 0);
                 opReturnAddr = baselineScript->prologueEntryAddr();
                 IonSpew(IonSpew_BaselineBailouts, "      Resuming into prologue.");
 
                 // If bailing into prologue, HAS_PUSHED_SPS_FRAME should not be set on frame.
                 blFrame->unsetPushedSPSFrame();
+
+                // Additionally, if SPS is enabled, there are two corner cases to handle:
+                //  1. If resuming into the prologue, and innermost frame is an inlined frame,
+                //     and bailout is because of argument check failure, then:
+                //          Top SPS profiler entry would be for caller frame.
+                //          Ion would not have set the PC index field on that frame
+                //              (since this bailout happens before MFunctionBoundary).
+                //          Make sure that's done now.
+                //  2. If resuming into the prologue, and the bailout is NOT because of an
+                //     argument check, then:
+                //          Top SPS profiler entry would be for callee frame.
+                //          Ion would already have pushed an SPS entry for this frame.
+                //          The pc for this entry would be set to NULL.
+                //          Make sure it's set to script->pc.
+                if (cx->runtime->spsProfiler.enabled()) {
+                    if (caller && bailoutKind == Bailout_ArgumentCheck) {
+                        IonSpew(IonSpew_BaselineBailouts, "      Setting PCidx on innermost "
+                                "inlined frame's parent's SPS entry (%s:%d) (pcIdx=%d)!",
+                                caller->filename(), caller->lineno, callerPC - caller->code);
+                        cx->runtime->spsProfiler.updatePC(caller, callerPC);
+                    } else if (bailoutKind != Bailout_ArgumentCheck) {
+                        IonSpew(IonSpew_BaselineBailouts,
+                                "      Popping SPS entry for innermost inlined frame's SPS entry");
+                        cx->runtime->spsProfiler.exit(cx, script, fun);
+                    }
+                }
             } else {
                 opReturnAddr = nativeCodeForPC;
             }
             builder.setResumeAddr(opReturnAddr);
             IonSpew(IonSpew_BaselineBailouts, "      Set resumeAddr=%p", opReturnAddr);
         }
 
         return true;
     }
 
+    *callPC = pc;
+
     // Write out descriptor of BaselineJS frame.
     size_t baselineFrameDescr = MakeFrameDescriptor((uint32_t) builder.framePushed(),
                                                     IonFrame_BaselineJS);
     if (!builder.writeWord(baselineFrameDescr, "Descriptor"))
         return false;
 
     // Calculate and write out return address.
     // The icEntry in question MUST have a ICCall_Fallback as its fallback stub.
@@ -1013,28 +1047,39 @@ ion::BailoutIonToBaseline(JSContext *cx,
         IonSpew(IonSpew_BaselineBailouts, "  Constructing!");
     else
         IonSpew(IonSpew_BaselineBailouts, "  Not constructing!");
 
     IonSpew(IonSpew_BaselineBailouts, "  Restoring frames:");
     int frameNo = 0;
 
     // Reconstruct baseline frames using the builder.
+    RootedScript caller(cx);
+    jsbytecode *callerPC = NULL;
     RootedFunction fun(cx, callee);
     RootedScript scr(cx, iter.script());
     while (true) {
         IonSpew(IonSpew_BaselineBailouts, "    FrameNo %d", frameNo);
+        jsbytecode *callPC = NULL;
         RootedFunction nextCallee(cx, NULL);
-        if (!InitFromBailout(cx, fun, scr, snapIter, invalidate, builder, &nextCallee))
+        if (!InitFromBailout(cx, caller, callerPC, fun, scr, snapIter, invalidate, builder,
+                             &nextCallee, &callPC))
+        {
             return BAILOUT_RETURN_FATAL_ERROR;
+        }
 
-        if (!snapIter.moreFrames())
-             break;
+        if (!snapIter.moreFrames()) {
+            JS_ASSERT(!callPC);
+            break;
+        }
 
         JS_ASSERT(nextCallee);
+        JS_ASSERT(callPC);
+        caller = scr;
+        callerPC = callPC;
         fun = nextCallee;
         scr = fun->nonLazyScript();
         snapIter.nextFrame();
 
         frameNo++;
     }
     IonSpew(IonSpew_BaselineBailouts, "  Done restoring frames");
     BailoutKind bailoutKind = snapIter.bailoutKind();