Changeset 221602 in webkit for trunk/Source/JavaScriptCore/b3


Ignore:
Timestamp:
Sep 4, 2017, 8:21:33 PM (8 years ago)
Author:
[email protected]
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/b3/air
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • 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);
Note: See TracChangeset for help on using the changeset viewer.