Commit 4ffd3956 authored by fpizlo@apple.com's avatar fpizlo@apple.com

DFG does not have flow-sensitive intraprocedural control flow analysis

https://bugs.webkit.org/show_bug.cgi?id=69690

Reviewed by Gavin Barraclough.

Implemented a control flow analysis (CFA). It currently propagates type
proofs only. For example, if all predecessors to a basic block have
checks that variable X is a JSFinalObject with structure 0xabcdef, then
this basic block will now know this fact and will know that it does not
have to emit either JSFinalObject checks or any structure checks since
the structure is precisely known. The CFA takes heap side-effects into
account (though somewhat conservatively), so that if the object pointed
to by variable X could have possibly undergone a structure transition
then this is reflected: the analysis may simply say that X's structure
is unknown.
        
This also propagates a wealth of other type information which is
currently not being used. For example, we now know when a variable can
only hold doubles. Even if a variable may hold other types at different
points in its live range, we can still prove exactly when it will only
be double.
        
There's a bunch of stuff that the CFA could do that it still does not
do, like precise handling of PutStructure (i.e. structure transitions),
precise handling of CheckFunction and CheckMethod, etc. So this is
very much intended to be a starting point rather than an end unto
itself.
        
This is a 1% win on V8 (mostly due to a 3% win on richards and deltablue)
and a 1% win on Kraken (mostly due to a 6% win on imaging-desaturate).
Neutral on SunSpider.

* GNUmakefile.list.am:
* JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
* JavaScriptCore.xcodeproj/project.pbxproj:
* bytecode/ActionablePrediction.h: Removed.
* bytecode/PredictedType.cpp:
(JSC::predictionToString):
* bytecode/PredictedType.h:
* dfg/DFGAbstractState.cpp: Added.
(JSC::DFG::AbstractState::AbstractState):
(JSC::DFG::AbstractState::~AbstractState):
(JSC::DFG::AbstractState::beginBasicBlock):
(JSC::DFG::AbstractState::initialize):
(JSC::DFG::AbstractState::endBasicBlock):
(JSC::DFG::AbstractState::reset):
(JSC::DFG::AbstractState::execute):
(JSC::DFG::AbstractState::clobberStructures):
(JSC::DFG::AbstractState::mergeStateAtTail):
(JSC::DFG::AbstractState::merge):
(JSC::DFG::AbstractState::mergeToSuccessors):
(JSC::DFG::AbstractState::mergeVariableBetweenBlocks):
(JSC::DFG::AbstractState::dump):
* dfg/DFGAbstractState.h: Added.
(JSC::DFG::AbstractState::forNode):
(JSC::DFG::AbstractState::isValid):
* dfg/DFGAbstractValue.h: Added.
(JSC::DFG::StructureAbstractValue::StructureAbstractValue):
(JSC::DFG::StructureAbstractValue::clear):
(JSC::DFG::StructureAbstractValue::makeTop):
(JSC::DFG::StructureAbstractValue::top):
(JSC::DFG::StructureAbstractValue::add):
(JSC::DFG::StructureAbstractValue::addAll):
(JSC::DFG::StructureAbstractValue::contains):
(JSC::DFG::StructureAbstractValue::isSubsetOf):
(JSC::DFG::StructureAbstractValue::doesNotContainAnyOtherThan):
(JSC::DFG::StructureAbstractValue::isSupersetOf):
(JSC::DFG::StructureAbstractValue::filter):
(JSC::DFG::StructureAbstractValue::isClear):
(JSC::DFG::StructureAbstractValue::isTop):
(JSC::DFG::StructureAbstractValue::size):
(JSC::DFG::StructureAbstractValue::at):
(JSC::DFG::StructureAbstractValue::operator[]):
(JSC::DFG::StructureAbstractValue::last):
(JSC::DFG::StructureAbstractValue::predictionFromStructures):
(JSC::DFG::StructureAbstractValue::operator==):
(JSC::DFG::StructureAbstractValue::dump):
(JSC::DFG::AbstractValue::AbstractValue):
(JSC::DFG::AbstractValue::clear):
(JSC::DFG::AbstractValue::isClear):
(JSC::DFG::AbstractValue::makeTop):
(JSC::DFG::AbstractValue::clobberStructures):
(JSC::DFG::AbstractValue::isTop):
(JSC::DFG::AbstractValue::top):
(JSC::DFG::AbstractValue::set):
(JSC::DFG::AbstractValue::operator==):
(JSC::DFG::AbstractValue::merge):
(JSC::DFG::AbstractValue::filter):
(JSC::DFG::AbstractValue::validate):
(JSC::DFG::AbstractValue::dump):
* dfg/DFGBasicBlock.h: Added.
(JSC::DFG::BasicBlock::BasicBlock):
(JSC::DFG::BasicBlock::getBytecodeBegin):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::getLocal):
(JSC::DFG::ByteCodeParser::setLocal):
(JSC::DFG::ByteCodeParser::getArgument):
(JSC::DFG::ByteCodeParser::setArgument):
(JSC::DFG::ByteCodeParser::parseBlock):
(JSC::DFG::ByteCodeParser::processPhiStack):
(JSC::DFG::ByteCodeParser::setupPredecessors):
* dfg/DFGGraph.cpp:
(JSC::DFG::Graph::dump):
* dfg/DFGGraph.h:
* dfg/DFGJITCodeGenerator.h:
(JSC::DFG::block):
* dfg/DFGJITCodeGenerator32_64.cpp:
(JSC::DFG::JITCodeGenerator::nonSpeculativePeepholeBranchNull):
(JSC::DFG::JITCodeGenerator::nonSpeculativePeepholeBranch):
(JSC::DFG::JITCodeGenerator::nonSpeculativePeepholeStrictEq):
* dfg/DFGJITCodeGenerator64.cpp:
(JSC::DFG::JITCodeGenerator::nonSpeculativePeepholeBranchNull):
(JSC::DFG::JITCodeGenerator::nonSpeculativePeepholeBranch):
(JSC::DFG::JITCodeGenerator::nonSpeculativePeepholeStrictEq):
* dfg/DFGJITCompiler.h:
(JSC::DFG::JITCompiler::noticeOSREntry):
* dfg/DFGNode.h:
(JSC::DFG::NodeIndexTraits::defaultValue):
(JSC::DFG::Node::variableAccessData):
(JSC::DFG::Node::takenBytecodeOffsetDuringParsing):
(JSC::DFG::Node::notTakenBytecodeOffsetDuringParsing):
(JSC::DFG::Node::setTakenBlockIndex):
(JSC::DFG::Node::setNotTakenBlockIndex):
(JSC::DFG::Node::takenBlockIndex):
(JSC::DFG::Node::notTakenBlockIndex):
* dfg/DFGOSREntry.cpp:
(JSC::DFG::prepareOSREntry):
* dfg/DFGOSREntry.h:
* dfg/DFGOperands.h: Added.
(JSC::DFG::operandIsArgument):
(JSC::DFG::OperandValueTraits::defaultValue):
(JSC::DFG::Operands::Operands):
(JSC::DFG::Operands::numberOfArguments):
(JSC::DFG::Operands::numberOfLocals):
(JSC::DFG::Operands::argument):
(JSC::DFG::Operands::local):
(JSC::DFG::Operands::setLocal):
(JSC::DFG::Operands::setArgumentFirstTime):
(JSC::DFG::Operands::setLocalFirstTime):
(JSC::DFG::Operands::operand):
(JSC::DFG::Operands::setOperand):
(JSC::DFG::Operands::clear):
(JSC::DFG::dumpOperands):
* dfg/DFGPropagator.cpp:
(JSC::DFG::Propagator::fixpoint):
(JSC::DFG::Propagator::propagateArithNodeFlags):
(JSC::DFG::Propagator::propagateNodePredictions):
(JSC::DFG::Propagator::propagatePredictions):
(JSC::DFG::Propagator::performBlockCFA):
(JSC::DFG::Propagator::performForwardCFA):
(JSC::DFG::Propagator::globalCFA):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compilePeepHoleDoubleBranch):
(JSC::DFG::SpeculativeJIT::compilePeepHoleObjectEquality):
(JSC::DFG::SpeculativeJIT::compilePeepHoleIntegerBranch):
(JSC::DFG::SpeculativeJIT::compilePeepHoleBranch):
(JSC::DFG::SpeculativeJIT::compile):
(JSC::DFG::SpeculativeJIT::compileGetCharCodeAt):
(JSC::DFG::SpeculativeJIT::compileGetByValOnString):
* dfg/DFGSpeculativeJIT.h:
(JSC::DFG::SpeculativeJIT::SpeculativeJIT):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compileObjectEquality):
(JSC::DFG::SpeculativeJIT::compare):
(JSC::DFG::SpeculativeJIT::compileObjectOrOtherLogicalNot):
(JSC::DFG::SpeculativeJIT::compileLogicalNot):
(JSC::DFG::SpeculativeJIT::emitObjectOrOtherBranch):
(JSC::DFG::SpeculativeJIT::emitBranch):
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compileObjectEquality):
(JSC::DFG::SpeculativeJIT::compare):
(JSC::DFG::SpeculativeJIT::compileObjectOrOtherLogicalNot):
(JSC::DFG::SpeculativeJIT::compileLogicalNot):
(JSC::DFG::SpeculativeJIT::emitObjectOrOtherBranch):
(JSC::DFG::SpeculativeJIT::emitBranch):
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGStructureSet.h:
(JSC::DFG::StructureSet::clear):
(JSC::DFG::StructureSet::predictionFromStructures):
(JSC::DFG::StructureSet::operator==):
(JSC::DFG::StructureSet::dump):
* dfg/DFGVariableAccessData.h: Added.



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@97218 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent d1c64692
2011-10-08 Filip Pizlo <fpizlo@apple.com>
DFG does not have flow-sensitive intraprocedural control flow analysis
https://bugs.webkit.org/show_bug.cgi?id=69690
Reviewed by Gavin Barraclough.
Implemented a control flow analysis (CFA). It currently propagates type
proofs only. For example, if all predecessors to a basic block have
checks that variable X is a JSFinalObject with structure 0xabcdef, then
this basic block will now know this fact and will know that it does not
have to emit either JSFinalObject checks or any structure checks since
the structure is precisely known. The CFA takes heap side-effects into
account (though somewhat conservatively), so that if the object pointed
to by variable X could have possibly undergone a structure transition
then this is reflected: the analysis may simply say that X's structure
is unknown.
This also propagates a wealth of other type information which is
currently not being used. For example, we now know when a variable can
only hold doubles. Even if a variable may hold other types at different
points in its live range, we can still prove exactly when it will only
be double.
There's a bunch of stuff that the CFA could do that it still does not
do, like precise handling of PutStructure (i.e. structure transitions),
precise handling of CheckFunction and CheckMethod, etc. So this is
very much intended to be a starting point rather than an end unto
itself.
This is a 1% win on V8 (mostly due to a 3% win on richards and deltablue)
and a 1% win on Kraken (mostly due to a 6% win on imaging-desaturate).
Neutral on SunSpider.
* GNUmakefile.list.am:
* JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
* JavaScriptCore.xcodeproj/project.pbxproj:
* bytecode/ActionablePrediction.h: Removed.
* bytecode/PredictedType.cpp:
(JSC::predictionToString):
* bytecode/PredictedType.h:
* dfg/DFGAbstractState.cpp: Added.
(JSC::DFG::AbstractState::AbstractState):
(JSC::DFG::AbstractState::~AbstractState):
(JSC::DFG::AbstractState::beginBasicBlock):
(JSC::DFG::AbstractState::initialize):
(JSC::DFG::AbstractState::endBasicBlock):
(JSC::DFG::AbstractState::reset):
(JSC::DFG::AbstractState::execute):
(JSC::DFG::AbstractState::clobberStructures):
(JSC::DFG::AbstractState::mergeStateAtTail):
(JSC::DFG::AbstractState::merge):
(JSC::DFG::AbstractState::mergeToSuccessors):
(JSC::DFG::AbstractState::mergeVariableBetweenBlocks):
(JSC::DFG::AbstractState::dump):
* dfg/DFGAbstractState.h: Added.
(JSC::DFG::AbstractState::forNode):
(JSC::DFG::AbstractState::isValid):
* dfg/DFGAbstractValue.h: Added.
(JSC::DFG::StructureAbstractValue::StructureAbstractValue):
(JSC::DFG::StructureAbstractValue::clear):
(JSC::DFG::StructureAbstractValue::makeTop):
(JSC::DFG::StructureAbstractValue::top):
(JSC::DFG::StructureAbstractValue::add):
(JSC::DFG::StructureAbstractValue::addAll):
(JSC::DFG::StructureAbstractValue::contains):
(JSC::DFG::StructureAbstractValue::isSubsetOf):
(JSC::DFG::StructureAbstractValue::doesNotContainAnyOtherThan):
(JSC::DFG::StructureAbstractValue::isSupersetOf):
(JSC::DFG::StructureAbstractValue::filter):
(JSC::DFG::StructureAbstractValue::isClear):
(JSC::DFG::StructureAbstractValue::isTop):
(JSC::DFG::StructureAbstractValue::size):
(JSC::DFG::StructureAbstractValue::at):
(JSC::DFG::StructureAbstractValue::operator[]):
(JSC::DFG::StructureAbstractValue::last):
(JSC::DFG::StructureAbstractValue::predictionFromStructures):
(JSC::DFG::StructureAbstractValue::operator==):
(JSC::DFG::StructureAbstractValue::dump):
(JSC::DFG::AbstractValue::AbstractValue):
(JSC::DFG::AbstractValue::clear):
(JSC::DFG::AbstractValue::isClear):
(JSC::DFG::AbstractValue::makeTop):
(JSC::DFG::AbstractValue::clobberStructures):
(JSC::DFG::AbstractValue::isTop):
(JSC::DFG::AbstractValue::top):
(JSC::DFG::AbstractValue::set):
(JSC::DFG::AbstractValue::operator==):
(JSC::DFG::AbstractValue::merge):
(JSC::DFG::AbstractValue::filter):
(JSC::DFG::AbstractValue::validate):
(JSC::DFG::AbstractValue::dump):
* dfg/DFGBasicBlock.h: Added.
(JSC::DFG::BasicBlock::BasicBlock):
(JSC::DFG::BasicBlock::getBytecodeBegin):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::getLocal):
(JSC::DFG::ByteCodeParser::setLocal):
(JSC::DFG::ByteCodeParser::getArgument):
(JSC::DFG::ByteCodeParser::setArgument):
(JSC::DFG::ByteCodeParser::parseBlock):
(JSC::DFG::ByteCodeParser::processPhiStack):
(JSC::DFG::ByteCodeParser::setupPredecessors):
* dfg/DFGGraph.cpp:
(JSC::DFG::Graph::dump):
* dfg/DFGGraph.h:
* dfg/DFGJITCodeGenerator.h:
(JSC::DFG::block):
* dfg/DFGJITCodeGenerator32_64.cpp:
(JSC::DFG::JITCodeGenerator::nonSpeculativePeepholeBranchNull):
(JSC::DFG::JITCodeGenerator::nonSpeculativePeepholeBranch):
(JSC::DFG::JITCodeGenerator::nonSpeculativePeepholeStrictEq):
* dfg/DFGJITCodeGenerator64.cpp:
(JSC::DFG::JITCodeGenerator::nonSpeculativePeepholeBranchNull):
(JSC::DFG::JITCodeGenerator::nonSpeculativePeepholeBranch):
(JSC::DFG::JITCodeGenerator::nonSpeculativePeepholeStrictEq):
* dfg/DFGJITCompiler.h:
(JSC::DFG::JITCompiler::noticeOSREntry):
* dfg/DFGNode.h:
(JSC::DFG::NodeIndexTraits::defaultValue):
(JSC::DFG::Node::variableAccessData):
(JSC::DFG::Node::takenBytecodeOffsetDuringParsing):
(JSC::DFG::Node::notTakenBytecodeOffsetDuringParsing):
(JSC::DFG::Node::setTakenBlockIndex):
(JSC::DFG::Node::setNotTakenBlockIndex):
(JSC::DFG::Node::takenBlockIndex):
(JSC::DFG::Node::notTakenBlockIndex):
* dfg/DFGOSREntry.cpp:
(JSC::DFG::prepareOSREntry):
* dfg/DFGOSREntry.h:
* dfg/DFGOperands.h: Added.
(JSC::DFG::operandIsArgument):
(JSC::DFG::OperandValueTraits::defaultValue):
(JSC::DFG::Operands::Operands):
(JSC::DFG::Operands::numberOfArguments):
(JSC::DFG::Operands::numberOfLocals):
(JSC::DFG::Operands::argument):
(JSC::DFG::Operands::local):
(JSC::DFG::Operands::setLocal):
(JSC::DFG::Operands::setArgumentFirstTime):
(JSC::DFG::Operands::setLocalFirstTime):
(JSC::DFG::Operands::operand):
(JSC::DFG::Operands::setOperand):
(JSC::DFG::Operands::clear):
(JSC::DFG::dumpOperands):
* dfg/DFGPropagator.cpp:
(JSC::DFG::Propagator::fixpoint):
(JSC::DFG::Propagator::propagateArithNodeFlags):
(JSC::DFG::Propagator::propagateNodePredictions):
(JSC::DFG::Propagator::propagatePredictions):
(JSC::DFG::Propagator::performBlockCFA):
(JSC::DFG::Propagator::performForwardCFA):
(JSC::DFG::Propagator::globalCFA):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compilePeepHoleDoubleBranch):
(JSC::DFG::SpeculativeJIT::compilePeepHoleObjectEquality):
(JSC::DFG::SpeculativeJIT::compilePeepHoleIntegerBranch):
(JSC::DFG::SpeculativeJIT::compilePeepHoleBranch):
(JSC::DFG::SpeculativeJIT::compile):
(JSC::DFG::SpeculativeJIT::compileGetCharCodeAt):
(JSC::DFG::SpeculativeJIT::compileGetByValOnString):
* dfg/DFGSpeculativeJIT.h:
(JSC::DFG::SpeculativeJIT::SpeculativeJIT):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compileObjectEquality):
(JSC::DFG::SpeculativeJIT::compare):
(JSC::DFG::SpeculativeJIT::compileObjectOrOtherLogicalNot):
(JSC::DFG::SpeculativeJIT::compileLogicalNot):
(JSC::DFG::SpeculativeJIT::emitObjectOrOtherBranch):
(JSC::DFG::SpeculativeJIT::emitBranch):
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compileObjectEquality):
(JSC::DFG::SpeculativeJIT::compare):
(JSC::DFG::SpeculativeJIT::compileObjectOrOtherLogicalNot):
(JSC::DFG::SpeculativeJIT::compileLogicalNot):
(JSC::DFG::SpeculativeJIT::emitObjectOrOtherBranch):
(JSC::DFG::SpeculativeJIT::emitBranch):
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGStructureSet.h:
(JSC::DFG::StructureSet::clear):
(JSC::DFG::StructureSet::predictionFromStructures):
(JSC::DFG::StructureSet::operator==):
(JSC::DFG::StructureSet::dump):
* dfg/DFGVariableAccessData.h: Added.
2011-10-11 Gavin Barraclough <baraclough@apple.com>
DFG JIT 32_64 - Fix silentFillGPR for non-integer constants.
......@@ -81,7 +81,6 @@ javascriptcore_sources += \
Source/JavaScriptCore/assembler/RepatchBuffer.h \
Source/JavaScriptCore/assembler/SH4Assembler.h \
Source/JavaScriptCore/assembler/X86Assembler.h \
Source/JavaScriptCore/bytecode/ActionablePrediction.h \
Source/JavaScriptCore/bytecode/CodeBlock.cpp \
Source/JavaScriptCore/bytecode/CodeBlock.h \
Source/JavaScriptCore/bytecode/EvalCodeCache.h \
......@@ -105,6 +104,10 @@ javascriptcore_sources += \
Source/JavaScriptCore/bytecompiler/LabelScope.h \
Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp \
Source/JavaScriptCore/bytecompiler/RegisterID.h \
Source/JavaScriptCore/dfg/DFGAbstractState.cpp \
Source/JavaScriptCore/dfg/DFGAbstractState.h \
Source/JavaScriptCore/dfg/DFGAbstractValue.h \
Source/JavaScriptCoer/dfg/DFGBasicBlock.h \
Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp \
Source/JavaScriptCore/dfg/DFGByteCodeParser.h \
Source/JavaScriptCore/dfg/DFGCapabilities.cpp \
......@@ -122,6 +125,7 @@ javascriptcore_sources += \
Source/JavaScriptCore/dfg/DFGJITCompiler.cpp \
Source/JavaScriptCore/dfg/DFGJITCompiler.h \
Source/JavaScriptCore/dfg/DFGNode.h \
Source/JavaScriptCore/dfg/DFGOperands.h \
Source/JavaScriptCore/dfg/DFGOperations.cpp \
Source/JavaScriptCore/dfg/DFGOperations.h \
Source/JavaScriptCore/dfg/DFGOSREntry.cpp \
......@@ -135,6 +139,7 @@ javascriptcore_sources += \
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp \
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h \
Source/JavaScriptCore/dfg/DFGStructureSet.h \
Source/JavaScriptCore/dfg/DFGVariableAccessData.h \
Source/JavaScriptCore/heap/AllocationSpace.cpp \
Source/JavaScriptCore/heap/AllocationSpace.h \
Source/JavaScriptCore/heap/CardSet.h \
......
......@@ -1437,10 +1437,6 @@
<Filter
Name="bytecode"
>
<File
RelativePath="..\..\bytecode\ActionablePrediction.h"
>
</File>
<File
RelativePath="..\..\bytecode\CodeBlock.cpp"
>
......@@ -1585,6 +1581,10 @@
RelativePath="..\..\dfg\DFGIntrinsic.h"
>
</File>
<File
RelativePath="..\..\dfg\DFGOSREntry.h"
>
</File>
</Filter>
<Filter
Name="yarr"
......
......@@ -51,8 +51,13 @@
0BF28A2911A33DC300638F84 /* SizeLimits.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0BF28A2811A33DC300638F84 /* SizeLimits.cpp */; };
0F16D726142C39C000CF784A /* BitVector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F16D724142C39A200CF784A /* BitVector.cpp */; };
0F242DA713F3B1E8007ADD4C /* WeakReferenceHarvester.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F242DA513F3B1BB007ADD4C /* WeakReferenceHarvester.h */; settings = {ATTRIBUTES = (Private, ); }; };
0F620174143FCD330068B77C /* DFGVariableAccessData.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F620172143FCD2F0068B77C /* DFGVariableAccessData.h */; settings = {ATTRIBUTES = (Private, ); }; };
0F620175143FCD370068B77C /* DFGOperands.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F620171143FCD2F0068B77C /* DFGOperands.h */; settings = {ATTRIBUTES = (Private, ); }; };
0F620176143FCD3B0068B77C /* DFGBasicBlock.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F620170143FCD2F0068B77C /* DFGBasicBlock.h */; settings = {ATTRIBUTES = (Private, ); }; };
0F620177143FCD3F0068B77C /* DFGAbstractValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F62016F143FCD2F0068B77C /* DFGAbstractValue.h */; settings = {ATTRIBUTES = (Private, ); }; };
0F620178143FCD440068B77C /* DFGAbstractState.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F62016E143FCD2F0068B77C /* DFGAbstractState.h */; settings = {ATTRIBUTES = (Private, ); }; };
0F620179143FCD480068B77C /* DFGAbstractState.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F62016D143FCD2F0068B77C /* DFGAbstractState.cpp */; };
0F636DA0142D27D700B2E66A /* PackedIntVector.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F636D9F142D27D200B2E66A /* PackedIntVector.h */; };
0F636DA2142D27F000B2E66A /* ActionablePrediction.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F636DA1142D27ED00B2E66A /* ActionablePrediction.h */; };
0F7700921402FF3C0078EB39 /* SamplingCounter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F7700911402FF280078EB39 /* SamplingCounter.cpp */; };
0F963B2713F753BB0002D9B2 /* RedBlackTree.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F963B2613F753990002D9B2 /* RedBlackTree.h */; settings = {ATTRIBUTES = (Private, ); }; };
0F963B2C13F853EC0002D9B2 /* MetaAllocator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F963B2B13F853C70002D9B2 /* MetaAllocator.cpp */; settings = {COMPILER_FLAGS = "-fno-strict-aliasing"; }; };
......@@ -809,8 +814,13 @@
0BF28A2811A33DC300638F84 /* SizeLimits.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SizeLimits.cpp; sourceTree = "<group>"; };
0F16D724142C39A200CF784A /* BitVector.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BitVector.cpp; sourceTree = "<group>"; };
0F242DA513F3B1BB007ADD4C /* WeakReferenceHarvester.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WeakReferenceHarvester.h; sourceTree = "<group>"; };
0F62016D143FCD2F0068B77C /* DFGAbstractState.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGAbstractState.cpp; path = dfg/DFGAbstractState.cpp; sourceTree = "<group>"; };
0F62016E143FCD2F0068B77C /* DFGAbstractState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGAbstractState.h; path = dfg/DFGAbstractState.h; sourceTree = "<group>"; };
0F62016F143FCD2F0068B77C /* DFGAbstractValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGAbstractValue.h; path = dfg/DFGAbstractValue.h; sourceTree = "<group>"; };
0F620170143FCD2F0068B77C /* DFGBasicBlock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGBasicBlock.h; path = dfg/DFGBasicBlock.h; sourceTree = "<group>"; };
0F620171143FCD2F0068B77C /* DFGOperands.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGOperands.h; path = dfg/DFGOperands.h; sourceTree = "<group>"; };
0F620172143FCD2F0068B77C /* DFGVariableAccessData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGVariableAccessData.h; path = dfg/DFGVariableAccessData.h; sourceTree = "<group>"; };
0F636D9F142D27D200B2E66A /* PackedIntVector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PackedIntVector.h; sourceTree = "<group>"; };
0F636DA1142D27ED00B2E66A /* ActionablePrediction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ActionablePrediction.h; sourceTree = "<group>"; };
0F77008E1402FDD60078EB39 /* SamplingCounter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SamplingCounter.h; sourceTree = "<group>"; };
0F7700911402FF280078EB39 /* SamplingCounter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SamplingCounter.cpp; sourceTree = "<group>"; };
0F963B2613F753990002D9B2 /* RedBlackTree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RedBlackTree.h; sourceTree = "<group>"; };
......@@ -2283,6 +2293,12 @@
86EC9DB31328DF44002B2AD7 /* dfg */ = {
isa = PBXGroup;
children = (
0F62016D143FCD2F0068B77C /* DFGAbstractState.cpp */,
0F62016E143FCD2F0068B77C /* DFGAbstractState.h */,
0F62016F143FCD2F0068B77C /* DFGAbstractValue.h */,
0F620170143FCD2F0068B77C /* DFGBasicBlock.h */,
0F620171143FCD2F0068B77C /* DFGOperands.h */,
0F620172143FCD2F0068B77C /* DFGVariableAccessData.h */,
0FFF4BB2143955E600655BC0 /* DFGStructureSet.h */,
86EC9DB41328DF82002B2AD7 /* DFGByteCodeParser.cpp */,
86EC9DB51328DF82002B2AD7 /* DFGByteCodeParser.h */,
......@@ -2384,7 +2400,6 @@
969A078F0ED1D3AE00F1F681 /* bytecode */ = {
isa = PBXGroup;
children = (
0F636DA1142D27ED00B2E66A /* ActionablePrediction.h */,
0FD82E8E14207A5100179C94 /* ValueProfile.cpp */,
0FD82E84141F3FDA00179C94 /* PredictedType.cpp */,
0FD82E4F141DAEA100179C94 /* PredictedType.h */,
......@@ -2870,13 +2885,17 @@
A70456B01427FB910037DA68 /* AllocationSpace.h in Headers */,
86FA9E92142BBB2E001773B7 /* JSBoundFunction.h in Headers */,
0F636DA0142D27D700B2E66A /* PackedIntVector.h in Headers */,
0F636DA2142D27F000B2E66A /* ActionablePrediction.h in Headers */,
A7521E131429169A003C8D0C /* CardSet.h in Headers */,
0FD52AAE143035A00026DC9F /* UnionFind.h in Headers */,
86880F1E14328BB900B08D42 /* DFGJITCompilerInlineMethods.h in Headers */,
0FE228ED1436AB2700196C48 /* Heuristics.h in Headers */,
0FFF4BB4143955E900655BC0 /* DFGStructureSet.h in Headers */,
8604F505143CE1C200B295F5 /* JSGlobalThis.h in Headers */,
0F620174143FCD330068B77C /* DFGVariableAccessData.h in Headers */,
0F620175143FCD370068B77C /* DFGOperands.h in Headers */,
0F620176143FCD3B0068B77C /* DFGBasicBlock.h in Headers */,
0F620177143FCD3F0068B77C /* DFGAbstractValue.h in Headers */,
0F620178143FCD440068B77C /* DFGAbstractState.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
......@@ -3408,6 +3427,7 @@
86880F44143531A800B08D42 /* DFGJITCodeGenerator64.cpp in Sources */,
86880F4D14353B2100B08D42 /* DFGSpeculativeJIT64.cpp in Sources */,
0FE228EE1436AB2C00196C48 /* Heuristics.cpp in Sources */,
0F620179143FCD480068B77C /* DFGAbstractState.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
......
......@@ -44,32 +44,55 @@ const char* predictionToString(PredictedType value)
static char description[size];
BoundsCheckedPointer<char> ptr(description, size);
bool isTop = true;
if (value & PredictCellOther)
ptr.strcat("Othercell");
else
isTop = false;
if (value & PredictObjectOther)
ptr.strcat("Otherobj");
else
isTop = false;
if (value & PredictFinalObject)
ptr.strcat("Final");
else
isTop = false;
if (value & PredictArray)
ptr.strcat("Array");
else
isTop = false;
if (value & PredictString)
ptr.strcat("String");
else
isTop = false;
if (value & PredictInt32)
ptr.strcat("Int");
else
isTop = false;
if (value & PredictDouble)
ptr.strcat("Double");
else
isTop = false;
if (value & PredictBoolean)
ptr.strcat("Bool");
else
isTop = false;
if (value & PredictOther)
ptr.strcat("Other");
else
isTop = false;
if (isTop)
return "Top";
*ptr++ = 0;
......
......@@ -51,6 +51,8 @@ static const PredictedType PredictBoolean = 0x0400; // It's definitely a B
static const PredictedType PredictOther = 0x4000; // It's definitely none of the above.
static const PredictedType PredictTop = 0x7fff; // It can be any of the above.
typedef bool (*PredictionChecker)(PredictedType);
inline bool isCellPrediction(PredictedType value)
{
return !!(value & PredictCell) && !(value & ~PredictCell);
......@@ -115,6 +117,10 @@ inline bool isOtherPrediction(PredictedType value)
const char* predictionToString(PredictedType value);
#endif
// Merge two predictions. Note that currently this just does left | right. It may
// seem tempting to do so directly, but you would be doing so at your own peril,
// since the merging protocol PredictedType may change at any time (and has already
// changed several times in its history).
inline PredictedType mergePredictions(PredictedType left, PredictedType right)
{
return left | right;
......
This diff is collapsed.
/*
* Copyright (C) 2011 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef DFGAbstractState_h
#define DFGAbstractState_h
#include <wtf/Platform.h>
#if ENABLE(DFG_JIT)
#include "DFGAbstractValue.h"
#include "DFGGraph.h"
#include "DFGNode.h"
#include <wtf/Vector.h>
namespace JSC {
class CodeBlock;
namespace DFG {
struct BasicBlock;
// This implements the notion of an abstract state for flow-sensitive intraprocedural
// control flow analysis (CFA), with a focus on the elimination of redundant type checks.
// It also implements most of the mechanisms of abstract interpretation that such an
// analysis would use. This class should be used in two idioms:
//
// 1) Performing the CFA. In this case, AbstractState should be run over all basic
// blocks repeatedly until convergence is reached. Convergence is defined by
// endBasicBlock(AbstractState::MergeToSuccessors) returning false for all blocks.
//
// 2) Rematerializing the results of a previously executed CFA. In this case,
// AbstractState should be run over whatever basic block you're interested in up
// to the point of the node at which you'd like to interrogate the known type
// of all other nodes. At this point it's safe to discard the AbstractState entirely,
// call reset(), or to run it to the end of the basic block and call
// endBasicBlock(AbstractState::DontMerge). The latter option is safest because
// it performs some useful integrity checks.
//
// After the CFA is run, the inter-block state is saved at the heads and tails of all
// basic blocks. This allows the intra-block state to be rematerialized by just
// executing the CFA for that block. If you need to know inter-block state only, then
// you only need to examine the BasicBlock::m_valuesAtHead or m_valuesAtTail fields.
//
// Running this analysis involves the following, modulo the inter-block state
// merging and convergence fixpoint:
//
// AbstractState state(codeBlock, graph);
// state.beginBasicBlock(basicBlock);
// bool endReached = true;
// for (NodeIndex idx = basicBlock.begin; idx < basicBlock.end; ++idx) {
// if (!state.execute(idx))
// break;
// }
// bool result = state.endBasicBlock(<either Merge or DontMerge>);
class AbstractState {
public:
enum MergeMode {
// Don't merge the state in AbstractState with basic blocks.
DontMerge,
// Merge the state in AbstractState with the tail of the basic
// block being analyzed.
MergeToTail,
// Merge the state in AbstractState with the tail of the basic
// block, and with the heads of successor blocks.
MergeToSuccessors
};
AbstractState(CodeBlock*, Graph&);
~AbstractState();
AbstractValue& forNode(NodeIndex nodeIndex)
{
return m_nodes[nodeIndex - m_block->begin];
}
// Call this before beginning CFA to initialize the abstract values of
// arguments, and to indicate which blocks should be listed for CFA
// execution.
static void initialize(Graph&);
// Start abstractly executing the given basic block. Initializes the
// notion of abstract state to what we believe it to be at the head
// of the basic block, according to the basic block's data structures.
// This method also sets cfaShouldRevisit to false.
void beginBasicBlock(BasicBlock*);
// Finish abstractly executing a basic block. If MergeToTail or
// MergeToSuccessors is passed, then this merges everything we have
// learned about how the state changes during this block's execution into
// the block's data structures. There are three return modes, depending
// on the value of mergeMode:
//
// DontMerge:
// Always returns false.
//
// MergeToTail:
// Returns true if the state of the block at the tail was changed.
// This means that you must call mergeToSuccessors(), and if that
// returns true, then you must revisit (at least) the successor
// blocks. False will always be returned if the block is terminal
// (i.e. ends in Throw or Return, or has a ForceOSRExit inside it).
//
// MergeToSuccessors:
// Returns true if the state of the block at the tail was changed,
// and, if the state at the heads of successors was changed.
// A true return means that you must revisit (at least) the successor
// blocks. This also sets cfaShouldRevisit to true for basic blocks
// that must be visited next.
bool endBasicBlock(MergeMode);
// Reset the AbstractState. This throws away any results, and at this point
// you can safely call beginBasicBlock() on any basic block.
void reset();
// Abstractly executes the given node. The new abstract state is stored into an
// abstract register file stored in *this. Loads of local variables (that span
// basic blocks) interrogate the basic block's notion of the state at the head.
// Stores to local variables are handled in endBasicBlock(). This returns true
// if execution should continue past this node. Notably, it will return true
// for block terminals, so long as those terminals are not Return or variants
// of Throw.
bool execute(NodeIndex);
// Is the execution state still valid? This will be false if execute() has
// returned false previously.
bool isValid() const { return m_isValid; }
// Merge the abstract state stored at the first block's tail into the second
// block's head. Returns true if the second block's state changed. If so,
// that block must be abstractly interpreted again. This also sets
// to->cfaShouldRevisit to true, if it returns true, or if to has not been
// visited yet.
static bool merge(BasicBlock* from, BasicBlock* to);
// Merge the abstract state stored at the block's tail into all of its
// successors. Returns true if any of the successors' states changed. Note
// that this is automatically called in endBasicBlock() if MergeMode is
// MergeToSuccessors.
static bool mergeToSuccessors(Graph&, BasicBlock*);
#ifndef NDEBUG
void dump(FILE* out);
#endif
private:
void clobberStructures(NodeIndex);
bool mergeStateAtTail(AbstractValue& destination, AbstractValue& inVariable, NodeIndex);
static bool mergeVariableBetweenBlocks(AbstractValue& destination, AbstractValue& source, NodeIndex destinationNodeIndex, NodeIndex sourceNodeIndex);
CodeBlock* m_codeBlock;
Graph& m_graph;
Vector<AbstractValue, 32> m_nodes;
Operands<AbstractValue> m_variables;
BasicBlock* m_block;
bool m_haveStructures;
bool m_isValid;
};
} } // namespace JSC::DFG
#endif // ENABLE(DFG_JIT)
#endif // DFGAbstractState_h
This diff is collapsed.
/*
* Copyright (C) 2011 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef DFGBasicBlock_h
#define DFGBasicBlock_h
#if ENABLE(DFG_JIT)
#include "DFGAbstractValue.h"
#include "DFGNode.h"
#include "DFGOperands.h"
#include <wtf/OwnPtr.h>
#include <wtf/Vector.h>
namespace JSC { namespace DFG {
typedef Vector <BlockIndex, 2> PredecessorList;
struct BasicBlock {
BasicBlock(unsigned bytecodeBegin, NodeIndex begin, unsigned numArguments, unsigned numLocals)
: bytecodeBegin(bytecodeBegin)
, begin(begin)
, end(NoNode)
, isOSRTarget(false)
, cfaHasVisited(false)
, cfaShouldRevisit(false)
, variablesAtHead(numArguments, numLocals)
, variablesAtTail(numArguments, numLocals)
, valuesAtHead(numArguments, numLocals)
, valuesAtTail(numArguments, numLocals)
{
}
static inline BlockIndex getBytecodeBegin(OwnPtr<BasicBlock>* block)