IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &activations, BailoutStack *bailout) : IonFrameIterator(activations), machine_(bailout->machine()) { uint8_t *sp = bailout->parentStackPointer(); uint8_t *fp = sp + bailout->frameSize(); current_ = fp; type_ = IonFrame_OptimizedJS; topFrameSize_ = current_ - sp; topIonScript_ = script()->ionScript(); if (bailout->frameClass() == FrameSizeClass::None()) { snapshotOffset_ = bailout->snapshotOffset(); return; } // Compute the snapshot offset from the bailout ID. JitActivation *activation = activations.activation()->asJit(); JSRuntime *rt = activation->compartment()->runtimeFromMainThread(); JitCode *code = rt->jitRuntime()->getBailoutTable(bailout->frameClass()); uintptr_t tableOffset = bailout->tableOffset(); uintptr_t tableStart = reinterpret_cast<uintptr_t>(code->raw()); JS_ASSERT(tableOffset >= tableStart && tableOffset < tableStart + code->instructionsSize()); JS_ASSERT((tableOffset - tableStart) % BAILOUT_TABLE_ENTRY_SIZE == 0); uint32_t bailoutId = ((tableOffset - tableStart) / BAILOUT_TABLE_ENTRY_SIZE) - 1; JS_ASSERT(bailoutId < BAILOUT_TABLE_SIZE); snapshotOffset_ = topIonScript_->bailoutToSnapshot(bailoutId); }
BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator &activations, BailoutStack *bailout) : machine_(bailout->machine()) { uint8_t *sp = bailout->parentStackPointer(); framePointer_ = sp + bailout->frameSize(); topFrameSize_ = framePointer_ - sp; JSScript *script = ScriptFromCalleeToken(((JitFrameLayout *) framePointer_)->calleeToken()); JitActivation *activation = activations.activation()->asJit(); topIonScript_ = script->ionScript(); attachOnJitActivation(activations); if (bailout->frameClass() == FrameSizeClass::None()) { snapshotOffset_ = bailout->snapshotOffset(); return; } // Compute the snapshot offset from the bailout ID. JSRuntime *rt = activation->compartment()->runtimeFromMainThread(); JitCode *code = rt->jitRuntime()->getBailoutTable(bailout->frameClass()); uintptr_t tableOffset = bailout->tableOffset(); uintptr_t tableStart = reinterpret_cast<uintptr_t>(Assembler::BailoutTableStart(code->raw())); MOZ_ASSERT(tableOffset >= tableStart && tableOffset < tableStart + code->instructionsSize()); MOZ_ASSERT((tableOffset - tableStart) % BAILOUT_TABLE_ENTRY_SIZE == 0); uint32_t bailoutId = ((tableOffset - tableStart) / BAILOUT_TABLE_ENTRY_SIZE) - 1; MOZ_ASSERT(bailoutId < BAILOUT_TABLE_SIZE); snapshotOffset_ = topIonScript_->bailoutToSnapshot(bailoutId); }
IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &activations, BailoutStack *bailout) : JitFrameIterator(activations), machine_(bailout->machine()) { uint8_t *sp = bailout->parentStackPointer(); uint8_t *fp = sp + bailout->frameSize(); kind_ = Kind_BailoutIterator; current_ = fp; type_ = JitFrame_IonJS; topFrameSize_ = current_ - sp; switch (mode_) { case SequentialExecution: topIonScript_ = script()->ionScript(); break; case ParallelExecution: topIonScript_ = script()->parallelIonScript(); break; default: MOZ_ASSUME_UNREACHABLE("No such execution mode"); } if (bailout->frameClass() == FrameSizeClass::None()) { snapshotOffset_ = bailout->snapshotOffset(); return; } // Compute the snapshot offset from the bailout ID. JitActivation *activation = activations.activation()->asJit(); JSRuntime *rt = activation->compartment()->runtimeFromMainThread(); JitCode *code = rt->jitRuntime()->getBailoutTable(bailout->frameClass()); uintptr_t tableOffset = bailout->tableOffset(); uintptr_t tableStart = reinterpret_cast<uintptr_t>(Assembler::BailoutTableStart(code->raw())); JS_ASSERT(tableOffset >= tableStart && tableOffset < tableStart + code->instructionsSize()); JS_ASSERT((tableOffset - tableStart) % BAILOUT_TABLE_ENTRY_SIZE == 0); uint32_t bailoutId = ((tableOffset - tableStart) / BAILOUT_TABLE_ENTRY_SIZE) - 1; JS_ASSERT(bailoutId < BAILOUT_TABLE_SIZE); snapshotOffset_ = topIonScript_->bailoutToSnapshot(bailoutId); }
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; }