diff options
Diffstat (limited to 'Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp')
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp | 343 |
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) |