GCAwareJITStubRoutineWithExceptionHandler::GCAwareJITStubRoutineWithExceptionHandler( const MacroAssemblerCodeRef& code, VM& vm, const JSCell* owner, const Vector<JSCell*>& cells, CodeBlock* codeBlockForExceptionHandlers, CallSiteIndex exceptionHandlerCallSiteIndex) : MarkingGCAwareJITStubRoutine(code, vm, owner, cells) , m_codeBlockWithExceptionHandler(codeBlockForExceptionHandlers) , m_exceptionHandlerCallSiteIndex(exceptionHandlerCallSiteIndex) { RELEASE_ASSERT(m_codeBlockWithExceptionHandler); ASSERT(!!m_codeBlockWithExceptionHandler->handlerForIndex(exceptionHandlerCallSiteIndex.bits())); }
RegisterSet JITCode::liveRegistersToPreserveAtExceptionHandlingCallSite(CodeBlock*, CallSiteIndex callSiteIndex) { for (OSRExit& exit : osrExit) { if (exit.m_exceptionHandlerCallSiteIndex.bits() == callSiteIndex.bits()) { RELEASE_ASSERT(exit.m_isExceptionHandler); return stackmaps.records[exit.m_stackmapRecordIndex].usedRegisterSet(); } } return RegisterSet(); }
void PatchpointExceptionHandle::scheduleExitCreationForUnwind( const B3::StackmapGenerationParams& params, CallSiteIndex callSiteIndex) { if (!m_descriptor) return; RefPtr<OSRExitHandle> handle = createHandle(GenericUnwind, params); handle->exit.m_exceptionHandlerCallSiteIndex = callSiteIndex; HandlerInfo handler = m_handler; params.addLatePath( [handle, handler, callSiteIndex] (CCallHelpers& jit) { CodeBlock* codeBlock = jit.codeBlock(); jit.addLinkTask( [=] (LinkBuffer& linkBuffer) { HandlerInfo newHandler = handler; newHandler.start = callSiteIndex.bits(); newHandler.end = callSiteIndex.bits() + 1; newHandler.nativeCode = linkBuffer.locationOf(handle->label); codeBlock->appendExceptionHandler(newHandler); }); }); }
void StackVisitor::Frame::dump(PrintStream& out, Indenter indent, WTF::Function<void(PrintStream&)> prefix) const { if (!this->callFrame()) { out.print(indent, "frame 0x0\n"); return; } CodeBlock* codeBlock = this->codeBlock(); out.print(indent); prefix(out); out.print("frame ", RawPointer(this->callFrame()), " {\n"); { indent++; CallFrame* callFrame = m_callFrame; CallFrame* callerFrame = this->callerFrame(); const void* returnPC = callFrame->hasReturnPC() ? callFrame->returnPC().value() : nullptr; out.print(indent, "name: ", functionName(), "\n"); out.print(indent, "sourceURL: ", sourceURL(), "\n"); bool isInlined = false; #if ENABLE(DFG_JIT) isInlined = isInlinedFrame(); out.print(indent, "isInlinedFrame: ", isInlinedFrame(), "\n"); if (isInlinedFrame()) out.print(indent, "InlineCallFrame: ", RawPointer(m_inlineCallFrame), "\n"); #endif out.print(indent, "callee: ", RawPointer(callee().rawPtr()), "\n"); out.print(indent, "returnPC: ", RawPointer(returnPC), "\n"); out.print(indent, "callerFrame: ", RawPointer(callerFrame), "\n"); uintptr_t locationRawBits = callFrame->callSiteAsRawBits(); out.print(indent, "rawLocationBits: ", locationRawBits, " ", RawPointer(reinterpret_cast<void*>(locationRawBits)), "\n"); out.print(indent, "codeBlock: ", RawPointer(codeBlock)); if (codeBlock) out.print(" ", *codeBlock); out.print("\n"); if (codeBlock && !isInlined) { indent++; if (callFrame->callSiteBitsAreBytecodeOffset()) { unsigned bytecodeOffset = callFrame->bytecodeOffset(); out.print(indent, "bytecodeOffset: ", bytecodeOffset, " of ", codeBlock->instructions().size(), "\n"); #if ENABLE(DFG_JIT) } else { out.print(indent, "hasCodeOrigins: ", codeBlock->hasCodeOrigins(), "\n"); if (codeBlock->hasCodeOrigins()) { CallSiteIndex callSiteIndex = callFrame->callSiteIndex(); out.print(indent, "callSiteIndex: ", callSiteIndex.bits(), " of ", codeBlock->codeOrigins().size(), "\n"); JITCode::JITType jitType = codeBlock->jitType(); if (jitType != JITCode::FTLJIT) { JITCode* jitCode = codeBlock->jitCode().get(); out.print(indent, "jitCode: ", RawPointer(jitCode), " start ", RawPointer(jitCode->start()), " end ", RawPointer(jitCode->end()), "\n"); } } #endif } unsigned line = 0; unsigned column = 0; computeLineAndColumn(line, column); out.print(indent, "line: ", line, "\n"); out.print(indent, "column: ", column, "\n"); indent--; } out.print(indent, "EntryFrame: ", RawPointer(m_entryFrame), "\n"); indent--; } out.print(indent, "}\n"); }
void StackVisitor::Frame::print(int indent) { if (!this->callFrame()) { log(indent, "frame 0x0\n"); return; } CodeBlock* codeBlock = this->codeBlock(); logF(indent, "frame %p {\n", this->callFrame()); { indent++; CallFrame* callFrame = m_callFrame; CallFrame* callerFrame = this->callerFrame(); void* returnPC = callFrame->hasReturnPC() ? callFrame->returnPC().value() : nullptr; log(indent, "name: ", functionName(), "\n"); log(indent, "sourceURL: ", sourceURL(), "\n"); bool isInlined = false; #if ENABLE(DFG_JIT) isInlined = isInlinedFrame(); log(indent, "isInlinedFrame: ", isInlinedFrame(), "\n"); if (isInlinedFrame()) logF(indent, "InlineCallFrame: %p\n", m_inlineCallFrame); #endif logF(indent, "callee: %p\n", callee()); logF(indent, "returnPC: %p\n", returnPC); logF(indent, "callerFrame: %p\n", callerFrame); unsigned locationRawBits = callFrame->callSiteAsRawBits(); logF(indent, "rawLocationBits: %u 0x%x\n", locationRawBits, locationRawBits); logF(indent, "codeBlock: %p ", codeBlock); if (codeBlock) dataLog(*codeBlock); dataLog("\n"); if (codeBlock && !isInlined) { indent++; if (callFrame->callSiteBitsAreBytecodeOffset()) { unsigned bytecodeOffset = callFrame->bytecodeOffset(); log(indent, "bytecodeOffset: ", bytecodeOffset, " of ", codeBlock->instructions().size(), "\n"); #if ENABLE(DFG_JIT) } else { log(indent, "hasCodeOrigins: ", codeBlock->hasCodeOrigins(), "\n"); if (codeBlock->hasCodeOrigins()) { CallSiteIndex callSiteIndex = callFrame->callSiteIndex(); log(indent, "callSiteIndex: ", callSiteIndex.bits(), " of ", codeBlock->codeOrigins().size(), "\n"); JITCode::JITType jitType = codeBlock->jitType(); if (jitType != JITCode::FTLJIT) { JITCode* jitCode = codeBlock->jitCode().get(); logF(indent, "jitCode: %p start %p end %p\n", jitCode, jitCode->start(), jitCode->end()); } } #endif } unsigned line = 0; unsigned column = 0; computeLineAndColumn(line, column); log(indent, "line: ", line, "\n"); log(indent, "column: ", column, "\n"); indent--; } indent--; } log(indent, "}\n"); }
void JITCompiler::link(LinkBuffer& linkBuffer) { // Link the code, populate data in CodeBlock data structures. m_jitCode->common.frameRegisterCount = m_graph.frameRegisterCount(); m_jitCode->common.requiredRegisterCountForExit = m_graph.requiredRegisterCountForExit(); if (!m_graph.m_plan.inlineCallFrames->isEmpty()) m_jitCode->common.inlineCallFrames = m_graph.m_plan.inlineCallFrames; #if USE(JSVALUE32_64) m_jitCode->common.doubleConstants = WTFMove(m_graph.m_doubleConstants); #endif m_graph.registerFrozenValues(); BitVector usedJumpTables; for (Bag<SwitchData>::iterator iter = m_graph.m_switchData.begin(); !!iter; ++iter) { SwitchData& data = **iter; if (!data.didUseJumpTable) continue; if (data.kind == SwitchString) continue; RELEASE_ASSERT(data.kind == SwitchImm || data.kind == SwitchChar); usedJumpTables.set(data.switchTableIndex); SimpleJumpTable& table = m_codeBlock->switchJumpTable(data.switchTableIndex); table.ctiDefault = linkBuffer.locationOf(m_blockHeads[data.fallThrough.block->index]); table.ctiOffsets.grow(table.branchOffsets.size()); for (unsigned j = table.ctiOffsets.size(); j--;) table.ctiOffsets[j] = table.ctiDefault; for (unsigned j = data.cases.size(); j--;) { SwitchCase& myCase = data.cases[j]; table.ctiOffsets[myCase.value.switchLookupValue(data.kind) - table.min] = linkBuffer.locationOf(m_blockHeads[myCase.target.block->index]); } } for (unsigned i = m_codeBlock->numberOfSwitchJumpTables(); i--;) { if (usedJumpTables.get(i)) continue; m_codeBlock->switchJumpTable(i).clear(); } // NOTE: we cannot clear string switch tables because (1) we're running concurrently // and we cannot deref StringImpl's and (2) it would be weird to deref those // StringImpl's since we refer to them. for (Bag<SwitchData>::iterator switchDataIter = m_graph.m_switchData.begin(); !!switchDataIter; ++switchDataIter) { SwitchData& data = **switchDataIter; if (!data.didUseJumpTable) continue; if (data.kind != SwitchString) continue; StringJumpTable& table = m_codeBlock->stringSwitchJumpTable(data.switchTableIndex); table.ctiDefault = linkBuffer.locationOf(m_blockHeads[data.fallThrough.block->index]); StringJumpTable::StringOffsetTable::iterator iter; StringJumpTable::StringOffsetTable::iterator end = table.offsetTable.end(); for (iter = table.offsetTable.begin(); iter != end; ++iter) iter->value.ctiOffset = table.ctiDefault; for (unsigned j = data.cases.size(); j--;) { SwitchCase& myCase = data.cases[j]; iter = table.offsetTable.find(myCase.value.stringImpl()); RELEASE_ASSERT(iter != end); iter->value.ctiOffset = linkBuffer.locationOf(m_blockHeads[myCase.target.block->index]); } } // Link all calls out from the JIT code to their respective functions. for (unsigned i = 0; i < m_calls.size(); ++i) linkBuffer.link(m_calls[i].m_call, m_calls[i].m_function); for (unsigned i = m_getByIds.size(); i--;) m_getByIds[i].finalize(linkBuffer); for (unsigned i = m_putByIds.size(); i--;) m_putByIds[i].finalize(linkBuffer); for (unsigned i = 0; i < m_ins.size(); ++i) { StructureStubInfo& info = *m_ins[i].m_stubInfo; CodeLocationCall callReturnLocation = linkBuffer.locationOf(m_ins[i].m_slowPathGenerator->call()); info.patch.deltaCallToDone = differenceBetweenCodePtr(callReturnLocation, linkBuffer.locationOf(m_ins[i].m_done)); info.patch.deltaCallToJump = differenceBetweenCodePtr(callReturnLocation, linkBuffer.locationOf(m_ins[i].m_jump)); info.callReturnLocation = callReturnLocation; info.patch.deltaCallToSlowCase = differenceBetweenCodePtr(callReturnLocation, linkBuffer.locationOf(m_ins[i].m_slowPathGenerator->label())); } for (unsigned i = 0; i < m_jsCalls.size(); ++i) { JSCallRecord& record = m_jsCalls[i]; CallLinkInfo& info = *record.m_info; linkBuffer.link(record.m_slowCall, FunctionPtr(m_vm->getCTIStub(linkCallThunkGenerator).code().executableAddress())); info.setCallLocations(linkBuffer.locationOfNearCall(record.m_slowCall), linkBuffer.locationOf(record.m_targetToCheck), linkBuffer.locationOfNearCall(record.m_fastCall)); } MacroAssemblerCodeRef osrExitThunk = vm()->getCTIStub(osrExitGenerationThunkGenerator); CodeLocationLabel target = CodeLocationLabel(osrExitThunk.code()); for (unsigned i = 0; i < m_jitCode->osrExit.size(); ++i) { OSRExit& exit = m_jitCode->osrExit[i]; OSRExitCompilationInfo& info = m_exitCompilationInfo[i]; linkBuffer.link(exit.getPatchableCodeOffsetAsJump(), target); exit.correctJump(linkBuffer); if (info.m_replacementSource.isSet()) { m_jitCode->common.jumpReplacements.append(JumpReplacement( linkBuffer.locationOf(info.m_replacementSource), linkBuffer.locationOf(info.m_replacementDestination))); } } if (m_graph.compilation()) { ASSERT(m_exitSiteLabels.size() == m_jitCode->osrExit.size()); for (unsigned i = 0; i < m_exitSiteLabels.size(); ++i) { Vector<Label>& labels = m_exitSiteLabels[i]; Vector<const void*> addresses; for (unsigned j = 0; j < labels.size(); ++j) addresses.append(linkBuffer.locationOf(labels[j]).executableAddress()); m_graph.compilation()->addOSRExitSite(addresses); } } else ASSERT(!m_exitSiteLabels.size()); m_jitCode->common.compilation = m_graph.compilation(); // Link new DFG exception handlers and remove baseline JIT handlers. m_codeBlock->clearExceptionHandlers(); for (unsigned i = 0; i < m_exceptionHandlerOSRExitCallSites.size(); i++) { OSRExitCompilationInfo& info = m_exceptionHandlerOSRExitCallSites[i].exitInfo; if (info.m_replacementDestination.isSet()) { // If this is is *not* set, it means that we already jumped to the OSR exit in pure generated control flow. // i.e, we explicitly emitted an exceptionCheck that we know will be caught in this machine frame. // If this *is set*, it means we will be landing at this code location from genericUnwind from an // exception thrown in a child call frame. CodeLocationLabel catchLabel = linkBuffer.locationOf(info.m_replacementDestination); HandlerInfo newExceptionHandler = m_exceptionHandlerOSRExitCallSites[i].baselineExceptionHandler; CallSiteIndex callSite = m_exceptionHandlerOSRExitCallSites[i].callSiteIndex; newExceptionHandler.start = callSite.bits(); newExceptionHandler.end = callSite.bits() + 1; newExceptionHandler.nativeCode = catchLabel; m_codeBlock->appendExceptionHandler(newExceptionHandler); } } if (m_pcToCodeOriginMapBuilder.didBuildMapping()) m_codeBlock->setPCToCodeOriginMap(std::make_unique<PCToCodeOriginMap>(WTFMove(m_pcToCodeOriginMapBuilder), linkBuffer)); }