Changeset 95672 in webkit


Ignore:
Timestamp:
Sep 21, 2011 3:17:06 PM (13 years ago)
Author:
fpizlo@apple.com
Message:

DFG does not support compiling functions as constructors
https://bugs.webkit.org/show_bug.cgi?id=68500

Reviewed by Oliver Hunt.

This adds support for compiling constructors to the DFG. It's a
1% speed-up on V8, mostly due to a 6% speed-up on early-boyer.
It's also a 13% win on access-binary-trees, but it's neutral in
the SunSpider and Kraken averages.

  • dfg/DFGByteCodeParser.cpp:

(JSC::DFG::ByteCodeParser::parseBlock):

  • dfg/DFGCapabilities.h:

(JSC::DFG::mightCompileFunctionForConstruct):
(JSC::DFG::canCompileOpcode):

  • dfg/DFGNode.h:
  • dfg/DFGOperations.cpp:
  • dfg/DFGOperations.h:
  • dfg/DFGPropagator.cpp:

(JSC::DFG::Propagator::propagateNodePredictions):
(JSC::DFG::Propagator::performNodeCSE):

  • dfg/DFGSpeculativeJIT.cpp:

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

  • runtime/Executable.cpp:

(JSC::FunctionExecutable::compileOptimizedForConstruct):
(JSC::FunctionExecutable::compileForConstructInternal):

  • runtime/Executable.h:

(JSC::FunctionExecutable::compileForConstruct):
(JSC::FunctionExecutable::compileFor):
(JSC::FunctionExecutable::compileOptimizedFor):

Location:
trunk/Source/JavaScriptCore
Files:
10 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r95666 r95672  
     12011-09-21  Filip Pizlo  <fpizlo@apple.com>
     2
     3        DFG does not support compiling functions as constructors
     4        https://bugs.webkit.org/show_bug.cgi?id=68500
     5
     6        Reviewed by Oliver Hunt.
     7       
     8        This adds support for compiling constructors to the DFG. It's a
     9        1% speed-up on V8, mostly due to a 6% speed-up on early-boyer.
     10        It's also a 13% win on access-binary-trees, but it's neutral in
     11        the SunSpider and Kraken averages.
     12
     13        * dfg/DFGByteCodeParser.cpp:
     14        (JSC::DFG::ByteCodeParser::parseBlock):
     15        * dfg/DFGCapabilities.h:
     16        (JSC::DFG::mightCompileFunctionForConstruct):
     17        (JSC::DFG::canCompileOpcode):
     18        * dfg/DFGNode.h:
     19        * dfg/DFGOperations.cpp:
     20        * dfg/DFGOperations.h:
     21        * dfg/DFGPropagator.cpp:
     22        (JSC::DFG::Propagator::propagateNodePredictions):
     23        (JSC::DFG::Propagator::performNodeCSE):
     24        * dfg/DFGSpeculativeJIT.cpp:
     25        (JSC::DFG::SpeculativeJIT::compile):
     26        * runtime/Executable.cpp:
     27        (JSC::FunctionExecutable::compileOptimizedForConstruct):
     28        (JSC::FunctionExecutable::compileForConstructInternal):
     29        * runtime/Executable.h:
     30        (JSC::FunctionExecutable::compileForConstruct):
     31        (JSC::FunctionExecutable::compileFor):
     32        (JSC::FunctionExecutable::compileOptimizedFor):
     33
    1342011-09-21  Gavin Barraclough  <barraclough@apple.com>
    235
  • trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp

    r95666 r95672  
    729729            setThis(addToGraph(ConvertThis, op1));
    730730            NEXT_OPCODE(op_convert_this);
     731        }
     732
     733        case op_create_this: {
     734            NodeIndex op1 = get(currentInstruction[2].u.operand);
     735            set(currentInstruction[1].u.operand, addToGraph(CreateThis, op1));
     736            NEXT_OPCODE(op_create_this);
     737        }
     738           
     739        case op_get_callee: {
     740            set(currentInstruction[1].u.operand, addToGraph(GetCallee));
     741            NEXT_OPCODE(op_get_callee);
    731742        }
    732743
  • trunk/Source/JavaScriptCore/dfg/DFGCapabilities.h

    r95016 r95672  
    3838inline bool mightCompileProgram(CodeBlock*) { return true; }
    3939inline bool mightCompileFunctionForCall(CodeBlock*) { return true; }
    40 inline bool mightCompileFunctionForConstruct(CodeBlock*) { return false; }
     40inline bool mightCompileFunctionForConstruct(CodeBlock*) { return true; }
    4141
    4242// Opcode checking.
     
    4646    case op_enter:
    4747    case op_convert_this:
     48    case op_create_this:
     49    case op_get_callee:
    4850    case op_bitand:
    4951    case op_bitor:
  • trunk/Source/JavaScriptCore/dfg/DFGNode.h

    r95594 r95672  
    212212    /* Nodes for constants. */\
    213213    macro(JSConstant, NodeResultJS) \
     214    \
     215    /* Nodes for handling functions (both as call and as construct). */\
    214216    macro(ConvertThis, NodeResultJS) \
     217    macro(CreateThis, NodeResultJS) /* Note this is not MustGenerate since we're returning it anyway. */ \
     218    macro(GetCallee, NodeResultJS) \
    215219    \
    216220    /* Nodes for local variable access. */\
  • trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp

    r95666 r95672  
    120120}
    121121
     122EncodedJSValue operationCreateThis(ExecState* exec, EncodedJSValue encodedOp)
     123{
     124    JSFunction* constructor = asFunction(exec->callee());
     125   
     126#if !ASSERT_DISABLED
     127    ConstructData constructData;
     128    ASSERT(constructor->getConstructData(constructData) == ConstructTypeJS);
     129#endif
     130   
     131    JSGlobalData& globalData = exec->globalData();
     132   
     133    Structure* structure;
     134    JSValue proto = JSValue::decode(encodedOp);
     135    if (proto.isObject())
     136        structure = asObject(proto)->inheritorID(globalData);
     137    else
     138        structure = constructor->scope()->globalObject->emptyObjectStructure();
     139   
     140    return JSValue::encode(constructEmptyObject(exec, structure));
     141}
     142
    122143EncodedJSValue operationValueAdd(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
    123144{
  • trunk/Source/JavaScriptCore/dfg/DFGOperations.h

    r95147 r95672  
    5757// These routines are provide callbacks out to C++ implementations of operations too complex to JIT.
    5858EncodedJSValue operationConvertThis(ExecState*, EncodedJSValue encodedOp1);
     59EncodedJSValue operationCreateThis(ExecState*, EncodedJSValue encodedOp1);
    5960EncodedJSValue operationValueAdd(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2);
    6061EncodedJSValue operationValueAddNotNumber(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2);
  • trunk/Source/JavaScriptCore/dfg/DFGPropagator.cpp

    r95594 r95672  
    534534            break;
    535535        }
     536           
     537        case GetCallee: {
     538            changed |= setPrediction(makePrediction(PredictObjectOther, StrongPrediction));
     539            break;
     540        }
     541           
     542        case CreateThis: {
     543            changed |= mergeUse(node.child1(), PredictObjectUnknown | StrongPredictionTag);
     544            changed |= setPrediction(makePrediction(PredictFinalObject, StrongPrediction));
     545            break;
     546        }
    536547
    537548#ifndef NDEBUG
     
    10191030        case ArithMax:
    10201031        case ArithSqrt:
     1032        case GetCallee:
    10211033            setReplacement(pureCSE(node));
    10221034            break;
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp

    r95594 r95672  
    15281528        break;
    15291529    }
     1530       
     1531    case CreateThis: {
     1532        // Note that there is not so much profit to speculate here. The only things we
     1533        // speculate on are (1) that it's a cell, since that eliminates cell checks
     1534        // later if the proto is reused, and (2) if we have a FinalObject prediction
     1535        // then we speculate because we want to get recompiled if it isn't (since
     1536        // otherwise we'd start taking slow path a lot).
     1537       
     1538        SpeculateCellOperand proto(this, node.child1());
     1539        GPRTemporary result(this);
     1540        GPRTemporary scratch(this);
     1541       
     1542        GPRReg protoGPR = proto.gpr();
     1543        GPRReg resultGPR = result.gpr();
     1544        GPRReg scratchGPR = scratch.gpr();
     1545       
     1546        proto.use();
     1547       
     1548        MacroAssembler::JumpList slowPath;
     1549       
     1550        // Need to verify that the prototype is an object. If we have reason to believe
     1551        // that it's a FinalObject then we speculate on that directly. Otherwise we
     1552        // do the slow (structure-based) check.
     1553        if (shouldSpeculateFinalObject(node.child1()))
     1554            speculationCheck(m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(protoGPR), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsFinalObjectVPtr)));
     1555        else {
     1556            m_jit.loadPtr(MacroAssembler::Address(protoGPR, JSCell::structureOffset()), scratchGPR);
     1557            slowPath.append(m_jit.branch8(MacroAssembler::Below, MacroAssembler::Address(scratchGPR, Structure::typeInfoTypeOffset()), MacroAssembler::TrustedImm32(ObjectType)));
     1558        }
     1559       
     1560        // Load the inheritorID (the Structure that objects who have protoGPR as the prototype
     1561        // use to refer to that prototype). If the inheritorID is not set, go to slow path.
     1562        m_jit.loadPtr(MacroAssembler::Address(protoGPR, JSObject::offsetOfInheritorID()), scratchGPR);
     1563        slowPath.append(m_jit.branchTestPtr(MacroAssembler::Zero, scratchGPR));
     1564       
     1565        MarkedSpace::SizeClass* sizeClass = &m_jit.globalData()->heap.sizeClassForObject(sizeof(JSFinalObject));
     1566       
     1567        m_jit.loadPtr(&sizeClass->firstFreeCell, resultGPR);
     1568        slowPath.append(m_jit.branchTestPtr(MacroAssembler::Zero, resultGPR));
     1569       
     1570        // The object is half-allocated: we have what we know is a fresh object, but
     1571        // it's still on the GC's free list.
     1572       
     1573        // Ditch the inheritorID by placing it into the structure, so that we can reuse
     1574        // scratchGPR.
     1575        m_jit.storePtr(scratchGPR, MacroAssembler::Address(resultGPR, JSObject::structureOffset()));
     1576       
     1577        // Now that we have scratchGPR back, remove the object from the free list
     1578        m_jit.loadPtr(MacroAssembler::Address(resultGPR), scratchGPR);
     1579        m_jit.storePtr(scratchGPR, &sizeClass->firstFreeCell);
     1580       
     1581        // Initialize the object's vtable
     1582        m_jit.storePtr(MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsFinalObjectVPtr), MacroAssembler::Address(resultGPR));
     1583       
     1584        // Initialize the object's inheritorID.
     1585        m_jit.storePtr(MacroAssembler::TrustedImmPtr(0), MacroAssembler::Address(resultGPR, JSObject::offsetOfInheritorID()));
     1586       
     1587        // Initialize the object's property storage pointer.
     1588        m_jit.addPtr(MacroAssembler::TrustedImm32(sizeof(JSObject)), resultGPR, scratchGPR);
     1589        m_jit.storePtr(scratchGPR, MacroAssembler::Address(resultGPR, JSFinalObject::offsetOfPropertyStorage()));
     1590       
     1591        MacroAssembler::Jump done = m_jit.jump();
     1592       
     1593        slowPath.link(&m_jit);
     1594       
     1595        silentSpillAllRegisters(resultGPR);
     1596        m_jit.move(protoGPR, GPRInfo::argumentGPR1);
     1597        m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
     1598        appendCallWithExceptionCheck(operationCreateThis);
     1599        m_jit.move(GPRInfo::returnValueGPR, resultGPR);
     1600        silentFillAllRegisters(resultGPR);
     1601       
     1602        done.link(&m_jit);
     1603       
     1604        cellResult(resultGPR, m_compileIndex, UseChildrenCalledExplicitly);
     1605        break;
     1606    }
     1607       
     1608    case GetCallee: {
     1609        GPRTemporary result(this);
     1610        m_jit.loadPtr(JITCompiler::addressFor(static_cast<VirtualRegister>(RegisterFile::Callee)), result.gpr());
     1611        cellResult(result.gpr(), m_compileIndex);
     1612        break;
     1613    }
    15301614
    15311615    case GetById: {
  • trunk/Source/JavaScriptCore/runtime/Executable.cpp

    r95310 r95672  
    371371}
    372372
    373 JSObject* FunctionExecutable::compileOptimizedForConstruct(ExecState* exec, ScopeChainNode* scopeChainNode)
     373JSObject* FunctionExecutable::compileOptimizedForConstruct(ExecState* exec, ScopeChainNode* scopeChainNode, ExecState* calleeArgsExec)
    374374{
    375375    ASSERT(exec->globalData().dynamicGlobalObject);
     
    377377    JSObject* error = 0;
    378378    if (m_codeBlockForConstruct->getJITType() != JITCode::topTierJIT())
    379         error = compileForConstructInternal(exec, scopeChainNode, JITCode::nextTierJIT(m_codeBlockForConstruct->getJITType()));
     379        error = compileForConstructInternal(exec, scopeChainNode, calleeArgsExec, JITCode::nextTierJIT(m_codeBlockForConstruct->getJITType()));
    380380    ASSERT(!!m_codeBlockForConstruct);
    381381    return error;
     
    460460}
    461461
    462 JSObject* FunctionExecutable::compileForConstructInternal(ExecState* exec, ScopeChainNode* scopeChainNode, JITCode::JITType jitType)
     462JSObject* FunctionExecutable::compileForConstructInternal(ExecState* exec, ScopeChainNode* scopeChainNode, ExecState* calleeArgsExec, JITCode::JITType jitType)
    463463{
    464464    UNUSED_PARAM(jitType);
     
    499499    if (exec->globalData().canUseJIT()) {
    500500        bool dfgCompiled = false;
    501         // FIXME: Make it possible to compile constructors with DFG.
     501        if (jitType == JITCode::DFGJIT)
     502            dfgCompiled = DFG::tryCompileFunction(exec, calleeArgsExec, m_codeBlockForConstruct.get(), m_jitCodeForConstruct, m_jitCodeForConstructWithArityCheck);
    502503        if (dfgCompiled) {
    503504            if (m_codeBlockForConstruct->alternative())
  • trunk/Source/JavaScriptCore/runtime/Executable.h

    r95666 r95672  
    488488        }
    489489
    490         JSObject* compileForConstruct(ExecState* exec, ScopeChainNode* scopeChainNode)
     490        JSObject* compileForConstruct(ExecState* exec, ScopeChainNode* scopeChainNode, ExecState* calleeArgsExec = 0)
    491491        {
    492492            ASSERT(exec->globalData().dynamicGlobalObject);
    493493            JSObject* error = 0;
    494494            if (!m_codeBlockForConstruct)
    495                 error = compileForConstructInternal(exec, scopeChainNode, JITCode::bottomTierJIT());
     495                error = compileForConstructInternal(exec, scopeChainNode, calleeArgsExec, JITCode::bottomTierJIT());
    496496            ASSERT(!error == !!m_codeBlockForConstruct);
    497497            return error;
    498498        }
    499499
    500         JSObject* compileOptimizedForConstruct(ExecState*, ScopeChainNode*);
     500        JSObject* compileOptimizedForConstruct(ExecState*, ScopeChainNode*, ExecState* calleeArgsExec = 0);
    501501
    502502        bool isGeneratedForConstruct() const
     
    522522                return compileForCall(exec, scopeChainNode, exec);
    523523            ASSERT(kind == CodeForConstruct);
    524             return compileForConstruct(exec, scopeChainNode);
     524            return compileForConstruct(exec, scopeChainNode, exec);
    525525        }
    526526       
     
    536536                return compileOptimizedForCall(exec, scopeChainNode, exec);
    537537            ASSERT(kind == CodeForConstruct);
    538             return compileOptimizedForConstruct(exec, scopeChainNode);
     538            return compileOptimizedForConstruct(exec, scopeChainNode, exec);
    539539        }
    540540       
     
    588588
    589589        JSObject* compileForCallInternal(ExecState*, ScopeChainNode*, ExecState* calleeArgsExec, JITCode::JITType);
    590         JSObject* compileForConstructInternal(ExecState*, ScopeChainNode*, JITCode::JITType);
     590        JSObject* compileForConstructInternal(ExecState*, ScopeChainNode*, ExecState* calleeArgsExec, JITCode::JITType);
    591591       
    592592        static const unsigned StructureFlags = OverridesVisitChildren | ScriptExecutable::StructureFlags;
Note: See TracChangeset for help on using the changeset viewer.