diff options
Diffstat (limited to 'Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp')
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp | 237 |
1 files changed, 233 insertions, 4 deletions
diff --git a/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp b/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp index 43aa2c007..2221954b5 100644 --- a/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp @@ -33,6 +33,8 @@ #include "DFGGraph.h" #include "DFGInsertionSet.h" #include "DFGPhase.h" +#include "GetByIdStatus.h" +#include "PutByIdStatus.h" namespace JSC { namespace DFG { @@ -65,7 +67,7 @@ private: bool foldConstants(BlockIndex blockIndex) { #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) - dataLog("Constant folding considering Block #%u.\n", blockIndex); + dataLogF("Constant folding considering Block #%u.\n", blockIndex); #endif BasicBlock* block = m_graph.m_blocks[blockIndex].get(); bool changed = false; @@ -109,14 +111,16 @@ private: StructureAbstractValue& structureValue = value.m_futurePossibleStructure; if (structureValue.isSubsetOf(set) && structureValue.hasSingleton() - && isCellSpeculation(value.m_type)) + && isCellSpeculation(value.m_type)) { node.convertToStructureTransitionWatchpoint(structureValue.singleton()); + changed = true; + } break; } case CheckArray: case Arrayify: { - if (!node.arrayMode().alreadyChecked(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); @@ -124,6 +128,206 @@ private: break; } + case CheckFunction: { + if (m_state.forNode(node.child1()).value() != node.function()) + break; + node.setOpAndDefaultFlags(Phantom); + 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(); + + if (!isCellSpeculation(m_graph[child].prediction())) + break; + + Structure* structure = m_state.forNode(child).bestProvenStructure(); + if (!structure) + break; + + bool needsWatchpoint = !m_state.forNode(child).m_currentKnownStructure.hasSingleton(); + + GetByIdStatus status = GetByIdStatus::computeFor( + globalData(), structure, codeBlock()->identifier(identifierNumber)); + + if (!status.isSimple()) + break; + + ASSERT(status.structureSet().size() == 1); + ASSERT(status.chain().isEmpty()); + ASSERT(status.structureSet().singletonStructure() == structure); + + // Now before we do anything else, push the CFA forward over the GetById + // and make sure we signal to the loop that it should continue and not + // do any eliminations. + m_state.execute(indexInBlock); + eliminated = true; + + 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); + } + + NodeIndex propertyStorageIndex; + + m_graph[child].ref(); + if (isInlineOffset(status.offset())) + propertyStorageIndex = child; + else { + Node getButterfly(GetButterfly, codeOrigin, child); + getButterfly.ref(); + propertyStorageIndex = m_graph.size(); + m_graph.append(getButterfly); + m_insertionSet.append(indexInBlock, propertyStorageIndex); + } + + m_graph[nodeIndex].convertToGetByOffset(m_graph.m_storageAccessData.size(), propertyStorageIndex); + + StorageAccessData storageAccessData; + storageAccessData.offset = indexRelativeToBase(status.offset()); + storageAccessData.identifierNumber = identifierNumber; + m_graph.m_storageAccessData.append(storageAccessData); + break; + } + + case PutById: + case PutByIdDirect: { + CodeOrigin codeOrigin = node.codeOrigin; + NodeIndex child = node.child1().index(); + unsigned identifierNumber = node.identifierNumber(); + + Structure* structure = m_state.forNode(child).bestProvenStructure(); + if (!structure) + break; + + bool needsWatchpoint = !m_state.forNode(child).m_currentKnownStructure.hasSingleton(); + + PutByIdStatus status = PutByIdStatus::computeFor( + globalData(), + m_graph.globalObjectFor(codeOrigin), + structure, + codeBlock()->identifier(identifierNumber), + node.op() == PutByIdDirect); + + if (!status.isSimpleReplace() && !status.isSimpleTransition()) + break; + + ASSERT(status.oldStructure() == structure); + + // Now before we do anything else, push the CFA forward over the PutById + // and make sure we signal to the loop that it should continue and not + // do any eliminations. + m_state.execute(indexInBlock); + eliminated = true; + + 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); + } + + StructureTransitionData* transitionData = 0; + if (status.isSimpleTransition()) { + transitionData = m_graph.addStructureTransitionData( + StructureTransitionData(structure, status.newStructure())); + + if (node.op() == PutById) { + if (!structure->storedPrototype().isNull()) { + addStructureTransitionCheck( + codeOrigin, indexInBlock, + structure->storedPrototype().asCell()); + } + + for (WriteBarrier<Structure>* it = status.structureChain()->head(); *it; ++it) { + JSValue prototype = (*it)->storedPrototype(); + if (prototype.isNull()) + continue; + ASSERT(prototype.isCell()); + addStructureTransitionCheck( + codeOrigin, indexInBlock, prototype.asCell()); + } + } + } + + NodeIndex propertyStorageIndex; + + m_graph[child].ref(); + if (isInlineOffset(status.offset())) + propertyStorageIndex = child; + 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); + } 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); + } 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); + } + + 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_graph[nodeIndex].convertToPutByOffset(m_graph.m_storageAccessData.size(), propertyStorageIndex); + + StorageAccessData storageAccessData; + storageAccessData.offset = indexRelativeToBase(status.offset()); + storageAccessData.identifierNumber = identifierNumber; + m_graph.m_storageAccessData.append(storageAccessData); + break; + } + default: break; } @@ -213,6 +417,31 @@ private: return changed; } + 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); + + 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); + 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); + } + // This is necessary because the CFA may reach conclusions about constants based on its // assumption that certain code must exit, but then those constants may lead future // reexecutions of the CFA to believe that the same code will now no longer exit. Thus @@ -225,7 +454,7 @@ private: bool changed = false; #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) - dataLog("Painting unreachable code in Block #%u.\n", blockIndex); + dataLogF("Painting unreachable code in Block #%u.\n", blockIndex); #endif BasicBlock* block = m_graph.m_blocks[blockIndex].get(); m_state.beginBasicBlock(block); |