summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/dfg/DFGSSAConversionPhase.cpp
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2016-04-10 09:28:39 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2016-04-10 09:28:39 +0000
commit32761a6cee1d0dee366b885b7b9c777e67885688 (patch)
treed6bec92bebfb216f4126356e55518842c2f476a1 /Source/JavaScriptCore/dfg/DFGSSAConversionPhase.cpp
parenta4e969f4965059196ca948db781e52f7cfebf19e (diff)
downloadWebKitGtk-tarball-32761a6cee1d0dee366b885b7b9c777e67885688.tar.gz
webkitgtk-2.4.11webkitgtk-2.4.11
Diffstat (limited to 'Source/JavaScriptCore/dfg/DFGSSAConversionPhase.cpp')
-rw-r--r--Source/JavaScriptCore/dfg/DFGSSAConversionPhase.cpp609
1 files changed, 330 insertions, 279 deletions
diff --git a/Source/JavaScriptCore/dfg/DFGSSAConversionPhase.cpp b/Source/JavaScriptCore/dfg/DFGSSAConversionPhase.cpp
index de100687b..57fc09529 100644
--- a/Source/JavaScriptCore/dfg/DFGSSAConversionPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSSAConversionPhase.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013-2015 Apple Inc. All rights reserved.
+ * Copyright (C) 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
@@ -32,9 +32,7 @@
#include "DFGGraph.h"
#include "DFGInsertionSet.h"
#include "DFGPhase.h"
-#include "DFGSSACalculator.h"
-#include "DFGVariableAccessDataDump.h"
-#include "JSCInlines.h"
+#include "Operations.h"
namespace JSC { namespace DFG {
@@ -44,8 +42,8 @@ class SSAConversionPhase : public Phase {
public:
SSAConversionPhase(Graph& graph)
: Phase(graph, "SSA conversion")
- , m_calculator(graph)
, m_insertionSet(graph)
+ , m_changed(false)
{
}
@@ -53,318 +51,315 @@ public:
{
RELEASE_ASSERT(m_graph.m_form == ThreadedCPS);
- m_graph.clearReplacements();
- m_graph.ensureDominators();
-
- if (verbose) {
- dataLog("Graph before SSA transformation:\n");
- m_graph.dump();
- }
-
- // Create a SSACalculator::Variable for every root VariableAccessData.
- for (VariableAccessData& variable : m_graph.m_variableAccessData) {
- if (!variable.isRoot())
+ // Figure out which SetLocal's need flushing. Need to do this while the
+ // Phi graph is still intact.
+ for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) {
+ BasicBlock* block = m_graph.block(blockIndex);
+ if (!block)
continue;
-
- SSACalculator::Variable* ssaVariable = m_calculator.newVariable();
- ASSERT(ssaVariable->index() == m_variableForSSAIndex.size());
- m_variableForSSAIndex.append(&variable);
- m_ssaVariableForVariable.add(&variable, ssaVariable);
+ for (unsigned nodeIndex = block->size(); nodeIndex--;) {
+ Node* node = block->at(nodeIndex);
+ if (node->op() != Flush)
+ continue;
+ addFlushedLocalOp(node);
+ }
+ }
+ while (!m_flushedLocalOpWorklist.isEmpty()) {
+ Node* node = m_flushedLocalOpWorklist.takeLast();
+ ASSERT(m_flushedLocalOps.contains(node));
+ DFG_NODE_DO_TO_CHILDREN(m_graph, node, addFlushedLocalEdge);
}
- // Find all SetLocals and create Defs for them. We handle SetArgument by creating a
- // GetLocal, and recording the flush format.
+ // Eliminate all duplicate or self-pointing Phi edges. This means that
+ // we transform:
+ //
+ // p: Phi(@n1, @n2, @n3)
+ //
+ // into:
+ //
+ // p: Phi(@x)
+ //
+ // if each @ni in {@n1, @n2, @n3} is either equal to @p to is equal
+ // to @x, for exactly one other @x. Additionally, trivial Phis (i.e.
+ // p: Phi(@x)) are forwarded, so that if have an edge to such @p, we
+ // replace it with @x. This loop does this for Phis only; later we do
+ // such forwarding for Phi references found in other nodes.
+ //
+ // See Aycock and Horspool in CC'00 for a better description of what
+ // we're doing here.
+ do {
+ m_changed = false;
+ for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) {
+ BasicBlock* block = m_graph.block(blockIndex);
+ if (!block)
+ continue;
+ for (unsigned phiIndex = block->phis.size(); phiIndex--;) {
+ Node* phi = block->phis[phiIndex];
+ if (phi->variableAccessData()->isCaptured())
+ continue;
+ forwardPhiChildren(phi);
+ deduplicateChildren(phi);
+ }
+ }
+ } while (m_changed);
+
+ // For each basic block, for each local live at the head of that block,
+ // figure out what node we should be referring to instead of that local.
+ // If it turns out to be a non-trivial Phi, make sure that we create an
+ // SSA Phi and Upsilons in predecessor blocks. We reuse
+ // BasicBlock::variablesAtHead for tracking which nodes to refer to.
for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) {
BasicBlock* block = m_graph.block(blockIndex);
if (!block)
continue;
- // Must process the block in forward direction because we want to see the last
- // assignment for every local.
- for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) {
- Node* node = block->at(nodeIndex);
- if (node->op() != SetLocal && node->op() != SetArgument)
+ for (unsigned i = block->variablesAtHead.size(); i--;) {
+ Node* node = block->variablesAtHead[i];
+ if (!node)
continue;
VariableAccessData* variable = node->variableAccessData();
+ if (variable->isCaptured()) {
+ // Poison this entry in variablesAtHead because we don't
+ // want anyone to try to refer to it, if the variable is
+ // captured.
+ block->variablesAtHead[i] = 0;
+ continue;
+ }
+
+ switch (node->op()) {
+ case Phi:
+ case SetArgument:
+ break;
+ case Flush:
+ case GetLocal:
+ case PhantomLocal:
+ node = node->child1().node();
+ break;
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ }
+ RELEASE_ASSERT(node->op() == Phi || node->op() == SetArgument);
- Node* childNode;
- if (node->op() == SetLocal)
- childNode = node->child1().node();
- else {
- ASSERT(node->op() == SetArgument);
- childNode = m_insertionSet.insertNode(
- nodeIndex, node->variableAccessData()->prediction(),
- GetStack, node->origin,
- OpInfo(m_graph.m_stackAccessData.add(variable->local(), variable->flushFormat())));
- if (!ASSERT_DISABLED)
- m_argumentGetters.add(childNode);
- m_argumentMapping.add(node, childNode);
+ bool isFlushed = m_flushedLocalOps.contains(node);
+
+ if (node->op() == Phi) {
+ Edge edge = node->children.justOneChild();
+ if (edge)
+ node = edge.node(); // It's something from a different basic block.
+ else {
+ // It's a non-trivial Phi.
+ FlushFormat format = variable->flushFormat();
+ NodeFlags result = resultFor(format);
+ UseKind useKind = useKindFor(format);
+
+ node = m_insertionSet.insertNode(0, SpecNone, Phi, CodeOrigin());
+ node->mergeFlags(result);
+ RELEASE_ASSERT((node->flags() & NodeResultMask) == result);
+
+ for (unsigned j = block->predecessors.size(); j--;) {
+ BasicBlock* predecessor = block->predecessors[j];
+ predecessor->appendNonTerminal(
+ m_graph, SpecNone, Upsilon, predecessor->last()->codeOrigin,
+ OpInfo(node), Edge(predecessor->variablesAtTail[i], useKind));
+ }
+
+ if (isFlushed) {
+ // Do nothing. For multiple reasons.
+
+ // Reason #1: If the local is flushed then we don't need to bother
+ // with a MovHint since every path to this point in the code will
+ // have flushed the bytecode variable using a SetLocal and hence
+ // the Availability::flushedAt() will agree, and that will be
+ // sufficient for figuring out how to recover the variable's value.
+
+ // Reason #2: If we had inserted a MovHint and the Phi function had
+ // died (because the only user of the value was the "flush" - i.e.
+ // some asynchronous runtime thingy) then the MovHint would turn
+ // into a ZombieHint, which would fool us into thinking that the
+ // variable is dead.
+
+ // Reason #3: If we had inserted a MovHint then even if the Phi
+ // stayed alive, we would still end up generating inefficient code
+ // since we would be telling the OSR exit compiler to use some SSA
+ // value for the bytecode variable rather than just telling it that
+ // the value was already on the stack.
+ } else {
+ m_insertionSet.insertNode(
+ 0, SpecNone, MovHint, CodeOrigin(),
+ OpInfo(variable->local().offset()), Edge(node));
+ }
+ }
}
- m_calculator.newDef(
- m_ssaVariableForVariable.get(variable), block, childNode);
+ block->variablesAtHead[i] = node;
}
-
+
m_insertionSet.execute(block);
}
- // Decide where Phis are to be inserted. This creates the Phi's but doesn't insert them
- // yet. We will later know where to insert them because SSACalculator is such a bro.
- m_calculator.computePhis(
- [&] (SSACalculator::Variable* ssaVariable, BasicBlock* block) -> Node* {
- VariableAccessData* variable = m_variableForSSAIndex[ssaVariable->index()];
-
- // Prune by liveness. This doesn't buy us much other than compile times.
- Node* headNode = block->variablesAtHead.operand(variable->local());
- if (!headNode)
- return nullptr;
-
- // There is the possibiltiy of "rebirths". The SSA calculator will already prune
- // rebirths for the same VariableAccessData. But it will not be able to prune
- // rebirths that arose from the same local variable number but a different
- // VariableAccessData. We do that pruning here.
- //
- // Here's an example of a rebirth that this would catch:
- //
- // var x;
- // if (foo) {
- // if (bar) {
- // x = 42;
- // } else {
- // x = 43;
- // }
- // print(x);
- // x = 44;
- // } else {
- // x = 45;
- // }
- // print(x); // Without this check, we'd have a Phi for x = 42|43 here.
- //
- // FIXME: Consider feeding local variable numbers, not VariableAccessData*'s, as
- // the "variables" for SSACalculator. That would allow us to eliminate this
- // special case.
- // https://bugs.webkit.org/show_bug.cgi?id=136641
- if (headNode->variableAccessData() != variable)
- return nullptr;
-
- Node* phiNode = m_graph.addNode(
- variable->prediction(), Phi, block->at(0)->origin.withInvalidExit());
- FlushFormat format = variable->flushFormat();
- NodeFlags result = resultFor(format);
- phiNode->mergeFlags(result);
- return phiNode;
- });
-
if (verbose) {
- dataLog("Computed Phis, about to transform the graph.\n");
- dataLog("\n");
- dataLog("Graph:\n");
- m_graph.dump();
- dataLog("\n");
- dataLog("Mappings:\n");
- for (unsigned i = 0; i < m_variableForSSAIndex.size(); ++i)
- dataLog(" ", i, ": ", VariableAccessDataDump(m_graph, m_variableForSSAIndex[i]), "\n");
- dataLog("\n");
- dataLog("SSA calculator: ", m_calculator, "\n");
+ dataLog("Variables at head after SSA Phi insertion:\n");
+ for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) {
+ BasicBlock* block = m_graph.block(blockIndex);
+ if (!block)
+ continue;
+ dataLog(" ", *block, ": ", block->variablesAtHead, "\n");
+ }
}
- // Do the bulk of the SSA conversion. For each block, this tracks the operand->Node
- // mapping based on a combination of what the SSACalculator tells us, and us walking over
- // the block in forward order. We use our own data structure, valueForOperand, for
- // determining the local mapping, but we rely on SSACalculator for the non-local mapping.
- //
- // This does three things at once:
- //
- // - Inserts the Phis in all of the places where they need to go. We've already created
- // them and they are accounted for in the SSACalculator's data structures, but we
- // haven't inserted them yet, mostly because we want to insert all of a block's Phis in
- // one go to amortize the cost of node insertion.
- //
- // - Create and insert Upsilons.
- //
- // - Convert all of the preexisting SSA nodes (other than the old CPS Phi nodes) into SSA
- // form by replacing as follows:
+ // At this point variablesAtHead in each block refers to either:
//
- // - MovHint has KillLocal prepended to it.
+ // 1) A new SSA phi in the current block.
+ // 2) A SetArgument, which will soon get converted into a GetArgument.
+ // 3) An old CPS phi in a different block.
//
- // - GetLocal die and get replaced with references to the node specified by
- // valueForOperand.
- //
- // - SetLocal turns into PutStack if it's flushed, or turns into a Check otherwise.
- //
- // - Flush loses its children and turns into a Phantom.
- //
- // - PhantomLocal becomes Phantom, and its child is whatever is specified by
- // valueForOperand.
- //
- // - SetArgument is removed. Note that GetStack nodes have already been inserted.
- Operands<Node*> valueForOperand(OperandsLike, m_graph.block(0)->variablesAtHead);
- for (BasicBlock* block : m_graph.blocksInPreOrder()) {
- valueForOperand.clear();
-
- // CPS will claim that the root block has all arguments live. But we have already done
- // the first step of SSA conversion: argument locals are no longer live at head;
- // instead we have GetStack nodes for extracting the values of arguments. So, we
- // skip the at-head available value calculation for the root block.
- if (block != m_graph.block(0)) {
- for (size_t i = valueForOperand.size(); i--;) {
- Node* nodeAtHead = block->variablesAtHead[i];
- if (!nodeAtHead)
- continue;
-
- VariableAccessData* variable = nodeAtHead->variableAccessData();
-
- if (verbose)
- dataLog("Considering live variable ", VariableAccessDataDump(m_graph, variable), " at head of block ", *block, "\n");
-
- SSACalculator::Variable* ssaVariable = m_ssaVariableForVariable.get(variable);
- SSACalculator::Def* def = m_calculator.reachingDefAtHead(block, ssaVariable);
- if (!def) {
- // If we are required to insert a Phi, then we won't have a reaching def
- // at head.
- continue;
- }
-
- Node* node = def->value();
- if (node->replacement()) {
- // This will occur when a SetLocal had a GetLocal as its source. The
- // GetLocal would get replaced with an actual SSA value by the time we get
- // here. Note that the SSA value with which the GetLocal got replaced
- // would not in turn have a replacement.
- node = node->replacement();
- ASSERT(!node->replacement());
- }
- if (verbose)
- dataLog("Mapping: ", VirtualRegister(valueForOperand.operandForIndex(i)), " -> ", node, "\n");
- valueForOperand[i] = node;
+ // We don't have to do anything for (1) and (2), but we do need to
+ // do a replacement for (3).
+
+ // Clear all replacements, since other phases may have used them.
+ m_graph.clearReplacements();
+
+ // For all of the old CPS Phis, figure out what they correspond to in SSA.
+ for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) {
+ BasicBlock* block = m_graph.block(blockIndex);
+ if (!block)
+ continue;
+ for (unsigned phiIndex = block->phis.size(); phiIndex--;) {
+ Node* phi = block->phis[phiIndex];
+ if (verbose) {
+ dataLog(
+ "Considering ", phi, ", for r", phi->local(),
+ ", and its replacement in ", *block, ", ",
+ block->variablesAtHead.operand(phi->local()), "\n");
}
+ phi->misc.replacement = block->variablesAtHead.operand(phi->local());
+ }
+ }
+
+ // Now make sure that all variablesAtHead in each block points to the
+ // canonical SSA value. Prior to this, variablesAtHead[local] may point to
+ // an old CPS Phi in a different block.
+ for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) {
+ BasicBlock* block = m_graph.block(blockIndex);
+ if (!block)
+ continue;
+ for (size_t i = block->variablesAtHead.size(); i--;) {
+ Node* node = block->variablesAtHead[i];
+ if (!node)
+ continue;
+ while (node->misc.replacement)
+ node = node->misc.replacement;
+ block->variablesAtHead[i] = node;
+ }
+ }
+
+ if (verbose) {
+ dataLog("Variables at head after convergence:\n");
+ for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) {
+ BasicBlock* block = m_graph.block(blockIndex);
+ if (!block)
+ continue;
+ dataLog(" ", *block, ": ", block->variablesAtHead, "\n");
}
+ }
+
+ // Convert operations over locals into operations over SSA nodes.
+ // - GetLocal over captured variables lose their phis.
+ // - GetLocal over uncaptured variables die and get replaced with references
+ // to the node specified by variablesAtHead.
+ // - SetLocal gets NodeMustGenerate if it's flushed, or turns into a
+ // Check otherwise.
+ // - Flush loses its children but remains, because we want to know when a
+ // flushed SetLocal's value is no longer needed. This also makes it simpler
+ // to reason about the format of a local, since we can just do a backwards
+ // analysis (see FlushLivenessAnalysisPhase). As part of the backwards
+ // analysis, we say that the type of a local can be either int32, double,
+ // value, or dead.
+ // - PhantomLocal becomes Phantom, and its child is whatever is specified
+ // by variablesAtHead.
+ // - SetArgument turns into GetArgument unless it's a captured variable.
+ // - Upsilons get their children fixed to refer to the true value of that local
+ // at the end of the block. Prior to this loop, Upsilons will refer to
+ // variableAtTail[operand], which may be any of Flush, PhantomLocal, GetLocal,
+ // SetLocal, SetArgument, or Phi. We accomplish this by setting the
+ // replacement pointers of all of those nodes to refer to either
+ // variablesAtHead[operand], or the child of the SetLocal.
+ for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) {
+ BasicBlock* block = m_graph.block(blockIndex);
+ if (!block)
+ continue;
- // Insert Phis by asking the calculator what phis there are in this block. Also update
- // valueForOperand with those Phis. For Phis associated with variables that are not
- // flushed, we also insert a MovHint.
- size_t phiInsertionPoint = 0;
- for (SSACalculator::Def* phiDef : m_calculator.phisForBlock(block)) {
- VariableAccessData* variable = m_variableForSSAIndex[phiDef->variable()->index()];
-
- m_insertionSet.insert(phiInsertionPoint, phiDef->value());
- valueForOperand.operand(variable->local()) = phiDef->value();
-
- m_insertionSet.insertNode(
- phiInsertionPoint, SpecNone, MovHint, block->at(0)->origin.withInvalidExit(),
- OpInfo(variable->local().offset()), phiDef->value()->defaultEdge());
+ for (unsigned phiIndex = block->phis.size(); phiIndex--;) {
+ block->phis[phiIndex]->misc.replacement =
+ block->variablesAtHead.operand(block->phis[phiIndex]->local());
}
-
- if (block->at(0)->origin.exitOK)
- m_insertionSet.insertNode(phiInsertionPoint, SpecNone, ExitOK, block->at(0)->origin);
+ for (unsigned nodeIndex = block->size(); nodeIndex--;)
+ ASSERT(!block->at(nodeIndex)->misc.replacement);
for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) {
Node* node = block->at(nodeIndex);
- if (verbose) {
- dataLog("Processing node ", node, ":\n");
- m_graph.dump(WTF::dataFile(), " ", node);
- }
-
m_graph.performSubstitution(node);
switch (node->op()) {
- case MovHint: {
- m_insertionSet.insertNode(
- nodeIndex, SpecNone, KillStack, node->origin,
- OpInfo(node->unlinkedLocal().offset()));
- node->origin.exitOK = false; // KillStack clobbers exit.
- break;
- }
-
case SetLocal: {
VariableAccessData* variable = node->variableAccessData();
- Node* child = node->child1().node();
-
- if (!!(node->flags() & NodeIsFlushed)) {
- node->convertToPutStack(
- m_graph.m_stackAccessData.add(
- variable->local(), variable->flushFormat()));
- } else
- node->remove();
-
- if (verbose)
- dataLog("Mapping: ", variable->local(), " -> ", child, "\n");
- valueForOperand.operand(variable->local()) = child;
- break;
- }
-
- case GetStack: {
- ASSERT(m_argumentGetters.contains(node));
- valueForOperand.operand(node->stackAccessData()->local) = node;
+ if (variable->isCaptured() || m_flushedLocalOps.contains(node))
+ node->mergeFlags(NodeMustGenerate);
+ else
+ node->setOpAndDefaultFlags(Check);
+ node->misc.replacement = node->child1().node(); // Only for Upsilons.
break;
}
case GetLocal: {
- VariableAccessData* variable = node->variableAccessData();
+ // It seems tempting to just do forwardPhi(GetLocal), except that we
+ // could have created a new (SSA) Phi, and the GetLocal could still be
+ // referring to an old (CPS) Phi. Uses variablesAtHead to tell us what
+ // to refer to.
node->children.reset();
-
- node->remove();
- if (verbose)
- dataLog("Replacing node ", node, " with ", valueForOperand.operand(variable->local()), "\n");
- node->setReplacement(valueForOperand.operand(variable->local()));
+ VariableAccessData* variable = node->variableAccessData();
+ if (variable->isCaptured())
+ break;
+ node->convertToPhantom();
+ node->misc.replacement = block->variablesAtHead.operand(variable->local());
break;
}
case Flush: {
node->children.reset();
- node->remove();
+ // This is only for Upsilons. An Upsilon will only refer to a Flush if
+ // there were no SetLocals or GetLocals in the block.
+ node->misc.replacement = block->variablesAtHead.operand(node->local());
break;
}
case PhantomLocal: {
- ASSERT(node->child1().useKind() == UntypedUse);
VariableAccessData* variable = node->variableAccessData();
- node->child1() = valueForOperand.operand(variable->local())->defaultEdge();
- node->remove();
+ if (variable->isCaptured())
+ break;
+ node->child1().setNode(block->variablesAtHead.operand(variable->local()));
+ node->convertToPhantom();
+ // This is only for Upsilons. An Upsilon will only refer to a
+ // PhantomLocal if there were no SetLocals or GetLocals in the block.
+ node->misc.replacement = block->variablesAtHead.operand(variable->local());
break;
}
case SetArgument: {
- node->remove();
+ VariableAccessData* variable = node->variableAccessData();
+ if (variable->isCaptured())
+ break;
+ node->setOpAndDefaultFlags(GetArgument);
+ node->mergeFlags(resultFor(node->variableAccessData()->flushFormat()));
break;
}
-
+
default:
break;
}
}
-
- // We want to insert Upsilons just before the end of the block. On the surface this
- // seems dangerous because the Upsilon will have a checking UseKind. But, we will not
- // actually be performing the check at the point of the Upsilon; the check will
- // already have been performed at the point where the original SetLocal was.
- NodeAndIndex terminal = block->findTerminal();
- size_t upsilonInsertionPoint = terminal.index;
- NodeOrigin upsilonOrigin = terminal.node->origin;
- for (unsigned successorIndex = block->numSuccessors(); successorIndex--;) {
- BasicBlock* successorBlock = block->successor(successorIndex);
- for (SSACalculator::Def* phiDef : m_calculator.phisForBlock(successorBlock)) {
- Node* phiNode = phiDef->value();
- SSACalculator::Variable* ssaVariable = phiDef->variable();
- VariableAccessData* variable = m_variableForSSAIndex[ssaVariable->index()];
- FlushFormat format = variable->flushFormat();
-
- // We can use an unchecked use kind because the SetLocal was turned into a Check.
- // We have to use an unchecked use because at least sometimes, the end of the block
- // is not exitOK.
- UseKind useKind = uncheckedUseKindFor(format);
-
- m_insertionSet.insertNode(
- upsilonInsertionPoint, SpecNone, Upsilon, upsilonOrigin,
- OpInfo(phiNode), Edge(
- valueForOperand.operand(variable->local()),
- useKind));
- }
- }
-
- m_insertionSet.execute(block);
}
// Free all CPS phis and reset variables vectors.
@@ -379,39 +374,95 @@ public:
block->variablesAtTail.clear();
block->valuesAtHead.clear();
block->valuesAtHead.clear();
- block->ssa = std::make_unique<BasicBlock::SSAData>(block);
+ block->ssa = adoptPtr(new BasicBlock::SSAData(block));
}
- m_graph.m_argumentFormats.resize(m_graph.m_arguments.size());
- for (unsigned i = m_graph.m_arguments.size(); i--;) {
- FlushFormat format = FlushedJSValue;
-
- Node* node = m_argumentMapping.get(m_graph.m_arguments[i]);
-
- RELEASE_ASSERT(node);
- format = node->stackAccessData()->format;
-
- m_graph.m_argumentFormats[i] = format;
- m_graph.m_arguments[i] = node; // Record the load that loads the arguments for the benefit of exit profiling.
- }
+ m_graph.m_arguments.clear();
m_graph.m_form = SSA;
+ return true;
+ }
- if (verbose) {
- dataLog("Graph after SSA transformation:\n");
- m_graph.dump();
+private:
+ void forwardPhiChildren(Node* node)
+ {
+ for (unsigned i = 0; i < AdjacencyList::Size; ++i) {
+ Edge& edge = node->children.child(i);
+ if (!edge)
+ break;
+ m_changed |= forwardPhiEdge(edge);
}
-
+ }
+
+ Node* forwardPhi(Node* node)
+ {
+ for (;;) {
+ switch (node->op()) {
+ case Phi: {
+ Edge edge = node->children.justOneChild();
+ if (!edge)
+ return node;
+ node = edge.node();
+ break;
+ }
+ case GetLocal:
+ case SetLocal:
+ if (node->variableAccessData()->isCaptured())
+ return node;
+ node = node->child1().node();
+ break;
+ default:
+ return node;
+ }
+ }
+ }
+
+ bool forwardPhiEdge(Edge& edge)
+ {
+ Node* newNode = forwardPhi(edge.node());
+ if (newNode == edge.node())
+ return false;
+ edge.setNode(newNode);
return true;
}
+
+ void deduplicateChildren(Node* node)
+ {
+ for (unsigned i = 0; i < AdjacencyList::Size; ++i) {
+ Edge edge = node->children.child(i);
+ if (!edge)
+ break;
+ if (edge == node) {
+ node->children.removeEdge(i--);
+ m_changed = true;
+ continue;
+ }
+ for (unsigned j = i + 1; j < AdjacencyList::Size; ++j) {
+ if (node->children.child(j) == edge) {
+ node->children.removeEdge(j--);
+ m_changed = true;
+ }
+ }
+ }
+ }
+
+ void addFlushedLocalOp(Node* node)
+ {
+ if (m_flushedLocalOps.contains(node))
+ return;
+ m_flushedLocalOps.add(node);
+ m_flushedLocalOpWorklist.append(node);
+ }
-private:
- SSACalculator m_calculator;
+ void addFlushedLocalEdge(Node*, Edge edge)
+ {
+ addFlushedLocalOp(edge.node());
+ }
+
InsertionSet m_insertionSet;
- HashMap<VariableAccessData*, SSACalculator::Variable*> m_ssaVariableForVariable;
- HashMap<Node*, Node*> m_argumentMapping;
- HashSet<Node*> m_argumentGetters;
- Vector<VariableAccessData*> m_variableForSSAIndex;
+ HashSet<Node*> m_flushedLocalOps;
+ Vector<Node*> m_flushedLocalOpWorklist;
+ bool m_changed;
};
bool performSSAConversion(Graph& graph)