Ignore:
Timestamp:
Aug 1, 2012, 9:32:30 PM (13 years ago)
Author:
[email protected]
Message:

DFG should hoist structure checks
https://bugs.webkit.org/show_bug.cgi?id=92696

Source/JavaScriptCore:

Reviewed by Gavin Barraclough.

This hoists structure checks in the same way that we would hoist array checks, but with added
complexity to cope with the fact that the structure of an object may change. This is handled
by performing a side effects analysis over the region in which the respective variable is
live. If a structure clobbering side effect may happen then we either hoist the structure
checks and fall back on structure transition watchpoints (if the watchpoint set is still
valid), or we avoid hoisting altogether.

Doing this required teaching the CFA that we may have an expectation that an object has a
particular structure even after structure clobbering happens, in the sense that structure
proofs that were cobbered can be revived using watchpoints. CFA must know about this so that
OSR entry may know about it, since we cannot allow entry to happen if the variable has a
clobbered structure proof, will have a watchpoint to revive the proof, and the variable in
the baseline JIT has a completely unrelated structure.

This is mostly performance neutral.

  • CMakeLists.txt:
  • GNUmakefile.list.am:
  • JavaScriptCore.xcodeproj/project.pbxproj:
  • Target.pri:
  • bytecode/ValueRecovery.h:

(JSC::ValueRecovery::isSet):
(JSC::ValueRecovery::operator!):
(ValueRecovery):

  • dfg/DFGAbstractState.cpp:

(JSC::DFG::AbstractState::execute):
(JSC::DFG::AbstractState::clobberWorld):
(DFG):
(JSC::DFG::AbstractState::clobberCapturedVars):

  • dfg/DFGAbstractState.h:

(AbstractState):

  • dfg/DFGAbstractValue.h:

(JSC::DFG::AbstractValue::clear):
(JSC::DFG::AbstractValue::isClear):
(JSC::DFG::AbstractValue::makeTop):
(JSC::DFG::AbstractValue::isTop):
(JSC::DFG::AbstractValue::set):
(JSC::DFG::AbstractValue::operator==):
(JSC::DFG::AbstractValue::merge):
(JSC::DFG::AbstractValue::filter):
(JSC::DFG::AbstractValue::validate):
(JSC::DFG::AbstractValue::validateForEntry):
(AbstractValue):
(JSC::DFG::AbstractValue::checkConsistency):
(JSC::DFG::AbstractValue::dump):

  • dfg/DFGByteCodeParser.cpp:

(JSC::DFG::ByteCodeParser::setLocal):
(JSC::DFG::ByteCodeParser::getArgument):
(JSC::DFG::ByteCodeParser::setArgument):
(JSC::DFG::ByteCodeParser::parseBlock):
(JSC::DFG::ByteCodeParser::fixVariableAccessSpeculations):

  • dfg/DFGCSEPhase.cpp:

(JSC::DFG::CSEPhase::checkStructureLoadElimination):
(JSC::DFG::CSEPhase::structureTransitionWatchpointElimination):
(JSC::DFG::CSEPhase::putStructureStoreElimination):
(JSC::DFG::CSEPhase::getLocalLoadElimination):
(JSC::DFG::CSEPhase::performNodeCSE):

  • dfg/DFGDriver.cpp:

(JSC::DFG::compile):

  • dfg/DFGGraph.cpp:

(JSC::DFG::Graph::dump):

  • dfg/DFGGraph.h:

(JSC::DFG::Graph::vote):
(Graph):

  • dfg/DFGNode.h:

(JSC::DFG::Node::convertToStructureTransitionWatchpoint):
(Node):
(JSC::DFG::Node::hasStructureSet):

  • dfg/DFGNodeType.h:

(DFG):

  • dfg/DFGOSREntry.cpp:

(JSC::DFG::prepareOSREntry):

  • dfg/DFGPredictionPropagationPhase.cpp:

(JSC::DFG::PredictionPropagationPhase::propagate):
(PredictionPropagationPhase):
(JSC::DFG::PredictionPropagationPhase::doRoundOfDoubleVoting):

  • dfg/DFGSpeculativeJIT.h:

(SpeculativeJIT):
(JSC::DFG::SpeculativeJIT::forwardSpeculationCheck):
(JSC::DFG::SpeculativeJIT::speculationCheckWithConditionalDirection):
(JSC::DFG::SpeculativeJIT::terminateSpeculativeExecutionWithConditionalDirection):
(JSC::DFG::SpeculateCellOperand::SpeculateCellOperand):
(JSC::DFG::SpeculateCellOperand::gpr):
(SpeculateCellOperand):

  • dfg/DFGSpeculativeJIT32_64.cpp:

(JSC::DFG::SpeculativeJIT::fillSpeculateCell):
(JSC::DFG::SpeculativeJIT::compile):

  • dfg/DFGSpeculativeJIT64.cpp:

(JSC::DFG::SpeculativeJIT::fillSpeculateCell):
(JSC::DFG::SpeculativeJIT::compile):

  • dfg/DFGStructureCheckHoistingPhase.cpp: Added.

(DFG):
(StructureCheckHoistingPhase):
(JSC::DFG::StructureCheckHoistingPhase::StructureCheckHoistingPhase):
(JSC::DFG::StructureCheckHoistingPhase::run):
(JSC::DFG::StructureCheckHoistingPhase::noticeStructureCheck):
(JSC::DFG::StructureCheckHoistingPhase::noticeClobber):
(JSC::DFG::StructureCheckHoistingPhase::clobber):
(CheckData):
(JSC::DFG::StructureCheckHoistingPhase::CheckData::CheckData):
(JSC::DFG::performStructureCheckHoisting):

  • dfg/DFGStructureCheckHoistingPhase.h: Added.

(DFG):

  • dfg/DFGVariableAccessData.h:

(VariableAccessData):
(JSC::DFG::VariableAccessData::VariableAccessData):
(JSC::DFG::VariableAccessData::mergeStructureCheckHoistingFailed):
(JSC::DFG::VariableAccessData::structureCheckHoistingFailed):
(JSC::DFG::VariableAccessData::clearVotes):
(JSC::DFG::VariableAccessData::vote):
(JSC::DFG::VariableAccessData::voteRatio):
(JSC::DFG::VariableAccessData::shouldUseDoubleFormatAccordingToVote):

  • runtime/Options.h:

(JSC):

LayoutTests:

Rubber stamped by Gavin Barraclough.

Added a new test that covers the following scenarios:

  • OSR entry if a variable with a hoisted check has an unexpected structure, structures get clobbered, and we're protecting ourselves with structure transition watchpoints.


  • OSR exit on hoisted structure checks, if the object doesn't have the expected structure, and where the source of the assignment is side-effecting.


I combined these into a single test because there is no way to test the latter without testing the former.

  • fast/js/dfg-osr-entry-hoisted-clobbered-structure-check-expected.txt: Added.
  • fast/js/dfg-osr-entry-hoisted-clobbered-structure-check.html: Added.
  • fast/js/jsc-test-list:
  • fast/js/script-tests/dfg-osr-entry-hoisted-clobbered-structure-check.js: Added.

(foo):
(bar):
(baz):

File:
1 edited

Legend:

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

    r121798 r124404  
    3838namespace JSC { namespace DFG {
    3939
     40enum DoubleBallot { VoteValue, VoteDouble };
     41
    4042class VariableAccessData : public UnionFind<VariableAccessData> {
    4143public:
    42     enum Ballot { VoteValue, VoteDouble };
    43 
    4444    VariableAccessData()
    4545        : m_local(static_cast<VirtualRegister>(std::numeric_limits<int>::min()))
     
    5050        , m_isCaptured(false)
    5151        , m_isArgumentsAlias(false)
     52        , m_structureCheckHoistingFailed(false)
    5253    {
    5354        clearVotes();
     
    6263        , m_isCaptured(isCaptured)
    6364        , m_isArgumentsAlias(false)
     65        , m_structureCheckHoistingFailed(false)
    6466    {
    6567        clearVotes();
     
    8991    {
    9092        return m_isCaptured;
     93    }
     94   
     95    bool mergeStructureCheckHoistingFailed(bool failed)
     96    {
     97        bool newFailed = m_structureCheckHoistingFailed | failed;
     98        if (newFailed == m_structureCheckHoistingFailed)
     99            return false;
     100        m_structureCheckHoistingFailed = newFailed;
     101        return true;
     102    }
     103   
     104    bool structureCheckHoistingFailed()
     105    {
     106        return m_structureCheckHoistingFailed;
    91107    }
    92108   
     
    137153    {
    138154        ASSERT(find() == this);
    139         m_votes[VoteValue] = 0;
    140         m_votes[VoteDouble] = 0;
    141     }
    142    
    143     void vote(Ballot ballot)
    144     {
    145         ASSERT(static_cast<unsigned>(ballot) < 2);
     155        m_votes[0] = 0;
     156        m_votes[1] = 0;
     157    }
     158   
     159    void vote(unsigned ballot)
     160    {
     161        ASSERT(ballot < 2);
    146162        m_votes[ballot]++;
    147163    }
    148164   
    149     double doubleVoteRatio()
     165    double voteRatio()
    150166    {
    151167        ASSERT(find() == this);
    152         return static_cast<double>(m_votes[VoteDouble]) / m_votes[VoteValue];
     168        return static_cast<double>(m_votes[1]) / m_votes[0];
    153169    }
    154170   
     
    177193        // If the variable has been voted to become a double, then make it a
    178194        // double.
    179         if (doubleVoteRatio() >= Options::doubleVoteRatioForDoubleFormat())
     195        if (voteRatio() >= Options::doubleVoteRatioForDoubleFormat())
    180196            return true;
    181197       
     
    251267    NodeFlags m_flags;
    252268   
    253     float m_votes[2];
     269    float m_votes[2]; // Used primarily for double voting but may be reused for other purposes.
    254270    DoubleFormatState m_doubleFormatState;
    255271   
    256272    bool m_isCaptured;
    257273    bool m_isArgumentsAlias;
     274    bool m_structureCheckHoistingFailed;
    258275};
    259276
Note: See TracChangeset for help on using the changeset viewer.