Changeset 232742 in webkit
- Timestamp:
- Jun 11, 2018, 10:05:49 PM (8 years ago)
- Location:
- trunk/Source/JavaScriptCore
- Files:
-
- 4 edited
-
ChangeLog (modified) (1 diff)
-
dfg/DFGByteCodeParser.cpp (modified) (3 diffs)
-
dfg/DFGGraph.cpp (modified) (2 diffs)
-
dfg/DFGGraph.h (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/ChangeLog
r232741 r232742 1 2018-06-11 Saam Barati <sbarati@apple.com> 2 3 Reduce graph size by replacing terminal nodes in blocks that have a ForceOSRExit with Unreachable 4 https://bugs.webkit.org/show_bug.cgi?id=181409 5 <rdar://problem/36383749> 6 7 Reviewed by Keith Miller. 8 9 This patch is me redoing r226655. This is a patch I wrote when 10 profiling Speedometer. Fil rolled this change out in r230928. He 11 showed this slowed down a sunspider tests by ~2x. This sunspider 12 regression revealed a real performance bug in the original change: 13 we would kill blocks that reached OSR entry targets, sometimes leading 14 us to not do OSR entry into the DFG, since we could end up deleting 15 entire loops from the CFG. The reason for this is that code that has run 16 ~once and that reaches loops often has ForceOSRExits inside of it. The 17 solution to this is to not perform this optimization on blocks that can 18 reach OSR entry targets. 19 20 The reason I'm redoing this patch is that it turns out Fil rolling 21 out the change was a Speedometer 2 regression. 22 23 This is a modified version of the original ChangeLog I wrote in r226655: 24 25 When I was looking at profiler data for Speedometer, I noticed that one of 26 the hottest functions in Speedometer is around 1100 bytecode operations long. 27 Only about 100 of those bytecode ops ever execute. However, we ended up 28 spending a lot of time compiling basic blocks that never executed. We often 29 plant ForceOSRExit nodes when we parse bytecodes that have a null value profile. 30 This is the case when such a node never executes. 31 32 This patch makes it so that anytime a block has a ForceOSRExit, and that block 33 can not reach an OSR entry target, we replace its terminal node with an Unreachable 34 node, and remove all nodes after the ForceOSRExit. This cuts down the graph 35 size since it removes control flow edges from the CFG. This allows us to get 36 rid of huge chunks of the CFG in certain programs. When doing this transformation, 37 we also insert Flushes/PhantomLocals to ensure we can recover values that are bytecode 38 live-in to the ForceOSRExit. 39 40 Using ForceOSRExit as the signal for this is a bit of a hack. It definitely 41 does not get rid of all the CFG that it could. If we decide it's worth 42 it, we could use additional inputs into this mechanism. For example, we could 43 profile if a basic block ever executes inside the LLInt/Baseline, and 44 remove parts of the CFG based on that. 45 46 When running Speedometer with the concurrent JIT turned off, this patch 47 improves DFG/FTL compile times by around 5%. 48 49 * dfg/DFGByteCodeParser.cpp: 50 (JSC::DFG::ByteCodeParser::addToGraph): 51 (JSC::DFG::ByteCodeParser::inlineCall): 52 (JSC::DFG::ByteCodeParser::parse): 53 * dfg/DFGGraph.cpp: 54 (JSC::DFG::Graph::blocksInPostOrder): 55 1 56 2018-06-11 Saam Barati <sbarati@apple.com> 2 57 -
trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
r232461 r232742 698 698 { 699 699 VERBOSE_LOG(" appended ", node, " ", Graph::opName(node->op()), "\n"); 700 701 m_hasAnyForceOSRExits |= (node->op() == ForceOSRExit); 702 700 703 m_currentBlock->append(node); 701 704 if (clobbersExitState(m_graph, node)) … … 1151 1154 Instruction* m_currentInstruction; 1152 1155 bool m_hasDebuggerEnabled; 1156 bool m_hasAnyForceOSRExits { false }; 1153 1157 }; 1154 1158 … … 6833 6837 linkBlocks(inlineStackEntry.m_unlinkedBlocks, inlineStackEntry.m_blockLinkingTargets); 6834 6838 6839 if (m_hasAnyForceOSRExits) { 6840 BlockSet blocksToIgnore; 6841 for (BasicBlock* block : m_graph.blocksInNaturalOrder()) { 6842 if (block->isOSRTarget) 6843 blocksToIgnore.add(block); 6844 } 6845 6846 { 6847 bool isSafeToValidate = false; 6848 auto postOrder = m_graph.blocksInPostOrder(isSafeToValidate); // This algorithm doesn't rely on the predecessors list, which is not yet built. 6849 bool changed; 6850 do { 6851 changed = false; 6852 for (BasicBlock* block : postOrder) { 6853 for (BasicBlock* successor : block->successors()) { 6854 if (blocksToIgnore.contains(successor)) { 6855 changed |= blocksToIgnore.add(block); 6856 break; 6857 } 6858 } 6859 } 6860 } while (changed); 6861 } 6862 6863 InsertionSet insertionSet(m_graph); 6864 Operands<VariableAccessData*> mapping(OperandsLike, m_graph.block(0)->variablesAtHead); 6865 6866 for (BasicBlock* block : m_graph.blocksInNaturalOrder()) { 6867 if (blocksToIgnore.contains(block)) 6868 continue; 6869 6870 mapping.fill(nullptr); 6871 if (validationEnabled()) { 6872 // Verify that it's correct to fill mapping with nullptr. 6873 for (unsigned i = 0; i < block->variablesAtHead.size(); ++i) { 6874 Node* node = block->variablesAtHead.at(i); 6875 RELEASE_ASSERT(!node); 6876 } 6877 } 6878 6879 for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) { 6880 Node* node = block->at(nodeIndex); 6881 6882 if (node->hasVariableAccessData(m_graph)) 6883 mapping.operand(node->local()) = node->variableAccessData(); 6884 6885 if (node->op() == ForceOSRExit) { 6886 NodeOrigin endOrigin = node->origin.withExitOK(true); 6887 6888 if (validationEnabled()) { 6889 // This verifies that we don't need to change any of the successors's predecessor 6890 // list after planting the Unreachable below. At this point in the bytecode 6891 // parser, we haven't linked up the predecessor lists yet. 6892 for (BasicBlock* successor : block->successors()) 6893 RELEASE_ASSERT(successor->predecessors.isEmpty()); 6894 } 6895 6896 block->resize(nodeIndex + 1); 6897 6898 insertionSet.insertNode(block->size(), SpecNone, ExitOK, endOrigin); 6899 6900 auto insertLivenessPreservingOp = [&] (InlineCallFrame* inlineCallFrame, NodeType op, VirtualRegister operand) { 6901 VariableAccessData* variable = mapping.operand(operand); 6902 if (!variable) { 6903 variable = newVariableAccessData(operand); 6904 mapping.operand(operand) = variable; 6905 } 6906 6907 VirtualRegister argument = operand - (inlineCallFrame ? inlineCallFrame->stackOffset : 0); 6908 if (argument.isArgument() && !argument.isHeader()) { 6909 const Vector<ArgumentPosition*>& arguments = m_inlineCallFrameToArgumentPositions.get(inlineCallFrame); 6910 arguments[argument.toArgument()]->addVariable(variable); 6911 } 6912 6913 insertionSet.insertNode(block->size(), SpecNone, op, endOrigin, OpInfo(variable)); 6914 }; 6915 auto addFlushDirect = [&] (InlineCallFrame* inlineCallFrame, VirtualRegister operand) { 6916 insertLivenessPreservingOp(inlineCallFrame, Flush, operand); 6917 }; 6918 auto addPhantomLocalDirect = [&] (InlineCallFrame* inlineCallFrame, VirtualRegister operand) { 6919 insertLivenessPreservingOp(inlineCallFrame, PhantomLocal, operand); 6920 }; 6921 flushForTerminalImpl(endOrigin.semantic, addFlushDirect, addPhantomLocalDirect); 6922 6923 insertionSet.insertNode(block->size(), SpecNone, Unreachable, endOrigin); 6924 insertionSet.execute(block); 6925 break; 6926 } 6927 } 6928 } 6929 } else if (validationEnabled()) { 6930 // Ensure our bookkeeping for ForceOSRExit nodes is working. 6931 for (BasicBlock* block : m_graph.blocksInNaturalOrder()) { 6932 for (Node* node : *block) 6933 RELEASE_ASSERT(node->op() != ForceOSRExit); 6934 } 6935 } 6936 6835 6937 m_graph.determineReachability(); 6836 6938 m_graph.killUnreachableBlocks(); -
trunk/Source/JavaScriptCore/dfg/DFGGraph.cpp
r232741 r232742 913 913 } 914 914 915 BlockList Graph::blocksInPostOrder( )915 BlockList Graph::blocksInPostOrder(bool isSafeToValidate) 916 916 { 917 917 BlockList result; … … 932 932 } 933 933 934 if ( validationEnabled()) {934 if (isSafeToValidate && validationEnabled()) { // There are users of this where we haven't yet built of the CFG enough to be able to run dominators. 935 935 auto validateResults = [&] (auto& dominators) { 936 936 // When iterating over reverse post order, we should see dominators -
trunk/Source/JavaScriptCore/dfg/DFGGraph.h
r232000 r232742 628 628 629 629 BlockList blocksInPreOrder(); 630 BlockList blocksInPostOrder( );630 BlockList blocksInPostOrder(bool isSafeToValidate = true); 631 631 632 632 class NaturalBlockIterable {
Note:
See TracChangeset
for help on using the changeset viewer.