Changeset 161126 in webkit


Ignore:
Timestamp:
Dec 29, 2013 1:50:55 PM (10 years ago)
Author:
fpizlo@apple.com
Message:

Get rid of DFG forward exiting
https://bugs.webkit.org/show_bug.cgi?id=125531

Reviewed by Oliver Hunt.

This finally gets rid of forward exiting. Forward exiting was always a fragile concept
since it involved the compiler trying to figure out how to "roll forward" the
execution from some DFG node to the next bytecode index. It was always easy to find
counterexamples where it broke, and it has always served as an obstacle to adding
compiler improvements - the latest being http://webkit.org/b/125523, which tried to
make DCE work for more things.

This change finishes the work of removing forward exiting. A lot of forward exiting
was already removed in some other bugs, but SetLocal still did forward exits. SetLocal
is in many ways the hardest to remove, since the forward exiting of SetLocal also
implied that any conversion nodes inserted before the SetLocal would then also be
marked as forward-exiting. Hence SetLocal's forward-exiting made a bunch of other
things also forward-exiting, and this was always a source of weirdo bugs.

SetLocal must be able to exit in case it performs a hoisted type speculation. Nodes
inserted just before SetLocal must also be able to exit - for example type check
hoisting may insert a CheckStructure, or fixup phase may insert something like
Int32ToDouble. But if any of those nodes tried to backward exit, then this could lead
to the reexecution of a side-effecting operation, for example:

a: Call(...)
b: SetLocal(@a, r1)


For a long time it seemed like SetLocal *had* to exit forward because of this. But
this change side-steps the problem by changing the ByteCodeParser to always emit a
kind of "two-phase commit" for stores to local variables. Now when the ByteCodeParser
wishes to store to a local, it first emits a MovHint and then enqueues a SetLocal.
The SetLocal isn't actually emitted until the beginning of the next bytecode
instruction (which the exception of op_enter and op_ret, which emit theirs immediately
since it's always safe to reexecute those bytecode instructions and since deferring
SetLocals would be weird there - op_enter has many SetLocals and op_ret is a set
followed by a jump in case of inlining, so we'd have to emit the SetLocal "after" the
jump and that would be awkward). This means that the above IR snippet would look
something like:

a: Call(..., bc#42)
b: MovHint(@a, r1, bc#42)
c: SetLocal(@a, r1, bc#47)


Where the SetLocal exits "backwards" but appears at the beginning of the next bytecode
instruction. This means that by the time we get to that SetLocal, the OSR exit
analysis already knows that r1 is associated with @a, and it means that the SetLocal
or anything hoisted above it can exit backwards as normal.

This change also means that the "forward rewiring" can be killed. Previously, we might
have inserted a conversion node on SetLocal and then the SetLocal died (i.e. turned
into a MovHint) and the conversion node either died completely or had its lifetime
truncated to be less than the actual value's bytecode lifetime. This no longer happens
since conversion nodes are only inserted at SetLocals.

More precisely, this change introduces two laws that we were basically already
following anyway:

1) A MovHint's child should never be changed except if all other uses of that child

are also replaced. Specifically, this prohibits insertion of conversion nodes at
MovHints.


2) Anytime any child is replaced with something else, and all other uses aren't also

replaced, we must insert a Phantom use of the original child.

This is a slight compile-time regression but has no effect on code-gen. It unlocks a
bunch of optimization opportunities so I think it's worth it.

  • bytecode/CodeBlock.cpp:

(JSC::CodeBlock::dumpAssumingJITType):

  • bytecode/CodeBlock.h:

(JSC::CodeBlock::instructionCount):

  • dfg/DFGAbstractInterpreterInlines.h:

(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):

  • dfg/DFGArgumentsSimplificationPhase.cpp:

(JSC::DFG::ArgumentsSimplificationPhase::run):

  • dfg/DFGArrayifySlowPathGenerator.h:

(JSC::DFG::ArrayifySlowPathGenerator::ArrayifySlowPathGenerator):

  • dfg/DFGBackwardsPropagationPhase.cpp:

(JSC::DFG::BackwardsPropagationPhase::propagate):

  • dfg/DFGByteCodeParser.cpp:

(JSC::DFG::ByteCodeParser::setDirect):
(JSC::DFG::ByteCodeParser::DelayedSetLocal::DelayedSetLocal):
(JSC::DFG::ByteCodeParser::DelayedSetLocal::execute):
(JSC::DFG::ByteCodeParser::handleInlining):
(JSC::DFG::ByteCodeParser::parseBlock):

  • dfg/DFGCSEPhase.cpp:

(JSC::DFG::CSEPhase::eliminate):

  • dfg/DFGClobberize.h:

(JSC::DFG::clobberize):

  • dfg/DFGCommon.h:
  • dfg/DFGConstantFoldingPhase.cpp:

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

  • dfg/DFGDCEPhase.cpp:

(JSC::DFG::DCEPhase::run):
(JSC::DFG::DCEPhase::fixupBlock):
(JSC::DFG::DCEPhase::cleanVariables):

  • dfg/DFGFixupPhase.cpp:

(JSC::DFG::FixupPhase::fixupNode):
(JSC::DFG::FixupPhase::fixEdge):
(JSC::DFG::FixupPhase::injectInt32ToDoubleNode):

  • dfg/DFGLICMPhase.cpp:

(JSC::DFG::LICMPhase::run):
(JSC::DFG::LICMPhase::attemptHoist):

  • dfg/DFGMinifiedNode.cpp:

(JSC::DFG::MinifiedNode::fromNode):

  • dfg/DFGMinifiedNode.h:

(JSC::DFG::belongsInMinifiedGraph):
(JSC::DFG::MinifiedNode::constantNumber):
(JSC::DFG::MinifiedNode::weakConstant):

  • dfg/DFGNode.cpp:

(JSC::DFG::Node::hasVariableAccessData):

  • dfg/DFGNode.h:

(JSC::DFG::Node::convertToPhantom):
(JSC::DFG::Node::convertToPhantomUnchecked):
(JSC::DFG::Node::convertToIdentity):
(JSC::DFG::Node::containsMovHint):
(JSC::DFG::Node::hasUnlinkedLocal):
(JSC::DFG::Node::willHaveCodeGenOrOSR):

  • dfg/DFGNodeFlags.cpp:

(JSC::DFG::dumpNodeFlags):

  • dfg/DFGNodeFlags.h:
  • dfg/DFGNodeType.h:
  • dfg/DFGOSRAvailabilityAnalysisPhase.cpp:

(JSC::DFG::OSRAvailabilityAnalysisPhase::run):

  • dfg/DFGOSREntrypointCreationPhase.cpp:

(JSC::DFG::OSREntrypointCreationPhase::run):

  • dfg/DFGOSRExit.cpp:
  • dfg/DFGOSRExit.h:
  • dfg/DFGOSRExitBase.cpp:
  • dfg/DFGOSRExitBase.h:

(JSC::DFG::OSRExitBase::considerAddingAsFrequentExitSite):

  • dfg/DFGPredictionPropagationPhase.cpp:

(JSC::DFG::PredictionPropagationPhase::propagate):
(JSC::DFG::PredictionPropagationPhase::doDoubleVoting):

  • dfg/DFGSSAConversionPhase.cpp:

(JSC::DFG::SSAConversionPhase::run):

  • dfg/DFGSafeToExecute.h:

(JSC::DFG::safeToExecute):

  • dfg/DFGSpeculativeJIT.cpp:

(JSC::DFG::SpeculativeJIT::speculationCheck):
(JSC::DFG::SpeculativeJIT::emitInvalidationPoint):
(JSC::DFG::SpeculativeJIT::typeCheck):
(JSC::DFG::SpeculativeJIT::compileMovHint):
(JSC::DFG::SpeculativeJIT::compileCurrentBlock):
(JSC::DFG::SpeculativeJIT::checkArgumentTypes):
(JSC::DFG::SpeculativeJIT::compileInt32ToDouble):

  • dfg/DFGSpeculativeJIT.h:

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

  • dfg/DFGSpeculativeJIT32_64.cpp:

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

  • dfg/DFGSpeculativeJIT64.cpp:

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

  • dfg/DFGTypeCheckHoistingPhase.cpp:

(JSC::DFG::TypeCheckHoistingPhase::run):
(JSC::DFG::TypeCheckHoistingPhase::identifyRedundantStructureChecks):
(JSC::DFG::TypeCheckHoistingPhase::identifyRedundantArrayChecks):

  • dfg/DFGValidate.cpp:

(JSC::DFG::Validate::validateCPS):

  • dfg/DFGVariableAccessData.h:

(JSC::DFG::VariableAccessData::VariableAccessData):

  • dfg/DFGVariableEventStream.cpp:

(JSC::DFG::VariableEventStream::reconstruct):

  • ftl/FTLCapabilities.cpp:

(JSC::FTL::canCompile):

  • ftl/FTLLowerDFGToLLVM.cpp:

(JSC::FTL::LowerDFGToLLVM::compileNode):
(JSC::FTL::LowerDFGToLLVM::compileGetArgument):
(JSC::FTL::LowerDFGToLLVM::compileSetLocal):
(JSC::FTL::LowerDFGToLLVM::compileMovHint):
(JSC::FTL::LowerDFGToLLVM::compileZombieHint):
(JSC::FTL::LowerDFGToLLVM::compileInt32ToDouble):
(JSC::FTL::LowerDFGToLLVM::speculate):
(JSC::FTL::LowerDFGToLLVM::typeCheck):
(JSC::FTL::LowerDFGToLLVM::appendTypeCheck):
(JSC::FTL::LowerDFGToLLVM::appendOSRExit):
(JSC::FTL::LowerDFGToLLVM::emitOSRExitCall):

  • ftl/FTLOSRExit.cpp:
  • ftl/FTLOSRExit.h:
  • tests/stress/dead-int32-to-double.js: Added.

(foo):

  • tests/stress/dead-uint32-to-number.js: Added.

(foo):

Location:
trunk/Source/JavaScriptCore
Files:
2 added
43 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r161077 r161126  
     12013-12-28  Filip Pizlo  <fpizlo@apple.com>
     2
     3        Get rid of DFG forward exiting
     4        https://bugs.webkit.org/show_bug.cgi?id=125531
     5
     6        Reviewed by Oliver Hunt.
     7       
     8        This finally gets rid of forward exiting. Forward exiting was always a fragile concept
     9        since it involved the compiler trying to figure out how to "roll forward" the
     10        execution from some DFG node to the next bytecode index. It was always easy to find
     11        counterexamples where it broke, and it has always served as an obstacle to adding
     12        compiler improvements - the latest being http://webkit.org/b/125523, which tried to
     13        make DCE work for more things.
     14       
     15        This change finishes the work of removing forward exiting. A lot of forward exiting
     16        was already removed in some other bugs, but SetLocal still did forward exits. SetLocal
     17        is in many ways the hardest to remove, since the forward exiting of SetLocal also
     18        implied that any conversion nodes inserted before the SetLocal would then also be
     19        marked as forward-exiting. Hence SetLocal's forward-exiting made a bunch of other
     20        things also forward-exiting, and this was always a source of weirdo bugs.
     21       
     22        SetLocal must be able to exit in case it performs a hoisted type speculation. Nodes
     23        inserted just before SetLocal must also be able to exit - for example type check
     24        hoisting may insert a CheckStructure, or fixup phase may insert something like
     25        Int32ToDouble. But if any of those nodes tried to backward exit, then this could lead
     26        to the reexecution of a side-effecting operation, for example:
     27       
     28            a: Call(...)
     29            b: SetLocal(@a, r1)
     30       
     31        For a long time it seemed like SetLocal *had* to exit forward because of this. But
     32        this change side-steps the problem by changing the ByteCodeParser to always emit a
     33        kind of "two-phase commit" for stores to local variables. Now when the ByteCodeParser
     34        wishes to store to a local, it first emits a MovHint and then enqueues a SetLocal.
     35        The SetLocal isn't actually emitted until the beginning of the next bytecode
     36        instruction (which the exception of op_enter and op_ret, which emit theirs immediately
     37        since it's always safe to reexecute those bytecode instructions and since deferring
     38        SetLocals would be weird there - op_enter has many SetLocals and op_ret is a set
     39        followed by a jump in case of inlining, so we'd have to emit the SetLocal "after" the
     40        jump and that would be awkward). This means that the above IR snippet would look
     41        something like:
     42       
     43            a: Call(..., bc#42)
     44            b: MovHint(@a, r1, bc#42)
     45            c: SetLocal(@a, r1, bc#47)
     46       
     47        Where the SetLocal exits "backwards" but appears at the beginning of the next bytecode
     48        instruction. This means that by the time we get to that SetLocal, the OSR exit
     49        analysis already knows that r1 is associated with @a, and it means that the SetLocal
     50        or anything hoisted above it can exit backwards as normal.
     51       
     52        This change also means that the "forward rewiring" can be killed. Previously, we might
     53        have inserted a conversion node on SetLocal and then the SetLocal died (i.e. turned
     54        into a MovHint) and the conversion node either died completely or had its lifetime
     55        truncated to be less than the actual value's bytecode lifetime. This no longer happens
     56        since conversion nodes are only inserted at SetLocals.
     57       
     58        More precisely, this change introduces two laws that we were basically already
     59        following anyway:
     60       
     61        1) A MovHint's child should never be changed except if all other uses of that child
     62           are also replaced. Specifically, this prohibits insertion of conversion nodes at
     63           MovHints.
     64       
     65        2) Anytime any child is replaced with something else, and all other uses aren't also
     66           replaced, we must insert a Phantom use of the original child.
     67
     68        This is a slight compile-time regression but has no effect on code-gen. It unlocks a
     69        bunch of optimization opportunities so I think it's worth it.
     70
     71        * bytecode/CodeBlock.cpp:
     72        (JSC::CodeBlock::dumpAssumingJITType):
     73        * bytecode/CodeBlock.h:
     74        (JSC::CodeBlock::instructionCount):
     75        * dfg/DFGAbstractInterpreterInlines.h:
     76        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
     77        * dfg/DFGArgumentsSimplificationPhase.cpp:
     78        (JSC::DFG::ArgumentsSimplificationPhase::run):
     79        * dfg/DFGArrayifySlowPathGenerator.h:
     80        (JSC::DFG::ArrayifySlowPathGenerator::ArrayifySlowPathGenerator):
     81        * dfg/DFGBackwardsPropagationPhase.cpp:
     82        (JSC::DFG::BackwardsPropagationPhase::propagate):
     83        * dfg/DFGByteCodeParser.cpp:
     84        (JSC::DFG::ByteCodeParser::setDirect):
     85        (JSC::DFG::ByteCodeParser::DelayedSetLocal::DelayedSetLocal):
     86        (JSC::DFG::ByteCodeParser::DelayedSetLocal::execute):
     87        (JSC::DFG::ByteCodeParser::handleInlining):
     88        (JSC::DFG::ByteCodeParser::parseBlock):
     89        * dfg/DFGCSEPhase.cpp:
     90        (JSC::DFG::CSEPhase::eliminate):
     91        * dfg/DFGClobberize.h:
     92        (JSC::DFG::clobberize):
     93        * dfg/DFGCommon.h:
     94        * dfg/DFGConstantFoldingPhase.cpp:
     95        (JSC::DFG::ConstantFoldingPhase::foldConstants):
     96        * dfg/DFGDCEPhase.cpp:
     97        (JSC::DFG::DCEPhase::run):
     98        (JSC::DFG::DCEPhase::fixupBlock):
     99        (JSC::DFG::DCEPhase::cleanVariables):
     100        * dfg/DFGFixupPhase.cpp:
     101        (JSC::DFG::FixupPhase::fixupNode):
     102        (JSC::DFG::FixupPhase::fixEdge):
     103        (JSC::DFG::FixupPhase::injectInt32ToDoubleNode):
     104        * dfg/DFGLICMPhase.cpp:
     105        (JSC::DFG::LICMPhase::run):
     106        (JSC::DFG::LICMPhase::attemptHoist):
     107        * dfg/DFGMinifiedNode.cpp:
     108        (JSC::DFG::MinifiedNode::fromNode):
     109        * dfg/DFGMinifiedNode.h:
     110        (JSC::DFG::belongsInMinifiedGraph):
     111        (JSC::DFG::MinifiedNode::constantNumber):
     112        (JSC::DFG::MinifiedNode::weakConstant):
     113        * dfg/DFGNode.cpp:
     114        (JSC::DFG::Node::hasVariableAccessData):
     115        * dfg/DFGNode.h:
     116        (JSC::DFG::Node::convertToPhantom):
     117        (JSC::DFG::Node::convertToPhantomUnchecked):
     118        (JSC::DFG::Node::convertToIdentity):
     119        (JSC::DFG::Node::containsMovHint):
     120        (JSC::DFG::Node::hasUnlinkedLocal):
     121        (JSC::DFG::Node::willHaveCodeGenOrOSR):
     122        * dfg/DFGNodeFlags.cpp:
     123        (JSC::DFG::dumpNodeFlags):
     124        * dfg/DFGNodeFlags.h:
     125        * dfg/DFGNodeType.h:
     126        * dfg/DFGOSRAvailabilityAnalysisPhase.cpp:
     127        (JSC::DFG::OSRAvailabilityAnalysisPhase::run):
     128        * dfg/DFGOSREntrypointCreationPhase.cpp:
     129        (JSC::DFG::OSREntrypointCreationPhase::run):
     130        * dfg/DFGOSRExit.cpp:
     131        * dfg/DFGOSRExit.h:
     132        * dfg/DFGOSRExitBase.cpp:
     133        * dfg/DFGOSRExitBase.h:
     134        (JSC::DFG::OSRExitBase::considerAddingAsFrequentExitSite):
     135        * dfg/DFGPredictionPropagationPhase.cpp:
     136        (JSC::DFG::PredictionPropagationPhase::propagate):
     137        (JSC::DFG::PredictionPropagationPhase::doDoubleVoting):
     138        * dfg/DFGSSAConversionPhase.cpp:
     139        (JSC::DFG::SSAConversionPhase::run):
     140        * dfg/DFGSafeToExecute.h:
     141        (JSC::DFG::safeToExecute):
     142        * dfg/DFGSpeculativeJIT.cpp:
     143        (JSC::DFG::SpeculativeJIT::speculationCheck):
     144        (JSC::DFG::SpeculativeJIT::emitInvalidationPoint):
     145        (JSC::DFG::SpeculativeJIT::typeCheck):
     146        (JSC::DFG::SpeculativeJIT::compileMovHint):
     147        (JSC::DFG::SpeculativeJIT::compileCurrentBlock):
     148        (JSC::DFG::SpeculativeJIT::checkArgumentTypes):
     149        (JSC::DFG::SpeculativeJIT::compileInt32ToDouble):
     150        * dfg/DFGSpeculativeJIT.h:
     151        (JSC::DFG::SpeculativeJIT::detectPeepHoleBranch):
     152        (JSC::DFG::SpeculativeJIT::needsTypeCheck):
     153        * dfg/DFGSpeculativeJIT32_64.cpp:
     154        (JSC::DFG::SpeculativeJIT::compile):
     155        * dfg/DFGSpeculativeJIT64.cpp:
     156        (JSC::DFG::SpeculativeJIT::compile):
     157        * dfg/DFGTypeCheckHoistingPhase.cpp:
     158        (JSC::DFG::TypeCheckHoistingPhase::run):
     159        (JSC::DFG::TypeCheckHoistingPhase::identifyRedundantStructureChecks):
     160        (JSC::DFG::TypeCheckHoistingPhase::identifyRedundantArrayChecks):
     161        * dfg/DFGValidate.cpp:
     162        (JSC::DFG::Validate::validateCPS):
     163        * dfg/DFGVariableAccessData.h:
     164        (JSC::DFG::VariableAccessData::VariableAccessData):
     165        * dfg/DFGVariableEventStream.cpp:
     166        (JSC::DFG::VariableEventStream::reconstruct):
     167        * ftl/FTLCapabilities.cpp:
     168        (JSC::FTL::canCompile):
     169        * ftl/FTLLowerDFGToLLVM.cpp:
     170        (JSC::FTL::LowerDFGToLLVM::compileNode):
     171        (JSC::FTL::LowerDFGToLLVM::compileGetArgument):
     172        (JSC::FTL::LowerDFGToLLVM::compileSetLocal):
     173        (JSC::FTL::LowerDFGToLLVM::compileMovHint):
     174        (JSC::FTL::LowerDFGToLLVM::compileZombieHint):
     175        (JSC::FTL::LowerDFGToLLVM::compileInt32ToDouble):
     176        (JSC::FTL::LowerDFGToLLVM::speculate):
     177        (JSC::FTL::LowerDFGToLLVM::typeCheck):
     178        (JSC::FTL::LowerDFGToLLVM::appendTypeCheck):
     179        (JSC::FTL::LowerDFGToLLVM::appendOSRExit):
     180        (JSC::FTL::LowerDFGToLLVM::emitOSRExitCall):
     181        * ftl/FTLOSRExit.cpp:
     182        * ftl/FTLOSRExit.h:
     183        * tests/stress/dead-int32-to-double.js: Added.
     184        (foo):
     185        * tests/stress/dead-uint32-to-number.js: Added.
     186        (foo):
     187
    11882013-12-25  Commit Queue  <commit-queue@webkit.org>
    2189
  • trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp

    r160587 r161126  
    136136    if (codeType() == FunctionCode)
    137137        out.print(specializationKind());
     138    out.print(", ", instructionCount());
    138139    if (this->jitType() == JITCode::BaselineJIT && m_shouldAlwaysBeInlined)
    139140        out.print(" (SABI)");
  • trunk/Source/JavaScriptCore/bytecode/CodeBlock.h

    r159943 r161126  
    245245    bool usesOpcode(OpcodeID);
    246246
    247     unsigned instructionCount() { return m_instructions.size(); }
     247    unsigned instructionCount() const { return m_instructions.size(); }
    248248
    249249    int argumentIndexAfterCapture(size_t argument);
  • trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h

    r160796 r161126  
    196196    }
    197197       
    198     case MovHint:
    199     case MovHintAndCheck: {
    200         // Don't need to do anything. A MovHint is effectively a promise that the SetLocal
    201         // was dead.
     198    case MovHint: {
     199        // Don't need to do anything. A MovHint only informs us about what would have happened
     200        // in bytecode, but this code is just concerned with what is actually happening during
     201        // DFG execution.
    202202        break;
    203203    }
     
    15841584           
    15851585    case Phantom:
     1586    case Check:
    15861587    case CountExecution:
    15871588    case CheckTierUpInLoop:
  • trunk/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp

    r161072 r161126  
    334334                    break;
    335335                   
     336                case MovHint:
     337                    // We don't care about MovHints at all, since they represent what happens
     338                    // in bytecode. We rematerialize arguments objects on OSR exit anyway.
     339                    break;
     340                   
    336341                default:
    337342                    observeBadArgumentsUses(node);
  • trunk/Source/JavaScriptCore/dfg/DFGArrayifySlowPathGenerator.h

    r157044 r161126  
    6464            case Array::Double:
    6565            case Array::Contiguous:
    66                 m_badPropertyJump = jit->backwardSpeculationCheck(Uncountable, JSValueRegs(), 0);
     66                m_badPropertyJump = jit->speculationCheck(Uncountable, JSValueRegs(), 0);
    6767                break;
    6868            default:
     
    7070            }
    7171        }
    72         m_badIndexingTypeJump = jit->backwardSpeculationCheck(BadIndexingType, JSValueSource::unboxedCell(m_baseGPR), 0);
     72        m_badIndexingTypeJump = jit->speculationCheck(BadIndexingType, JSValueSource::unboxedCell(m_baseGPR), 0);
    7373    }
    7474   
  • trunk/Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp

    r158384 r161126  
    188188        }
    189189           
     190        case MovHint:
     191        case Check:
     192            break;
     193           
    190194        case BitAnd:
    191195        case BitOr:
  • trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp

    r160587 r161126  
    233233    }
    234234   
    235     enum SetMode { NormalSet, SetOnEntry };
     235    enum SetMode { NormalSet, ImmediateSet };
    236236    Node* setDirect(VirtualRegister operand, Node* value, SetMode setMode = NormalSet)
    237237    {
    238         // Is this an argument?
    239         if (operand.isArgument())
    240             return setArgument(operand, value, setMode);
    241 
    242         // Must be a local.
    243         return setLocal(operand, value, setMode);
     238        addToGraph(MovHint, OpInfo(operand.offset()), value);
     239       
     240        DelayedSetLocal delayed = DelayedSetLocal(operand, value);
     241       
     242        if (setMode == NormalSet) {
     243            m_setLocalQueue.append(delayed);
     244            return 0;
     245        }
     246       
     247        return delayed.execute(this, setMode);
    244248    }
    245249
     
    11221126   
    11231127    InlineStackEntry* m_inlineStackTop;
     1128   
     1129    struct DelayedSetLocal {
     1130        VirtualRegister m_operand;
     1131        Node* m_value;
     1132       
     1133        DelayedSetLocal() { }
     1134        DelayedSetLocal(VirtualRegister operand, Node* value)
     1135            : m_operand(operand)
     1136            , m_value(value)
     1137        {
     1138        }
     1139       
     1140        Node* execute(ByteCodeParser* parser, SetMode setMode = NormalSet)
     1141        {
     1142            if (m_operand.isArgument())
     1143                return parser->setArgument(m_operand, m_value, setMode);
     1144            return parser->setLocal(m_operand, m_value, setMode);
     1145        }
     1146    };
     1147   
     1148    Vector<DelayedSetLocal, 2> m_setLocalQueue;
    11241149
    11251150    // Have we built operand maps? We initialize them lazily, and only when doing
     
    13261351    if (callLinkStatus.isClosureCall()) {
    13271352        VariableAccessData* calleeVariable =
    1328             set(VirtualRegister(JSStack::Callee), callTargetNode)->variableAccessData();
     1353            set(VirtualRegister(JSStack::Callee), callTargetNode, ImmediateSet)->variableAccessData();
    13291354        VariableAccessData* scopeVariable =
    1330             set(VirtualRegister(JSStack::ScopeChain), addToGraph(GetScope, callTargetNode))->variableAccessData();
     1355            set(VirtualRegister(JSStack::ScopeChain), addToGraph(GetScope, callTargetNode), ImmediateSet)->variableAccessData();
    13311356       
    13321357        calleeVariable->mergeShouldNeverUnbox(true);
     
    18731898
    18741899    while (true) {
     1900        for (unsigned i = 0; i < m_setLocalQueue.size(); ++i)
     1901            m_setLocalQueue[i].execute(this);
     1902        m_setLocalQueue.resize(0);
     1903       
    18751904        // Don't extend over jump destinations.
    18761905        if (m_currentIndex == limit) {
     
    19041933            // Initialize all locals to undefined.
    19051934            for (int i = 0; i < m_inlineStackTop->m_codeBlock->m_numVars; ++i)
    1906                 set(virtualRegisterForLocal(i), constantUndefined(), SetOnEntry);
     1935                set(virtualRegisterForLocal(i), constantUndefined(), ImmediateSet);
    19071936            NEXT_OPCODE(op_enter);
    19081937           
     
    29092938            if (inlineCallFrame()) {
    29102939                ASSERT(m_inlineStackTop->m_returnValue.isValid());
    2911                 setDirect(m_inlineStackTop->m_returnValue, get(VirtualRegister(currentInstruction[1].u.operand)));
     2940                setDirect(m_inlineStackTop->m_returnValue, get(VirtualRegister(currentInstruction[1].u.operand)), ImmediateSet);
    29122941                m_inlineStackTop->m_didReturn = true;
    29132942                if (m_inlineStackTop->m_unlinkedBlocks.isEmpty()) {
  • trunk/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp

    r160407 r161126  
    10521052            return;
    10531053        ASSERT(node->mustGenerate());
    1054         node->setOpAndDefaultNonExitFlags(phantomType);
     1054        node->setOpAndDefaultFlags(phantomType);
    10551055        if (phantomType == Phantom)
    10561056            eliminateIrrelevantPhantomChildren(node);
  • trunk/Source/JavaScriptCore/dfg/DFGClobberize.h

    r160796 r161126  
    130130    case UInt32ToNumber:
    131131    case DoubleAsInt32:
    132         return;
    133        
    134     case MovHintAndCheck:
     132    case Check:
     133        return;
     134       
    135135    case MovHint:
    136136    case ZombieHint:
  • trunk/Source/JavaScriptCore/dfg/DFGCommon.h

    r159886 r161126  
    182182
    183183enum OperandSpeculationMode { AutomaticOperandSpeculation, ManualOperandSpeculation };
    184 
    185 enum SpeculationDirection { ForwardSpeculation, BackwardSpeculation };
    186184
    187185enum ProofStatus { NeedsCheck, IsProved };
  • trunk/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp

    r160796 r161126  
    111111                    AdjacencyList children = node->children;
    112112                    children.removeEdge(0);
    113                     if (!!children.child1()) {
    114                         Node phantom(Phantom, node->codeOrigin, children);
    115                         if (node->flags() & NodeExitsForward)
    116                             phantom.mergeFlags(NodeExitsForward);
    117                         m_insertionSet.insertNode(indexInBlock, SpecNone, phantom);
    118                     }
     113                    if (!!children.child1())
     114                        m_insertionSet.insertNode(indexInBlock, SpecNone, Phantom, node->codeOrigin, children);
    119115                    node->children.setChild2(Edge());
    120116                    node->children.setChild3(Edge());
  • trunk/Source/JavaScriptCore/dfg/DFGDCEPhase.cpp

    r156047 r161126  
    114114                fixupBlock(depthFirst[i]);
    115115        } else {
     116            RELEASE_ASSERT(m_graph.m_form == ThreadedCPS);
     117           
    116118            for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex)
    117119                fixupBlock(m_graph.block(blockIndex));
     120           
     121            cleanVariables(m_graph.m_arguments);
    118122        }
    119123       
     
    153157        if (!block)
    154158            return;
     159       
     160        switch (m_graph.m_form) {
     161        case SSA:
     162            break;
     163           
     164        case ThreadedCPS: {
     165            // Clean up variable links for the block. We need to do this before the actual DCE
     166            // because we need to see GetLocals, so we can bypass them in situations where the
     167            // vars-at-tail point to a GetLocal, the GetLocal is dead, but the Phi it points
     168            // to is alive.
     169           
     170            for (unsigned phiIndex = 0; phiIndex < block->phis.size(); ++phiIndex) {
     171                if (!block->phis[phiIndex]->shouldGenerate()) {
     172                    // FIXME: We could actually free nodes here. Except that it probably
     173                    // doesn't matter, since we don't add any nodes after this phase.
     174                    // https://bugs.webkit.org/show_bug.cgi?id=126239
     175                    block->phis[phiIndex--] = block->phis.last();
     176                    block->phis.removeLast();
     177                }
     178            }
     179           
     180            cleanVariables(block->variablesAtHead);
     181            cleanVariables(block->variablesAtTail);
     182            break;
     183        }
     184           
     185        default:
     186            RELEASE_ASSERT_NOT_REACHED();
     187            return;
     188        }
    155189
    156190        for (unsigned indexInBlock = block->size(); indexInBlock--;) {
     
    160194               
    161195            switch (node->op()) {
    162             case SetLocal:
    163196            case MovHint: {
    164                 ASSERT((node->op() == SetLocal) == (m_graph.m_form == ThreadedCPS));
    165                 if (node->child1().willNotHaveCheck()) {
    166                     // Consider the possibility that UInt32ToNumber is dead but its
    167                     // child isn't; if so then we should MovHint the child.
    168                     if (!node->child1()->shouldGenerate()
    169                         && permitsOSRBackwardRewiring(node->child1()->op()))
    170                         node->child1() = node->child1()->child1();
    171 
    172                     if (!node->child1()->shouldGenerate()) {
    173                         node->setOpAndDefaultFlags(ZombieHint);
    174                         node->child1() = Edge();
    175                         break;
    176                     }
    177                     node->setOpAndDefaultFlags(MovHint);
     197                ASSERT(node->child1().useKind() == UntypedUse);
     198                if (!node->child1()->shouldGenerate()) {
     199                    node->setOpAndDefaultFlags(ZombieHint);
     200                    node->child1() = Edge();
    178201                    break;
    179202                }
    180                 node->setOpAndDefaultFlags(MovHintAndCheck);
    181                 node->setRefCount(1);
     203                node->setOpAndDefaultFlags(MovHint);
    182204                break;
    183205            }
    184                    
    185             case GetLocal:
    186             case SetArgument: {
    187                 if (m_graph.m_form == ThreadedCPS) {
    188                     // Leave them as not shouldGenerate.
    189                     break;
    190                 }
    191             }
    192 
     206               
     207            case ZombieHint: {
     208                // Currently we assume that DCE runs only once.
     209                RELEASE_ASSERT_NOT_REACHED();
     210                break;
     211            }
     212           
    193213            default: {
    194214                if (node->flags() & NodeHasVarArgs) {
     
    229249    }
    230250   
     251    template<typename VariablesVectorType>
     252    void cleanVariables(VariablesVectorType& variables)
     253    {
     254        for (unsigned i = variables.size(); i--;) {
     255            Node* node = variables[i];
     256            if (!node)
     257                continue;
     258            if (node->op() != Phantom && node->shouldGenerate())
     259                continue;
     260            if (node->op() == GetLocal) {
     261                node = node->child1().node();
     262                ASSERT(node->op() == Phi);
     263                if (node->shouldGenerate()) {
     264                    variables[i] = node;
     265                    continue;
     266                }
     267            }
     268            variables[i] = 0;
     269        }
     270    }
     271   
    231272    Vector<Node*, 128> m_worklist;
    232273    InsertionSet m_insertionSet;
  • trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp

    r160796 r161126  
    887887
    888888        case Phantom:
    889         case Identity: {
     889        case Identity:
     890        case Check: {
    890891            switch (node->child1().useKind()) {
    891892            case NumberUse:
     
    908909        case GetTypedArrayByteOffset:
    909910        case LastNodeType:
    910         case MovHint:
    911         case MovHintAndCheck:
    912         case ZombieHint:
    913911        case CheckTierUpInLoop:
    914912        case CheckTierUpAtReturn:
     
    952950            }
    953951            break;
    954 
     952           
    955953#if !ASSERT_DISABLED
    956954        // Have these no-op cases here to ensure that nobody forgets to add handlers for new opcodes.
     
    10061004        case FunctionReentryWatchpoint:
    10071005        case TypedArrayWatchpoint:
     1006        case MovHint:
     1007        case ZombieHint:
    10081008            break;
    10091009#else
     
    10131013        }
    10141014       
    1015         DFG_NODE_DO_TO_CHILDREN(m_graph, node, observeUntypedEdge);
     1015        if (!node->containsMovHint())
     1016            DFG_NODE_DO_TO_CHILDREN(m_graph, node, observeUntypedEdge);
    10161017    }
    10171018   
     
    14791480        if (isDouble(useKind)) {
    14801481            if (edge->shouldSpeculateInt32ForArithmetic()) {
    1481                 injectInt32ToDoubleNode(edge, useKind, m_currentNode->speculationDirection());
     1482                injectInt32ToDoubleNode(edge, useKind);
    14821483                return;
    14831484            }
     
    14921493                    m_indexInBlock, SpecInt52AsDouble, Int52ToDouble,
    14931494                    m_currentNode->codeOrigin, Edge(edge.node(), NumberUse));
    1494                 result->setSpeculationDirection(m_currentNode->speculationDirection());
    14951495                edge = Edge(result, useKind);
    14961496                return;
     
    15461546                m_indexInBlock, SpecInt52, Int52ToValue,
    15471547                m_currentNode->codeOrigin, Edge(edge.node(), UntypedUse));
    1548             result->setSpeculationDirection(m_currentNode->speculationDirection());
    15491548            edge = Edge(result, useKind);
    15501549            return;
     
    15881587    }
    15891588   
    1590     void injectInt32ToDoubleNode(Edge& edge, UseKind useKind = NumberUse, SpeculationDirection direction = BackwardSpeculation)
     1589    void injectInt32ToDoubleNode(Edge& edge, UseKind useKind = NumberUse)
    15911590    {
    15921591        Node* result = m_insertionSet.insertNode(
    15931592            m_indexInBlock, SpecInt52AsDouble, Int32ToDouble,
    15941593            m_currentNode->codeOrigin, Edge(edge.node(), NumberUse));
    1595         if (direction == ForwardSpeculation)
    1596             result->mergeFlags(NodeExitsForward);
    15971594       
    15981595        edge = Edge(result, useKind);
  • trunk/Source/JavaScriptCore/dfg/DFGLICMPhase.cpp

    r155281 r161126  
    129129        //
    130130        // Also, we need to remember to:
    131         // - Clear NodeExitsForward for any nodes we hoisted.
    132131        // - Update the state-at-tail with the node we hoisted, so future hoist candidates
    133132        //   know about any type checks we hoisted.
     
    231230        data.preHeader->insertBeforeLast(node);
    232231        node->misc.owner = data.preHeader;
    233         NodeFlags didExitForward = node->flags() & NodeExitsForward;
    234         node->clearFlags(NodeExitsForward);
    235232        node->codeOriginForExitTarget = data.preHeader->last()->codeOriginForExitTarget;
    236233       
     
    257254       
    258255        nodeRef = m_graph.addNode(SpecNone, Phantom, node->codeOrigin, node->children);
    259         nodeRef->mergeFlags(didExitForward);
    260256       
    261257        return true;
  • trunk/Source/JavaScriptCore/dfg/DFGMinifiedNode.cpp

    r141069 r161126  
    3939    result.m_id = MinifiedID(node);
    4040    result.m_op = node->op();
    41     if (hasChild(node->op()))
    42         result.m_childOrInfo = MinifiedID(node->child1().node()).m_id;
    43     else if (hasConstantNumber(node->op()))
    44         result.m_childOrInfo = node->constantNumber();
     41    if (hasConstantNumber(node->op()))
     42        result.m_info = node->constantNumber();
    4543    else if (hasWeakConstant(node->op()))
    46         result.m_childOrInfo = bitwise_cast<uintptr_t>(node->weakConstant());
     44        result.m_info = bitwise_cast<uintptr_t>(node->weakConstant());
    4745    else {
    4846        ASSERT(node->op() == PhantomArguments);
    49         result.m_childOrInfo = 0;
     47        result.m_info = 0;
    5048    }
    5149    return result;
  • trunk/Source/JavaScriptCore/dfg/DFGMinifiedNode.h

    r156047 r161126  
    4444    case JSConstant:
    4545    case WeakJSConstant:
    46     case ValueToInt32:
    47     case Int32ToDouble:
    48     case UInt32ToNumber:
    49     case DoubleAsInt32:
    5046    case PhantomArguments:
    51     case Int52ToValue:
    52     case Int52ToDouble:
    5347        return true;
    5448    default:
    55         ASSERT(!permitsOSRBackwardRewiring(type) && !permitsOSRForwardRewiring(type));
    5649        return false;
    5750    }
     
    6760    NodeType op() const { return m_op; }
    6861   
    69     bool hasChild1() const { return hasChild(m_op); }
    70    
    71     MinifiedID child1() const
    72     {
    73         ASSERT(hasChild(m_op));
    74         return MinifiedID::fromBits(m_childOrInfo);
    75     }
    76    
    7762    bool hasConstant() const { return hasConstantNumber() || hasWeakConstant(); }
    7863   
     
    8267    {
    8368        ASSERT(hasConstantNumber(m_op));
    84         return m_childOrInfo;
     69        return m_info;
    8570    }
    8671   
     
    9075    {
    9176        ASSERT(hasWeakConstant(m_op));
    92         return bitwise_cast<JSCell*>(m_childOrInfo);
     77        return bitwise_cast<JSCell*>(m_info);
    9378    }
    9479   
     
    10085   
    10186private:
    102     static bool hasChild(NodeType type)
    103     {
    104         switch (type) {
    105         case ValueToInt32:
    106         case Int32ToDouble:
    107         case UInt32ToNumber:
    108         case DoubleAsInt32:
    109         case Int52ToDouble:
    110         case Int52ToValue:
    111             return true;
    112         default:
    113             return false;
    114         }
    115     }
    11687    static bool hasConstantNumber(NodeType type)
    11788    {
     
    12495   
    12596    MinifiedID m_id;
    126     uintptr_t m_childOrInfo; // Nodes in the minified graph have only one child each.
     97    uintptr_t m_info;
    12798    NodeType m_op;
    12899};
  • trunk/Source/JavaScriptCore/dfg/DFGNode.cpp

    r153274 r161126  
    4747    case GetArgument:
    4848    case SetLocal:
    49     case MovHint:
    50     case MovHintAndCheck:
    51     case ZombieHint:
    5249    case SetArgument:
    5350    case Flush:
  • trunk/Source/JavaScriptCore/dfg/DFGNode.h

    r160796 r161126  
    275275    }
    276276   
    277     SpeculationDirection speculationDirection()
    278     {
    279         if (flags() & NodeExitsForward)
    280             return ForwardSpeculation;
    281         return BackwardSpeculation;
    282     }
    283    
    284     void setSpeculationDirection(SpeculationDirection direction)
    285     {
    286         switch (direction) {
    287         case ForwardSpeculation:
    288             mergeFlags(NodeExitsForward);
    289             return;
    290         case BackwardSpeculation:
    291             clearFlags(NodeExitsForward);
    292             return;
    293         }
    294         RELEASE_ASSERT_NOT_REACHED();
    295     }
    296    
    297277    void setOpAndDefaultFlags(NodeType op)
    298278    {
     
    301281    }
    302282
    303     void setOpAndDefaultNonExitFlags(NodeType op)
    304     {
    305         ASSERT(!(m_flags & NodeHasVarArgs));
    306         setOpAndDefaultNonExitFlagsUnchecked(op);
    307     }
    308 
    309     void setOpAndDefaultNonExitFlagsUnchecked(NodeType op)
    310     {
    311         m_op = op;
    312         m_flags = (defaultFlags(op) & ~NodeExitsForward) | (m_flags & NodeExitsForward);
    313     }
    314 
    315283    void convertToPhantom()
    316284    {
    317         setOpAndDefaultNonExitFlags(Phantom);
     285        setOpAndDefaultFlags(Phantom);
    318286    }
    319287
    320288    void convertToPhantomUnchecked()
    321289    {
    322         setOpAndDefaultNonExitFlagsUnchecked(Phantom);
     290        setOpAndDefaultFlags(Phantom);
    323291    }
    324292
     
    327295        RELEASE_ASSERT(child1());
    328296        RELEASE_ASSERT(!child2());
    329         setOpAndDefaultNonExitFlags(Identity);
     297        setOpAndDefaultFlags(Identity);
    330298    }
    331299
     
    532500    {
    533501        switch (op()) {
    534         case SetLocal:
    535502        case MovHint:
    536         case MovHintAndCheck:
    537503        case ZombieHint:
    538504            return true;
     
    568534        case GetLocalUnlinked:
    569535        case ExtractOSREntryLocal:
     536        case MovHint:
     537        case ZombieHint:
    570538            return true;
    571539        default:
     
    11911159        case MovHint:
    11921160        case ZombieHint:
    1193         case MovHintAndCheck:
    1194         case Int32ToDouble:
    1195         case ValueToInt32:
    1196         case UInt32ToNumber:
    1197         case DoubleAsInt32:
    11981161        case PhantomArguments:
    11991162            return true;
  • trunk/Source/JavaScriptCore/dfg/DFGNodeFlags.cpp

    r156984 r161126  
    9797        out.print(comma, "CanExit");
    9898   
    99     if (flags & NodeExitsForward)
    100         out.print(comma, "NodeExitsForward");
    101    
    10299    CString string = out.toCString();
    103100    if (!string.length())
  • trunk/Source/JavaScriptCore/dfg/DFGNodeFlags.h

    r159545 r161126  
    6969#define NodeRelevantToOSR                0x4000
    7070
    71 #define NodeExitsForward                 0x8000
    72 
    73 #define NodeIsStaticConstant            0x10000 // Used only by the parser, to determine if a constant arose statically and hence could be folded at parse-time.
     71#define NodeIsStaticConstant             0x8000 // Used only by the parser, to determine if a constant arose statically and hence could be folded at parse-time.
    7472
    7573typedef uint32_t NodeFlags;
  • trunk/Source/JavaScriptCore/dfg/DFGNodeType.h

    r160796 r161126  
    5858    /* VariableAccessData, and thus will share predictions. */\
    5959    macro(GetLocal, NodeResultJS) \
    60     macro(SetLocal, NodeExitsForward) \
    61     macro(MovHintAndCheck, NodeMustGenerate | NodeExitsForward) \
     60    macro(SetLocal, 0) \
    6261    macro(MovHint, NodeDoesNotExit) \
    6362    macro(ZombieHint, NodeDoesNotExit) \
    6463    macro(GetArgument, NodeResultJS | NodeMustGenerate) \
    6564    macro(Phantom, NodeMustGenerate) \
     65    macro(Check, 0) /* Used if we want just a type check but not liveness. DCE eithers kills this or converts it to Phantom. */\
    6666    macro(Upsilon, NodeDoesNotExit | NodeRelevantToOSR) \
    6767    macro(Phi, NodeDoesNotExit | NodeRelevantToOSR) \
     
    319319}
    320320
    321 inline bool permitsOSRBackwardRewiring(NodeType op)
    322 {
    323     switch (op) {
    324     case Identity:
    325         RELEASE_ASSERT_NOT_REACHED();
    326         return true;
    327     case UInt32ToNumber:
    328     case Int52ToValue:
    329     case Int52ToDouble:
    330         // These are the only node where we do:
    331         //
    332         //     b: UInt32ToNumber(@a)
    333         //     c: SetLocal(@b)
    334         //
    335         // and then also have some uses of @a without Phantom'ing @b.
    336         return true;
    337     default:
    338         return false;
    339     }
    340 }
    341 
    342 // Returns the priority with which we should select the given node for forward
    343 // rewiring. Higher is better. Zero means that the node is not useful for rewiring.
    344 // By convention, we use 100 to mean that the node is totally equivalent to its
    345 // input with no information loss.
    346 inline unsigned forwardRewiringSelectionScore(NodeType op)
    347 {
    348     switch (op) {
    349     case Identity:
    350         // We shouldn't see these by the time we get to OSR even though it clearly
    351         // is a perfect identity function.
    352         RELEASE_ASSERT_NOT_REACHED();
    353         return 100;
    354        
    355     case DoubleAsInt32:
    356         // This speculates that the incoming double is convertible to an int32. So
    357         // its result is totally equivalent.
    358         return 100;
    359        
    360     case Int32ToDouble:
    361         // This converts an int32 to a double, but that loses a bit of information.
    362         // OTOH it's still an equivalent number.
    363         return 75;
    364        
    365     case UInt32ToNumber:
    366         // It's completely fine to use this for OSR exit, since the uint32 isn't
    367         // actually representable in bytecode.
    368         return 100;
    369 
    370     case ValueToInt32:
    371         // This loses information. Only use it if there are no better alternatives.
    372         return 25;
    373        
    374     case Int52ToValue:
    375         // Loses no information. It just boxes the value, which is what OSR wants
    376         // to do anyway.
    377         return 100;
    378        
    379     case Int52ToDouble:
    380         // This is like Int32ToDouble; we can use it because it gives a semantically
    381         // equivalent value but that value may be an int32 in a double, so we'd
    382         // rather not if we can avoid it.
    383         return 75;
    384        
    385     default:
    386         return 0;
    387     }
    388 }
    389 
    390 inline bool permitsOSRForwardRewiring(NodeType op)
    391 {
    392     return forwardRewiringSelectionScore(op) > 0;
    393 }
    394 
    395321} } // namespace JSC::DFG
    396322
  • trunk/Source/JavaScriptCore/dfg/DFGOSRAvailabilityAnalysisPhase.cpp

    r159394 r161126  
    104104                    }
    105105                       
    106                     case MovHint:
    107                     case MovHintAndCheck: {
    108                         VariableAccessData* variable = node->variableAccessData();
    109                         availability.operand(variable->local()) =
     106                    case MovHint: {
     107                        availability.operand(node->unlinkedLocal()) =
    110108                            Availability(node->child1().node());
    111109                        break;
     
    113111                       
    114112                    case ZombieHint: {
    115                         VariableAccessData* variable = node->variableAccessData();
    116                         availability.operand(variable->local()) = Availability::unavailable();
     113                        availability.operand(node->unlinkedLocal()) =
     114                            Availability::unavailable();
    117115                        break;
    118116                    }
  • trunk/Source/JavaScriptCore/dfg/DFGOSREntrypointCreationPhase.cpp

    r156677 r161126  
    105105                OpInfo(variable->local().offset()));
    106106           
    107             // Create a MovHint. We can't use MovHint's directly at this stage of
    108             // compilation, so we cook one up by creating a new VariableAccessData
    109             // that isn't unified with any of the others. This ensures that this
    110             // SetLocal will turn into a MovHint and will not have any type checks.
    111             m_graph.m_variableAccessData.append(
    112                 VariableAccessData(variable->local(), variable->isCaptured()));
    113             VariableAccessData* newVariable = &m_graph.m_variableAccessData.last();
    114             Node* setLocal = newRoot->appendNode(
    115                 m_graph, SpecNone, SetLocal, codeOrigin, OpInfo(newVariable),
     107            newRoot->appendNode(
     108                m_graph, SpecNone, MovHint, codeOrigin, OpInfo(variable->local().offset()),
    116109                Edge(locals[local]));
    117             setLocal->setSpeculationDirection(BackwardSpeculation);
    118110        }
    119111        for (int local = 0; local < baseline->m_numCalleeRegisters; ++local) {
     
    123115            VariableAccessData* variable = previousHead->variableAccessData();
    124116            Node* node = locals[local];
    125             Node* setLocal = newRoot->appendNode(
     117            newRoot->appendNode(
    126118                m_graph, SpecNone, SetLocal, codeOrigin, OpInfo(variable), Edge(node));
    127             setLocal->setSpeculationDirection(BackwardSpeculation);
    128119        }
    129120       
  • trunk/Source/JavaScriptCore/dfg/DFGOSRExit.cpp

    r159091 r161126  
    6969}
    7070
    71 void OSRExit::convertToForward(BasicBlock* block, Node* currentNode, unsigned nodeIndex, const ValueRecovery& valueRecovery)
    72 {
    73     Node* node;
    74     Node* lastMovHint;
    75     if (!doSearchForForwardConversion(block, currentNode, nodeIndex, !!valueRecovery, node, lastMovHint))
    76         return;
    77 
    78     ASSERT(node->codeOrigin != currentNode->codeOrigin);
    79    
    80     m_codeOrigin = node->codeOrigin;
    81    
    82     if (!valueRecovery)
    83         return;
    84    
    85     ASSERT(lastMovHint);
    86     ASSERT(lastMovHint->child1() == currentNode);
    87     m_valueRecoveryOverride = adoptRef(
    88         new ValueRecoveryOverride(lastMovHint->local(), valueRecovery));
    89 }
    90 
    9171} } // namespace JSC::DFG
    9272
  • trunk/Source/JavaScriptCore/dfg/DFGOSRExit.h

    r159091 r161126  
    102102    CodeLocationJump codeLocationForRepatch(CodeBlock*) const;
    103103    void correctJump(LinkBuffer&);
    104    
    105     void convertToForward(BasicBlock*, Node*, unsigned nodeIndex, const ValueRecovery&);
    106104
    107105    unsigned m_streamIndex;
  • trunk/Source/JavaScriptCore/dfg/DFGOSRExitBase.cpp

    r158459 r161126  
    4747}
    4848
    49 bool OSRExitBase::doSearchForForwardConversion(
    50     BasicBlock* block, Node* currentNode, unsigned nodeIndex, bool hasValueRecovery,
    51     Node*& node, Node*& lastMovHint)
    52 {
    53     // Check that either the current node is a SetLocal, or the preceding node was a
    54     // SetLocal with the same code origin, or that we've provided a valueRecovery.
    55     if (!ASSERT_DISABLED
    56         && !hasValueRecovery
    57         && !currentNode->containsMovHint()) {
    58         Node* setLocal = block->at(nodeIndex - 1);
    59         ASSERT_UNUSED(setLocal, setLocal->containsMovHint());
    60         ASSERT_UNUSED(setLocal, setLocal->codeOriginForExitTarget == currentNode->codeOriginForExitTarget);
    61     }
    62    
    63     // Find the first node for the next bytecode instruction. Also track the last mov hint
    64     // on this node.
    65     unsigned indexInBlock = nodeIndex + 1;
    66     node = 0;
    67     lastMovHint = 0;
    68     for (;;) {
    69         if (indexInBlock == block->size()) {
    70             // This is an inline return. Give up and do a backwards speculation. This is safe
    71             // because an inline return has its own bytecode index and it's always safe to
    72             // reexecute that bytecode.
    73             ASSERT(node->op() == Jump);
    74             return false;
    75         }
    76         node = block->at(indexInBlock);
    77         if (node->containsMovHint() && node->child1() == currentNode)
    78             lastMovHint = node;
    79         if (node->codeOriginForExitTarget != currentNode->codeOriginForExitTarget)
    80             break;
    81         indexInBlock++;
    82     }
    83    
    84     ASSERT(node->codeOriginForExitTarget != currentNode->codeOriginForExitTarget);
    85     return true;
    86 }
    87 
    8849} } // namespace JSC::DFG
    8950
  • trunk/Source/JavaScriptCore/dfg/DFGOSRExitBase.h

    r160348 r161126  
    6565        return considerAddingAsFrequentExitSiteSlow(profiledCodeBlock);
    6666    }
    67    
    68     // Returns true if the forward conversion is really needed.
    69     bool doSearchForForwardConversion(
    70         BasicBlock*, Node* currentNode, unsigned nodeIndex, bool hasValueRecovery,
    71         Node*& nextBCNode, Node*& lastMovHint);
    7267
    7368private:
  • trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp

    r160796 r161126  
    505505        case Arrayify:
    506506        case ArrayifyToStructure:
    507         case MovHint:
    508         case MovHintAndCheck:
    509         case ZombieHint:
    510507        case CheckTierUpInLoop:
    511508        case CheckTierUpAtReturn:
     
    578575        case AllocationProfileWatchpoint:
    579576        case Phantom:
     577        case Check:
    580578        case PutGlobalVar:
    581579        case CheckWatchdogTimer:
     
    586584        case TypedArrayWatchpoint:
    587585        case ConstantStoragePointer:
     586        case MovHint:
     587        case ZombieHint:
    588588            break;
    589589           
     
    745745        }
    746746           
     747        case MovHint:
     748            // Ignore these since they have no effect on in-DFG execution.
     749            break;
     750           
    747751        default:
    748752            m_graph.voteChildren(node, VoteValue);
  • trunk/Source/JavaScriptCore/dfg/DFGSSAConversionPhase.cpp

    r160613 r161126  
    187187                        } else {
    188188                            m_insertionSet.insertNode(
    189                                 0, SpecNone, MovHint, CodeOrigin(), OpInfo(variable),
    190                                 Edge(node));
     189                                0, SpecNone, MovHint, CodeOrigin(),
     190                                OpInfo(variable->local().offset()), Edge(node));
    191191                        }
    192192                    }
     
    270270        //   to the node specified by variablesAtHead.
    271271        // - SetLocal gets NodeMustGenerate if it's flushed, or turns into a
    272         //   MovHint otherwise.
     272        //   Check otherwise.
    273273        // - Flush loses its children but remains, because we want to know when a
    274274        //   flushed SetLocal's value is no longer needed. This also makes it simpler
     
    309309                        node->mergeFlags(NodeMustGenerate);
    310310                    else
    311                         node->setOpAndDefaultFlags(MovHint);
     311                        node->setOpAndDefaultFlags(Check);
    312312                    node->misc.replacement = node->child1().node(); // Only for Upsilons.
    313313                    break;
  • trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h

    r160796 r161126  
    119119    case GetLocal:
    120120    case SetLocal:
    121     case MovHintAndCheck:
    122121    case MovHint:
    123122    case ZombieHint:
     
    251250    case CheckInBounds:
    252251    case ConstantStoragePointer:
     252    case Check:
    253253        return true;
    254254       
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp

    r161072 r161126  
    107107}
    108108
    109 void SpeculativeJIT::backwardSpeculationCheck(ExitKind kind, JSValueSource jsValueSource, Node* node, MacroAssembler::Jump jumpToFail)
     109void SpeculativeJIT::speculationCheck(ExitKind kind, JSValueSource jsValueSource, Node* node, MacroAssembler::Jump jumpToFail)
    110110{
    111111    if (!m_compileOkay)
     
    116116}
    117117
    118 void SpeculativeJIT::backwardSpeculationCheck(ExitKind kind, JSValueSource jsValueSource, Node* node, const MacroAssembler::JumpList& jumpsToFail)
     118void SpeculativeJIT::speculationCheck(ExitKind kind, JSValueSource jsValueSource, Node* node, const MacroAssembler::JumpList& jumpsToFail)
    119119{
    120120    if (!m_compileOkay)
     
    125125}
    126126
    127 void SpeculativeJIT::speculationCheck(ExitKind kind, JSValueSource jsValueSource, Node* node, MacroAssembler::Jump jumpToFail)
    128 {
    129     if (!m_compileOkay)
    130         return;
    131     backwardSpeculationCheck(kind, jsValueSource, node, jumpToFail);
    132     if (m_speculationDirection == ForwardSpeculation)
    133         convertLastOSRExitToForward();
    134 }
    135 
    136 void SpeculativeJIT::speculationCheck(ExitKind kind, JSValueSource jsValueSource, Edge nodeUse, MacroAssembler::Jump jumpToFail)
    137 {
    138     ASSERT(m_isCheckingArgumentTypes || m_canExit);
    139     speculationCheck(kind, jsValueSource, nodeUse.node(), jumpToFail);
    140 }
    141 
    142 OSRExitJumpPlaceholder SpeculativeJIT::backwardSpeculationCheck(ExitKind kind, JSValueSource jsValueSource, Node* node)
     127OSRExitJumpPlaceholder SpeculativeJIT::speculationCheck(ExitKind kind, JSValueSource jsValueSource, Node* node)
    143128{
    144129    if (!m_compileOkay)
     
    151136}
    152137
    153 OSRExitJumpPlaceholder SpeculativeJIT::backwardSpeculationCheck(ExitKind kind, JSValueSource jsValueSource, Edge nodeUse)
     138OSRExitJumpPlaceholder SpeculativeJIT::speculationCheck(ExitKind kind, JSValueSource jsValueSource, Edge nodeUse)
    154139{
    155140    ASSERT(m_isCheckingArgumentTypes || m_canExit);
    156     return backwardSpeculationCheck(kind, jsValueSource, nodeUse.node());
    157 }
    158 
    159 void SpeculativeJIT::speculationCheck(ExitKind kind, JSValueSource jsValueSource, Node* node, const MacroAssembler::JumpList& jumpsToFail)
    160 {
    161     if (!m_compileOkay)
    162         return;
    163     backwardSpeculationCheck(kind, jsValueSource, node, jumpsToFail);
    164     if (m_speculationDirection == ForwardSpeculation)
    165         convertLastOSRExitToForward();
     141    return speculationCheck(kind, jsValueSource, nodeUse.node());
     142}
     143
     144void SpeculativeJIT::speculationCheck(ExitKind kind, JSValueSource jsValueSource, Edge nodeUse, MacroAssembler::Jump jumpToFail)
     145{
     146    ASSERT(m_isCheckingArgumentTypes || m_canExit);
     147    speculationCheck(kind, jsValueSource, nodeUse.node(), jumpToFail);
    166148}
    167149
     
    172154}
    173155
    174 void SpeculativeJIT::backwardSpeculationCheck(ExitKind kind, JSValueSource jsValueSource, Node* node, MacroAssembler::Jump jumpToFail, const SpeculationRecovery& recovery)
     156void SpeculativeJIT::speculationCheck(ExitKind kind, JSValueSource jsValueSource, Node* node, MacroAssembler::Jump jumpToFail, const SpeculationRecovery& recovery)
    175157{
    176158    if (!m_compileOkay)
     
    182164}
    183165
    184 void SpeculativeJIT::backwardSpeculationCheck(ExitKind kind, JSValueSource jsValueSource, Edge nodeUse, MacroAssembler::Jump jumpToFail, const SpeculationRecovery& recovery)
     166void SpeculativeJIT::speculationCheck(ExitKind kind, JSValueSource jsValueSource, Edge nodeUse, MacroAssembler::Jump jumpToFail, const SpeculationRecovery& recovery)
    185167{
    186168    ASSERT(m_isCheckingArgumentTypes || m_canExit);
    187     backwardSpeculationCheck(kind, jsValueSource, nodeUse.node(), jumpToFail, recovery);
    188 }
    189 
    190 void SpeculativeJIT::speculationCheck(ExitKind kind, JSValueSource jsValueSource, Node* node, MacroAssembler::Jump jumpToFail, const SpeculationRecovery& recovery)
     169    speculationCheck(kind, jsValueSource, nodeUse.node(), jumpToFail, recovery);
     170}
     171
     172void SpeculativeJIT::emitInvalidationPoint(Node* node)
    191173{
    192174    if (!m_compileOkay)
    193175        return;
    194     backwardSpeculationCheck(kind, jsValueSource, node, jumpToFail, recovery);
    195     if (m_speculationDirection == ForwardSpeculation)
    196         convertLastOSRExitToForward();
    197 }
    198 
    199 void SpeculativeJIT::speculationCheck(ExitKind kind, JSValueSource jsValueSource, Edge edge, MacroAssembler::Jump jumpToFail, const SpeculationRecovery& recovery)
    200 {
    201     speculationCheck(kind, jsValueSource, edge.node(), jumpToFail, recovery);
    202 }
    203 
    204 void SpeculativeJIT::emitInvalidationPoint(Node* node)
    205 {
    206     if (!m_compileOkay)
    207         return;
    208176    ASSERT(m_canExit);
    209     ASSERT(m_speculationDirection == BackwardSpeculation);
    210177    OSRExitCompilationInfo& info = m_jit.appendExitInfo(JITCompiler::JumpList());
    211178    m_jit.jitCode()->appendOSRExit(OSRExit(
     
    218185}
    219186
    220 void SpeculativeJIT::convertLastOSRExitToForward(const ValueRecovery& valueRecovery)
    221 {
    222     m_jit.jitCode()->lastOSRExit().convertToForward(
    223         m_block, m_currentNode, m_indexInBlock, valueRecovery);
    224 }
    225 
    226 void SpeculativeJIT::forwardSpeculationCheck(ExitKind kind, JSValueSource jsValueSource, Node* node, MacroAssembler::Jump jumpToFail, const ValueRecovery& valueRecovery)
    227 {
    228     ASSERT(m_isCheckingArgumentTypes || m_canExit);
    229     backwardSpeculationCheck(kind, jsValueSource, node, jumpToFail);
    230     convertLastOSRExitToForward(valueRecovery);
    231 }
    232 
    233 void SpeculativeJIT::forwardSpeculationCheck(ExitKind kind, JSValueSource jsValueSource, Node* node, const MacroAssembler::JumpList& jumpsToFail, const ValueRecovery& valueRecovery)
    234 {
    235     ASSERT(m_isCheckingArgumentTypes || m_canExit);
    236     backwardSpeculationCheck(kind, jsValueSource, node, jumpsToFail);
    237     convertLastOSRExitToForward(valueRecovery);
    238 }
    239 
    240187void SpeculativeJIT::terminateSpeculativeExecution(ExitKind kind, JSValueRegs jsValueRegs, Node* node)
    241188{
     
    253200}
    254201
    255 void SpeculativeJIT::backwardTypeCheck(JSValueSource source, Edge edge, SpeculatedType typesPassedThrough, MacroAssembler::Jump jumpToFail)
     202void SpeculativeJIT::typeCheck(JSValueSource source, Edge edge, SpeculatedType typesPassedThrough, MacroAssembler::Jump jumpToFail)
    256203{
    257204    ASSERT(needsTypeCheck(edge, typesPassedThrough));
    258205    m_interpreter.filter(edge, typesPassedThrough);
    259     backwardSpeculationCheck(BadType, source, edge.node(), jumpToFail);
    260 }
    261 
    262 void SpeculativeJIT::typeCheck(JSValueSource source, Edge edge, SpeculatedType typesPassedThrough, MacroAssembler::Jump jumpToFail)
    263 {
    264     backwardTypeCheck(source, edge, typesPassedThrough, jumpToFail);
    265     if (m_speculationDirection == ForwardSpeculation)
    266         convertLastOSRExitToForward();
    267 }
    268 
    269 void SpeculativeJIT::forwardTypeCheck(JSValueSource source, Edge edge, SpeculatedType typesPassedThrough, MacroAssembler::Jump jumpToFail, const ValueRecovery& valueRecovery)
    270 {
    271     backwardTypeCheck(source, edge, typesPassedThrough, jumpToFail);
    272     convertLastOSRExitToForward(valueRecovery);
     206    speculationCheck(BadType, source, edge.node(), jumpToFail);
    273207}
    274208
     
    13811315    noticeOSRBirth(child);
    13821316   
    1383     m_stream->appendAndLog(VariableEvent::movHint(MinifiedID(child), node->local()));
    1384 }
    1385 
    1386 void SpeculativeJIT::compileMovHintAndCheck(Node* node)
    1387 {
    1388     compileMovHint(node);
    1389     speculate(node, node->child1());
    1390     noResult(node);
     1317    m_stream->appendAndLog(VariableEvent::movHint(MinifiedID(child), node->unlinkedLocal()));
    13911318}
    13921319
     
    14831410               
    14841411            case ZombieHint: {
    1485                 recordSetLocal(DataFormatDead);
     1412                recordSetLocal(m_currentNode->unlinkedLocal(), VirtualRegister(), DataFormatDead);
    14861413                break;
    14871414            }
     
    15021429            }
    15031430           
    1504             m_speculationDirection = (m_currentNode->flags() & NodeExitsForward) ? ForwardSpeculation : BackwardSpeculation;
    1505            
    15061431            compile(m_currentNode);
    15071432
     
    15411466    ASSERT(!m_currentNode);
    15421467    m_isCheckingArgumentTypes = true;
    1543     m_speculationDirection = BackwardSpeculation;
    15441468    m_codeOriginForExitTarget = CodeOrigin(0);
    15451469    m_codeOriginForExitProfile = CodeOrigin(0);
     
    15471471    for (int i = 0; i < m_jit.codeBlock()->numParameters(); ++i) {
    15481472        Node* node = m_jit.graph().m_arguments[i];
    1549         ASSERT(node->op() == SetArgument);
    1550         if (!node->shouldGenerate()) {
     1473        if (!node) {
    15511474            // The argument is dead. We don't do any checks for such arguments.
    15521475            continue;
    15531476        }
    15541477       
     1478        ASSERT(node->op() == SetArgument);
     1479        ASSERT(node->shouldGenerate());
     1480
    15551481        VariableAccessData* variableAccessData = node->variableAccessData();
    15561482        FlushFormat format = variableAccessData->flushFormat();
     
    21682094   
    21692095    if (needsTypeCheck(node->child1(), SpecFullNumber)) {
    2170         if (node->flags() & NodeExitsForward) {
    2171             forwardTypeCheck(
    2172                 JSValueRegs(op1GPR), node->child1(), SpecFullNumber,
    2173                 m_jit.branchTest64(MacroAssembler::Zero, op1GPR, GPRInfo::tagTypeNumberRegister),
    2174                 ValueRecovery::inGPR(op1GPR, DataFormatJS));
    2175         } else {
    2176             backwardTypeCheck(
    2177                 JSValueRegs(op1GPR), node->child1(), SpecFullNumber,
    2178                 m_jit.branchTest64(MacroAssembler::Zero, op1GPR, GPRInfo::tagTypeNumberRegister));
    2179         }
     2096        typeCheck(
     2097            JSValueRegs(op1GPR), node->child1(), SpecFullNumber,
     2098            m_jit.branchTest64(MacroAssembler::Zero, op1GPR, GPRInfo::tagTypeNumberRegister));
    21802099    }
    21812100   
     
    21992118   
    22002119    if (needsTypeCheck(node->child1(), SpecFullNumber)) {
    2201         if (node->flags() & NodeExitsForward) {
    2202             forwardTypeCheck(
    2203                 JSValueRegs(op1TagGPR, op1PayloadGPR), node->child1(), SpecFullNumber,
    2204                 m_jit.branch32(MacroAssembler::AboveOrEqual, op1TagGPR, TrustedImm32(JSValue::LowestTag)),
    2205                 ValueRecovery::inPair(op1TagGPR, op1PayloadGPR));
    2206         } else {
    2207             backwardTypeCheck(
    2208                 JSValueRegs(op1TagGPR, op1PayloadGPR), node->child1(), SpecFullNumber,
    2209                 m_jit.branch32(MacroAssembler::AboveOrEqual, op1TagGPR, TrustedImm32(JSValue::LowestTag)));
    2210         }
     2120        typeCheck(
     2121            JSValueRegs(op1TagGPR, op1PayloadGPR), node->child1(), SpecFullNumber,
     2122            m_jit.branch32(MacroAssembler::AboveOrEqual, op1TagGPR, TrustedImm32(JSValue::LowestTag)));
    22112123    }
    22122124   
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h

    r160919 r161126  
    698698        for (unsigned index = m_indexInBlock + 1; index < m_block->size() - 1; ++index) {
    699699            Node* node = m_block->at(index);
    700             if (node->shouldGenerate())
    701                 return UINT_MAX;
     700            if (!node->shouldGenerate())
     701                continue;
     702            // Check if it's a Phantom that can be safely ignored.
     703            if (node->op() == Phantom && !node->child1())
     704                continue;
     705            return UINT_MAX;
    702706        }
    703707
     
    21442148#endif
    21452149   
    2146     // Add a backward speculation check.
    2147     void backwardSpeculationCheck(ExitKind, JSValueSource, Node*, MacroAssembler::Jump jumpToFail);
    2148     void backwardSpeculationCheck(ExitKind, JSValueSource, Node*, const MacroAssembler::JumpList& jumpsToFail);
    2149 
    2150     // Add a speculation check without additional recovery.
     2150    // Add a speculation check.
    21512151    void speculationCheck(ExitKind, JSValueSource, Node*, MacroAssembler::Jump jumpToFail);
     2152    void speculationCheck(ExitKind, JSValueSource, Node*, const MacroAssembler::JumpList& jumpsToFail);
     2153
     2154    // Add a speculation check without additional recovery, and with a promise to supply a jump later.
     2155    OSRExitJumpPlaceholder speculationCheck(ExitKind, JSValueSource, Node*);
     2156    OSRExitJumpPlaceholder speculationCheck(ExitKind, JSValueSource, Edge);
    21522157    void speculationCheck(ExitKind, JSValueSource, Edge, MacroAssembler::Jump jumpToFail);
    2153     // Add a speculation check without additional recovery, and with a promise to supply a jump later.
    2154     OSRExitJumpPlaceholder backwardSpeculationCheck(ExitKind, JSValueSource, Node*);
    2155     OSRExitJumpPlaceholder backwardSpeculationCheck(ExitKind, JSValueSource, Edge);
    2156     // Add a set of speculation checks without additional recovery.
    2157     void speculationCheck(ExitKind, JSValueSource, Node*, const MacroAssembler::JumpList& jumpsToFail);
    21582158    void speculationCheck(ExitKind, JSValueSource, Edge, const MacroAssembler::JumpList& jumpsToFail);
    21592159    // Add a speculation check with additional recovery.
    2160     void backwardSpeculationCheck(ExitKind, JSValueSource, Node*, MacroAssembler::Jump jumpToFail, const SpeculationRecovery&);
    2161     void backwardSpeculationCheck(ExitKind, JSValueSource, Edge, MacroAssembler::Jump jumpToFail, const SpeculationRecovery&);
    2162    
    2163     void emitInvalidationPoint(Node*);
    2164    
    2165     // It is generally a good idea to not use this directly.
    2166     void convertLastOSRExitToForward(const ValueRecovery& = ValueRecovery());
    2167    
    2168     // Note: not specifying the valueRecovery argument (leaving it as ValueRecovery()) implies
    2169     // that you've ensured that there exists a MovHint prior to your use of forwardSpeculationCheck().
    2170     void forwardSpeculationCheck(ExitKind, JSValueSource, Node*, MacroAssembler::Jump jumpToFail, const ValueRecovery& = ValueRecovery());
    2171     void forwardSpeculationCheck(ExitKind, JSValueSource, Node*, const MacroAssembler::JumpList& jumpsToFail, const ValueRecovery& = ValueRecovery());
    21722160    void speculationCheck(ExitKind, JSValueSource, Node*, MacroAssembler::Jump jumpToFail, const SpeculationRecovery&);
    21732161    void speculationCheck(ExitKind, JSValueSource, Edge, MacroAssembler::Jump jumpToFail, const SpeculationRecovery&);
     2162   
     2163    void emitInvalidationPoint(Node*);
     2164   
    21742165    // Called when we statically determine that a speculation will fail.
    21752166    void terminateSpeculativeExecution(ExitKind, JSValueRegs, Node*);
     
    21782169    // Helpers for performing type checks on an edge stored in the given registers.
    21792170    bool needsTypeCheck(Edge edge, SpeculatedType typesPassedThrough) { return m_interpreter.needsTypeCheck(edge, typesPassedThrough); }
    2180     void backwardTypeCheck(JSValueSource, Edge, SpeculatedType typesPassedThrough, MacroAssembler::Jump jumpToFail);
    21812171    void typeCheck(JSValueSource, Edge, SpeculatedType typesPassedThrough, MacroAssembler::Jump jumpToFail);
    2182     void forwardTypeCheck(JSValueSource, Edge, SpeculatedType typesPassedThrough, MacroAssembler::Jump jumpToFail, const ValueRecovery&);
    21832172
    21842173    void speculateInt32(Edge);
     
    22532242    BasicBlock* m_block;
    22542243    Node* m_currentNode;
    2255     SpeculationDirection m_speculationDirection;
    22562244    bool m_canExit;
    22572245    unsigned m_indexInBlock;
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp

    r161072 r161126  
    19221922    }
    19231923
    1924     case MovHintAndCheck: {
    1925         compileMovHintAndCheck(node);
    1926         break;
    1927     }
    1928        
    19291924    case MovHint:
    1930     case ZombieHint: {
     1925    case ZombieHint:
     1926    case Check: {
    19311927        RELEASE_ASSERT_NOT_REACHED();
    19321928        break;
     
    19341930
    19351931    case SetLocal: {
    1936         // SetLocal doubles as a hint as to where a node will be stored and
    1937         // as a speculation point. So before we speculate make sure that we
    1938         // know where the child of this node needs to go in the virtual
    1939         // stack.
    1940         compileMovHint(node);
    1941        
    19421932        switch (node->variableAccessData()->flushFormat()) {
    19431933        case FlushedDouble: {
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp

    r161072 r161126  
    22372237    }
    22382238       
    2239     case MovHintAndCheck: {
    2240         compileMovHintAndCheck(node);
    2241         break;
    2242     }
    2243        
    22442239    case MovHint:
    2245     case ZombieHint: {
     2240    case ZombieHint:
     2241    case Check: {
    22462242        RELEASE_ASSERT_NOT_REACHED();
    22472243        break;
     
    22492245
    22502246    case SetLocal: {
    2251         // SetLocal doubles as a hint as to where a node will be stored and
    2252         // as a speculation point. So before we speculate make sure that we
    2253         // know where the child of this node needs to go in the virtual
    2254         // stack.
    2255         compileMovHint(node);
    2256        
    22572247        switch (node->variableAccessData()->flushFormat()) {
    22582248        case FlushedDouble: {
     
    23052295            m_jit.store64(value.gpr(), JITCompiler::addressFor(node->machineLocal()));
    23062296            noResult(node);
    2307            
    23082297            recordSetLocal(DataFormatJS);
    23092298            break;
  • trunk/Source/JavaScriptCore/dfg/DFGTypeCheckHoistingPhase.cpp

    r157656 r161126  
    164164                        break;
    165165
    166                     // First insert a dead SetLocal to tell OSR that the child's value should
    167                     // be dropped into this bytecode variable if the CheckStructure decides
    168                     // to exit.
    169                    
    170166                    CodeOrigin codeOrigin = node->codeOrigin;
    171167                    Edge child1 = node->child1();
    172168                   
    173                     insertionSet.insertNode(
    174                         indexInBlock, SpecNone, SetLocal, codeOrigin, OpInfo(variable), child1);
    175 
    176                     // Use NodeExitsForward to indicate that we should exit to the next
    177                     // bytecode instruction rather than reexecuting the current one.
    178                     Node* newNode = 0;
    179169                    if (iter->value.m_structure) {
    180                         newNode = insertionSet.insertNode(
     170                        insertionSet.insertNode(
    181171                            indexInBlock, SpecNone, CheckStructure, codeOrigin,
    182172                            OpInfo(m_graph.addStructureSet(iter->value.m_structure)),
     
    184174                    } else if (iter->value.m_arrayModeIsValid) {
    185175                        ASSERT(iter->value.m_arrayModeHoistingOkay);
    186                         newNode = insertionSet.insertNode(
     176                        insertionSet.insertNode(
    187177                            indexInBlock, SpecNone, CheckArray, codeOrigin,
    188178                            OpInfo(iter->value.m_arrayMode.asWord()),
     
    190180                    } else
    191181                        RELEASE_ASSERT_NOT_REACHED();
    192                     newNode->mergeFlags(NodeExitsForward);
    193182                    changed = true;
    194183                    break;
     
    229218                case CheckStructure:
    230219                case StructureTransitionWatchpoint: {
    231                     // We currently rely on the fact that we're the only ones who would
    232                     // insert these nodes with NodeExitsForward.
    233                     RELEASE_ASSERT(!(node->flags() & NodeExitsForward));
    234220                    Node* child = node->child1().node();
    235221                    if (child->op() != GetLocal)
     
    258244                case GetTypedArrayByteOffset:
    259245                case Phantom:
     246                case MovHint:
    260247                    // Don't count these uses.
    261248                    break;
     
    330317                switch (node->op()) {
    331318                case CheckArray: {
    332                     // We currently rely on the fact that we're the only ones who would
    333                     // insert these nodes with NodeExitsForward.
    334                     RELEASE_ASSERT(!(node->flags() & NodeExitsForward));
    335319                    Node* child = node->child1().node();
    336320                    if (child->op() != GetLocal)
     
    358342                case GetIndexedPropertyStorage:
    359343                case Phantom:
     344                case MovHint:
    360345                    // Don't count these uses.
    361346                    break;
  • trunk/Source/JavaScriptCore/dfg/DFGValidate.cpp

    r160348 r161126  
    246246                        || edge->op() == SetArgument
    247247                        || edge->op() == Flush
    248                         || edge->op() == Phi
    249                         || edge->op() == ZombieHint
    250                         || edge->op() == MovHint
    251                         || edge->op() == MovHintAndCheck);
     248                        || edge->op() == Phi);
    252249                   
    253250                    if (phisInThisBlock.contains(edge.node()))
     
    258255                            (node, edge),
    259256                            edge->op() == SetLocal
    260                             || edge->op() == ZombieHint
    261                             || edge->op() == MovHint
    262                             || edge->op() == MovHintAndCheck
    263257                            || edge->op() == SetArgument
    264258                            || edge->op() == Flush);
     
    293287                            (local, block->predecessors[k], prevNode),
    294288                            prevNode->op() == SetLocal
    295                             || prevNode->op() == MovHint
    296                             || prevNode->op() == MovHintAndCheck
    297                             || prevNode->op() == ZombieHint
    298289                            || prevNode->op() == SetArgument
    299290                            || prevNode->op() == Phi);
  • trunk/Source/JavaScriptCore/dfg/DFGVariableAccessData.h

    r161072 r161126  
    7575        , m_checkArrayHoistingFailed(false)
    7676        , m_isProfitableToUnbox(false)
     77        , m_isLoadedFrom(false)
    7778        , m_doubleFormatState(EmptyDoubleFormatState)
    7879    {
  • trunk/Source/JavaScriptCore/dfg/DFGVariableEventStream.cpp

    r159886 r161126  
    193193        MinifiedGenerationInfo info = generationInfos.get(source.id());
    194194        if (info.format == DataFormatNone) {
    195             // Try to see if there is an alternate node that would contain the value we want.
    196             //
    197             // Backward rewiring refers to:
    198             //
    199             //     a: Something(...)
    200             //     b: Id(@a) // some identity function
    201             //     c: SetLocal(@b)
    202             //
    203             // Where we find @b being dead, but @a is still alive.
    204             //
    205             // Forward rewiring refers to:
    206             //
    207             //     a: Something(...)
    208             //     b: SetLocal(@a)
    209             //     c: Id(@a) // some identity function
    210             //
    211             // Where we find @a being dead, but @b is still alive.
    212            
    213             bool found = false;
    214            
    215             if (node && permitsOSRBackwardRewiring(node->op())) {
    216                 MinifiedID id = node->child1();
    217                 if (tryToSetConstantRecovery(valueRecoveries[i], codeBlock, graph.at(id)))
    218                     continue;
    219                 info = generationInfos.get(id);
    220                 if (info.format != DataFormatNone)
    221                     found = true;
    222             }
    223            
    224             if (!found) {
    225                 MinifiedID bestID;
    226                 unsigned bestScore = 0;
    227                
    228                 HashMap<MinifiedID, MinifiedGenerationInfo>::iterator iter = generationInfos.begin();
    229                 HashMap<MinifiedID, MinifiedGenerationInfo>::iterator end = generationInfos.end();
    230                 for (; iter != end; ++iter) {
    231                     MinifiedID id = iter->key;
    232                     node = graph.at(id);
    233                     if (!node)
    234                         continue;
    235                     if (!node->hasChild1())
    236                         continue;
    237                     if (node->child1() != source.id())
    238                         continue;
    239                     if (iter->value.format == DataFormatNone)
    240                         continue;
    241                     unsigned myScore = forwardRewiringSelectionScore(node->op());
    242                     if (myScore <= bestScore)
    243                         continue;
    244                     bestID = id;
    245                     bestScore = myScore;
    246                 }
    247                
    248                 if (!!bestID) {
    249                     info = generationInfos.get(bestID);
    250                     ASSERT(info.format != DataFormatNone);
    251                     found = true;
    252                 }
    253             }
    254            
    255             if (!found) {
    256                 valueRecoveries[i] = ValueRecovery::constant(jsUndefined());
    257                 continue;
    258             }
     195            valueRecoveries[i] = ValueRecovery::constant(jsUndefined());
     196            continue;
    259197        }
    260198       
  • trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp

    r160347 r161126  
    4343    case GetLocal:
    4444    case SetLocal:
    45     case MovHintAndCheck:
    4645    case MovHint:
    4746    case ZombieHint:
     
    112111    case CheckInBounds:
    113112    case ConstantStoragePointer:
     113    case Check:
    114114        // These are OK.
    115115        break;
  • trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp

    r161072 r161126  
    229229        bool shouldExecuteEffects = m_interpreter.startExecuting(m_node);
    230230       
    231         m_direction = (m_node->flags() & NodeExitsForward) ? ForwardSpeculation : BackwardSpeculation;
    232        
    233231        switch (m_node->op()) {
    234232        case Upsilon:
     
    260258        case ZombieHint:
    261259            compileZombieHint();
    262             break;
    263         case MovHintAndCheck:
    264             compileMovHintAndCheck();
    265260            break;
    266261        case Phantom:
     
    658653        switch (useKindFor(variable->flushFormat())) {
    659654        case Int32Use:
    660             speculateBackward(BadType, jsValueValue(jsValue), m_node, isNotInt32(jsValue));
     655            speculate(BadType, jsValueValue(jsValue), m_node, isNotInt32(jsValue));
    661656            setInt32(unboxInt32(jsValue));
    662657            break;
    663658        case CellUse:
    664             speculateBackward(BadType, jsValueValue(jsValue), m_node, isNotCell(jsValue));
     659            speculate(BadType, jsValueValue(jsValue), m_node, isNotCell(jsValue));
    665660            setJSValue(jsValue);
    666661            break;
    667662        case BooleanUse:
    668             speculateBackward(BadType, jsValueValue(jsValue), m_node, isNotBoolean(jsValue));
     663            speculate(BadType, jsValueValue(jsValue), m_node, isNotBoolean(jsValue));
    669664            setBoolean(unboxBoolean(jsValue));
    670665            break;
     
    702697    void compileSetLocal()
    703698    {
    704         observeMovHint(m_node);
    705        
    706699        VariableAccessData* variable = m_node->variableAccessData();
    707700        switch (variable->flushFormat()) {
     
    754747    void compileMovHint()
    755748    {
    756         observeMovHint(m_node);
     749        ASSERT(m_node->containsMovHint());
     750        ASSERT(m_node->op() != ZombieHint);
     751       
     752        VirtualRegister operand = m_node->unlinkedLocal();
     753        m_availability.operand(operand) = Availability(m_node->child1().node());
    757754    }
    758755   
    759756    void compileZombieHint()
    760757    {
    761         VariableAccessData* data = m_node->variableAccessData();
    762         m_availability.operand(data->local()) = Availability::unavailable();
    763     }
    764    
    765     void compileMovHintAndCheck()
    766     {
    767         observeMovHint(m_node);
    768         speculate(m_node->child1());
     758        m_availability.operand(m_node->unlinkedLocal()) = Availability::unavailable();
    769759    }
    770760   
     
    11781168    void compileInt32ToDouble()
    11791169    {
    1180         if (!m_interpreter.needsTypeCheck(m_node->child1(), SpecFullNumber)
    1181             || m_node->speculationDirection() == BackwardSpeculation) {
    1182             setDouble(lowDouble(m_node->child1()));
    1183             return;
    1184         }
    1185        
    1186         LValue boxedValue = lowJSValue(m_node->child1(), ManualOperandSpeculation);
    1187        
    1188         LBasicBlock intCase = FTL_NEW_BLOCK(m_out, ("Double unboxing int case"));
    1189         LBasicBlock doubleCase = FTL_NEW_BLOCK(m_out, ("Double unboxing double case"));
    1190         LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("Double unboxing continuation"));
    1191        
    1192         m_out.branch(isNotInt32(boxedValue), doubleCase, intCase);
    1193        
    1194         LBasicBlock lastNext = m_out.appendTo(intCase, doubleCase);
    1195        
    1196         ValueFromBlock intToDouble = m_out.anchor(
    1197             m_out.intToDouble(unboxInt32(boxedValue)));
    1198         m_out.jump(continuation);
    1199        
    1200         m_out.appendTo(doubleCase, continuation);
    1201 
    1202         forwardTypeCheck(
    1203             jsValueValue(boxedValue), m_node->child1(), SpecFullNumber,
    1204             isCellOrMisc(boxedValue), jsValueValue(boxedValue));
    1205        
    1206         ValueFromBlock unboxedDouble = m_out.anchor(unboxDouble(boxedValue));
    1207         m_out.jump(continuation);
    1208        
    1209         m_out.appendTo(continuation, lastNext);
    1210        
    1211         LValue result = m_out.phi(m_out.doubleType, intToDouble, unboxedDouble);
    1212        
    1213         setDouble(result);
     1170        setDouble(lowDouble(m_node->child1()));
    12141171    }
    12151172   
     
    31973154    }
    31983155   
    3199     void speculateBackward(
    3200         ExitKind kind, FormattedValue lowValue, Node* highValue, LValue failCondition)
    3201     {
    3202         appendOSRExit(
    3203             kind, lowValue, highValue, failCondition, BackwardSpeculation, FormattedValue());
    3204     }
    3205    
    3206     void speculateForward(
    3207         ExitKind kind, FormattedValue lowValue, Node* highValue, LValue failCondition,
    3208         const FormattedValue& recovery)
    3209     {
    3210         appendOSRExit(
    3211             kind, lowValue, highValue, failCondition, ForwardSpeculation, recovery);
    3212     }
    3213    
    32143156    void speculate(
    32153157        ExitKind kind, FormattedValue lowValue, Node* highValue, LValue failCondition)
    32163158    {
    3217         appendOSRExit(
    3218             kind, lowValue, highValue, failCondition, m_direction, FormattedValue());
     3159        appendOSRExit(kind, lowValue, highValue, failCondition);
    32193160    }
    32203161   
     
    32223163    {
    32233164        speculate(kind, noValue(), 0, m_out.booleanTrue);
    3224     }
    3225    
    3226     void backwardTypeCheck(
    3227         FormattedValue lowValue, Edge highValue, SpeculatedType typesPassedThrough,
    3228         LValue failCondition)
    3229     {
    3230         appendTypeCheck(
    3231             lowValue, highValue, typesPassedThrough, failCondition, BackwardSpeculation,
    3232             FormattedValue());
    3233     }
    3234    
    3235     void forwardTypeCheck(
    3236         FormattedValue lowValue, Edge highValue, SpeculatedType typesPassedThrough,
    3237         LValue failCondition, const FormattedValue& recovery)
    3238     {
    3239         appendTypeCheck(
    3240             lowValue, highValue, typesPassedThrough, failCondition, ForwardSpeculation,
    3241             recovery);
    32423165    }
    32433166   
     
    32463169        LValue failCondition)
    32473170    {
    3248         appendTypeCheck(
    3249             lowValue, highValue, typesPassedThrough, failCondition, m_direction,
    3250             FormattedValue());
     3171        appendTypeCheck(lowValue, highValue, typesPassedThrough, failCondition);
    32513172    }
    32523173   
    32533174    void appendTypeCheck(
    32543175        FormattedValue lowValue, Edge highValue, SpeculatedType typesPassedThrough,
    3255         LValue failCondition, SpeculationDirection direction, FormattedValue recovery)
     3176        LValue failCondition)
    32563177    {
    32573178        if (!m_interpreter.needsTypeCheck(highValue, typesPassedThrough))
    32583179            return;
    32593180        ASSERT(mayHaveTypeCheck(highValue.useKind()));
    3260         appendOSRExit(BadType, lowValue, highValue.node(), failCondition, direction, recovery);
     3181        appendOSRExit(BadType, lowValue, highValue.node(), failCondition);
    32613182        m_interpreter.filter(highValue, typesPassedThrough);
    32623183    }
     
    40934014   
    40944015    void appendOSRExit(
    4095         ExitKind kind, FormattedValue lowValue, Node* highValue, LValue failCondition,
    4096         SpeculationDirection direction, FormattedValue recovery)
     4016        ExitKind kind, FormattedValue lowValue, Node* highValue, LValue failCondition)
    40974017    {
    40984018        if (verboseCompilationEnabled())
     
    41194039        lastNext = m_out.appendTo(failCase, continuation);
    41204040       
    4121         emitOSRExitCall(exit, lowValue, direction, recovery);
     4041        emitOSRExitCall(exit, lowValue);
    41224042       
    41234043        m_out.unreachable();
     
    41264046    }
    41274047   
    4128     void emitOSRExitCall(
    4129         OSRExit& exit, FormattedValue lowValue, SpeculationDirection direction,
    4130         FormattedValue recovery)
     4048    void emitOSRExitCall(OSRExit& exit, FormattedValue lowValue)
    41314049    {
    41324050        ExitArgumentList arguments;
     
    41344052        CodeOrigin codeOrigin = exit.m_codeOrigin;
    41354053       
    4136         if (direction == BackwardSpeculation)
    4137             buildExitArguments(exit, arguments, lowValue, codeOrigin);
    4138         else {
    4139             ASSERT(direction == ForwardSpeculation);
    4140             if (!recovery) {
    4141                 for (unsigned nodeIndex = m_nodeIndex; nodeIndex < m_highBlock->size(); ++nodeIndex) {
    4142                     Node* node = m_highBlock->at(nodeIndex);
    4143                     if (node->codeOriginForExitTarget == codeOrigin)
    4144                         continue;
    4145                     codeOrigin = node->codeOriginForExitTarget;
    4146                     break;
    4147                 }
    4148             }
    4149            
    4150             buildExitArguments(exit, arguments, lowValue, codeOrigin);
    4151             exit.convertToForward(m_highBlock, m_node, m_nodeIndex, recovery, arguments);
    4152         }
     4054        buildExitArguments(exit, arguments, lowValue, codeOrigin);
    41534055       
    41544056        callStackmap(exit, arguments);
     
    43104212    }
    43114213   
    4312     void observeMovHint(Node* node)
    4313     {
    4314         ASSERT(node->containsMovHint());
    4315         ASSERT(node->op() != ZombieHint);
    4316        
    4317         VirtualRegister operand = node->local();
    4318        
    4319         m_availability.operand(operand) = Availability(node->child1().node());
    4320     }
    4321    
    43224214    void setInt32(Node* node, LValue value)
    43234215    {
     
    44904382    unsigned m_nodeIndex;
    44914383    Node* m_node;
    4492     SpeculationDirection m_direction;
    44934384   
    44944385    uint32_t m_stackmapIDs;
  • trunk/Source/JavaScriptCore/ftl/FTLOSRExit.cpp

    r159091 r161126  
    6262}
    6363
    64 void OSRExit::convertToForward(
    65     BasicBlock* block, Node* currentNode, unsigned nodeIndex,
    66     const FormattedValue &value, ExitArgumentList& arguments)
    67 {
    68     Node* node;
    69     Node* lastMovHint;
    70     if (!doSearchForForwardConversion(block, currentNode, nodeIndex, !!value, node, lastMovHint))
    71         return;
    72 
    73     ASSERT(node->codeOrigin != currentNode->codeOrigin);
    74    
    75     m_codeOrigin = node->codeOrigin;
    76    
    77     if (!value)
    78         return;
    79    
    80     VirtualRegister overriddenOperand = lastMovHint->local();
    81    
    82     // Is the value for this operand being passed as an argument to the exit, or is
    83     // it something else? If it's an argument already, then replace that argument;
    84     // otherwise add another argument.
    85     if (m_values.operand(overriddenOperand).isArgument()) {
    86         ExitArgument exitArgument = m_values.operand(overriddenOperand).exitArgument();
    87         arguments[exitArgument.argument()] = value.value();
    88         m_values.operand(overriddenOperand) = ExitValue::exitArgument(
    89             exitArgument.withFormat(value.format()));
    90         return;
    91     }
    92    
    93     unsigned argument = arguments.size();
    94     arguments.append(value.value());
    95     m_values.operand(overriddenOperand) = ExitValue::exitArgument(
    96         ExitArgument(value.format(), argument));
    97 }
    98 
    9964} } // namespace JSC::FTL
    10065
  • trunk/Source/JavaScriptCore/ftl/FTLOSRExit.h

    r159091 r161126  
    167167   
    168168    CodeLocationJump codeLocationForRepatch(CodeBlock* ftlCodeBlock) const;
    169    
    170     void convertToForward(
    171         DFG::BasicBlock*, DFG::Node* currentNode, unsigned nodeIndex,
    172         const FormattedValue&, ExitArgumentList& arguments);
    173169};
    174170
Note: See TracChangeset for help on using the changeset viewer.