From 4e6b3a206fa4ad8bb0b664f7674c9a70376d6e26 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Mon, 16 Jul 2012 14:51:15 +0200 Subject: Imported WebKit commit 953baa67aa07087b6ecd4199351ec554c724e27d (http://svn.webkit.org/repository/webkit/trunk@122676) --- .../JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp | 227 ++++++++++++++------- 1 file changed, 153 insertions(+), 74 deletions(-) (limited to 'Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp') diff --git a/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp b/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp index d3029b39a..a8eb9ee5c 100644 --- a/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp @@ -40,6 +40,7 @@ class ConstantFoldingPhase : public Phase { public: ConstantFoldingPhase(Graph& graph) : Phase(graph, "constant folding") + , m_state(graph) { } @@ -47,114 +48,192 @@ public: { bool changed = false; - AbstractState state(m_graph); - InsertionSet insertionSet; - for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) { BasicBlock* block = m_graph.m_blocks[blockIndex].get(); if (!block) continue; - if (!block->cfaFoundConstants) - continue; + if (!block->cfaDidFinish) + changed |= paintUnreachableCode(blockIndex); + if (block->cfaFoundConstants) + changed |= foldConstants(blockIndex); + } + + return changed; + } + +private: + bool foldConstants(BlockIndex blockIndex) + { #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) - dataLog("Constant folding considering Block #%u.\n", blockIndex); + dataLog("Constant folding considering Block #%u.\n", blockIndex); #endif - state.beginBasicBlock(block); - for (unsigned indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) { - if (!state.isValid()) - break; - NodeIndex nodeIndex = block->at(indexInBlock); - Node& node = m_graph[nodeIndex]; + BasicBlock* block = m_graph.m_blocks[blockIndex].get(); + bool changed = false; + m_state.beginBasicBlock(block); + for (unsigned indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) { + NodeIndex nodeIndex = block->at(indexInBlock); + Node& node = m_graph[nodeIndex]; - bool eliminated = false; + if (!m_state.isValid()) + break; + + bool eliminated = false; - switch (node.op()) { - case CheckArgumentsNotCreated: { - if (!isEmptySpeculation( - state.variables().operand( - m_graph.argumentsRegisterFor(node.codeOrigin)).m_type)) - break; - ASSERT(node.refCount() == 1); - node.setOpAndDefaultFlags(Phantom); - eliminated = true; + switch (node.op()) { + case CheckArgumentsNotCreated: { + if (!isEmptySpeculation( + m_state.variables().operand( + m_graph.argumentsRegisterFor(node.codeOrigin)).m_type)) break; - } + ASSERT(node.refCount() == 1); + node.setOpAndDefaultFlags(Phantom); + eliminated = true; + break; + } // FIXME: This would be a great place to remove CheckStructure's. - default: - break; - } + default: + break; + } - if (eliminated) { - changed = true; - continue; - } + if (eliminated) { + changed = true; + continue; + } - state.execute(indexInBlock); - if (!node.shouldGenerate() - || state.didClobber() - || node.hasConstant()) - continue; - JSValue value = state.forNode(nodeIndex).value(); - if (!value) - continue; + m_state.execute(indexInBlock); + if (!node.shouldGenerate() + || m_state.didClobber() + || node.hasConstant()) + continue; + JSValue value = m_state.forNode(nodeIndex).value(); + if (!value) + continue; - Node phantom(Phantom, node.codeOrigin); + Node phantom(Phantom, node.codeOrigin); - if (node.op() == GetLocal) { - NodeIndex previousLocalAccess = NoNode; - if (block->variablesAtHead.operand(node.local()) == nodeIndex - && m_graph[node.child1()].op() == Phi) { - // We expect this to be the common case. - ASSERT(block->isInPhis(node.child1().index())); - previousLocalAccess = node.child1().index(); - block->variablesAtHead.operand(node.local()) = previousLocalAccess; - } else { - ASSERT(indexInBlock > 0); - // Must search for the previous access to this local. - for (BlockIndex subIndexInBlock = indexInBlock; subIndexInBlock--;) { - NodeIndex subNodeIndex = block->at(subIndexInBlock); - Node& subNode = m_graph[subNodeIndex]; - if (!subNode.shouldGenerate()) - continue; - if (!subNode.hasVariableAccessData()) + if (node.op() == GetLocal) { + NodeIndex previousLocalAccess = NoNode; + if (block->variablesAtHead.operand(node.local()) == nodeIndex + && m_graph[node.child1()].op() == Phi) { + // We expect this to be the common case. + ASSERT(block->isInPhis(node.child1().index())); + previousLocalAccess = node.child1().index(); + block->variablesAtHead.operand(node.local()) = previousLocalAccess; + } else { + ASSERT(indexInBlock > 0); + // Must search for the previous access to this local. + for (BlockIndex subIndexInBlock = indexInBlock; subIndexInBlock--;) { + NodeIndex subNodeIndex = block->at(subIndexInBlock); + Node& subNode = m_graph[subNodeIndex]; + if (!subNode.shouldGenerate()) + continue; + if (!subNode.hasVariableAccessData()) + continue; + if (subNode.local() != node.local()) + continue; + // The two must have been unified. + ASSERT(subNode.variableAccessData() == node.variableAccessData()); + previousLocalAccess = subNodeIndex; + break; + } + if (previousLocalAccess == NoNode) { + // The previous access must have been a Phi. + for (BlockIndex phiIndexInBlock = block->phis.size(); phiIndexInBlock--;) { + NodeIndex phiNodeIndex = block->phis[phiIndexInBlock]; + Node& phiNode = m_graph[phiNodeIndex]; + if (!phiNode.shouldGenerate()) continue; - if (subNode.local() != node.local()) + if (phiNode.local() != node.local()) continue; // The two must have been unified. - ASSERT(subNode.variableAccessData() == node.variableAccessData()); - previousLocalAccess = subNodeIndex; + ASSERT(phiNode.variableAccessData() == node.variableAccessData()); + previousLocalAccess = phiNodeIndex; break; } ASSERT(previousLocalAccess != NoNode); } + } - NodeIndex tailNodeIndex = block->variablesAtTail.operand(node.local()); - if (tailNodeIndex == nodeIndex) - block->variablesAtTail.operand(node.local()) = previousLocalAccess; - else { - ASSERT(m_graph[tailNodeIndex].op() == Flush - || m_graph[tailNodeIndex].op() == SetLocal); - } + ASSERT(previousLocalAccess != NoNode); + + NodeIndex tailNodeIndex = block->variablesAtTail.operand(node.local()); + if (tailNodeIndex == nodeIndex) + block->variablesAtTail.operand(node.local()) = previousLocalAccess; + else { + ASSERT(m_graph[tailNodeIndex].op() == Flush + || m_graph[tailNodeIndex].op() == SetLocal); } + } - phantom.children = node.children; - phantom.ref(); + phantom.children = node.children; + phantom.ref(); + + m_graph.convertToConstant(nodeIndex, value); + NodeIndex phantomNodeIndex = m_graph.size(); + m_graph.append(phantom); + m_insertionSet.append(indexInBlock, phantomNodeIndex); - m_graph.convertToConstant(nodeIndex, value); - NodeIndex phantomNodeIndex = m_graph.size(); - m_graph.append(phantom); - insertionSet.append(indexInBlock, phantomNodeIndex); + changed = true; + } + m_state.reset(); + m_insertionSet.execute(*block); + + return changed; + } + + // This is necessary because the CFA may reach conclusions about constants based on its + // assumption that certain code must exit, but then those constants may lead future + // reexecutions of the CFA to believe that the same code will now no longer exit. Thus + // to ensure soundness, we must paint unreachable code as such, by inserting an + // unconditional ForceOSRExit wherever we find that a node would have always exited. + // This will only happen in cases where we are making static speculations, or we're + // making totally wrong speculations due to imprecision on the prediction propagator. + bool paintUnreachableCode(BlockIndex blockIndex) + { + bool changed = false; + +#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) + dataLog("Painting unreachable code in Block #%u.\n", blockIndex); +#endif + BasicBlock* block = m_graph.m_blocks[blockIndex].get(); + m_state.beginBasicBlock(block); + + for (unsigned indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) { + m_state.execute(indexInBlock); + if (m_state.isValid()) + continue; + + NodeIndex nodeIndex = block->at(indexInBlock); + Node& node = m_graph[nodeIndex]; + switch (node.op()) { + case Return: + case Throw: + case ThrowReferenceError: + case ForceOSRExit: + // Do nothing. These nodes will already do the right thing. + break; + default: + Node forceOSRExit(ForceOSRExit, node.codeOrigin); + forceOSRExit.ref(); + NodeIndex forceOSRExitIndex = m_graph.size(); + m_graph.append(forceOSRExit); + m_insertionSet.append(indexInBlock, forceOSRExitIndex); changed = true; + break; } - insertionSet.execute(*block); - state.reset(); + break; } + m_state.reset(); + m_insertionSet.execute(*block); return changed; } + + AbstractState m_state; + InsertionSet m_insertionSet; }; bool performConstantFolding(Graph& graph) -- cgit v1.2.1