summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@digia.com>2013-09-13 12:51:20 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-09-19 20:50:05 +0200
commitd441d6f39bb846989d95bcf5caf387b42414718d (patch)
treee367e64a75991c554930278175d403c072de6bb8 /Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp
parent0060b2994c07842f4c59de64b5e3e430525c4b90 (diff)
downloadqtwebkit-d441d6f39bb846989d95bcf5caf387b42414718d.tar.gz
Import Qt5x2 branch of QtWebkit for Qt 5.2
Importing a new snapshot of webkit. Change-Id: I2d01ad12cdc8af8cb015387641120a9d7ea5f10c Reviewed-by: Allan Sandfeld Jensen <allan.jensen@digia.com>
Diffstat (limited to 'Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp')
-rw-r--r--Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp466
1 files changed, 47 insertions, 419 deletions
diff --git a/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp b/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp
index 52cebf80f..c022fce2b 100644
--- a/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2012, 2013 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -29,11 +29,12 @@
#if ENABLE(DFG_JIT)
#include "DFGAbstractState.h"
-#include "DFGBasicBlock.h"
+#include "DFGBasicBlockInlines.h"
#include "DFGGraph.h"
#include "DFGInsertionSet.h"
#include "DFGPhase.h"
#include "DFGValidate.h"
+#include "Operations.h"
namespace JSC { namespace DFG {
@@ -59,7 +60,7 @@ public:
continue;
ASSERT(block->isReachable);
- switch (m_graph[block->last()].op()) {
+ switch (block->last()->op()) {
case Jump: {
// Successor with one predecessor -> merge.
if (m_graph.m_blocks[m_graph.successor(block, 0)]->m_predecessors.size() == 1) {
@@ -71,6 +72,7 @@ public:
#endif
if (extremeLogging)
m_graph.dump();
+ m_graph.dethread();
mergeBlocks(blockIndex, m_graph.successor(block, 0), NoBlock);
innerChanged = outerChanged = true;
break;
@@ -112,6 +114,7 @@ public:
#endif
if (extremeLogging)
m_graph.dump();
+ m_graph.dethread();
mergeBlocks(
blockIndex,
m_graph.successorForCondition(block, condition),
@@ -125,21 +128,20 @@ public:
#endif
if (extremeLogging)
m_graph.dump();
+ m_graph.dethread();
BlockIndex takenBlockIndex = m_graph.successorForCondition(block, condition);
BlockIndex notTakenBlockIndex = m_graph.successorForCondition(block, !condition);
- ASSERT(m_graph[block->last()].isTerminal());
- CodeOrigin boundaryCodeOrigin = m_graph[block->last()].codeOrigin;
- m_graph[block->last()].setOpAndDefaultFlags(Phantom);
- ASSERT(m_graph[block->last()].refCount() == 1);
+ ASSERT(block->last()->isTerminal());
+ CodeOrigin boundaryCodeOrigin = block->last()->codeOrigin;
+ block->last()->convertToPhantom();
+ ASSERT(block->last()->refCount() == 1);
jettisonBlock(blockIndex, notTakenBlockIndex, boundaryCodeOrigin);
- NodeIndex jumpNodeIndex = m_graph.size();
- Node jump(Jump, boundaryCodeOrigin, OpInfo(takenBlockIndex));
- jump.ref();
- m_graph.append(jump);
- block->append(jumpNodeIndex);
+ block->appendNode(
+ m_graph, SpecNone, Jump, boundaryCodeOrigin,
+ OpInfo(takenBlockIndex));
}
innerChanged = outerChanged = true;
break;
@@ -155,24 +157,22 @@ public:
dataLogF("CFGSimplify: Branch to same successor merge on Block #%u to Block #%u.\n",
blockIndex, targetBlockIndex);
#endif
+ m_graph.dethread();
mergeBlocks(blockIndex, targetBlockIndex, NoBlock);
} else {
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
dataLogF("CFGSimplify: Branch->jump conversion to same successor on Block #%u to Block #%u.\n",
blockIndex, targetBlockIndex);
#endif
- ASSERT(m_graph[block->last()].isTerminal());
- Node& branch = m_graph[block->last()];
- ASSERT(branch.isTerminal());
- ASSERT(branch.op() == Branch);
- branch.setOpAndDefaultFlags(Phantom);
- ASSERT(branch.refCount() == 1);
+ Node* branch = block->last();
+ ASSERT(branch->isTerminal());
+ ASSERT(branch->op() == Branch);
+ branch->convertToPhantom();
+ ASSERT(branch->refCount() == 1);
- Node jump(Jump, branch.codeOrigin, OpInfo(targetBlockIndex));
- jump.ref();
- NodeIndex jumpNodeIndex = m_graph.size();
- m_graph.append(jump);
- block->append(jumpNodeIndex);
+ block->appendNode(
+ m_graph, SpecNone, Jump, branch->codeOrigin,
+ OpInfo(targetBlockIndex));
}
innerChanged = outerChanged = true;
break;
@@ -239,7 +239,8 @@ public:
}
}
- validate(m_graph);
+ if (Options::validateGraphAtEachPhase())
+ validate(m_graph);
} while (innerChanged);
return outerChanged;
@@ -253,109 +254,24 @@ private:
ASSERT(block);
ASSERT(!block->isReachable);
- // 1) Remove references from other blocks to this block.
- for (unsigned i = m_graph.numSuccessors(block); i--;)
- fixPhis(blockIndex, m_graph.successor(block, i));
+ for (unsigned phiIndex = block->phis.size(); phiIndex--;)
+ m_graph.m_allocator.free(block->phis[phiIndex]);
+ for (unsigned nodeIndex = block->size(); nodeIndex--;)
+ m_graph.m_allocator.free(block->at(nodeIndex));
- // 2) Kill the block
m_graph.m_blocks[blockIndex].clear();
}
- void keepOperandAlive(BasicBlock* block, CodeOrigin codeOrigin, int operand)
+ void keepOperandAlive(BasicBlock* block, BasicBlock* jettisonedBlock, CodeOrigin codeOrigin, int operand)
{
- NodeIndex nodeIndex = block->variablesAtTail.operand(operand);
- if (nodeIndex == NoNode)
+ Node* livenessNode = jettisonedBlock->variablesAtHead.operand(operand);
+ if (!livenessNode)
return;
- if (m_graph[nodeIndex].variableAccessData()->isCaptured())
+ if (livenessNode->variableAccessData()->isCaptured())
return;
- if (m_graph[nodeIndex].op() == SetLocal)
- nodeIndex = m_graph[nodeIndex].child1().index();
- Node& node = m_graph[nodeIndex];
- if (!node.shouldGenerate())
- return;
- ASSERT(m_graph[nodeIndex].op() != SetLocal);
- NodeIndex phantomNodeIndex = m_graph.size();
- Node phantom(Phantom, codeOrigin, nodeIndex);
- m_graph.append(phantom);
- m_graph.ref(phantomNodeIndex);
- block->append(phantomNodeIndex);
- }
-
- void fixPossibleGetLocal(BasicBlock* block, Edge& edge, bool changeRef)
- {
- Node& child = m_graph[edge];
- if (child.op() != GetLocal)
- return;
-#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLogF(" Considering GetLocal at @%u, local r%d.\n", edge.index(), child.local());
-#endif
- if (child.variableAccessData()->isCaptured()) {
-#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLogF(" It's captured.\n");
-#endif
- return;
- }
- NodeIndex originalNodeIndex = block->variablesAtTail.operand(child.local());
-#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLogF(" Dealing with original @%u.\n", originalNodeIndex);
-#endif
- ASSERT(originalNodeIndex != NoNode);
- Node* originalNode = &m_graph[originalNodeIndex];
-#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLogF(" Original has local r%d.\n", originalNode->local());
-#endif
- ASSERT(child.local() == originalNode->local());
- // Possibilities:
- // SetLocal -> the secondBlock is getting the value of something that is immediately
- // available in the first block with a known NodeIndex.
- // GetLocal -> the secondBlock is getting the value of something that the first
- // block also gets.
- // Phi -> the secondBlock is asking for keep-alive on an operand that the first block
- // was also asking for keep-alive on.
- // SetArgument -> the secondBlock is asking for keep-alive on an operand that the
- // first block was keeping alive by virtue of the firstBlock being the root and
- // the operand being an argument.
- // Flush -> the secondBlock is asking for keep-alive on an operand that the first
- // block was forcing to be alive, so the second block should refer child of
- // the flush.
- if (originalNode->op() == Flush) {
- originalNodeIndex = originalNode->child1().index();
- originalNode = &m_graph[originalNodeIndex];
- }
- switch (originalNode->op()) {
- case SetLocal: {
- if (changeRef)
- ASSERT(originalNode->shouldGenerate());
-#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLogF(" It's a SetLocal.\n");
-#endif
- m_graph.changeIndex(edge, originalNode->child1().index(), changeRef);
- break;
- }
- case GetLocal: {
-#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLogF(" It's a GetLocal.\n");
-#endif
- if (originalNode->shouldGenerate())
- m_graph.changeIndex(edge, originalNodeIndex, changeRef);
- // If we have a GetLocal that points to a child GetLocal that is dead, then
- // we have no need to do anything: this original GetLocal is still valid.
- break;
- }
- case Phi:
- case SetArgument: {
- if (changeRef)
- ASSERT(originalNode->shouldGenerate());
-#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLogF(" It's Phi/SetArgument.\n");
-#endif
- // Keep the GetLocal!
- break;
- }
- default:
- ASSERT_NOT_REACHED();
- break;
- }
+ block->appendNode(
+ m_graph, SpecNone, PhantomLocal, codeOrigin,
+ OpInfo(livenessNode->variableAccessData()));
}
void jettisonBlock(BlockIndex blockIndex, BlockIndex jettisonedBlockIndex, CodeOrigin boundaryCodeOrigin)
@@ -364,46 +280,13 @@ private:
BasicBlock* jettisonedBlock = m_graph.m_blocks[jettisonedBlockIndex].get();
for (size_t i = 0; i < jettisonedBlock->variablesAtHead.numberOfArguments(); ++i)
- keepOperandAlive(block, boundaryCodeOrigin, argumentToOperand(i));
+ keepOperandAlive(block, jettisonedBlock, boundaryCodeOrigin, argumentToOperand(i));
for (size_t i = 0; i < jettisonedBlock->variablesAtHead.numberOfLocals(); ++i)
- keepOperandAlive(block, boundaryCodeOrigin, i);
+ keepOperandAlive(block, jettisonedBlock, boundaryCodeOrigin, i);
fixJettisonedPredecessors(blockIndex, jettisonedBlockIndex);
}
- void fixPhis(BlockIndex sourceBlockIndex, BlockIndex destinationBlockIndex)
- {
- BasicBlock* sourceBlock = m_graph.m_blocks[sourceBlockIndex].get();
- BasicBlock* destinationBlock = m_graph.m_blocks[destinationBlockIndex].get();
- if (!destinationBlock) {
- // If we're trying to kill off the source block and the destination block is already
- // dead, then we're done!
- return;
- }
- for (size_t i = 0; i < destinationBlock->phis.size(); ++i) {
- NodeIndex phiNodeIndex = destinationBlock->phis[i];
- Node& phiNode = m_graph[phiNodeIndex];
- NodeIndex myNodeIndex = sourceBlock->variablesAtTail.operand(phiNode.local());
-#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLogF("Considering removing reference from phi @%u to @%u on local r%d:",
- phiNodeIndex, myNodeIndex, phiNode.local());
-#endif
- if (myNodeIndex == NoNode) {
- // This will happen if there is a phi in the destination that refers into
- // the destination itself.
- continue;
- }
- Node& myNode = m_graph[myNodeIndex];
- if (myNode.op() == GetLocal)
- myNodeIndex = myNode.child1().index();
- for (unsigned j = 0; j < AdjacencyList::Size; ++j)
- removePotentiallyDeadPhiReference(myNodeIndex, phiNode, j, sourceBlock->isReachable);
-#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLogF("\n");
-#endif
- }
- }
-
void fixJettisonedPredecessors(BlockIndex blockIndex, BlockIndex jettisonedBlockIndex)
{
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
@@ -418,145 +301,6 @@ private:
jettisonedBlock->m_predecessors.removeLast();
break;
}
-
- fixPhis(blockIndex, jettisonedBlockIndex);
- }
-
- void removePotentiallyDeadPhiReference(NodeIndex myNodeIndex, Node& phiNode, unsigned edgeIndex, bool changeRef)
- {
- if (phiNode.children.child(edgeIndex).indexUnchecked() != myNodeIndex)
- return;
-#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLogF(" Removing reference at child %u.", edgeIndex);
-#endif
- if (changeRef && phiNode.shouldGenerate())
- m_graph.deref(myNodeIndex);
- phiNode.children.removeEdgeFromBag(edgeIndex);
- }
-
- struct OperandSubstitution {
- OperandSubstitution()
- : oldChild(NoNode)
- , newChild(NoNode)
- {
- }
-
- explicit OperandSubstitution(NodeIndex oldChild)
- : oldChild(oldChild)
- , newChild(oldChild)
- {
- }
-
- OperandSubstitution(NodeIndex oldChild, NodeIndex newChild)
- : oldChild(oldChild)
- , newChild(newChild)
- {
- ASSERT((oldChild == NoNode) == (newChild == NoNode));
- }
-
- void dump(FILE* out)
- {
- if (oldChild == NoNode)
- fprintf(out, "-");
- else
- fprintf(out, "@%u -> @%u", oldChild, newChild);
- }
-
- NodeIndex oldChild;
- NodeIndex newChild;
- };
-
- NodeIndex skipGetLocal(NodeIndex nodeIndex)
- {
- if (nodeIndex == NoNode)
- return NoNode;
- Node& node = m_graph[nodeIndex];
- if (node.op() == GetLocal)
- return node.child1().index();
- return nodeIndex;
- }
-
- void recordPossibleIncomingReference(
- BasicBlock* secondBlock, Operands<OperandSubstitution>& substitutions, int operand)
- {
- substitutions.operand(operand) = OperandSubstitution(
- skipGetLocal(secondBlock->variablesAtTail.operand(operand)));
- }
-
- void recordNewTarget(Operands<OperandSubstitution>& substitutions, int operand, NodeIndex nodeIndex)
- {
- ASSERT(m_graph[nodeIndex].op() == SetLocal
- || m_graph[nodeIndex].op() == SetArgument
- || m_graph[nodeIndex].op() == Flush
- || m_graph[nodeIndex].op() == Phi);
- substitutions.operand(operand).newChild = nodeIndex;
- }
-
- void fixTailOperand(
- BasicBlock* firstBlock, BasicBlock* secondBlock, int operand,
- Operands<OperandSubstitution>& substitutions)
- {
- NodeIndex atSecondTail = secondBlock->variablesAtTail.operand(operand);
-
- if (atSecondTail == NoNode) {
- // If the variable is dead at the end of the second block, then do nothing; essentially
- // this means that we want the tail state to reflect whatever the first block did.
- return;
- }
-
- Node& secondNode = m_graph[atSecondTail];
-
- switch (secondNode.op()) {
- case SetLocal:
- case Flush: {
- // The second block did interesting things to the variables, so update the tail
- // accordingly.
- firstBlock->variablesAtTail.operand(operand) = atSecondTail;
- break;
- }
-
- case Phi: {
- // Keep what was in the first block.
- ASSERT(firstBlock->variablesAtTail.operand(operand) != NoNode);
- recordNewTarget(substitutions, operand, skipGetLocal(firstBlock->variablesAtTail.operand(operand)));
- break;
- }
-
- case GetLocal: {
- // If it's a GetLocal on a captured var, then definitely keep what was
- // in the second block. In particular, it's possible that the first
- // block doesn't even know about this variable.
- if (secondNode.variableAccessData()->isCaptured()) {
- firstBlock->variablesAtTail.operand(operand) = atSecondTail;
- recordNewTarget(substitutions, operand, secondNode.child1().index());
- break;
- }
-
- // It's possible that the second block had a GetLocal and the first block
- // had a SetArgument or a Phi. Then update the tail. Otherwise keep what was in the
- // first block.
- NodeIndex atFirstTail = firstBlock->variablesAtTail.operand(operand);
- ASSERT(atFirstTail != NoNode);
- switch (m_graph[atFirstTail].op()) {
- case SetArgument:
- case Phi:
- firstBlock->variablesAtTail.operand(operand) = atSecondTail;
- recordNewTarget(substitutions, operand, secondNode.child1().index());
- break;
-
- default:
- // Keep what was in the first block, and adjust the substitution to account for
- // the fact that successors will refer to the child of the GetLocal.
- ASSERT(firstBlock->variablesAtTail.operand(operand) != NoNode);
- recordNewTarget(substitutions, operand, skipGetLocal(firstBlock->variablesAtTail.operand(operand)));
- break;
- }
- break;
- }
-
- default:
- ASSERT_NOT_REACHED();
- }
}
void mergeBlocks(
@@ -573,10 +317,10 @@ private:
// Remove the terminal of firstBlock since we don't need it anymore. Well, we don't
// really remove it; we actually turn it into a Phantom.
- ASSERT(m_graph[firstBlock->last()].isTerminal());
- CodeOrigin boundaryCodeOrigin = m_graph[firstBlock->last()].codeOrigin;
- m_graph[firstBlock->last()].setOpAndDefaultFlags(Phantom);
- ASSERT(m_graph[firstBlock->last()].refCount() == 1);
+ ASSERT(firstBlock->last()->isTerminal());
+ CodeOrigin boundaryCodeOrigin = firstBlock->last()->codeOrigin;
+ firstBlock->last()->convertToPhantom();
+ ASSERT(firstBlock->last()->refCount() == 1);
if (jettisonedBlockIndex != NoBlock) {
BasicBlock* jettisonedBlock = m_graph.m_blocks[jettisonedBlockIndex].get();
@@ -586,101 +330,18 @@ private:
// different path than secondBlock.
for (size_t i = 0; i < jettisonedBlock->variablesAtHead.numberOfArguments(); ++i)
- keepOperandAlive(firstBlock, boundaryCodeOrigin, argumentToOperand(i));
+ keepOperandAlive(firstBlock, jettisonedBlock, boundaryCodeOrigin, argumentToOperand(i));
for (size_t i = 0; i < jettisonedBlock->variablesAtHead.numberOfLocals(); ++i)
- keepOperandAlive(firstBlock, boundaryCodeOrigin, i);
+ keepOperandAlive(firstBlock, jettisonedBlock, boundaryCodeOrigin, i);
}
for (size_t i = 0; i < secondBlock->phis.size(); ++i)
firstBlock->phis.append(secondBlock->phis[i]);
- // Before we start changing the second block's graph, record what nodes would
- // be referenced by successors of the second block.
- Operands<OperandSubstitution> substitutions(
- secondBlock->variablesAtTail.numberOfArguments(),
- secondBlock->variablesAtTail.numberOfLocals());
- for (size_t i = 0; i < secondBlock->variablesAtTail.numberOfArguments(); ++i)
- recordPossibleIncomingReference(secondBlock, substitutions, argumentToOperand(i));
- for (size_t i = 0; i < secondBlock->variablesAtTail.numberOfLocals(); ++i)
- recordPossibleIncomingReference(secondBlock, substitutions, i);
-
- for (size_t i = 0; i < secondBlock->size(); ++i) {
- NodeIndex nodeIndex = secondBlock->at(i);
- Node& node = m_graph[nodeIndex];
-
- bool childrenAlreadyFixed = false;
-
- switch (node.op()) {
- case Phantom: {
- if (!node.child1())
- break;
-
- ASSERT(node.shouldGenerate());
- Node& possibleLocalOp = m_graph[node.child1()];
- if (possibleLocalOp.op() != GetLocal
- && possibleLocalOp.hasLocal()
- && !possibleLocalOp.variableAccessData()->isCaptured()) {
- NodeIndex setLocalIndex =
- firstBlock->variablesAtTail.operand(possibleLocalOp.local());
- Node& setLocal = m_graph[setLocalIndex];
- if (setLocal.op() == SetLocal) {
- m_graph.changeEdge(node.children.child1(), setLocal.child1());
- ASSERT(!node.child2());
- ASSERT(!node.child3());
- childrenAlreadyFixed = true;
- }
- }
- break;
- }
-
- case Flush:
- case GetLocal: {
- // A Flush could use a GetLocal, SetLocal, SetArgument, or a Phi.
- // If it uses a GetLocal, it'll be taken care of below. If it uses a
- // SetLocal or SetArgument, then it must be using a node from the
- // same block. But if it uses a Phi, then we should redirect it to
- // use whatever the first block advertised as a tail operand.
- // Similarly for GetLocal; it could use any of those except for
- // GetLocal. If it uses a Phi then it should be redirected to use a
- // Phi from the tail operand.
- if (m_graph[node.child1()].op() != Phi)
- break;
-
- NodeIndex atFirstIndex = firstBlock->variablesAtTail.operand(node.local());
- m_graph.changeEdge(node.children.child1(), Edge(skipGetLocal(atFirstIndex)), node.shouldGenerate());
- childrenAlreadyFixed = true;
- break;
- }
-
- default:
- break;
- }
-
- if (!childrenAlreadyFixed) {
- bool changeRef = node.shouldGenerate();
-
- // If the child is a GetLocal, then we might like to fix it.
- if (node.flags() & NodeHasVarArgs) {
- for (unsigned childIdx = node.firstChild();
- childIdx < node.firstChild() + node.numChildren();
- ++childIdx) {
- if (!!m_graph.m_varArgChildren[childIdx])
- fixPossibleGetLocal(firstBlock, m_graph.m_varArgChildren[childIdx], changeRef);
- }
- } else if (!!node.child1()) {
- fixPossibleGetLocal(firstBlock, node.children.child1(), changeRef);
- if (!!node.child2()) {
- fixPossibleGetLocal(firstBlock, node.children.child2(), changeRef);
- if (!!node.child3())
- fixPossibleGetLocal(firstBlock, node.children.child3(), changeRef);
- }
- }
- }
-
- firstBlock->append(nodeIndex);
- }
+ for (size_t i = 0; i < secondBlock->size(); ++i)
+ firstBlock->append(secondBlock->at(i));
- ASSERT(m_graph[firstBlock->last()].isTerminal());
+ ASSERT(firstBlock->last()->isTerminal());
// Fix the predecessors of my new successors. This is tricky, since we are going to reset
// all predecessors anyway due to reachability analysis. But we need to fix the
@@ -700,39 +361,6 @@ private:
if (jettisonedBlockIndex != NoBlock)
fixJettisonedPredecessors(firstBlockIndex, jettisonedBlockIndex);
- // Fix up the variables at tail.
- for (size_t i = 0; i < secondBlock->variablesAtHead.numberOfArguments(); ++i)
- fixTailOperand(firstBlock, secondBlock, argumentToOperand(i), substitutions);
- for (size_t i = 0; i < secondBlock->variablesAtHead.numberOfLocals(); ++i)
- fixTailOperand(firstBlock, secondBlock, i, substitutions);
-
- // Fix up the references from our new successors.
- for (unsigned i = m_graph.numSuccessors(firstBlock); i--;) {
- BasicBlock* successor = m_graph.m_blocks[m_graph.successor(firstBlock, i)].get();
- for (unsigned j = 0; j < successor->phis.size(); ++j) {
- NodeIndex phiNodeIndex = successor->phis[j];
- Node& phiNode = m_graph[phiNodeIndex];
- bool changeRef = phiNode.shouldGenerate();
- OperandSubstitution substitution = substitutions.operand(phiNode.local());
-#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLogF(" Performing operand substitution @%u -> @%u.\n",
- substitution.oldChild, substitution.newChild);
-#endif
- if (!phiNode.child1())
- continue;
- if (phiNode.child1().index() == substitution.oldChild)
- m_graph.changeIndex(phiNode.children.child1(), substitution.newChild, changeRef);
- if (!phiNode.child2())
- continue;
- if (phiNode.child2().index() == substitution.oldChild)
- m_graph.changeIndex(phiNode.children.child2(), substitution.newChild, changeRef);
- if (!phiNode.child3())
- continue;
- if (phiNode.child3().index() == substitution.oldChild)
- m_graph.changeIndex(phiNode.children.child3(), substitution.newChild, changeRef);
- }
- }
-
firstBlock->valuesAtTail = secondBlock->valuesAtTail;
firstBlock->cfaBranchDirection = secondBlock->cfaBranchDirection;