Ignore:
Timestamp:
Sep 24, 2015, 2:42:59 PM (10 years ago)
Author:
[email protected]
Message:

[ES6] Implement tail calls in the DFG
https://bugs.webkit.org/show_bug.cgi?id=148663

Reviewed by Filip Pizlo.

jsc-tailcall: Implement the tail call opcodes in the DFG
https://bugs.webkit.org/show_bug.cgi?id=146850

This patch adds support for tail calls in the DFG. This requires a slightly high number of nodes:

  • TailCall and TailCallVarargs are straightforward. They are terminal nodes and have the semantics of an actual tail call.
  • TailCallInlinedCaller and TailCallVarargsInlinedCaller are here to perform a tail call inside an inlined function. They are non terminal nodes, and are performing the call as a regular call after popping an appropriate number of inlined tail call frames.
  • TailCallForwardVarargs and TailCallForwardVarargsInlinedCaller are the extension of TailCallVarargs and TailCallVarargsInlinedCaller to enable the varargs forwarding optimization so that we don't lose performance with a tail call instead of a regular call.

This also required two broad kind of changes:

  • Changes in the JIT itself (DFGSpeculativeJIT) are pretty straightforward since they are just an extension of the baseline JIT changes introduced previously.
  • Changes in the runtime are mostly related with handling inline call frames. The idea here is that we have a special TailCall type for call frames that indicates to the various pieces of code walking the inline call frame that they should (recursively) skip the caller in their analysis.
  • bytecode/CallMode.h:

(JSC::specializationKindFor):

  • bytecode/CodeOrigin.cpp:

(JSC::CodeOrigin::inlineDepthForCallFrame):
(JSC::CodeOrigin::isApproximatelyEqualTo):
(JSC::CodeOrigin::approximateHash):
(JSC::CodeOrigin::inlineStack):

  • bytecode/CodeOrigin.h:
  • bytecode/InlineCallFrame.cpp:

(JSC::InlineCallFrame::dumpInContext):
(WTF::printInternal):

  • bytecode/InlineCallFrame.h:

(JSC::InlineCallFrame::callModeFor):
(JSC::InlineCallFrame::kindFor):
(JSC::InlineCallFrame::varargsKindFor):
(JSC::InlineCallFrame::specializationKindFor):
(JSC::InlineCallFrame::isVarargs):
(JSC::InlineCallFrame::isTail):
(JSC::InlineCallFrame::computeCallerSkippingDeadFrames):
(JSC::InlineCallFrame::getCallerSkippingDeadFrames):
(JSC::InlineCallFrame::getCallerInlineFrameSkippingDeadFrames):

  • dfg/DFGAbstractInterpreterInlines.h:

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

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

(JSC::DFG::BasicBlock::findTerminal):

  • dfg/DFGByteCodeParser.cpp:

(JSC::DFG::ByteCodeParser::inlineCallFrame):
(JSC::DFG::ByteCodeParser::allInlineFramesAreTailCalls):
(JSC::DFG::ByteCodeParser::currentCodeOrigin):
(JSC::DFG::ByteCodeParser::addCallWithoutSettingResult):
(JSC::DFG::ByteCodeParser::addCall):
(JSC::DFG::ByteCodeParser::getPredictionWithoutOSRExit):
(JSC::DFG::ByteCodeParser::getPrediction):
(JSC::DFG::ByteCodeParser::handleCall):
(JSC::DFG::ByteCodeParser::handleVarargsCall):
(JSC::DFG::ByteCodeParser::emitArgumentPhantoms):
(JSC::DFG::ByteCodeParser::inliningCost):
(JSC::DFG::ByteCodeParser::inlineCall):
(JSC::DFG::ByteCodeParser::attemptToInlineCall):
(JSC::DFG::ByteCodeParser::parseBlock):
(JSC::DFG::ByteCodeParser::InlineStackEntry::InlineStackEntry):
(JSC::DFG::ByteCodeParser::parseCodeBlock):

  • dfg/DFGCapabilities.cpp:

(JSC::DFG::capabilityLevel):

  • dfg/DFGClobberize.h:

(JSC::DFG::clobberize):

  • dfg/DFGDoesGC.cpp:

(JSC::DFG::doesGC):

  • dfg/DFGFixupPhase.cpp:

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

  • dfg/DFGGraph.cpp:

(JSC::DFG::Graph::isLiveInBytecode):

  • dfg/DFGGraph.h:

(JSC::DFG::Graph::forAllLocalsLiveInBytecode):

  • dfg/DFGInPlaceAbstractState.cpp:

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

  • dfg/DFGJITCompiler.cpp:

(JSC::DFG::JITCompiler::willCatchExceptionInMachineFrame):

  • dfg/DFGLiveCatchVariablePreservationPhase.cpp:

(JSC::DFG::FlushLiveCatchVariablesInsertionPhase::willCatchException):

  • dfg/DFGNode.h:

(JSC::DFG::Node::hasCallVarargsData):
(JSC::DFG::Node::isTerminal):
(JSC::DFG::Node::hasHeapPrediction):

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

(JSC::DFG::handleExitCounts):
(JSC::DFG::reifyInlinedCallFrames):
(JSC::DFG::osrWriteBarrier):

  • dfg/DFGOSRExitPreparation.cpp:

(JSC::DFG::prepareCodeOriginForOSRExit):

  • dfg/DFGOperations.cpp:
  • dfg/DFGPreciseLocalClobberize.h:

(JSC::DFG::PreciseLocalClobberizeAdaptor::readTop):

  • dfg/DFGPredictionPropagationPhase.cpp:

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

  • dfg/DFGSafeToExecute.h:

(JSC::DFG::safeToExecute):

  • dfg/DFGSpeculativeJIT32_64.cpp:

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

  • dfg/DFGSpeculativeJIT64.cpp:

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

  • dfg/DFGValidate.cpp:

(JSC::DFG::Validate::validateSSA):

  • dfg/DFGVarargsForwardingPhase.cpp:
  • interpreter/CallFrame.cpp:

(JSC::CallFrame::bytecodeOffset):

  • interpreter/StackVisitor.cpp:

(JSC::StackVisitor::gotoNextFrame):

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/bytecode/InlineCallFrame.h

    r189518 r190220  
    5050        Call,
    5151        Construct,
     52        TailCall,
    5253        CallVarargs,
    5354        ConstructVarargs,
     55        TailCallVarargs,
    5456       
    5557        // For these, the stackOffset incorporates the argument count plus the true return PC
     
    5860        SetterCall
    5961    };
    60    
    61     static Kind kindFor(CodeSpecializationKind kind)
    62     {
    63         switch (kind) {
    64         case CodeForCall:
    65             return Call;
    66         case CodeForConstruct:
    67             return Construct;
    68         }
    69         RELEASE_ASSERT_NOT_REACHED();
    70         return Call;
    71     }
    72    
    73     static Kind varargsKindFor(CodeSpecializationKind kind)
    74     {
    75         switch (kind) {
    76         case CodeForCall:
    77             return CallVarargs;
    78         case CodeForConstruct:
    79             return ConstructVarargs;
    80         }
    81         RELEASE_ASSERT_NOT_REACHED();
    82         return Call;
    83     }
    84    
    85     static CodeSpecializationKind specializationKindFor(Kind kind)
     62
     63    static CallMode callModeFor(Kind kind)
    8664    {
    8765        switch (kind) {
    8866        case Call:
    8967        case CallVarargs:
     68        case GetterCall:
     69        case SetterCall:
     70            return CallMode::Regular;
     71        case TailCall:
     72        case TailCallVarargs:
     73            return CallMode::Tail;
     74        case Construct:
     75        case ConstructVarargs:
     76            return CallMode::Construct;
     77        }
     78        RELEASE_ASSERT_NOT_REACHED();
     79    }
     80
     81    static Kind kindFor(CallMode callMode)
     82    {
     83        switch (callMode) {
     84        case CallMode::Regular:
     85            return Call;
     86        case CallMode::Construct:
     87            return Construct;
     88        case CallMode::Tail:
     89            return TailCall;
     90        }
     91        RELEASE_ASSERT_NOT_REACHED();
     92    }
     93   
     94    static Kind varargsKindFor(CallMode callMode)
     95    {
     96        switch (callMode) {
     97        case CallMode::Regular:
     98            return CallVarargs;
     99        case CallMode::Construct:
     100            return ConstructVarargs;
     101        case CallMode::Tail:
     102            return TailCallVarargs;
     103        }
     104        RELEASE_ASSERT_NOT_REACHED();
     105    }
     106   
     107    static CodeSpecializationKind specializationKindFor(Kind kind)
     108    {
     109        switch (kind) {
     110        case Call:
     111        case CallVarargs:
     112        case TailCall:
     113        case TailCallVarargs:
    90114        case GetterCall:
    91115        case SetterCall:
     
    96120        }
    97121        RELEASE_ASSERT_NOT_REACHED();
    98         return CodeForCall;
    99122    }
    100123   
     
    103126        switch (kind) {
    104127        case CallVarargs:
     128        case TailCallVarargs:
    105129        case ConstructVarargs:
    106130            return true;
     
    109133        }
    110134    }
     135
     136    static bool isTail(Kind kind)
     137    {
     138        switch (kind) {
     139        case TailCall:
     140        case TailCallVarargs:
     141            return true;
     142        default:
     143            return false;
     144        }
     145    }
     146    bool isTail() const
     147    {
     148        return isTail(static_cast<Kind>(kind));
     149    }
     150
     151    static CodeOrigin* computeCallerSkippingDeadFrames(InlineCallFrame* inlineCallFrame)
     152    {
     153        CodeOrigin* codeOrigin;
     154        bool tailCallee;
     155        do {
     156            tailCallee = inlineCallFrame->isTail();
     157            codeOrigin = &inlineCallFrame->directCaller;
     158            inlineCallFrame = codeOrigin->inlineCallFrame;
     159        } while (inlineCallFrame && tailCallee);
     160        if (tailCallee)
     161            return nullptr;
     162        return codeOrigin;
     163    }
     164
     165    CodeOrigin* getCallerSkippingDeadFrames()
     166    {
     167        return computeCallerSkippingDeadFrames(this);
     168    }
     169
     170    InlineCallFrame* getCallerInlineFrameSkippingDeadFrames()
     171    {
     172        CodeOrigin* caller = getCallerSkippingDeadFrames();
     173        return caller ? caller->inlineCallFrame : nullptr;
     174    }
    111175   
    112176    Vector<ValueRecovery> arguments; // Includes 'this'.
    113177    WriteBarrier<ScriptExecutable> executable;
    114178    ValueRecovery calleeRecovery;
    115     CodeOrigin caller;
     179    CodeOrigin directCaller;
    116180
    117181    signed stackOffset : 28;
Note: See TracChangeset for help on using the changeset viewer.