Ignore:
Timestamp:
Dec 12, 2016, 1:46:45 PM (9 years ago)
Author:
[email protected]
Message:

REGRESSION(r209653): speedometer crashes making virtual slow path tailcalls
https://bugs.webkit.org/show_bug.cgi?id=165748

Reviewed by Filip Pizlo.

JSTests:

New regression test.

  • stress/regress-165748.js: Added.

(sum1):
(sum2):
(sum3):
(sum4):
(sum5):
(sum6):
(tailCaller):
(test):

Source/JavaScriptCore:

The virtual slow path for tailcalls always passes arguments on the stack.
The fix here is to link to the stack argument entrypoint instead of a register
argument entrypoint.

While fixing this bug, I found that we weren't clearing the code origin when
shuffling the call frame for a register argument tailcall.

Also rolling back in r209653, r209654, r209663, and r209673.

  • jit/CallFrameShuffler.cpp:

(JSC::CallFrameShuffler::prepareAny):

  • jit/ThunkGenerators.cpp:

(JSC::virtualThunkFor):

Source/WTF:

Rolling back in r209653, r209654, r209663, and r209673.

  • wtf/Platform.h:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp

    r209678 r209725  
    8181}
    8282
    83 GPRReg SpeculativeJIT::fillJSValue(Edge edge)
     83GPRReg SpeculativeJIT::fillJSValue(Edge edge, GPRReg gprToUse)
    8484{
    8585    VirtualRegister virtualRegister = edge->virtualRegister();
     
    8888    switch (info.registerFormat()) {
    8989    case DataFormatNone: {
    90         GPRReg gpr = allocate();
     90        GPRReg gpr = allocate(gprToUse);
    9191
    9292        if (edge->hasConstant()) {
     
    121121        // If not, we'll zero extend in place, so mark on the info that this is now type DataFormatInt32, not DataFormatJSInt32.
    122122        if (m_gprs.isLocked(gpr)) {
    123             GPRReg result = allocate();
     123            GPRReg result = allocate(gprToUse);
     124            m_jit.or64(GPRInfo::tagTypeNumberRegister, gpr, result);
     125            return result;
     126        }
     127        if (gprToUse != InvalidGPRReg && gpr != gprToUse) {
     128            GPRReg result = allocate(gprToUse);
    124129            m_jit.or64(GPRInfo::tagTypeNumberRegister, gpr, result);
    125130            return result;
     
    139144    case DataFormatJSBoolean: {
    140145        GPRReg gpr = info.gpr();
     146        if (gprToUse != InvalidGPRReg && gpr != gprToUse) {
     147            GPRReg result = allocate(gprToUse);
     148            m_jit.move(gpr, result);
     149            return result;
     150        }
    141151        m_gprs.lock(gpr);
    142152        return gpr;
     
    633643{
    634644    CallLinkInfo::CallType callType;
     645    ArgumentsLocation argumentsLocation = StackArgs;
    635646    bool isVarargs = false;
    636647    bool isForwardVarargs = false;
     
    715726    GPRReg calleeGPR = InvalidGPRReg;
    716727    CallFrameShuffleData shuffleData;
    717    
     728    std::optional<JSValueOperand> tailCallee;
     729    std::optional<GPRTemporary> calleeGPRTemporary;
     730
     731    incrementCounter(&m_jit, VM::DFGCaller);
     732
    718733    ExecutableBase* executable = nullptr;
    719734    FunctionExecutable* functionExecutable = nullptr;
     
    734749        unsigned numUsedStackSlots = m_jit.graph().m_nextMachineLocal;
    735750       
     751        incrementCounter(&m_jit, VM::CallVarargs);
    736752        if (isForwardVarargs) {
    737753            flushRegisters();
     
    842858
    843859        if (isTail) {
     860            incrementCounter(&m_jit, VM::TailCall);
    844861            Edge calleeEdge = m_jit.graph().child(node, 0);
    845             JSValueOperand callee(this, calleeEdge);
    846             calleeGPR = callee.gpr();
     862            // We can't get the a specific register for the callee, since that will just move
     863            // from any current register.  When we silent fill in the slow path we'll fill
     864            // the original register and won't have the callee in the right register.
     865            // Therefore we allocate a temp register for the callee and move ourselves.
     866            tailCallee.emplace(this, calleeEdge);
     867            GPRReg tailCalleeGPR = tailCallee->gpr();
     868            calleeGPR = argumentRegisterForCallee();
     869            if (tailCalleeGPR != calleeGPR)
     870                calleeGPRTemporary = GPRTemporary(this, calleeGPR);
    847871            if (!isDirect)
    848                 callee.use();
    849 
     872                tailCallee->use();
     873
     874            argumentsLocation = argumentsLocationFor(numAllocatedArgs);
     875            shuffleData.argumentsInRegisters = argumentsLocation != StackArgs;
    850876            shuffleData.tagTypeNumber = GPRInfo::tagTypeNumberRegister;
    851877            shuffleData.numLocals = m_jit.graph().frameRegisterCount();
    852             shuffleData.callee = ValueRecovery::inGPR(calleeGPR, DataFormatJS);
     878            shuffleData.callee = ValueRecovery::inGPR(tailCalleeGPR, DataFormatJS);
    853879            shuffleData.args.resize(numAllocatedArgs);
    854880
     
    865891
    866892            shuffleData.setupCalleeSaveRegisters(m_jit.codeBlock());
    867         } else {
     893        } else if (node->op() == CallEval) {
     894            // CallEval is handled with the arguments in the stack
    868895            m_jit.store32(MacroAssembler::TrustedImm32(numPassedArgs), JITCompiler::calleeFramePayloadSlot(CallFrameSlot::argumentCount));
    869896
     
    879906            for (unsigned i = numPassedArgs; i < numAllocatedArgs; ++i)
    880907                m_jit.storeTrustedValue(jsUndefined(), JITCompiler::calleeArgumentSlot(i));
     908
     909            incrementCounter(&m_jit, VM::CallEval);
     910        } else {
     911            for (unsigned i = numPassedArgs; i-- > 0;) {
     912                GPRReg platformArgGPR = argumentRegisterForFunctionArgument(i);
     913                Edge argEdge = m_jit.graph().m_varArgChildren[node->firstChild() + 1 + i];
     914                JSValueOperand arg(this, argEdge, platformArgGPR);
     915                GPRReg argGPR = arg.gpr();
     916                ASSERT(argGPR == platformArgGPR || platformArgGPR == InvalidGPRReg);
     917
     918                // Only free the non-argument registers at this point.
     919                if (platformArgGPR == InvalidGPRReg) {
     920                    use(argEdge);
     921                    m_jit.store64(argGPR, JITCompiler::calleeArgumentSlot(i));
     922                }
     923            }
     924
     925            // Use the argument edges for arguments passed in registers.
     926            for (unsigned i = numPassedArgs; i-- > 0;) {
     927                GPRReg argGPR = argumentRegisterForFunctionArgument(i);
     928                if (argGPR != InvalidGPRReg) {
     929                    Edge argEdge = m_jit.graph().m_varArgChildren[node->firstChild() + 1 + i];
     930                    use(argEdge);
     931                }
     932            }
     933
     934            GPRTemporary argCount(this, argumentRegisterForArgumentCount());
     935            GPRReg argCountGPR = argCount.gpr();
     936            m_jit.move(TrustedImm32(numPassedArgs), argCountGPR);
     937            argumentsLocation = argumentsLocationFor(numAllocatedArgs);
     938
     939            for (unsigned i = numPassedArgs; i < numAllocatedArgs; ++i) {
     940                GPRReg platformArgGPR = argumentRegisterForFunctionArgument(i);
     941
     942                // FIXME: https://bugs.webkit.org/show_bug.cgi?id=165769
     943                // Eliminate filling extra stack slots with undefined JSValues for register arguments.
     944                // The LLInt thunks aren't smart enough to know what register arguments to spill therefore
     945                // we put undefined in both the extra argument register and stack slot.
     946                if (platformArgGPR != InvalidGPRReg) {
     947                    GPRTemporary argumentTemp(this, platformArgGPR);
     948                    m_jit.move(TrustedImm64(JSValue::encode(jsUndefined())), argumentTemp.gpr());
     949                }
     950                m_jit.storeTrustedValue(jsUndefined(), JITCompiler::calleeArgumentSlot(i));
     951            }
    881952        }
    882953    }
     
    884955    if (!isTail || isVarargs || isForwardVarargs) {
    885956        Edge calleeEdge = m_jit.graph().child(node, 0);
    886         JSValueOperand callee(this, calleeEdge);
     957        JSValueOperand callee(this, calleeEdge, argumentRegisterForCallee());
    887958        calleeGPR = callee.gpr();
    888959        callee.use();
    889         m_jit.store64(calleeGPR, JITCompiler::calleeFrameSlot(CallFrameSlot::callee));
     960        if (argumentsLocation == StackArgs)
     961            m_jit.store64(calleeGPR, JITCompiler::calleeFrameSlot(CallFrameSlot::callee));
    890962
    891963        flushRegisters();
     
    914986   
    915987    CallLinkInfo* callLinkInfo = m_jit.codeBlock()->addCallLinkInfo();
    916     callLinkInfo->setUpCall(callType, m_currentNode->origin.semantic, calleeGPR);
     988    callLinkInfo->setUpCall(callType, argumentsLocation, m_currentNode->origin.semantic, calleeGPR);
    917989
    918990    if (node->op() == CallEval) {
     
    9551027            RELEASE_ASSERT(node->op() == DirectTailCall);
    9561028           
     1029            if (calleeGPRTemporary != std::nullopt)
     1030                m_jit.move(tailCallee->gpr(), calleeGPRTemporary->gpr());
     1031
    9571032            JITCompiler::PatchableJump patchableJump = m_jit.patchableJump();
    9581033            JITCompiler::Label mainPath = m_jit.label();
     1034
     1035            incrementCounter(&m_jit, VM::TailCall);
     1036            incrementCounter(&m_jit, VM::DirectCall);
    9591037           
    9601038            m_jit.emitStoreCallSiteIndex(callSite);
     
    9721050            silentFillAllRegisters(InvalidGPRReg);
    9731051            m_jit.exceptionCheck();
     1052            if (calleeGPRTemporary != std::nullopt)
     1053                m_jit.move(tailCallee->gpr(), calleeGPRTemporary->gpr());
    9741054            m_jit.jump().linkTo(mainPath, &m_jit);
    9751055           
     
    9821062        JITCompiler::Label mainPath = m_jit.label();
    9831063       
     1064        incrementCounter(&m_jit, VM::DirectCall);
     1065
    9841066        m_jit.emitStoreCallSiteIndex(callSite);
    9851067       
     
    9891071        JITCompiler::Label slowPath = m_jit.label();
    9901072        if (isX86())
    991             m_jit.pop(JITCompiler::selectScratchGPR(calleeGPR));
    992 
    993         callOperation(operationLinkDirectCall, callLinkInfo, calleeGPR);
     1073            m_jit.pop(GPRInfo::nonArgGPR0);
     1074
     1075        m_jit.move(MacroAssembler::TrustedImmPtr(callLinkInfo), GPRInfo::nonArgGPR0); // Link info needs to be in nonArgGPR0
     1076        JITCompiler::Call slowCall = m_jit.nearCall();
     1077
    9941078        m_jit.exceptionCheck();
    9951079        m_jit.jump().linkTo(mainPath, &m_jit);
     
    9981082       
    9991083        setResultAndResetStack();
    1000        
    1001         m_jit.addJSDirectCall(call, slowPath, callLinkInfo);
     1084
     1085        m_jit.addJSDirectCall(call, slowCall, slowPath, callLinkInfo);
    10021086        return;
    10031087    }
    1004    
     1088
     1089    if (isTail && calleeGPRTemporary != std::nullopt)
     1090        m_jit.move(tailCallee->gpr(), calleeGPRTemporary->gpr());
     1091
    10051092    m_jit.emitStoreCallSiteIndex(callSite);
    10061093   
     
    10261113    if (node->op() == TailCall) {
    10271114        CallFrameShuffler callFrameShuffler(m_jit, shuffleData);
    1028         callFrameShuffler.setCalleeJSValueRegs(JSValueRegs(GPRInfo::regT0));
     1115        if (argumentsLocation == StackArgs)
     1116            callFrameShuffler.setCalleeJSValueRegs(JSValueRegs(argumentRegisterForCallee()));
    10291117        callFrameShuffler.prepareForSlowPath();
    1030     } else {
    1031         m_jit.move(calleeGPR, GPRInfo::regT0); // Callee needs to be in regT0
    1032 
    1033         if (isTail)
    1034             m_jit.emitRestoreCalleeSaves(); // This needs to happen after we moved calleeGPR to regT0
    1035     }
    1036 
    1037     m_jit.move(MacroAssembler::TrustedImmPtr(callLinkInfo), GPRInfo::regT2); // Link info needs to be in regT2
     1118    } else if (isTail)
     1119        m_jit.emitRestoreCalleeSaves();
     1120
     1121    m_jit.move(MacroAssembler::TrustedImmPtr(callLinkInfo), GPRInfo::nonArgGPR0); // Link info needs to be in nonArgGPR0
    10381122    JITCompiler::Call slowCall = m_jit.nearCall();
    10391123
    10401124    done.link(&m_jit);
    10411125
    1042     if (isTail)
     1126    if (isTail) {
     1127        tailCallee = std::nullopt;
     1128        calleeGPRTemporary = std::nullopt;
    10431129        m_jit.abortWithReason(JITDidReturnFromTailCall);
    1044     else
     1130    } else
    10451131        setResultAndResetStack();
    10461132
     
    41674253    }
    41684254
     4255    case GetArgumentRegister:
     4256        break;
     4257           
    41694258    case GetRestLength: {
    41704259        compileGetRestLength(node);
Note: See TracChangeset for help on using the changeset viewer.