diff --git a/js/src/jit/BaselineBailouts.cpp b/js/src/jit/BaselineBailouts.cpp index 1f3e4e05d034..a30647a224ad 100644 --- a/js/src/jit/BaselineBailouts.cpp +++ b/js/src/jit/BaselineBailouts.cpp @@ -129,15 +129,9 @@ struct BaselineStackBuilder { header_->incomingStack = reinterpret_cast(frame_); header_->copyStackTop = buffer_ + bufferTotal_; header_->copyStackBottom = header_->copyStackTop; - header_->setR0 = 0; - header_->valueR0 = UndefinedValue(); - header_->setR1 = 0; - header_->valueR1 = UndefinedValue(); header_->resumeFramePtr = nullptr; header_->resumeAddr = nullptr; - header_->resumePC = nullptr; header_->monitorPC = nullptr; - header_->monitorValue = UndefinedValue(); header_->tryPC = nullptr; header_->faultPC = nullptr; header_->numFrames = 0; @@ -287,36 +281,13 @@ struct BaselineStackBuilder { return result; } - void popValueInto(PCMappingSlotInfo::SlotLocation loc) { - MOZ_ASSERT(PCMappingSlotInfo::ValidSlotLocation(loc)); - switch (loc) { - case PCMappingSlotInfo::SlotInR0: - header_->setR0 = 1; - header_->valueR0 = popValue(); - break; - case PCMappingSlotInfo::SlotInR1: - header_->setR1 = 1; - header_->valueR1 = popValue(); - break; - default: - MOZ_ASSERT(loc == PCMappingSlotInfo::SlotIgnore); - popValue(); - break; - } - } - void setResumeFramePtr(void* resumeFramePtr) { header_->resumeFramePtr = resumeFramePtr; } void setResumeAddr(void* resumeAddr) { header_->resumeAddr = resumeAddr; } - void setResumePC(jsbytecode* pc) { header_->resumePC = pc; } - - void setMonitorPCAndValue(jsbytecode* pc, Value val) { - header_->monitorPC = pc; - header_->monitorValue = val; - } + void setMonitorPC(jsbytecode* pc) { header_->monitorPC = pc; } template BufferPointer pointerAtStackOffset(size_t offset) { @@ -694,7 +665,7 @@ static bool InitFromBailout(JSContext* cx, size_t frameNo, HandleFunction fun, BufferPointer blFrame = builder.pointerAtStackOffset(0); - uint32_t flags = 0; + uint32_t flags = BaselineFrame::RUNNING_IN_INTERPRETER; // If we are bailing to a script whose execution is observed, mark the // baseline frame as a debuggee frame. This is to cover the case where we @@ -1053,8 +1024,7 @@ static bool InitFromBailout(JSContext* cx, size_t frameNo, HandleFunction fun, MOZ_ASSERT(blFrame->numValueSlots() <= script->nslots()); // If we are resuming at a LOOPENTRY op, resume at the next op to avoid - // a bailout -> enter Ion -> bailout loop with --ion-eager. See also - // ThunkToInterpreter. + // a bailout -> enter Ion -> bailout loop with --ion-eager. // // The algorithm below is the "tortoise and the hare" algorithm. See bug // 994444 for more explanation. @@ -1077,7 +1047,6 @@ static bool InitFromBailout(JSContext* cx, size_t frameNo, HandleFunction fun, } const uint32_t pcOff = script->pcToOffset(pc); - BaselineScript* baselineScript = script->baselineScript(); JitScript* jitScript = script->jitScript(); #ifdef DEBUG @@ -1128,6 +1097,9 @@ static bool InitFromBailout(JSContext* cx, size_t frameNo, HandleFunction fun, BailoutKindString(bailoutKind)); #endif + const BaselineInterpreter& baselineInterp = + cx->runtime()->jitRuntime()->baselineInterpreter(); + // If this was the last inline frame, or we are bailing out to a catch or // finally block in this frame, then unpacking is almost done. if (!iter.moreFrames() || catchingException) { @@ -1141,76 +1113,33 @@ static bool InitFromBailout(JSContext* cx, size_t frameNo, HandleFunction fun, // value directly. if ((CodeSpec[op].format & JOF_TYPESET) && !propagatingIonExceptionForDebugMode) { - builder.setMonitorPCAndValue(pc, blFrame->topStackValue()); + builder.setMonitorPC(pc); } pc = GetNextPc(pc); } - builder.setResumePC(pc); builder.setResumeFramePtr(prevFramePtr); - // If needed, initialize BaselineBailoutInfo's valueR0 and/or valueR1 with - // the top stack values. - // - // Note that we use the 'maybe' variant of nativeCodeForPC because - // of exception propagation for debug mode. See note below. - PCMappingSlotInfo slotInfo; - uint8_t* nativeCodeForPC; - - if (propagatingIonExceptionForDebugMode) { + uint8_t* resumeAddr; + if (isPrologueBailout) { + JitSpew(JitSpew_BaselineBailouts, " Resuming into prologue."); + MOZ_ASSERT(pc == script->code()); + blFrame->setInterpreterFieldsForPrologueBailout(script); + resumeAddr = baselineInterp.bailoutPrologueEntryAddr(); + } else if (propagatingIonExceptionForDebugMode) { // When propagating an exception for debug mode, set the // resume pc to the throwing pc, so that Debugger hooks report // the correct pc offset of the throwing op instead of its - // successor (this pc will be used as the BaselineFrame's - // override pc). + // successor. jsbytecode* throwPC = script->offsetToPC(iter.pcOffset()); - builder.setResumePC(throwPC); - - // Note that we never resume at this pc, it is set for the sake - // of frame iterators giving the correct answer. - PCMappingSlotInfo unused; - nativeCodeForPC = - baselineScript->nativeCodeForPC(script, throwPC, &unused); + blFrame->setInterpreterFields(script, throwPC); + resumeAddr = baselineInterp.interpretOpAddr().value; } else { - nativeCodeForPC = baselineScript->nativeCodeForPC(script, pc, &slotInfo); + blFrame->setInterpreterFields(script, pc); + resumeAddr = baselineInterp.interpretOpAddr().value; } - MOZ_ASSERT(nativeCodeForPC); - - unsigned numUnsynced = slotInfo.numUnsynced(); - - MOZ_ASSERT(numUnsynced <= 2); - PCMappingSlotInfo::SlotLocation loc1, loc2; - if (numUnsynced > 0) { - loc1 = slotInfo.topSlotLocation(); - JitSpew(JitSpew_BaselineBailouts, - " Popping top stack value into %d.", (int)loc1); - builder.popValueInto(loc1); - } - if (numUnsynced > 1) { - loc2 = slotInfo.nextSlotLocation(); - JitSpew(JitSpew_BaselineBailouts, - " Popping next stack value into %d.", (int)loc2); - MOZ_ASSERT_IF(loc1 != PCMappingSlotInfo::SlotIgnore, loc1 != loc2); - builder.popValueInto(loc2); - } - - // Need to adjust the frameSize for the frame to match the values popped - // into registers. - frameSize -= sizeof(Value) * numUnsynced; - blFrame->setFrameSize(frameSize); - JitSpew(JitSpew_BaselineBailouts, " Adjusted framesize -= %d: %d", - int(sizeof(Value) * numUnsynced), int(frameSize)); - - uint8_t* opReturnAddr; - if (isPrologueBailout) { - MOZ_ASSERT(numUnsynced == 0); - opReturnAddr = baselineScript->bailoutPrologueEntryAddr(); - JitSpew(JitSpew_BaselineBailouts, " Resuming into prologue."); - } else { - opReturnAddr = nativeCodeForPC; - } - builder.setResumeAddr(opReturnAddr); - JitSpew(JitSpew_BaselineBailouts, " Set resumeAddr=%p", opReturnAddr); + builder.setResumeAddr(resumeAddr); + JitSpew(JitSpew_BaselineBailouts, " Set resumeAddr=%p", resumeAddr); if (cx->runtime()->geckoProfiler().enabled()) { // Register bailout with profiler. @@ -1234,6 +1163,10 @@ static bool InitFromBailout(JSContext* cx, size_t frameNo, HandleFunction fun, return true; } + // This is an outer frame for an inlined getter/setter/call. + + blFrame->setInterpreterFields(script, pc); + // Write out descriptor of BaselineJS frame. size_t baselineFrameDescr = MakeFrameDescriptor( (uint32_t)builder.framePushed(), FrameType::BaselineJS, @@ -1247,10 +1180,8 @@ static bool InitFromBailout(JSContext* cx, size_t frameNo, HandleFunction fun, ICEntry& icEntry = jitScript->icEntryFromPCOffset(pcOff); MOZ_ASSERT(IsInlinableFallback(icEntry.fallbackStub())); - RetAddrEntry& retAddrEntry = - baselineScript->retAddrEntryFromPCOffset(pcOff, RetAddrEntry::Kind::IC); - if (!builder.writePtr(baselineScript->returnAddressForEntry(retAddrEntry), - "ReturnAddr")) { + uint8_t* retAddr = baselineInterp.retAddrForIC(JSOp(*pc)); + if (!builder.writePtr(retAddr, "ReturnAddr")) { return false; } @@ -1906,12 +1837,7 @@ bool jit::FinishBailoutToBaseline(BaselineBailoutInfo* bailoutInfo) { JitSpew(JitSpew_BaselineBailouts, " Done restoring frames"); - // The current native code pc may not have a corresponding ICEntry, so we - // store the bytecode pc in the frame for frame iterators. This pc is - // cleared at the end of this function. If we return false, we don't clear - // it: the exception handler also needs it and will clear it for us. BaselineFrame* topFrame = GetTopBaselineFrame(cx); - topFrame->setOverridePc(bailoutInfo->resumePC); jsbytecode* faultPC = bailoutInfo->faultPC; jsbytecode* tryPC = bailoutInfo->tryPC; @@ -1923,7 +1849,6 @@ bool jit::FinishBailoutToBaseline(BaselineBailoutInfo* bailoutInfo) { uint8_t* incomingStack = bailoutInfo->incomingStack; jsbytecode* monitorPC = bailoutInfo->monitorPC; - RootedValue monitorValue(cx, bailoutInfo->monitorValue); // We have to get rid of the rematerialized frame, whether it is // restored or unwound. @@ -1956,7 +1881,7 @@ bool jit::FinishBailoutToBaseline(BaselineBailoutInfo* bailoutInfo) { // Monitor the top stack value if we are resuming after a JOF_TYPESET op. if (monitorPC) { MOZ_ASSERT(CodeSpec[*monitorPC].format & JOF_TYPESET); - MOZ_ASSERT(GetNextPc(monitorPC) == topFrame->overridePc()); + MOZ_ASSERT(GetNextPc(monitorPC) == topFrame->interpreterPC()); RootedScript script(cx, topFrame->script()); uint32_t monitorOffset = script->pcToOffset(monitorPC); @@ -1968,8 +1893,8 @@ bool jit::FinishBailoutToBaseline(BaselineBailoutInfo* bailoutInfo) { // particular script/pc location. if (fallbackStub->isMonitoredFallback()) { ICMonitoredFallbackStub* stub = fallbackStub->toMonitoredFallbackStub(); - if (!TypeMonitorResult(cx, stub, topFrame, script, monitorPC, - monitorValue)) { + RootedValue val(cx, topFrame->topStackValue()); + if (!TypeMonitorResult(cx, stub, topFrame, script, monitorPC, val)) { return false; } } @@ -2164,8 +2089,5 @@ bool jit::FinishBailoutToBaseline(BaselineBailoutInfo* bailoutInfo) { } CheckFrequentBailouts(cx, outerScript, bailoutKind); - - // We're returning to JIT code, so we should clear the override pc. - topFrame->clearOverridePc(); return true; } diff --git a/js/src/jit/BaselineCodeGen.cpp b/js/src/jit/BaselineCodeGen.cpp index 02d1f5540425..642289fdb867 100644 --- a/js/src/jit/BaselineCodeGen.cpp +++ b/js/src/jit/BaselineCodeGen.cpp @@ -292,8 +292,7 @@ MethodStatus BaselineCompiler::compile() { } UniquePtr baselineScript( - BaselineScript::New(script, bailoutPrologueOffset_.offset(), - warmUpCheckPrologueOffset_.offset(), + BaselineScript::New(script, warmUpCheckPrologueOffset_.offset(), profilerEnterFrameToggleOffset_.offset(), profilerExitFrameToggleOffset_.offset(), handler.retAddrEntries().length(), @@ -6808,8 +6807,8 @@ bool BaselineCodeGen::emitPrologue() { } #endif - // Record prologue offset for Ion bailouts. - bailoutPrologueOffset_ = CodeOffset(masm.currentOffset()); + // Ion prologue bailouts will enter here in the Baseline Interpreter. + masm.bind(&bailoutPrologue_); frame.assertSyncedStack(); @@ -7089,6 +7088,11 @@ bool BaselineInterpreterGenerator::emitInterpreterLoop() { restoreInterpreterPCReg(); masm.jump(&interpretOpAfterDebugTrap); + // External entry point for Ion prologue bailouts. + bailoutPrologueOffset_ = CodeOffset(masm.currentOffset()); + restoreInterpreterPCReg(); + masm.jump(&bailoutPrologue_); + // Emit code for JSOP_UNUSED* ops. Label invalidOp; masm.bind(&invalidOp); @@ -7220,6 +7224,7 @@ bool BaselineInterpreterGenerator::generate(BaselineInterpreter& interpreter) { interpreter.init( code, interpretOpOffset_, interpretOpNoDebugTrapOffset_, + bailoutPrologueOffset_.offset(), profilerEnterFrameToggleOffset_.offset(), profilerExitFrameToggleOffset_.offset(), std::move(handler.debugInstrumentationOffsets()), diff --git a/js/src/jit/BaselineCodeGen.h b/js/src/jit/BaselineCodeGen.h index ba0f5face1f1..c87e56085639 100644 --- a/js/src/jit/BaselineCodeGen.h +++ b/js/src/jit/BaselineCodeGen.h @@ -285,6 +285,9 @@ class BaselineCodeGen { NonAssertingLabel postBarrierSlot_; + // Prologue code where we resume for Ion prologue bailouts. + NonAssertingLabel bailoutPrologue_; + CodeOffset profilerEnterFrameToggleOffset_; CodeOffset profilerExitFrameToggleOffset_; diff --git a/js/src/jit/BaselineJIT.cpp b/js/src/jit/BaselineJIT.cpp index ddc3d89d2090..f0164c8ad019 100644 --- a/js/src/jit/BaselineJIT.cpp +++ b/js/src/jit/BaselineJIT.cpp @@ -440,11 +440,10 @@ bool jit::BaselineCompileFromBaselineInterpreter(JSContext* cx, } BaselineScript* BaselineScript::New( - JSScript* jsscript, uint32_t bailoutPrologueOffset, - uint32_t warmUpCheckPrologueOffset, uint32_t profilerEnterToggleOffset, - uint32_t profilerExitToggleOffset, size_t retAddrEntries, - size_t pcMappingIndexEntries, size_t pcMappingSize, size_t resumeEntries, - size_t traceLoggerToggleOffsetEntries) { + JSScript* jsscript, uint32_t warmUpCheckPrologueOffset, + uint32_t profilerEnterToggleOffset, uint32_t profilerExitToggleOffset, + size_t retAddrEntries, size_t pcMappingIndexEntries, size_t pcMappingSize, + size_t resumeEntries, size_t traceLoggerToggleOffsetEntries) { static const unsigned DataAlignment = sizeof(uintptr_t); size_t retAddrEntriesSize = retAddrEntries * sizeof(RetAddrEntry); @@ -472,8 +471,8 @@ BaselineScript* BaselineScript::New( return nullptr; } new (script) - BaselineScript(bailoutPrologueOffset, warmUpCheckPrologueOffset, - profilerEnterToggleOffset, profilerExitToggleOffset); + BaselineScript(warmUpCheckPrologueOffset, profilerEnterToggleOffset, + profilerExitToggleOffset); size_t offsetCursor = sizeof(BaselineScript); MOZ_ASSERT(offsetCursor == AlignBytes(sizeof(BaselineScript), DataAlignment)); @@ -1115,6 +1114,7 @@ void jit::ToggleBaselineTraceLoggerEngine(JSRuntime* runtime, bool enable) { void BaselineInterpreter::init(JitCode* code, uint32_t interpretOpOffset, uint32_t interpretOpNoDebugTrapOffset, + uint32_t bailoutPrologueOffset, uint32_t profilerEnterToggleOffset, uint32_t profilerExitToggleOffset, CodeOffsetVector&& debugInstrumentationOffsets, @@ -1125,6 +1125,7 @@ void BaselineInterpreter::init(JitCode* code, uint32_t interpretOpOffset, code_ = code; interpretOpOffset_ = interpretOpOffset; interpretOpNoDebugTrapOffset_ = interpretOpNoDebugTrapOffset; + bailoutPrologueOffset_ = bailoutPrologueOffset; profilerEnterToggleOffset_ = profilerEnterToggleOffset; profilerExitToggleOffset_ = profilerExitToggleOffset; debugInstrumentationOffsets_ = std::move(debugInstrumentationOffsets); diff --git a/js/src/jit/BaselineJIT.h b/js/src/jit/BaselineJIT.h index 458f79de3b10..38edd161e8fe 100644 --- a/js/src/jit/BaselineJIT.h +++ b/js/src/jit/BaselineJIT.h @@ -201,10 +201,6 @@ struct BaselineScript final { // Code pointer containing the actual method. HeapPtr method_ = nullptr; - // Early Ion bailouts will enter at this address. This is after frame - // construction and before environment chain is initialized. - uint32_t bailoutPrologueOffset_; - // Baseline Interpreter can enter Baseline Compiler code at this address. This // is right after the warm-up counter check in the prologue. uint32_t warmUpCheckPrologueOffset_; @@ -264,24 +260,19 @@ struct BaselineScript final { // Use BaselineScript::New to create new instances. It will properly // allocate trailing objects. - BaselineScript(uint32_t bailoutPrologueOffset, - uint32_t warmUpCheckPrologueOffset, + BaselineScript(uint32_t warmUpCheckPrologueOffset, uint32_t profilerEnterToggleOffset, uint32_t profilerExitToggleOffset) - : bailoutPrologueOffset_(bailoutPrologueOffset), - warmUpCheckPrologueOffset_(warmUpCheckPrologueOffset), + : warmUpCheckPrologueOffset_(warmUpCheckPrologueOffset), profilerEnterToggleOffset_(profilerEnterToggleOffset), profilerExitToggleOffset_(profilerExitToggleOffset) {} public: - static BaselineScript* New(JSScript* jsscript, uint32_t bailoutPrologueOffset, - uint32_t warmUpCheckPrologueOffset, - uint32_t profilerEnterToggleOffset, - uint32_t profilerExitToggleOffset, - size_t retAddrEntries, - size_t pcMappingIndexEntries, size_t pcMappingSize, - size_t resumeEntries, - size_t traceLoggerToggleOffsetEntries); + static BaselineScript* New( + JSScript* jsscript, uint32_t warmUpCheckPrologueOffset, + uint32_t profilerEnterToggleOffset, uint32_t profilerExitToggleOffset, + size_t retAddrEntries, size_t pcMappingIndexEntries, size_t pcMappingSize, + size_t resumeEntries, size_t traceLoggerToggleOffsetEntries); static void Trace(JSTracer* trc, BaselineScript* script); static void Destroy(FreeOp* fop, BaselineScript* script); @@ -300,9 +291,6 @@ struct BaselineScript final { return flags_ & HAS_DEBUG_INSTRUMENTATION; } - uint8_t* bailoutPrologueEntryAddr() const { - return method_->raw() + bailoutPrologueOffset_; - } uint8_t* warmUpCheckPrologueAddr() const { return method_->raw() + warmUpCheckPrologueOffset_; } @@ -478,27 +466,15 @@ struct BaselineBailoutInfo { uint8_t* copyStackTop; uint8_t* copyStackBottom; - // Fields to store the top-of-stack baseline values that are held - // in registers. The setR0 and setR1 fields are flags indicating - // whether each one is initialized. - uint32_t setR0; - Value valueR0; - uint32_t setR1; - Value valueR1; - // The value of the frame pointer register on resume. void* resumeFramePtr; // The native code address to resume into. void* resumeAddr; - // The bytecode pc where we will resume. - jsbytecode* resumePC; - // If non-null, we have to type monitor the top stack value for this pc (we // resume right after it). jsbytecode* monitorPC; - Value monitorValue; // The bytecode pc of try block and fault block. jsbytecode* tryPC; @@ -552,6 +528,10 @@ class BaselineInterpreter { // Like interpretOpOffset_ but skips the debug trap for the current op. uint32_t interpretOpNoDebugTrapOffset_ = 0; + // Early Ion bailouts will enter at this address. This is after frame + // construction and environment initialization. + uint32_t bailoutPrologueOffset_ = 0; + // The offsets for the toggledJump instructions for profiler instrumentation. uint32_t profilerEnterToggleOffset_ = 0; uint32_t profilerExitToggleOffset_ = 0; @@ -587,7 +567,7 @@ class BaselineInterpreter { void init(JitCode* code, uint32_t interpretOpOffset, uint32_t interpretOpNoDebugTrapOffset, - uint32_t profilerEnterToggleOffset, + uint32_t bailoutPrologueOffset, uint32_t profilerEnterToggleOffset, uint32_t profilerExitToggleOffset, CodeOffsetVector&& debugInstrumentationOffsets, CodeOffsetVector&& debugTrapOffsets, @@ -606,6 +586,9 @@ class BaselineInterpreter { uint8_t* retAddrForDebugAfterYieldCallVM() const { return codeAtOffset(callVMOffsets_.debugAfterYieldOffset); } + uint8_t* bailoutPrologueEntryAddr() const { + return codeAtOffset(bailoutPrologueOffset_); + } uint8_t* retAddrForIC(JSOp op) const; diff --git a/js/src/jit/MacroAssembler.cpp b/js/src/jit/MacroAssembler.cpp index add54c0e46f4..4c17d5487e17 100644 --- a/js/src/jit/MacroAssembler.cpp +++ b/js/src/jit/MacroAssembler.cpp @@ -1571,8 +1571,6 @@ void MacroAssembler::generateBailoutTail(Register scratch, enterFakeExitFrame(scratch, scratch, ExitFrameType::Bare); // Save needed values onto stack temporarily. - pushValue(Address(bailoutInfo, offsetof(BaselineBailoutInfo, valueR0))); - pushValue(Address(bailoutInfo, offsetof(BaselineBailoutInfo, valueR1))); push(Address(bailoutInfo, offsetof(BaselineBailoutInfo, resumeFramePtr))); push(Address(bailoutInfo, offsetof(BaselineBailoutInfo, resumeAddr))); @@ -1585,15 +1583,11 @@ void MacroAssembler::generateBailoutTail(Register scratch, // Restore values where they need to be and resume execution. AllocatableGeneralRegisterSet enterRegs(GeneralRegisterSet::All()); - enterRegs.take(R0); - enterRegs.take(R1); enterRegs.take(BaselineFrameReg); Register jitcodeReg = enterRegs.takeAny(); pop(jitcodeReg); pop(BaselineFrameReg); - popValue(R1); - popValue(R0); // Discard exit frame. addToStackPtr(Imm32(ExitFrameLayout::SizeWithFooter()));