Changeset 221602 in webkit
- Timestamp:
- Sep 4, 2017 8:21:33 PM (7 years ago)
- Location:
- trunk/Source/JavaScriptCore
- Files:
-
- 41 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/ChangeLog
r221601 r221602 1 2017-09-04 Saam Barati <sbarati@apple.com> 2 3 Support compiling catch in the FTL 4 https://bugs.webkit.org/show_bug.cgi?id=175396 5 6 Reviewed by Filip Pizlo. 7 8 This patch implements op_catch in the FTL. It extends the DFG implementation 9 by supporting multiple entrypoints in DFG-SSA. This patch implements this 10 by introducing an EntrySwitch node. When converting to SSA, we introduce a new 11 root block with an EntrySwitch that has the previous DFG entrypoints as its 12 successors. By convention, we pick the zeroth entry point index to be the 13 op_enter entrypoint. Like in B3, in DFG-SSA, EntrySwitch just acts like a 14 switch over the entrypoint index argument. DFG::EntrySwitch in the FTL 15 simply lowers to B3::EntrySwitch. The EntrySwitch in the root block that 16 SSAConversion creates can not exit because we would both not know where to exit 17 to in the program: we would not have valid OSR exit state. This design also 18 mandates that anything we hoist above EntrySwitch in the new root block 19 can not exit since they also do not have valid OSR exit state. 20 21 This patch also adds a new metadata node named InitializeEntrypointArguments. 22 InitializeEntrypointArguments is a metadata node that initializes the flush format for 23 the arguments at a given entrypoint. For a given entrypoint index, this node 24 tells AI and OSRAvailabilityAnalysis what the flush format for each argument 25 is. This allows each individual entrypoint to have an independent set of 26 argument types. Currently, this won't happen in practice because ArgumentPosition 27 unifies flush formats, but this is an implementation detail we probably want 28 to modify in the future. SSAConversion will add InitializeEntrypointArguments 29 to the beginning of each of the original DFG entrypoint blocks. 30 31 This patch also adds the ability to specify custom prologue code generators in Air. 32 This allows the FTL to specify a custom prologue for catch entrypoints that 33 matches the op_catch OSR entry calling convention that the DFG uses. This way, 34 the baseline JIT code OSR enters into op_catch the same way both in the DFG 35 and the FTL. In the future, we can use this same mechanism to perform stack 36 overflow checks instead of using a patchpoint. 37 38 * b3/air/AirCode.cpp: 39 (JSC::B3::Air::Code::isEntrypoint): 40 (JSC::B3::Air::Code::entrypointIndex): 41 * b3/air/AirCode.h: 42 (JSC::B3::Air::Code::setPrologueForEntrypoint): 43 (JSC::B3::Air::Code::prologueGeneratorForEntrypoint): 44 * b3/air/AirGenerate.cpp: 45 (JSC::B3::Air::generate): 46 * dfg/DFGAbstractInterpreterInlines.h: 47 (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): 48 * dfg/DFGBasicBlock.h: 49 * dfg/DFGByteCodeParser.cpp: 50 (JSC::DFG::ByteCodeParser::parseBlock): 51 (JSC::DFG::ByteCodeParser::parse): 52 * dfg/DFGCFG.h: 53 (JSC::DFG::selectCFG): 54 * dfg/DFGClobberize.h: 55 (JSC::DFG::clobberize): 56 * dfg/DFGClobbersExitState.cpp: 57 (JSC::DFG::clobbersExitState): 58 * dfg/DFGCommonData.cpp: 59 (JSC::DFG::CommonData::shrinkToFit): 60 (JSC::DFG::CommonData::finalizeCatchEntrypoints): 61 * dfg/DFGCommonData.h: 62 (JSC::DFG::CommonData::catchOSREntryDataForBytecodeIndex): 63 (JSC::DFG::CommonData::appendCatchEntrypoint): 64 * dfg/DFGDoesGC.cpp: 65 (JSC::DFG::doesGC): 66 * dfg/DFGFixupPhase.cpp: 67 (JSC::DFG::FixupPhase::fixupNode): 68 * dfg/DFGGraph.cpp: 69 (JSC::DFG::Graph::dump): 70 (JSC::DFG::Graph::invalidateCFG): 71 (JSC::DFG::Graph::ensureCPSCFG): 72 (JSC::DFG::Graph::methodOfGettingAValueProfileFor): 73 * dfg/DFGGraph.h: 74 (JSC::DFG::Graph::isEntrypoint): 75 * dfg/DFGInPlaceAbstractState.cpp: 76 (JSC::DFG::InPlaceAbstractState::initialize): 77 (JSC::DFG::InPlaceAbstractState::mergeToSuccessors): 78 * dfg/DFGJITCode.cpp: 79 (JSC::DFG::JITCode::shrinkToFit): 80 (JSC::DFG::JITCode::finalizeOSREntrypoints): 81 * dfg/DFGJITCode.h: 82 (JSC::DFG::JITCode::catchOSREntryDataForBytecodeIndex): Deleted. 83 (JSC::DFG::JITCode::appendCatchEntrypoint): Deleted. 84 * dfg/DFGJITCompiler.cpp: 85 (JSC::DFG::JITCompiler::noticeCatchEntrypoint): 86 (JSC::DFG::JITCompiler::makeCatchOSREntryBuffer): 87 * dfg/DFGMayExit.cpp: 88 * dfg/DFGNode.h: 89 (JSC::DFG::Node::isEntrySwitch): 90 (JSC::DFG::Node::isTerminal): 91 (JSC::DFG::Node::entrySwitchData): 92 (JSC::DFG::Node::numSuccessors): 93 (JSC::DFG::Node::successor): 94 (JSC::DFG::Node::entrypointIndex): 95 * dfg/DFGNodeType.h: 96 * dfg/DFGOSRAvailabilityAnalysisPhase.cpp: 97 (JSC::DFG::OSRAvailabilityAnalysisPhase::run): 98 (JSC::DFG::LocalOSRAvailabilityCalculator::executeNode): 99 * dfg/DFGOSREntry.cpp: 100 (JSC::DFG::prepareCatchOSREntry): 101 * dfg/DFGOSREntry.h: 102 * dfg/DFGOSREntrypointCreationPhase.cpp: 103 (JSC::DFG::OSREntrypointCreationPhase::run): 104 * dfg/DFGPredictionPropagationPhase.cpp: 105 * dfg/DFGSSAConversionPhase.cpp: 106 (JSC::DFG::SSAConversionPhase::SSAConversionPhase): 107 (JSC::DFG::SSAConversionPhase::run): 108 * dfg/DFGSafeToExecute.h: 109 (JSC::DFG::safeToExecute): 110 * dfg/DFGSpeculativeJIT.cpp: 111 (JSC::DFG::SpeculativeJIT::linkOSREntries): 112 * dfg/DFGSpeculativeJIT32_64.cpp: 113 (JSC::DFG::SpeculativeJIT::compile): 114 * dfg/DFGSpeculativeJIT64.cpp: 115 (JSC::DFG::SpeculativeJIT::compile): 116 * dfg/DFGStaticExecutionCountEstimationPhase.cpp: 117 (JSC::DFG::StaticExecutionCountEstimationPhase::run): 118 * dfg/DFGValidate.cpp: 119 * ftl/FTLCapabilities.cpp: 120 (JSC::FTL::canCompile): 121 * ftl/FTLCompile.cpp: 122 (JSC::FTL::compile): 123 * ftl/FTLLowerDFGToB3.cpp: 124 (JSC::FTL::DFG::LowerDFGToB3::lower): 125 (JSC::FTL::DFG::LowerDFGToB3::compileNode): 126 (JSC::FTL::DFG::LowerDFGToB3::compileExtractCatchLocal): 127 (JSC::FTL::DFG::LowerDFGToB3::compileGetStack): 128 (JSC::FTL::DFG::LowerDFGToB3::compileEntrySwitch): 129 (JSC::FTL::DFG::LowerDFGToB3::speculate): 130 (JSC::FTL::DFG::LowerDFGToB3::appendOSRExitDescriptor): 131 (JSC::FTL::DFG::LowerDFGToB3::appendOSRExit): 132 (JSC::FTL::DFG::LowerDFGToB3::blessSpeculation): 133 * ftl/FTLOutput.cpp: 134 (JSC::FTL::Output::entrySwitch): 135 * ftl/FTLOutput.h: 136 * jit/JITOperations.cpp: 137 1 138 2017-09-03 Yusuke Suzuki <utatane.tea@gmail.com> 2 139 -
trunk/Source/JavaScriptCore/b3/air/AirCode.cpp
r216989 r221602 157 157 bool Code::isEntrypoint(BasicBlock* block) const 158 158 { 159 // Note: This function must work both before and after LowerEntrySwitch. 160 159 161 if (m_entrypoints.isEmpty()) 160 162 return !block->index(); … … 165 167 } 166 168 return false; 169 } 170 171 std::optional<unsigned> Code::entrypointIndex(BasicBlock* block) const 172 { 173 RELEASE_ASSERT(m_entrypoints.size()); 174 for (unsigned i = 0; i < m_entrypoints.size(); ++i) { 175 if (m_entrypoints[i].block() == block) 176 return i; 177 } 178 return std::nullopt; 167 179 } 168 180 -
trunk/Source/JavaScriptCore/b3/air/AirCode.h
r216989 r221602 54 54 class CCallSpecial; 55 55 class CFG; 56 class Code; 56 57 class Disassembler; 57 58 58 59 typedef void WasmBoundsCheckGeneratorFunction(CCallHelpers&, GPRReg); 59 60 typedef SharedTask<WasmBoundsCheckGeneratorFunction> WasmBoundsCheckGenerator; 61 62 typedef void PrologueGeneratorFunction(CCallHelpers&, Code&); 63 typedef SharedTask<PrologueGeneratorFunction> PrologueGenerator; 60 64 61 65 // This is an IR that is very close to the bare metal. It requires about 40x more bytes than the … … 166 170 const FrequentedBlock& entrypoint(unsigned index) const { return m_entrypoints[index]; } 167 171 bool isEntrypoint(BasicBlock*) const; 168 172 // Note: It is only valid to call this function after LowerEntrySwitch. 173 std::optional<unsigned> entrypointIndex(BasicBlock*) const; 174 void setPrologueForEntrypoint(unsigned entrypointIndex, RefPtr<PrologueGenerator> generator) 175 { 176 // Note: We allow this to be called even before we set m_entrypoints just for convenience to users of this API. 177 m_entrypointIndexToGenerator.set(entrypointIndex, generator); 178 } 179 RefPtr<PrologueGenerator> prologueGeneratorForEntrypoint(unsigned entrypointIndex) 180 { 181 return m_entrypointIndexToGenerator.get(entrypointIndex); 182 } 183 169 184 // This is used by lowerEntrySwitch(). 170 185 template<typename Vector> … … 354 369 Vector<FrequentedBlock> m_entrypoints; // This is empty until after lowerEntrySwitch(). 355 370 Vector<CCallHelpers::Label> m_entrypointLabels; // This is empty until code generation. 371 HashMap<unsigned, RefPtr<PrologueGenerator>, WTF::IntHash<unsigned>, WTF::UnsignedWithZeroKeyHashTraits<unsigned>> m_entrypointIndexToGenerator; 356 372 RefPtr<WasmBoundsCheckGenerator> m_wasmBoundsCheckGenerator; 357 373 const char* m_lastPhaseName; -
trunk/Source/JavaScriptCore/b3/air/AirGenerate.cpp
r217221 r221602 209 209 disassembler->startBlock(block, jit); 210 210 211 if (code.isEntrypoint(block)) { 211 if (std::optional<unsigned> entrypointIndex = code.entrypointIndex(block)) { 212 ASSERT(code.isEntrypoint(block)); 213 212 214 if (disassembler) 213 215 disassembler->startEntrypoint(jit); 214 216 215 jit.emitFunctionPrologue(); 216 if (code.frameSize()) { 217 AllowMacroScratchRegisterUsageIf allowScratch(jit, isARM64()); 218 jit.addPtr(CCallHelpers::TrustedImm32(-code.frameSize()), MacroAssembler::stackPointerRegister); 217 if (RefPtr<PrologueGenerator> prologueGenerator = code.prologueGeneratorForEntrypoint(*entrypointIndex)) 218 prologueGenerator->run(jit, code); 219 else { 220 jit.emitFunctionPrologue(); 221 if (code.frameSize()) { 222 AllowMacroScratchRegisterUsageIf allowScratch(jit, isARM64()); 223 jit.addPtr(CCallHelpers::TrustedImm32(-code.frameSize()), MacroAssembler::stackPointerRegister); 224 } 225 226 jit.emitSave(code.calleeSaveRegisterAtOffsetList()); 219 227 } 220 221 jit.emitSave(code.calleeSaveRegisterAtOffsetList());222 228 223 229 if (disassembler) 224 230 disassembler->endEntrypoint(jit); 225 } 231 } else 232 ASSERT(!code.isEntrypoint(block)); 226 233 227 234 ASSERT(block->size() >= 1); -
trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
r221601 r221602 261 261 break; 262 262 } 263 263 264 264 case KillStack: { 265 265 // This is just a hint telling us that the OSR state of the local is no longer inside the … … 274 274 ASSERT(!m_state.variables().operand(node->local()).isClear()); 275 275 break; 276 276 277 case InitializeEntrypointArguments: { 278 unsigned entrypointIndex = node->entrypointIndex(); 279 const Vector<FlushFormat>& argumentFormats = m_graph.m_argumentFormats[entrypointIndex]; 280 for (unsigned argument = 0; argument < argumentFormats.size(); ++argument) { 281 AbstractValue& value = m_state.variables().argument(argument); 282 switch (argumentFormats[argument]) { 283 case FlushedInt32: 284 value.setType(SpecInt32Only); 285 break; 286 case FlushedBoolean: 287 value.setType(SpecBoolean); 288 break; 289 case FlushedCell: 290 value.setType(m_graph, SpecCell); 291 break; 292 case FlushedJSValue: 293 value.makeBytecodeTop(); 294 break; 295 default: 296 DFG_CRASH(m_graph, node, "Bad flush format for argument"); 297 break; 298 } 299 } 300 break; 301 } 302 277 303 case LoadVarargs: 278 304 case ForwardVarargs: { … … 1867 1893 } 1868 1894 1895 case EntrySwitch: 1896 break; 1897 1869 1898 case Return: 1870 1899 m_state.setIsValid(false); -
trunk/Source/JavaScriptCore/dfg/DFGBasicBlock.h
r221196 r221602 222 222 float executionCount; 223 223 224 // These fields are reserved for NaturalLoops.225 226 224 struct SSAData { 227 225 WTF_MAKE_FAST_ALLOCATED; -
trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
r221528 r221602 5263 5263 } 5264 5264 5265 if (isFTL(m_graph.m_plan.mode)) { 5266 // FIXME: Support catch in the FTL. 5267 // https://bugs.webkit.org/show_bug.cgi?id=175396 5265 if (m_graph.m_plan.mode == FTLForOSREntryMode) { 5268 5266 NEXT_OPCODE(op_catch); 5269 5267 } … … 6466 6464 m_graph.killUnreachableBlocks(); 6467 6465 6468 m_graph.m_cpsCFG = std::make_unique<CPSCFG>(m_graph);6469 6470 6466 for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) { 6471 6467 BasicBlock* block = m_graph.block(blockIndex); -
trunk/Source/JavaScriptCore/dfg/DFGCFG.h
r221196 r221602 99 99 CPSCFG& selectCFG(Graph& graph) 100 100 { 101 RELEASE_ASSERT(graph.m_cpsCFG); 102 return *graph.m_cpsCFG; 101 return graph.ensureCPSCFG(); 103 102 } 104 103 -
trunk/Source/JavaScriptCore/dfg/DFGClobberize.h
r221601 r221602 427 427 case Branch: 428 428 case Switch: 429 case EntrySwitch: 429 430 case ForceOSRExit: 430 431 case CheckBadCell: … … 438 439 case ProfileControlFlow: 439 440 case PutHint: 441 case InitializeEntrypointArguments: 440 442 write(SideState); 441 443 return; -
trunk/Source/JavaScriptCore/dfg/DFGClobbersExitState.cpp
r221080 r221602 41 41 // normally clobber. 42 42 switch (node->op()) { 43 case InitializeEntrypointArguments: 43 44 case MovHint: 44 45 case ZombieHint: -
trunk/Source/JavaScriptCore/dfg/DFGCommonData.cpp
r221528 r221602 88 88 weakReferences.shrinkToFit(); 89 89 transitions.shrinkToFit(); 90 catchEntrypoints.shrinkToFit(); 90 91 } 91 92 … … 194 195 } 195 196 197 void CommonData::finalizeCatchEntrypoints() 198 { 199 std::sort(catchEntrypoints.begin(), catchEntrypoints.end(), 200 [] (const CatchEntrypointData& a, const CatchEntrypointData& b) { return a.bytecodeIndex < b.bytecodeIndex; }); 201 202 #if !ASSERT_DISABLED 203 for (unsigned i = 0; i + 1 < catchEntrypoints.size(); ++i) 204 ASSERT(catchEntrypoints[i].bytecodeIndex <= catchEntrypoints[i + 1].bytecodeIndex); 205 #endif 206 } 207 196 208 } } // namespace JSC::DFG 197 209 -
trunk/Source/JavaScriptCore/dfg/DFGCommonData.h
r218936 r221602 32 32 #include "DFGAdaptiveStructureWatchpoint.h" 33 33 #include "DFGJumpReplacement.h" 34 #include "DFGOSREntry.h" 34 35 #include "InlineCallFrameSet.h" 35 36 #include "JSCell.h" … … 91 92 bool isVMTrapBreakpoint(void* address); 92 93 94 CatchEntrypointData* catchOSREntryDataForBytecodeIndex(unsigned bytecodeIndex) 95 { 96 return tryBinarySearch<CatchEntrypointData, unsigned>( 97 catchEntrypoints, catchEntrypoints.size(), bytecodeIndex, 98 [] (const CatchEntrypointData* item) { return item->bytecodeIndex; }); 99 } 100 101 void appendCatchEntrypoint(unsigned bytecodeIndex, void* machineCode, Vector<FlushFormat>&& argumentFormats) 102 { 103 catchEntrypoints.append(CatchEntrypointData { machineCode, WTFMove(argumentFormats), bytecodeIndex }); 104 } 105 106 void finalizeCatchEntrypoints(); 107 93 108 unsigned requiredRegisterCountForExecutionAndExit() const 94 109 { … … 107 122 Vector<WriteBarrier<JSCell>> weakReferences; 108 123 Vector<WriteBarrier<Structure>> weakStructureReferences; 124 Vector<CatchEntrypointData> catchEntrypoints; 109 125 Bag<CodeBlockJettisoningWatchpoint> watchpoints; 110 126 Bag<AdaptiveStructureWatchpoint> adaptiveStructureWatchpoints; … … 112 128 Vector<JumpReplacement> jumpReplacements; 113 129 130 ScratchBuffer* catchOSREntryBuffer; 114 131 RefPtr<Profiler::Compilation> compilation; 115 132 bool livenessHasBeenProved; // Initialized and used on every GC. -
trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp
r221601 r221602 57 57 case SetLocal: 58 58 case MovHint: 59 case InitializeEntrypointArguments: 59 60 case ZombieHint: 60 61 case ExitOK: … … 185 186 case Branch: 186 187 case Switch: 188 case EntrySwitch: 187 189 case Return: 188 190 case TailCall: -
trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
r221601 r221602 1550 1550 case Phi: 1551 1551 case Upsilon: 1552 case EntrySwitch: 1552 1553 case GetIndexedPropertyStorage: 1553 1554 case LastNodeType: … … 2038 2039 case LoopHint: 2039 2040 case MovHint: 2041 case InitializeEntrypointArguments: 2040 2042 case ZombieHint: 2041 2043 case ExitOK: -
trunk/Source/JavaScriptCore/dfg/DFGGraph.cpp
r221528 r221602 369 369 out.print(comma, "default:", data->fallThrough); 370 370 } 371 if (node->isEntrySwitch()) { 372 EntrySwitchData* data = node->entrySwitchData(); 373 for (unsigned i = 0; i < data->cases.size(); ++i) 374 out.print(comma, BranchTarget(data->cases[i])); 375 } 371 376 ClobberSet reads; 372 377 ClobberSet writes; … … 516 521 out.print("DFG for ", CodeBlockWithJITType(m_codeBlock, JITCode::DFGJIT), ":\n"); 517 522 out.print(" Fixpoint state: ", m_fixpointState, "; Form: ", m_form, "; Unification state: ", m_unificationState, "; Ref count state: ", m_refCountState, "\n"); 518 if (m_form == SSA) 519 out.print(" Argument formats: ", listDump(m_argumentFormats), "\n"); 523 if (m_form == SSA) { 524 for (unsigned entrypointIndex = 0; entrypointIndex < m_argumentFormats.size(); ++entrypointIndex) 525 out.print(" Argument formats for entrypoint index: ", entrypointIndex, " : ", listDump(m_argumentFormats[entrypointIndex]), "\n"); 526 } 520 527 else { 521 528 for (auto pair : m_entrypointToArguments) … … 825 832 m_backwardsDominators = nullptr; 826 833 m_backwardsCFG = nullptr; 834 m_cpsCFG = nullptr; 827 835 } 828 836 … … 1544 1552 } 1545 1553 1554 CPSCFG& Graph::ensureCPSCFG() 1555 { 1556 RELEASE_ASSERT(m_form != SSA && !m_isInSSAConversion); 1557 if (!m_cpsCFG) 1558 m_cpsCFG = std::make_unique<CPSCFG>(*this); 1559 return *m_cpsCFG; 1560 } 1561 1546 1562 CPSDominators& Graph::ensureCPSDominators() 1547 1563 { … … 1611 1627 1612 1628 if (node->accessesStack(*this)) { 1613 ValueProfile* result = [&] () -> ValueProfile* { 1614 if (!node->local().isArgument()) 1615 return nullptr; 1629 if (m_form != SSA && node->local().isArgument()) { 1616 1630 int argument = node->local().toArgument(); 1631 Node* argumentNode = m_entrypointToArguments.find(block(0))->value[argument]; 1617 1632 // FIXME: We should match SetArgument nodes at other entrypoints as well: 1618 1633 // https://bugs.webkit.org/show_bug.cgi?id=175841 1619 Node* argumentNode = m_entrypointToArguments.find(block(0))->value[argument]; 1620 if (!argumentNode) 1621 return nullptr; 1622 if (node->variableAccessData() != argumentNode->variableAccessData()) 1623 return nullptr; 1624 return &profiledBlock->valueProfileForArgument(argument); 1625 }(); 1626 if (result) 1627 return result; 1634 if (argumentNode && node->variableAccessData() == argumentNode->variableAccessData()) 1635 return &profiledBlock->valueProfileForArgument(argument); 1636 } 1628 1637 1629 1638 if (node->op() == GetLocal) { -
trunk/Source/JavaScriptCore/dfg/DFGGraph.h
r221601 r221602 932 932 BackwardsDominators& ensureBackwardsDominators(); 933 933 ControlEquivalenceAnalysis& ensureControlEquivalenceAnalysis(); 934 CPSCFG& ensureCPSCFG(); 934 935 935 936 // These functions only makes sense to call after bytecode parsing … … 951 952 bool isEntrypoint(BasicBlock* block) const 952 953 { 954 ASSERT_WITH_MESSAGE(!m_isInSSAConversion, "This is not written to work during SSA conversion."); 955 956 if (m_form == SSA) { 957 ASSERT(m_entrypoints.size() == 1); 958 ASSERT(m_entrypoints.contains(this->block(0))); 959 return block == this->block(0); 960 } 961 953 962 if (m_entrypoints.size() <= 4) { 954 963 bool result = m_entrypoints.contains(block); … … 979 988 // In CPS, this is all of the SetArgument nodes for the arguments in the machine code block 980 989 // that survived DCE. All of them except maybe "this" will survive DCE, because of the Flush 981 // nodes. 990 // nodes. In SSA, this has no meaning. It's empty. 991 HashMap<BasicBlock*, ArgumentsVector> m_entrypointToArguments; 992 993 // In SSA, this is the argument speculation that we've locked in for an entrypoint block. 982 994 // 983 // In SSA, this is all of the GetStack nodes for the arguments in the machine code block that 984 // may have some speculation in the prologue and survived DCE. Note that to get the speculation 985 // for an argument in SSA, you must use m_argumentFormats, since we still have to speculate 986 // even if the argument got killed. For example: 995 // We must speculate on the argument types at each entrypoint even if operations involving 996 // arguments get killed. For example: 987 997 // 988 998 // function foo(x) { … … 1002 1012 // If we DCE the ArithAdd and we remove the int check on x, then this won't do the side 1003 1013 // effects. 1004 HashMap<BasicBlock*, ArgumentsVector> m_entrypointToArguments; 1005 1006 // In CPS, this is meaningless. In SSA, this is the argument speculation that we've locked in. 1007 Vector<FlushFormat> m_argumentFormats; 1014 // 1015 // By convention, entrypoint index 0 is used for the CodeBlock's op_enter entrypoint. 1016 // So argumentFormats[0] are the argument formats for the normal call entrypoint. 1017 Vector<Vector<FlushFormat>> m_argumentFormats; 1018 1019 // This maps an entrypoint index to a particular op_catch bytecode offset. By convention, 1020 // it'll never have zero as a key because we use zero to mean the op_enter entrypoint. 1021 HashMap<unsigned, unsigned> m_entrypointIndexToCatchBytecodeOffset; 1022 1023 // This is the number of logical entrypoints that we're compiling. This is only used 1024 // in SSA. Each EntrySwitch node must have numberOfEntrypoints cases. Note, this is 1025 // not the same as m_entrypoints.size(). m_entrypoints.size() represents the number 1026 // of roots in the CFG. In SSA, m_entrypoints.size() == 1. 1027 unsigned m_numberOfEntrypoints { UINT_MAX }; 1008 1028 1009 1029 SegmentedVector<VariableAccessData, 16> m_variableAccessData; … … 1061 1081 std::unique_ptr<FlowIndexing> m_indexingCache; 1062 1082 std::unique_ptr<FlowMap<AbstractValue>> m_abstractValuesCache; 1083 Bag<EntrySwitchData> m_entrySwitchData; 1063 1084 1064 1085 RegisteredStructure stringStructure; -
trunk/Source/JavaScriptCore/dfg/DFGInPlaceAbstractState.cpp
r221472 r221602 101 101 entrypoint->cfaStructureClobberStateAtTail = StructuresAreWatched; 102 102 103 for (size_t i = 0; i < entrypoint->valuesAtHead.numberOfArguments(); ++i) { 104 entrypoint->valuesAtTail.argument(i).clear(); 105 106 FlushFormat format; 107 if (m_graph.m_form == SSA) { 108 // FIXME: When supporting multiple entrypoints in the FTL, we need to change 109 // what we do here: https://bugs.webkit.org/show_bug.cgi?id=175396 110 format = m_graph.m_argumentFormats[i]; 111 } else { 112 Node* node = m_graph.m_entrypointToArguments.find(entrypoint)->value[i]; 103 if (m_graph.m_form == SSA) { 104 for (size_t i = 0; i < entrypoint->valuesAtHead.numberOfArguments(); ++i) { 105 entrypoint->valuesAtHead.argument(i).clear(); 106 entrypoint->valuesAtTail.argument(i).clear(); 107 } 108 } else { 109 const ArgumentsVector& arguments = m_graph.m_entrypointToArguments.find(entrypoint)->value; 110 for (size_t i = 0; i < entrypoint->valuesAtHead.numberOfArguments(); ++i) { 111 entrypoint->valuesAtTail.argument(i).clear(); 112 113 FlushFormat format; 114 Node* node = arguments[i]; 113 115 if (!node) 114 116 format = FlushedJSValue; … … 117 119 format = node->variableAccessData()->flushFormat(); 118 120 } 121 122 switch (format) { 123 case FlushedInt32: 124 entrypoint->valuesAtHead.argument(i).setType(SpecInt32Only); 125 break; 126 case FlushedBoolean: 127 entrypoint->valuesAtHead.argument(i).setType(SpecBoolean); 128 break; 129 case FlushedCell: 130 entrypoint->valuesAtHead.argument(i).setType(m_graph, SpecCell); 131 break; 132 case FlushedJSValue: 133 entrypoint->valuesAtHead.argument(i).makeBytecodeTop(); 134 break; 135 default: 136 DFG_CRASH(m_graph, nullptr, "Bad flush format for argument"); 137 break; 138 } 119 139 } 120 121 switch (format) { 122 case FlushedInt32: 123 entrypoint->valuesAtHead.argument(i).setType(SpecInt32Only); 124 break; 125 case FlushedBoolean: 126 entrypoint->valuesAtHead.argument(i).setType(SpecBoolean); 127 break; 128 case FlushedCell: 129 entrypoint->valuesAtHead.argument(i).setType(m_graph, SpecCell); 130 break; 131 case FlushedJSValue: 132 entrypoint->valuesAtHead.argument(i).makeBytecodeTop(); 133 break; 134 default: 135 DFG_CRASH(m_graph, nullptr, "Bad flush format for argument"); 136 break; 137 } 138 } 140 } 141 139 142 for (size_t i = 0; i < entrypoint->valuesAtHead.numberOfLocals(); ++i) { 140 143 entrypoint->valuesAtHead.local(i).clear(); … … 164 167 } 165 168 } 169 166 170 if (m_graph.m_form == SSA) { 167 171 for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) { … … 372 376 return changed; 373 377 } 378 379 case EntrySwitch: { 380 EntrySwitchData* data = terminal->entrySwitchData(); 381 bool changed = false; 382 for (unsigned i = data->cases.size(); i--;) 383 changed |= merge(basicBlock, data->cases[i]); 384 return changed; 385 } 374 386 375 387 case Return: -
trunk/Source/JavaScriptCore/dfg/DFGJITCode.cpp
r221200 r221602 64 64 osrEntry.shrinkToFit(); 65 65 osrExit.shrinkToFit(); 66 catchEntrypoints.shrinkToFit();67 66 speculationRecovery.shrinkToFit(); 68 67 minifiedDFG.prepareAndShrink(); … … 244 243 return a.m_bytecodeIndex < b.m_bytecodeIndex; 245 244 }; 246 std::sort(catchEntrypoints.begin(), catchEntrypoints.end(), comparator);247 245 std::sort(osrEntry.begin(), osrEntry.end(), comparator); 248 246 … … 252 250 ASSERT(osrVector[i].m_bytecodeIndex <= osrVector[i + 1].m_bytecodeIndex); 253 251 }; 254 verifyIsSorted(catchEntrypoints);255 252 verifyIsSorted(osrEntry); 256 253 #endif -
trunk/Source/JavaScriptCore/dfg/DFGJITCode.h
r221200 r221602 71 71 } 72 72 73 CatchEntrypointData* catchOSREntryDataForBytecodeIndex(unsigned bytecodeIndex)74 {75 return tryBinarySearch<CatchEntrypointData, unsigned>(76 catchEntrypoints, catchEntrypoints.size(), bytecodeIndex,77 [] (const CatchEntrypointData* item) { return item->m_bytecodeIndex; });78 }79 80 73 void finalizeOSREntrypoints(); 81 74 82 void appendCatchEntrypoint(unsigned bytecodeIndex, unsigned machineCodeOffset, Vector<FlushFormat>&& argumentFormats)83 {84 catchEntrypoints.append(CatchEntrypointData { bytecodeIndex, machineCodeOffset, WTFMove(argumentFormats) });85 }86 87 75 unsigned appendOSRExit(const OSRExit& exit) 88 76 { … … 147 135 CommonData common; 148 136 Vector<DFG::OSREntryData> osrEntry; 149 Vector<CatchEntrypointData> catchEntrypoints;150 137 SegmentedVector<DFG::OSRExit, 8> osrExit; 151 138 Vector<DFG::SpeculationRecovery> speculationRecovery; 152 139 DFG::VariableEventStream variableEventStream; 153 140 DFG::MinifiedGraph minifiedDFG; 154 ScratchBuffer* catchOSREntryBuffer;155 141 156 142 #if ENABLE(FTL_JIT) -
trunk/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp
r221196 r221602 560 560 RELEASE_ASSERT(basicBlock.isCatchEntrypoint); 561 561 RELEASE_ASSERT(basicBlock.intersectionOfCFAHasVisited); // An entrypoint is reachable by definition. 562 m_jitCode-> appendCatchEntrypoint(basicBlock.bytecodeBegin, linkBuffer.offsetOf(blockHead), WTFMove(argumentFormats));562 m_jitCode->common.appendCatchEntrypoint(basicBlock.bytecodeBegin, linkBuffer.locationOf(blockHead).executableAddress(), WTFMove(argumentFormats)); 563 563 } 564 564 … … 688 688 if (m_graph.m_maxLocalsForCatchOSREntry) { 689 689 uint32_t numberOfLiveLocals = std::max(*m_graph.m_maxLocalsForCatchOSREntry, 1u); // Make sure we always allocate a non-null catchOSREntryBuffer. 690 m_jitCode->c atchOSREntryBuffer = vm()->scratchBufferForSize(sizeof(JSValue) * numberOfLiveLocals);690 m_jitCode->common.catchOSREntryBuffer = vm()->scratchBufferForSize(sizeof(JSValue) * numberOfLiveLocals); 691 691 } 692 692 } -
trunk/Source/JavaScriptCore/dfg/DFGMayExit.cpp
r221196 r221602 54 54 case Int52Constant: 55 55 case MovHint: 56 case InitializeEntrypointArguments: 56 57 case SetLocal: 57 58 case Flush: … … 79 80 case CountExecution: 80 81 case Jump: 82 case EntrySwitch: 81 83 case Branch: 82 84 case Unreachable: -
trunk/Source/JavaScriptCore/dfg/DFGNode.h
r221601 r221602 204 204 }; 205 205 206 struct EntrySwitchData { 207 Vector<BasicBlock*> cases; 208 }; 209 206 210 struct CallVarargsData { 207 211 int firstVarArgOffset; … … 1316 1320 } 1317 1321 1322 bool isEntrySwitch() const 1323 { 1324 return op() == EntrySwitch; 1325 } 1326 1318 1327 bool isTerminal() 1319 1328 { … … 1322 1331 case Branch: 1323 1332 case Switch: 1333 case EntrySwitch: 1324 1334 case Return: 1325 1335 case TailCall: … … 1383 1393 return m_opInfo.as<SwitchData*>(); 1384 1394 } 1395 1396 EntrySwitchData* entrySwitchData() 1397 { 1398 ASSERT(isEntrySwitch()); 1399 return m_opInfo.as<EntrySwitchData*>(); 1400 } 1385 1401 1386 1402 unsigned numSuccessors() … … 1393 1409 case Switch: 1394 1410 return switchData()->cases.size() + 1; 1411 case EntrySwitch: 1412 return entrySwitchData()->cases.size(); 1395 1413 default: 1396 1414 return 0; … … 1405 1423 RELEASE_ASSERT(index == switchData()->cases.size()); 1406 1424 return switchData()->fallThrough.block; 1407 } 1425 } else if (isEntrySwitch()) 1426 return entrySwitchData()->cases[index]; 1408 1427 1409 1428 switch (index) { … … 2014 2033 } 2015 2034 2035 unsigned entrypointIndex() 2036 { 2037 ASSERT(op() == InitializeEntrypointArguments); 2038 return m_opInfo.as<unsigned>(); 2039 } 2040 2016 2041 bool shouldGenerate() 2017 2042 { -
trunk/Source/JavaScriptCore/dfg/DFGNodeType.h
r221601 r221602 391 391 macro(Branch, NodeMustGenerate) \ 392 392 macro(Switch, NodeMustGenerate) \ 393 macro(EntrySwitch, NodeMustGenerate) \ 393 394 macro(Return, NodeMustGenerate) \ 394 395 macro(TailCall, NodeMustGenerate | NodeHasVarArgs) \ … … 441 442 macro(CallDOMGetter, NodeResultJS | NodeMustGenerate) \ 442 443 macro(CallDOM, NodeResultJS | NodeMustGenerate) \ 444 /* Metadata node that initializes the state for flushed argument types at an entrypoint in the program. */ \ 445 /* Currently, we only use this for the blocks an EntrySwitch branches to at the root of the program. */ \ 446 /* This is only used in SSA. */ \ 447 macro(InitializeEntrypointArguments, NodeMustGenerate) 443 448 444 449 // This enum generates a monotonically increasing id for all Node types, -
trunk/Source/JavaScriptCore/dfg/DFGOSRAvailabilityAnalysisPhase.cpp
r221528 r221602 58 58 BasicBlock* root = m_graph.block(0); 59 59 root->ssa->availabilityAtHead.m_locals.fill(Availability::unavailable()); 60 for (unsigned argument = m_graph.m_argumentFormats.size(); argument--;) { 61 FlushedAt flushedAt = FlushedAt( 62 m_graph.m_argumentFormats[argument], 63 virtualRegisterForArgument(argument)); 64 root->ssa->availabilityAtHead.m_locals.argument(argument) = Availability(flushedAt); 65 } 60 61 for (unsigned argument = 0; argument < m_graph.block(0)->valuesAtHead.numberOfArguments(); ++argument) 62 root->ssa->availabilityAtHead.m_locals.argument(argument) = Availability::unavailable(); 66 63 67 64 // This could be made more efficient by processing blocks in reverse postorder. … … 87 84 block->ssa->availabilityAtTail = calculator.m_availability; 88 85 changed = true; 89 86 90 87 for (unsigned successorIndex = block->numSuccessors(); successorIndex--;) { 91 88 BasicBlock* successor = block->successor(successorIndex); 92 89 successor->ssa->availabilityAtHead.merge(calculator.m_availability); 90 } 91 92 for (unsigned successorIndex = block->numSuccessors(); successorIndex--;) { 93 BasicBlock* successor = block->successor(successorIndex); 93 94 successor->ssa->availabilityAtHead.pruneByLiveness( 94 95 m_graph, successor->at(0)->origin.forExit); … … 200 201 break; 201 202 } 203 204 case InitializeEntrypointArguments: { 205 unsigned entrypointIndex = node->entrypointIndex(); 206 const Vector<FlushFormat>& argumentFormats = m_graph.m_argumentFormats[entrypointIndex]; 207 for (unsigned argument = argumentFormats.size(); argument--; ) { 208 FlushedAt flushedAt = FlushedAt(argumentFormats[argument], virtualRegisterForArgument(argument)); 209 m_availability.m_locals.argument(argument) = Availability(flushedAt); 210 } 211 break; 212 } 202 213 203 214 case LoadVarargs: -
trunk/Source/JavaScriptCore/dfg/DFGOSREntry.cpp
r221196 r221602 339 339 340 340 void* prepareCatchOSREntry(ExecState* exec, CodeBlock* codeBlock, unsigned bytecodeIndex) 341 { 342 if (!Options::useOSREntryToDFG()) 341 { 342 ASSERT(codeBlock->jitType() == JITCode::DFGJIT || codeBlock->jitType() == JITCode::FTLJIT); 343 344 if (!Options::useOSREntryToDFG() && codeBlock->jitCode()->jitType() == JITCode::DFGJIT) 343 345 return nullptr; 346 if (!Options::useOSREntryToFTL() && codeBlock->jitCode()->jitType() == JITCode::FTLJIT) 347 return nullptr; 344 348 345 349 VM& vm = exec->vm(); 346 ASSERT(codeBlock->jitType() == JITCode::DFGJIT); 347 DFG::JITCode* jitCode = codeBlock->jitCode()->dfg(); 348 RELEASE_ASSERT(jitCode); 349 350 DFG::CatchEntrypointData* catchEntrypoint = jitCode->catchOSREntryDataForBytecodeIndex(bytecodeIndex); 350 351 CommonData* dfgCommon = codeBlock->jitCode()->dfgCommon(); 352 RELEASE_ASSERT(dfgCommon); 353 DFG::CatchEntrypointData* catchEntrypoint = dfgCommon->catchOSREntryDataForBytecodeIndex(bytecodeIndex); 351 354 if (!catchEntrypoint) { 352 355 // This can be null under some circumstances. The most common is that we didn't … … 357 360 358 361 // We're only allowed to OSR enter if we've proven we have compatible argument types. 359 for (unsigned argument = 0; argument < catchEntrypoint-> m_argumentFormats.size(); ++argument) {362 for (unsigned argument = 0; argument < catchEntrypoint->argumentFormats.size(); ++argument) { 360 363 JSValue value = exec->uncheckedR(virtualRegisterForArgument(argument)).jsValue(); 361 switch (catchEntrypoint-> m_argumentFormats[argument]) {364 switch (catchEntrypoint->argumentFormats[argument]) { 362 365 case DFG::FlushedInt32: 363 366 if (!value.isInt32()) … … 383 386 } 384 387 385 unsigned frameSizeForCheck = jitCode->common.requiredRegisterCountForExecutionAndExit();388 unsigned frameSizeForCheck = dfgCommon->requiredRegisterCountForExecutionAndExit(); 386 389 if (UNLIKELY(!vm.ensureStackCapacityFor(&exec->registers()[virtualRegisterForLocal(frameSizeForCheck).offset()]))) 387 390 return nullptr; … … 389 392 ASSERT(Interpreter::getOpcodeID(exec->codeBlock()->instructions()[exec->bytecodeOffset()].u.opcode) == op_catch); 390 393 ValueProfileAndOperandBuffer* buffer = static_cast<ValueProfileAndOperandBuffer*>(exec->codeBlock()->instructions()[exec->bytecodeOffset() + 3].u.pointer); 391 JSValue* dataBuffer = reinterpret_cast<JSValue*>( jitCode->catchOSREntryBuffer->dataBuffer());394 JSValue* dataBuffer = reinterpret_cast<JSValue*>(dfgCommon->catchOSREntryBuffer->dataBuffer()); 392 395 unsigned index = 0; 393 396 buffer->forEach([&] (ValueProfileAndOperand& profile) { … … 398 401 }); 399 402 400 jitCode->catchOSREntryBuffer->setActiveLength(sizeof(JSValue) * index); 401 402 return jitCode->executableAddressAtOffset(catchEntrypoint->m_machineCodeOffset); 403 dfgCommon->catchOSREntryBuffer->setActiveLength(sizeof(JSValue) * index); 404 return catchEntrypoint->machineCode; 403 405 } 404 406 -
trunk/Source/JavaScriptCore/dfg/DFGOSREntry.h
r221196 r221602 72 72 73 73 struct CatchEntrypointData { 74 unsigned m_bytecodeIndex;75 unsigned m_machineCodeOffset;76 74 // We use this when doing OSR entry at catch. We prove the arguments 77 75 // are of the expected type before entering at a catch block. 78 Vector<FlushFormat> m_argumentFormats; 76 void* machineCode; 77 Vector<FlushFormat> argumentFormats; 78 unsigned bytecodeIndex; 79 79 }; 80 80 -
trunk/Source/JavaScriptCore/dfg/DFGOSREntrypointCreationPhase.cpp
r221196 r221602 148 148 m_graph.m_entrypointToArguments.add(newRoot, newArguments); 149 149 150 m_graph.m_cpsCFG = std::make_unique<CPSCFG>(m_graph); 151 150 m_graph.invalidateCFG(); 152 151 m_graph.resetReachability(); 153 152 m_graph.killUnreachableBlocks(); -
trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
r221601 r221602 1094 1094 break; 1095 1095 1096 case EntrySwitch: 1096 1097 case Upsilon: 1097 1098 // These don't get inserted until we go into SSA. … … 1157 1158 case PutDynamicVar: 1158 1159 case NukeStructureAndSetButterfly: 1160 case InitializeEntrypointArguments: 1159 1161 break; 1160 1162 -
trunk/Source/JavaScriptCore/dfg/DFGSSAConversionPhase.cpp
r221196 r221602 30 30 31 31 #include "DFGBasicBlockInlines.h" 32 #include "DFGBlockInsertionSet.h" 32 33 #include "DFGGraph.h" 33 34 #include "DFGInsertionSet.h" … … 45 46 SSAConversionPhase(Graph& graph) 46 47 : Phase(graph, "SSA conversion") 47 , m_calculator(graph)48 48 , m_insertionSet(graph) 49 49 { … … 53 53 { 54 54 RELEASE_ASSERT(m_graph.m_form == ThreadedCPS); 55 RELEASE_ASSERT(!m_graph.m_isInSSAConversion); 56 m_graph.m_isInSSAConversion = true; 55 57 56 58 m_graph.clearReplacements(); 57 59 m_graph.clearCPSCFGData(); 60 61 HashMap<unsigned, BasicBlock*, WTF::IntHash<unsigned>, WTF::UnsignedWithZeroKeyHashTraits<unsigned>> entrypointIndexToArgumentsBlock; 62 63 { 64 m_graph.m_numberOfEntrypoints = m_graph.m_entrypoints.size(); 65 66 BlockInsertionSet blockInsertionSet(m_graph); 67 BasicBlock* newRoot = blockInsertionSet.insert(0, 1.0f); 68 69 EntrySwitchData* entrySwitchData = m_graph.m_entrySwitchData.add(); 70 for (unsigned entrypointIndex = 0; entrypointIndex < m_graph.m_numberOfEntrypoints; ++entrypointIndex) { 71 BasicBlock* oldRoot = m_graph.m_entrypoints[entrypointIndex]; 72 entrypointIndexToArgumentsBlock.add(entrypointIndex, oldRoot); 73 entrySwitchData->cases.append(oldRoot); 74 75 ASSERT(oldRoot->predecessors.isEmpty()); 76 oldRoot->predecessors.append(newRoot); 77 78 if (oldRoot->isCatchEntrypoint) { 79 ASSERT(!!entrypointIndex); 80 m_graph.m_entrypointIndexToCatchBytecodeOffset.add(entrypointIndex, oldRoot->bytecodeBegin); 81 } 82 83 NodeOrigin origin = oldRoot->at(0)->origin; 84 m_insertionSet.insertNode( 85 0, SpecNone, InitializeEntrypointArguments, origin, OpInfo(entrypointIndex)); 86 m_insertionSet.insertNode( 87 0, SpecNone, ExitOK, origin); 88 m_insertionSet.execute(oldRoot); 89 } 90 91 RELEASE_ASSERT(entrySwitchData->cases[0] == m_graph.block(0)); // We strongly assume the normal call entrypoint is the first item in the list. 92 93 m_graph.m_argumentFormats.resize(m_graph.m_numberOfEntrypoints); 94 95 const bool exitOK = false; 96 NodeOrigin origin { CodeOrigin(0), CodeOrigin(0), exitOK }; 97 newRoot->appendNode( 98 m_graph, SpecNone, EntrySwitch, origin, OpInfo(entrySwitchData)); 99 100 m_graph.m_entrypoints.clear(); 101 m_graph.m_entrypoints.append(newRoot); 102 103 blockInsertionSet.execute(); 104 } 105 106 SSACalculator calculator(m_graph); 107 58 108 m_graph.ensureSSADominators(); 59 109 … … 68 118 continue; 69 119 70 SSACalculator::Variable* ssaVariable = m_calculator.newVariable();120 SSACalculator::Variable* ssaVariable = calculator.newVariable(); 71 121 ASSERT(ssaVariable->index() == m_variableForSSAIndex.size()); 72 122 m_variableForSSAIndex.append(&variable); … … 104 154 } 105 155 106 m_calculator.newDef(156 calculator.newDef( 107 157 m_ssaVariableForVariable.get(variable), block, childNode); 108 158 } … … 113 163 // Decide where Phis are to be inserted. This creates the Phi's but doesn't insert them 114 164 // yet. We will later know where to insert based on where SSACalculator tells us to. 115 m_calculator.computePhis(165 calculator.computePhis( 116 166 [&] (SSACalculator::Variable* ssaVariable, BasicBlock* block) -> Node* { 117 167 VariableAccessData* variable = m_variableForSSAIndex[ssaVariable->index()]; … … 168 218 dataLog(" ", i, ": ", VariableAccessDataDump(m_graph, m_variableForSSAIndex[i]), "\n"); 169 219 dataLog("\n"); 170 dataLog("SSA calculator: ", m_calculator, "\n");220 dataLog("SSA calculator: ", calculator, "\n"); 171 221 } 172 222 … … 221 271 222 272 SSACalculator::Variable* ssaVariable = m_ssaVariableForVariable.get(variable); 223 SSACalculator::Def* def = m_calculator.reachingDefAtHead(block, ssaVariable);273 SSACalculator::Def* def = calculator.reachingDefAtHead(block, ssaVariable); 224 274 if (!def) { 225 275 // If we are required to insert a Phi, then we won't have a reaching def … … 247 297 // flushed, we also insert a MovHint. 248 298 size_t phiInsertionPoint = 0; 249 for (SSACalculator::Def* phiDef : m_calculator.phisForBlock(block)) {299 for (SSACalculator::Def* phiDef : calculator.phisForBlock(block)) { 250 300 VariableAccessData* variable = m_variableForSSAIndex[phiDef->variable()->index()]; 251 301 … … 347 397 for (unsigned successorIndex = block->numSuccessors(); successorIndex--;) { 348 398 BasicBlock* successorBlock = block->successor(successorIndex); 349 for (SSACalculator::Def* phiDef : m_calculator.phisForBlock(successorBlock)) {399 for (SSACalculator::Def* phiDef : calculator.phisForBlock(successorBlock)) { 350 400 Node* phiNode = phiDef->value(); 351 401 SSACalculator::Variable* ssaVariable = phiDef->variable(); … … 384 434 } 385 435 386 // FIXME: Support multiple entrypoints in DFG SSA: 387 // https://bugs.webkit.org/show_bug.cgi?id=175396 388 RELEASE_ASSERT(m_graph.m_entrypoints.size() == 1); 389 auto& arguments = m_graph.m_entrypointToArguments.find(m_graph.block(0))->value; 390 m_graph.m_argumentFormats.resize(arguments.size()); 391 for (unsigned i = arguments.size(); i--;) { 392 FlushFormat format = FlushedJSValue; 393 394 Node* node = m_argumentMapping.get(arguments[i]); 395 396 RELEASE_ASSERT(node); 397 format = node->stackAccessData()->format; 398 399 m_graph.m_argumentFormats[i] = format; 400 arguments[i] = node; // Record the load that loads the arguments for the benefit of exit profiling. 401 } 402 436 for (auto& pair : entrypointIndexToArgumentsBlock) { 437 unsigned entrypointIndex = pair.key; 438 BasicBlock* oldRoot = pair.value; 439 ArgumentsVector& arguments = m_graph.m_entrypointToArguments.find(oldRoot)->value; 440 Vector<FlushFormat> argumentFormats; 441 argumentFormats.reserveInitialCapacity(arguments.size()); 442 for (unsigned i = 0; i < arguments.size(); ++i) { 443 Node* node = m_argumentMapping.get(arguments[i]); 444 RELEASE_ASSERT(node); 445 argumentFormats.uncheckedAppend(node->stackAccessData()->format); 446 } 447 m_graph.m_argumentFormats[entrypointIndex] = WTFMove(argumentFormats); 448 } 449 450 m_graph.m_entrypointToArguments.clear(); 451 452 RELEASE_ASSERT(m_graph.m_isInSSAConversion); 453 m_graph.m_isInSSAConversion = false; 454 403 455 m_graph.m_form = SSA; 404 456 … … 412 464 413 465 private: 414 SSACalculator m_calculator;415 466 InsertionSet m_insertionSet; 416 467 HashMap<VariableAccessData*, SSACalculator::Variable*> m_ssaVariableForVariable; … … 422 473 bool performSSAConversion(Graph& graph) 423 474 { 424 RELEASE_ASSERT(!graph.m_isInSSAConversion);425 graph.m_isInSSAConversion = true;426 475 bool result = runPhase<SSAConversionPhase>(graph); 427 RELEASE_ASSERT(graph.m_isInSSAConversion);428 graph.m_isInSSAConversion = false;429 476 return result; 430 477 } -
trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h
r221601 r221602 312 312 case Branch: 313 313 case Switch: 314 case EntrySwitch: 314 315 case Return: 315 316 case TailCall: … … 400 401 case AtomicsXor: 401 402 case AtomicsIsLockFree: 403 case InitializeEntrypointArguments: 402 404 return true; 403 405 -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
r221601 r221602 1932 1932 1933 1933 m_jit.jitCode()->finalizeOSREntrypoints(); 1934 m_jit.jitCode()->common.finalizeCatchEntrypoints(); 1934 1935 1935 1936 ASSERT(osrEntryIndex == m_osrEntryHeads.size()); -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
r221601 r221602 5651 5651 GPRReg payloadGPR = payload.gpr(); 5652 5652 5653 JSValue* ptr = &reinterpret_cast<JSValue*>(m_jit.jitCode()->c atchOSREntryBuffer->dataBuffer())[node->catchOSREntryIndex()];5653 JSValue* ptr = &reinterpret_cast<JSValue*>(m_jit.jitCode()->common.catchOSREntryBuffer->dataBuffer())[node->catchOSREntryIndex()]; 5654 5654 m_jit.move(CCallHelpers::TrustedImmPtr(ptr), tempGPR); 5655 5655 m_jit.load32(CCallHelpers::Address(tempGPR, TagOffset), tagGPR); … … 5704 5704 case AtomicsXor: 5705 5705 case IdentityWithProfile: 5706 case InitializeEntrypointArguments: 5707 case EntrySwitch: 5706 5708 DFG_CRASH(m_jit.graph(), node, "unexpected node in DFG backend"); 5707 5709 break; -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
r221601 r221602 6007 6007 6008 6008 case ExtractCatchLocal: { 6009 JSValue* ptr = &reinterpret_cast<JSValue*>(m_jit.jitCode()->c atchOSREntryBuffer->dataBuffer())[node->catchOSREntryIndex()];6009 JSValue* ptr = &reinterpret_cast<JSValue*>(m_jit.jitCode()->common.catchOSREntryBuffer->dataBuffer())[node->catchOSREntryIndex()]; 6010 6010 GPRTemporary temp(this); 6011 6011 GPRReg tempGPR = temp.gpr(); … … 6114 6114 6115 6115 case LastNodeType: 6116 case EntrySwitch: 6117 case InitializeEntrypointArguments: 6116 6118 case Phi: 6117 6119 case Upsilon: -
trunk/Source/JavaScriptCore/dfg/DFGStaticExecutionCountEstimationPhase.cpp
r221196 r221602 81 81 break; 82 82 } 83 84 case EntrySwitch: { 85 DFG_CRASH(m_graph, terminal, "Unexpected EntrySwitch in CPS form."); 86 break; 87 } 83 88 84 89 default: -
trunk/Source/JavaScriptCore/dfg/DFGValidate.cpp
r221196 r221602 85 85 86 86 VALIDATE((m_graph.block(0)), m_graph.isEntrypoint(m_graph.block(0))); 87 VALIDATE((m_graph.block(0)), m_graph.block(0) == m_graph.m_entrypoints[0]); 88 89 for (BasicBlock* block : m_graph.m_entrypoints) 90 VALIDATE((block), block->predecessors.isEmpty()); 87 91 88 92 // Validate that all local variables at the head of all entrypoints are dead. … … 550 554 case KillStack: 551 555 case GetStack: 556 case EntrySwitch: 557 case InitializeEntrypointArguments: 552 558 VALIDATE((node), !"unexpected node type in CPS"); 553 559 break; … … 640 646 // https://bugs.webkit.org/show_bug.cgi?id=123471 641 647 648 VALIDATE((), m_graph.m_entrypoints.size() == 1); 649 VALIDATE((), m_graph.m_entrypoints[0] == m_graph.block(0)); 650 VALIDATE((), !m_graph.m_argumentFormats.isEmpty()); // We always have at least one entrypoint. 651 652 for (unsigned entrypointIndex : m_graph.m_entrypointIndexToCatchBytecodeOffset.keys()) 653 VALIDATE((), entrypointIndex > 0); // By convention, 0 is the entrypoint index for the op_enter entrypoint, which can not be in a catch. 654 642 655 for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) { 643 656 BasicBlock* block = m_graph.block(blockIndex); … … 741 754 } 742 755 756 case EntrySwitch: 757 VALIDATE((node), node->entrySwitchData()->cases.size() == m_graph.m_numberOfEntrypoints); 758 break; 759 760 case InitializeEntrypointArguments: 761 VALIDATE((node), node->entrypointIndex() < m_graph.m_numberOfEntrypoints); 762 break; 763 743 764 default: 744 765 m_graph.doToChildren( … … 781 802 } 782 803 804 void reportValidationContext() { } 805 783 806 void reportValidationContext(Node* node) 784 807 { -
trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp
r221601 r221602 112 112 case Upsilon: 113 113 case ExtractOSREntryLocal: 114 case ExtractCatchLocal: 114 115 case LoopHint: 115 116 case SkipScope: … … 246 247 case GetMyArgumentByValOutOfBounds: 247 248 case ForwardVarargs: 249 case EntrySwitch: 248 250 case Switch: 249 251 case TypeOf: … … 302 304 case AtomicsXor: 303 305 case AtomicsIsLockFree: 306 case InitializeEntrypointArguments: 304 307 // These are OK. 305 308 break; -
trunk/Source/JavaScriptCore/ftl/FTLCompile.cpp
r221528 r221602 143 143 144 144 state.finalizer->b3CodeLinkBuffer = std::make_unique<LinkBuffer>(jit, codeBlock, JITCompilationCanFail); 145 145 146 if (state.finalizer->b3CodeLinkBuffer->didFailToAllocate()) { 146 147 state.allocationFailed = true; … … 153 154 154 155 state.generatedFunction = bitwise_cast<GeneratedFunction>( 155 state.finalizer->b3CodeLinkBuffer-> entrypoint().executableAddress());156 state.finalizer->b3CodeLinkBuffer->locationOf(state.proc->entrypointLabel(0))); 156 157 state.jitCode->initializeB3Byproducts(state.proc->releaseByproducts()); 158 159 for (auto pair : state.graph.m_entrypointIndexToCatchBytecodeOffset) { 160 unsigned catchBytecodeOffset = pair.value; 161 unsigned entrypointIndex = pair.key; 162 Vector<FlushFormat> argumentFormats = state.graph.m_argumentFormats[entrypointIndex]; 163 state.jitCode->common.appendCatchEntrypoint( 164 catchBytecodeOffset, state.finalizer->b3CodeLinkBuffer->locationOf(state.proc->entrypointLabel(entrypointIndex)).executableAddress(), WTFMove(argumentFormats)); 165 } 166 state.jitCode->common.finalizeCatchEntrypoints(); 157 167 158 168 if (B3::Air::Disassembler* disassembler = state.proc->code().disassembler()) { -
trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
r221601 r221602 29 29 #if ENABLE(FTL_JIT) 30 30 31 #include "AirCode.h" 31 32 #include "AirGenerationContext.h" 32 33 #include "AllowMacroScratchRegisterUsage.h" … … 152 153 } else 153 154 name = "jsBody"; 155 156 { 157 m_proc.setNumEntrypoints(m_graph.m_numberOfEntrypoints); 158 CodeBlock* codeBlock = m_graph.m_codeBlock; 159 160 RefPtr<B3::Air::PrologueGenerator> catchPrologueGenerator = createSharedTask<B3::Air::PrologueGeneratorFunction>( 161 [codeBlock] (CCallHelpers& jit, B3::Air::Code& code) { 162 AllowMacroScratchRegisterUsage allowScratch(jit); 163 jit.addPtr(CCallHelpers::TrustedImm32(-code.frameSize()), GPRInfo::callFrameRegister, CCallHelpers::stackPointerRegister); 164 jit.emitSave(code.calleeSaveRegisterAtOffsetList()); 165 jit.emitPutToCallFrameHeader(codeBlock, CallFrameSlot::codeBlock); 166 }); 167 168 for (unsigned catchEntrypointIndex : m_graph.m_entrypointIndexToCatchBytecodeOffset.keys()) { 169 RELEASE_ASSERT(catchEntrypointIndex != 0); 170 m_proc.code().setPrologueForEntrypoint(catchEntrypointIndex, catchPrologueGenerator); 171 } 172 173 if (m_graph.m_maxLocalsForCatchOSREntry) { 174 uint32_t numberOfLiveLocals = std::max(*m_graph.m_maxLocalsForCatchOSREntry, 1u); // Make sure we always allocate a non-null catchOSREntryBuffer. 175 m_ftlState.jitCode->common.catchOSREntryBuffer = m_graph.m_vm.scratchBufferForSize(sizeof(JSValue) * numberOfLiveLocals); 176 } 177 } 154 178 155 179 m_graph.ensureSSADominators(); … … 163 187 m_out.setFrequency(1); 164 188 165 m_prologue = m_out.newBlock(); 189 LBasicBlock prologue = m_out.newBlock(); 190 LBasicBlock callEntrypointArgumentSpeculations = m_out.newBlock(); 166 191 m_handleExceptions = m_out.newBlock(); 167 192 … … 177 202 m_out.setFrequency(1); 178 203 179 m_out.appendTo( m_prologue, m_handleExceptions);180 m_out.initializeConstants(m_proc, m_prologue);204 m_out.appendTo(prologue, callEntrypointArgumentSpeculations); 205 m_out.initializeConstants(m_proc, prologue); 181 206 createPhiVariables(); 182 207 … … 260 285 261 286 LBasicBlock firstDFGBasicBlock = lowBlock(m_graph.block(0)); 262 // Check Arguments. 263 availabilityMap().clear(); 264 availabilityMap().m_locals = Operands<Availability>(codeBlock()->numParameters(), 0); 265 for (unsigned i = codeBlock()->numParameters(); i--;) { 266 availabilityMap().m_locals.argument(i) = 267 Availability(FlushedAt(FlushedJSValue, virtualRegisterForArgument(i))); 268 } 269 m_node = nullptr; 270 m_origin = NodeOrigin(CodeOrigin(0), CodeOrigin(0), true); 271 auto& arguments = m_graph.m_entrypointToArguments.find(m_graph.block(0))->value; 272 for (unsigned i = codeBlock()->numParameters(); i--;) { 273 Node* node = arguments[i]; 274 m_out.setOrigin(node); 275 VirtualRegister operand = virtualRegisterForArgument(i); 276 277 LValue jsValue = m_out.load64(addressFor(operand)); 278 279 if (node) { 280 DFG_ASSERT(m_graph, node, operand == node->stackAccessData()->machineLocal); 287 288 { 289 Vector<LBasicBlock> successors(m_graph.m_numberOfEntrypoints); 290 successors[0] = callEntrypointArgumentSpeculations; 291 for (unsigned i = 1; i < m_graph.m_numberOfEntrypoints; ++i) { 292 // Currently, the only other entrypoint is an op_catch entrypoint. 293 // We do OSR entry at op_catch, and we prove argument formats before 294 // jumping to FTL code, so we don't need to check argument types here 295 // for these entrypoints. 296 successors[i] = firstDFGBasicBlock; 297 } 298 299 m_out.entrySwitch(successors); 300 m_out.appendTo(callEntrypointArgumentSpeculations, m_handleExceptions); 301 302 m_node = nullptr; 303 m_origin = NodeOrigin(CodeOrigin(0), CodeOrigin(0), true); 304 305 // Check Arguments. 306 availabilityMap().clear(); 307 availabilityMap().m_locals = Operands<Availability>(codeBlock()->numParameters(), 0); 308 for (unsigned i = codeBlock()->numParameters(); i--;) { 309 availabilityMap().m_locals.argument(i) = 310 Availability(FlushedAt(FlushedJSValue, virtualRegisterForArgument(i))); 311 } 312 313 for (unsigned i = codeBlock()->numParameters(); i--;) { 314 MethodOfGettingAValueProfile profile(&m_graph.m_profiledBlock->valueProfileForArgument(i)); 315 VirtualRegister operand = virtualRegisterForArgument(i); 316 LValue jsValue = m_out.load64(addressFor(operand)); 281 317 282 // This is a hack, but it's an effective one. It allows us to do CSE on the 283 // primordial load of arguments. This assumes that the GetLocal that got put in 284 // place of the original SetArgument doesn't have any effects before it. This 285 // should hold true. 286 m_loadedArgumentValues.add(node, jsValue); 318 switch (m_graph.m_argumentFormats[0][i]) { 319 case FlushedInt32: 320 speculate(BadType, jsValueValue(jsValue), profile, isNotInt32(jsValue)); 321 break; 322 case FlushedBoolean: 323 speculate(BadType, jsValueValue(jsValue), profile, isNotBoolean(jsValue)); 324 break; 325 case FlushedCell: 326 speculate(BadType, jsValueValue(jsValue), profile, isNotCell(jsValue)); 327 break; 328 case FlushedJSValue: 329 break; 330 default: 331 DFG_CRASH(m_graph, nullptr, "Bad flush format for argument"); 332 break; 333 } 287 334 } 288 289 switch (m_graph.m_argumentFormats[i]) { 290 case FlushedInt32: 291 speculate(BadType, jsValueValue(jsValue), node, isNotInt32(jsValue)); 292 break; 293 case FlushedBoolean: 294 speculate(BadType, jsValueValue(jsValue), node, isNotBoolean(jsValue)); 295 break; 296 case FlushedCell: 297 speculate(BadType, jsValueValue(jsValue), node, isNotCell(jsValue)); 298 break; 299 case FlushedJSValue: 300 break; 301 default: 302 DFG_CRASH(m_graph, node, "Bad flush format for argument"); 303 break; 304 } 305 } 306 m_out.jump(firstDFGBasicBlock); 335 m_out.jump(firstDFGBasicBlock); 336 } 337 307 338 308 339 m_out.appendTo(m_handleExceptions, firstDFGBasicBlock); … … 513 544 compileExtractOSREntryLocal(); 514 545 break; 546 case ExtractCatchLocal: 547 compileExtractCatchLocal(); 548 break; 515 549 case GetStack: 516 550 compileGetStack(); … … 940 974 case DFG::Switch: 941 975 compileSwitch(); 976 break; 977 case DFG::EntrySwitch: 978 compileEntrySwitch(); 942 979 break; 943 980 case DFG::Return: … … 1156 1193 case BottomValue: 1157 1194 case KillStack: 1195 case InitializeEntrypointArguments: 1158 1196 break; 1159 1197 default: … … 1526 1564 setJSValue(m_out.load64(m_out.absolute(buffer + m_node->unlinkedLocal().toLocal()))); 1527 1565 } 1566 1567 void compileExtractCatchLocal() 1568 { 1569 EncodedJSValue* buffer = static_cast<EncodedJSValue*>(m_ftlState.jitCode->common.catchOSREntryBuffer->dataBuffer()); 1570 setJSValue(m_out.load64(m_out.absolute(buffer + m_node->catchOSREntryIndex()))); 1571 } 1528 1572 1529 1573 void compileGetStack() 1530 1574 { 1531 // GetLocals arise only for captured variables and arguments. For arguments, we might have1532 // already loaded it.1533 if (LValue value = m_loadedArgumentValues.get(m_node)) {1534 setJSValue(value);1535 return;1536 }1537 1538 1575 StackAccessData* data = m_node->stackAccessData(); 1539 1576 AbstractValue& value = m_state.variables().operand(data->local); … … 7791 7828 7792 7829 DFG_CRASH(m_graph, m_node, "Bad switch kind"); 7830 } 7831 7832 void compileEntrySwitch() 7833 { 7834 Vector<LBasicBlock> successors; 7835 for (DFG::BasicBlock* successor : m_node->entrySwitchData()->cases) 7836 successors.append(lowBlock(successor)); 7837 m_out.entrySwitch(successors); 7793 7838 } 7794 7839 … … 12612 12657 appendOSRExit(kind, lowValue, highValue, failCondition, m_origin); 12613 12658 } 12659 12660 void speculate( 12661 ExitKind kind, FormattedValue lowValue, const MethodOfGettingAValueProfile& profile, LValue failCondition) 12662 { 12663 appendOSRExit(kind, lowValue, profile, failCondition, m_origin); 12664 } 12614 12665 12615 12666 void terminate(ExitKind kind) … … 14136 14187 OSRExitDescriptor* appendOSRExitDescriptor(FormattedValue lowValue, Node* highValue) 14137 14188 { 14189 return appendOSRExitDescriptor(lowValue, m_graph.methodOfGettingAValueProfileFor(m_node, highValue)); 14190 } 14191 14192 OSRExitDescriptor* appendOSRExitDescriptor(FormattedValue lowValue, const MethodOfGettingAValueProfile& profile) 14193 { 14138 14194 return &m_ftlState.jitCode->osrExitDescriptors.alloc( 14139 lowValue.format(), m_graph.methodOfGettingAValueProfileFor(m_node, highValue),14195 lowValue.format(), profile, 14140 14196 availabilityMap().m_locals.numberOfArguments(), 14141 14197 availabilityMap().m_locals.numberOfLocals()); 14142 14198 } 14143 14199 14144 14200 void appendOSRExit( 14145 14201 ExitKind kind, FormattedValue lowValue, Node* highValue, LValue failCondition, 14202 NodeOrigin origin, bool isExceptionHandler = false) 14203 { 14204 return appendOSRExit(kind, lowValue, m_graph.methodOfGettingAValueProfileFor(m_node, highValue), 14205 failCondition, origin, isExceptionHandler); 14206 } 14207 14208 void appendOSRExit( 14209 ExitKind kind, FormattedValue lowValue, const MethodOfGettingAValueProfile& profile, LValue failCondition, 14146 14210 NodeOrigin origin, bool isExceptionHandler = false) 14147 14211 { … … 14180 14244 14181 14245 blessSpeculation( 14182 m_out.speculate(failCondition), kind, lowValue, highValue, origin);14246 m_out.speculate(failCondition), kind, lowValue, profile, origin); 14183 14247 } 14184 14248 14185 14249 void blessSpeculation(CheckValue* value, ExitKind kind, FormattedValue lowValue, Node* highValue, NodeOrigin origin) 14186 14250 { 14187 OSRExitDescriptor* exitDescriptor = appendOSRExitDescriptor(lowValue, highValue); 14251 blessSpeculation(value, kind, lowValue, m_graph.methodOfGettingAValueProfileFor(m_node, highValue), origin); 14252 } 14253 14254 void blessSpeculation(CheckValue* value, ExitKind kind, FormattedValue lowValue, const MethodOfGettingAValueProfile& profile, NodeOrigin origin) 14255 { 14256 OSRExitDescriptor* exitDescriptor = appendOSRExitDescriptor(lowValue, profile); 14188 14257 14189 14258 value->appendColdAnys(buildExitArguments(exitDescriptor, origin.forExit, lowValue)); … … 14672 14741 Procedure& m_proc; 14673 14742 14674 LBasicBlock m_prologue;14675 14743 LBasicBlock m_handleExceptions; 14676 14744 HashMap<DFG::BasicBlock*, LBasicBlock> m_blocks; … … 14689 14757 HashMap<Node*, LoweredNodeValue> m_doubleValues; 14690 14758 14691 // This is a bit of a hack. It prevents B3 from having to do CSE on loading of arguments.14692 // It's nice to have these optimizations on our end because we can guarantee them a bit better.14693 // Probably also saves B3 compile time.14694 HashMap<Node*, LValue> m_loadedArgumentValues;14695 14696 14759 HashMap<Node*, LValue> m_phis; 14697 14760 -
trunk/Source/JavaScriptCore/ftl/FTLOutput.cpp
r220625 r221602 862 862 } 863 863 864 void Output::entrySwitch(const Vector<LBasicBlock>& cases) 865 { 866 RELEASE_ASSERT(cases.size() == m_proc.numEntrypoints()); 867 m_block->appendNew<Value>(m_proc, EntrySwitch, origin()); 868 for (LBasicBlock block : cases) 869 m_block->appendSuccessor(FrequentedBlock(block)); 870 } 871 864 872 } } // namespace JSC::FTL 865 873 -
trunk/Source/JavaScriptCore/ftl/FTLOutput.h
r220625 r221602 430 430 } 431 431 432 void entrySwitch(const Vector<LBasicBlock>&); 433 432 434 void ret(LValue); 433 435 -
trunk/Source/JavaScriptCore/jit/JITOperations.cpp
r221196 r221602 43 43 #include "EvalCodeBlock.h" 44 44 #include "ExceptionFuzz.h" 45 #include "FTLOSREntry.h" 45 46 #include "FrameTracers.h" 46 47 #include "FunctionCodeBlock.h" … … 1534 1535 1535 1536 CodeBlock* optimizedReplacement = exec->codeBlock()->replacement(); 1536 if (optimizedReplacement->jitType() != JITCode::DFGJIT) 1537 return nullptr; 1538 1539 return static_cast<char*>(DFG::prepareCatchOSREntry(exec, optimizedReplacement, bytecodeIndex)); 1537 switch (optimizedReplacement->jitType()) { 1538 case JITCode::DFGJIT: 1539 case JITCode::FTLJIT: 1540 return static_cast<char*>(DFG::prepareCatchOSREntry(exec, optimizedReplacement, bytecodeIndex)); 1541 default: 1542 break; 1543 } 1544 return nullptr; 1540 1545 } 1541 1546 … … 1547 1552 CodeBlock* codeBlock = exec->codeBlock(); 1548 1553 CodeBlock* optimizedReplacement = codeBlock->replacement(); 1549 if (optimizedReplacement->jitType() == JITCode::DFGJIT) 1554 1555 switch (optimizedReplacement->jitType()) { 1556 case JITCode::DFGJIT: 1557 case JITCode::FTLJIT: 1550 1558 return static_cast<char*>(DFG::prepareCatchOSREntry(exec, optimizedReplacement, bytecodeIndex)); 1559 default: 1560 break; 1561 } 1551 1562 1552 1563 codeBlock->ensureCatchLivenessIsComputedForBytecodeOffset(bytecodeIndex);
Note: See TracChangeset
for help on using the changeset viewer.