Changeset 123169 in webkit


Ignore:
Timestamp:
Jul 19, 2012 8:50:02 PM (12 years ago)
Author:
fpizlo@apple.com
Message:

DFG cell checks should be hoisted
https://bugs.webkit.org/show_bug.cgi?id=91717

Reviewed by Geoffrey Garen.

The DFG has always had the policy of hoisting array and integer checks to
the point of variable assignment. Eventually, we added doubles and booleans
to the mix. But cells should really be part of this as well, particularly
for 32-bit where accessing a known-type variable is dramatically cheaper
than accessing a variable whose types is only predicted but otherwise
unproven.

This appears to be a definite speed-up for V8 on 32-bit, a possible speed-up
for Kraken, and a possible slow-down for V8 on 64-bit (around 0.2% if at
all). Any slow-downs can, and should, be addressed by making the hoisting
logic cognizant of variables that are never used in a manner that requires
type checks, and by sinking argument checks to the point(s) of first use.

To make this work I had to change some OSR machinery, and special-case the
type predictions of the 'this' argument for constructors. OSR exit normally
assumes that arguments are boxed, which happens to be true because the
type prediction used for check hoisting is LUB'd with the type of the
argument that was passed in - so either the arguments are always stored to
with the full tag+payload, or if only the payload is stored then the tag
matches whatever the caller would have set. But not so with the 'this'
argument for constructors, which is not initialized by the caller. We
could make this more precise by having argument types for OSR be inferred
using similar machinery to other locals, but I figured that for this patch
I should use the surgical fix.

  • assembler/MacroAssemblerX86_64.h:

(JSC::MacroAssemblerX86_64::branchTestPtr):
(MacroAssemblerX86_64):

  • assembler/X86Assembler.h:

(JSC::X86Assembler::testq_rm):
(X86Assembler):

  • dfg/DFGAbstractState.cpp:

(JSC::DFG::AbstractState::initialize):
(JSC::DFG::AbstractState::execute):

  • dfg/DFGDriver.cpp:

(JSC::DFG::compile):

  • dfg/DFGGraph.h:

(JSC::DFG::Graph::isCreatedThisArgument):
(Graph):

  • dfg/DFGSpeculativeJIT.cpp:

(JSC::DFG::SpeculativeJIT::checkArgumentTypes):

  • dfg/DFGSpeculativeJIT32_64.cpp:

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

  • dfg/DFGSpeculativeJIT64.cpp:

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

  • dfg/DFGValueSource.h:

(JSC::DFG::ValueSource::forSpeculation):

Location:
trunk/Source/JavaScriptCore
Files:
10 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r123164 r123169  
     12012-07-18  Filip Pizlo  <fpizlo@apple.com>
     2
     3        DFG cell checks should be hoisted
     4        https://bugs.webkit.org/show_bug.cgi?id=91717
     5
     6        Reviewed by Geoffrey Garen.
     7
     8        The DFG has always had the policy of hoisting array and integer checks to
     9        the point of variable assignment. Eventually, we added doubles and booleans
     10        to the mix. But cells should really be part of this as well, particularly
     11        for 32-bit where accessing a known-type variable is dramatically cheaper
     12        than accessing a variable whose types is only predicted but otherwise
     13        unproven.
     14       
     15        This appears to be a definite speed-up for V8 on 32-bit, a possible speed-up
     16        for Kraken, and a possible slow-down for V8 on 64-bit (around 0.2% if at
     17        all). Any slow-downs can, and should, be addressed by making the hoisting
     18        logic cognizant of variables that are never used in a manner that requires
     19        type checks, and by sinking argument checks to the point(s) of first use.
     20       
     21        To make this work I had to change some OSR machinery, and special-case the
     22        type predictions of the 'this' argument for constructors. OSR exit normally
     23        assumes that arguments are boxed, which happens to be true because the
     24        type prediction used for check hoisting is LUB'd with the type of the
     25        argument that was passed in - so either the arguments are always stored to
     26        with the full tag+payload, or if only the payload is stored then the tag
     27        matches whatever the caller would have set. But not so with the 'this'
     28        argument for constructors, which is not initialized by the caller. We
     29        could make this more precise by having argument types for OSR be inferred
     30        using similar machinery to other locals, but I figured that for this patch
     31        I should use the surgical fix.
     32
     33        * assembler/MacroAssemblerX86_64.h:
     34        (JSC::MacroAssemblerX86_64::branchTestPtr):
     35        (MacroAssemblerX86_64):
     36        * assembler/X86Assembler.h:
     37        (JSC::X86Assembler::testq_rm):
     38        (X86Assembler):
     39        * dfg/DFGAbstractState.cpp:
     40        (JSC::DFG::AbstractState::initialize):
     41        (JSC::DFG::AbstractState::execute):
     42        * dfg/DFGDriver.cpp:
     43        (JSC::DFG::compile):
     44        * dfg/DFGGraph.h:
     45        (JSC::DFG::Graph::isCreatedThisArgument):
     46        (Graph):
     47        * dfg/DFGSpeculativeJIT.cpp:
     48        (JSC::DFG::SpeculativeJIT::checkArgumentTypes):
     49        * dfg/DFGSpeculativeJIT32_64.cpp:
     50        (JSC::DFG::SpeculativeJIT::compile):
     51        * dfg/DFGSpeculativeJIT64.cpp:
     52        (JSC::DFG::SpeculativeJIT::compile):
     53        * dfg/DFGValueSource.h:
     54        (JSC::DFG::ValueSource::forSpeculation):
     55
    1562012-07-19  Filip Pizlo  <fpizlo@apple.com>
    257
  • trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h

    r122677 r123169  
    477477    }
    478478
     479    Jump branchTestPtr(ResultCondition cond, Address address, RegisterID reg)
     480    {
     481        m_assembler.testq_rm(reg, address.offset, address.base);
     482        return Jump(m_assembler.jCC(x86Condition(cond)));
     483    }
     484
    479485    Jump branchTestPtr(ResultCondition cond, BaseIndex address, TrustedImm32 mask = TrustedImm32(-1))
    480486    {
  • trunk/Source/JavaScriptCore/assembler/X86Assembler.h

    r122677 r123169  
    998998    }
    999999
     1000    void testq_rm(RegisterID src, int offset, RegisterID base)
     1001    {
     1002        m_formatter.oneByteOp64(OP_TEST_EvGv, src, base, offset);
     1003    }
     1004
    10001005    void testq_i32r(int imm, RegisterID dst)
    10011006    {
  • trunk/Source/JavaScriptCore/dfg/DFGAbstractState.cpp

    r123052 r123169  
    129129        else if (isFloat64ArraySpeculation(prediction))
    130130            root->valuesAtHead.argument(i).set(SpecFloat64Array);
     131        else if (isCellSpeculation(prediction))
     132            root->valuesAtHead.argument(i).set(SpecCell);
    131133        else
    132134            root->valuesAtHead.argument(i).makeTop();
     
    273275       
    274276    case SetLocal: {
    275         if (node.variableAccessData()->isCaptured()) {
     277        if (node.variableAccessData()->isCaptured()
     278            || m_graph.isCreatedThisArgument(node.local())) {
    276279            m_variables.operand(node.local()) = forNode(node.child1());
    277280            node.setCanExit(false);
     
    291294            node.setCanExit(!isArraySpeculation(forNode(node.child1()).m_type));
    292295            forNode(node.child1()).filter(SpecArray);
     296        } else if (isCellSpeculation(predictedType)) {
     297            node.setCanExit(!isCellSpeculation(forNode(node.child1()).m_type));
     298            forNode(node.child1()).filter(SpecCell);
    293299        } else if (isBooleanSpeculation(predictedType))
    294300            speculateBooleanUnary(node);
  • trunk/Source/JavaScriptCore/dfg/DFGDriver.cpp

    r121798 r123169  
    6565    if (!Options::useDFGJIT())
    6666        return false;
    67 
     67   
    6868#if DFG_ENABLE(DEBUG_VERBOSE)
    6969    dataLog("DFG compiling code block %p(%p) for executable %p, number of instructions = %u.\n", codeBlock, codeBlock->alternative(), codeBlock->ownerExecutable(), codeBlock->instructionCount());
  • trunk/Source/JavaScriptCore/dfg/DFGGraph.h

    r122678 r123169  
    442442    }
    443443   
     444    bool isCreatedThisArgument(int operand)
     445    {
     446        if (!operandIsArgument(operand))
     447            return false;
     448        if (operandToArgument(operand))
     449            return false;
     450        return m_codeBlock->specializationKind() == CodeForConstruct;
     451    }
     452   
    444453    unsigned numSuccessors(BasicBlock* block)
    445454    {
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp

    r123164 r123169  
    12421242            speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchTestPtr(MacroAssembler::NonZero, temp.gpr(), GPRInfo::tagMaskRegister));
    12431243            speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->float64ArrayDescriptor().m_classInfo)));
    1244         }
     1244        } else if (isCellSpeculation(predictedType))
     1245            speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchTestPtr(MacroAssembler::NonZero, JITCompiler::addressFor(virtualRegister), GPRInfo::tagMaskRegister));
    12451246#else
    12461247        if (isInt32Speculation(predictedType))
     
    13081309            m_jit.load32(JITCompiler::payloadFor(virtualRegister), temp.gpr());
    13091310            speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->float64ArrayDescriptor().m_classInfo)));
    1310         }
     1311        }   else if (isCellSpeculation(predictedType))
     1312            speculationCheck(BadType, valueSource, nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::CellTag)));
    13111313#endif
    13121314    }
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp

    r123052 r123169  
    19191919            }
    19201920
    1921             if (isArraySpeculation(value.m_type)) {
     1921            if (isArraySpeculation(value.m_type) || isCellSpeculation(value.m_type)) {
    19221922                GPRTemporary result(this);
    19231923                m_jit.load32(JITCompiler::payloadFor(node.local()), result.gpr());
     
    20112011        m_codeOriginForOSR = nextNode->codeOrigin;
    20122012       
    2013         if (!node.variableAccessData()->isCaptured()) {
     2013        if (!node.variableAccessData()->isCaptured() && !m_jit.graph().isCreatedThisArgument(node.local())) {
    20142014            if (node.variableAccessData()->shouldUseDoubleFormat()) {
    20152015                SpeculateDoubleOperand value(this, node.child1());
     
    20472047                break;
    20482048            }
     2049            if (isCellSpeculation(predictedType)) {
     2050                SpeculateCellOperand cell(this, node.child1());
     2051                GPRReg cellGPR = cell.gpr();
     2052                m_jit.storePtr(cellGPR, JITCompiler::payloadFor(node.local()));
     2053                noResult(m_compileIndex);
     2054                recordSetLocal(node.local(), ValueSource(CellInRegisterFile));
     2055                break;
     2056            }
    20492057            if (isBooleanSpeculation(predictedType)) {
    20502058                SpeculateBooleanOperand value(this, node.child1());
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp

    r123052 r123169  
    20532053        m_codeOriginForOSR = nextNode->codeOrigin;
    20542054       
    2055         if (!node.variableAccessData()->isCaptured()) {
     2055        if (!node.variableAccessData()->isCaptured() && !m_jit.graph().isCreatedThisArgument(node.local())) {
    20562056            if (node.variableAccessData()->shouldUseDoubleFormat()) {
    20572057                SpeculateDoubleOperand value(this, node.child1());
     
    20832083                break;
    20842084            }
     2085            if (isCellSpeculation(predictedType)) {
     2086                SpeculateCellOperand cell(this, node.child1());
     2087                GPRReg cellGPR = cell.gpr();
     2088                m_jit.storePtr(cellGPR, JITCompiler::addressFor(node.local()));
     2089                noResult(m_compileIndex);
     2090                recordSetLocal(node.local(), ValueSource(CellInRegisterFile));
     2091                break;
     2092            }
    20852093            if (isBooleanSpeculation(predictedType)) {
    20862094                SpeculateBooleanOperand boolean(this, node.child1());
  • trunk/Source/JavaScriptCore/dfg/DFGValueSource.h

    r121717 r123169  
    131131        if (isInt32Speculation(prediction))
    132132            return ValueSource(Int32InRegisterFile);
    133         if (isArraySpeculation(prediction))
     133        if (isArraySpeculation(prediction) || isCellSpeculation(prediction))
    134134            return ValueSource(CellInRegisterFile);
    135135        if (isBooleanSpeculation(prediction))
Note: See TracChangeset for help on using the changeset viewer.