Ignore:
Timestamp:
Jul 24, 2013, 9:04:45 PM (12 years ago)
Author:
[email protected]
Message:

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!

(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

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/dfg/DFGBasicBlock.h

    r153267 r153274  
    3434#include "DFGVariadicFunction.h"
    3535#include "Operands.h"
     36#include <wtf/HashMap.h>
     37#include <wtf/HashSet.h>
    3638#include <wtf/OwnPtr.h>
    3739#include <wtf/Vector.h>
     
    4547
    4648struct BasicBlock : RefCounted<BasicBlock> {
    47     BasicBlock(unsigned bytecodeBegin, unsigned numArguments, unsigned numLocals)
    48         : bytecodeBegin(bytecodeBegin)
    49         , index(NoBlock)
    50         , isOSRTarget(false)
    51         , cfaHasVisited(false)
    52         , cfaShouldRevisit(false)
    53         , cfaFoundConstants(false)
    54         , cfaDidFinish(true)
    55         , cfaBranchDirection(InvalidBranchDirection)
    56 #if !ASSERT_DISABLED
    57         , isLinked(false)
    58 #endif
    59         , isReachable(false)
    60         , variablesAtHead(numArguments, numLocals)
    61         , variablesAtTail(numArguments, numLocals)
    62         , valuesAtHead(numArguments, numLocals)
    63         , valuesAtTail(numArguments, numLocals)
    64     {
    65     }
     49    BasicBlock(unsigned bytecodeBegin, unsigned numArguments, unsigned numLocals);
     50    ~BasicBlock();
    6651   
    67     ~BasicBlock()
    68     {
    69     }
    70    
    71     void ensureLocals(unsigned newNumLocals)
    72     {
    73         variablesAtHead.ensureLocals(newNumLocals);
    74         variablesAtTail.ensureLocals(newNumLocals);
    75         valuesAtHead.ensureLocals(newNumLocals);
    76         valuesAtTail.ensureLocals(newNumLocals);
    77     }
     52    void ensureLocals(unsigned newNumLocals);
    7853   
    7954    size_t size() const { return m_nodes.size(); }
     
    8156    Node*& at(size_t i) { return m_nodes[i]; }
    8257    Node* at(size_t i) const { return m_nodes[i]; }
     58    Node*& operator[](size_t i) { return at(i); }
    8359    Node* operator[](size_t i) const { return at(i); }
    8460    Node* last() const { return at(size() - 1); }
     
    9773    bool isPhiIndex(size_t i) const { return i < phis.size(); }
    9874   
    99     bool isInPhis(Node* node) const
    100     {
    101         for (size_t i = 0; i < phis.size(); ++i) {
    102             if (phis[i] == node)
    103                 return true;
    104         }
    105         return false;
    106     }
    107    
    108     bool isInBlock(Node* myNode) const
    109     {
    110         for (size_t i = 0; i < numNodes(); ++i) {
    111             if (node(i) == myNode)
    112                 return true;
    113         }
    114         return false;
    115     }
     75    bool isInPhis(Node* node) const;
     76    bool isInBlock(Node* myNode) const;
    11677   
    11778    unsigned numSuccessors() { return last()->numSuccessors(); }
    11879   
    119     BasicBlock* successor(unsigned index)
     80    BasicBlock*& successor(unsigned index)
    12081    {
    12182        return last()->successor(index);
    12283    }
    123     BasicBlock* successorForCondition(bool condition)
     84    BasicBlock*& successorForCondition(bool condition)
    12485    {
    12586        return last()->successorForCondition(condition);
    12687    }
     88   
     89    void removePredecessor(BasicBlock* block);
     90    void replacePredecessor(BasicBlock* from, BasicBlock* to);
    12791
    12892#define DFG_DEFINE_APPEND_NODE(templatePre, templatePost, typeParams, valueParamsComma, valueParams, valueArgs) \
     
    13195#undef DFG_DEFINE_APPEND_NODE
    13296   
    133     void dump(PrintStream& out) const
    134     {
    135         out.print("#", index);
    136     }
     97#define DFG_DEFINE_APPEND_NODE(templatePre, templatePost, typeParams, valueParamsComma, valueParams, valueArgs) \
     98    templatePre typeParams templatePost Node* appendNonTerminal(Graph&, SpeculatedType valueParamsComma valueParams);
     99    DFG_VARIADIC_TEMPLATE_FUNCTION(DFG_DEFINE_APPEND_NODE)
     100#undef DFG_DEFINE_APPEND_NODE
     101   
     102    void dump(PrintStream& out) const;
    137103   
    138104    // This value is used internally for block linking and OSR entry. It is mostly meaningless
     
    161127    Operands<AbstractValue> valuesAtHead;
    162128    Operands<AbstractValue> valuesAtTail;
     129   
     130    struct SSAData {
     131        Operands<FlushFormat> flushFormatAtHead;
     132        Operands<FlushFormat> flushFormatAtTail;
     133        Operands<Node*> availabilityAtHead;
     134        Operands<Node*> availabilityAtTail;
     135        HashSet<Node*> liveAtHead;
     136        HashSet<Node*> liveAtTail;
     137        HashMap<Node*, AbstractValue> valuesAtHead;
     138        HashMap<Node*, AbstractValue> valuesAtTail;
     139       
     140        SSAData(BasicBlock*);
     141        ~SSAData();
     142    };
     143    OwnPtr<SSAData> ssa;
    163144
    164145private:
Note: See TracChangeset for help on using the changeset viewer.