author | Shu-yu Guo <shu@rfrn.org> |
Tue, 09 Dec 2014 23:10:38 -0800 | |
changeset 219047 | 170231ba49501eccdeed0cd5aa5c9874408857ef |
parent 219046 | 263322550d0a37858bc0aeb9561c6a4275a87da4 |
child 219048 | 0a6dbb9910a1b2d0533700a676bde4be989d3a01 |
push id | 27954 |
push user | ryanvm@gmail.com |
push date | Wed, 10 Dec 2014 21:10:24 +0000 |
treeherder | mozilla-central@0cf461e62ce5 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | jandem |
bugs | 1107525 |
milestone | 37.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
|
new file mode 100644 --- /dev/null +++ b/js/src/jit-test/tests/debug/bug1107525.js @@ -0,0 +1,9 @@ +// |jit-test| error: InternalError +enableSPSProfiling(); +var g = newGlobal(); +g.parent = this; +g.eval("new Debugger(parent).onExceptionUnwind = function () { hits++; };"); +function f() { + var x = f(); +} +f();
--- a/js/src/jit/Bailouts.cpp +++ b/js/src/jit/Bailouts.cpp @@ -176,34 +176,33 @@ BailoutFrameInfo::BailoutFrameInfo(const const OsiIndex *osiIndex = frame.osiIndex(); snapshotOffset_ = osiIndex->snapshotOffset(); } uint32_t jit::ExceptionHandlerBailout(JSContext *cx, const InlineFrameIterator &frame, ResumeFromException *rfe, const ExceptionBailoutInfo &excInfo, - bool *overrecursed) + bool *overrecursed, bool *poppedLastSPSFrameOut) { // We can be propagating debug mode exceptions without there being an // actual exception pending. For instance, when we return false from an // operation callback like a timeout handler. MOZ_ASSERT_IF(!excInfo.propagatingIonExceptionForDebugMode(), cx->isExceptionPending()); cx->mainThread().jitTop = FAKE_JIT_TOP_FOR_BAILOUT; gc::AutoSuppressGC suppress(cx); JitActivationIterator jitActivations(cx->runtime()); BailoutFrameInfo bailoutData(jitActivations, frame.frame()); JitFrameIterator iter(jitActivations); BaselineBailoutInfo *bailoutInfo = nullptr; - bool poppedLastSPSFrame = false; uint32_t retval = BailoutIonToBaseline(cx, bailoutData.activation(), iter, true, - &bailoutInfo, &excInfo, &poppedLastSPSFrame); + &bailoutInfo, &excInfo, poppedLastSPSFrameOut); if (retval == BAILOUT_RETURN_OK) { MOZ_ASSERT(bailoutInfo); // Overwrite the kind so HandleException after the bailout returns // false, jumping directly to the exception tail. if (excInfo.propagatingIonExceptionForDebugMode()) bailoutInfo->bailoutKind = Bailout_IonExceptionDebugMode;
--- a/js/src/jit/Bailouts.h +++ b/js/src/jit/Bailouts.h @@ -204,17 +204,17 @@ class ExceptionBailoutInfo } }; // Called from the exception handler to enter a catch or finally block. // Returns a BAILOUT_* error code. uint32_t ExceptionHandlerBailout(JSContext *cx, const InlineFrameIterator &frame, ResumeFromException *rfe, const ExceptionBailoutInfo &excInfo, - bool *overrecursed); + bool *overrecursed, bool *poppedLastSPSFrameOut); uint32_t FinishBailoutToBaseline(BaselineBailoutInfo *bailoutInfo); bool CheckFrequentBailouts(JSContext *cx, JSScript *script); } // namespace jit } // namespace js
--- a/js/src/jit/JitFrames.cpp +++ b/js/src/jit/JitFrames.cpp @@ -407,17 +407,17 @@ CloseLiveIterator(JSContext *cx, const I if (cx->isExceptionPending()) UnwindIteratorForException(cx, obj); else UnwindIteratorForUncatchableException(cx, obj); } static void HandleExceptionIon(JSContext *cx, const InlineFrameIterator &frame, ResumeFromException *rfe, - bool *overrecursed) + bool *overrecursed, bool *poppedLastSPSFrameOut) { RootedScript script(cx, frame.script()); jsbytecode *pc = frame.pc(); if (cx->compartment()->isDebuggee()) { // We need to bail when we are the debuggee of a Debugger with a live // onExceptionUnwind hook, or if a Debugger has observed this frame // (e.g., for onPop). @@ -439,17 +439,18 @@ HandleExceptionIon(JSContext *cx, const // frame. // // An empty exception info denotes that we're propagating an Ion // exception due to debug mode, which BailoutIonToBaseline needs to // know. This is because we might not be able to fully reconstruct up // to the stack depth at the snapshot, as we could've thrown in the // middle of a call. ExceptionBailoutInfo propagateInfo; - uint32_t retval = ExceptionHandlerBailout(cx, frame, rfe, propagateInfo, overrecursed); + uint32_t retval = ExceptionHandlerBailout(cx, frame, rfe, propagateInfo, overrecursed, + poppedLastSPSFrameOut); if (retval == BAILOUT_RETURN_OK) return; } } if (!script->hasTrynotes()) return; @@ -481,17 +482,18 @@ HandleExceptionIon(JSContext *cx, const // Ion can compile try-catch, but bailing out to catch // exceptions is slow. Reset the warm-up counter so that if we // catch many exceptions we won't Ion-compile the script. script->resetWarmUpCounter(); // Bailout at the start of the catch block. jsbytecode *catchPC = script->main() + tn->start + tn->length; ExceptionBailoutInfo excInfo(frame.frameNo(), catchPC, tn->stackDepth); - uint32_t retval = ExceptionHandlerBailout(cx, frame, rfe, excInfo, overrecursed); + uint32_t retval = ExceptionHandlerBailout(cx, frame, rfe, excInfo, overrecursed, + poppedLastSPSFrameOut); if (retval == BAILOUT_RETURN_OK) return; // Error on bailout clears pending exception. MOZ_ASSERT(!cx->isExceptionPending()); } break; @@ -737,17 +739,18 @@ HandleException(ResumeFromException *rfe // them. InlineFrameIterator frames(cx, &iter); // Invalidation state will be the same for all inlined scripts in the frame. IonScript *ionScript = nullptr; bool invalidated = iter.checkInvalidation(&ionScript); for (;;) { - HandleExceptionIon(cx, frames, rfe, &overrecursed); + bool poppedLastSPSFrame = false; + HandleExceptionIon(cx, frames, rfe, &overrecursed, &poppedLastSPSFrame); if (rfe->kind == ResumeFromException::RESUME_BAILOUT) { if (invalidated) ionScript->decrementInvalidationCount(cx->runtime()->defaultFreeOp()); return; } MOZ_ASSERT(rfe->kind == ResumeFromException::RESUME_ENTRY_FRAME); @@ -759,16 +762,21 @@ HandleException(ResumeFromException *rfe bool popSPSFrame = cx->runtime()->spsProfiler.enabled(); if (invalidated) popSPSFrame = ionScript->hasSPSInstrumentation(); // Don't pop an SPS frame for inlined frames, since they are not instrumented. if (frames.more()) popSPSFrame = false; + // Don't pop the last SPS frame if it's already been popped by + // bailing out. + if (poppedLastSPSFrame) + popSPSFrame = false; + // When profiling, each frame popped needs a notification that // the function has exited, so invoke the probe that a function // is exiting. JSScript *script = frames.script(); probes::ExitScript(cx, script, script->functionNonDelazifying(), popSPSFrame); if (!frames.more()) { TraceLogStopEvent(logger, TraceLogger::IonMonkey);