Changeset 96189 in webkit


Ignore:
Timestamp:
Sep 27, 2011 10:33:21 PM (13 years ago)
Author:
fpizlo@apple.com
Message:

DFG JIT cannot compile op_new_object, op_new_array,
op_new_array_buffer, or op_new_regexp
https://bugs.webkit.org/show_bug.cgi?id=68580

Reviewed by Oliver Hunt.

This implements all four opcodes, but has op_new_regexp turns off
by default because it unveils some bad speculation logic when
compiling string-validate-input.

With op_new_regexp turned off, this is a 5% win on Kraken and a
0.7% speed-up on V8. Neutral on SunSpider.

  • dfg/DFGByteCodeParser.cpp:

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

  • dfg/DFGCapabilities.h:

(JSC::DFG::canCompileOpcode):

  • dfg/DFGJITCodeGenerator.h:

(JSC::DFG::callOperation):

  • dfg/DFGNode.h:

(JSC::DFG::Node::hasConstantBuffer):
(JSC::DFG::Node::startConstant):
(JSC::DFG::Node::numConstants):
(JSC::DFG::Node::hasRegexpIndex):
(JSC::DFG::Node::regexpIndex):

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

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

  • dfg/DFGSpeculativeJIT.cpp:

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

  • dfg/DFGSpeculativeJIT.h:

(JSC::DFG::SpeculativeJIT::isKnownArray):

Location:
trunk/Source/JavaScriptCore
Files:
10 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r96184 r96189  
     12011-09-27  Filip Pizlo  <fpizlo@apple.com>
     2
     3        DFG JIT cannot compile op_new_object, op_new_array,
     4        op_new_array_buffer, or op_new_regexp
     5        https://bugs.webkit.org/show_bug.cgi?id=68580
     6
     7        Reviewed by Oliver Hunt.
     8       
     9        This implements all four opcodes, but has op_new_regexp turns off
     10        by default because it unveils some bad speculation logic when
     11        compiling string-validate-input.
     12       
     13        With op_new_regexp turned off, this is a 5% win on Kraken and a
     14        0.7% speed-up on V8. Neutral on SunSpider.
     15
     16        * dfg/DFGByteCodeParser.cpp:
     17        (JSC::DFG::ByteCodeParser::parseBlock):
     18        * dfg/DFGCapabilities.h:
     19        (JSC::DFG::canCompileOpcode):
     20        * dfg/DFGJITCodeGenerator.h:
     21        (JSC::DFG::callOperation):
     22        * dfg/DFGNode.h:
     23        (JSC::DFG::Node::hasConstantBuffer):
     24        (JSC::DFG::Node::startConstant):
     25        (JSC::DFG::Node::numConstants):
     26        (JSC::DFG::Node::hasRegexpIndex):
     27        (JSC::DFG::Node::regexpIndex):
     28        * dfg/DFGOperations.cpp:
     29        * dfg/DFGOperations.h:
     30        * dfg/DFGPropagator.cpp:
     31        (JSC::DFG::Propagator::propagateNodePredictions):
     32        * dfg/DFGSpeculativeJIT.cpp:
     33        (JSC::DFG::SpeculativeJIT::emitAllocateJSFinalObject):
     34        (JSC::DFG::SpeculativeJIT::compile):
     35        * dfg/DFGSpeculativeJIT.h:
     36        (JSC::DFG::SpeculativeJIT::isKnownArray):
     37
    1382011-09-27  Filip Pizlo  <fpizlo@apple.com>
    239
  • trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp

    r95930 r96189  
    723723            set(currentInstruction[1].u.operand, addToGraph(CreateThis, op1));
    724724            NEXT_OPCODE(op_create_this);
     725        }
     726           
     727        case op_new_object: {
     728            set(currentInstruction[1].u.operand, addToGraph(NewObject));
     729            NEXT_OPCODE(op_new_object);
     730        }
     731           
     732        case op_new_array: {
     733            int startOperand = currentInstruction[2].u.operand;
     734            int numOperands = currentInstruction[3].u.operand;
     735            for (int operandIdx = startOperand; operandIdx < startOperand + numOperands; ++operandIdx)
     736                addVarArgChild(get(operandIdx));
     737            set(currentInstruction[1].u.operand, addToGraph(Node::VarArg, NewArray, OpInfo(0), OpInfo(0)));
     738            NEXT_OPCODE(op_new_array);
     739        }
     740           
     741        case op_new_array_buffer: {
     742            int startConstant = currentInstruction[2].u.operand;
     743            int numConstants = currentInstruction[3].u.operand;
     744            set(currentInstruction[1].u.operand, addToGraph(NewArrayBuffer, OpInfo(startConstant), OpInfo(numConstants)));
     745            NEXT_OPCODE(op_new_array_buffer);
     746        }
     747           
     748        case op_new_regexp: {
     749            set(currentInstruction[1].u.operand, addToGraph(NewRegexp, OpInfo(currentInstruction[2].u.operand)));
     750            NEXT_OPCODE(op_new_regexp);
    725751        }
    726752           
     
    14021428
    14031429        default:
    1404             // Parse failed!
    1405             ASSERT(!canCompileOpcode(opcodeID));
     1430            // Parse failed! This should not happen because the capabilities checker
     1431            // should have caught it.
     1432            ASSERT_NOT_REACHED();
    14061433            return false;
    14071434        }
  • trunk/Source/JavaScriptCore/dfg/DFGCapabilities.h

    r95932 r96189  
    3131
    3232namespace JSC { namespace DFG {
     33
     34#define ENABLE_DFG_RESTRICTIONS 1
    3335
    3436#if ENABLE(DFG_JIT)
     
    120122    case op_resolve_base:
    121123    case op_resolve_global:
     124    case op_new_object:
     125    case op_new_array:
     126    case op_new_array_buffer:
    122127    case op_strcat:
    123128    case op_to_primitive:
     
    125130    case op_throw_reference_error:
    126131        return true;
     132       
     133    // Opcodes we support conditionally. Enabling these opcodes currently results in
     134    // performance regressions. Each node that we disable under restrictions has a
     135    // comment describing what we know about the regression so far.
     136       
     137    // Regresses string-validate-input, probably because it uses comparisons (< and >)
     138    // on strings, which currently will cause speculation failures in some cases.
     139    case op_new_regexp:
     140#if ENABLE(DFG_RESTRICTIONS)
     141        return false;
     142#else
     143        return true;
     144#endif
     145       
    127146    default:
    128147        return false;
  • trunk/Source/JavaScriptCore/dfg/DFGJITCodeGenerator.h

    r96175 r96189  
    10691069        m_jit.move(GPRInfo::returnValueGPR, result);
    10701070    }
     1071    void callOperation(J_DFGOperation_ESS operation, GPRReg result, int startConstant, int numConstants)
     1072    {
     1073        ASSERT(isFlushed());
     1074
     1075        m_jit.move(JITCompiler::TrustedImm32(numConstants), GPRInfo::argumentGPR2);
     1076        m_jit.move(JITCompiler::TrustedImm32(startConstant), GPRInfo::argumentGPR1);
     1077        m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
     1078
     1079        appendCallWithExceptionCheck(operation);
     1080        m_jit.move(GPRInfo::returnValueGPR, result);
     1081    }
    10711082    void callOperation(J_DFGOperation_EJP operation, GPRReg result, GPRReg arg1, void* pointer)
    10721083    {
  • trunk/Source/JavaScriptCore/dfg/DFGNode.h

    r96184 r96189  
    288288    macro(Construct, NodeResultJS | NodeMustGenerate | NodeHasVarArgs | NodeClobbersWorld) \
    289289    \
     290    /* Allocations. */\
     291    macro(NewObject, NodeResultJS) \
     292    macro(NewArray, NodeResultJS | NodeHasVarArgs) \
     293    macro(NewArrayBuffer, NodeResultJS) \
     294    macro(NewRegexp, NodeResultJS) \
     295    \
    290296    /* Resolve nodes. */\
    291297    macro(Resolve, NodeResultJS | NodeMustGenerate | NodeClobbersWorld) \
     
    561567    }
    562568   
     569    bool hasConstantBuffer()
     570    {
     571        return op == NewArrayBuffer;
     572    }
     573   
     574    unsigned startConstant()
     575    {
     576        ASSERT(hasConstantBuffer());
     577        return m_opInfo;
     578    }
     579   
     580    unsigned numConstants()
     581    {
     582        ASSERT(hasConstantBuffer());
     583        return m_opInfo2;
     584    }
     585   
     586    bool hasRegexpIndex()
     587    {
     588        return op == NewRegexp;
     589    }
     590   
     591    unsigned regexpIndex()
     592    {
     593        ASSERT(hasRegexpIndex());
     594        return m_opInfo;
     595    }
     596   
    563597    bool hasVarNumber()
    564598    {
  • trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp

    r96175 r96189  
    158158}
    159159
     160EncodedJSValue operationNewObject(ExecState* exec)
     161{
     162    return JSValue::encode(constructEmptyObject(exec));
     163}
     164
    160165EncodedJSValue operationValueAdd(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
    161166{
     
    791796}
    792797
     798EncodedJSValue operationNewArray(ExecState* exec, void* start, size_t size)
     799{
     800    ArgList argList(static_cast<Register*>(start), size);
     801    return JSValue::encode(constructArray(exec, argList));
     802}
     803
     804EncodedJSValue operationNewArrayBuffer(ExecState* exec, size_t start, size_t size)
     805{
     806    ArgList argList(exec->codeBlock()->constantBuffer(start), size);
     807    return JSValue::encode(constructArray(exec, argList));
     808}
     809
     810EncodedJSValue operationNewRegexp(ExecState* exec, void* regexpPtr)
     811{
     812    RegExp* regexp = static_cast<RegExp*>(regexpPtr);
     813    if (!regexp->isValid()) {
     814        throwError(exec, createSyntaxError(exec, "Invalid flags supplied to RegExp constructor."));
     815        return JSValue::encode(jsUndefined());
     816    }
     817   
     818    return RegExpObject::create(exec->globalData(), exec->lexicalGlobalObject(), exec->lexicalGlobalObject()->regExpStructure(), regexp);
     819}
     820
    793821void operationThrowHasInstanceError(ExecState* exec, EncodedJSValue encodedBase)
    794822{
  • trunk/Source/JavaScriptCore/dfg/DFGOperations.h

    r95901 r96189  
    5151typedef EncodedJSValue (*J_DFGOperation_EP)(ExecState*, void*);
    5252typedef EncodedJSValue (*J_DFGOperation_EPS)(ExecState*, void*, size_t);
     53typedef EncodedJSValue (*J_DFGOperation_ESS)(ExecState*, size_t, size_t);
    5354typedef EncodedJSValue (*J_DFGOperation_EI)(ExecState*, Identifier*);
    5455typedef RegisterSizedBoolean (*Z_DFGOperation_EJ)(ExecState*, EncodedJSValue);
     
    6364EncodedJSValue operationConvertThis(ExecState*, EncodedJSValue encodedOp1);
    6465EncodedJSValue operationCreateThis(ExecState*, EncodedJSValue encodedOp1);
     66EncodedJSValue operationNewObject(ExecState*);
    6567EncodedJSValue operationValueAdd(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2);
    6668EncodedJSValue operationValueAddNotNumber(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2);
     
    8385EncodedJSValue operationToPrimitive(ExecState*, EncodedJSValue);
    8486EncodedJSValue operationStrCat(ExecState*, void* start, size_t);
     87EncodedJSValue operationNewArray(ExecState*, void* start, size_t);
     88EncodedJSValue operationNewArrayBuffer(ExecState*, size_t, size_t);
     89EncodedJSValue operationNewRegexp(ExecState*, void*);
    8590void operationThrowHasInstanceError(ExecState*, EncodedJSValue base);
    8691void operationPutByValStrict(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue);
  • trunk/Source/JavaScriptCore/dfg/DFGPropagator.cpp

    r96184 r96189  
    510510        }
    511511           
    512         case CreateThis: {
     512        case CreateThis:
     513        case NewObject: {
    513514            changed |= setPrediction(PredictFinalObject);
     515            break;
     516        }
     517           
     518        case NewArray:
     519        case NewArrayBuffer: {
     520            changed |= setPrediction(PredictArray);
     521            break;
     522        }
     523           
     524        case NewRegexp: {
     525            changed |= setPrediction(PredictObjectOther);
    514526            break;
    515527        }
     
    539551            break;
    540552        }
    541 
     553           
    542554        case ValueToDouble:
    543555        case GetArrayLength: {
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp

    r96184 r96189  
    686686}
    687687
     688template<typename T>
     689void SpeculativeJIT::emitAllocateJSFinalObject(T structure, GPRReg resultGPR, GPRReg scratchGPR, MacroAssembler::JumpList& slowPath)
     690{
     691    MarkedSpace::SizeClass* sizeClass = &m_jit.globalData()->heap.sizeClassForObject(sizeof(JSFinalObject));
     692   
     693    m_jit.loadPtr(&sizeClass->firstFreeCell, resultGPR);
     694    slowPath.append(m_jit.branchTestPtr(MacroAssembler::Zero, resultGPR));
     695   
     696    // The object is half-allocated: we have what we know is a fresh object, but
     697    // it's still on the GC's free list.
     698   
     699    // Ditch the structure by placing it into the structure slot, so that we can reuse
     700    // scratchGPR.
     701    m_jit.storePtr(structure, MacroAssembler::Address(resultGPR, JSObject::structureOffset()));
     702   
     703    // Now that we have scratchGPR back, remove the object from the free list
     704    m_jit.loadPtr(MacroAssembler::Address(resultGPR), scratchGPR);
     705    m_jit.storePtr(scratchGPR, &sizeClass->firstFreeCell);
     706   
     707    // Initialize the object's vtable
     708    m_jit.storePtr(MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsFinalObjectVPtr), MacroAssembler::Address(resultGPR));
     709   
     710    // Initialize the object's inheritorID.
     711    m_jit.storePtr(MacroAssembler::TrustedImmPtr(0), MacroAssembler::Address(resultGPR, JSObject::offsetOfInheritorID()));
     712   
     713    // Initialize the object's property storage pointer.
     714    m_jit.addPtr(MacroAssembler::TrustedImm32(sizeof(JSObject)), resultGPR, scratchGPR);
     715    m_jit.storePtr(scratchGPR, MacroAssembler::Address(resultGPR, JSFinalObject::offsetOfPropertyStorage()));
     716}
     717
    688718void SpeculativeJIT::compile(Node& node)
    689719{
     
    13871417        // Check that base is an array, and that property is contained within m_vector (< m_vectorLength).
    13881418        // If we have predicted the base to be type array, we can skip the check.
    1389         Node& baseNode = m_jit.graph()[node.child1()];
    1390         if (baseNode.op != GetLocal || !isArrayPrediction(m_jit.graph().getPrediction(baseNode.local())))
     1419        if (!isKnownArray(node.child1()))
    13911420            speculationCheck(m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsArrayVPtr)));
    13921421        speculationCheck(m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSArray::vectorLengthOffset())));
     
    14221451        // Check that base is an array, and that property is contained within m_vector (< m_vectorLength).
    14231452        // If we have predicted the base to be type array, we can skip the check.
    1424         Node& baseNode = m_jit.graph()[node.child1()];
    1425         if (baseNode.op != GetLocal || !isArrayPrediction(m_jit.graph().getPrediction(baseNode.local())))
     1453        if (!isKnownArray(node.child1()))
    14261454            speculationCheck(m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsArrayVPtr)));
    14271455
     
    16381666    }
    16391667       
    1640     case StrCat: {
    1641         // We really don't want to grow the register file just to do a StrCat. Say we
    1642         // have 50 functions on the stack that all have a StrCat in them that has
     1668    case StrCat:
     1669    case NewArray: {
     1670        // We really don't want to grow the register file just to do a StrCat or NewArray.
     1671        // Say we have 50 functions on the stack that all have a StrCat in them that has
    16431672        // upwards of 10 operands. In the DFG this would mean that each one gets
    16441673        // some random virtual register, and then to do the StrCat we'd need a second
     
    16701699        GPRResult result(this);
    16711700       
    1672         callOperation(operationStrCat, result.gpr(), buffer, node.numChildren());
    1673        
    1674         jsValueResult(result.gpr(), m_compileIndex, UseChildrenCalledExplicitly);
    1675         break;
    1676     }
    1677 
     1701        callOperation(op == StrCat ? operationStrCat : operationNewArray, result.gpr(), buffer, node.numChildren());
     1702       
     1703        cellResult(result.gpr(), m_compileIndex, UseChildrenCalledExplicitly);
     1704        break;
     1705    }
     1706       
     1707    case NewArrayBuffer: {
     1708        flushRegisters();
     1709        GPRResult result(this);
     1710       
     1711        callOperation(operationNewArrayBuffer, result.gpr(), node.startConstant(), node.numConstants());
     1712       
     1713        cellResult(result.gpr(), m_compileIndex);
     1714        break;
     1715    }
     1716       
     1717    case NewRegexp: {
     1718        flushRegisters();
     1719        GPRResult result(this);
     1720       
     1721        callOperation(operationNewRegexp, result.gpr(), m_jit.codeBlock()->regexp(node.regexpIndex()));
     1722       
     1723        cellResult(result.gpr(), m_compileIndex);
     1724        break;
     1725    }
     1726       
    16781727    case ConvertThis: {
    16791728        SpeculateCellOperand thisValue(this, node.child1());
     
    17191768        slowPath.append(m_jit.branchTestPtr(MacroAssembler::Zero, scratchGPR));
    17201769       
    1721         MarkedSpace::SizeClass* sizeClass = &m_jit.globalData()->heap.sizeClassForObject(sizeof(JSFinalObject));
    1722        
    1723         m_jit.loadPtr(&sizeClass->firstFreeCell, resultGPR);
    1724         slowPath.append(m_jit.branchTestPtr(MacroAssembler::Zero, resultGPR));
    1725        
    1726         // The object is half-allocated: we have what we know is a fresh object, but
    1727         // it's still on the GC's free list.
    1728        
    1729         // Ditch the inheritorID by placing it into the structure, so that we can reuse
    1730         // scratchGPR.
    1731         m_jit.storePtr(scratchGPR, MacroAssembler::Address(resultGPR, JSObject::structureOffset()));
    1732        
    1733         // Now that we have scratchGPR back, remove the object from the free list
    1734         m_jit.loadPtr(MacroAssembler::Address(resultGPR), scratchGPR);
    1735         m_jit.storePtr(scratchGPR, &sizeClass->firstFreeCell);
    1736        
    1737         // Initialize the object's vtable
    1738         m_jit.storePtr(MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsFinalObjectVPtr), MacroAssembler::Address(resultGPR));
    1739        
    1740         // Initialize the object's inheritorID.
    1741         m_jit.storePtr(MacroAssembler::TrustedImmPtr(0), MacroAssembler::Address(resultGPR, JSObject::offsetOfInheritorID()));
    1742        
    1743         // Initialize the object's property storage pointer.
    1744         m_jit.addPtr(MacroAssembler::TrustedImm32(sizeof(JSObject)), resultGPR, scratchGPR);
    1745         m_jit.storePtr(scratchGPR, MacroAssembler::Address(resultGPR, JSFinalObject::offsetOfPropertyStorage()));
     1770        emitAllocateJSFinalObject(scratchGPR, resultGPR, scratchGPR, slowPath);
    17461771       
    17471772        MacroAssembler::Jump done = m_jit.jump();
     
    17591784       
    17601785        cellResult(resultGPR, m_compileIndex, UseChildrenCalledExplicitly);
     1786        break;
     1787    }
     1788       
     1789    case NewObject: {
     1790        GPRTemporary result(this);
     1791        GPRTemporary scratch(this);
     1792       
     1793        GPRReg resultGPR = result.gpr();
     1794        GPRReg scratchGPR = scratch.gpr();
     1795       
     1796        MacroAssembler::JumpList slowPath;
     1797       
     1798        emitAllocateJSFinalObject(MacroAssembler::TrustedImmPtr(m_jit.codeBlock()->globalObject()->emptyObjectStructure()), resultGPR, scratchGPR, slowPath);
     1799       
     1800        MacroAssembler::Jump done = m_jit.jump();
     1801       
     1802        slowPath.link(&m_jit);
     1803       
     1804        silentSpillAllRegisters(resultGPR);
     1805        m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
     1806        appendCallWithExceptionCheck(operationNewObject);
     1807        m_jit.move(GPRInfo::returnValueGPR, resultGPR);
     1808        silentFillAllRegisters(resultGPR);
     1809       
     1810        done.link(&m_jit);
     1811       
     1812        cellResult(resultGPR, m_compileIndex);
    17611813        break;
    17621814    }
     
    18341886       
    18351887    case GetArrayLength: {
    1836         Node& baseNode = m_jit.graph()[node.child1()];
    18371888        SpeculateCellOperand base(this, node.child1());
    18381889        GPRTemporary result(this);
     
    18411892        GPRReg resultGPR = result.gpr();
    18421893       
    1843         if (baseNode.op != GetLocal || !isArrayPrediction(m_jit.graph().getPrediction(baseNode.local())))
     1894        if (!isKnownArray(node.child1()))
    18441895            speculationCheck(m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseGPR), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsArrayVPtr)));
    18451896       
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h

    r95930 r96189  
    513513    }
    514514   
     515    bool isKnownArray(NodeIndex op1)
     516    {
     517        Node& node = m_jit.graph()[op1];
     518        switch (node.op) {
     519        case GetLocal:
     520            return isArrayPrediction(m_jit.graph().getPrediction(node.local()));
     521           
     522        case NewArray:
     523        case NewArrayBuffer:
     524            return true;
     525           
     526        default:
     527            return false;
     528        }
     529    }
     530   
    515531    bool compare(Node&, MacroAssembler::RelationalCondition, MacroAssembler::DoubleCondition, Z_DFGOperation_EJJ);
    516532    void compilePeepHoleIntegerBranch(Node&, NodeIndex branchNodeIndex, JITCompiler::RelationalCondition);
     
    518534    void compilePeepHoleObjectEquality(Node&, NodeIndex branchNodeIndex, void* vptr);
    519535    void compileObjectEquality(Node&, void* vptr);
     536   
     537    // It is acceptable to have structure be equal to scratch, so long as you're fine
     538    // with the structure GPR being clobbered.
     539    template<typename T>
     540    void emitAllocateJSFinalObject(T structure, GPRReg resultGPR, GPRReg scratchGPR, MacroAssembler::JumpList& slowPath);
    520541   
    521542#if USE(JSVALUE64)
Note: See TracChangeset for help on using the changeset viewer.