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/jit/CallFrameShuffler.cpp

    r209678 r209725  
    4343    , m_alignedNewFrameSize(CallFrame::headerSizeInRegisters
    4444        + roundArgumentCountToAlignFrame(data.args.size()))
     45#if USE(JSVALUE64)
     46    , m_argumentsInRegisters(data.argumentsInRegisters)
     47#endif
    4548    , m_frameDelta(m_alignedNewFrameSize - m_alignedOldFrameSize)
    4649    , m_lockedRegisters(RegisterSet::allRegisters())
     
    5558
    5659    ASSERT(!data.callee.isInJSStack() || data.callee.virtualRegister().isLocal());
    57     addNew(VirtualRegister(CallFrameSlot::callee), data.callee);
    58 
     60#if USE(JSVALUE64)
     61    if (data.argumentsInRegisters)
     62        addNew(JSValueRegs(argumentRegisterForCallee()), data.callee);
     63    else
     64#endif
     65        addNew(VirtualRegister(CallFrameSlot::callee), data.callee);
     66   
    5967    for (size_t i = 0; i < data.args.size(); ++i) {
    6068        ASSERT(!data.args[i].isInJSStack() || data.args[i].virtualRegister().isLocal());
    61         addNew(virtualRegisterForArgument(i), data.args[i]);
     69#if USE(JSVALUE64)
     70        if (data.argumentsInRegisters && i < NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS)
     71            addNew(JSValueRegs(argumentRegisterForFunctionArgument(i)), data.args[i]);
     72        else
     73#endif
     74            addNew(virtualRegisterForArgument(i), data.args[i]);
    6275    }
    6376
     
    186199        }
    187200#else
    188         if (newCachedRecovery)
     201        if (newCachedRecovery) {
    189202            out.print("         ", reg, " <- ", newCachedRecovery->recovery());
     203            if (newCachedRecovery->gprTargets().size() > 1) {
     204                for (size_t i = 1; i < newCachedRecovery->gprTargets().size(); i++)
     205                    out.print(", ", newCachedRecovery->gprTargets()[i].gpr(), " <- ", newCachedRecovery->recovery());
     206            }
     207        }
    190208#endif
    191209        out.print("\n");
     
    497515        || cachedRecovery.recovery().isConstant());
    498516
    499     if (verbose)
     517    if (verbose && cachedRecovery.targets().size())
    500518        dataLog("   * Storing ", cachedRecovery.recovery());
    501519    for (size_t i = 0; i < cachedRecovery.targets().size(); ++i) {
     
    506524        emitStore(cachedRecovery, addressForNew(target));
    507525        setNew(target, nullptr);
    508     }
    509     if (verbose)
    510         dataLog("\n");
     526        if (verbose)
     527            dataLog("\n");
     528    }
    511529    cachedRecovery.clearTargets();
    512530    if (!cachedRecovery.wantedJSValueRegs() && cachedRecovery.wantedFPR() == InvalidFPRReg)
     
    607625    ASSERT(!isUndecided());
    608626
    609     updateDangerFrontier();
     627    initDangerFrontier();
    610628
    611629    // First, we try to store any value that goes above the danger
     
    703721    }
    704722
    705 #if USE(JSVALUE64)
    706     if (m_tagTypeNumber != InvalidGPRReg && m_newRegisters[m_tagTypeNumber])
    707         releaseGPR(m_tagTypeNumber);
    708 #endif
    709 
    710723    // Handle 2) by loading all registers. We don't have to do any
    711724    // writes, since they have been taken care of above.
     725    // Note that we need m_tagTypeNumber to remain locked to box wanted registers.
    712726    if (verbose)
    713727        dataLog("  Loading wanted registers into registers\n");
     
    743757    // We need to handle 4) first because it implies releasing
    744758    // m_newFrameBase, which could be a wanted register.
     759    // Note that we delay setting the argument count register as it needs to be released in step 3.
    745760    if (verbose)
    746761        dataLog("   * Storing the argument count into ", VirtualRegister { CallFrameSlot::argumentCount }, "\n");
     762
    747763    m_jit.store32(MacroAssembler::TrustedImm32(0),
    748764        addressForNew(VirtualRegister { CallFrameSlot::argumentCount }).withOffset(TagOffset));
    749     m_jit.store32(MacroAssembler::TrustedImm32(argCount()),
    750         addressForNew(VirtualRegister { CallFrameSlot::argumentCount }).withOffset(PayloadOffset));
     765
     766#if USE(JSVALUE64)
     767    if (!m_argumentsInRegisters) {
     768#endif
     769        m_jit.store32(MacroAssembler::TrustedImm32(argCount()),
     770            addressForNew(VirtualRegister { CallFrameSlot::argumentCount }).withOffset(PayloadOffset));
     771#if USE(JSVALUE64)
     772    }
     773#endif
    751774
    752775    if (!isSlowPath()) {
     
    768791        emitDisplace(*cachedRecovery);
    769792    }
     793
     794#if USE(JSVALUE64)
     795    // For recoveries with multiple register targets, copy the contents of the first target to the
     796    // remaining targets.
     797    for (Reg reg = Reg::first(); reg <= Reg::last(); reg = reg.next()) {
     798        CachedRecovery* cachedRecovery { m_newRegisters[reg] };
     799        if (!cachedRecovery || cachedRecovery->gprTargets().size() < 2)
     800            continue;
     801
     802        GPRReg sourceGPR = cachedRecovery->gprTargets()[0].gpr();
     803        for (size_t i = 1; i < cachedRecovery->gprTargets().size(); i++)
     804            m_jit.move(sourceGPR, cachedRecovery->gprTargets()[i].gpr());
     805    }
     806
     807    if (m_argumentsInRegisters)
     808        m_jit.move(MacroAssembler::TrustedImm32(argCount()), argumentRegisterForArgumentCount());
     809#endif
    770810}
    771811
Note: See TracChangeset for help on using the changeset viewer.