Modified: branches/safari-605-branch/Source/_javascript_Core/ChangeLog (226862 => 226863)
--- branches/safari-605-branch/Source/_javascript_Core/ChangeLog 2018-01-12 05:29:01 UTC (rev 226862)
+++ branches/safari-605-branch/Source/_javascript_Core/ChangeLog 2018-01-12 06:30:35 UTC (rev 226863)
@@ -1,5 +1,44 @@
2018-01-11 Jason Marcell <jmarc...@apple.com>
+ Cherry-pick r226655. rdar://problem/36450822
+
+ 2018-01-09 Saam Barati <sbar...@apple.com>
+
+ Reduce graph size by replacing terminal nodes in blocks that have a ForceOSRExit with Unreachable
+ https://bugs.webkit.org/show_bug.cgi?id=181409
+
+ Reviewed by Keith Miller.
+
+ When I was looking at profiler data for Speedometer, I noticed that one of
+ the hottest functions in Speedometer is around 1100 bytecode operations long.
+ Only about 100 of those bytecode ops ever execute. However, we ended up
+ spending a lot of time compiling basic blocks that never executed. We often
+ plant ForceOSRExit nodes when we parse bytecodes that have a null value profile.
+ This is the case when such a node never executes.
+
+ This patch makes it so that anytime a block has a ForceOSRExit, we replace its
+ terminal node with an Unreachable node (and remove all nodes after the
+ ForceOSRExit). This will cut down on graph size when such a block dominates
+ other blocks in the CFG. This allows us to get rid of huge chunks of the CFG
+ in certain programs. When doing this transformation, we also insert
+ Flushes/PhantomLocals to ensure we can recover values that are bytecode
+ live-in to the ForceOSRExit.
+
+ Using ForceOSRExit as the signal for this is a bit of a hack. It definitely
+ does not get rid of all the CFG that it could. If we decide it's worth
+ it, we could use additional inputs into this mechanism. For example, we could
+ profile if a basic block ever executes inside the LLInt/Baseline, and
+ remove parts of the CFG based on that.
+
+ When running Speedometer with the concurrent JIT turned off, this patch
+ improves DFG/FTL compile times by around 5%.
+
+ * dfg/DFGByteCodeParser.cpp:
+ (JSC::DFG::ByteCodeParser::addToGraph):
+ (JSC::DFG::ByteCodeParser::parse):
+
+2018-01-11 Jason Marcell <jmarc...@apple.com>
+
Cherry-pick r226650. rdar://problem/36429150
2018-01-09 Mark Lam <mark....@apple.com>
Modified: branches/safari-605-branch/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp (226862 => 226863)
--- branches/safari-605-branch/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp 2018-01-12 05:29:01 UTC (rev 226862)
+++ branches/safari-605-branch/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp 2018-01-12 06:30:35 UTC (rev 226863)
@@ -694,7 +694,10 @@
Node* addToGraph(Node* node)
{
+ m_hasAnyForceOSRExits |= (node->op() == ForceOSRExit);
+
VERBOSE_LOG(" appended ", node, " ", Graph::opName(node->op()), "\n");
+
m_currentBlock->append(node);
if (clobbersExitState(m_graph, node))
m_exitOK = false;
@@ -1141,6 +1144,7 @@
Instruction* m_currentInstruction;
bool m_hasDebuggerEnabled;
+ bool m_hasAnyForceOSRExits { false };
};
BasicBlock* ByteCodeParser::allocateTargetableBlock(unsigned bytecodeIndex)
@@ -6559,6 +6563,67 @@
parseCodeBlock();
linkBlocks(inlineStackEntry.m_unlinkedBlocks, inlineStackEntry.m_blockLinkingTargets);
+ if (m_hasAnyForceOSRExits) {
+ InsertionSet insertionSet(m_graph);
+ Operands<VariableAccessData*> mapping(OperandsLike, m_graph.block(0)->variablesAtHead);
+
+ for (BasicBlock* block : m_graph.blocksInNaturalOrder()) {
+ mapping.fill(nullptr);
+ if (validationEnabled()) {
+ // Verify that it's correct to fill mapping with nullptr.
+ for (unsigned i = 0; i < block->variablesAtHead.size(); ++i) {
+ Node* node = block->variablesAtHead.at(i);
+ RELEASE_ASSERT(!node);
+ }
+ }
+
+ for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) {
+ Node* node = block->at(nodeIndex);
+
+ if (node->hasVariableAccessData(m_graph))
+ mapping.operand(node->local()) = node->variableAccessData();
+
+ if (node->op() == ForceOSRExit) {
+ NodeOrigin endOrigin = node->origin.withExitOK(true);
+
+ if (validationEnabled()) {
+ // This verifies that we don't need to change any of the successors's predecessor
+ // list after planting the Unreachable below. At this point in the bytecode
+ // parser, we haven't linked up the predecessor lists yet.
+ for (BasicBlock* successor : block->successors())
+ RELEASE_ASSERT(successor->predecessors.isEmpty());
+ }
+
+ block->resize(nodeIndex + 1);
+
+ insertionSet.insertNode(block->size(), SpecNone, ExitOK, endOrigin);
+ m_graph.forAllLiveInBytecode(endOrigin.semantic, [&] (VirtualRegister operand) {
+ VariableAccessData* variable = mapping.operand(operand);
+ if (!variable)
+ variable = newVariableAccessData(operand);
+
+ auto op = PhantomLocal;
+ if ((m_graph.needsScopeRegister() && operand == m_codeBlock->scopeRegister())
+ || (operand.isArgument() && (operand != virtualRegisterForArgument(0) || m_graph.needsFlushedThis()))) {
+ op = Flush;
+ }
+ insertionSet.insertNode(block->size(), SpecNone, op, endOrigin, OpInfo(variable));
+ });
+
+ insertionSet.insertNode(block->size(), SpecNone, Unreachable, endOrigin);
+ insertionSet.execute(block);
+ break;
+ }
+ }
+ }
+ } else if (validationEnabled()) {
+ // Ensure our bookkeeping for ForceOSRExit nodes is working.
+ for (BasicBlock* block : m_graph.blocksInNaturalOrder()) {
+ for (Node* node : *block)
+ RELEASE_ASSERT(node->op() != ForceOSRExit);
+ }
+ }
+
m_graph.determineReachability();
m_graph.killUnreachableBlocks();