Changeset 89861 in webkit


Ignore:
Timestamp:
Jun 27, 2011 2:38:09 PM (13 years ago)
Author:
commit-queue@webkit.org
Message:

2011-06-27 Filip Pizlo <fpizlo@apple.com>

Reviewed by Gavin Barraclough.

DFG JIT does not perform put_by_id caching.
https://bugs.webkit.org/show_bug.cgi?id=63409

  • bytecode/StructureStubInfo.h:
  • dfg/DFGJITCodeGenerator.cpp: (JSC::DFG::JITCodeGenerator::cachedPutById):
  • dfg/DFGJITCodeGenerator.h:
  • dfg/DFGJITCompiler.cpp: (JSC::DFG::JITCompiler::compileFunction):
  • dfg/DFGJITCompiler.h: (JSC::DFG::JITCompiler::addPropertyAccess): (JSC::DFG::JITCompiler::PropertyAccessRecord::PropertyAccessRecord):
  • dfg/DFGNonSpeculativeJIT.cpp: (JSC::DFG::NonSpeculativeJIT::compile):
  • dfg/DFGOperations.cpp:
  • dfg/DFGOperations.h:
  • dfg/DFGRepatch.cpp: (JSC::DFG::dfgRepatchByIdSelfAccess): (JSC::DFG::tryCacheGetByID): (JSC::DFG::appropriatePutByIdFunction): (JSC::DFG::tryCachePutByID): (JSC::DFG::dfgRepatchPutByID):
  • dfg/DFGRepatch.h:
  • dfg/DFGSpeculativeJIT.cpp: (JSC::DFG::SpeculativeJIT::compile):
Location:
trunk/Source/JavaScriptCore
Files:
12 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r89817 r89861  
     12011-06-27  Filip Pizlo  <fpizlo@apple.com>
     2
     3        Reviewed by Gavin Barraclough.
     4
     5        DFG JIT does not perform put_by_id caching.
     6        https://bugs.webkit.org/show_bug.cgi?id=63409
     7
     8        * bytecode/StructureStubInfo.h:
     9        * dfg/DFGJITCodeGenerator.cpp:
     10        (JSC::DFG::JITCodeGenerator::cachedPutById):
     11        * dfg/DFGJITCodeGenerator.h:
     12        * dfg/DFGJITCompiler.cpp:
     13        (JSC::DFG::JITCompiler::compileFunction):
     14        * dfg/DFGJITCompiler.h:
     15        (JSC::DFG::JITCompiler::addPropertyAccess):
     16        (JSC::DFG::JITCompiler::PropertyAccessRecord::PropertyAccessRecord):
     17        * dfg/DFGNonSpeculativeJIT.cpp:
     18        (JSC::DFG::NonSpeculativeJIT::compile):
     19        * dfg/DFGOperations.cpp:
     20        * dfg/DFGOperations.h:
     21        * dfg/DFGRepatch.cpp:
     22        (JSC::DFG::dfgRepatchByIdSelfAccess):
     23        (JSC::DFG::tryCacheGetByID):
     24        (JSC::DFG::appropriatePutByIdFunction):
     25        (JSC::DFG::tryCachePutByID):
     26        (JSC::DFG::dfgRepatchPutByID):
     27        * dfg/DFGRepatch.h:
     28        * dfg/DFGSpeculativeJIT.cpp:
     29        (JSC::DFG::SpeculativeJIT::compile):
     30
    1312011-06-27  Gustavo Noronha Silva  <gns@gnome.org>
    232
  • trunk/Source/JavaScriptCore/bytecode/StructureStubInfo.h

    r87771 r89861  
    134134            struct {
    135135                intptr_t deltaCheckToCall;
    136                 intptr_t deltaCallToLoad;
     136                intptr_t deltaCallToLoadOrStore;
    137137            } unset;
    138138            struct {
  • trunk/Source/JavaScriptCore/dfg/DFGJITCodeGenerator.cpp

    r89643 r89861  
    351351}
    352352
     353void JITCodeGenerator::cachedPutById(GPRReg baseGPR, GPRReg valueGPR, GPRReg scratchGPR, unsigned identifierNumber, PutKind putKind, JITCompiler::Jump slowPathTarget)
     354{
     355    JITCompiler::DataLabelPtr structureToCompare;
     356    JITCompiler::Jump structureCheck = m_jit.branchPtrWithPatch(JITCompiler::Equal, JITCompiler::Address(baseGPR, JSCell::structureOffset()), structureToCompare, JITCompiler::TrustedImmPtr(reinterpret_cast<void*>(-1)));
     357   
     358    if (slowPathTarget.isSet())
     359        slowPathTarget.link(&m_jit);
     360
     361    silentSpillAllRegisters(InvalidGPRReg, baseGPR, valueGPR);
     362    setupTwoStubArgs<GPRInfo::argumentGPR1, GPRInfo::argumentGPR2>(valueGPR, baseGPR);
     363    m_jit.move(JITCompiler::ImmPtr(identifier(identifierNumber)), GPRInfo::argumentGPR3);
     364    m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
     365    V_DFGOperation_EJJI optimizedCall;
     366    if (m_jit.codeBlock()->isStrictMode()) {
     367        if (putKind == Direct)
     368            optimizedCall = operationPutByIdDirectStrictOptimize;
     369        else
     370            optimizedCall = operationPutByIdStrictOptimize;
     371    } else {
     372        if (putKind == Direct)
     373            optimizedCall = operationPutByIdDirectNonStrictOptimize;
     374        else
     375            optimizedCall = operationPutByIdNonStrictOptimize;
     376    }
     377    JITCompiler::Call functionCall = appendCallWithExceptionCheck(optimizedCall);
     378    silentFillAllRegisters(InvalidGPRReg);
     379
     380    JITCompiler::Jump handledByC = m_jit.jump();
     381    structureCheck.link(&m_jit);
     382
     383    m_jit.loadPtr(JITCompiler::Address(baseGPR, JSObject::offsetOfPropertyStorage()), scratchGPR);
     384    JITCompiler::DataLabel32 storeWithPatch = m_jit.storePtrWithAddressOffsetPatch(valueGPR, JITCompiler::Address(scratchGPR, 0));
     385
     386    intptr_t checkToCall = m_jit.differenceBetween(structureToCompare, functionCall);
     387    intptr_t callToStore = m_jit.differenceBetween(functionCall, storeWithPatch);
     388
     389    handledByC.link(&m_jit);
     390
     391    m_jit.addPropertyAccess(functionCall, checkToCall, callToStore);
     392}
     393
    353394#ifndef NDEBUG
    354395static const char* dataFormatString(DataFormat format)
  • trunk/Source/JavaScriptCore/dfg/DFGJITCodeGenerator.h

    r89643 r89861  
    502502
    503503    void cachedGetById(GPRReg baseGPR, GPRReg resultGPR, unsigned identifierNumber, JITCompiler::Jump slowPathTarget = JITCompiler::Jump());
     504    void cachedPutById(GPRReg baseGPR, GPRReg valueGPR, GPRReg scratchGPR, unsigned identifierNumber, PutKind, JITCompiler::Jump slowPathTarget = JITCompiler::Jump());
    504505
    505506    // Called once a node has completed code generation but prior to setting
  • trunk/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp

    r89611 r89861  
    389389        info.callReturnLocation = linkBuffer.locationOf(m_propertyAccesses[i].m_functionCall);
    390390        info.u.unset.deltaCheckToCall = m_propertyAccesses[i].m_deltaCheckToCall;
    391         info.u.unset.deltaCallToLoad = m_propertyAccesses[i].m_deltaCallToLoad;
     391        info.u.unset.deltaCallToLoadOrStore = m_propertyAccesses[i].m_deltaCallToLoadOrStore;
    392392    }
    393393
  • trunk/Source/JavaScriptCore/dfg/DFGJITCompiler.h

    r89611 r89861  
    233233#endif
    234234
    235     void addPropertyAccess(JITCompiler::Call functionCall, intptr_t deltaCheckToCall, intptr_t deltaCallToLoad)
    236     {
    237         m_propertyAccesses.append(PropertyAccessRecord(functionCall, deltaCheckToCall, deltaCallToLoad));
     235    void addPropertyAccess(JITCompiler::Call functionCall, intptr_t deltaCheckToCall, intptr_t deltaCallToLoadOrStore)
     236    {
     237        m_propertyAccesses.append(PropertyAccessRecord(functionCall, deltaCheckToCall, deltaCallToLoadOrStore));
    238238    }
    239239
     
    259259
    260260    struct PropertyAccessRecord {
    261         PropertyAccessRecord(JITCompiler::Call functionCall, intptr_t deltaCheckToCall, intptr_t deltaCallToLoad)
     261        PropertyAccessRecord(JITCompiler::Call functionCall, intptr_t deltaCheckToCall, intptr_t deltaCallToLoadOrStore)
    262262            : m_functionCall(functionCall)
    263263            , m_deltaCheckToCall(deltaCheckToCall)
    264             , m_deltaCallToLoad(deltaCallToLoad)
     264            , m_deltaCallToLoadOrStore(deltaCallToLoadOrStore)
    265265        {
    266266        }
     
    268268        JITCompiler::Call m_functionCall;
    269269        intptr_t m_deltaCheckToCall;
    270         intptr_t m_deltaCallToLoad;
     270        intptr_t m_deltaCallToLoadOrStore;
    271271    };
    272272
  • trunk/Source/JavaScriptCore/dfg/DFGNonSpeculativeJIT.cpp

    r89772 r89861  
    771771        JSValueOperand base(this, node.child1);
    772772        JSValueOperand value(this, node.child2);
     773        GPRTemporary scratch(this, base);
    773774        GPRReg valueGPR = value.gpr();
    774775        GPRReg baseGPR = base.gpr();
    775         flushRegisters();
    776 
    777         callOperation(m_jit.codeBlock()->isStrictMode() ? operationPutByIdStrict : operationPutByIdNonStrict, valueGPR, baseGPR, identifier(node.identifierNumber()));
     776       
     777        JITCompiler::Jump notCell = m_jit.branchTestPtr(MacroAssembler::NonZero, baseGPR, GPRInfo::tagMaskRegister);
     778
     779        cachedPutById(baseGPR, valueGPR, scratch.gpr(), node.identifierNumber(), NotDirect, notCell);
     780
    778781        noResult(m_compileIndex);
    779782        break;
     
    783786        JSValueOperand base(this, node.child1);
    784787        JSValueOperand value(this, node.child2);
     788        GPRTemporary scratch(this, base);
    785789        GPRReg valueGPR = value.gpr();
    786790        GPRReg baseGPR = base.gpr();
    787         flushRegisters();
    788 
    789         callOperation(m_jit.codeBlock()->isStrictMode() ? operationPutByIdDirectStrict : operationPutByIdDirectNonStrict, valueGPR, baseGPR, identifier(node.identifierNumber()));
     791       
     792        JITCompiler::Jump notCell = m_jit.branchTestPtr(MacroAssembler::NonZero, baseGPR, GPRInfo::tagMaskRegister);
     793
     794        cachedPutById(baseGPR, valueGPR, scratch.gpr(), node.identifierNumber(), Direct, notCell);
     795
    790796        noResult(m_compileIndex);
    791797        break;
  • trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp

    r89772 r89861  
    4444    );
    4545#define FUNCTION_WRAPPER_WITH_ARG4_RETURN_ADDRESS(function) FUNCTION_WRAPPER_WITH_RETURN_ADDRESS(function, rcx)
     46#define FUNCTION_WRAPPER_WITH_ARG5_RETURN_ADDRESS(function) FUNCTION_WRAPPER_WITH_RETURN_ADDRESS(function, r8)
    4647
    4748namespace JSC { namespace DFG {
     
    285286}
    286287
     288void operationPutByIdStrictOptimizeWithReturnAddress(ExecState*, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier* propertyName, ReturnAddressPtr);
     289FUNCTION_WRAPPER_WITH_ARG5_RETURN_ADDRESS(operationPutByIdStrictOptimize);
     290void operationPutByIdStrictOptimizeWithReturnAddress(ExecState* exec, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier* propertyName, ReturnAddressPtr returnAddress)
     291{
     292    JSValue value = JSValue::decode(encodedValue);
     293    JSValue base = JSValue::decode(encodedBase);
     294    PutPropertySlot slot(true);
     295   
     296    base.put(exec, *propertyName, value, slot);
     297   
     298    StructureStubInfo& stubInfo = exec->codeBlock()->getStubInfo(returnAddress);
     299    if (stubInfo.seen)
     300        dfgRepatchPutByID(exec, base, *propertyName, slot, stubInfo, NotDirect);
     301    else
     302        stubInfo.seen = true;
     303}
     304
     305void operationPutByIdNonStrictOptimizeWithReturnAddress(ExecState*, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier* propertyName, ReturnAddressPtr);
     306FUNCTION_WRAPPER_WITH_ARG5_RETURN_ADDRESS(operationPutByIdNonStrictOptimize);
     307void operationPutByIdNonStrictOptimizeWithReturnAddress(ExecState* exec, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier* propertyName, ReturnAddressPtr returnAddress)
     308{
     309    JSValue value = JSValue::decode(encodedValue);
     310    JSValue base = JSValue::decode(encodedBase);
     311    PutPropertySlot slot(false);
     312   
     313    base.put(exec, *propertyName, value, slot);
     314   
     315    StructureStubInfo& stubInfo = exec->codeBlock()->getStubInfo(returnAddress);
     316    if (stubInfo.seen)
     317        dfgRepatchPutByID(exec, base, *propertyName, slot, stubInfo, NotDirect);
     318    else
     319        stubInfo.seen = true;
     320}
     321
     322void operationPutByIdDirectStrictOptimizeWithReturnAddress(ExecState*, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier* propertyName, ReturnAddressPtr);
     323FUNCTION_WRAPPER_WITH_ARG5_RETURN_ADDRESS(operationPutByIdDirectStrictOptimize);
     324void operationPutByIdDirectStrictOptimizeWithReturnAddress(ExecState* exec, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier* propertyName, ReturnAddressPtr returnAddress)
     325{
     326    JSValue value = JSValue::decode(encodedValue);
     327    JSValue base = JSValue::decode(encodedBase);
     328    PutPropertySlot slot(true);
     329   
     330    base.putDirect(exec, *propertyName, value, slot);
     331   
     332    StructureStubInfo& stubInfo = exec->codeBlock()->getStubInfo(returnAddress);
     333    if (stubInfo.seen)
     334        dfgRepatchPutByID(exec, base, *propertyName, slot, stubInfo, Direct);
     335    else
     336        stubInfo.seen = true;
     337}
     338
     339void operationPutByIdDirectNonStrictOptimizeWithReturnAddress(ExecState*, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier* propertyName, ReturnAddressPtr);
     340FUNCTION_WRAPPER_WITH_ARG5_RETURN_ADDRESS(operationPutByIdDirectNonStrictOptimize);
     341void operationPutByIdDirectNonStrictOptimizeWithReturnAddress(ExecState* exec, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier* propertyName, ReturnAddressPtr returnAddress)
     342{
     343    JSValue value = JSValue::decode(encodedValue);
     344    JSValue base = JSValue::decode(encodedBase);
     345    PutPropertySlot slot(false);
     346   
     347    base.putDirect(exec, *propertyName, value, slot);
     348   
     349    StructureStubInfo& stubInfo = exec->codeBlock()->getStubInfo(returnAddress);
     350    if (stubInfo.seen)
     351        dfgRepatchPutByID(exec, base, *propertyName, slot, stubInfo, Direct);
     352    else
     353        stubInfo.seen = true;
     354}
     355
    287356bool operationCompareLess(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
    288357{
  • trunk/Source/JavaScriptCore/dfg/DFGOperations.h

    r89772 r89861  
    3232
    3333namespace JSC { namespace DFG {
     34
     35enum PutKind { Direct, NotDirect };
     36
    3437extern "C" {
    3538
     
    6568void operationPutByIdDirectStrict(ExecState*, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier*);
    6669void operationPutByIdDirectNonStrict(ExecState*, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier*);
     70void operationPutByIdStrictOptimize(ExecState*, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier*);
     71void operationPutByIdNonStrictOptimize(ExecState*, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier*);
     72void operationPutByIdDirectStrictOptimize(ExecState*, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier*);
     73void operationPutByIdDirectNonStrictOptimize(ExecState*, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier*);
    6774bool operationCompareLess(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2);
    6875bool operationCompareLessEq(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2);
  • trunk/Source/JavaScriptCore/dfg/DFGRepatch.cpp

    r87431 r89861  
    2929#if ENABLE(DFG_JIT)
    3030
    31 #include "DFGOperations.h"
    3231#include "RepatchBuffer.h"
    3332
     
    4039}
    4140
    42 static void dfgRepatchGetByIdSelf(CodeBlock* codeBlock, StructureStubInfo& stubInfo, Structure* structure, size_t offset)
     41static void dfgRepatchByIdSelfAccess(CodeBlock* codeBlock, StructureStubInfo& stubInfo, Structure* structure, size_t offset, const FunctionPtr &slowPathFunction, bool compact)
    4342{
    4443    RepatchBuffer repatchBuffer(codeBlock);
    4544
    4645    // Only optimize once!
    47     repatchBuffer.relink(stubInfo.callReturnLocation, operationGetById);
     46    repatchBuffer.relink(stubInfo.callReturnLocation, slowPathFunction);
    4847
    4948    // Patch the structure check & the offset of the load.
    5049    repatchBuffer.repatch(stubInfo.callReturnLocation.dataLabelPtrAtOffset(-(intptr_t)stubInfo.u.unset.deltaCheckToCall), structure);
    51     repatchBuffer.repatch(stubInfo.callReturnLocation.dataLabelCompactAtOffset(stubInfo.u.unset.deltaCallToLoad), sizeof(JSValue) * offset);
     50    if (compact)
     51        repatchBuffer.repatch(stubInfo.callReturnLocation.dataLabelCompactAtOffset(stubInfo.u.unset.deltaCallToLoadOrStore), sizeof(JSValue) * offset);
     52    else
     53        repatchBuffer.repatch(stubInfo.callReturnLocation.dataLabel32AtOffset(stubInfo.u.unset.deltaCallToLoadOrStore), sizeof(JSValue) * offset);
    5254}
    5355
     
    7779            return false;
    7880
    79         dfgRepatchGetByIdSelf(codeBlock, stubInfo, structure, slot.cachedOffset());
     81        dfgRepatchByIdSelfAccess(codeBlock, stubInfo, structure, slot.cachedOffset(), operationGetById, true);
    8082        stubInfo.initGetByIdSelf(*globalData, codeBlock->ownerExecutable(), structure);
    8183        return true;
     
    9395}
    9496
     97static V_DFGOperation_EJJI appropriatePutByIdFunction(const PutPropertySlot &slot, PutKind putKind)
     98{
     99    if (slot.isStrictMode()) {
     100        if (putKind == Direct)
     101            return operationPutByIdDirectStrict;
     102        return operationPutByIdStrict;
     103    }
     104    if (putKind == Direct)
     105        return operationPutByIdDirectNonStrict;
     106    return operationPutByIdNonStrict;
     107}
     108
     109static bool tryCachePutByID(ExecState* exec, JSValue baseValue, const Identifier&, const PutPropertySlot& slot, StructureStubInfo& stubInfo, PutKind putKind)
     110{
     111    CodeBlock* codeBlock = exec->codeBlock();
     112    JSGlobalData* globalData = &exec->globalData();
     113
     114    if (!baseValue.isCell())
     115        return false;
     116    JSCell* baseCell = baseValue.asCell();
     117    Structure* structure = baseCell->structure();
     118    if (!slot.isCacheable())
     119        return false;
     120    if (structure->isUncacheableDictionary())
     121        return false;
     122
     123    // Optimize self access.
     124    if (slot.base() == baseValue) {
     125        if (slot.type() == PutPropertySlot::NewProperty)
     126            return false;
     127
     128        dfgRepatchByIdSelfAccess(codeBlock, stubInfo, structure, slot.cachedOffset(), appropriatePutByIdFunction(slot, putKind), false);
     129        stubInfo.initPutByIdReplace(*globalData, codeBlock->ownerExecutable(), structure);
     130        return true;
     131    }
     132
     133    // FIXME: should support the transition case!
     134    return false;
     135}
     136
     137void dfgRepatchPutByID(ExecState* exec, JSValue baseValue, const Identifier& propertyName, const PutPropertySlot& slot, StructureStubInfo& stubInfo, PutKind putKind)
     138{
     139    bool cached = tryCachePutByID(exec, baseValue, propertyName, slot, stubInfo, putKind);
     140    if (!cached)
     141        dfgRepatchCall(exec->codeBlock(), stubInfo.callReturnLocation, appropriatePutByIdFunction(slot, putKind));
     142}
     143
    95144} } // namespace JSC::DFG
    96145
  • trunk/Source/JavaScriptCore/dfg/DFGRepatch.h

    r87431 r89861  
    3030
    3131#include <dfg/DFGJITCompiler.h>
     32#include <dfg/DFGOperations.h>
    3233
    3334namespace JSC { namespace DFG {
    3435
    3536void dfgRepatchGetByID(ExecState*, JSValue, const Identifier&, const PropertySlot&, StructureStubInfo&);
     37void dfgRepatchPutByID(ExecState*, JSValue, const Identifier&, const PutPropertySlot&, StructureStubInfo&, PutKind);
    3638
    3739} } // namespace JSC::DFG
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp

    r89643 r89861  
    864864
    865865    case PutById: {
    866         JSValueOperand base(this, node.child1);
     866        SpeculateCellOperand base(this, node.child1);
    867867        JSValueOperand value(this, node.child2);
    868         GPRReg valueGPR = value.gpr();
    869         GPRReg baseGPR = base.gpr();
    870         flushRegisters();
    871 
    872         callOperation(m_jit.codeBlock()->isStrictMode() ? operationPutByIdStrict : operationPutByIdNonStrict, valueGPR, baseGPR, identifier(node.identifierNumber()));
     868        GPRTemporary scratch(this, base);
     869
     870        cachedPutById(base.gpr(), value.gpr(), scratch.gpr(), node.identifierNumber(), NotDirect);
     871       
    873872        noResult(m_compileIndex);
    874873        break;
     
    876875
    877876    case PutByIdDirect: {
    878         JSValueOperand base(this, node.child1);
     877        SpeculateCellOperand base(this, node.child1);
    879878        JSValueOperand value(this, node.child2);
    880         GPRReg valueGPR = value.gpr();
    881         GPRReg baseGPR = base.gpr();
    882         flushRegisters();
    883 
    884         callOperation(m_jit.codeBlock()->isStrictMode() ? operationPutByIdDirectStrict : operationPutByIdDirectNonStrict, valueGPR, baseGPR, identifier(node.identifierNumber()));
     879        GPRTemporary scratch(this, base);
     880
     881        cachedPutById(base.gpr(), value.gpr(), scratch.gpr(), node.identifierNumber(), Direct);
     882
    885883        noResult(m_compileIndex);
    886884        break;
Note: See TracChangeset for help on using the changeset viewer.