static void CloseLiveIterators(JSContext *cx, const InlineFrameIterator &frame) { AssertCanGC(); RootedScript script(cx, frame.script()); jsbytecode *pc = frame.pc(); if (!script->hasTrynotes()) return; JSTryNote *tn = script->trynotes()->vector; JSTryNote *tnEnd = tn + script->trynotes()->length; uint32 pcOffset = uint32(pc - script->main()); for (; tn != tnEnd; ++tn) { if (pcOffset < tn->start) continue; if (pcOffset >= tn->start + tn->length) continue; if (tn->kind != JSTRY_ITER) continue; JS_ASSERT(JSOp(*(script->main() + tn->start + tn->length)) == JSOP_ENDITER); JS_ASSERT(tn->stackDepth > 0); uint32 localSlot = tn->stackDepth; CloseLiveIterator(cx, frame, localSlot); } }
/* static */ bool RematerializedFrame::RematerializeInlineFrames(JSContext* cx, uint8_t* top, InlineFrameIterator& iter, MaybeReadFallback& fallback, GCVector<RematerializedFrame*>& frames) { Rooted<GCVector<RematerializedFrame*>> tempFrames(cx, GCVector<RematerializedFrame*>(cx)); if (!tempFrames.resize(iter.frameCount())) return false; while (true) { size_t frameNo = iter.frameNo(); tempFrames[frameNo].set(RematerializedFrame::New(cx, top, iter, fallback)); if (!tempFrames[frameNo]) return false; if (tempFrames[frameNo]->environmentChain()) { if (!EnsureHasEnvironmentObjects(cx, tempFrames[frameNo].get())) return false; } if (!iter.more()) break; ++iter; } frames = Move(tempFrames.get()); return true; }
/* static */ bool RematerializedFrame::RematerializeInlineFrames(JSContext *cx, uint8_t *top, InlineFrameIterator &iter, MaybeReadFallback &fallback, Vector<RematerializedFrame *> &frames) { if (!frames.resize(iter.frameCount())) return false; while (true) { size_t frameNo = iter.frameNo(); RematerializedFrame *frame = RematerializedFrame::New(cx, top, iter, fallback); if (!frame) return false; if (frame->scopeChain()) { if (!EnsureHasScopeObjects(cx, frame)) return false; } frames[frameNo] = frame; if (!iter.more()) break; ++iter; } return true; }
RematerializedFrame::RematerializedFrame(ThreadSafeContext *cx, uint8_t *top, InlineFrameIterator &iter) : prevUpToDate_(false), top_(top), frameNo_(iter.frameNo()), numActualArgs_(iter.numActualArgs()), script_(iter.script()) { CopyValueToRematerializedFrame op(slots_); iter.readFrameArgsAndLocals(cx, op, op, &scopeChain_, &returnValue_, &argsObj_, &thisValue_, ReadFrame_Actuals); }
RematerializedFrame::RematerializedFrame(JSContext *cx, uint8_t *top, unsigned numActualArgs, InlineFrameIterator &iter, MaybeReadFallback &fallback) : prevUpToDate_(false), isDebuggee_(iter.script()->isDebuggee()), top_(top), pc_(iter.pc()), frameNo_(iter.frameNo()), numActualArgs_(numActualArgs), script_(iter.script()) { CopyValueToRematerializedFrame op(slots_); iter.readFrameArgsAndLocals(cx, op, op, &scopeChain_, &hasCallObj_, &returnValue_, &argsObj_, &thisValue_, ReadFrame_Actuals, fallback); }
uint32_t jit::ExceptionHandlerBailout(JSContext* cx, const InlineFrameIterator& frame, ResumeFromException* rfe, const ExceptionBailoutInfo& excInfo, bool* overrecursed) { // 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->runtime()->jitTop = FAKE_JIT_TOP_FOR_BAILOUT; gc::AutoSuppressGC suppress(cx); JitActivationIterator jitActivations(cx->runtime()); BailoutFrameInfo bailoutData(jitActivations, frame.frame()); JitFrameIterator iter(jitActivations); CommonFrameLayout* currentFramePtr = iter.current(); BaselineBailoutInfo* bailoutInfo = nullptr; uint32_t retval = BailoutIonToBaseline(cx, bailoutData.activation(), iter, true, &bailoutInfo, &excInfo); 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; rfe->kind = ResumeFromException::RESUME_BAILOUT; rfe->target = cx->runtime()->jitRuntime()->getBailoutTail()->raw(); rfe->bailoutInfo = bailoutInfo; } else { // Bailout failed. If there was a fatal error, clear the // exception to turn this into an uncatchable error. If the // overrecursion check failed, continue popping all inline // frames and have the caller report an overrecursion error. MOZ_ASSERT(!bailoutInfo); if (!excInfo.propagatingIonExceptionForDebugMode()) cx->clearPendingException(); if (retval == BAILOUT_RETURN_OVERRECURSED) *overrecursed = true; else MOZ_ASSERT(retval == BAILOUT_RETURN_FATAL_ERROR); } // Make the frame being bailed out the top profiled frame. if (cx->runtime()->jitRuntime()->isProfilerInstrumentationEnabled(cx->runtime())) cx->runtime()->jitActivation->setLastProfilingFrame(currentFramePtr); return retval; }
static void CloseLiveIterator(JSContext *cx, const InlineFrameIterator &frame, uint32 localSlot) { SnapshotIterator si = frame.snapshotIterator(); // Skip stack slots until we reach the iterator object. uint32 base = CountArgSlots(frame.maybeCallee()) + frame.script()->nfixed; uint32 skipSlots = base + localSlot - 1; for (unsigned i = 0; i < skipSlots; i++) si.skip(); Value v = si.read(); JSObject *obj = &v.toObject(); if (cx->isExceptionPending()) UnwindIteratorForException(cx, obj); else UnwindIteratorForUncatchableException(cx, obj); }
uint32_t jit::ExceptionHandlerBailout(JSContext *cx, const InlineFrameIterator &frame, ResumeFromException *rfe, const ExceptionBailoutInfo &excInfo, bool *overrecursed) { // 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().ionTop = nullptr; JitActivationIterator jitActivations(cx->runtime()); IonBailoutIterator iter(jitActivations, frame.frame()); JitActivation *activation = jitActivations.activation()->asJit(); BaselineBailoutInfo *bailoutInfo = nullptr; uint32_t retval = BailoutIonToBaseline(cx, activation, iter, true, &bailoutInfo, &excInfo); 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; rfe->kind = ResumeFromException::RESUME_BAILOUT; rfe->target = cx->runtime()->jitRuntime()->getBailoutTail()->raw(); rfe->bailoutInfo = bailoutInfo; } else { // Bailout failed. If there was a fatal error, clear the // exception to turn this into an uncatchable error. If the // overrecursion check failed, continue popping all inline // frames and have the caller report an overrecursion error. MOZ_ASSERT(!bailoutInfo); if (!excInfo.propagatingIonExceptionForDebugMode()) cx->clearPendingException(); if (retval == BAILOUT_RETURN_OVERRECURSED) *overrecursed = true; else MOZ_ASSERT(retval == BAILOUT_RETURN_FATAL_ERROR); } return retval; }
RematerializedFrame::RematerializedFrame(JSContext* cx, uint8_t* top, unsigned numActualArgs, InlineFrameIterator& iter, MaybeReadFallback& fallback) : prevUpToDate_(false), isDebuggee_(iter.script()->isDebuggee()), isConstructing_(iter.isConstructing()), hasCachedSavedFrame_(false), top_(top), pc_(iter.pc()), frameNo_(iter.frameNo()), numActualArgs_(numActualArgs), script_(iter.script()) { if (iter.isFunctionFrame()) callee_ = iter.callee(fallback); else callee_ = nullptr; CopyValueToRematerializedFrame op(slots_); iter.readFrameArgsAndLocals(cx, op, op, &scopeChain_, &hasCallObj_, &returnValue_, &argsObj_, &thisArgument_, ReadFrame_Actuals, fallback); }
uint32_t ion::ExceptionHandlerBailout(JSContext *cx, const InlineFrameIterator &frame, const ExceptionBailoutInfo &excInfo, BaselineBailoutInfo **bailoutInfo) { JS_ASSERT(cx->isExceptionPending()); cx->mainThread().ionTop = NULL; JitActivationIterator jitActivations(cx->runtime()); IonBailoutIterator iter(jitActivations, frame.frame()); JitActivation *activation = jitActivations.activation()->asJit(); *bailoutInfo = NULL; uint32_t retval = BailoutIonToBaseline(cx, activation, iter, true, bailoutInfo, &excInfo); JS_ASSERT(retval == BAILOUT_RETURN_OK || retval == BAILOUT_RETURN_FATAL_ERROR || retval == BAILOUT_RETURN_OVERRECURSED); JS_ASSERT((retval == BAILOUT_RETURN_OK) == (*bailoutInfo != NULL)); return retval; }
uint32_t jit::ExceptionHandlerBailout(JSContext* cx, const InlineFrameIterator& frame, ResumeFromException* rfe, const ExceptionBailoutInfo& excInfo, bool* overrecursed) { // 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()); JitActivation* act = cx->activation()->asJit(); uint8_t* prevExitFP = act->exitFP(); auto restoreExitFP = mozilla::MakeScopeExit([&]() { act->setExitFP(prevExitFP); }); act->setExitFP(FAKE_EXITFP_FOR_BAILOUT); gc::AutoSuppressGC suppress(cx); JitActivationIterator jitActivations(cx); BailoutFrameInfo bailoutData(jitActivations, frame.frame()); JitFrameIterator iter(jitActivations); CommonFrameLayout* currentFramePtr = iter.current(); BaselineBailoutInfo* bailoutInfo = nullptr; uint32_t retval; { // Currently we do not tolerate OOM here so as not to complicate the // exception handling code further. AutoEnterOOMUnsafeRegion oomUnsafe; retval = BailoutIonToBaseline(cx, bailoutData.activation(), iter, true, &bailoutInfo, &excInfo); if (retval == BAILOUT_RETURN_FATAL_ERROR && cx->isThrowingOutOfMemory()) oomUnsafe.crash("ExceptionHandlerBailout"); } 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; rfe->kind = ResumeFromException::RESUME_BAILOUT; rfe->target = cx->runtime()->jitRuntime()->getBailoutTail()->raw(); rfe->bailoutInfo = bailoutInfo; } else { // Bailout failed. If the overrecursion check failed, clear the // exception to turn this into an uncatchable error, continue popping // all inline frames and have the caller report the error. MOZ_ASSERT(!bailoutInfo); if (retval == BAILOUT_RETURN_OVERRECURSED) { *overrecursed = true; if (!excInfo.propagatingIonExceptionForDebugMode()) cx->clearPendingException(); } else { MOZ_ASSERT(retval == BAILOUT_RETURN_FATAL_ERROR); // Crash for now so as not to complicate the exception handling code // further. MOZ_CRASH(); } } // Make the frame being bailed out the top profiled frame. if (cx->runtime()->jitRuntime()->isProfilerInstrumentationEnabled(cx->runtime())) cx->jitActivation->setLastProfilingFrame(currentFramePtr); return retval; }