summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp')
-rw-r--r--Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp343
1 files changed, 153 insertions, 190 deletions
diff --git a/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp b/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp
index 2221954b5..39ac2ff7a 100644
--- a/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.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
@@ -34,6 +34,7 @@
#include "DFGInsertionSet.h"
#include "DFGPhase.h"
#include "GetByIdStatus.h"
+#include "Operations.h"
#include "PutByIdStatus.h"
namespace JSC { namespace DFG {
@@ -43,6 +44,7 @@ public:
ConstantFoldingPhase(Graph& graph)
: Phase(graph, "constant folding")
, m_state(graph)
+ , m_insertionSet(graph)
{
}
@@ -73,22 +75,20 @@ private:
bool changed = false;
m_state.beginBasicBlock(block);
for (unsigned indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) {
- NodeIndex nodeIndex = block->at(indexInBlock);
- Node& node = m_graph[nodeIndex];
-
if (!m_state.isValid())
break;
+ Node* node = block->at(indexInBlock);
+
bool eliminated = false;
- switch (node.op()) {
+ switch (node->op()) {
case CheckArgumentsNotCreated: {
if (!isEmptySpeculation(
m_state.variables().operand(
- m_graph.argumentsRegisterFor(node.codeOrigin)).m_type))
+ m_graph.argumentsRegisterFor(node->codeOrigin)).m_type))
break;
- ASSERT(node.refCount() == 1);
- node.setOpAndDefaultFlags(Phantom);
+ node->convertToPhantom();
eliminated = true;
break;
}
@@ -96,61 +96,55 @@ private:
case CheckStructure:
case ForwardCheckStructure:
case ArrayifyToStructure: {
- AbstractValue& value = m_state.forNode(node.child1());
+ AbstractValue& value = m_state.forNode(node->child1());
StructureSet set;
- if (node.op() == ArrayifyToStructure)
- set = node.structure();
+ if (node->op() == ArrayifyToStructure)
+ set = node->structure();
else
- set = node.structureSet();
+ set = node->structureSet();
if (value.m_currentKnownStructure.isSubsetOf(set)) {
- ASSERT(node.refCount() == 1);
- node.setOpAndDefaultFlags(Phantom);
+ m_state.execute(indexInBlock); // Catch the fact that we may filter on cell.
+ node->convertToPhantom();
eliminated = true;
break;
}
StructureAbstractValue& structureValue = value.m_futurePossibleStructure;
if (structureValue.isSubsetOf(set)
- && structureValue.hasSingleton()
- && isCellSpeculation(value.m_type)) {
- node.convertToStructureTransitionWatchpoint(structureValue.singleton());
- changed = true;
+ && structureValue.hasSingleton()) {
+ Structure* structure = structureValue.singleton();
+ m_state.execute(indexInBlock); // Catch the fact that we may filter on cell.
+ node->convertToStructureTransitionWatchpoint(structure);
+ eliminated = true;
+ break;
}
break;
}
case CheckArray:
case Arrayify: {
- if (!node.arrayMode().alreadyChecked(m_graph, node, m_state.forNode(node.child1())))
+ if (!node->arrayMode().alreadyChecked(m_graph, node, m_state.forNode(node->child1())))
break;
- ASSERT(node.refCount() == 1);
- node.setOpAndDefaultFlags(Phantom);
+ node->convertToPhantom();
eliminated = true;
break;
}
case CheckFunction: {
- if (m_state.forNode(node.child1()).value() != node.function())
+ if (m_state.forNode(node->child1()).value() != node->function())
break;
- node.setOpAndDefaultFlags(Phantom);
+ node->convertToPhantom();
eliminated = true;
break;
}
- case ConvertThis: {
- if (!isObjectSpeculation(m_state.forNode(node.child1()).m_type))
- break;
- node.setOpAndDefaultFlags(Identity);
- changed = true;
- break;
- }
-
case GetById:
case GetByIdFlush: {
- CodeOrigin codeOrigin = node.codeOrigin;
- NodeIndex child = node.child1().index();
- unsigned identifierNumber = node.identifierNumber();
+ CodeOrigin codeOrigin = node->codeOrigin;
+ Edge childEdge = node->child1();
+ Node* child = childEdge.node();
+ unsigned identifierNumber = node->identifierNumber();
- if (!isCellSpeculation(m_graph[child].prediction()))
+ if (childEdge.useKind() != CellUse)
break;
Structure* structure = m_state.forNode(child).bestProvenStructure();
@@ -158,12 +152,16 @@ private:
break;
bool needsWatchpoint = !m_state.forNode(child).m_currentKnownStructure.hasSingleton();
+ bool needsCellCheck = m_state.forNode(child).m_type & ~SpecCell;
GetByIdStatus status = GetByIdStatus::computeFor(
- globalData(), structure, codeBlock()->identifier(identifierNumber));
+ vm(), structure, codeBlock()->identifier(identifierNumber));
- if (!status.isSimple())
+ if (!status.isSimple()) {
+ // FIXME: We could handle prototype cases.
+ // https://bugs.webkit.org/show_bug.cgi?id=110386
break;
+ }
ASSERT(status.structureSet().size() == 1);
ASSERT(status.chain().isEmpty());
@@ -177,28 +175,26 @@ private:
if (needsWatchpoint) {
ASSERT(m_state.forNode(child).m_futurePossibleStructure.isSubsetOf(StructureSet(structure)));
- m_graph[child].ref();
- Node watchpoint(StructureTransitionWatchpoint, codeOrigin, OpInfo(structure), child);
- watchpoint.ref();
- NodeIndex watchpointIndex = m_graph.size();
- m_graph.append(watchpoint);
- m_insertionSet.append(indexInBlock, watchpointIndex);
+ m_insertionSet.insertNode(
+ indexInBlock, SpecNone, StructureTransitionWatchpoint, codeOrigin,
+ OpInfo(structure), childEdge);
+ } else if (needsCellCheck) {
+ m_insertionSet.insertNode(
+ indexInBlock, SpecNone, Phantom, codeOrigin, childEdge);
}
- NodeIndex propertyStorageIndex;
+ childEdge.setUseKind(KnownCellUse);
+
+ Edge propertyStorage;
- m_graph[child].ref();
if (isInlineOffset(status.offset()))
- propertyStorageIndex = child;
+ propertyStorage = childEdge;
else {
- Node getButterfly(GetButterfly, codeOrigin, child);
- getButterfly.ref();
- propertyStorageIndex = m_graph.size();
- m_graph.append(getButterfly);
- m_insertionSet.append(indexInBlock, propertyStorageIndex);
+ propertyStorage = Edge(m_insertionSet.insertNode(
+ indexInBlock, SpecNone, GetButterfly, codeOrigin, childEdge));
}
- m_graph[nodeIndex].convertToGetByOffset(m_graph.m_storageAccessData.size(), propertyStorageIndex);
+ node->convertToGetByOffset(m_graph.m_storageAccessData.size(), propertyStorage);
StorageAccessData storageAccessData;
storageAccessData.offset = indexRelativeToBase(status.offset());
@@ -209,22 +205,26 @@ private:
case PutById:
case PutByIdDirect: {
- CodeOrigin codeOrigin = node.codeOrigin;
- NodeIndex child = node.child1().index();
- unsigned identifierNumber = node.identifierNumber();
+ CodeOrigin codeOrigin = node->codeOrigin;
+ Edge childEdge = node->child1();
+ Node* child = childEdge.node();
+ unsigned identifierNumber = node->identifierNumber();
+
+ ASSERT(childEdge.useKind() == CellUse);
Structure* structure = m_state.forNode(child).bestProvenStructure();
if (!structure)
break;
bool needsWatchpoint = !m_state.forNode(child).m_currentKnownStructure.hasSingleton();
+ bool needsCellCheck = m_state.forNode(child).m_type & ~SpecCell;
PutByIdStatus status = PutByIdStatus::computeFor(
- globalData(),
+ vm(),
m_graph.globalObjectFor(codeOrigin),
structure,
codeBlock()->identifier(identifierNumber),
- node.op() == PutByIdDirect);
+ node->op() == PutByIdDirect);
if (!status.isSimpleReplace() && !status.isSimpleTransition())
break;
@@ -239,20 +239,22 @@ private:
if (needsWatchpoint) {
ASSERT(m_state.forNode(child).m_futurePossibleStructure.isSubsetOf(StructureSet(structure)));
- m_graph[child].ref();
- Node watchpoint(StructureTransitionWatchpoint, codeOrigin, OpInfo(structure), child);
- watchpoint.ref();
- NodeIndex watchpointIndex = m_graph.size();
- m_graph.append(watchpoint);
- m_insertionSet.append(indexInBlock, watchpointIndex);
+ m_insertionSet.insertNode(
+ indexInBlock, SpecNone, StructureTransitionWatchpoint, codeOrigin,
+ OpInfo(structure), childEdge);
+ } else if (needsCellCheck) {
+ m_insertionSet.insertNode(
+ indexInBlock, SpecNone, Phantom, codeOrigin, childEdge);
}
+ childEdge.setUseKind(KnownCellUse);
+
StructureTransitionData* transitionData = 0;
if (status.isSimpleTransition()) {
transitionData = m_graph.addStructureTransitionData(
StructureTransitionData(structure, status.newStructure()));
- if (node.op() == PutById) {
+ if (node->op() == PutById) {
if (!structure->storedPrototype().isNull()) {
addStructureTransitionCheck(
codeOrigin, indexInBlock,
@@ -269,57 +271,39 @@ private:
}
}
}
-
- NodeIndex propertyStorageIndex;
- m_graph[child].ref();
+ Edge propertyStorage;
+
if (isInlineOffset(status.offset()))
- propertyStorageIndex = child;
+ propertyStorage = childEdge;
else if (status.isSimpleReplace() || structure->outOfLineCapacity() == status.newStructure()->outOfLineCapacity()) {
- Node getButterfly(GetButterfly, codeOrigin, child);
- getButterfly.ref();
- propertyStorageIndex = m_graph.size();
- m_graph.append(getButterfly);
- m_insertionSet.append(indexInBlock, propertyStorageIndex);
+ propertyStorage = Edge(m_insertionSet.insertNode(
+ indexInBlock, SpecNone, GetButterfly, codeOrigin, childEdge));
} else if (!structure->outOfLineCapacity()) {
ASSERT(status.newStructure()->outOfLineCapacity());
ASSERT(!isInlineOffset(status.offset()));
- Node allocateStorage(AllocatePropertyStorage, codeOrigin, OpInfo(transitionData), child);
- allocateStorage.ref(); // Once for the use.
- allocateStorage.ref(); // Twice because it's must-generate.
- propertyStorageIndex = m_graph.size();
- m_graph.append(allocateStorage);
- m_insertionSet.append(indexInBlock, propertyStorageIndex);
+ propertyStorage = Edge(m_insertionSet.insertNode(
+ indexInBlock, SpecNone, AllocatePropertyStorage,
+ codeOrigin, OpInfo(transitionData), childEdge));
} else {
ASSERT(structure->outOfLineCapacity());
ASSERT(status.newStructure()->outOfLineCapacity() > structure->outOfLineCapacity());
ASSERT(!isInlineOffset(status.offset()));
- Node getButterfly(GetButterfly, codeOrigin, child);
- getButterfly.ref();
- NodeIndex getButterflyIndex = m_graph.size();
- m_graph.append(getButterfly);
- m_insertionSet.append(indexInBlock, getButterflyIndex);
-
- m_graph[child].ref();
- Node reallocateStorage(ReallocatePropertyStorage, codeOrigin, OpInfo(transitionData), child, getButterflyIndex);
- reallocateStorage.ref(); // Once for the use.
- reallocateStorage.ref(); // Twice because it's must-generate.
- propertyStorageIndex = m_graph.size();
- m_graph.append(reallocateStorage);
- m_insertionSet.append(indexInBlock, propertyStorageIndex);
+ propertyStorage = Edge(m_insertionSet.insertNode(
+ indexInBlock, SpecNone, ReallocatePropertyStorage, codeOrigin,
+ OpInfo(transitionData), childEdge,
+ Edge(m_insertionSet.insertNode(
+ indexInBlock, SpecNone, GetButterfly, codeOrigin, childEdge))));
}
if (status.isSimpleTransition()) {
- m_graph[child].ref();
- Node putStructure(PutStructure, codeOrigin, OpInfo(transitionData), child);
- putStructure.ref();
- NodeIndex putStructureIndex = m_graph.size();
- m_graph.append(putStructure);
- m_insertionSet.append(indexInBlock, putStructureIndex);
+ m_insertionSet.insertNode(
+ indexInBlock, SpecNone, PutStructure, codeOrigin,
+ OpInfo(transitionData), childEdge);
}
- m_graph[nodeIndex].convertToPutByOffset(m_graph.m_storageAccessData.size(), propertyStorageIndex);
+ node->convertToPutByOffset(m_graph.m_storageAccessData.size(), propertyStorage);
StorageAccessData storageAccessData;
storageAccessData.offset = indexRelativeToBase(status.offset());
@@ -338,108 +322,91 @@ private:
}
m_state.execute(indexInBlock);
- if (!node.shouldGenerate() || m_state.didClobber() || node.hasConstant())
+ if (!node->shouldGenerate() || m_state.didClobber() || node->hasConstant())
continue;
- JSValue value = m_state.forNode(nodeIndex).value();
+ JSValue value = m_state.forNode(node).value();
if (!value)
continue;
- Node phantom(Phantom, node.codeOrigin);
-
- if (node.op() == GetLocal) {
- NodeIndex previousLocalAccess = NoNode;
- if (block->variablesAtHead.operand(node.local()) == nodeIndex
- && m_graph[node.child1()].op() == Phi) {
- // We expect this to be the common case.
- ASSERT(block->isInPhis(node.child1().index()));
- previousLocalAccess = node.child1().index();
- block->variablesAtHead.operand(node.local()) = previousLocalAccess;
- } else {
- ASSERT(indexInBlock > 0);
- // Must search for the previous access to this local.
- for (BlockIndex subIndexInBlock = indexInBlock; subIndexInBlock--;) {
- NodeIndex subNodeIndex = block->at(subIndexInBlock);
- Node& subNode = m_graph[subNodeIndex];
- if (!subNode.shouldGenerate())
- continue;
- if (!subNode.hasVariableAccessData())
- continue;
- if (subNode.local() != node.local())
- continue;
- // The two must have been unified.
- ASSERT(subNode.variableAccessData() == node.variableAccessData());
- previousLocalAccess = subNodeIndex;
- break;
- }
- if (previousLocalAccess == NoNode) {
- // The previous access must have been a Phi.
- for (BlockIndex phiIndexInBlock = block->phis.size(); phiIndexInBlock--;) {
- NodeIndex phiNodeIndex = block->phis[phiIndexInBlock];
- Node& phiNode = m_graph[phiNodeIndex];
- if (!phiNode.shouldGenerate())
- continue;
- if (phiNode.local() != node.local())
- continue;
- // The two must have been unified.
- ASSERT(phiNode.variableAccessData() == node.variableAccessData());
- previousLocalAccess = phiNodeIndex;
- break;
- }
- ASSERT(previousLocalAccess != NoNode);
+ CodeOrigin codeOrigin = node->codeOrigin;
+ AdjacencyList children = node->children;
+
+ if (node->op() == GetLocal) {
+ // GetLocals without a Phi child are guaranteed dead. We don't have to
+ // do anything about them.
+ if (!node->child1())
+ continue;
+
+ if (m_graph.m_form != LoadStore) {
+ VariableAccessData* variable = node->variableAccessData();
+ Node* phi = node->child1().node();
+ if (phi->op() == Phi
+ && block->variablesAtHead.operand(variable->local()) == phi
+ && block->variablesAtTail.operand(variable->local()) == node) {
+
+ // Keep the graph threaded for easy cases. This is improves compile
+ // times. It would be correct to just dethread here.
+
+ m_graph.convertToConstant(node, value);
+ Node* phantom = m_insertionSet.insertNode(
+ indexInBlock, SpecNone, PhantomLocal, codeOrigin,
+ OpInfo(variable), Edge(phi));
+ block->variablesAtHead.operand(variable->local()) = phantom;
+ block->variablesAtTail.operand(variable->local()) = phantom;
+
+ changed = true;
+
+ continue;
}
- }
- ASSERT(previousLocalAccess != NoNode);
-
- NodeIndex tailNodeIndex = block->variablesAtTail.operand(node.local());
- if (tailNodeIndex == nodeIndex)
- block->variablesAtTail.operand(node.local()) = previousLocalAccess;
- else {
- ASSERT(m_graph[tailNodeIndex].op() == Flush
- || m_graph[tailNodeIndex].op() == SetLocal
- || node.variableAccessData()->isCaptured());
+ m_graph.dethread();
}
- }
-
- phantom.children = node.children;
- phantom.ref();
+ } else
+ ASSERT(!node->hasVariableAccessData());
+
+ m_graph.convertToConstant(node, value);
+ m_insertionSet.insertNode(
+ indexInBlock, SpecNone, Phantom, codeOrigin, children);
- m_graph.convertToConstant(nodeIndex, value);
- NodeIndex phantomNodeIndex = m_graph.size();
- m_graph.append(phantom);
- m_insertionSet.append(indexInBlock, phantomNodeIndex);
-
changed = true;
}
m_state.reset();
- m_insertionSet.execute(*block);
+ m_insertionSet.execute(block);
return changed;
}
+#if !ASSERT_DISABLED
+ bool isCapturedAtOrAfter(BasicBlock* block, unsigned indexInBlock, int operand)
+ {
+ for (; indexInBlock < block->size(); ++indexInBlock) {
+ Node* node = block->at(indexInBlock);
+ if (!node->hasLocal())
+ continue;
+ if (node->local() != operand)
+ continue;
+ if (node->variableAccessData()->isCaptured())
+ return true;
+ }
+ return false;
+ }
+#endif // !ASSERT_DISABLED
+
void addStructureTransitionCheck(CodeOrigin codeOrigin, unsigned indexInBlock, JSCell* cell)
{
- Node weakConstant(WeakJSConstant, codeOrigin, OpInfo(cell));
- weakConstant.ref();
- weakConstant.predict(speculationFromValue(cell));
- NodeIndex weakConstantIndex = m_graph.size();
- m_graph.append(weakConstant);
- m_insertionSet.append(indexInBlock, weakConstantIndex);
+ Node* weakConstant = m_insertionSet.insertNode(
+ indexInBlock, speculationFromValue(cell), WeakJSConstant, codeOrigin, OpInfo(cell));
if (cell->structure()->transitionWatchpointSetIsStillValid()) {
- Node watchpoint(StructureTransitionWatchpoint, codeOrigin, OpInfo(cell->structure()), weakConstantIndex);
- watchpoint.ref();
- NodeIndex watchpointIndex = m_graph.size();
- m_graph.append(watchpoint);
- m_insertionSet.append(indexInBlock, watchpointIndex);
+ m_insertionSet.insertNode(
+ indexInBlock, SpecNone, StructureTransitionWatchpoint, codeOrigin,
+ OpInfo(cell->structure()), Edge(weakConstant, CellUse));
return;
}
-
- Node check(CheckStructure, codeOrigin, OpInfo(m_graph.addStructureSet(cell->structure())), weakConstantIndex);
- check.ref();
- NodeIndex checkIndex = m_graph.size();
- m_graph.append(check);
- m_insertionSet.append(indexInBlock, checkIndex);
+
+ m_insertionSet.insertNode(
+ indexInBlock, SpecNone, CheckStructure, codeOrigin,
+ OpInfo(m_graph.addStructureSet(cell->structure())), Edge(weakConstant, CellUse));
}
// This is necessary because the CFA may reach conclusions about constants based on its
@@ -464,9 +431,8 @@ private:
if (m_state.isValid())
continue;
- NodeIndex nodeIndex = block->at(indexInBlock);
- Node& node = m_graph[nodeIndex];
- switch (node.op()) {
+ Node* node = block->at(indexInBlock);
+ switch (node->op()) {
case Return:
case Throw:
case ThrowReferenceError:
@@ -475,24 +441,21 @@ private:
break;
default:
- Node forceOSRExit(ForceOSRExit, node.codeOrigin);
- forceOSRExit.ref();
- NodeIndex forceOSRExitIndex = m_graph.size();
- m_graph.append(forceOSRExit);
- m_insertionSet.append(indexInBlock, forceOSRExitIndex);
+ m_insertionSet.insertNode(
+ indexInBlock, SpecNone, ForceOSRExit, node->codeOrigin);
changed = true;
break;
}
break;
}
m_state.reset();
- m_insertionSet.execute(*block);
+ m_insertionSet.execute(block);
return changed;
}
AbstractState m_state;
- InsertionSet<NodeIndex> m_insertionSet;
+ InsertionSet m_insertionSet;
};
bool performConstantFolding(Graph& graph)