From 22067a94a8bfda9b444727fd464c2a5856c31d9c Mon Sep 17 00:00:00 2001 From: Shu-yu Guo Date: Wed, 12 Aug 2015 16:37:07 -0700 Subject: [PATCH] Bug 1188878 - Ensure RematerializedFrames are cleared from Debugger instances on Ion bailout failure. (r=jandem) --- js/src/jit/BaselineBailouts.cpp | 9 +++++++++ js/src/jit/JitFrames.cpp | 7 ------- js/src/vm/Stack.cpp | 15 +++++++++++++++ js/src/vm/Stack.h | 4 ++++ 4 files changed, 28 insertions(+), 7 deletions(-) diff --git a/js/src/jit/BaselineBailouts.cpp b/js/src/jit/BaselineBailouts.cpp index ff310b945470..836a54aff60e 100644 --- a/js/src/jit/BaselineBailouts.cpp +++ b/js/src/jit/BaselineBailouts.cpp @@ -4,6 +4,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "mozilla/ScopeExit.h" #include "mozilla/SizePrintfMacros.h" #include "jsprf.h" @@ -1406,6 +1407,13 @@ jit::BailoutIonToBaseline(JSContext* cx, JitActivation* activation, JitFrameIter TraceLogStopEvent(logger, TraceLogger_IonMonkey); TraceLogStartEvent(logger, TraceLogger_Baseline); + // Ion bailout can fail due to overrecursion and OOM. In such cases we + // cannot honor any further Debugger hooks on the frame, and need to + // ensure that its Debugger.Frame entry is cleaned up. + auto guardRemoveRematerializedFramesFromDebugger = mozilla::MakeScopeExit([&] { + activation->removeRematerializedFramesFromDebugger(cx, iter.fp()); + }); + // The caller of the top frame must be one of the following: // IonJS - Ion calling into Ion. // BaselineStub - Baseline calling into Ion. @@ -1591,6 +1599,7 @@ jit::BailoutIonToBaseline(JSContext* cx, JitActivation* activation, JitFrameIter info->numFrames = frameNo + 1; info->bailoutKind = bailoutKind; *bailoutInfo = info; + guardRemoveRematerializedFramesFromDebugger.release(); return BAILOUT_RETURN_OK; } diff --git a/js/src/jit/JitFrames.cpp b/js/src/jit/JitFrames.cpp index 7b5bcb75e9ad..c26e5110b3c4 100644 --- a/js/src/jit/JitFrames.cpp +++ b/js/src/jit/JitFrames.cpp @@ -466,13 +466,6 @@ HandleExceptionIon(JSContext* cx, const InlineFrameIterator& frame, ResumeFromEx uint32_t retval = ExceptionHandlerBailout(cx, frame, rfe, propagateInfo, overrecursed); if (retval == BAILOUT_RETURN_OK) return; - - // If bailout failed (e.g., due to overrecursion), clean up any - // Debugger.Frame instances here. Normally this should happen - // inside the debug epilogue, but due to bailout failure, we - // cannot honor any Debugger hooks. - if (rematFrame) - Debugger::handleUnrecoverableIonBailoutError(cx, rematFrame); } MOZ_ASSERT_IF(rematFrame, !Debugger::inFrameMaps(rematFrame)); diff --git a/js/src/vm/Stack.cpp b/js/src/vm/Stack.cpp index ab0c452a7e47..853ffaf994a9 100644 --- a/js/src/vm/Stack.cpp +++ b/js/src/vm/Stack.cpp @@ -17,6 +17,7 @@ #include "jit/JitcodeMap.h" #include "jit/JitCompartment.h" #include "js/GCAPI.h" +#include "vm/Debugger.h" #include "vm/Opcodes.h" #include "jit/JitFrameIterator-inl.h" @@ -1569,6 +1570,20 @@ jit::JitActivation::lookupRematerializedFrame(uint8_t* top, size_t inlineDepth) return nullptr; } +void +jit::JitActivation::removeRematerializedFramesFromDebugger(JSContext* cx, uint8_t* top) +{ + // Ion bailout can fail due to overrecursion and OOM. In such cases we + // cannot honor any further Debugger hooks on the frame, and need to + // ensure that its Debugger.Frame entry is cleaned up. + if (!cx->compartment()->isDebuggee() || !rematerializedFrames_) + return; + if (RematerializedFrameTable::Ptr p = rematerializedFrames_->lookup(top)) { + for (uint32_t i = 0; i < p->value().length(); i++) + Debugger::handleUnrecoverableIonBailoutError(cx, p->value()[i]); + } +} + void jit::JitActivation::markRematerializedFrames(JSTracer* trc) { diff --git a/js/src/vm/Stack.h b/js/src/vm/Stack.h index 2a3b656ca511..0997a78c2e39 100644 --- a/js/src/vm/Stack.h +++ b/js/src/vm/Stack.h @@ -1604,6 +1604,10 @@ class JitActivation : public Activation // bounds of what has been rematerialized, nullptr is returned. RematerializedFrame* lookupRematerializedFrame(uint8_t* top, size_t inlineDepth = 0); + // Remove all rematerialized frames associated with the fp top from the + // Debugger. + void removeRematerializedFramesFromDebugger(JSContext* cx, uint8_t* top); + bool hasRematerializedFrame(uint8_t* top, size_t inlineDepth = 0) { return !!lookupRematerializedFrame(top, inlineDepth); }