Commit 827d2cf7 authored by oliver@apple.com's avatar oliver@apple.com

fourthTier: DFG should have an SSA form for use by FTL

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

Source/JavaScriptCore:

Reviewed by Mark Hahnenberg.

Adds an SSA form to the DFG. We can convert ThreadedCPS form into SSA form
after breaking critical edges. The conversion algorithm follows Aycock and
Horspool, and the SSA form itself follows something I've done before, where
instead of having Phi functions specify input nodes corresponding to block
predecessors, we instead have Upsilon functions in the predecessors that
specify which value in that block goes into which subsequent Phi. Upsilons
don't have to dominate Phis (usually they don't) and they correspond to a
non-SSA "mov" into the Phi's "variable". This gives all of the good
properties of SSA, while ensuring that a bunch of CFG transformations don't
have to be SSA-aware.

So far the only DFG phases that are SSA-aware are DCE and CFA. CFG
simplification is probably SSA-aware by default, though I haven't tried it.
Constant folding probably needs a few tweaks, but is likely ready. Ditto
for CSE, though it's not clear that we'd want to use block-local CSE when
we could be doing GVN.

Currently only the FTL can generate code from the SSA form, and there is no
way to convert from SSA to ThreadedCPS or LoadStore. There probably will
never be such a capability.

In order to handle OSR exit state in the SSA, we place MovHints at Phi
points. Other than that, you can reconstruct state-at-exit by forward
propagating MovHints. Note that MovHint is the new SetLocal in SSA.
SetLocal and GetLocal only survive into SSA if they are on captured
variables, or in the case of flushes. A "live SetLocal" will be
NodeMustGenerate and will always correspond to a flush. Computing the
state-at-exit requires running SSA liveness analysis, OSR availability
analysis, and flush liveness analysis. The FTL runs all of these prior to
generating code. While OSR exit continues to be tricky, much of the logic
is now factored into separate phases and the backend has to do less work
to reason about what happened outside of the basic block that is being
lowered.

Conversion from DFG SSA to LLVM SSA is done by ensuring that we generate
code in depth-first order, thus guaranteeing that a node will always be
lowered (and hence have a LValue) before any of the blocks dominated by
that node's block have code generated. For Upsilon/Phi, we just use
alloca's. We could do something more clever there, but it's probably not
worth it, at least not now.

Finally, while the SSA form is currently only being converted to LLVM IR,
there is nothing that prevents us from considering other backends in the
future - with the caveat that this form is designed to be first lowered to
a lower-level SSA before actual machine code generation commences. So we
ought to either use LLVM (the intended path) or we will have to write our
own SSA low-level backend.

This runs all of the code that the FTL was known to run previously. No
change in performance for now. But it does open some exciting
possibilities!

* JavaScriptCore.xcodeproj/project.pbxproj:
* bytecode/Operands.h:
(JSC::OperandValueTraits::dump):
(JSC::Operands::fill):
(Operands):
(JSC::Operands::clear):
(JSC::Operands::operator==):
* dfg/DFGAbstractState.cpp:
(JSC::DFG::AbstractState::beginBasicBlock):
(JSC::DFG::setLiveValues):
(DFG):
(JSC::DFG::AbstractState::initialize):
(JSC::DFG::AbstractState::endBasicBlock):
(JSC::DFG::AbstractState::executeEffects):
(JSC::DFG::AbstractState::mergeStateAtTail):
(JSC::DFG::AbstractState::merge):
* dfg/DFGAbstractState.h:
(AbstractState):
* dfg/DFGAdjacencyList.h:
(JSC::DFG::AdjacencyList::justOneChild):
(AdjacencyList):
* dfg/DFGBasicBlock.cpp: Added.
(DFG):
(JSC::DFG::BasicBlock::BasicBlock):
(JSC::DFG::BasicBlock::~BasicBlock):
(JSC::DFG::BasicBlock::ensureLocals):
(JSC::DFG::BasicBlock::isInPhis):
(JSC::DFG::BasicBlock::isInBlock):
(JSC::DFG::BasicBlock::removePredecessor):
(JSC::DFG::BasicBlock::replacePredecessor):
(JSC::DFG::BasicBlock::dump):
(JSC::DFG::BasicBlock::SSAData::SSAData):
(JSC::DFG::BasicBlock::SSAData::~SSAData):
* dfg/DFGBasicBlock.h:
(BasicBlock):
(JSC::DFG::BasicBlock::operator[]):
(JSC::DFG::BasicBlock::successor):
(JSC::DFG::BasicBlock::successorForCondition):
(SSAData):
* dfg/DFGBasicBlockInlines.h:
(DFG):
* dfg/DFGBlockInsertionSet.cpp: Added.
(DFG):
(JSC::DFG::BlockInsertionSet::BlockInsertionSet):
(JSC::DFG::BlockInsertionSet::~BlockInsertionSet):
(JSC::DFG::BlockInsertionSet::insert):
(JSC::DFG::BlockInsertionSet::insertBefore):
(JSC::DFG::BlockInsertionSet::execute):
* dfg/DFGBlockInsertionSet.h: Added.
(DFG):
(BlockInsertionSet):
* dfg/DFGCFAPhase.cpp:
(JSC::DFG::CFAPhase::run):
* dfg/DFGCFGSimplificationPhase.cpp:
* dfg/DFGCPSRethreadingPhase.cpp:
(JSC::DFG::CPSRethreadingPhase::canonicalizeLocalsInBlock):
* dfg/DFGCommon.cpp:
(WTF::printInternal):
* dfg/DFGCommon.h:
(JSC::DFG::doesKill):
(DFG):
(JSC::DFG::killStatusForDoesKill):
* dfg/DFGConstantFoldingPhase.cpp:
(JSC::DFG::ConstantFoldingPhase::foldConstants):
(JSC::DFG::ConstantFoldingPhase::isCapturedAtOrAfter):
* dfg/DFGCriticalEdgeBreakingPhase.cpp: Added.
(DFG):
(CriticalEdgeBreakingPhase):
(JSC::DFG::CriticalEdgeBreakingPhase::CriticalEdgeBreakingPhase):
(JSC::DFG::CriticalEdgeBreakingPhase::run):
(JSC::DFG::CriticalEdgeBreakingPhase::breakCriticalEdge):
(JSC::DFG::performCriticalEdgeBreaking):
* dfg/DFGCriticalEdgeBreakingPhase.h: Added.
(DFG):
* dfg/DFGDCEPhase.cpp:
(JSC::DFG::DCEPhase::run):
(JSC::DFG::DCEPhase::findTypeCheckRoot):
(JSC::DFG::DCEPhase::countNode):
(DCEPhase):
(JSC::DFG::DCEPhase::countEdge):
(JSC::DFG::DCEPhase::eliminateIrrelevantPhantomChildren):
* dfg/DFGDriver.cpp:
(JSC::DFG::compile):
* dfg/DFGEdge.cpp:
(JSC::DFG::Edge::dump):
* dfg/DFGEdge.h:
(JSC::DFG::Edge::Edge):
(JSC::DFG::Edge::setNode):
(JSC::DFG::Edge::useKindUnchecked):
(JSC::DFG::Edge::setUseKind):
(JSC::DFG::Edge::setProofStatus):
(JSC::DFG::Edge::willNotHaveCheck):
(JSC::DFG::Edge::willHaveCheck):
(Edge):
(JSC::DFG::Edge::killStatusUnchecked):
(JSC::DFG::Edge::killStatus):
(JSC::DFG::Edge::setKillStatus):
(JSC::DFG::Edge::doesKill):
(JSC::DFG::Edge::doesNotKill):
(JSC::DFG::Edge::shift):
(JSC::DFG::Edge::makeWord):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGFlushFormat.cpp: Added.
(WTF):
(WTF::printInternal):
* dfg/DFGFlushFormat.h: Added.
(DFG):
(JSC::DFG::resultFor):
(JSC::DFG::useKindFor):
(WTF):
* dfg/DFGFlushLivenessAnalysisPhase.cpp: Added.
(DFG):
(FlushLivenessAnalysisPhase):
(JSC::DFG::FlushLivenessAnalysisPhase::FlushLivenessAnalysisPhase):
(JSC::DFG::FlushLivenessAnalysisPhase::run):
(JSC::DFG::FlushLivenessAnalysisPhase::process):
(JSC::DFG::FlushLivenessAnalysisPhase::setForNode):
(JSC::DFG::FlushLivenessAnalysisPhase::flushFormat):
(JSC::DFG::performFlushLivenessAnalysis):
* dfg/DFGFlushLivenessAnalysisPhase.h: Added.
(DFG):
* dfg/DFGGraph.cpp:
(JSC::DFG::Graph::dump):
(JSC::DFG::Graph::dumpBlockHeader):
(DFG):
(JSC::DFG::Graph::addForDepthFirstSort):
(JSC::DFG::Graph::getBlocksInDepthFirstOrder):
* dfg/DFGGraph.h:
(JSC::DFG::Graph::convertToConstant):
(JSC::DFG::Graph::valueProfileFor):
(Graph):
* dfg/DFGInsertionSet.h:
(DFG):
(JSC::DFG::InsertionSet::execute):
* dfg/DFGLivenessAnalysisPhase.cpp: Added.
(DFG):
(LivenessAnalysisPhase):
(JSC::DFG::LivenessAnalysisPhase::LivenessAnalysisPhase):
(JSC::DFG::LivenessAnalysisPhase::run):
(JSC::DFG::LivenessAnalysisPhase::process):
(JSC::DFG::LivenessAnalysisPhase::addChildUse):
(JSC::DFG::performLivenessAnalysis):
* dfg/DFGLivenessAnalysisPhase.h: Added.
(DFG):
* dfg/DFGNode.cpp:
(JSC::DFG::Node::hasVariableAccessData):
(DFG):
* dfg/DFGNode.h:
(DFG):
(Node):
(JSC::DFG::Node::hasLocal):
(JSC::DFG::Node::variableAccessData):
(JSC::DFG::Node::hasPhi):
(JSC::DFG::Node::phi):
(JSC::DFG::Node::takenBlock):
(JSC::DFG::Node::notTakenBlock):
(JSC::DFG::Node::successor):
(JSC::DFG::Node::successorForCondition):
(JSC::DFG::nodeComparator):
(JSC::DFG::nodeListDump):
(JSC::DFG::nodeMapDump):
* dfg/DFGNodeFlags.cpp:
(JSC::DFG::dumpNodeFlags):
* dfg/DFGNodeType.h:
(DFG):
* dfg/DFGOSRAvailabilityAnalysisPhase.cpp: Added.
(DFG):
(OSRAvailabilityAnalysisPhase):
(JSC::DFG::OSRAvailabilityAnalysisPhase::OSRAvailabilityAnalysisPhase):
(JSC::DFG::OSRAvailabilityAnalysisPhase::run):
(JSC::DFG::performOSRAvailabilityAnalysis):
* dfg/DFGOSRAvailabilityAnalysisPhase.h: Added.
(DFG):
* dfg/DFGPlan.cpp:
(JSC::DFG::Plan::compileInThreadImpl):
* dfg/DFGPredictionInjectionPhase.cpp:
(JSC::DFG::PredictionInjectionPhase::run):
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
* dfg/DFGSSAConversionPhase.cpp: Added.
(DFG):
(SSAConversionPhase):
(JSC::DFG::SSAConversionPhase::SSAConversionPhase):
(JSC::DFG::SSAConversionPhase::run):
(JSC::DFG::SSAConversionPhase::forwardPhiChildren):
(JSC::DFG::SSAConversionPhase::forwardPhi):
(JSC::DFG::SSAConversionPhase::forwardPhiEdge):
(JSC::DFG::SSAConversionPhase::deduplicateChildren):
(JSC::DFG::SSAConversionPhase::addFlushedLocalOp):
(JSC::DFG::SSAConversionPhase::addFlushedLocalEdge):
(JSC::DFG::performSSAConversion):
* dfg/DFGSSAConversionPhase.h: Added.
(DFG):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGValidate.cpp:
(JSC::DFG::Validate::validate):
(Validate):
(JSC::DFG::Validate::validateCPS):
* dfg/DFGVariableAccessData.h:
(JSC::DFG::VariableAccessData::flushFormat):
(VariableAccessData):
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToLLVM.cpp:
(JSC::FTL::LowerDFGToLLVM::LowerDFGToLLVM):
(JSC::FTL::LowerDFGToLLVM::lower):
(JSC::FTL::LowerDFGToLLVM::createPhiVariables):
(JSC::FTL::LowerDFGToLLVM::compileBlock):
(JSC::FTL::LowerDFGToLLVM::compileNode):
(JSC::FTL::LowerDFGToLLVM::compileUpsilon):
(LowerDFGToLLVM):
(JSC::FTL::LowerDFGToLLVM::compilePhi):
(JSC::FTL::LowerDFGToLLVM::compileJSConstant):
(JSC::FTL::LowerDFGToLLVM::compileWeakJSConstant):
(JSC::FTL::LowerDFGToLLVM::compileGetArgument):
(JSC::FTL::LowerDFGToLLVM::compileGetLocal):
(JSC::FTL::LowerDFGToLLVM::compileSetLocal):
(JSC::FTL::LowerDFGToLLVM::compileAdd):
(JSC::FTL::LowerDFGToLLVM::compileArithSub):
(JSC::FTL::LowerDFGToLLVM::compileArithMul):
(JSC::FTL::LowerDFGToLLVM::compileArithDiv):
(JSC::FTL::LowerDFGToLLVM::compileArithMod):
(JSC::FTL::LowerDFGToLLVM::compileArithMinOrMax):
(JSC::FTL::LowerDFGToLLVM::compileArithAbs):
(JSC::FTL::LowerDFGToLLVM::compileArithNegate):
(JSC::FTL::LowerDFGToLLVM::compileBitAnd):
(JSC::FTL::LowerDFGToLLVM::compileBitOr):
(JSC::FTL::LowerDFGToLLVM::compileBitXor):
(JSC::FTL::LowerDFGToLLVM::compileBitRShift):
(JSC::FTL::LowerDFGToLLVM::compileBitLShift):
(JSC::FTL::LowerDFGToLLVM::compileBitURShift):
(JSC::FTL::LowerDFGToLLVM::compileUInt32ToNumber):
(JSC::FTL::LowerDFGToLLVM::compileInt32ToDouble):
(JSC::FTL::LowerDFGToLLVM::compileGetButterfly):
(JSC::FTL::LowerDFGToLLVM::compileGetArrayLength):
(JSC::FTL::LowerDFGToLLVM::compileGetByVal):
(JSC::FTL::LowerDFGToLLVM::compileGetByOffset):
(JSC::FTL::LowerDFGToLLVM::compileGetGlobalVar):
(JSC::FTL::LowerDFGToLLVM::compileCompareEqConstant):
(JSC::FTL::LowerDFGToLLVM::compileCompareStrictEq):
(JSC::FTL::LowerDFGToLLVM::compileCompareStrictEqConstant):
(JSC::FTL::LowerDFGToLLVM::compileCompareLess):
(JSC::FTL::LowerDFGToLLVM::compileCompareLessEq):
(JSC::FTL::LowerDFGToLLVM::compileCompareGreater):
(JSC::FTL::LowerDFGToLLVM::compileCompareGreaterEq):
(JSC::FTL::LowerDFGToLLVM::compileLogicalNot):
(JSC::FTL::LowerDFGToLLVM::speculateBackward):
(JSC::FTL::LowerDFGToLLVM::lowInt32):
(JSC::FTL::LowerDFGToLLVM::lowCell):
(JSC::FTL::LowerDFGToLLVM::lowBoolean):
(JSC::FTL::LowerDFGToLLVM::lowDouble):
(JSC::FTL::LowerDFGToLLVM::lowJSValue):
(JSC::FTL::LowerDFGToLLVM::lowStorage):
(JSC::FTL::LowerDFGToLLVM::speculate):
(JSC::FTL::LowerDFGToLLVM::speculateBoolean):
(JSC::FTL::LowerDFGToLLVM::isLive):
(JSC::FTL::LowerDFGToLLVM::use):
(JSC::FTL::LowerDFGToLLVM::initializeOSRExitStateForBlock):
(JSC::FTL::LowerDFGToLLVM::appendOSRExit):
(JSC::FTL::LowerDFGToLLVM::emitOSRExitCall):
(JSC::FTL::LowerDFGToLLVM::addExitArgumentForNode):
(JSC::FTL::LowerDFGToLLVM::linkOSRExitsAndCompleteInitializationBlocks):
(JSC::FTL::LowerDFGToLLVM::setInt32):
(JSC::FTL::LowerDFGToLLVM::setJSValue):
(JSC::FTL::LowerDFGToLLVM::setBoolean):
(JSC::FTL::LowerDFGToLLVM::setStorage):
(JSC::FTL::LowerDFGToLLVM::setDouble):
(JSC::FTL::LowerDFGToLLVM::isValid):
* ftl/FTLLoweredNodeValue.h: Added.
(FTL):
(LoweredNodeValue):
(JSC::FTL::LoweredNodeValue::LoweredNodeValue):
(JSC::FTL::LoweredNodeValue::isSet):
(JSC::FTL::LoweredNodeValue::operator!):
(JSC::FTL::LoweredNodeValue::value):
(JSC::FTL::LoweredNodeValue::block):
* ftl/FTLValueFromBlock.h:
(JSC::FTL::ValueFromBlock::ValueFromBlock):
(ValueFromBlock):
* ftl/FTLValueSource.cpp:
(JSC::FTL::ValueSource::dump):
* ftl/FTLValueSource.h:

Source/WTF:

Reviewed by Mark Hahnenberg.

- Extend variadicity of PrintStream and dataLog.

- Give HashSet the ability to add a span of things.

- Give HashSet the ability to == another HashSet.

- Note FIXME's in HashTable concerning copying performance, that affects
  the way that the DFG now uses HashSets and HashMaps.

- Factor out the bulk-insertion logic of JSC::DFG::InsertionSet into
  WTF::Insertion, so that it can be used in more places.

- Create a dumper for lists and maps.

* WTF.xcodeproj/project.pbxproj:
* wtf/DataLog.h:
(WTF):
(WTF::dataLog):
* wtf/HashSet.h:
(HashSet):
(WTF):
(WTF::::add):
(WTF::=):
* wtf/HashTable.h:
(WTF::::HashTable):
(WTF::=):
* wtf/Insertion.h: Added.
(WTF):
(Insertion):
(WTF::Insertion::Insertion):
(WTF::Insertion::index):
(WTF::Insertion::element):
(WTF::Insertion::operator<):
(WTF::executeInsertions):
* wtf/ListDump.h: Added.
(WTF):
(ListDump):
(WTF::ListDump::ListDump):
(WTF::ListDump::dump):
(MapDump):
(WTF::MapDump::MapDump):
(WTF::MapDump::dump):
(WTF::listDump):
(WTF::sortedListDump):
(WTF::lessThan):
(WTF::mapDump):
(WTF::sortedMapDump):
* wtf/PrintStream.h:
(PrintStream):
(WTF::PrintStream::print):

Conflicts:
	Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@153274 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 0d587919
This diff is collapsed.
......@@ -43,7 +43,7 @@ template<typename T> struct OperandValueTraits;
template<typename T>
struct OperandValueTraits {
static T defaultValue() { return T(); }
static void dump(const T& value, PrintStream& out) { value.dump(out); }
static void dump(const T& value, PrintStream& out) { out.print(value); }
};
enum OperandKind { ArgumentOperand, LocalOperand };
......@@ -209,12 +209,25 @@ public:
setLocalFirstTime(operand, value);
}
void clear()
void fill(T value)
{
for (size_t i = 0; i < m_arguments.size(); ++i)
m_arguments[i] = Traits::defaultValue();
m_arguments[i] = value;
for (size_t i = 0; i < m_locals.size(); ++i)
m_locals[i] = Traits::defaultValue();
m_locals[i] = value;
}
void clear()
{
fill(Traits::defaultValue());
}
bool operator==(const Operands& other) const
{
ASSERT(numberOfArguments() == other.numberOfArguments());
ASSERT(numberOfLocals() == other.numberOfLocals());
return m_arguments == other.m_arguments && m_locals == other.m_locals;
}
void dump(PrintStream& out) const;
......
......@@ -130,7 +130,7 @@ public:
// 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&);
void initialize();
// Start abstractly executing the given basic block. Initializes the
// notion of abstract state to what we believe it to be at the head
......
......@@ -99,6 +99,15 @@ public:
Edge child1Unchecked() const { return m_words[0]; }
Edge justOneChild() const
{
if (!!child1() && !child2()) {
ASSERT(!child3());
return child1();
}
return Edge();
}
void initialize(Edge child1, Edge child2, Edge child3)
{
child(0) = child1;
......
/*
* Copyright (C) 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
* 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.
*/
#include "config.h"
#include "DFGBasicBlock.h"
#if ENABLE(DFG_JIT)
#include "Operations.h"
namespace JSC { namespace DFG {
BasicBlock::BasicBlock(unsigned bytecodeBegin, unsigned numArguments, unsigned numLocals)
: bytecodeBegin(bytecodeBegin)
, index(NoBlock)
, isOSRTarget(false)
, cfaHasVisited(false)
, cfaShouldRevisit(false)
, cfaFoundConstants(false)
, cfaDidFinish(true)
, cfaBranchDirection(InvalidBranchDirection)
#if !ASSERT_DISABLED
, isLinked(false)
#endif
, isReachable(false)
, variablesAtHead(numArguments, numLocals)
, variablesAtTail(numArguments, numLocals)
, valuesAtHead(numArguments, numLocals)
, valuesAtTail(numArguments, numLocals)
{
}
BasicBlock::~BasicBlock() { }
void BasicBlock::ensureLocals(unsigned newNumLocals)
{
variablesAtHead.ensureLocals(newNumLocals);
variablesAtTail.ensureLocals(newNumLocals);
valuesAtHead.ensureLocals(newNumLocals);
valuesAtTail.ensureLocals(newNumLocals);
}
bool BasicBlock::isInPhis(Node* node) const
{
for (size_t i = 0; i < phis.size(); ++i) {
if (phis[i] == node)
return true;
}
return false;
}
bool BasicBlock::isInBlock(Node* myNode) const
{
for (size_t i = 0; i < numNodes(); ++i) {
if (node(i) == myNode)
return true;
}
return false;
}
void BasicBlock::removePredecessor(BasicBlock* block)
{
for (unsigned i = 0; i < predecessors.size(); ++i) {
if (predecessors[i] != block)
continue;
predecessors[i] = predecessors.last();
predecessors.removeLast();
return;
}
RELEASE_ASSERT_NOT_REACHED();
}
void BasicBlock::replacePredecessor(BasicBlock* from, BasicBlock* to)
{
for (unsigned i = predecessors.size(); i--;) {
if (predecessors[i] != from)
continue;
predecessors[i] = to;
return;
}
RELEASE_ASSERT_NOT_REACHED();
}
void BasicBlock::dump(PrintStream& out) const
{
out.print("#", index);
}
BasicBlock::SSAData::SSAData(BasicBlock* block)
: flushFormatAtHead(OperandsLike, block->variablesAtHead)
, flushFormatAtTail(OperandsLike, block->variablesAtHead)
, availabilityAtHead(OperandsLike, block->variablesAtHead)
, availabilityAtTail(OperandsLike, block->variablesAtHead)
{
}
BasicBlock::SSAData::~SSAData() { }
} } // namespace JSC::DFG
#endif // ENABLE(DFG_JIT)
......@@ -33,6 +33,8 @@
#include "DFGNode.h"
#include "DFGVariadicFunction.h"
#include "Operands.h"
#include <wtf/HashMap.h>
#include <wtf/HashSet.h>
#include <wtf/OwnPtr.h>
#include <wtf/Vector.h>
......@@ -44,42 +46,16 @@ class InsertionSet;
typedef Vector<BasicBlock*, 2> PredecessorList;
struct BasicBlock : RefCounted<BasicBlock> {
BasicBlock(unsigned bytecodeBegin, unsigned numArguments, unsigned numLocals)
: bytecodeBegin(bytecodeBegin)
, index(NoBlock)
, isOSRTarget(false)
, cfaHasVisited(false)
, cfaShouldRevisit(false)
, cfaFoundConstants(false)
, cfaDidFinish(true)
, cfaBranchDirection(InvalidBranchDirection)
#if !ASSERT_DISABLED
, isLinked(false)
#endif
, isReachable(false)
, variablesAtHead(numArguments, numLocals)
, variablesAtTail(numArguments, numLocals)
, valuesAtHead(numArguments, numLocals)
, valuesAtTail(numArguments, numLocals)
{
}
BasicBlock(unsigned bytecodeBegin, unsigned numArguments, unsigned numLocals);
~BasicBlock();
~BasicBlock()
{
}
void ensureLocals(unsigned newNumLocals)
{
variablesAtHead.ensureLocals(newNumLocals);
variablesAtTail.ensureLocals(newNumLocals);
valuesAtHead.ensureLocals(newNumLocals);
valuesAtTail.ensureLocals(newNumLocals);
}
void ensureLocals(unsigned newNumLocals);
size_t size() const { return m_nodes.size(); }
bool isEmpty() const { return !size(); }
Node*& at(size_t i) { return m_nodes[i]; }
Node* at(size_t i) const { return m_nodes[i]; }
Node*& operator[](size_t i) { return at(i); }
Node* operator[](size_t i) const { return at(i); }
Node* last() const { return at(size() - 1); }
void resize(size_t size) { m_nodes.resize(size); }
......@@ -96,44 +72,34 @@ struct BasicBlock : RefCounted<BasicBlock> {
}
bool isPhiIndex(size_t i) const { return i < phis.size(); }
bool isInPhis(Node* node) const
{
for (size_t i = 0; i < phis.size(); ++i) {
if (phis[i] == node)
return true;
}
return false;
}
bool isInBlock(Node* myNode) const
{
for (size_t i = 0; i < numNodes(); ++i) {
if (node(i) == myNode)
return true;
}
return false;
}
bool isInPhis(Node* node) const;
bool isInBlock(Node* myNode) const;
unsigned numSuccessors() { return last()->numSuccessors(); }
BasicBlock* successor(unsigned index)
BasicBlock*& successor(unsigned index)
{
return last()->successor(index);
}
BasicBlock* successorForCondition(bool condition)
BasicBlock*& successorForCondition(bool condition)
{
return last()->successorForCondition(condition);
}
void removePredecessor(BasicBlock* block);
void replacePredecessor(BasicBlock* from, BasicBlock* to);
#define DFG_DEFINE_APPEND_NODE(templatePre, templatePost, typeParams, valueParamsComma, valueParams, valueArgs) \
templatePre typeParams templatePost Node* appendNode(Graph&, SpeculatedType valueParamsComma valueParams);
DFG_VARIADIC_TEMPLATE_FUNCTION(DFG_DEFINE_APPEND_NODE)
#undef DFG_DEFINE_APPEND_NODE
void dump(PrintStream& out) const
{
out.print("#", index);
}
#define DFG_DEFINE_APPEND_NODE(templatePre, templatePost, typeParams, valueParamsComma, valueParams, valueArgs) \
templatePre typeParams templatePost Node* appendNonTerminal(Graph&, SpeculatedType valueParamsComma valueParams);
DFG_VARIADIC_TEMPLATE_FUNCTION(DFG_DEFINE_APPEND_NODE)
#undef DFG_DEFINE_APPEND_NODE
void dump(PrintStream& out) const;
// This value is used internally for block linking and OSR entry. It is mostly meaningless
// for other purposes due to inlining.
......@@ -160,6 +126,21 @@ struct BasicBlock : RefCounted<BasicBlock> {
Operands<AbstractValue> valuesAtHead;
Operands<AbstractValue> valuesAtTail;
struct SSAData {
Operands<FlushFormat> flushFormatAtHead;
Operands<FlushFormat> flushFormatAtTail;
Operands<Node*> availabilityAtHead;
Operands<Node*> availabilityAtTail;
HashSet<Node*> liveAtHead;
HashSet<Node*> liveAtTail;
HashMap<Node*, AbstractValue> valuesAtHead;
HashMap<Node*, AbstractValue> valuesAtTail;
SSAData(BasicBlock*);
~SSAData();
};
OwnPtr<SSAData> ssa;
private:
friend class InsertionSet;
......
......@@ -43,6 +43,17 @@ namespace JSC { namespace DFG {
DFG_VARIADIC_TEMPLATE_FUNCTION(DFG_DEFINE_APPEND_NODE)
#undef DFG_DEFINE_APPEND_NODE
#define DFG_DEFINE_APPEND_NODE(templatePre, templatePost, typeParams, valueParamsComma, valueParams, valueArgs) \
templatePre typeParams templatePost inline Node* BasicBlock::appendNonTerminal(Graph& graph, SpeculatedType type valueParamsComma valueParams) \
{ \
Node* result = graph.addNode(type valueParamsComma valueArgs); \
append(last()); \
at(size() - 2) = result; \
return result; \
}
DFG_VARIADIC_TEMPLATE_FUNCTION(DFG_DEFINE_APPEND_NODE)
#undef DFG_DEFINE_APPEND_NODE
} } // namespace JSC::DFG
#endif // ENABLE(DFG_JIT)
......
/*
* Copyright (C) 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
* 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.
*/
#include "config.h"
#include "DFGBlockInsertionSet.h"
#if ENABLE(DFG_JIT)
namespace JSC { namespace DFG {
BlockInsertionSet::BlockInsertionSet(Graph& graph)
: m_graph(graph)
{
}
BlockInsertionSet::~BlockInsertionSet() { }
void BlockInsertionSet::insert(const BlockInsertion& insertion)
{
m_insertions.append(insertion);
}
void BlockInsertionSet::insert(size_t index, PassRefPtr<BasicBlock> block)
{
insert(BlockInsertion(index, block));
}
BasicBlock* BlockInsertionSet::insert(size_t index)
{
RefPtr<BasicBlock> block = adoptRef(new BasicBlock(
UINT_MAX,
m_graph.block(0)->variablesAtHead.numberOfArguments(),
m_graph.block(0)->variablesAtHead.numberOfLocals()));
block->isReachable = true;
insert(index, block);
return block.get();
}
BasicBlock* BlockInsertionSet::insertBefore(BasicBlock* before)
{
return insert(before->index);
}
bool BlockInsertionSet::execute()
{
if (m_insertions.isEmpty())
return false;
// We allow insertions to be given to us in any order. So, we need to
// sort them before running WTF::executeInsertions.
std::sort(m_insertions.begin(), m_insertions.end());
executeInsertions(m_graph.m_blocks, m_insertions);
// Prune out empty entries. This isn't strictly necessary but it's
// healthy to keep the block list from growing.
unsigned targetIndex = 0;
for (unsigned sourceIndex = 0; sourceIndex < m_graph.m_blocks.size();) {
RefPtr<BasicBlock> block = m_graph.m_blocks[sourceIndex++];
if (!block)
continue;
m_graph.m_blocks[targetIndex++] = block;
}
m_graph.m_blocks.resize(targetIndex);
// Make sure that the blocks know their new indices.
for (unsigned i = 0; i < m_graph.m_blocks.size(); ++i)
m_graph.m_blocks[i]->index = i;
// And finally, invalidate all analyses that rely on the CFG.
m_graph.invalidateCFG();
return true;
}
} } // namespace JSC::DFG
#endif // ENABLE(DFG_JIT)
/*
* Copyright (C) 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
* 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 DFGBlockInsertionSet_h
#define DFGBlockInsertionSet_h
#include <wtf/Platform.h>
#if ENABLE(DFG_JIT)
#include "DFGGraph.h"
#include <wtf/Insertion.h>
#include <wtf/Vector.h>
namespace JSC { namespace DFG {
typedef WTF::Insertion<RefPtr<BasicBlock> > BlockInsertion;
class BlockInsertionSet {
public:
BlockInsertionSet(Graph& graph);
~BlockInsertionSet();
void insert(const BlockInsertion& insertion);
void insert(size_t index, PassRefPtr<BasicBlock> block);
BasicBlock* insert(size_t index);
BasicBlock* insertBefore(BasicBlock* before);
bool execute();
private:
Graph& m_graph;
Vector<BlockInsertion, 8> m_insertions;
};
} } // namespace JSC::DFG
#endif // ENABLE(DFG_JIT)
#endif // DFGBlockInsertionSet_h
......@@ -51,7 +51,7 @@ public:
bool run()
{
ASSERT(m_graph.m_form == ThreadedCPS);
ASSERT(m_graph.m_form == ThreadedCPS || m_graph.m_form == SSA);
ASSERT(m_graph.m_unificationState == GloballyUnified);
ASSERT(m_graph.m_refCountState == EverythingIsLive);
......@@ -68,7 +68,7 @@ public:
// after all predecessors have been visited. Only loops will cause this analysis to
// revisit blocks, and the amount of revisiting is proportional to loop depth.
AbstractState::initialize(m_graph);
m_state.initialize();
do {
m_changed = false;
......
......@@ -361,15 +361,9 @@ private:
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
dataLog(
"Fixing predecessors and phis due to jettison of Block ", *jettisonedBlock,
" from Block ", *block, ".\n",
" from Block ", *block, ".\n");
#endif
for (unsigned i = 0; i < jettisonedBlock->predecessors.size(); ++i) {
if (jettisonedBlock->predecessors[i] != block)
continue;
jettisonedBlock->predecessors[i] = jettisonedBlock->predecessors.last();
jettisonedBlock->predecessors.removeLast();
break;
}
jettisonedBlock->removePredecessor(block);
}
Vector<BasicBlock*, 1> noBlocks()
......
......@@ -327,12 +327,14 @@ private:
// SetArgument may only appear in the root block.
//
// Tail variable: the last thing that happened to the variable in the block.
// It may be a Flush, PhantomLocal, GetLocal, SetLocal, or SetArgument.
// It may be a Flush, PhantomLocal, GetLocal, SetLocal, SetArgument, or Phi.
// SetArgument may only appear in the root block. Note that if there ever
// was a GetLocal to the variable, and it was followed by PhantomLocals and
// Flushes but not SetLocals, then the tail variable will be the GetLocal.
// This reflects the fact that you only care that the tail variable is a
// Flush or PhantomLocal if nothing else interesting happened.
// Flush or PhantomLocal if nothing else interesting happened. Likewise, if
// there ever was a SetLocal and it was followed by Flushes, then the tail
// variable will be a SetLocal and not those subsequent Flushes.
//
// Child of GetLocal: the operation that the GetLocal keeps alive. For
// uncaptured locals, it may be a Phi from the current block. For arguments,
......
......@@ -48,17 +48,15 @@ void printInternal(PrintStream& out, OptimizationFixpointState state)
switch (state) {
case BeforeFixpoint:
out.print("BeforeFixpoint");
break;
return;
case FixpointNotConverged:
out.print("FixpointNotConverged");
break;
return;
case FixpointConverged:
out.print("FixpointConverged");
break;
default:
RELEASE_ASSERT_NOT_REACHED();
break;
return;
}
RELEASE_ASSERT_NOT_REACHED();
}
void printInternal(PrintStream& out, GraphForm form)
......@@ -66,14 +64,15 @@ void printInternal(PrintStream& out, GraphForm form)
switch (form) {
case LoadStore:
out.print("LoadStore");
break;
return;