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

fourthTier: Decouple the way that CFA stores its state from the way it does abstract interpretation
https://bugs.webkit.org/show_bug.cgi?id=118835

Reviewed by Oliver Hunt.

This separates AbstractState into two things:

  • InPlaceAbstractState, which can tell you the abstract state of anything you might care about, and uses the old AbstractState's algorithms and data structures for doing so.
  • AbstractInterpreter<AbstractStateType>, which can execute a DFG::Node* with respect to an AbstractStateType. Currently we always use AbstractStateType = InPlaceAbstractState. But we could drop in an other class that supports basic primitives like forNode() and variables().

This is important because:

  • We want to hoist things out of loops.
  • We don't know what things rely on what type checks.
  • We only want to hoist type checks out of loops if they aren't clobbered.
  • We may want to still hoist things that depended on those type checks, if it's safe to do those things based on the CFA state at the tail of the loop pre-header.
  • We don't want things to rely on their type checks by way of a token, because that's just weird.

So, we want to be able to have a special form of the CFA that can
incrementally update a basic block's state-at-tail, and we want to be able to
do this for multiple blocks simultaneously. This requires *not* storing the
per-node state in the nodes themselves, but instead using the at-tail HashMap
directly.

Hence we need to have a way of making the abstract interpreter (i.e.
AbstractState::execute) polymorphic with respect to state representation. Put
another way, we need to separate the way that abstract state is represented
from the way DFG IR is abstractly interpreted.

  • JavaScriptCore.xcodeproj/project.pbxproj:
  • dfg/DFGAbstractInterpreter.h: Added.

(DFG):
(AbstractInterpreter):
(JSC::DFG::AbstractInterpreter::forNode):
(JSC::DFG::AbstractInterpreter::variables):
(JSC::DFG::AbstractInterpreter::needsTypeCheck):
(JSC::DFG::AbstractInterpreter::filterEdgeByUse):
(JSC::DFG::AbstractInterpreter::filter):
(JSC::DFG::AbstractInterpreter::filterArrayModes):
(JSC::DFG::AbstractInterpreter::filterByValue):
(JSC::DFG::AbstractInterpreter::trySetConstant):
(JSC::DFG::AbstractInterpreter::filterByType):

  • dfg/DFGAbstractInterpreterInlines.h: Added.

(DFG):
(JSC::DFG::::AbstractInterpreter):
(JSC::DFG::::~AbstractInterpreter):
(JSC::DFG::::booleanResult):
(JSC::DFG::::startExecuting):
(JSC::DFG::::executeEdges):
(JSC::DFG::::verifyEdge):
(JSC::DFG::::verifyEdges):
(JSC::DFG::::executeEffects):
(JSC::DFG::::execute):
(JSC::DFG::::clobberWorld):
(JSC::DFG::::clobberCapturedVars):
(JSC::DFG::::clobberStructures):
(JSC::DFG::::dump):
(JSC::DFG::::filter):
(JSC::DFG::::filterArrayModes):
(JSC::DFG::::filterByValue):

  • dfg/DFGAbstractState.cpp: Removed.
  • dfg/DFGAbstractState.h: Removed.
  • dfg/DFGArgumentsSimplificationPhase.cpp:
  • dfg/DFGCFAPhase.cpp:

(JSC::DFG::CFAPhase::CFAPhase):
(JSC::DFG::CFAPhase::performBlockCFA):
(CFAPhase):

  • dfg/DFGCFGSimplificationPhase.cpp:
  • dfg/DFGConstantFoldingPhase.cpp:

(JSC::DFG::ConstantFoldingPhase::ConstantFoldingPhase):
(JSC::DFG::ConstantFoldingPhase::foldConstants):
(ConstantFoldingPhase):

  • dfg/DFGInPlaceAbstractState.cpp: Added.

(DFG):
(JSC::DFG::InPlaceAbstractState::InPlaceAbstractState):
(JSC::DFG::InPlaceAbstractState::~InPlaceAbstractState):
(JSC::DFG::InPlaceAbstractState::beginBasicBlock):
(JSC::DFG::setLiveValues):
(JSC::DFG::InPlaceAbstractState::initialize):
(JSC::DFG::InPlaceAbstractState::endBasicBlock):
(JSC::DFG::InPlaceAbstractState::reset):
(JSC::DFG::InPlaceAbstractState::mergeStateAtTail):
(JSC::DFG::InPlaceAbstractState::merge):
(JSC::DFG::InPlaceAbstractState::mergeToSuccessors):
(JSC::DFG::InPlaceAbstractState::mergeVariableBetweenBlocks):

  • dfg/DFGInPlaceAbstractState.h: Added.

(DFG):
(InPlaceAbstractState):
(JSC::DFG::InPlaceAbstractState::forNode):
(JSC::DFG::InPlaceAbstractState::variables):
(JSC::DFG::InPlaceAbstractState::block):
(JSC::DFG::InPlaceAbstractState::didClobber):
(JSC::DFG::InPlaceAbstractState::isValid):
(JSC::DFG::InPlaceAbstractState::setDidClobber):
(JSC::DFG::InPlaceAbstractState::setIsValid):
(JSC::DFG::InPlaceAbstractState::setBranchDirection):
(JSC::DFG::InPlaceAbstractState::setFoundConstants):
(JSC::DFG::InPlaceAbstractState::haveStructures):
(JSC::DFG::InPlaceAbstractState::setHaveStructures):

  • dfg/DFGMergeMode.h: Added.

(DFG):

  • dfg/DFGSpeculativeJIT.cpp:

(JSC::DFG::SpeculativeJIT::SpeculativeJIT):
(JSC::DFG::SpeculativeJIT::backwardTypeCheck):
(JSC::DFG::SpeculativeJIT::compileCurrentBlock):
(JSC::DFG::SpeculativeJIT::compileToStringOnCell):
(JSC::DFG::SpeculativeJIT::speculateStringIdentAndLoadStorage):
(JSC::DFG::SpeculativeJIT::speculateStringObject):
(JSC::DFG::SpeculativeJIT::speculateStringOrStringObject):

  • dfg/DFGSpeculativeJIT.h:

(JSC::DFG::SpeculativeJIT::needsTypeCheck):
(SpeculativeJIT):

  • dfg/DFGSpeculativeJIT32_64.cpp:

(JSC::DFG::SpeculativeJIT::fillSpeculateIntInternal):
(JSC::DFG::SpeculativeJIT::fillSpeculateDouble):
(JSC::DFG::SpeculativeJIT::fillSpeculateCell):
(JSC::DFG::SpeculativeJIT::fillSpeculateBoolean):

  • dfg/DFGSpeculativeJIT64.cpp:

(JSC::DFG::SpeculativeJIT::fillSpeculateIntInternal):
(JSC::DFG::SpeculativeJIT::fillSpeculateDouble):
(JSC::DFG::SpeculativeJIT::fillSpeculateCell):
(JSC::DFG::SpeculativeJIT::fillSpeculateBoolean):

  • ftl/FTLLowerDFGToLLVM.cpp:

(FTL):
(JSC::FTL::LowerDFGToLLVM::LowerDFGToLLVM):
(JSC::FTL::LowerDFGToLLVM::compileNode):
(JSC::FTL::LowerDFGToLLVM::appendTypeCheck):
(JSC::FTL::LowerDFGToLLVM::speculate):
(JSC::FTL::LowerDFGToLLVM::speculateNumber):
(JSC::FTL::LowerDFGToLLVM::speculateRealNumber):
(LowerDFGToLLVM):

Conflicts:

Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj

File:
1 moved

Legend:

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

    r153281 r153282  
    11/*
    2  * Copyright (C) 2011, 2012, 2013 Apple Inc. All rights reserved.
     2 * Copyright (C) 2013 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    2424 */
    2525
    26 #ifndef DFGAbstractState_h
    27 #define DFGAbstractState_h
     26#ifndef DFGAbstractInterpreter_h
     27#define DFGAbstractInterpreter_h
    2828
    2929#include <wtf/Platform.h>
     
    3535#include "DFGGraph.h"
    3636#include "DFGNode.h"
    37 #include <wtf/Vector.h>
    38 
    39 namespace JSC {
    40 
    41 class CodeBlock;
    42 
    43 namespace DFG {
    44 
    45 struct BasicBlock;
    46 
    47 // This implements the notion of an abstract state for flow-sensitive intraprocedural
    48 // control flow analysis (CFA), with a focus on the elimination of redundant type checks.
    49 // It also implements most of the mechanisms of abstract interpretation that such an
    50 // analysis would use. This class should be used in two idioms:
    51 //
    52 // 1) Performing the CFA. In this case, AbstractState should be run over all basic
    53 //    blocks repeatedly until convergence is reached. Convergence is defined by
    54 //    endBasicBlock(AbstractState::MergeToSuccessors) returning false for all blocks.
    55 //
    56 // 2) Rematerializing the results of a previously executed CFA. In this case,
    57 //    AbstractState should be run over whatever basic block you're interested in up
    58 //    to the point of the node at which you'd like to interrogate the known type
    59 //    of all other nodes. At this point it's safe to discard the AbstractState entirely,
    60 //    call reset(), or to run it to the end of the basic block and call
    61 //    endBasicBlock(AbstractState::DontMerge). The latter option is safest because
    62 //    it performs some useful integrity checks.
    63 //
    64 // After the CFA is run, the inter-block state is saved at the heads and tails of all
    65 // basic blocks. This allows the intra-block state to be rematerialized by just
    66 // executing the CFA for that block. If you need to know inter-block state only, then
    67 // you only need to examine the BasicBlock::m_valuesAtHead or m_valuesAtTail fields.
    68 //
    69 // Running this analysis involves the following, modulo the inter-block state
    70 // merging and convergence fixpoint:
    71 //
    72 // AbstractState state(codeBlock, graph);
    73 // state.beginBasicBlock(basicBlock);
    74 // bool endReached = true;
    75 // for (unsigned i = 0; i < basicBlock->size(); ++i) {
    76 //     if (!state.execute(i))
    77 //         break;
    78 // }
    79 // bool result = state.endBasicBlock(<either Merge or DontMerge>);
    80 
    81 class AbstractState {
     37
     38namespace JSC { namespace DFG {
     39
     40template<typename AbstractStateType>
     41class AbstractInterpreter {
    8242public:
    83     enum MergeMode {
    84         // Don't merge the state in AbstractState with basic blocks.
    85         DontMerge,
    86        
    87         // Merge the state in AbstractState with the tail of the basic
    88         // block being analyzed.
    89         MergeToTail,
    90        
    91         // Merge the state in AbstractState with the tail of the basic
    92         // block, and with the heads of successor blocks.
    93         MergeToSuccessors
    94     };
    95    
    96     AbstractState(Graph&);
    97    
    98     ~AbstractState();
     43    AbstractInterpreter(Graph&, AbstractStateType& state);
     44    ~AbstractInterpreter();
    9945   
    10046    AbstractValue& forNode(Node* node)
    10147    {
    102         return node->value;
     48        return m_state.forNode(node);
    10349    }
    10450   
     
    11056    Operands<AbstractValue>& variables()
    11157    {
    112         return m_variables;
     58        return m_state.variables();
    11359    }
    11460   
     
    12773        return needsTypeCheck(edge, typeFilterFor(edge.useKind()));
    12874    }
    129    
    130     // Call this before beginning CFA to initialize the abstract values of
    131     // arguments, and to indicate which blocks should be listed for CFA
    132     // execution.
    133     void initialize();
    134 
    135     // Start abstractly executing the given basic block. Initializes the
    136     // notion of abstract state to what we believe it to be at the head
    137     // of the basic block, according to the basic block's data structures.
    138     // This method also sets cfaShouldRevisit to false.
    139     void beginBasicBlock(BasicBlock*);
    140    
    141     // Finish abstractly executing a basic block. If MergeToTail or
    142     // MergeToSuccessors is passed, then this merges everything we have
    143     // learned about how the state changes during this block's execution into
    144     // the block's data structures. There are three return modes, depending
    145     // on the value of mergeMode:
    146     //
    147     // DontMerge:
    148     //    Always returns false.
    149     //
    150     // MergeToTail:
    151     //    Returns true if the state of the block at the tail was changed.
    152     //    This means that you must call mergeToSuccessors(), and if that
    153     //    returns true, then you must revisit (at least) the successor
    154     //    blocks. False will always be returned if the block is terminal
    155     //    (i.e. ends in Throw or Return, or has a ForceOSRExit inside it).
    156     //
    157     // MergeToSuccessors:
    158     //    Returns true if the state of the block at the tail was changed,
    159     //    and, if the state at the heads of successors was changed.
    160     //    A true return means that you must revisit (at least) the successor
    161     //    blocks. This also sets cfaShouldRevisit to true for basic blocks
    162     //    that must be visited next.
    163     bool endBasicBlock(MergeMode);
    164    
    165     // Reset the AbstractState. This throws away any results, and at this point
    166     // you can safely call beginBasicBlock() on any basic block.
    167     void reset();
    16875   
    16976    // Abstractly executes the given node. The new abstract state is stored into an
     
    210117    bool executeEffects(unsigned indexInBlock, Node*);
    211118   
    212     // Did the last executed node clobber the world?
    213     bool didClobber() const { return m_didClobber; }
    214    
    215     // Is the execution state still valid? This will be false if execute() has
    216     // returned false previously.
    217     bool isValid() const { return m_isValid; }
    218    
    219     // Merge the abstract state stored at the first block's tail into the second
    220     // block's head. Returns true if the second block's state changed. If so,
    221     // that block must be abstractly interpreted again. This also sets
    222     // to->cfaShouldRevisit to true, if it returns true, or if to has not been
    223     // visited yet.
    224     bool merge(BasicBlock* from, BasicBlock* to);
    225    
    226     // Merge the abstract state stored at the block's tail into all of its
    227     // successors. Returns true if any of the successors' states changed. Note
    228     // that this is automatically called in endBasicBlock() if MergeMode is
    229     // MergeToSuccessors.
    230     bool mergeToSuccessors(BasicBlock*);
    231    
    232119    void dump(PrintStream& out);
    233120   
     
    265152    void clobberCapturedVars(const CodeOrigin&);
    266153    void clobberStructures(unsigned indexInBlock);
    267    
    268     bool mergeStateAtTail(AbstractValue& destination, AbstractValue& inVariable, Node*);
    269    
    270     static bool mergeVariableBetweenBlocks(AbstractValue& destination, AbstractValue& source, Node* destinationNode, Node* sourceNode);
    271154   
    272155    enum BooleanResult {
     
    311194    CodeBlock* m_codeBlock;
    312195    Graph& m_graph;
    313    
    314     Operands<AbstractValue> m_variables;
    315     BasicBlock* m_block;
    316    
    317     bool m_haveStructures;
    318     bool m_foundConstants;
    319    
    320     bool m_isValid;
    321     bool m_didClobber;
    322    
    323     BranchDirection m_branchDirection; // This is only set for blocks that end in Branch and that execute to completion (i.e. m_isValid == true).
     196    AbstractStateType& m_state;
    324197};
    325198
     
    328201#endif // ENABLE(DFG_JIT)
    329202
    330 #endif // DFGAbstractState_h
    331 
     203#endif // DFGAbstractInterpreter_h
     204
Note: See TracChangeset for help on using the changeset viewer.