Changeset 221602 in webkit


Ignore:
Timestamp:
Sep 4, 2017 8:21:33 PM (7 years ago)
Author:
sbarati@apple.com
Message:

Support compiling catch in the FTL
https://bugs.webkit.org/show_bug.cgi?id=175396

Reviewed by Filip Pizlo.

This patch implements op_catch in the FTL. It extends the DFG implementation
by supporting multiple entrypoints in DFG-SSA. This patch implements this
by introducing an EntrySwitch node. When converting to SSA, we introduce a new
root block with an EntrySwitch that has the previous DFG entrypoints as its
successors. By convention, we pick the zeroth entry point index to be the
op_enter entrypoint. Like in B3, in DFG-SSA, EntrySwitch just acts like a
switch over the entrypoint index argument. DFG::EntrySwitch in the FTL
simply lowers to B3::EntrySwitch. The EntrySwitch in the root block that
SSAConversion creates can not exit because we would both not know where to exit
to in the program: we would not have valid OSR exit state. This design also
mandates that anything we hoist above EntrySwitch in the new root block
can not exit since they also do not have valid OSR exit state.

This patch also adds a new metadata node named InitializeEntrypointArguments.
InitializeEntrypointArguments is a metadata node that initializes the flush format for
the arguments at a given entrypoint. For a given entrypoint index, this node
tells AI and OSRAvailabilityAnalysis what the flush format for each argument
is. This allows each individual entrypoint to have an independent set of
argument types. Currently, this won't happen in practice because ArgumentPosition
unifies flush formats, but this is an implementation detail we probably want
to modify in the future. SSAConversion will add InitializeEntrypointArguments
to the beginning of each of the original DFG entrypoint blocks.

This patch also adds the ability to specify custom prologue code generators in Air.
This allows the FTL to specify a custom prologue for catch entrypoints that
matches the op_catch OSR entry calling convention that the DFG uses. This way,
the baseline JIT code OSR enters into op_catch the same way both in the DFG
and the FTL. In the future, we can use this same mechanism to perform stack
overflow checks instead of using a patchpoint.

  • b3/air/AirCode.cpp:

(JSC::B3::Air::Code::isEntrypoint):
(JSC::B3::Air::Code::entrypointIndex):

  • b3/air/AirCode.h:

(JSC::B3::Air::Code::setPrologueForEntrypoint):
(JSC::B3::Air::Code::prologueGeneratorForEntrypoint):

  • b3/air/AirGenerate.cpp:

(JSC::B3::Air::generate):

  • dfg/DFGAbstractInterpreterInlines.h:

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

  • dfg/DFGBasicBlock.h:
  • dfg/DFGByteCodeParser.cpp:

(JSC::DFG::ByteCodeParser::parseBlock):
(JSC::DFG::ByteCodeParser::parse):

  • dfg/DFGCFG.h:

(JSC::DFG::selectCFG):

  • dfg/DFGClobberize.h:

(JSC::DFG::clobberize):

  • dfg/DFGClobbersExitState.cpp:

(JSC::DFG::clobbersExitState):

  • dfg/DFGCommonData.cpp:

(JSC::DFG::CommonData::shrinkToFit):
(JSC::DFG::CommonData::finalizeCatchEntrypoints):

  • dfg/DFGCommonData.h:

(JSC::DFG::CommonData::catchOSREntryDataForBytecodeIndex):
(JSC::DFG::CommonData::appendCatchEntrypoint):

  • dfg/DFGDoesGC.cpp:

(JSC::DFG::doesGC):

  • dfg/DFGFixupPhase.cpp:

(JSC::DFG::FixupPhase::fixupNode):

  • dfg/DFGGraph.cpp:

(JSC::DFG::Graph::dump):
(JSC::DFG::Graph::invalidateCFG):
(JSC::DFG::Graph::ensureCPSCFG):
(JSC::DFG::Graph::methodOfGettingAValueProfileFor):

  • dfg/DFGGraph.h:

(JSC::DFG::Graph::isEntrypoint):

  • dfg/DFGInPlaceAbstractState.cpp:

(JSC::DFG::InPlaceAbstractState::initialize):
(JSC::DFG::InPlaceAbstractState::mergeToSuccessors):

  • dfg/DFGJITCode.cpp:

(JSC::DFG::JITCode::shrinkToFit):
(JSC::DFG::JITCode::finalizeOSREntrypoints):

  • dfg/DFGJITCode.h:

(JSC::DFG::JITCode::catchOSREntryDataForBytecodeIndex): Deleted.
(JSC::DFG::JITCode::appendCatchEntrypoint): Deleted.

  • dfg/DFGJITCompiler.cpp:

(JSC::DFG::JITCompiler::noticeCatchEntrypoint):
(JSC::DFG::JITCompiler::makeCatchOSREntryBuffer):

  • dfg/DFGMayExit.cpp:
  • dfg/DFGNode.h:

(JSC::DFG::Node::isEntrySwitch):
(JSC::DFG::Node::isTerminal):
(JSC::DFG::Node::entrySwitchData):
(JSC::DFG::Node::numSuccessors):
(JSC::DFG::Node::successor):
(JSC::DFG::Node::entrypointIndex):

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

(JSC::DFG::OSRAvailabilityAnalysisPhase::run):
(JSC::DFG::LocalOSRAvailabilityCalculator::executeNode):

  • dfg/DFGOSREntry.cpp:

(JSC::DFG::prepareCatchOSREntry):

  • dfg/DFGOSREntry.h:
  • dfg/DFGOSREntrypointCreationPhase.cpp:

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

  • dfg/DFGPredictionPropagationPhase.cpp:
  • dfg/DFGSSAConversionPhase.cpp:

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

  • dfg/DFGSafeToExecute.h:

(JSC::DFG::safeToExecute):

  • dfg/DFGSpeculativeJIT.cpp:

(JSC::DFG::SpeculativeJIT::linkOSREntries):

  • dfg/DFGSpeculativeJIT32_64.cpp:

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

  • dfg/DFGSpeculativeJIT64.cpp:

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

  • dfg/DFGStaticExecutionCountEstimationPhase.cpp:

(JSC::DFG::StaticExecutionCountEstimationPhase::run):

  • dfg/DFGValidate.cpp:
  • ftl/FTLCapabilities.cpp:

(JSC::FTL::canCompile):

  • ftl/FTLCompile.cpp:

(JSC::FTL::compile):

  • ftl/FTLLowerDFGToB3.cpp:

(JSC::FTL::DFG::LowerDFGToB3::lower):
(JSC::FTL::DFG::LowerDFGToB3::compileNode):
(JSC::FTL::DFG::LowerDFGToB3::compileExtractCatchLocal):
(JSC::FTL::DFG::LowerDFGToB3::compileGetStack):
(JSC::FTL::DFG::LowerDFGToB3::compileEntrySwitch):
(JSC::FTL::DFG::LowerDFGToB3::speculate):
(JSC::FTL::DFG::LowerDFGToB3::appendOSRExitDescriptor):
(JSC::FTL::DFG::LowerDFGToB3::appendOSRExit):
(JSC::FTL::DFG::LowerDFGToB3::blessSpeculation):

  • ftl/FTLOutput.cpp:

(JSC::FTL::Output::entrySwitch):

  • ftl/FTLOutput.h:
  • jit/JITOperations.cpp:
Location:
trunk/Source/JavaScriptCore
Files:
41 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r221601 r221602  
     12017-09-04  Saam Barati  <sbarati@apple.com>
     2
     3        Support compiling catch in the FTL
     4        https://bugs.webkit.org/show_bug.cgi?id=175396
     5
     6        Reviewed by Filip Pizlo.
     7
     8        This patch implements op_catch in the FTL. It extends the DFG implementation
     9        by supporting multiple entrypoints in DFG-SSA. This patch implements this
     10        by introducing an EntrySwitch node. When converting to SSA, we introduce a new
     11        root block with an EntrySwitch that has the previous DFG entrypoints as its
     12        successors. By convention, we pick the zeroth entry point index to be the
     13        op_enter entrypoint. Like in B3, in DFG-SSA, EntrySwitch just acts like a
     14        switch over the entrypoint index argument. DFG::EntrySwitch in the FTL
     15        simply lowers to B3::EntrySwitch. The EntrySwitch in the root block that
     16        SSAConversion creates can not exit because we would both not know where to exit
     17        to in the program: we would not have valid OSR exit state. This design also
     18        mandates that anything we hoist above EntrySwitch in the new root block
     19        can not exit since they also do not have valid OSR exit state.
     20       
     21        This patch also adds a new metadata node named InitializeEntrypointArguments.
     22        InitializeEntrypointArguments is a metadata node that initializes the flush format for
     23        the arguments at a given entrypoint. For a given entrypoint index, this node
     24        tells AI and OSRAvailabilityAnalysis what the flush format for each argument
     25        is. This allows each individual entrypoint to have an independent set of
     26        argument types. Currently, this won't happen in practice because ArgumentPosition
     27        unifies flush formats, but this is an implementation detail we probably want
     28        to modify in the future. SSAConversion will add InitializeEntrypointArguments
     29        to the beginning of each of the original DFG entrypoint blocks.
     30       
     31        This patch also adds the ability to specify custom prologue code generators in Air.
     32        This allows the FTL to specify a custom prologue for catch entrypoints that
     33        matches the op_catch OSR entry calling convention that the DFG uses. This way,
     34        the baseline JIT code OSR enters into op_catch the same way both in the DFG
     35        and the FTL. In the future, we can use this same mechanism to perform stack
     36        overflow checks instead of using a patchpoint.
     37
     38        * b3/air/AirCode.cpp:
     39        (JSC::B3::Air::Code::isEntrypoint):
     40        (JSC::B3::Air::Code::entrypointIndex):
     41        * b3/air/AirCode.h:
     42        (JSC::B3::Air::Code::setPrologueForEntrypoint):
     43        (JSC::B3::Air::Code::prologueGeneratorForEntrypoint):
     44        * b3/air/AirGenerate.cpp:
     45        (JSC::B3::Air::generate):
     46        * dfg/DFGAbstractInterpreterInlines.h:
     47        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
     48        * dfg/DFGBasicBlock.h:
     49        * dfg/DFGByteCodeParser.cpp:
     50        (JSC::DFG::ByteCodeParser::parseBlock):
     51        (JSC::DFG::ByteCodeParser::parse):
     52        * dfg/DFGCFG.h:
     53        (JSC::DFG::selectCFG):
     54        * dfg/DFGClobberize.h:
     55        (JSC::DFG::clobberize):
     56        * dfg/DFGClobbersExitState.cpp:
     57        (JSC::DFG::clobbersExitState):
     58        * dfg/DFGCommonData.cpp:
     59        (JSC::DFG::CommonData::shrinkToFit):
     60        (JSC::DFG::CommonData::finalizeCatchEntrypoints):
     61        * dfg/DFGCommonData.h:
     62        (JSC::DFG::CommonData::catchOSREntryDataForBytecodeIndex):
     63        (JSC::DFG::CommonData::appendCatchEntrypoint):
     64        * dfg/DFGDoesGC.cpp:
     65        (JSC::DFG::doesGC):
     66        * dfg/DFGFixupPhase.cpp:
     67        (JSC::DFG::FixupPhase::fixupNode):
     68        * dfg/DFGGraph.cpp:
     69        (JSC::DFG::Graph::dump):
     70        (JSC::DFG::Graph::invalidateCFG):
     71        (JSC::DFG::Graph::ensureCPSCFG):
     72        (JSC::DFG::Graph::methodOfGettingAValueProfileFor):
     73        * dfg/DFGGraph.h:
     74        (JSC::DFG::Graph::isEntrypoint):
     75        * dfg/DFGInPlaceAbstractState.cpp:
     76        (JSC::DFG::InPlaceAbstractState::initialize):
     77        (JSC::DFG::InPlaceAbstractState::mergeToSuccessors):
     78        * dfg/DFGJITCode.cpp:
     79        (JSC::DFG::JITCode::shrinkToFit):
     80        (JSC::DFG::JITCode::finalizeOSREntrypoints):
     81        * dfg/DFGJITCode.h:
     82        (JSC::DFG::JITCode::catchOSREntryDataForBytecodeIndex): Deleted.
     83        (JSC::DFG::JITCode::appendCatchEntrypoint): Deleted.
     84        * dfg/DFGJITCompiler.cpp:
     85        (JSC::DFG::JITCompiler::noticeCatchEntrypoint):
     86        (JSC::DFG::JITCompiler::makeCatchOSREntryBuffer):
     87        * dfg/DFGMayExit.cpp:
     88        * dfg/DFGNode.h:
     89        (JSC::DFG::Node::isEntrySwitch):
     90        (JSC::DFG::Node::isTerminal):
     91        (JSC::DFG::Node::entrySwitchData):
     92        (JSC::DFG::Node::numSuccessors):
     93        (JSC::DFG::Node::successor):
     94        (JSC::DFG::Node::entrypointIndex):
     95        * dfg/DFGNodeType.h:
     96        * dfg/DFGOSRAvailabilityAnalysisPhase.cpp:
     97        (JSC::DFG::OSRAvailabilityAnalysisPhase::run):
     98        (JSC::DFG::LocalOSRAvailabilityCalculator::executeNode):
     99        * dfg/DFGOSREntry.cpp:
     100        (JSC::DFG::prepareCatchOSREntry):
     101        * dfg/DFGOSREntry.h:
     102        * dfg/DFGOSREntrypointCreationPhase.cpp:
     103        (JSC::DFG::OSREntrypointCreationPhase::run):
     104        * dfg/DFGPredictionPropagationPhase.cpp:
     105        * dfg/DFGSSAConversionPhase.cpp:
     106        (JSC::DFG::SSAConversionPhase::SSAConversionPhase):
     107        (JSC::DFG::SSAConversionPhase::run):
     108        * dfg/DFGSafeToExecute.h:
     109        (JSC::DFG::safeToExecute):
     110        * dfg/DFGSpeculativeJIT.cpp:
     111        (JSC::DFG::SpeculativeJIT::linkOSREntries):
     112        * dfg/DFGSpeculativeJIT32_64.cpp:
     113        (JSC::DFG::SpeculativeJIT::compile):
     114        * dfg/DFGSpeculativeJIT64.cpp:
     115        (JSC::DFG::SpeculativeJIT::compile):
     116        * dfg/DFGStaticExecutionCountEstimationPhase.cpp:
     117        (JSC::DFG::StaticExecutionCountEstimationPhase::run):
     118        * dfg/DFGValidate.cpp:
     119        * ftl/FTLCapabilities.cpp:
     120        (JSC::FTL::canCompile):
     121        * ftl/FTLCompile.cpp:
     122        (JSC::FTL::compile):
     123        * ftl/FTLLowerDFGToB3.cpp:
     124        (JSC::FTL::DFG::LowerDFGToB3::lower):
     125        (JSC::FTL::DFG::LowerDFGToB3::compileNode):
     126        (JSC::FTL::DFG::LowerDFGToB3::compileExtractCatchLocal):
     127        (JSC::FTL::DFG::LowerDFGToB3::compileGetStack):
     128        (JSC::FTL::DFG::LowerDFGToB3::compileEntrySwitch):
     129        (JSC::FTL::DFG::LowerDFGToB3::speculate):
     130        (JSC::FTL::DFG::LowerDFGToB3::appendOSRExitDescriptor):
     131        (JSC::FTL::DFG::LowerDFGToB3::appendOSRExit):
     132        (JSC::FTL::DFG::LowerDFGToB3::blessSpeculation):
     133        * ftl/FTLOutput.cpp:
     134        (JSC::FTL::Output::entrySwitch):
     135        * ftl/FTLOutput.h:
     136        * jit/JITOperations.cpp:
     137
    11382017-09-03  Yusuke Suzuki  <utatane.tea@gmail.com>
    2139
  • trunk/Source/JavaScriptCore/b3/air/AirCode.cpp

    r216989 r221602  
    157157bool Code::isEntrypoint(BasicBlock* block) const
    158158{
     159    // Note: This function must work both before and after LowerEntrySwitch.
     160
    159161    if (m_entrypoints.isEmpty())
    160162        return !block->index();
     
    165167    }
    166168    return false;
     169}
     170
     171std::optional<unsigned> Code::entrypointIndex(BasicBlock* block) const
     172{
     173    RELEASE_ASSERT(m_entrypoints.size());
     174    for (unsigned i = 0; i < m_entrypoints.size(); ++i) {
     175        if (m_entrypoints[i].block() == block)
     176            return i;
     177    }
     178    return std::nullopt;
    167179}
    168180
  • trunk/Source/JavaScriptCore/b3/air/AirCode.h

    r216989 r221602  
    5454class CCallSpecial;
    5555class CFG;
     56class Code;
    5657class Disassembler;
    5758
    5859typedef void WasmBoundsCheckGeneratorFunction(CCallHelpers&, GPRReg);
    5960typedef SharedTask<WasmBoundsCheckGeneratorFunction> WasmBoundsCheckGenerator;
     61
     62typedef void PrologueGeneratorFunction(CCallHelpers&, Code&);
     63typedef SharedTask<PrologueGeneratorFunction> PrologueGenerator;
    6064
    6165// This is an IR that is very close to the bare metal. It requires about 40x more bytes than the
     
    166170    const FrequentedBlock& entrypoint(unsigned index) const { return m_entrypoints[index]; }
    167171    bool isEntrypoint(BasicBlock*) const;
    168    
     172    // Note: It is only valid to call this function after LowerEntrySwitch.
     173    std::optional<unsigned> entrypointIndex(BasicBlock*) const;
     174    void setPrologueForEntrypoint(unsigned entrypointIndex, RefPtr<PrologueGenerator> generator)
     175    {
     176        // Note: We allow this to be called even before we set m_entrypoints just for convenience to users of this API.
     177        m_entrypointIndexToGenerator.set(entrypointIndex, generator);
     178    }
     179    RefPtr<PrologueGenerator> prologueGeneratorForEntrypoint(unsigned entrypointIndex)
     180    {
     181        return m_entrypointIndexToGenerator.get(entrypointIndex);
     182    }
     183
    169184    // This is used by lowerEntrySwitch().
    170185    template<typename Vector>
     
    354369    Vector<FrequentedBlock> m_entrypoints; // This is empty until after lowerEntrySwitch().
    355370    Vector<CCallHelpers::Label> m_entrypointLabels; // This is empty until code generation.
     371    HashMap<unsigned, RefPtr<PrologueGenerator>, WTF::IntHash<unsigned>, WTF::UnsignedWithZeroKeyHashTraits<unsigned>> m_entrypointIndexToGenerator;
    356372    RefPtr<WasmBoundsCheckGenerator> m_wasmBoundsCheckGenerator;
    357373    const char* m_lastPhaseName;
  • trunk/Source/JavaScriptCore/b3/air/AirGenerate.cpp

    r217221 r221602  
    209209            disassembler->startBlock(block, jit);
    210210
    211         if (code.isEntrypoint(block)) {
     211        if (std::optional<unsigned> entrypointIndex = code.entrypointIndex(block)) {
     212            ASSERT(code.isEntrypoint(block));
     213
    212214            if (disassembler)
    213215                disassembler->startEntrypoint(jit);
    214216
    215             jit.emitFunctionPrologue();
    216             if (code.frameSize()) {
    217                 AllowMacroScratchRegisterUsageIf allowScratch(jit, isARM64());
    218                 jit.addPtr(CCallHelpers::TrustedImm32(-code.frameSize()), MacroAssembler::stackPointerRegister);
     217            if (RefPtr<PrologueGenerator> prologueGenerator = code.prologueGeneratorForEntrypoint(*entrypointIndex))
     218                prologueGenerator->run(jit, code);
     219            else {
     220                jit.emitFunctionPrologue();
     221                if (code.frameSize()) {
     222                    AllowMacroScratchRegisterUsageIf allowScratch(jit, isARM64());
     223                    jit.addPtr(CCallHelpers::TrustedImm32(-code.frameSize()), MacroAssembler::stackPointerRegister);
     224                }
     225               
     226                jit.emitSave(code.calleeSaveRegisterAtOffsetList());
    219227            }
    220            
    221             jit.emitSave(code.calleeSaveRegisterAtOffsetList());
    222228
    223229            if (disassembler)
    224230                disassembler->endEntrypoint(jit);
    225         }
     231        } else
     232            ASSERT(!code.isEntrypoint(block));
    226233       
    227234        ASSERT(block->size() >= 1);
  • trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h

    r221601 r221602  
    261261        break;
    262262    }
    263        
     263
    264264    case KillStack: {
    265265        // This is just a hint telling us that the OSR state of the local is no longer inside the
     
    274274        ASSERT(!m_state.variables().operand(node->local()).isClear());
    275275        break;
    276        
     276
     277    case InitializeEntrypointArguments: {
     278        unsigned entrypointIndex = node->entrypointIndex();
     279        const Vector<FlushFormat>& argumentFormats = m_graph.m_argumentFormats[entrypointIndex];
     280        for (unsigned argument = 0; argument < argumentFormats.size(); ++argument) {
     281            AbstractValue& value = m_state.variables().argument(argument);
     282            switch (argumentFormats[argument]) {
     283            case FlushedInt32:
     284                value.setType(SpecInt32Only);
     285                break;
     286            case FlushedBoolean:
     287                value.setType(SpecBoolean);
     288                break;
     289            case FlushedCell:
     290                value.setType(m_graph, SpecCell);
     291                break;
     292            case FlushedJSValue:
     293                value.makeBytecodeTop();
     294                break;
     295            default:
     296                DFG_CRASH(m_graph, node, "Bad flush format for argument");
     297                break;
     298            }
     299        }
     300        break;
     301    }
     302
    277303    case LoadVarargs:
    278304    case ForwardVarargs: {
     
    18671893    }
    18681894
     1895    case EntrySwitch:
     1896        break;
     1897
    18691898    case Return:
    18701899        m_state.setIsValid(false);
  • trunk/Source/JavaScriptCore/dfg/DFGBasicBlock.h

    r221196 r221602  
    222222    float executionCount;
    223223   
    224     // These fields are reserved for NaturalLoops.
    225    
    226224    struct SSAData {
    227225        WTF_MAKE_FAST_ALLOCATED;
  • trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp

    r221528 r221602  
    52635263            }
    52645264
    5265             if (isFTL(m_graph.m_plan.mode)) {
    5266                 // FIXME: Support catch in the FTL.
    5267                 // https://bugs.webkit.org/show_bug.cgi?id=175396
     5265            if (m_graph.m_plan.mode == FTLForOSREntryMode) {
    52685266                NEXT_OPCODE(op_catch);
    52695267            }
     
    64666464    m_graph.killUnreachableBlocks();
    64676465
    6468     m_graph.m_cpsCFG = std::make_unique<CPSCFG>(m_graph);
    6469    
    64706466    for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) {
    64716467        BasicBlock* block = m_graph.block(blockIndex);
  • trunk/Source/JavaScriptCore/dfg/DFGCFG.h

    r221196 r221602  
    9999CPSCFG& selectCFG(Graph& graph)
    100100{
    101     RELEASE_ASSERT(graph.m_cpsCFG);
    102     return *graph.m_cpsCFG;
     101    return graph.ensureCPSCFG();
    103102}
    104103
  • trunk/Source/JavaScriptCore/dfg/DFGClobberize.h

    r221601 r221602  
    427427    case Branch:
    428428    case Switch:
     429    case EntrySwitch:
    429430    case ForceOSRExit:
    430431    case CheckBadCell:
     
    438439    case ProfileControlFlow:
    439440    case PutHint:
     441    case InitializeEntrypointArguments:
    440442        write(SideState);
    441443        return;
  • trunk/Source/JavaScriptCore/dfg/DFGClobbersExitState.cpp

    r221080 r221602  
    4141    // normally clobber.
    4242    switch (node->op()) {
     43    case InitializeEntrypointArguments:
    4344    case MovHint:
    4445    case ZombieHint:
  • trunk/Source/JavaScriptCore/dfg/DFGCommonData.cpp

    r221528 r221602  
    8888    weakReferences.shrinkToFit();
    8989    transitions.shrinkToFit();
     90    catchEntrypoints.shrinkToFit();
    9091}
    9192
     
    194195}
    195196
     197void CommonData::finalizeCatchEntrypoints()
     198{
     199    std::sort(catchEntrypoints.begin(), catchEntrypoints.end(),
     200        [] (const CatchEntrypointData& a, const CatchEntrypointData& b) { return a.bytecodeIndex < b.bytecodeIndex; });
     201
     202#if !ASSERT_DISABLED
     203    for (unsigned i = 0; i + 1 < catchEntrypoints.size(); ++i)
     204        ASSERT(catchEntrypoints[i].bytecodeIndex <= catchEntrypoints[i + 1].bytecodeIndex);
     205#endif
     206}
     207
    196208} } // namespace JSC::DFG
    197209
  • trunk/Source/JavaScriptCore/dfg/DFGCommonData.h

    r218936 r221602  
    3232#include "DFGAdaptiveStructureWatchpoint.h"
    3333#include "DFGJumpReplacement.h"
     34#include "DFGOSREntry.h"
    3435#include "InlineCallFrameSet.h"
    3536#include "JSCell.h"
     
    9192    bool isVMTrapBreakpoint(void* address);
    9293
     94    CatchEntrypointData* catchOSREntryDataForBytecodeIndex(unsigned bytecodeIndex)
     95    {
     96        return tryBinarySearch<CatchEntrypointData, unsigned>(
     97            catchEntrypoints, catchEntrypoints.size(), bytecodeIndex,
     98            [] (const CatchEntrypointData* item) { return item->bytecodeIndex; });
     99    }
     100
     101    void appendCatchEntrypoint(unsigned bytecodeIndex, void* machineCode, Vector<FlushFormat>&& argumentFormats)
     102    {
     103        catchEntrypoints.append(CatchEntrypointData { machineCode,  WTFMove(argumentFormats), bytecodeIndex });
     104    }
     105
     106    void finalizeCatchEntrypoints();
     107
    93108    unsigned requiredRegisterCountForExecutionAndExit() const
    94109    {
     
    107122    Vector<WriteBarrier<JSCell>> weakReferences;
    108123    Vector<WriteBarrier<Structure>> weakStructureReferences;
     124    Vector<CatchEntrypointData> catchEntrypoints;
    109125    Bag<CodeBlockJettisoningWatchpoint> watchpoints;
    110126    Bag<AdaptiveStructureWatchpoint> adaptiveStructureWatchpoints;
     
    112128    Vector<JumpReplacement> jumpReplacements;
    113129   
     130    ScratchBuffer* catchOSREntryBuffer;
    114131    RefPtr<Profiler::Compilation> compilation;
    115132    bool livenessHasBeenProved; // Initialized and used on every GC.
  • trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp

    r221601 r221602  
    5757    case SetLocal:
    5858    case MovHint:
     59    case InitializeEntrypointArguments:
    5960    case ZombieHint:
    6061    case ExitOK:
     
    185186    case Branch:
    186187    case Switch:
     188    case EntrySwitch:
    187189    case Return:
    188190    case TailCall:
  • trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp

    r221601 r221602  
    15501550        case Phi:
    15511551        case Upsilon:
     1552        case EntrySwitch:
    15521553        case GetIndexedPropertyStorage:
    15531554        case LastNodeType:
     
    20382039        case LoopHint:
    20392040        case MovHint:
     2041        case InitializeEntrypointArguments:
    20402042        case ZombieHint:
    20412043        case ExitOK:
  • trunk/Source/JavaScriptCore/dfg/DFGGraph.cpp

    r221528 r221602  
    369369        out.print(comma, "default:", data->fallThrough);
    370370    }
     371    if (node->isEntrySwitch()) {
     372        EntrySwitchData* data = node->entrySwitchData();
     373        for (unsigned i = 0; i < data->cases.size(); ++i)
     374            out.print(comma, BranchTarget(data->cases[i]));
     375    }
    371376    ClobberSet reads;
    372377    ClobberSet writes;
     
    516521    out.print("DFG for ", CodeBlockWithJITType(m_codeBlock, JITCode::DFGJIT), ":\n");
    517522    out.print("  Fixpoint state: ", m_fixpointState, "; Form: ", m_form, "; Unification state: ", m_unificationState, "; Ref count state: ", m_refCountState, "\n");
    518     if (m_form == SSA)
    519         out.print("  Argument formats: ", listDump(m_argumentFormats), "\n");
     523    if (m_form == SSA) {
     524        for (unsigned entrypointIndex = 0; entrypointIndex < m_argumentFormats.size(); ++entrypointIndex)
     525            out.print("  Argument formats for entrypoint index: ", entrypointIndex, " : ", listDump(m_argumentFormats[entrypointIndex]), "\n");
     526    }
    520527    else {
    521528        for (auto pair : m_entrypointToArguments)
     
    825832    m_backwardsDominators = nullptr;
    826833    m_backwardsCFG = nullptr;
     834    m_cpsCFG = nullptr;
    827835}
    828836
     
    15441552}
    15451553
     1554CPSCFG& Graph::ensureCPSCFG()
     1555{
     1556    RELEASE_ASSERT(m_form != SSA && !m_isInSSAConversion);
     1557    if (!m_cpsCFG)
     1558        m_cpsCFG = std::make_unique<CPSCFG>(*this);
     1559    return *m_cpsCFG;
     1560}
     1561
    15461562CPSDominators& Graph::ensureCPSDominators()
    15471563{
     
    16111627
    16121628            if (node->accessesStack(*this)) {
    1613                 ValueProfile* result = [&] () -> ValueProfile* {
    1614                     if (!node->local().isArgument())
    1615                         return nullptr;
     1629                if (m_form != SSA && node->local().isArgument()) {
    16161630                    int argument = node->local().toArgument();
     1631                    Node* argumentNode = m_entrypointToArguments.find(block(0))->value[argument];
    16171632                    // FIXME: We should match SetArgument nodes at other entrypoints as well:
    16181633                    // https://bugs.webkit.org/show_bug.cgi?id=175841
    1619                     Node* argumentNode = m_entrypointToArguments.find(block(0))->value[argument];
    1620                     if (!argumentNode)
    1621                         return nullptr;
    1622                     if (node->variableAccessData() != argumentNode->variableAccessData())
    1623                         return nullptr;
    1624                     return &profiledBlock->valueProfileForArgument(argument);
    1625                 }();
    1626                 if (result)
    1627                     return result;
     1634                    if (argumentNode && node->variableAccessData() == argumentNode->variableAccessData())
     1635                        return &profiledBlock->valueProfileForArgument(argument);
     1636                }
    16281637
    16291638                if (node->op() == GetLocal) {
  • trunk/Source/JavaScriptCore/dfg/DFGGraph.h

    r221601 r221602  
    932932    BackwardsDominators& ensureBackwardsDominators();
    933933    ControlEquivalenceAnalysis& ensureControlEquivalenceAnalysis();
     934    CPSCFG& ensureCPSCFG();
    934935
    935936    // These functions only makes sense to call after bytecode parsing
     
    951952    bool isEntrypoint(BasicBlock* block) const
    952953    {
     954        ASSERT_WITH_MESSAGE(!m_isInSSAConversion, "This is not written to work during SSA conversion.");
     955
     956        if (m_form == SSA) {
     957            ASSERT(m_entrypoints.size() == 1);
     958            ASSERT(m_entrypoints.contains(this->block(0)));
     959            return block == this->block(0);
     960        }
     961
    953962        if (m_entrypoints.size() <= 4) {
    954963            bool result = m_entrypoints.contains(block);
     
    979988    // In CPS, this is all of the SetArgument nodes for the arguments in the machine code block
    980989    // that survived DCE. All of them except maybe "this" will survive DCE, because of the Flush
    981     // nodes.
     990    // nodes. In SSA, this has no meaning. It's empty.
     991    HashMap<BasicBlock*, ArgumentsVector> m_entrypointToArguments;
     992
     993    // In SSA, this is the argument speculation that we've locked in for an entrypoint block.
    982994    //
    983     // In SSA, this is all of the GetStack nodes for the arguments in the machine code block that
    984     // may have some speculation in the prologue and survived DCE. Note that to get the speculation
    985     // for an argument in SSA, you must use m_argumentFormats, since we still have to speculate
    986     // even if the argument got killed. For example:
     995    // We must speculate on the argument types at each entrypoint even if operations involving
     996    // arguments get killed. For example:
    987997    //
    988998    //     function foo(x) {
     
    10021012    // If we DCE the ArithAdd and we remove the int check on x, then this won't do the side
    10031013    // effects.
    1004     HashMap<BasicBlock*, ArgumentsVector> m_entrypointToArguments;
    1005    
    1006     // In CPS, this is meaningless. In SSA, this is the argument speculation that we've locked in.
    1007     Vector<FlushFormat> m_argumentFormats;
     1014    //
     1015    // By convention, entrypoint index 0 is used for the CodeBlock's op_enter entrypoint.
     1016    // So argumentFormats[0] are the argument formats for the normal call entrypoint.
     1017    Vector<Vector<FlushFormat>> m_argumentFormats;
     1018
     1019    // This maps an entrypoint index to a particular op_catch bytecode offset. By convention,
     1020    // it'll never have zero as a key because we use zero to mean the op_enter entrypoint.
     1021    HashMap<unsigned, unsigned> m_entrypointIndexToCatchBytecodeOffset;
     1022
     1023    // This is the number of logical entrypoints that we're compiling. This is only used
     1024    // in SSA. Each EntrySwitch node must have numberOfEntrypoints cases. Note, this is
     1025    // not the same as m_entrypoints.size(). m_entrypoints.size() represents the number
     1026    // of roots in the CFG. In SSA, m_entrypoints.size() == 1.
     1027    unsigned m_numberOfEntrypoints { UINT_MAX };
    10081028
    10091029    SegmentedVector<VariableAccessData, 16> m_variableAccessData;
     
    10611081    std::unique_ptr<FlowIndexing> m_indexingCache;
    10621082    std::unique_ptr<FlowMap<AbstractValue>> m_abstractValuesCache;
     1083    Bag<EntrySwitchData> m_entrySwitchData;
    10631084
    10641085    RegisteredStructure stringStructure;
  • trunk/Source/JavaScriptCore/dfg/DFGInPlaceAbstractState.cpp

    r221472 r221602  
    101101        entrypoint->cfaStructureClobberStateAtTail = StructuresAreWatched;
    102102
    103         for (size_t i = 0; i < entrypoint->valuesAtHead.numberOfArguments(); ++i) {
    104             entrypoint->valuesAtTail.argument(i).clear();
    105 
    106             FlushFormat format;
    107             if (m_graph.m_form == SSA) {
    108                 // FIXME: When supporting multiple entrypoints in the FTL, we need to change
    109                 // what we do here: https://bugs.webkit.org/show_bug.cgi?id=175396
    110                 format = m_graph.m_argumentFormats[i];
    111             } else {
    112                 Node* node = m_graph.m_entrypointToArguments.find(entrypoint)->value[i];
     103        if (m_graph.m_form == SSA)  {
     104            for (size_t i = 0; i < entrypoint->valuesAtHead.numberOfArguments(); ++i) {
     105                entrypoint->valuesAtHead.argument(i).clear();
     106                entrypoint->valuesAtTail.argument(i).clear();
     107            }
     108        } else {
     109            const ArgumentsVector& arguments = m_graph.m_entrypointToArguments.find(entrypoint)->value;
     110            for (size_t i = 0; i < entrypoint->valuesAtHead.numberOfArguments(); ++i) {
     111                entrypoint->valuesAtTail.argument(i).clear();
     112
     113                FlushFormat format;
     114                Node* node = arguments[i];
    113115                if (!node)
    114116                    format = FlushedJSValue;
     
    117119                    format = node->variableAccessData()->flushFormat();
    118120                }
     121
     122                switch (format) {
     123                case FlushedInt32:
     124                    entrypoint->valuesAtHead.argument(i).setType(SpecInt32Only);
     125                    break;
     126                case FlushedBoolean:
     127                    entrypoint->valuesAtHead.argument(i).setType(SpecBoolean);
     128                    break;
     129                case FlushedCell:
     130                    entrypoint->valuesAtHead.argument(i).setType(m_graph, SpecCell);
     131                    break;
     132                case FlushedJSValue:
     133                    entrypoint->valuesAtHead.argument(i).makeBytecodeTop();
     134                    break;
     135                default:
     136                    DFG_CRASH(m_graph, nullptr, "Bad flush format for argument");
     137                    break;
     138                }
    119139            }
    120            
    121             switch (format) {
    122             case FlushedInt32:
    123                 entrypoint->valuesAtHead.argument(i).setType(SpecInt32Only);
    124                 break;
    125             case FlushedBoolean:
    126                 entrypoint->valuesAtHead.argument(i).setType(SpecBoolean);
    127                 break;
    128             case FlushedCell:
    129                 entrypoint->valuesAtHead.argument(i).setType(m_graph, SpecCell);
    130                 break;
    131             case FlushedJSValue:
    132                 entrypoint->valuesAtHead.argument(i).makeBytecodeTop();
    133                 break;
    134             default:
    135                 DFG_CRASH(m_graph, nullptr, "Bad flush format for argument");
    136                 break;
    137             }
    138         }
     140        }
     141
    139142        for (size_t i = 0; i < entrypoint->valuesAtHead.numberOfLocals(); ++i) {
    140143            entrypoint->valuesAtHead.local(i).clear();
     
    164167        }
    165168    }
     169
    166170    if (m_graph.m_form == SSA) {
    167171        for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) {
     
    372376        return changed;
    373377    }
     378   
     379    case EntrySwitch: {
     380        EntrySwitchData* data = terminal->entrySwitchData();
     381        bool changed = false;
     382        for (unsigned i = data->cases.size(); i--;)
     383            changed |= merge(basicBlock, data->cases[i]);
     384        return changed;
     385    }
    374386
    375387    case Return:
  • trunk/Source/JavaScriptCore/dfg/DFGJITCode.cpp

    r221200 r221602  
    6464    osrEntry.shrinkToFit();
    6565    osrExit.shrinkToFit();
    66     catchEntrypoints.shrinkToFit();
    6766    speculationRecovery.shrinkToFit();
    6867    minifiedDFG.prepareAndShrink();
     
    244243        return a.m_bytecodeIndex < b.m_bytecodeIndex;
    245244    };
    246     std::sort(catchEntrypoints.begin(), catchEntrypoints.end(), comparator);
    247245    std::sort(osrEntry.begin(), osrEntry.end(), comparator);
    248246
     
    252250            ASSERT(osrVector[i].m_bytecodeIndex <= osrVector[i + 1].m_bytecodeIndex);
    253251    };
    254     verifyIsSorted(catchEntrypoints);
    255252    verifyIsSorted(osrEntry);
    256253#endif
  • trunk/Source/JavaScriptCore/dfg/DFGJITCode.h

    r221200 r221602  
    7171    }
    7272
    73     CatchEntrypointData* catchOSREntryDataForBytecodeIndex(unsigned bytecodeIndex)
    74     {
    75         return tryBinarySearch<CatchEntrypointData, unsigned>(
    76             catchEntrypoints, catchEntrypoints.size(), bytecodeIndex,
    77             [] (const CatchEntrypointData* item) { return item->m_bytecodeIndex; });
    78     }
    79 
    8073    void finalizeOSREntrypoints();
    8174
    82     void appendCatchEntrypoint(unsigned bytecodeIndex, unsigned machineCodeOffset, Vector<FlushFormat>&& argumentFormats)
    83     {
    84         catchEntrypoints.append(CatchEntrypointData { bytecodeIndex, machineCodeOffset, WTFMove(argumentFormats) });
    85     }
    86    
    8775    unsigned appendOSRExit(const OSRExit& exit)
    8876    {
     
    147135    CommonData common;
    148136    Vector<DFG::OSREntryData> osrEntry;
    149     Vector<CatchEntrypointData> catchEntrypoints;
    150137    SegmentedVector<DFG::OSRExit, 8> osrExit;
    151138    Vector<DFG::SpeculationRecovery> speculationRecovery;
    152139    DFG::VariableEventStream variableEventStream;
    153140    DFG::MinifiedGraph minifiedDFG;
    154     ScratchBuffer* catchOSREntryBuffer;
    155141
    156142#if ENABLE(FTL_JIT)
  • trunk/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp

    r221196 r221602  
    560560    RELEASE_ASSERT(basicBlock.isCatchEntrypoint);
    561561    RELEASE_ASSERT(basicBlock.intersectionOfCFAHasVisited); // An entrypoint is reachable by definition.
    562     m_jitCode->appendCatchEntrypoint(basicBlock.bytecodeBegin, linkBuffer.offsetOf(blockHead), WTFMove(argumentFormats));
     562    m_jitCode->common.appendCatchEntrypoint(basicBlock.bytecodeBegin, linkBuffer.locationOf(blockHead).executableAddress(), WTFMove(argumentFormats));
    563563}
    564564
     
    688688    if (m_graph.m_maxLocalsForCatchOSREntry) {
    689689        uint32_t numberOfLiveLocals = std::max(*m_graph.m_maxLocalsForCatchOSREntry, 1u); // Make sure we always allocate a non-null catchOSREntryBuffer.
    690         m_jitCode->catchOSREntryBuffer = vm()->scratchBufferForSize(sizeof(JSValue) * numberOfLiveLocals);
     690        m_jitCode->common.catchOSREntryBuffer = vm()->scratchBufferForSize(sizeof(JSValue) * numberOfLiveLocals);
    691691    }
    692692}
  • trunk/Source/JavaScriptCore/dfg/DFGMayExit.cpp

    r221196 r221602  
    5454    case Int52Constant:
    5555    case MovHint:
     56    case InitializeEntrypointArguments:
    5657    case SetLocal:
    5758    case Flush:
     
    7980    case CountExecution:
    8081    case Jump:
     82    case EntrySwitch:
    8183    case Branch:
    8284    case Unreachable:
  • trunk/Source/JavaScriptCore/dfg/DFGNode.h

    r221601 r221602  
    204204};
    205205
     206struct EntrySwitchData {
     207    Vector<BasicBlock*> cases;
     208};
     209
    206210struct CallVarargsData {
    207211    int firstVarArgOffset;
     
    13161320    }
    13171321
     1322    bool isEntrySwitch() const
     1323    {
     1324        return op() == EntrySwitch;
     1325    }
     1326
    13181327    bool isTerminal()
    13191328    {
     
    13221331        case Branch:
    13231332        case Switch:
     1333        case EntrySwitch:
    13241334        case Return:
    13251335        case TailCall:
     
    13831393        return m_opInfo.as<SwitchData*>();
    13841394    }
     1395
     1396    EntrySwitchData* entrySwitchData()
     1397    {
     1398        ASSERT(isEntrySwitch());
     1399        return m_opInfo.as<EntrySwitchData*>();
     1400    }
    13851401   
    13861402    unsigned numSuccessors()
     
    13931409        case Switch:
    13941410            return switchData()->cases.size() + 1;
     1411        case EntrySwitch:
     1412            return entrySwitchData()->cases.size();
    13951413        default:
    13961414            return 0;
     
    14051423            RELEASE_ASSERT(index == switchData()->cases.size());
    14061424            return switchData()->fallThrough.block;
    1407         }
     1425        } else if (isEntrySwitch())
     1426            return entrySwitchData()->cases[index];
    14081427
    14091428        switch (index) {
     
    20142033    }
    20152034
     2035    unsigned entrypointIndex()
     2036    {
     2037        ASSERT(op() == InitializeEntrypointArguments);
     2038        return m_opInfo.as<unsigned>();
     2039    }
     2040
    20162041    bool shouldGenerate()
    20172042    {
  • trunk/Source/JavaScriptCore/dfg/DFGNodeType.h

    r221601 r221602  
    391391    macro(Branch, NodeMustGenerate) \
    392392    macro(Switch, NodeMustGenerate) \
     393    macro(EntrySwitch, NodeMustGenerate) \
    393394    macro(Return, NodeMustGenerate) \
    394395    macro(TailCall, NodeMustGenerate | NodeHasVarArgs) \
     
    441442    macro(CallDOMGetter, NodeResultJS | NodeMustGenerate) \
    442443    macro(CallDOM, NodeResultJS | NodeMustGenerate) \
     444    /* Metadata node that initializes the state for flushed argument types at an entrypoint in the program. */ \
     445    /* Currently, we only use this for the blocks an EntrySwitch branches to at the root of the program. */ \
     446    /* This is only used in SSA. */ \
     447    macro(InitializeEntrypointArguments, NodeMustGenerate)
    443448
    444449// This enum generates a monotonically increasing id for all Node types,
  • trunk/Source/JavaScriptCore/dfg/DFGOSRAvailabilityAnalysisPhase.cpp

    r221528 r221602  
    5858        BasicBlock* root = m_graph.block(0);
    5959        root->ssa->availabilityAtHead.m_locals.fill(Availability::unavailable());
    60         for (unsigned argument = m_graph.m_argumentFormats.size(); argument--;) {
    61             FlushedAt flushedAt = FlushedAt(
    62                 m_graph.m_argumentFormats[argument],
    63                 virtualRegisterForArgument(argument));
    64             root->ssa->availabilityAtHead.m_locals.argument(argument) = Availability(flushedAt);
    65         }
     60
     61        for (unsigned argument = 0; argument < m_graph.block(0)->valuesAtHead.numberOfArguments(); ++argument)
     62            root->ssa->availabilityAtHead.m_locals.argument(argument) = Availability::unavailable();
    6663
    6764        // This could be made more efficient by processing blocks in reverse postorder.
     
    8784                block->ssa->availabilityAtTail = calculator.m_availability;
    8885                changed = true;
    89                
     86
    9087                for (unsigned successorIndex = block->numSuccessors(); successorIndex--;) {
    9188                    BasicBlock* successor = block->successor(successorIndex);
    9289                    successor->ssa->availabilityAtHead.merge(calculator.m_availability);
     90                }
     91
     92                for (unsigned successorIndex = block->numSuccessors(); successorIndex--;) {
     93                    BasicBlock* successor = block->successor(successorIndex);
    9394                    successor->ssa->availabilityAtHead.pruneByLiveness(
    9495                        m_graph, successor->at(0)->origin.forExit);
     
    200201        break;
    201202    }
     203
     204    case InitializeEntrypointArguments: {
     205        unsigned entrypointIndex = node->entrypointIndex();
     206        const Vector<FlushFormat>& argumentFormats = m_graph.m_argumentFormats[entrypointIndex];
     207        for (unsigned argument = argumentFormats.size(); argument--; ) {
     208            FlushedAt flushedAt = FlushedAt(argumentFormats[argument], virtualRegisterForArgument(argument));
     209            m_availability.m_locals.argument(argument) = Availability(flushedAt);
     210        }
     211        break;
     212    }
    202213       
    203214    case LoadVarargs:
  • trunk/Source/JavaScriptCore/dfg/DFGOSREntry.cpp

    r221196 r221602  
    339339
    340340void* prepareCatchOSREntry(ExecState* exec, CodeBlock* codeBlock, unsigned bytecodeIndex)
    341 {
    342     if (!Options::useOSREntryToDFG())
     341{
     342    ASSERT(codeBlock->jitType() == JITCode::DFGJIT || codeBlock->jitType() == JITCode::FTLJIT);
     343
     344    if (!Options::useOSREntryToDFG() && codeBlock->jitCode()->jitType() == JITCode::DFGJIT)
    343345        return nullptr;
     346    if (!Options::useOSREntryToFTL() && codeBlock->jitCode()->jitType() == JITCode::FTLJIT)
     347        return nullptr;
    344348
    345349    VM& vm = exec->vm();
    346     ASSERT(codeBlock->jitType() == JITCode::DFGJIT);
    347     DFG::JITCode* jitCode = codeBlock->jitCode()->dfg();
    348     RELEASE_ASSERT(jitCode);
    349 
    350     DFG::CatchEntrypointData* catchEntrypoint = jitCode->catchOSREntryDataForBytecodeIndex(bytecodeIndex);
     350
     351    CommonData* dfgCommon = codeBlock->jitCode()->dfgCommon();
     352    RELEASE_ASSERT(dfgCommon);
     353    DFG::CatchEntrypointData* catchEntrypoint = dfgCommon->catchOSREntryDataForBytecodeIndex(bytecodeIndex);
    351354    if (!catchEntrypoint) {
    352355        // This can be null under some circumstances. The most common is that we didn't
     
    357360
    358361    // We're only allowed to OSR enter if we've proven we have compatible argument types.
    359     for (unsigned argument = 0; argument < catchEntrypoint->m_argumentFormats.size(); ++argument) {
     362    for (unsigned argument = 0; argument < catchEntrypoint->argumentFormats.size(); ++argument) {
    360363        JSValue value = exec->uncheckedR(virtualRegisterForArgument(argument)).jsValue();
    361         switch (catchEntrypoint->m_argumentFormats[argument]) {
     364        switch (catchEntrypoint->argumentFormats[argument]) {
    362365        case DFG::FlushedInt32:
    363366            if (!value.isInt32())
     
    383386    }
    384387
    385     unsigned frameSizeForCheck = jitCode->common.requiredRegisterCountForExecutionAndExit();
     388    unsigned frameSizeForCheck = dfgCommon->requiredRegisterCountForExecutionAndExit();
    386389    if (UNLIKELY(!vm.ensureStackCapacityFor(&exec->registers()[virtualRegisterForLocal(frameSizeForCheck).offset()])))
    387390        return nullptr;
     
    389392    ASSERT(Interpreter::getOpcodeID(exec->codeBlock()->instructions()[exec->bytecodeOffset()].u.opcode) == op_catch);
    390393    ValueProfileAndOperandBuffer* buffer = static_cast<ValueProfileAndOperandBuffer*>(exec->codeBlock()->instructions()[exec->bytecodeOffset() + 3].u.pointer);
    391     JSValue* dataBuffer = reinterpret_cast<JSValue*>(jitCode->catchOSREntryBuffer->dataBuffer());
     394    JSValue* dataBuffer = reinterpret_cast<JSValue*>(dfgCommon->catchOSREntryBuffer->dataBuffer());
    392395    unsigned index = 0;
    393396    buffer->forEach([&] (ValueProfileAndOperand& profile) {
     
    398401    });
    399402
    400     jitCode->catchOSREntryBuffer->setActiveLength(sizeof(JSValue) * index);
    401 
    402     return jitCode->executableAddressAtOffset(catchEntrypoint->m_machineCodeOffset);
     403    dfgCommon->catchOSREntryBuffer->setActiveLength(sizeof(JSValue) * index);
     404    return catchEntrypoint->machineCode;
    403405}
    404406
  • trunk/Source/JavaScriptCore/dfg/DFGOSREntry.h

    r221196 r221602  
    7272
    7373struct CatchEntrypointData {
    74     unsigned m_bytecodeIndex;
    75     unsigned m_machineCodeOffset;
    7674    // We use this when doing OSR entry at catch. We prove the arguments
    7775    // are of the expected type before entering at a catch block.
    78     Vector<FlushFormat> m_argumentFormats;
     76    void* machineCode;
     77    Vector<FlushFormat> argumentFormats;
     78    unsigned bytecodeIndex;
    7979};
    8080
  • trunk/Source/JavaScriptCore/dfg/DFGOSREntrypointCreationPhase.cpp

    r221196 r221602  
    148148        m_graph.m_entrypointToArguments.add(newRoot, newArguments);
    149149
    150         m_graph.m_cpsCFG = std::make_unique<CPSCFG>(m_graph);
    151 
     150        m_graph.invalidateCFG();
    152151        m_graph.resetReachability();
    153152        m_graph.killUnreachableBlocks();
  • trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp

    r221601 r221602  
    10941094            break;
    10951095           
     1096        case EntrySwitch:
    10961097        case Upsilon:
    10971098            // These don't get inserted until we go into SSA.
     
    11571158        case PutDynamicVar:
    11581159        case NukeStructureAndSetButterfly:
     1160        case InitializeEntrypointArguments:
    11591161            break;
    11601162           
  • trunk/Source/JavaScriptCore/dfg/DFGSSAConversionPhase.cpp

    r221196 r221602  
    3030
    3131#include "DFGBasicBlockInlines.h"
     32#include "DFGBlockInsertionSet.h"
    3233#include "DFGGraph.h"
    3334#include "DFGInsertionSet.h"
     
    4546    SSAConversionPhase(Graph& graph)
    4647        : Phase(graph, "SSA conversion")
    47         , m_calculator(graph)
    4848        , m_insertionSet(graph)
    4949    {
     
    5353    {
    5454        RELEASE_ASSERT(m_graph.m_form == ThreadedCPS);
     55        RELEASE_ASSERT(!m_graph.m_isInSSAConversion);
     56        m_graph.m_isInSSAConversion = true;
    5557       
    5658        m_graph.clearReplacements();
    5759        m_graph.clearCPSCFGData();
     60
     61        HashMap<unsigned, BasicBlock*, WTF::IntHash<unsigned>, WTF::UnsignedWithZeroKeyHashTraits<unsigned>> entrypointIndexToArgumentsBlock;
     62
     63        {
     64            m_graph.m_numberOfEntrypoints = m_graph.m_entrypoints.size();
     65
     66            BlockInsertionSet blockInsertionSet(m_graph);
     67            BasicBlock* newRoot = blockInsertionSet.insert(0, 1.0f);
     68
     69            EntrySwitchData* entrySwitchData = m_graph.m_entrySwitchData.add();
     70            for (unsigned entrypointIndex = 0; entrypointIndex < m_graph.m_numberOfEntrypoints; ++entrypointIndex) {
     71                BasicBlock* oldRoot = m_graph.m_entrypoints[entrypointIndex];
     72                entrypointIndexToArgumentsBlock.add(entrypointIndex, oldRoot);
     73                entrySwitchData->cases.append(oldRoot);
     74
     75                ASSERT(oldRoot->predecessors.isEmpty());
     76                oldRoot->predecessors.append(newRoot);
     77
     78                if (oldRoot->isCatchEntrypoint) {
     79                    ASSERT(!!entrypointIndex);
     80                    m_graph.m_entrypointIndexToCatchBytecodeOffset.add(entrypointIndex, oldRoot->bytecodeBegin);
     81                }
     82
     83                NodeOrigin origin = oldRoot->at(0)->origin;
     84                m_insertionSet.insertNode(
     85                    0, SpecNone, InitializeEntrypointArguments, origin, OpInfo(entrypointIndex));
     86                m_insertionSet.insertNode(
     87                    0, SpecNone, ExitOK, origin);
     88                m_insertionSet.execute(oldRoot);
     89            }
     90
     91            RELEASE_ASSERT(entrySwitchData->cases[0] == m_graph.block(0)); // We strongly assume the normal call entrypoint is the first item in the list.
     92
     93            m_graph.m_argumentFormats.resize(m_graph.m_numberOfEntrypoints);
     94
     95            const bool exitOK = false;
     96            NodeOrigin origin { CodeOrigin(0), CodeOrigin(0), exitOK };
     97            newRoot->appendNode(
     98                m_graph, SpecNone, EntrySwitch, origin, OpInfo(entrySwitchData));
     99
     100            m_graph.m_entrypoints.clear();
     101            m_graph.m_entrypoints.append(newRoot);
     102
     103            blockInsertionSet.execute();
     104        }
     105
     106        SSACalculator calculator(m_graph);
     107
    58108        m_graph.ensureSSADominators();
    59109       
     
    68118                continue;
    69119           
    70             SSACalculator::Variable* ssaVariable = m_calculator.newVariable();
     120            SSACalculator::Variable* ssaVariable = calculator.newVariable();
    71121            ASSERT(ssaVariable->index() == m_variableForSSAIndex.size());
    72122            m_variableForSSAIndex.append(&variable);
     
    104154                }
    105155               
    106                 m_calculator.newDef(
     156                calculator.newDef(
    107157                    m_ssaVariableForVariable.get(variable), block, childNode);
    108158            }
     
    113163        // Decide where Phis are to be inserted. This creates the Phi's but doesn't insert them
    114164        // yet. We will later know where to insert based on where SSACalculator tells us to.
    115         m_calculator.computePhis(
     165        calculator.computePhis(
    116166            [&] (SSACalculator::Variable* ssaVariable, BasicBlock* block) -> Node* {
    117167                VariableAccessData* variable = m_variableForSSAIndex[ssaVariable->index()];
     
    168218                dataLog("    ", i, ": ", VariableAccessDataDump(m_graph, m_variableForSSAIndex[i]), "\n");
    169219            dataLog("\n");
    170             dataLog("SSA calculator: ", m_calculator, "\n");
     220            dataLog("SSA calculator: ", calculator, "\n");
    171221        }
    172222       
     
    221271                   
    222272                    SSACalculator::Variable* ssaVariable = m_ssaVariableForVariable.get(variable);
    223                     SSACalculator::Def* def = m_calculator.reachingDefAtHead(block, ssaVariable);
     273                    SSACalculator::Def* def = calculator.reachingDefAtHead(block, ssaVariable);
    224274                    if (!def) {
    225275                        // If we are required to insert a Phi, then we won't have a reaching def
     
    247297            // flushed, we also insert a MovHint.
    248298            size_t phiInsertionPoint = 0;
    249             for (SSACalculator::Def* phiDef : m_calculator.phisForBlock(block)) {
     299            for (SSACalculator::Def* phiDef : calculator.phisForBlock(block)) {
    250300                VariableAccessData* variable = m_variableForSSAIndex[phiDef->variable()->index()];
    251301               
     
    347397            for (unsigned successorIndex = block->numSuccessors(); successorIndex--;) {
    348398                BasicBlock* successorBlock = block->successor(successorIndex);
    349                 for (SSACalculator::Def* phiDef : m_calculator.phisForBlock(successorBlock)) {
     399                for (SSACalculator::Def* phiDef : calculator.phisForBlock(successorBlock)) {
    350400                    Node* phiNode = phiDef->value();
    351401                    SSACalculator::Variable* ssaVariable = phiDef->variable();
     
    384434        }
    385435
    386         // FIXME: Support multiple entrypoints in DFG SSA:
    387         // https://bugs.webkit.org/show_bug.cgi?id=175396
    388         RELEASE_ASSERT(m_graph.m_entrypoints.size() == 1);
    389         auto& arguments = m_graph.m_entrypointToArguments.find(m_graph.block(0))->value;
    390         m_graph.m_argumentFormats.resize(arguments.size());
    391         for (unsigned i = arguments.size(); i--;) {
    392             FlushFormat format = FlushedJSValue;
    393 
    394             Node* node = m_argumentMapping.get(arguments[i]);
    395            
    396             RELEASE_ASSERT(node);
    397             format = node->stackAccessData()->format;
    398            
    399             m_graph.m_argumentFormats[i] = format;
    400             arguments[i] = node; // Record the load that loads the arguments for the benefit of exit profiling.
    401         }
    402        
     436        for (auto& pair : entrypointIndexToArgumentsBlock) {
     437            unsigned entrypointIndex = pair.key;
     438            BasicBlock* oldRoot = pair.value;
     439            ArgumentsVector& arguments = m_graph.m_entrypointToArguments.find(oldRoot)->value;
     440            Vector<FlushFormat> argumentFormats;
     441            argumentFormats.reserveInitialCapacity(arguments.size());
     442            for (unsigned i = 0; i < arguments.size(); ++i) {
     443                Node* node = m_argumentMapping.get(arguments[i]);
     444                RELEASE_ASSERT(node);
     445                argumentFormats.uncheckedAppend(node->stackAccessData()->format);
     446            }
     447            m_graph.m_argumentFormats[entrypointIndex] = WTFMove(argumentFormats);
     448        }
     449
     450        m_graph.m_entrypointToArguments.clear();
     451
     452        RELEASE_ASSERT(m_graph.m_isInSSAConversion);
     453        m_graph.m_isInSSAConversion = false;
     454
    403455        m_graph.m_form = SSA;
    404456
     
    412464
    413465private:
    414     SSACalculator m_calculator;
    415466    InsertionSet m_insertionSet;
    416467    HashMap<VariableAccessData*, SSACalculator::Variable*> m_ssaVariableForVariable;
     
    422473bool performSSAConversion(Graph& graph)
    423474{
    424     RELEASE_ASSERT(!graph.m_isInSSAConversion);
    425     graph.m_isInSSAConversion = true;
    426475    bool result = runPhase<SSAConversionPhase>(graph);
    427     RELEASE_ASSERT(graph.m_isInSSAConversion);
    428     graph.m_isInSSAConversion = false;
    429476    return result;
    430477}
  • trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h

    r221601 r221602  
    312312    case Branch:
    313313    case Switch:
     314    case EntrySwitch:
    314315    case Return:
    315316    case TailCall:
     
    400401    case AtomicsXor:
    401402    case AtomicsIsLockFree:
     403    case InitializeEntrypointArguments:
    402404        return true;
    403405
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp

    r221601 r221602  
    19321932
    19331933    m_jit.jitCode()->finalizeOSREntrypoints();
     1934    m_jit.jitCode()->common.finalizeCatchEntrypoints();
    19341935
    19351936    ASSERT(osrEntryIndex == m_osrEntryHeads.size());
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp

    r221601 r221602  
    56515651        GPRReg payloadGPR = payload.gpr();
    56525652
    5653         JSValue* ptr = &reinterpret_cast<JSValue*>(m_jit.jitCode()->catchOSREntryBuffer->dataBuffer())[node->catchOSREntryIndex()];
     5653        JSValue* ptr = &reinterpret_cast<JSValue*>(m_jit.jitCode()->common.catchOSREntryBuffer->dataBuffer())[node->catchOSREntryIndex()];
    56545654        m_jit.move(CCallHelpers::TrustedImmPtr(ptr), tempGPR);
    56555655        m_jit.load32(CCallHelpers::Address(tempGPR, TagOffset), tagGPR);
     
    57045704    case AtomicsXor:
    57055705    case IdentityWithProfile:
     5706    case InitializeEntrypointArguments:
     5707    case EntrySwitch:
    57065708        DFG_CRASH(m_jit.graph(), node, "unexpected node in DFG backend");
    57075709        break;
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp

    r221601 r221602  
    60076007
    60086008    case ExtractCatchLocal: {
    6009         JSValue* ptr = &reinterpret_cast<JSValue*>(m_jit.jitCode()->catchOSREntryBuffer->dataBuffer())[node->catchOSREntryIndex()];
     6009        JSValue* ptr = &reinterpret_cast<JSValue*>(m_jit.jitCode()->common.catchOSREntryBuffer->dataBuffer())[node->catchOSREntryIndex()];
    60106010        GPRTemporary temp(this);
    60116011        GPRReg tempGPR = temp.gpr();
     
    61146114
    61156115    case LastNodeType:
     6116    case EntrySwitch:
     6117    case InitializeEntrypointArguments:
    61166118    case Phi:
    61176119    case Upsilon:
  • trunk/Source/JavaScriptCore/dfg/DFGStaticExecutionCountEstimationPhase.cpp

    r221196 r221602  
    8181                break;
    8282            }
     83           
     84            case EntrySwitch: {
     85                DFG_CRASH(m_graph, terminal, "Unexpected EntrySwitch in CPS form.");
     86                break;
     87            }
    8388
    8489            default:
  • trunk/Source/JavaScriptCore/dfg/DFGValidate.cpp

    r221196 r221602  
    8585
    8686        VALIDATE((m_graph.block(0)), m_graph.isEntrypoint(m_graph.block(0)));
     87        VALIDATE((m_graph.block(0)), m_graph.block(0) == m_graph.m_entrypoints[0]);
     88
     89        for (BasicBlock* block : m_graph.m_entrypoints)
     90            VALIDATE((block), block->predecessors.isEmpty());
    8791
    8892        // Validate that all local variables at the head of all entrypoints are dead.
     
    550554                case KillStack:
    551555                case GetStack:
     556                case EntrySwitch:
     557                case InitializeEntrypointArguments:
    552558                    VALIDATE((node), !"unexpected node type in CPS");
    553559                    break;
     
    640646        // https://bugs.webkit.org/show_bug.cgi?id=123471
    641647       
     648        VALIDATE((), m_graph.m_entrypoints.size() == 1);
     649        VALIDATE((), m_graph.m_entrypoints[0] == m_graph.block(0));
     650        VALIDATE((), !m_graph.m_argumentFormats.isEmpty()); // We always have at least one entrypoint.
     651
     652        for (unsigned entrypointIndex : m_graph.m_entrypointIndexToCatchBytecodeOffset.keys())
     653            VALIDATE((), entrypointIndex > 0); // By convention, 0 is the entrypoint index for the op_enter entrypoint, which can not be in a catch.
     654
    642655        for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) {
    643656            BasicBlock* block = m_graph.block(blockIndex);
     
    741754                }
    742755
     756                case EntrySwitch:
     757                    VALIDATE((node), node->entrySwitchData()->cases.size() == m_graph.m_numberOfEntrypoints);
     758                    break;
     759
     760                case InitializeEntrypointArguments:
     761                    VALIDATE((node), node->entrypointIndex() < m_graph.m_numberOfEntrypoints);
     762                    break;
     763
    743764                default:
    744765                    m_graph.doToChildren(
     
    781802    }
    782803   
     804    void reportValidationContext() { }
     805
    783806    void reportValidationContext(Node* node)
    784807    {
  • trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp

    r221601 r221602  
    112112    case Upsilon:
    113113    case ExtractOSREntryLocal:
     114    case ExtractCatchLocal:
    114115    case LoopHint:
    115116    case SkipScope:
     
    246247    case GetMyArgumentByValOutOfBounds:
    247248    case ForwardVarargs:
     249    case EntrySwitch:
    248250    case Switch:
    249251    case TypeOf:
     
    302304    case AtomicsXor:
    303305    case AtomicsIsLockFree:
     306    case InitializeEntrypointArguments:
    304307        // These are OK.
    305308        break;
  • trunk/Source/JavaScriptCore/ftl/FTLCompile.cpp

    r221528 r221602  
    143143
    144144    state.finalizer->b3CodeLinkBuffer = std::make_unique<LinkBuffer>(jit, codeBlock, JITCompilationCanFail);
     145
    145146    if (state.finalizer->b3CodeLinkBuffer->didFailToAllocate()) {
    146147        state.allocationFailed = true;
     
    153154
    154155    state.generatedFunction = bitwise_cast<GeneratedFunction>(
    155         state.finalizer->b3CodeLinkBuffer->entrypoint().executableAddress());
     156        state.finalizer->b3CodeLinkBuffer->locationOf(state.proc->entrypointLabel(0)));
    156157    state.jitCode->initializeB3Byproducts(state.proc->releaseByproducts());
     158
     159    for (auto pair : state.graph.m_entrypointIndexToCatchBytecodeOffset) {
     160        unsigned catchBytecodeOffset = pair.value;
     161        unsigned entrypointIndex = pair.key;
     162        Vector<FlushFormat> argumentFormats = state.graph.m_argumentFormats[entrypointIndex];
     163        state.jitCode->common.appendCatchEntrypoint(
     164            catchBytecodeOffset, state.finalizer->b3CodeLinkBuffer->locationOf(state.proc->entrypointLabel(entrypointIndex)).executableAddress(), WTFMove(argumentFormats));
     165    }
     166    state.jitCode->common.finalizeCatchEntrypoints();
    157167
    158168    if (B3::Air::Disassembler* disassembler = state.proc->code().disassembler()) {
  • trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp

    r221601 r221602  
    2929#if ENABLE(FTL_JIT)
    3030
     31#include "AirCode.h"
    3132#include "AirGenerationContext.h"
    3233#include "AllowMacroScratchRegisterUsage.h"
     
    152153        } else
    153154            name = "jsBody";
     155
     156        {
     157            m_proc.setNumEntrypoints(m_graph.m_numberOfEntrypoints);
     158            CodeBlock* codeBlock = m_graph.m_codeBlock;
     159
     160            RefPtr<B3::Air::PrologueGenerator> catchPrologueGenerator = createSharedTask<B3::Air::PrologueGeneratorFunction>(
     161                [codeBlock] (CCallHelpers& jit, B3::Air::Code& code) {
     162                    AllowMacroScratchRegisterUsage allowScratch(jit);
     163                    jit.addPtr(CCallHelpers::TrustedImm32(-code.frameSize()), GPRInfo::callFrameRegister, CCallHelpers::stackPointerRegister);
     164                    jit.emitSave(code.calleeSaveRegisterAtOffsetList());
     165                    jit.emitPutToCallFrameHeader(codeBlock, CallFrameSlot::codeBlock);
     166                });
     167
     168            for (unsigned catchEntrypointIndex : m_graph.m_entrypointIndexToCatchBytecodeOffset.keys()) {
     169                RELEASE_ASSERT(catchEntrypointIndex != 0);
     170                m_proc.code().setPrologueForEntrypoint(catchEntrypointIndex, catchPrologueGenerator);
     171            }
     172
     173            if (m_graph.m_maxLocalsForCatchOSREntry) {
     174                uint32_t numberOfLiveLocals = std::max(*m_graph.m_maxLocalsForCatchOSREntry, 1u); // Make sure we always allocate a non-null catchOSREntryBuffer.
     175                m_ftlState.jitCode->common.catchOSREntryBuffer = m_graph.m_vm.scratchBufferForSize(sizeof(JSValue) * numberOfLiveLocals);
     176            }
     177        }
    154178       
    155179        m_graph.ensureSSADominators();
     
    163187        m_out.setFrequency(1);
    164188       
    165         m_prologue = m_out.newBlock();
     189        LBasicBlock prologue = m_out.newBlock();
     190        LBasicBlock callEntrypointArgumentSpeculations = m_out.newBlock();
    166191        m_handleExceptions = m_out.newBlock();
    167192
     
    177202        m_out.setFrequency(1);
    178203       
    179         m_out.appendTo(m_prologue, m_handleExceptions);
    180         m_out.initializeConstants(m_proc, m_prologue);
     204        m_out.appendTo(prologue, callEntrypointArgumentSpeculations);
     205        m_out.initializeConstants(m_proc, prologue);
    181206        createPhiVariables();
    182207
     
    260285
    261286        LBasicBlock firstDFGBasicBlock = lowBlock(m_graph.block(0));
    262         // Check Arguments.
    263         availabilityMap().clear();
    264         availabilityMap().m_locals = Operands<Availability>(codeBlock()->numParameters(), 0);
    265         for (unsigned i = codeBlock()->numParameters(); i--;) {
    266             availabilityMap().m_locals.argument(i) =
    267                 Availability(FlushedAt(FlushedJSValue, virtualRegisterForArgument(i)));
    268         }
    269         m_node = nullptr;
    270         m_origin = NodeOrigin(CodeOrigin(0), CodeOrigin(0), true);
    271         auto& arguments = m_graph.m_entrypointToArguments.find(m_graph.block(0))->value;
    272         for (unsigned i = codeBlock()->numParameters(); i--;) {
    273             Node* node = arguments[i];
    274             m_out.setOrigin(node);
    275             VirtualRegister operand = virtualRegisterForArgument(i);
    276            
    277             LValue jsValue = m_out.load64(addressFor(operand));
    278            
    279             if (node) {
    280                 DFG_ASSERT(m_graph, node, operand == node->stackAccessData()->machineLocal);
     287
     288        {
     289            Vector<LBasicBlock> successors(m_graph.m_numberOfEntrypoints);
     290            successors[0] = callEntrypointArgumentSpeculations;
     291            for (unsigned i = 1; i < m_graph.m_numberOfEntrypoints; ++i) {
     292                // Currently, the only other entrypoint is an op_catch entrypoint.
     293                // We do OSR entry at op_catch, and we prove argument formats before
     294                // jumping to FTL code, so we don't need to check argument types here
     295                // for these entrypoints.
     296                successors[i] = firstDFGBasicBlock;
     297            }
     298
     299            m_out.entrySwitch(successors);
     300            m_out.appendTo(callEntrypointArgumentSpeculations, m_handleExceptions);
     301
     302            m_node = nullptr;
     303            m_origin = NodeOrigin(CodeOrigin(0), CodeOrigin(0), true);
     304
     305            // Check Arguments.
     306            availabilityMap().clear();
     307            availabilityMap().m_locals = Operands<Availability>(codeBlock()->numParameters(), 0);
     308            for (unsigned i = codeBlock()->numParameters(); i--;) {
     309                availabilityMap().m_locals.argument(i) =
     310                    Availability(FlushedAt(FlushedJSValue, virtualRegisterForArgument(i)));
     311            }
     312
     313            for (unsigned i = codeBlock()->numParameters(); i--;) {
     314                MethodOfGettingAValueProfile profile(&m_graph.m_profiledBlock->valueProfileForArgument(i));
     315                VirtualRegister operand = virtualRegisterForArgument(i);
     316                LValue jsValue = m_out.load64(addressFor(operand));
    281317               
    282                 // This is a hack, but it's an effective one. It allows us to do CSE on the
    283                 // primordial load of arguments. This assumes that the GetLocal that got put in
    284                 // place of the original SetArgument doesn't have any effects before it. This
    285                 // should hold true.
    286                 m_loadedArgumentValues.add(node, jsValue);
     318                switch (m_graph.m_argumentFormats[0][i]) {
     319                case FlushedInt32:
     320                    speculate(BadType, jsValueValue(jsValue), profile, isNotInt32(jsValue));
     321                    break;
     322                case FlushedBoolean:
     323                    speculate(BadType, jsValueValue(jsValue), profile, isNotBoolean(jsValue));
     324                    break;
     325                case FlushedCell:
     326                    speculate(BadType, jsValueValue(jsValue), profile, isNotCell(jsValue));
     327                    break;
     328                case FlushedJSValue:
     329                    break;
     330                default:
     331                    DFG_CRASH(m_graph, nullptr, "Bad flush format for argument");
     332                    break;
     333                }
    287334            }
    288            
    289             switch (m_graph.m_argumentFormats[i]) {
    290             case FlushedInt32:
    291                 speculate(BadType, jsValueValue(jsValue), node, isNotInt32(jsValue));
    292                 break;
    293             case FlushedBoolean:
    294                 speculate(BadType, jsValueValue(jsValue), node, isNotBoolean(jsValue));
    295                 break;
    296             case FlushedCell:
    297                 speculate(BadType, jsValueValue(jsValue), node, isNotCell(jsValue));
    298                 break;
    299             case FlushedJSValue:
    300                 break;
    301             default:
    302                 DFG_CRASH(m_graph, node, "Bad flush format for argument");
    303                 break;
    304             }
    305         }
    306         m_out.jump(firstDFGBasicBlock);
     335            m_out.jump(firstDFGBasicBlock);
     336        }
     337
    307338
    308339        m_out.appendTo(m_handleExceptions, firstDFGBasicBlock);
     
    513544            compileExtractOSREntryLocal();
    514545            break;
     546        case ExtractCatchLocal:
     547            compileExtractCatchLocal();
     548            break;
    515549        case GetStack:
    516550            compileGetStack();
     
    940974        case DFG::Switch:
    941975            compileSwitch();
     976            break;
     977        case DFG::EntrySwitch:
     978            compileEntrySwitch();
    942979            break;
    943980        case DFG::Return:
     
    11561193        case BottomValue:
    11571194        case KillStack:
     1195        case InitializeEntrypointArguments:
    11581196            break;
    11591197        default:
     
    15261564        setJSValue(m_out.load64(m_out.absolute(buffer + m_node->unlinkedLocal().toLocal())));
    15271565    }
     1566
     1567    void compileExtractCatchLocal()
     1568    {
     1569        EncodedJSValue* buffer = static_cast<EncodedJSValue*>(m_ftlState.jitCode->common.catchOSREntryBuffer->dataBuffer());
     1570        setJSValue(m_out.load64(m_out.absolute(buffer + m_node->catchOSREntryIndex())));
     1571    }
    15281572   
    15291573    void compileGetStack()
    15301574    {
    1531         // GetLocals arise only for captured variables and arguments. For arguments, we might have
    1532         // already loaded it.
    1533         if (LValue value = m_loadedArgumentValues.get(m_node)) {
    1534             setJSValue(value);
    1535             return;
    1536         }
    1537        
    15381575        StackAccessData* data = m_node->stackAccessData();
    15391576        AbstractValue& value = m_state.variables().operand(data->local);
     
    77917828       
    77927829        DFG_CRASH(m_graph, m_node, "Bad switch kind");
     7830    }
     7831
     7832    void compileEntrySwitch()
     7833    {
     7834        Vector<LBasicBlock> successors;
     7835        for (DFG::BasicBlock* successor : m_node->entrySwitchData()->cases)
     7836            successors.append(lowBlock(successor));
     7837        m_out.entrySwitch(successors);
    77937838    }
    77947839   
     
    1261212657        appendOSRExit(kind, lowValue, highValue, failCondition, m_origin);
    1261312658    }
     12659
     12660    void speculate(
     12661        ExitKind kind, FormattedValue lowValue, const MethodOfGettingAValueProfile& profile, LValue failCondition)
     12662    {
     12663        appendOSRExit(kind, lowValue, profile, failCondition, m_origin);
     12664    }
    1261412665   
    1261512666    void terminate(ExitKind kind)
     
    1413614187    OSRExitDescriptor* appendOSRExitDescriptor(FormattedValue lowValue, Node* highValue)
    1413714188    {
     14189        return appendOSRExitDescriptor(lowValue, m_graph.methodOfGettingAValueProfileFor(m_node, highValue));
     14190    }
     14191
     14192    OSRExitDescriptor* appendOSRExitDescriptor(FormattedValue lowValue, const MethodOfGettingAValueProfile& profile)
     14193    {
    1413814194        return &m_ftlState.jitCode->osrExitDescriptors.alloc(
    14139             lowValue.format(), m_graph.methodOfGettingAValueProfileFor(m_node, highValue),
     14195            lowValue.format(), profile,
    1414014196            availabilityMap().m_locals.numberOfArguments(),
    1414114197            availabilityMap().m_locals.numberOfLocals());
    1414214198    }
    14143    
     14199
    1414414200    void appendOSRExit(
    1414514201        ExitKind kind, FormattedValue lowValue, Node* highValue, LValue failCondition,
     14202        NodeOrigin origin, bool isExceptionHandler = false)
     14203    {
     14204        return appendOSRExit(kind, lowValue, m_graph.methodOfGettingAValueProfileFor(m_node, highValue),
     14205            failCondition, origin, isExceptionHandler);
     14206    }
     14207   
     14208    void appendOSRExit(
     14209        ExitKind kind, FormattedValue lowValue, const MethodOfGettingAValueProfile& profile, LValue failCondition,
    1414614210        NodeOrigin origin, bool isExceptionHandler = false)
    1414714211    {
     
    1418014244
    1418114245        blessSpeculation(
    14182             m_out.speculate(failCondition), kind, lowValue, highValue, origin);
     14246            m_out.speculate(failCondition), kind, lowValue, profile, origin);
    1418314247    }
    1418414248
    1418514249    void blessSpeculation(CheckValue* value, ExitKind kind, FormattedValue lowValue, Node* highValue, NodeOrigin origin)
    1418614250    {
    14187         OSRExitDescriptor* exitDescriptor = appendOSRExitDescriptor(lowValue, highValue);
     14251        blessSpeculation(value, kind, lowValue, m_graph.methodOfGettingAValueProfileFor(m_node, highValue), origin);
     14252    }
     14253
     14254    void blessSpeculation(CheckValue* value, ExitKind kind, FormattedValue lowValue, const MethodOfGettingAValueProfile& profile, NodeOrigin origin)
     14255    {
     14256        OSRExitDescriptor* exitDescriptor = appendOSRExitDescriptor(lowValue, profile);
    1418814257       
    1418914258        value->appendColdAnys(buildExitArguments(exitDescriptor, origin.forExit, lowValue));
     
    1467214741    Procedure& m_proc;
    1467314742   
    14674     LBasicBlock m_prologue;
    1467514743    LBasicBlock m_handleExceptions;
    1467614744    HashMap<DFG::BasicBlock*, LBasicBlock> m_blocks;
     
    1468914757    HashMap<Node*, LoweredNodeValue> m_doubleValues;
    1469014758   
    14691     // This is a bit of a hack. It prevents B3 from having to do CSE on loading of arguments.
    14692     // It's nice to have these optimizations on our end because we can guarantee them a bit better.
    14693     // Probably also saves B3 compile time.
    14694     HashMap<Node*, LValue> m_loadedArgumentValues;
    14695    
    1469614759    HashMap<Node*, LValue> m_phis;
    1469714760   
  • trunk/Source/JavaScriptCore/ftl/FTLOutput.cpp

    r220625 r221602  
    862862}
    863863
     864void Output::entrySwitch(const Vector<LBasicBlock>& cases)
     865{
     866    RELEASE_ASSERT(cases.size() == m_proc.numEntrypoints());
     867    m_block->appendNew<Value>(m_proc, EntrySwitch, origin());
     868    for (LBasicBlock block : cases)
     869        m_block->appendSuccessor(FrequentedBlock(block));
     870}
     871
    864872} } // namespace JSC::FTL
    865873
  • trunk/Source/JavaScriptCore/ftl/FTLOutput.h

    r220625 r221602  
    430430    }
    431431
     432    void entrySwitch(const Vector<LBasicBlock>&);
     433
    432434    void ret(LValue);
    433435
  • trunk/Source/JavaScriptCore/jit/JITOperations.cpp

    r221196 r221602  
    4343#include "EvalCodeBlock.h"
    4444#include "ExceptionFuzz.h"
     45#include "FTLOSREntry.h"
    4546#include "FrameTracers.h"
    4647#include "FunctionCodeBlock.h"
     
    15341535
    15351536    CodeBlock* optimizedReplacement = exec->codeBlock()->replacement();
    1536     if (optimizedReplacement->jitType() != JITCode::DFGJIT)
    1537         return nullptr;
    1538 
    1539     return static_cast<char*>(DFG::prepareCatchOSREntry(exec, optimizedReplacement, bytecodeIndex));
     1537    switch (optimizedReplacement->jitType()) {
     1538    case JITCode::DFGJIT:
     1539    case JITCode::FTLJIT:
     1540        return static_cast<char*>(DFG::prepareCatchOSREntry(exec, optimizedReplacement, bytecodeIndex));
     1541    default:
     1542        break;
     1543    }
     1544    return nullptr;
    15401545}
    15411546
     
    15471552    CodeBlock* codeBlock = exec->codeBlock();
    15481553    CodeBlock* optimizedReplacement = codeBlock->replacement();
    1549     if (optimizedReplacement->jitType() == JITCode::DFGJIT)
     1554
     1555    switch (optimizedReplacement->jitType()) {
     1556    case JITCode::DFGJIT:
     1557    case JITCode::FTLJIT:
    15501558        return static_cast<char*>(DFG::prepareCatchOSREntry(exec, optimizedReplacement, bytecodeIndex));
     1559    default:
     1560        break;
     1561    }
    15511562
    15521563    codeBlock->ensureCatchLivenessIsComputedForBytecodeOffset(bytecodeIndex);
Note: See TracChangeset for help on using the changeset viewer.