Ignore:
Timestamp:
Nov 1, 2017, 6:25:21 AM (8 years ago)
Author:
Yusuke Suzuki
Message:

[DFG][FTL] Introduce StringSlice
https://bugs.webkit.org/show_bug.cgi?id=178934

Reviewed by Saam Barati.

JSTests:

  • microbenchmarks/string-slice-empty.js: Added.

(slice):

  • microbenchmarks/string-slice-one-char.js: Added.

(slice):

  • microbenchmarks/string-slice.js: Added.

(slice):

Source/JavaScriptCore:

String.prototype.slice is one of the most frequently called function in ARES-6/Babylon.
This patch introduces StringSlice DFG node to optimize it in DFG and FTL.

This patch's StringSlice node optimizes the following things.

  1. Empty string generation is accelerated. It is fully executed inline.
  2. One char string generation is accelerated. < 0x100 character is supported right now.

It is the same to charAt acceleration.

  1. We calculate start and end index in DFG/FTL with Int32Use information and call optimized

operation.

We do not inline (3)'s operation right now since we do not have a way to call bmalloc allocation from DFG / FTL.
And we do not optimize String.prototype.{substring,substr} right now. But they can be optimized based on this change
in subsequent changes.

This patch improves ARES-6/Babylon performance by 3% in steady state.

Baseline:

Running... Babylon ( 1 to go)
firstIteration: 50.05 +- 13.68 ms
averageWorstCase: 16.80 +- 1.27 ms
steadyState: 7.53 +- 0.22 ms

Patched:

Running... Babylon ( 1 to go)
firstIteration: 50.91 +- 13.41 ms
averageWorstCase: 16.12 +- 0.99 ms
steadyState: 7.30 +- 0.29 ms

  • dfg/DFGAbstractInterpreterInlines.h:

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

  • dfg/DFGBackwardsPropagationPhase.cpp:

(JSC::DFG::BackwardsPropagationPhase::propagate):

  • dfg/DFGByteCodeParser.cpp:

(JSC::DFG::ByteCodeParser::handleIntrinsicCall):

  • dfg/DFGClobberize.h:

(JSC::DFG::clobberize):

  • dfg/DFGDoesGC.cpp:

(JSC::DFG::doesGC):

  • dfg/DFGFixupPhase.cpp:

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

  • dfg/DFGNodeType.h:
  • dfg/DFGOperations.cpp:
  • dfg/DFGOperations.h:
  • dfg/DFGPredictionPropagationPhase.cpp:
  • dfg/DFGSafeToExecute.h:

(JSC::DFG::safeToExecute):

  • dfg/DFGSpeculativeJIT.cpp:

(JSC::DFG::SpeculativeJIT::compileStringSlice):
(JSC::DFG::SpeculativeJIT::emitPopulateSliceIndex):
(JSC::DFG::SpeculativeJIT::compileArraySlice):
(JSC::DFG::SpeculativeJIT::compileArrayIndexOf):

  • dfg/DFGSpeculativeJIT.h:

(JSC::DFG::SpeculativeJIT::callOperation):

  • dfg/DFGSpeculativeJIT32_64.cpp:

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

  • dfg/DFGSpeculativeJIT64.cpp:

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

  • ftl/FTLCapabilities.cpp:

(JSC::FTL::canCompile):

  • ftl/FTLLowerDFGToB3.cpp:

(JSC::FTL::DFG::LowerDFGToB3::compileNode):
(JSC::FTL::DFG::LowerDFGToB3::populateSliceRange):
(JSC::FTL::DFG::LowerDFGToB3::compileArraySlice):
(JSC::FTL::DFG::LowerDFGToB3::compileStringSlice):

  • jit/JITOperations.h:
  • runtime/Intrinsic.cpp:

(JSC::intrinsicName):

  • runtime/Intrinsic.h:
  • runtime/StringPrototype.cpp:

(JSC::StringPrototype::finishCreation):

File:
1 edited

Legend:

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

    r224258 r224276  
    15151515
    15161516    jump(notTaken);
     1517}
     1518
     1519void SpeculativeJIT::compileStringSlice(Node* node)
     1520{
     1521    SpeculateCellOperand string(this, node->child1());
     1522    GPRTemporary startIndex(this);
     1523    GPRTemporary temp(this);
     1524    GPRTemporary temp2(this);
     1525
     1526    GPRReg stringGPR = string.gpr();
     1527    GPRReg startIndexGPR = startIndex.gpr();
     1528    GPRReg tempGPR = temp.gpr();
     1529    GPRReg temp2GPR = temp2.gpr();
     1530
     1531    speculateString(node->child1(), stringGPR);
     1532
     1533    {
     1534        m_jit.load32(JITCompiler::Address(stringGPR, JSString::offsetOfLength()), temp2GPR);
     1535
     1536        emitPopulateSliceIndex(node->child2(), temp2GPR, startIndexGPR);
     1537        if (node->child3())
     1538            emitPopulateSliceIndex(node->child3(), temp2GPR, tempGPR);
     1539        else
     1540            m_jit.move(temp2GPR, tempGPR);
     1541    }
     1542
     1543    CCallHelpers::JumpList doneCases;
     1544    CCallHelpers::JumpList slowCases;
     1545
     1546    auto nonEmptyCase = m_jit.branch32(MacroAssembler::Below, startIndexGPR, tempGPR);
     1547    m_jit.move(TrustedImmPtr::weakPointer(m_jit.graph(), jsEmptyString(&vm())), tempGPR);
     1548    doneCases.append(m_jit.jump());
     1549
     1550    nonEmptyCase.link(&m_jit);
     1551    m_jit.sub32(startIndexGPR, tempGPR); // the size of the sliced string.
     1552    slowCases.append(m_jit.branch32(MacroAssembler::NotEqual, tempGPR, TrustedImm32(1)));
     1553
     1554    m_jit.loadPtr(MacroAssembler::Address(stringGPR, JSString::offsetOfValue()), temp2GPR);
     1555    slowCases.append(m_jit.branchTestPtr(MacroAssembler::Zero, temp2GPR));
     1556
     1557    m_jit.loadPtr(MacroAssembler::Address(temp2GPR, StringImpl::dataOffset()), tempGPR);
     1558
     1559    // Load the character into scratchReg
     1560    m_jit.zeroExtend32ToPtr(startIndexGPR, startIndexGPR);
     1561    auto is16Bit = m_jit.branchTest32(MacroAssembler::Zero, MacroAssembler::Address(temp2GPR, StringImpl::flagsOffset()), TrustedImm32(StringImpl::flagIs8Bit()));
     1562
     1563    m_jit.load8(MacroAssembler::BaseIndex(tempGPR, startIndexGPR, MacroAssembler::TimesOne, 0), tempGPR);
     1564    auto cont8Bit = m_jit.jump();
     1565
     1566    is16Bit.link(&m_jit);
     1567    m_jit.load16(MacroAssembler::BaseIndex(tempGPR, startIndexGPR, MacroAssembler::TimesTwo, 0), tempGPR);
     1568
     1569    auto bigCharacter = m_jit.branch32(MacroAssembler::AboveOrEqual, tempGPR, TrustedImm32(0x100));
     1570
     1571    // 8 bit string values don't need the isASCII check.
     1572    cont8Bit.link(&m_jit);
     1573
     1574    m_jit.lshift32(MacroAssembler::TrustedImm32(sizeof(void*) == 4 ? 2 : 3), tempGPR);
     1575    m_jit.addPtr(TrustedImmPtr(m_jit.vm()->smallStrings.singleCharacterStrings()), tempGPR);
     1576    m_jit.loadPtr(tempGPR, tempGPR);
     1577
     1578    addSlowPathGenerator(
     1579        slowPathCall(
     1580            bigCharacter, this, operationSingleCharacterString, tempGPR, tempGPR));
     1581
     1582    addSlowPathGenerator(
     1583        slowPathCall(
     1584            slowCases, this, operationStringSubstr, tempGPR, stringGPR, startIndexGPR, tempGPR));
     1585
     1586    doneCases.link(&m_jit);
     1587    cellResult(tempGPR, node);
    15171588}
    15181589
     
    74947565}
    74957566
     7567void SpeculativeJIT::emitPopulateSliceIndex(Edge& target, GPRReg length, GPRReg result)
     7568{
     7569    SpeculateInt32Operand index(this, target);
     7570    GPRReg indexGPR = index.gpr();
     7571    MacroAssembler::JumpList done;
     7572    auto isPositive = m_jit.branch32(MacroAssembler::GreaterThanOrEqual, indexGPR, TrustedImm32(0));
     7573    m_jit.move(length, result);
     7574    done.append(m_jit.branchAdd32(MacroAssembler::PositiveOrZero, indexGPR, result));
     7575    m_jit.move(TrustedImm32(0), result);
     7576    done.append(m_jit.jump());
     7577
     7578    isPositive.link(&m_jit);
     7579    m_jit.move(indexGPR, result);
     7580    done.append(m_jit.branch32(MacroAssembler::BelowOrEqual, result, length));
     7581    m_jit.move(length, result);
     7582
     7583    done.link(&m_jit);
     7584}
     7585
    74967586void SpeculativeJIT::compileArraySlice(Node* node)
    74977587{
     
    75077597    GPRReg resultGPR = result.gpr();
    75087598    GPRReg tempGPR = temp.gpr();
    7509 
    7510     auto populateIndex = [&] (unsigned childIndex, GPRReg length, GPRReg result) {
    7511         SpeculateInt32Operand index(this, m_jit.graph().varArgChild(node, childIndex));
    7512         GPRReg indexGPR = index.gpr();
    7513         MacroAssembler::JumpList done;
    7514         auto isPositive = m_jit.branch32(MacroAssembler::GreaterThanOrEqual, indexGPR, TrustedImm32(0));
    7515         m_jit.move(length, result);
    7516         done.append(m_jit.branchAdd32(MacroAssembler::PositiveOrZero, indexGPR, result));
    7517         m_jit.move(TrustedImm32(0), result);
    7518         done.append(m_jit.jump());
    7519 
    7520         isPositive.link(&m_jit);
    7521         m_jit.move(indexGPR, result);
    7522         done.append(m_jit.branch32(MacroAssembler::BelowOrEqual, result, length));
    7523         m_jit.move(length, result);
    7524 
    7525         done.link(&m_jit);
    7526     };
    75277599
    75287600    {
     
    75327604
    75337605        if (node->numChildren() == 4)
    7534             populateIndex(2, lengthGPR, tempGPR);
     7606            emitPopulateSliceIndex(m_jit.graph().varArgChild(node, 2), lengthGPR, tempGPR);
    75357607        else
    75367608            m_jit.move(lengthGPR, tempGPR);
     
    75387610        GPRTemporary tempStartIndex(this);
    75397611        GPRReg startGPR = tempStartIndex.gpr();
    7540         populateIndex(1, lengthGPR, startGPR);
     7612        emitPopulateSliceIndex(m_jit.graph().varArgChild(node, 1), lengthGPR, startGPR);
    75417613
    75427614        auto tooBig = m_jit.branch32(MacroAssembler::Above, startGPR, tempGPR);
     
    76297701    m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), tempValue);
    76307702    if (node->numChildren() == 4)
    7631         populateIndex(2, tempValue, tempGPR);
     7703        emitPopulateSliceIndex(m_jit.graph().varArgChild(node, 2), tempValue, tempGPR);
    76327704    else
    76337705        m_jit.move(tempValue, tempGPR);
    7634     populateIndex(1, tempValue, loadIndex);
     7706    emitPopulateSliceIndex(m_jit.graph().varArgChild(node, 1), tempValue, loadIndex);
    76357707
    76367708    GPRTemporary temp5(this);
     
    76857757    m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), lengthGPR);
    76867758
    7687     if (node->numChildren() == 4) {
    7688         SpeculateInt32Operand startIndex(this, m_jit.graph().varArgChild(node, 2));
    7689         GPRReg startIndexGPR = startIndex.gpr();
    7690         MacroAssembler::JumpList done;
    7691         auto isPositive = m_jit.branch32(MacroAssembler::GreaterThanOrEqual, startIndexGPR, TrustedImm32(0));
    7692         m_jit.move(lengthGPR, indexGPR);
    7693         done.append(m_jit.branchAdd32(MacroAssembler::PositiveOrZero, startIndexGPR, indexGPR));
    7694         m_jit.move(TrustedImm32(0), indexGPR);
    7695         done.append(m_jit.jump());
    7696 
    7697         isPositive.link(&m_jit);
    7698         m_jit.move(startIndexGPR, indexGPR);
    7699         done.append(m_jit.branch32(MacroAssembler::BelowOrEqual, indexGPR, lengthGPR));
    7700         m_jit.move(lengthGPR, indexGPR);
    7701 
    7702         done.link(&m_jit);
    7703     } else
     7759    if (node->numChildren() == 4)
     7760        emitPopulateSliceIndex(m_jit.graph().varArgChild(node, 2), lengthGPR, indexGPR);
     7761    else
    77047762        m_jit.move(TrustedImm32(0), indexGPR);
    77057763
Note: See TracChangeset for help on using the changeset viewer.