Changeset 243176 in webkit
- Timestamp:
- Mar 19, 2019, 3:53:40 PM (7 years ago)
- Location:
- trunk/Source/JavaScriptCore
- Files:
-
- 2 edited
-
ChangeLog (modified) (1 diff)
-
dfg/DFGByteCodeParser.cpp (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/ChangeLog
r243163 r243176 1 2019-03-19 Saam barati <sbarati@apple.com> 2 3 Prune code after ForceOSRExit 4 https://bugs.webkit.org/show_bug.cgi?id=195913 5 6 Reviewed by Keith Miller. 7 8 I removed our original implementation of this in r242989 because 9 it was not sound. It broke backwards propagation because it removed 10 uses of a node that backwards propagation relied on to be sound. 11 Essentially, backwards propagation relies on being able to see uses 12 that would exist in bytecode to be sound. 13 14 The rollout in r242989 was a 1% Speedometer2 regression. This patch 15 rolls back in the optimization in a sound way. 16 17 This patch augments the code we had prior to r242989 to be sound. In 18 addition to preserving liveness, we now also convert all uses after 19 the ForceOSRExit to be Phantom. This may pessimize the optimizations 20 we do in backwards propagation, but it will prevent that phase from 21 making unsound optimizations. 22 23 * dfg/DFGByteCodeParser.cpp: 24 (JSC::DFG::ByteCodeParser::addToGraph): 25 (JSC::DFG::ByteCodeParser::parse): 26 1 27 2019-03-19 Michael Catanzaro <mcatanzaro@igalia.com> 2 28 -
trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
r242989 r243176 716 716 VERBOSE_LOG(" appended ", node, " ", Graph::opName(node->op()), "\n"); 717 717 718 m_hasAnyForceOSRExits |= (node->op() == ForceOSRExit); 719 718 720 m_currentBlock->append(node); 719 721 if (clobbersExitState(m_graph, node)) … … 1177 1179 const Instruction* m_currentInstruction; 1178 1180 bool m_hasDebuggerEnabled; 1181 bool m_hasAnyForceOSRExits { false }; 1179 1182 }; 1180 1183 … … 7285 7288 linkBlocks(inlineStackEntry.m_unlinkedBlocks, inlineStackEntry.m_blockLinkingTargets); 7286 7289 7290 if (m_hasAnyForceOSRExits) { 7291 BlockSet blocksToIgnore; 7292 for (BasicBlock* block : m_graph.blocksInNaturalOrder()) { 7293 if (block->isOSRTarget && block->bytecodeBegin == m_graph.m_plan.osrEntryBytecodeIndex()) { 7294 blocksToIgnore.add(block); 7295 break; 7296 } 7297 } 7298 7299 { 7300 bool isSafeToValidate = false; 7301 auto postOrder = m_graph.blocksInPostOrder(isSafeToValidate); // This algorithm doesn't rely on the predecessors list, which is not yet built. 7302 bool changed; 7303 do { 7304 changed = false; 7305 for (BasicBlock* block : postOrder) { 7306 for (BasicBlock* successor : block->successors()) { 7307 if (blocksToIgnore.contains(successor)) { 7308 changed |= blocksToIgnore.add(block); 7309 break; 7310 } 7311 } 7312 } 7313 } while (changed); 7314 } 7315 7316 InsertionSet insertionSet(m_graph); 7317 Operands<VariableAccessData*> mapping(OperandsLike, m_graph.block(0)->variablesAtHead); 7318 7319 for (BasicBlock* block : m_graph.blocksInNaturalOrder()) { 7320 if (blocksToIgnore.contains(block)) 7321 continue; 7322 7323 mapping.fill(nullptr); 7324 if (validationEnabled()) { 7325 // Verify that it's correct to fill mapping with nullptr. 7326 for (unsigned i = 0; i < block->variablesAtHead.size(); ++i) { 7327 Node* node = block->variablesAtHead.at(i); 7328 RELEASE_ASSERT(!node); 7329 } 7330 } 7331 7332 for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) { 7333 { 7334 Node* node = block->at(nodeIndex); 7335 7336 if (node->hasVariableAccessData(m_graph)) 7337 mapping.operand(node->local()) = node->variableAccessData(); 7338 7339 if (node->op() != ForceOSRExit) 7340 continue; 7341 } 7342 7343 NodeOrigin origin = block->at(nodeIndex)->origin; 7344 RELEASE_ASSERT(origin.exitOK); 7345 7346 ++nodeIndex; 7347 7348 { 7349 if (validationEnabled()) { 7350 // This verifies that we don't need to change any of the successors's predecessor 7351 // list after planting the Unreachable below. At this point in the bytecode 7352 // parser, we haven't linked up the predecessor lists yet. 7353 for (BasicBlock* successor : block->successors()) 7354 RELEASE_ASSERT(successor->predecessors.isEmpty()); 7355 } 7356 7357 auto insertLivenessPreservingOp = [&] (InlineCallFrame* inlineCallFrame, NodeType op, VirtualRegister operand) { 7358 VariableAccessData* variable = mapping.operand(operand); 7359 if (!variable) { 7360 variable = newVariableAccessData(operand); 7361 mapping.operand(operand) = variable; 7362 } 7363 7364 VirtualRegister argument = operand - (inlineCallFrame ? inlineCallFrame->stackOffset : 0); 7365 if (argument.isArgument() && !argument.isHeader()) { 7366 const Vector<ArgumentPosition*>& arguments = m_inlineCallFrameToArgumentPositions.get(inlineCallFrame); 7367 arguments[argument.toArgument()]->addVariable(variable); 7368 } 7369 insertionSet.insertNode(nodeIndex, SpecNone, op, origin, OpInfo(variable)); 7370 }; 7371 auto addFlushDirect = [&] (InlineCallFrame* inlineCallFrame, VirtualRegister operand) { 7372 insertLivenessPreservingOp(inlineCallFrame, Flush, operand); 7373 }; 7374 auto addPhantomLocalDirect = [&] (InlineCallFrame* inlineCallFrame, VirtualRegister operand) { 7375 insertLivenessPreservingOp(inlineCallFrame, PhantomLocal, operand); 7376 }; 7377 flushForTerminalImpl(origin.semantic, addFlushDirect, addPhantomLocalDirect); 7378 } 7379 7380 while (true) { 7381 RELEASE_ASSERT(nodeIndex < block->size()); 7382 7383 Node* node = block->at(nodeIndex); 7384 7385 node->origin = origin; 7386 m_graph.doToChildren(node, [&] (Edge edge) { 7387 // We only need to keep data flow edges to nodes defined prior to the ForceOSRExit. The reason 7388 // for this is we rely on backwards propagation being able to see the "full" bytecode. To model 7389 // this, we preserve uses of a node in a generic way so that backwards propagation can reason 7390 // about them. Therefore, we can't remove uses of a node which is defined before the ForceOSRExit 7391 // even when we're at a point in the program after the ForceOSRExit, because that would break backwards 7392 // propagation's analysis over the uses of a node. However, we don't need this same preservation for 7393 // nodes defined after ForceOSRExit, as we've already exitted before those defs. 7394 if (edge->hasResult()) 7395 insertionSet.insertNode(nodeIndex, SpecNone, Phantom, origin, Edge(edge.node(), UntypedUse)); 7396 }); 7397 7398 bool isTerminal = node->isTerminal(); 7399 7400 node->removeWithoutChecks(); 7401 7402 if (isTerminal) { 7403 insertionSet.insertNode(nodeIndex, SpecNone, Unreachable, origin); 7404 break; 7405 } 7406 7407 ++nodeIndex; 7408 } 7409 7410 insertionSet.execute(block); 7411 7412 auto nodeAndIndex = block->findTerminal(); 7413 RELEASE_ASSERT(nodeAndIndex.node->op() == Unreachable); 7414 block->resize(nodeAndIndex.index + 1); 7415 break; 7416 } 7417 } 7418 } else if (validationEnabled()) { 7419 // Ensure our bookkeeping for ForceOSRExit nodes is working. 7420 for (BasicBlock* block : m_graph.blocksInNaturalOrder()) { 7421 for (Node* node : *block) 7422 RELEASE_ASSERT(node->op() != ForceOSRExit); 7423 } 7424 } 7425 7287 7426 m_graph.determineReachability(); 7288 7427 m_graph.killUnreachableBlocks();
Note:
See TracChangeset
for help on using the changeset viewer.