summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/JavaScriptCore/dfg/DFGCSEPhase.cpp')
-rw-r--r--Source/JavaScriptCore/dfg/DFGCSEPhase.cpp1063
1 files changed, 574 insertions, 489 deletions
diff --git a/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp b/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp
index 36acb2c21..47af696a0 100644
--- a/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2011, 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
@@ -30,49 +30,54 @@
#include "DFGGraph.h"
#include "DFGPhase.h"
+#include "JSCellInlines.h"
+#include <wtf/FastBitVector.h>
namespace JSC { namespace DFG {
+enum CSEMode { NormalCSE, StoreElimination };
+
+template<CSEMode cseMode>
class CSEPhase : public Phase {
public:
CSEPhase(Graph& graph)
- : Phase(graph, "common subexpression elimination")
+ : Phase(graph, cseMode == NormalCSE ? "common subexpression elimination" : "store elimination")
{
- // Replacements are used to implement local common subexpression elimination.
- m_replacements.resize(m_graph.size());
-
- for (unsigned i = 0; i < m_graph.size(); ++i)
- m_replacements[i] = NoNode;
}
bool run()
{
+ ASSERT((cseMode == NormalCSE) == (m_graph.m_fixpointState == FixpointNotConverged));
+ ASSERT(m_graph.m_fixpointState != BeforeFixpoint);
+
m_changed = false;
+
for (unsigned block = 0; block < m_graph.m_blocks.size(); ++block)
performBlockCSE(m_graph.m_blocks[block].get());
+
return m_changed;
}
private:
- NodeIndex canonicalize(NodeIndex nodeIndex)
+ Node* canonicalize(Node* node)
{
- if (nodeIndex == NoNode)
- return NoNode;
+ if (!node)
+ return 0;
- if (m_graph[nodeIndex].op() == ValueToInt32)
- nodeIndex = m_graph[nodeIndex].child1().index();
+ if (node->op() == ValueToInt32)
+ node = node->child1().node();
- return nodeIndex;
+ return node;
}
- NodeIndex canonicalize(Edge nodeUse)
+ Node* canonicalize(Edge edge)
{
- return canonicalize(nodeUse.indexUnchecked());
+ return canonicalize(edge.node());
}
unsigned endIndexForPureCSE()
{
- unsigned result = m_lastSeen[m_graph[m_compileIndex].op()];
+ unsigned result = m_lastSeen[m_currentNode->op()];
if (result == UINT_MAX)
result = 0;
else
@@ -83,278 +88,300 @@ private:
#endif
return result;
}
-
- NodeIndex pureCSE(Node& node)
+
+ Node* pureCSE(Node* node)
{
- NodeIndex child1 = canonicalize(node.child1());
- NodeIndex child2 = canonicalize(node.child2());
- NodeIndex child3 = canonicalize(node.child3());
+ Node* child1 = canonicalize(node->child1());
+ Node* child2 = canonicalize(node->child2());
+ Node* child3 = canonicalize(node->child3());
for (unsigned i = endIndexForPureCSE(); i--;) {
- NodeIndex index = m_currentBlock->at(i);
- if (index == child1 || index == child2 || index == child3)
+ Node* otherNode = m_currentBlock->at(i);
+ if (otherNode == child1 || otherNode == child2 || otherNode == child3)
break;
- Node& otherNode = m_graph[index];
- if (!otherNode.shouldGenerate())
- continue;
-
- if (node.op() != otherNode.op())
+ if (node->op() != otherNode->op())
continue;
- if (node.arithNodeFlags() != otherNode.arithNodeFlags())
+ if (node->arithNodeFlags() != otherNode->arithNodeFlags())
continue;
- NodeIndex otherChild = canonicalize(otherNode.child1());
- if (otherChild == NoNode)
- return index;
+ Node* otherChild = canonicalize(otherNode->child1());
+ if (!otherChild)
+ return otherNode;
if (otherChild != child1)
continue;
- otherChild = canonicalize(otherNode.child2());
- if (otherChild == NoNode)
- return index;
+ otherChild = canonicalize(otherNode->child2());
+ if (!otherChild)
+ return otherNode;
if (otherChild != child2)
continue;
- otherChild = canonicalize(otherNode.child3());
- if (otherChild == NoNode)
- return index;
+ otherChild = canonicalize(otherNode->child3());
+ if (!otherChild)
+ return otherNode;
if (otherChild != child3)
continue;
- return index;
+ return otherNode;
}
- return NoNode;
+ return 0;
}
- NodeIndex constantCSE(Node& node)
+ Node* int32ToDoubleCSE(Node* node)
+ {
+ for (unsigned i = m_indexInBlock; i--;) {
+ Node* otherNode = m_currentBlock->at(i);
+ if (otherNode == node->child1())
+ return 0;
+ switch (otherNode->op()) {
+ case Int32ToDouble:
+ case ForwardInt32ToDouble:
+ if (otherNode->child1() == node->child1())
+ return otherNode;
+ break;
+ default:
+ break;
+ }
+ }
+ return 0;
+ }
+
+ Node* constantCSE(Node* node)
{
for (unsigned i = endIndexForPureCSE(); i--;) {
- NodeIndex index = m_currentBlock->at(i);
- Node& otherNode = m_graph[index];
- if (otherNode.op() != JSConstant)
+ Node* otherNode = m_currentBlock->at(i);
+ if (otherNode->op() != JSConstant)
continue;
- if (otherNode.constantNumber() != node.constantNumber())
+ if (otherNode->constantNumber() != node->constantNumber())
continue;
- return index;
+ return otherNode;
}
- return NoNode;
+ return 0;
}
- NodeIndex weakConstantCSE(Node& node)
+ Node* weakConstantCSE(Node* node)
{
for (unsigned i = endIndexForPureCSE(); i--;) {
- NodeIndex index = m_currentBlock->at(i);
- Node& otherNode = m_graph[index];
- if (otherNode.op() != WeakJSConstant)
+ Node* otherNode = m_currentBlock->at(i);
+ if (otherNode->op() != WeakJSConstant)
continue;
- if (otherNode.weakConstant() != node.weakConstant())
+ if (otherNode->weakConstant() != node->weakConstant())
continue;
- return index;
+ return otherNode;
}
- return NoNode;
+ return 0;
}
- NodeIndex getArrayLengthElimination(NodeIndex array)
+ Node* getCalleeLoadElimination(InlineCallFrame* inlineCallFrame)
{
for (unsigned i = m_indexInBlock; i--;) {
- NodeIndex index = m_currentBlock->at(i);
- Node& node = m_graph[index];
- if (!node.shouldGenerate())
+ Node* node = m_currentBlock->at(i);
+ if (node->codeOrigin.inlineCallFrame != inlineCallFrame)
continue;
- switch (node.op()) {
+ switch (node->op()) {
+ case GetCallee:
+ return node;
+ case SetCallee:
+ return node->child1().node();
+ default:
+ break;
+ }
+ }
+ return 0;
+ }
+
+ Node* getArrayLengthElimination(Node* array)
+ {
+ for (unsigned i = m_indexInBlock; i--;) {
+ Node* node = m_currentBlock->at(i);
+ switch (node->op()) {
case GetArrayLength:
- if (node.child1() == array)
- return index;
+ if (node->child1() == array)
+ return node;
break;
case PutByVal:
if (!m_graph.byValIsPure(node))
- return NoNode;
- if (node.arrayMode().mayStoreToHole())
- return NoNode;
+ return 0;
+ if (node->arrayMode().mayStoreToHole())
+ return 0;
break;
default:
- if (m_graph.clobbersWorld(index))
- return NoNode;
+ if (m_graph.clobbersWorld(node))
+ return 0;
}
}
- return NoNode;
+ return 0;
}
- NodeIndex globalVarLoadElimination(WriteBarrier<Unknown>* registerPointer)
+ Node* globalVarLoadElimination(WriteBarrier<Unknown>* registerPointer)
{
for (unsigned i = m_indexInBlock; i--;) {
- NodeIndex index = m_currentBlock->at(i);
- Node& node = m_graph[index];
- if (!node.shouldGenerate())
- continue;
- switch (node.op()) {
+ Node* node = m_currentBlock->at(i);
+ switch (node->op()) {
case GetGlobalVar:
- if (node.registerPointer() == registerPointer)
- return index;
+ if (node->registerPointer() == registerPointer)
+ return node;
break;
case PutGlobalVar:
- if (node.registerPointer() == registerPointer)
- return node.child1().index();
+ if (node->registerPointer() == registerPointer)
+ return node->child1().node();
break;
default:
break;
}
- if (m_graph.clobbersWorld(index))
+ if (m_graph.clobbersWorld(node))
break;
}
- return NoNode;
+ return 0;
}
- NodeIndex scopedVarLoadElimination(unsigned scopeChainDepth, unsigned varNumber)
+ Node* scopedVarLoadElimination(Node* registers, unsigned varNumber)
{
for (unsigned i = m_indexInBlock; i--;) {
- NodeIndex index = m_currentBlock->at(i);
- Node& node = m_graph[index];
- if (!node.shouldGenerate())
- continue;
- switch (node.op()) {
+ Node* node = m_currentBlock->at(i);
+ switch (node->op()) {
case GetScopedVar: {
- Node& getScopeRegisters = m_graph[node.child1()];
- Node& getScope = m_graph[getScopeRegisters.child1()];
- if (getScope.scopeChainDepth() == scopeChainDepth && node.varNumber() == varNumber)
- return index;
+ if (node->child1() == registers && node->varNumber() == varNumber)
+ return node;
break;
}
case PutScopedVar: {
- Node& getScope = m_graph[node.child1()];
- if (getScope.scopeChainDepth() == scopeChainDepth && node.varNumber() == varNumber)
- return node.child3().index();
+ if (node->child2() == registers && node->varNumber() == varNumber)
+ return node->child3().node();
+ break;
+ }
+ case SetLocal: {
+ VariableAccessData* variableAccessData = node->variableAccessData();
+ if (variableAccessData->isCaptured()
+ && variableAccessData->local() == static_cast<VirtualRegister>(varNumber))
+ return 0;
break;
}
default:
break;
}
- if (m_graph.clobbersWorld(index))
+ if (m_graph.clobbersWorld(node))
break;
}
- return NoNode;
+ return 0;
}
bool globalVarWatchpointElimination(WriteBarrier<Unknown>* registerPointer)
{
for (unsigned i = m_indexInBlock; i--;) {
- NodeIndex index = m_currentBlock->at(i);
- Node& node = m_graph[index];
- if (!node.shouldGenerate())
- continue;
- switch (node.op()) {
+ Node* node = m_currentBlock->at(i);
+ switch (node->op()) {
case GlobalVarWatchpoint:
- if (node.registerPointer() == registerPointer)
+ if (node->registerPointer() == registerPointer)
return true;
break;
case PutGlobalVar:
- if (node.registerPointer() == registerPointer)
+ if (node->registerPointer() == registerPointer)
return false;
break;
default:
break;
}
- if (m_graph.clobbersWorld(index))
+ if (m_graph.clobbersWorld(node))
break;
}
return false;
}
- NodeIndex globalVarStoreElimination(WriteBarrier<Unknown>* registerPointer)
+ Node* globalVarStoreElimination(WriteBarrier<Unknown>* registerPointer)
{
for (unsigned i = m_indexInBlock; i--;) {
- NodeIndex index = m_currentBlock->at(i);
- Node& node = m_graph[index];
- if (!node.shouldGenerate())
- continue;
- switch (node.op()) {
+ Node* node = m_currentBlock->at(i);
+ switch (node->op()) {
case PutGlobalVar:
case PutGlobalVarCheck:
- if (node.registerPointer() == registerPointer)
- return index;
+ if (node->registerPointer() == registerPointer)
+ return node;
break;
case GetGlobalVar:
- if (node.registerPointer() == registerPointer)
- return NoNode;
+ if (node->registerPointer() == registerPointer)
+ return 0;
break;
default:
break;
}
- if (m_graph.clobbersWorld(index) || node.canExit())
- return NoNode;
+ if (m_graph.clobbersWorld(node) || node->canExit())
+ return 0;
}
- return NoNode;
+ return 0;
}
- NodeIndex scopedVarStoreElimination(unsigned scopeChainDepth, unsigned varNumber)
+ Node* scopedVarStoreElimination(Node* scope, Node* registers, unsigned varNumber)
{
for (unsigned i = m_indexInBlock; i--;) {
- NodeIndex index = m_currentBlock->at(i);
- Node& node = m_graph[index];
- if (!node.shouldGenerate())
- continue;
- switch (node.op()) {
+ Node* node = m_currentBlock->at(i);
+ switch (node->op()) {
case PutScopedVar: {
- Node& getScope = m_graph[node.child1()];
- if (getScope.scopeChainDepth() == scopeChainDepth && node.varNumber() == varNumber)
- return index;
+ if (node->child1() == scope && node->child2() == registers && node->varNumber() == varNumber)
+ return node;
break;
}
case GetScopedVar: {
- Node& getScopeRegisters = m_graph[node.child1()];
- Node& getScope = m_graph[getScopeRegisters.child1()];
- if (getScope.scopeChainDepth() == scopeChainDepth && node.varNumber() == varNumber)
- return NoNode;
+ // Let's be conservative.
+ if (node->varNumber() == varNumber)
+ return 0;
+ break;
+ }
+
+ case GetLocal: {
+ VariableAccessData* variableAccessData = node->variableAccessData();
+ if (variableAccessData->isCaptured()
+ && variableAccessData->local() == static_cast<VirtualRegister>(varNumber))
+ return 0;
break;
}
default:
break;
}
- if (m_graph.clobbersWorld(index) || node.canExit())
- return NoNode;
+ if (m_graph.clobbersWorld(node) || node->canExit())
+ return 0;
}
- return NoNode;
+ return 0;
}
- NodeIndex getByValLoadElimination(NodeIndex child1, NodeIndex child2)
+ Node* getByValLoadElimination(Node* child1, Node* child2)
{
for (unsigned i = m_indexInBlock; i--;) {
- NodeIndex index = m_currentBlock->at(i);
- if (index == child1 || index == canonicalize(child2))
+ Node* node = m_currentBlock->at(i);
+ if (node == child1 || node == canonicalize(child2))
break;
- Node& node = m_graph[index];
- if (!node.shouldGenerate())
- continue;
- switch (node.op()) {
+ switch (node->op()) {
case GetByVal:
if (!m_graph.byValIsPure(node))
- return NoNode;
- if (node.child1() == child1 && canonicalize(node.child2()) == canonicalize(child2))
- return index;
+ return 0;
+ if (node->child1() == child1 && canonicalize(node->child2()) == canonicalize(child2))
+ return node;
break;
case PutByVal:
case PutByValAlias: {
if (!m_graph.byValIsPure(node))
- return NoNode;
+ return 0;
if (m_graph.varArgChild(node, 0) == child1 && canonicalize(m_graph.varArgChild(node, 1)) == canonicalize(child2))
- return m_graph.varArgChild(node, 2).index();
+ return m_graph.varArgChild(node, 2).node();
// We must assume that the PutByVal will clobber the location we're getting from.
// FIXME: We can do better; if we know that the PutByVal is accessing an array of a
// different type than the GetByVal, then we know that they won't clobber each other.
- return NoNode;
+ // ... except of course for typed arrays, where all typed arrays clobber all other
+ // typed arrays! An Int32Array can alias a Float64Array for example, and so on.
+ return 0;
}
case PutStructure:
case PutByOffset:
@@ -364,58 +391,67 @@ private:
// the GetByVal.
break;
default:
- if (m_graph.clobbersWorld(index))
- return NoNode;
+ if (m_graph.clobbersWorld(node))
+ return 0;
break;
}
}
- return NoNode;
+ return 0;
}
- bool checkFunctionElimination(JSCell* function, NodeIndex child1)
+ bool checkFunctionElimination(JSCell* function, Node* child1)
{
for (unsigned i = endIndexForPureCSE(); i--;) {
- NodeIndex index = m_currentBlock->at(i);
- if (index == child1)
+ Node* node = m_currentBlock->at(i);
+ if (node == child1)
break;
- Node& node = m_graph[index];
- if (node.op() == CheckFunction && node.child1() == child1 && node.function() == function)
+ if (node->op() == CheckFunction && node->child1() == child1 && node->function() == function)
return true;
}
return false;
}
+
+ bool checkExecutableElimination(ExecutableBase* executable, Node* child1)
+ {
+ for (unsigned i = endIndexForPureCSE(); i--;) {
+ Node* node = m_currentBlock->at(i);
+ if (node == child1)
+ break;
- bool checkStructureElimination(const StructureSet& structureSet, NodeIndex child1)
+ if (node->op() == CheckExecutable && node->child1() == child1 && node->executable() == executable)
+ return true;
+ }
+ return false;
+ }
+
+ bool checkStructureElimination(const StructureSet& structureSet, Node* child1)
{
for (unsigned i = m_indexInBlock; i--;) {
- NodeIndex index = m_currentBlock->at(i);
- if (index == child1)
+ Node* node = m_currentBlock->at(i);
+ if (node == child1)
break;
- Node& node = m_graph[index];
- if (!node.shouldGenerate())
- continue;
- switch (node.op()) {
+ switch (node->op()) {
case CheckStructure:
case ForwardCheckStructure:
- if (node.child1() == child1
- && structureSet.isSupersetOf(node.structureSet()))
+ if (node->child1() == child1
+ && structureSet.isSupersetOf(node->structureSet()))
return true;
break;
case StructureTransitionWatchpoint:
case ForwardStructureTransitionWatchpoint:
- if (node.child1() == child1
- && structureSet.contains(node.structure()))
+ if (node->child1() == child1
+ && structureSet.contains(node->structure()))
return true;
break;
case PutStructure:
- if (node.child1() == child1
- && structureSet.contains(node.structureTransitionData().newStructure))
+ if (node->child1() == child1
+ && structureSet.contains(node->structureTransitionData().newStructure))
return true;
- if (structureSet.contains(node.structureTransitionData().previousStructure))
+ if (structureSet.contains(node->structureTransitionData().previousStructure))
return false;
break;
@@ -440,7 +476,7 @@ private:
return false;
default:
- if (m_graph.clobbersWorld(index))
+ if (m_graph.clobbersWorld(node))
return false;
break;
}
@@ -448,26 +484,23 @@ private:
return false;
}
- bool structureTransitionWatchpointElimination(Structure* structure, NodeIndex child1)
+ bool structureTransitionWatchpointElimination(Structure* structure, Node* child1)
{
for (unsigned i = m_indexInBlock; i--;) {
- NodeIndex index = m_currentBlock->at(i);
- if (index == child1)
+ Node* node = m_currentBlock->at(i);
+ if (node == child1)
break;
- Node& node = m_graph[index];
- if (!node.shouldGenerate())
- continue;
- switch (node.op()) {
+ switch (node->op()) {
case CheckStructure:
case ForwardCheckStructure:
- if (node.child1() == child1
- && node.structureSet().containsOnly(structure))
+ if (node->child1() == child1
+ && node->structureSet().containsOnly(structure))
return true;
break;
case PutStructure:
- ASSERT(node.structureTransitionData().previousStructure != structure);
+ ASSERT(node->structureTransitionData().previousStructure != structure);
break;
case PutByOffset:
@@ -486,7 +519,7 @@ private:
case StructureTransitionWatchpoint:
case ForwardStructureTransitionWatchpoint:
- if (node.structure() == structure && node.child1() == child1)
+ if (node->structure() == structure && node->child1() == child1)
return true;
break;
@@ -497,7 +530,7 @@ private:
return false;
default:
- if (m_graph.clobbersWorld(index))
+ if (m_graph.clobbersWorld(node))
return false;
break;
}
@@ -505,28 +538,25 @@ private:
return false;
}
- NodeIndex putStructureStoreElimination(NodeIndex child1)
+ Node* putStructureStoreElimination(Node* child1)
{
for (unsigned i = m_indexInBlock; i--;) {
- NodeIndex index = m_currentBlock->at(i);
- if (index == child1)
+ Node* node = m_currentBlock->at(i);
+ if (node == child1)
break;
- Node& node = m_graph[index];
- if (!node.shouldGenerate())
- continue;
- switch (node.op()) {
+ switch (node->op()) {
case CheckStructure:
case ForwardCheckStructure:
- return NoNode;
+ return 0;
case PhantomPutStructure:
- if (node.child1() == child1) // No need to retrace our steps.
- return NoNode;
+ if (node->child1() == child1) // No need to retrace our steps.
+ return 0;
break;
case PutStructure:
- if (node.child1() == child1)
- return index;
+ if (node->child1() == child1)
+ return node;
break;
// PutStructure needs to execute if we GC. Hence this needs to
@@ -538,7 +568,6 @@ private:
case NewFunctionExpression:
case CreateActivation:
case TearOffActivation:
- case StrCat:
case ToPrimitive:
case NewRegexp:
case NewArrayBuffer:
@@ -547,39 +576,45 @@ private:
case CreateThis:
case AllocatePropertyStorage:
case ReallocatePropertyStorage:
- return NoNode;
+ case TypeOf:
+ case ToString:
+ case NewStringObject:
+ case MakeRope:
+ return 0;
+
+ case GetIndexedPropertyStorage:
+ if (node->arrayMode().getIndexedPropertyStorageMayTriggerGC())
+ return 0;
+ break;
default:
break;
}
- if (m_graph.clobbersWorld(index) || node.canExit())
- return NoNode;
+ if (m_graph.clobbersWorld(node) || node->canExit())
+ return 0;
}
- return NoNode;
+ return 0;
}
- NodeIndex getByOffsetLoadElimination(unsigned identifierNumber, NodeIndex child1)
+ Node* getByOffsetLoadElimination(unsigned identifierNumber, Node* child1)
{
for (unsigned i = m_indexInBlock; i--;) {
- NodeIndex index = m_currentBlock->at(i);
- if (index == child1)
+ Node* node = m_currentBlock->at(i);
+ if (node == child1)
break;
- Node& node = m_graph[index];
- if (!node.shouldGenerate())
- continue;
- switch (node.op()) {
+ switch (node->op()) {
case GetByOffset:
- if (node.child1() == child1
- && m_graph.m_storageAccessData[node.storageAccessDataIndex()].identifierNumber == identifierNumber)
- return index;
+ if (node->child1() == child1
+ && m_graph.m_storageAccessData[node->storageAccessDataIndex()].identifierNumber == identifierNumber)
+ return node;
break;
case PutByOffset:
- if (m_graph.m_storageAccessData[node.storageAccessDataIndex()].identifierNumber == identifierNumber) {
- if (node.child1() == child1) // Must be same property storage.
- return node.child3().index();
- return NoNode;
+ if (m_graph.m_storageAccessData[node->storageAccessDataIndex()].identifierNumber == identifierNumber) {
+ if (node->child1() == child1) // Must be same property storage.
+ return node->child3().node();
+ return 0;
}
break;
@@ -595,38 +630,35 @@ private:
// change.
break;
}
- return NoNode;
+ return 0;
default:
- if (m_graph.clobbersWorld(index))
- return NoNode;
+ if (m_graph.clobbersWorld(node))
+ return 0;
break;
}
}
- return NoNode;
+ return 0;
}
- NodeIndex putByOffsetStoreElimination(unsigned identifierNumber, NodeIndex child1)
+ Node* putByOffsetStoreElimination(unsigned identifierNumber, Node* child1)
{
for (unsigned i = m_indexInBlock; i--;) {
- NodeIndex index = m_currentBlock->at(i);
- if (index == child1)
+ Node* node = m_currentBlock->at(i);
+ if (node == child1)
break;
- Node& node = m_graph[index];
- if (!node.shouldGenerate())
- continue;
- switch (node.op()) {
+ switch (node->op()) {
case GetByOffset:
- if (m_graph.m_storageAccessData[node.storageAccessDataIndex()].identifierNumber == identifierNumber)
- return NoNode;
+ if (m_graph.m_storageAccessData[node->storageAccessDataIndex()].identifierNumber == identifierNumber)
+ return 0;
break;
case PutByOffset:
- if (m_graph.m_storageAccessData[node.storageAccessDataIndex()].identifierNumber == identifierNumber) {
- if (node.child1() == child1) // Must be same property storage.
- return index;
- return NoNode;
+ if (m_graph.m_storageAccessData[node->storageAccessDataIndex()].identifierNumber == identifierNumber) {
+ if (node->child1() == child1) // Must be same property storage.
+ return node;
+ return 0;
}
break;
@@ -639,45 +671,42 @@ private:
// change.
break;
}
- return NoNode;
+ return 0;
default:
- if (m_graph.clobbersWorld(index))
- return NoNode;
+ if (m_graph.clobbersWorld(node))
+ return 0;
break;
}
- if (node.canExit())
- return NoNode;
+ if (node->canExit())
+ return 0;
}
- return NoNode;
+ return 0;
}
- NodeIndex getPropertyStorageLoadElimination(NodeIndex child1)
+ Node* getPropertyStorageLoadElimination(Node* child1)
{
for (unsigned i = m_indexInBlock; i--;) {
- NodeIndex index = m_currentBlock->at(i);
- if (index == child1)
+ Node* node = m_currentBlock->at(i);
+ if (node == child1)
break;
- Node& node = m_graph[index];
- if (!node.shouldGenerate())
- continue;
- switch (node.op()) {
+ switch (node->op()) {
case GetButterfly:
- if (node.child1() == child1)
- return index;
+ if (node->child1() == child1)
+ return node;
break;
case AllocatePropertyStorage:
case ReallocatePropertyStorage:
// If we can cheaply prove this is a change to our object's storage, we
// can optimize and use its result.
- if (node.child1() == child1)
- return index;
+ if (node->child1() == child1)
+ return node;
// Otherwise, we currently can't prove that this doesn't change our object's
// storage, so we conservatively assume that it may change the storage
// pointer of any object, including ours.
- return NoNode;
+ return 0;
case PutByOffset:
case PutStructure:
@@ -693,34 +722,31 @@ private:
// change.
break;
}
- return NoNode;
+ return 0;
case Arrayify:
case ArrayifyToStructure:
// We could check if the arrayification could affect our butterfly.
// But that seems like it would take Effort.
- return NoNode;
+ return 0;
default:
- if (m_graph.clobbersWorld(index))
- return NoNode;
+ if (m_graph.clobbersWorld(node))
+ return 0;
break;
}
}
- return NoNode;
+ return 0;
}
- bool checkArrayElimination(NodeIndex child1, ArrayMode arrayMode)
+ bool checkArrayElimination(Node* child1, ArrayMode arrayMode)
{
for (unsigned i = m_indexInBlock; i--;) {
- NodeIndex index = m_currentBlock->at(i);
- if (index == child1)
+ Node* node = m_currentBlock->at(i);
+ if (node == child1)
break;
- Node& node = m_graph[index];
- if (!node.shouldGenerate())
- continue;
- switch (node.op()) {
+ switch (node->op()) {
case PutByOffset:
case PutStructure:
// Changing the structure or putting to the storage cannot
@@ -728,7 +754,7 @@ private:
break;
case CheckArray:
- if (node.child1() == child1 && node.arrayMode() == arrayMode)
+ if (node->child1() == child1 && node->arrayMode() == arrayMode)
return true;
break;
@@ -739,7 +765,7 @@ private:
return false;
default:
- if (m_graph.clobbersWorld(index))
+ if (m_graph.clobbersWorld(node))
return false;
break;
}
@@ -747,20 +773,17 @@ private:
return false;
}
- NodeIndex getIndexedPropertyStorageLoadElimination(NodeIndex child1, ArrayMode arrayMode)
+ Node* getIndexedPropertyStorageLoadElimination(Node* child1, ArrayMode arrayMode)
{
for (unsigned i = m_indexInBlock; i--;) {
- NodeIndex index = m_currentBlock->at(i);
- if (index == child1)
+ Node* node = m_currentBlock->at(i);
+ if (node == child1)
break;
- Node& node = m_graph[index];
- if (!node.shouldGenerate())
- continue;
- switch (node.op()) {
+ switch (node->op()) {
case GetIndexedPropertyStorage: {
- if (node.child1() == child1 && node.arrayMode() == arrayMode)
- return index;
+ if (node->child1() == child1 && node->arrayMode() == arrayMode)
+ return node;
break;
}
@@ -771,80 +794,75 @@ private:
break;
default:
- if (m_graph.clobbersWorld(index))
- return NoNode;
+ if (m_graph.clobbersWorld(node))
+ return 0;
break;
}
}
- return NoNode;
+ return 0;
}
- NodeIndex getScopeLoadElimination(unsigned depth)
- {
- for (unsigned i = endIndexForPureCSE(); i--;) {
- NodeIndex index = m_currentBlock->at(i);
- Node& node = m_graph[index];
- if (!node.shouldGenerate())
- continue;
- if (node.op() == GetScope
- && node.scopeChainDepth() == depth)
- return index;
- }
- return NoNode;
- }
-
- NodeIndex getScopeRegistersLoadElimination(unsigned depth)
+ Node* getMyScopeLoadElimination(InlineCallFrame* inlineCallFrame)
{
- for (unsigned i = endIndexForPureCSE(); i--;) {
- NodeIndex index = m_currentBlock->at(i);
- Node& node = m_graph[index];
- if (!node.shouldGenerate())
+ for (unsigned i = m_indexInBlock; i--;) {
+ Node* node = m_currentBlock->at(i);
+ if (node->codeOrigin.inlineCallFrame != inlineCallFrame)
continue;
- if (node.op() == GetScopeRegisters
- && m_graph[node.scope()].scopeChainDepth() == depth)
- return index;
+ switch (node->op()) {
+ case CreateActivation:
+ // This may cause us to return a different scope.
+ return 0;
+ case GetMyScope:
+ return node;
+ case SetMyScope:
+ return node->child1().node();
+ default:
+ break;
+ }
}
- return NoNode;
+ return 0;
}
- NodeIndex getLocalLoadElimination(VirtualRegister local, NodeIndex& relevantLocalOp, bool careAboutClobbering)
+ Node* getLocalLoadElimination(VirtualRegister local, Node*& relevantLocalOp, bool careAboutClobbering)
{
- relevantLocalOp = NoNode;
+ relevantLocalOp = 0;
for (unsigned i = m_indexInBlock; i--;) {
- NodeIndex index = m_currentBlock->at(i);
- Node& node = m_graph[index];
- if (!node.shouldGenerate())
- continue;
- switch (node.op()) {
+ Node* node = m_currentBlock->at(i);
+ switch (node->op()) {
case GetLocal:
- if (node.local() == local) {
- relevantLocalOp = index;
- return index;
+ if (node->local() == local) {
+ relevantLocalOp = node;
+ return node;
}
break;
case GetLocalUnlinked:
- if (node.unlinkedLocal() == local) {
- relevantLocalOp = index;
- return index;
+ if (node->unlinkedLocal() == local) {
+ relevantLocalOp = node;
+ return node;
}
break;
case SetLocal:
- if (node.local() == local) {
- relevantLocalOp = index;
- return node.child1().index();
+ if (node->local() == local) {
+ relevantLocalOp = node;
+ return node->child1().node();
}
break;
+ case PutScopedVar:
+ if (static_cast<VirtualRegister>(node->varNumber()) == local)
+ return 0;
+ break;
+
default:
- if (careAboutClobbering && m_graph.clobbersWorld(index))
- return NoNode;
+ if (careAboutClobbering && m_graph.clobbersWorld(node))
+ return 0;
break;
}
}
- return NoNode;
+ return 0;
}
struct SetLocalStoreEliminationResult {
@@ -860,46 +878,46 @@ private:
bool mayClobberWorld;
};
SetLocalStoreEliminationResult setLocalStoreElimination(
- VirtualRegister local, NodeIndex expectedNodeIndex)
+ VirtualRegister local, Node* expectedNode)
{
SetLocalStoreEliminationResult result;
for (unsigned i = m_indexInBlock; i--;) {
- NodeIndex index = m_currentBlock->at(i);
- Node& node = m_graph[index];
- if (!node.shouldGenerate())
- continue;
- switch (node.op()) {
+ Node* node = m_currentBlock->at(i);
+ switch (node->op()) {
case GetLocal:
case Flush:
- if (node.local() == local)
+ if (node->local() == local)
result.mayBeAccessed = true;
break;
case GetLocalUnlinked:
- if (node.unlinkedLocal() == local)
+ if (node->unlinkedLocal() == local)
result.mayBeAccessed = true;
break;
case SetLocal: {
- if (node.local() != local)
+ if (node->local() != local)
break;
- if (index != expectedNodeIndex)
- result.mayBeAccessed = true;
- if (m_graph[index].refCount() > 1)
+ if (node != expectedNode)
result.mayBeAccessed = true;
return result;
}
- case GetScope:
- case GetScopeRegisters:
- if (m_graph.uncheckedActivationRegisterFor(node.codeOrigin) == local)
+ case GetScopedVar:
+ if (static_cast<VirtualRegister>(node->varNumber()) == local)
+ result.mayBeAccessed = true;
+ break;
+
+ case GetMyScope:
+ case SkipTopScope:
+ if (m_graph.uncheckedActivationRegisterFor(node->codeOrigin) == local)
result.mayBeAccessed = true;
break;
case CheckArgumentsNotCreated:
case GetMyArgumentsLength:
case GetMyArgumentsLengthSafe:
- if (m_graph.uncheckedArgumentsRegisterFor(node.codeOrigin) == local)
+ if (m_graph.uncheckedArgumentsRegisterFor(node->codeOrigin) == local)
result.mayBeAccessed = true;
break;
@@ -910,7 +928,7 @@ private:
case GetByVal:
// If this is accessing arguments then it's potentially accessing locals.
- if (m_graph[node.child1()].shouldSpeculateArguments())
+ if (node->arrayMode().type() == Array::Arguments)
result.mayBeAccessed = true;
break;
@@ -927,58 +945,49 @@ private:
default:
break;
}
- result.mayExit |= node.canExit();
- result.mayClobberWorld |= m_graph.clobbersWorld(index);
+ result.mayExit |= node->canExit();
+ result.mayClobberWorld |= m_graph.clobbersWorld(node);
}
- ASSERT_NOT_REACHED();
+ RELEASE_ASSERT_NOT_REACHED();
// Be safe in release mode.
result.mayBeAccessed = true;
return result;
}
- void performSubstitution(Edge& child, bool addRef = true)
+ void eliminateIrrelevantPhantomChildren(Node* node)
{
- // Check if this operand is actually unused.
- if (!child)
- return;
-
- // Check if there is any replacement.
- NodeIndex replacement = m_replacements[child.index()];
- if (replacement == NoNode)
- return;
-
- child.setIndex(replacement);
-
- // There is definitely a replacement. Assert that the replacement does not
- // have a replacement.
- ASSERT(m_replacements[child.index()] == NoNode);
-
- if (addRef)
- m_graph[child].ref();
+ ASSERT(node->op() == Phantom);
+ for (unsigned i = 0; i < AdjacencyList::Size; ++i) {
+ Edge edge = node->children.child(i);
+ if (!edge)
+ continue;
+ if (edge.useKind() != UntypedUse)
+ continue; // Keep the type check.
+ if (edge->flags() & NodeRelevantToOSR)
+ continue;
+
+#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
+ dataLog(" Eliminating edge @", m_currentNode->index(), " -> @", edge->index());
+#endif
+ node->children.removeEdge(i--);
+ m_changed = true;
+ }
}
- enum PredictionHandlingMode { RequireSamePrediction, AllowPredictionMismatch };
- bool setReplacement(NodeIndex replacement, PredictionHandlingMode predictionHandlingMode = RequireSamePrediction)
+ bool setReplacement(Node* replacement)
{
- if (replacement == NoNode)
- return false;
-
- // Be safe. Don't try to perform replacements if the predictions don't
- // agree.
- if (predictionHandlingMode == RequireSamePrediction
- && m_graph[m_compileIndex].prediction() != m_graph[replacement].prediction())
+ if (!replacement)
return false;
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLogF(" Replacing @%u -> @%u", m_compileIndex, replacement);
+ dataLogF(" Replacing @%u -> @%u", m_currentNode->index(), replacement->index());
#endif
- Node& node = m_graph[m_compileIndex];
- node.setOpAndDefaultFlags(Phantom);
- node.setRefCount(1);
+ m_currentNode->convertToPhantom();
+ eliminateIrrelevantPhantomChildren(m_currentNode);
// At this point we will eliminate all references to this node.
- m_replacements[m_compileIndex] = replacement;
+ m_currentNode->replacement = replacement;
m_changed = true;
@@ -988,63 +997,55 @@ private:
void eliminate()
{
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLogF(" Eliminating @%u", m_compileIndex);
+ dataLogF(" Eliminating @%u", m_currentNode->index());
#endif
- Node& node = m_graph[m_compileIndex];
- ASSERT(node.refCount() == 1);
- ASSERT(node.mustGenerate());
- node.setOpAndDefaultFlags(Phantom);
+ ASSERT(m_currentNode->mustGenerate());
+ m_currentNode->convertToPhantom();
+ eliminateIrrelevantPhantomChildren(m_currentNode);
m_changed = true;
}
- void eliminate(NodeIndex nodeIndex, NodeType phantomType = Phantom)
+ void eliminate(Node* node, NodeType phantomType = Phantom)
{
- if (nodeIndex == NoNode)
+ if (!node)
return;
- Node& node = m_graph[nodeIndex];
- if (node.refCount() != 1)
- return;
- ASSERT(node.mustGenerate());
- node.setOpAndDefaultFlags(phantomType);
+ ASSERT(node->mustGenerate());
+ node->setOpAndDefaultNonExitFlags(phantomType);
+ if (phantomType == Phantom)
+ eliminateIrrelevantPhantomChildren(node);
m_changed = true;
}
- void performNodeCSE(Node& node)
+ void performNodeCSE(Node* node)
{
- bool shouldGenerate = node.shouldGenerate();
-
- if (node.flags() & NodeHasVarArgs) {
- for (unsigned childIdx = node.firstChild(); childIdx < node.firstChild() + node.numChildren(); childIdx++)
- performSubstitution(m_graph.m_varArgChildren[childIdx], shouldGenerate);
- } else {
- performSubstitution(node.children.child1(), shouldGenerate);
- performSubstitution(node.children.child2(), shouldGenerate);
- performSubstitution(node.children.child3(), shouldGenerate);
- }
+ if (cseMode == NormalCSE)
+ m_graph.performSubstitution(node);
- if (!shouldGenerate)
- return;
+ if (node->op() == SetLocal)
+ node->child1()->mergeFlags(NodeRelevantToOSR);
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLogF(" %s @%u: ", Graph::opName(m_graph[m_compileIndex].op()), m_compileIndex);
+ dataLogF(" %s @%u: ", Graph::opName(node->op()), node->index());
#endif
// NOTE: there are some nodes that we deliberately don't CSE even though we
- // probably could, like StrCat and ToPrimitive. That's because there is no
+ // probably could, like MakeRope and ToPrimitive. That's because there is no
// evidence that doing CSE on these nodes would result in a performance
// progression. Hence considering these nodes in CSE would just mean that this
// code does more work with no win. Of course, we may want to reconsider this,
- // since StrCat is trivially CSE-able. It's not trivially doable for
+ // since MakeRope is trivially CSE-able. It's not trivially doable for
// ToPrimitive, but we could change that with some speculations if we really
// needed to.
- switch (node.op()) {
+ switch (node->op()) {
case Identity:
- setReplacement(node.child1().index());
+ if (cseMode == StoreElimination)
+ break;
+ setReplacement(node->child1().node());
break;
// Handle the pure nodes. These nodes never have any side-effects.
@@ -1058,16 +1059,15 @@ private:
case ArithSub:
case ArithNegate:
case ArithMul:
+ case ArithIMul:
case ArithMod:
case ArithDiv:
case ArithAbs:
case ArithMin:
case ArithMax:
case ArithSqrt:
- case GetCallee:
case StringCharAt:
case StringCharCodeAt:
- case Int32ToDouble:
case IsUndefined:
case IsBoolean:
case IsNumber:
@@ -1076,64 +1076,77 @@ private:
case IsFunction:
case DoubleAsInt32:
case LogicalNot:
+ case SkipTopScope:
+ case SkipScope:
+ case GetScopeRegisters:
+ case GetScope:
+ case TypeOf:
+ case CompareEqConstant:
+ case ValueToInt32:
+ if (cseMode == StoreElimination)
+ break;
setReplacement(pureCSE(node));
break;
+ case Int32ToDouble:
+ case ForwardInt32ToDouble:
+ if (cseMode == StoreElimination)
+ break;
+ setReplacement(int32ToDoubleCSE(node));
+ break;
+
+ case GetCallee:
+ if (cseMode == StoreElimination)
+ break;
+ setReplacement(getCalleeLoadElimination(node->codeOrigin.inlineCallFrame));
+ break;
+
case GetLocal: {
- VariableAccessData* variableAccessData = node.variableAccessData();
+ if (cseMode == StoreElimination)
+ break;
+ VariableAccessData* variableAccessData = node->variableAccessData();
if (!variableAccessData->isCaptured())
break;
- NodeIndex relevantLocalOp;
- NodeIndex possibleReplacement = getLocalLoadElimination(variableAccessData->local(), relevantLocalOp, variableAccessData->isCaptured());
- if (relevantLocalOp == NoNode)
+ Node* relevantLocalOp;
+ Node* possibleReplacement = getLocalLoadElimination(variableAccessData->local(), relevantLocalOp, variableAccessData->isCaptured());
+ if (!relevantLocalOp)
break;
- if (m_graph[relevantLocalOp].op() != GetLocalUnlinked
- && m_graph[relevantLocalOp].variableAccessData() != variableAccessData)
+ if (relevantLocalOp->op() != GetLocalUnlinked
+ && relevantLocalOp->variableAccessData() != variableAccessData)
break;
- NodeIndex phiIndex = node.child1().index();
+ Node* phi = node->child1().node();
if (!setReplacement(possibleReplacement))
break;
- // If the GetLocal we replaced used to refer to a SetLocal, then it now
- // should refer to the child of the SetLocal instead.
- if (m_graph[phiIndex].op() == SetLocal) {
- ASSERT(node.child1().index() == phiIndex);
- m_graph.changeEdge(node.children.child1(), m_graph[phiIndex].child1());
- }
- NodeIndex oldTailIndex = m_currentBlock->variablesAtTail.operand(
- variableAccessData->local());
- if (oldTailIndex == m_compileIndex) {
- m_currentBlock->variablesAtTail.operand(variableAccessData->local()) =
- relevantLocalOp;
-
- // Maintain graph integrity: since we're replacing a GetLocal with a GetLocalUnlinked,
- // make sure that the GetLocalUnlinked is now linked.
- if (m_graph[relevantLocalOp].op() == GetLocalUnlinked) {
- m_graph[relevantLocalOp].setOp(GetLocal);
- m_graph[relevantLocalOp].children.child1() = Edge(phiIndex);
- m_graph.ref(phiIndex);
- }
- }
+
+ m_graph.dethread();
+
+ // If we replace a GetLocal with a GetLocalUnlinked, then turn the GetLocalUnlinked
+ // into a GetLocal.
+ if (relevantLocalOp->op() == GetLocalUnlinked)
+ relevantLocalOp->convertToGetLocal(variableAccessData, phi);
+
m_changed = true;
break;
}
case GetLocalUnlinked: {
- NodeIndex relevantLocalOpIgnored;
- setReplacement(getLocalLoadElimination(node.unlinkedLocal(), relevantLocalOpIgnored, true));
+ if (cseMode == StoreElimination)
+ break;
+ Node* relevantLocalOpIgnored;
+ setReplacement(getLocalLoadElimination(node->unlinkedLocal(), relevantLocalOpIgnored, true));
break;
}
case Flush: {
- VariableAccessData* variableAccessData = node.variableAccessData();
+ VariableAccessData* variableAccessData = node->variableAccessData();
VirtualRegister local = variableAccessData->local();
- NodeIndex replacementIndex = node.child1().index();
- Node& replacement = m_graph[replacementIndex];
- if (replacement.op() != SetLocal)
+ Node* replacement = node->child1().node();
+ if (replacement->op() != SetLocal)
break;
- ASSERT(replacement.variableAccessData() == variableAccessData);
+ ASSERT(replacement->variableAccessData() == variableAccessData);
// FIXME: We should be able to remove SetLocals that can exit; we just need
// to replace them with appropriate type checks.
- if (m_graph.m_fixpointState == FixpointNotConverged) {
+ if (cseMode == NormalCSE) {
// Need to be conservative at this time; if the SetLocal has any chance of performing
// any speculations then we cannot do anything.
if (variableAccessData->isCaptured()) {
@@ -1150,53 +1163,52 @@ private:
break;
}
} else {
- if (replacement.canExit())
+ if (replacement->canExit())
break;
}
SetLocalStoreEliminationResult result =
- setLocalStoreElimination(local, replacementIndex);
+ setLocalStoreElimination(local, replacement);
if (result.mayBeAccessed || result.mayClobberWorld)
break;
- ASSERT(replacement.op() == SetLocal);
- ASSERT(replacement.refCount() == 1);
- ASSERT(replacement.shouldGenerate());
+ ASSERT(replacement->op() == SetLocal);
// FIXME: Investigate using mayExit as a further optimization.
- node.setOpAndDefaultFlags(Phantom);
- NodeIndex dataNodeIndex = replacement.child1().index();
- ASSERT(m_graph[dataNodeIndex].hasResult());
+ node->convertToPhantom();
+ Node* dataNode = replacement->child1().node();
+ ASSERT(dataNode->hasResult());
m_graph.clearAndDerefChild1(node);
- node.children.child1() = Edge(dataNodeIndex);
- m_graph.ref(dataNodeIndex);
- NodeIndex oldTailIndex = m_currentBlock->variablesAtTail.operand(local);
- if (oldTailIndex == m_compileIndex)
- m_currentBlock->variablesAtTail.operand(local) = replacementIndex;
+ node->children.child1() = Edge(dataNode);
+ m_graph.dethread();
m_changed = true;
break;
}
case JSConstant:
+ if (cseMode == StoreElimination)
+ break;
// This is strange, but necessary. Some phases will convert nodes to constants,
// which may result in duplicated constants. We use CSE to clean this up.
- setReplacement(constantCSE(node), AllowPredictionMismatch);
+ setReplacement(constantCSE(node));
break;
case WeakJSConstant:
+ if (cseMode == StoreElimination)
+ break;
// FIXME: have CSE for weak constants against strong constants and vice-versa.
setReplacement(weakConstantCSE(node));
break;
case GetArrayLength:
- setReplacement(getArrayLengthElimination(node.child1().index()));
- break;
-
- case GetScope:
- setReplacement(getScopeLoadElimination(node.scopeChainDepth()));
+ if (cseMode == StoreElimination)
+ break;
+ setReplacement(getArrayLengthElimination(node->child1().node()));
break;
- case GetScopeRegisters:
- setReplacement(getScopeRegistersLoadElimination(m_graph[node.scope()].scopeChainDepth()));
+ case GetMyScope:
+ if (cseMode == StoreElimination)
+ break;
+ setReplacement(getMyScopeLoadElimination(node->codeOrigin.inlineCallFrame));
break;
-
+
// Handle nodes that are conditionally pure: these are pure, and can
// be CSE'd, so long as the prediction is the one we want.
case ValueAdd:
@@ -1205,10 +1217,12 @@ private:
case CompareGreater:
case CompareGreaterEq:
case CompareEq: {
+ if (cseMode == StoreElimination)
+ break;
if (m_graph.isPredictedNumerical(node)) {
- NodeIndex replacementIndex = pureCSE(node);
- if (replacementIndex != NoNode && m_graph.isPredictedNumerical(m_graph[replacementIndex]))
- setReplacement(replacementIndex);
+ Node* replacement = pureCSE(node);
+ if (replacement && m_graph.isPredictedNumerical(replacement))
+ setReplacement(replacement);
}
break;
}
@@ -1216,98 +1230,132 @@ private:
// Finally handle heap accesses. These are not quite pure, but we can still
// optimize them provided that some subtle conditions are met.
case GetGlobalVar:
- setReplacement(globalVarLoadElimination(node.registerPointer()));
+ if (cseMode == StoreElimination)
+ break;
+ setReplacement(globalVarLoadElimination(node->registerPointer()));
break;
case GetScopedVar: {
- Node& getScopeRegisters = m_graph[node.child1()];
- Node& getScope = m_graph[getScopeRegisters.child1()];
- setReplacement(scopedVarLoadElimination(getScope.scopeChainDepth(), node.varNumber()));
+ if (cseMode == StoreElimination)
+ break;
+ setReplacement(scopedVarLoadElimination(node->child1().node(), node->varNumber()));
break;
}
case GlobalVarWatchpoint:
- if (globalVarWatchpointElimination(node.registerPointer()))
+ if (cseMode == StoreElimination)
+ break;
+ if (globalVarWatchpointElimination(node->registerPointer()))
eliminate();
break;
case PutGlobalVar:
case PutGlobalVarCheck:
- if (m_graph.m_fixpointState == FixpointNotConverged)
+ if (cseMode == NormalCSE)
break;
- eliminate(globalVarStoreElimination(node.registerPointer()));
+ eliminate(globalVarStoreElimination(node->registerPointer()));
break;
case PutScopedVar: {
- if (m_graph.m_fixpointState == FixpointNotConverged)
+ if (cseMode == NormalCSE)
break;
- Node& getScope = m_graph[node.child1()];
- eliminate(scopedVarStoreElimination(getScope.scopeChainDepth(), node.varNumber()));
+ eliminate(scopedVarStoreElimination(node->child1().node(), node->child2().node(), node->varNumber()));
break;
}
case GetByVal:
+ if (cseMode == StoreElimination)
+ break;
if (m_graph.byValIsPure(node))
- setReplacement(getByValLoadElimination(node.child1().index(), node.child2().index()));
+ setReplacement(getByValLoadElimination(node->child1().node(), node->child2().node()));
break;
case PutByVal: {
+ if (cseMode == StoreElimination)
+ break;
Edge child1 = m_graph.varArgChild(node, 0);
Edge child2 = m_graph.varArgChild(node, 1);
- if (node.arrayMode().canCSEStorage()) {
- NodeIndex nodeIndex = getByValLoadElimination(child1.index(), child2.index());
- if (nodeIndex == NoNode)
+ if (node->arrayMode().canCSEStorage()) {
+ Node* replacement = getByValLoadElimination(child1.node(), child2.node());
+ if (!replacement)
break;
- node.setOp(PutByValAlias);
+ node->setOp(PutByValAlias);
}
break;
}
case CheckStructure:
case ForwardCheckStructure:
- if (checkStructureElimination(node.structureSet(), node.child1().index()))
+ if (cseMode == StoreElimination)
+ break;
+ if (checkStructureElimination(node->structureSet(), node->child1().node()))
eliminate();
break;
case StructureTransitionWatchpoint:
case ForwardStructureTransitionWatchpoint:
- if (structureTransitionWatchpointElimination(node.structure(), node.child1().index()))
+ if (cseMode == StoreElimination)
+ break;
+ if (structureTransitionWatchpointElimination(node->structure(), node->child1().node()))
eliminate();
break;
case PutStructure:
- if (m_graph.m_fixpointState == FixpointNotConverged)
+ if (cseMode == NormalCSE)
break;
- eliminate(putStructureStoreElimination(node.child1().index()), PhantomPutStructure);
+ eliminate(putStructureStoreElimination(node->child1().node()), PhantomPutStructure);
break;
case CheckFunction:
- if (checkFunctionElimination(node.function(), node.child1().index()))
+ if (cseMode == StoreElimination)
+ break;
+ if (checkFunctionElimination(node->function(), node->child1().node()))
+ eliminate();
+ break;
+
+ case CheckExecutable:
+ if (cseMode == StoreElimination)
+ break;
+ if (checkExecutableElimination(node->executable(), node->child1().node()))
eliminate();
break;
case CheckArray:
- if (checkArrayElimination(node.child1().index(), node.arrayMode()))
+ if (cseMode == StoreElimination)
+ break;
+ if (checkArrayElimination(node->child1().node(), node->arrayMode()))
eliminate();
break;
case GetIndexedPropertyStorage: {
- setReplacement(getIndexedPropertyStorageLoadElimination(node.child1().index(), node.arrayMode()));
+ if (cseMode == StoreElimination)
+ break;
+ setReplacement(getIndexedPropertyStorageLoadElimination(node->child1().node(), node->arrayMode()));
break;
}
case GetButterfly:
- setReplacement(getPropertyStorageLoadElimination(node.child1().index()));
+ if (cseMode == StoreElimination)
+ break;
+ setReplacement(getPropertyStorageLoadElimination(node->child1().node()));
break;
case GetByOffset:
- setReplacement(getByOffsetLoadElimination(m_graph.m_storageAccessData[node.storageAccessDataIndex()].identifierNumber, node.child1().index()));
+ if (cseMode == StoreElimination)
+ break;
+ setReplacement(getByOffsetLoadElimination(m_graph.m_storageAccessData[node->storageAccessDataIndex()].identifierNumber, node->child1().node()));
break;
case PutByOffset:
- if (m_graph.m_fixpointState == FixpointNotConverged)
+ if (cseMode == NormalCSE)
break;
- eliminate(putByOffsetStoreElimination(m_graph.m_storageAccessData[node.storageAccessDataIndex()].identifierNumber, node.child1().index()));
+ eliminate(putByOffsetStoreElimination(m_graph.m_storageAccessData[node->storageAccessDataIndex()].identifierNumber, node->child1().node()));
+ break;
+
+ case Phantom:
+ // FIXME: we ought to remove Phantom's that have no children.
+
+ eliminateIrrelevantPhantomChildren(node);
break;
default:
@@ -1315,7 +1363,7 @@ private:
break;
}
- m_lastSeen[node.op()] = m_indexInBlock;
+ m_lastSeen[node->op()] = m_indexInBlock;
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
dataLogF("\n");
#endif
@@ -1331,17 +1379,48 @@ private:
m_currentBlock = block;
for (unsigned i = 0; i < LastNodeType; ++i)
m_lastSeen[i] = UINT_MAX;
+
+ // All Phis need to already be marked as relevant to OSR, and have their
+ // replacements cleared, so we don't get confused while doing substitutions on
+ // GetLocal's.
+ for (unsigned i = 0; i < block->phis.size(); ++i) {
+ ASSERT(block->phis[i]->flags() & NodeRelevantToOSR);
+ block->phis[i]->replacement = 0;
+ }
+
+ // Make all of my SetLocal and GetLocal nodes relevant to OSR, and do some other
+ // necessary bookkeeping.
+ for (unsigned i = 0; i < block->size(); ++i) {
+ Node* node = block->at(i);
+
+ node->replacement = 0;
+
+ switch (node->op()) {
+ case SetLocal:
+ case GetLocal: // FIXME: The GetLocal case is only necessary until we do https://bugs.webkit.org/show_bug.cgi?id=106707.
+ node->mergeFlags(NodeRelevantToOSR);
+ break;
+ default:
+ node->clearFlags(NodeRelevantToOSR);
+ break;
+ }
+ }
for (m_indexInBlock = 0; m_indexInBlock < block->size(); ++m_indexInBlock) {
- m_compileIndex = block->at(m_indexInBlock);
- performNodeCSE(m_graph[m_compileIndex]);
+ m_currentNode = block->at(m_indexInBlock);
+ performNodeCSE(m_currentNode);
+ }
+
+ if (!ASSERT_DISABLED && cseMode == StoreElimination) {
+ // Nobody should have replacements set.
+ for (unsigned i = 0; i < block->size(); ++i)
+ ASSERT(!block->at(i)->replacement);
}
}
BasicBlock* m_currentBlock;
- NodeIndex m_compileIndex;
+ Node* m_currentNode;
unsigned m_indexInBlock;
- Vector<NodeIndex, 16> m_replacements;
FixedArray<unsigned, LastNodeType> m_lastSeen;
bool m_changed; // Only tracks changes that have a substantive effect on other optimizations.
};
@@ -1349,7 +1428,13 @@ private:
bool performCSE(Graph& graph)
{
SamplingRegion samplingRegion("DFG CSE Phase");
- return runPhase<CSEPhase>(graph);
+ return runPhase<CSEPhase<NormalCSE> >(graph);
+}
+
+bool performStoreElimination(Graph& graph)
+{
+ SamplingRegion samplingRegion("DFG Store Elimination Phase");
+ return runPhase<CSEPhase<StoreElimination> >(graph);
}
} } // namespace JSC::DFG