Changeset 59056 in webkit for trunk/JavaScriptCore


Ignore:
Timestamp:
May 9, 2010, 4:42:22 AM (15 years ago)
Author:
[email protected]
Message:

2010-05-09 Oliver Hunt <[email protected]>

Reviewed by Maciej Stachowiak.

Improve string indexing performance
https://bugs.webkit.org/show_bug.cgi?id=38814

Add an assembly stub to do indexed loads from strings much
more cheaply than the current stub dispatch logic. We can
do this because we are able to make guarantees about the
register contents when entering the stub so the call overhead
is negligible.

  • jit/JIT.h:
  • jit/JITInlineMethods.h:
  • jit/JITOpcodes.cpp:
  • jit/JITPropertyAccess.cpp: (JSC::JIT::stringGetByValStubGenerator): (JSC::JIT::emitSlow_op_get_by_val):

Moved from JITOpcodes.cpp to keep the slowcase next to
the normal case codegen as we do for everything else.

  • jit/JITPropertyAccess32_64.cpp: (JSC::JIT::stringGetByValStubGenerator): (JSC::JIT::emitSlow_op_get_by_val):
  • jit/JSInterfaceJIT.h: (JSC::JSInterfaceJIT::emitFastArithImmToInt):
Location:
trunk/JavaScriptCore
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/ChangeLog

    r59055 r59056  
     12010-05-09  Oliver Hunt  <[email protected]>
     2
     3        Reviewed by Maciej Stachowiak.
     4
     5        Improve string indexing performance
     6        https://bugs.webkit.org/show_bug.cgi?id=38814
     7
     8        Add an assembly stub to do indexed loads from strings much
     9        more cheaply than the current stub dispatch logic.  We can
     10        do this because we are able to make guarantees about the
     11        register contents when entering the stub so the call overhead
     12        is negligible.
     13
     14        * jit/JIT.h:
     15        * jit/JITInlineMethods.h:
     16        * jit/JITOpcodes.cpp:
     17        * jit/JITPropertyAccess.cpp:
     18        (JSC::JIT::stringGetByValStubGenerator):
     19        (JSC::JIT::emitSlow_op_get_by_val):
     20           Moved from JITOpcodes.cpp to keep the slowcase next to
     21           the normal case codegen as we do for everything else.
     22        * jit/JITPropertyAccess32_64.cpp:
     23        (JSC::JIT::stringGetByValStubGenerator):
     24        (JSC::JIT::emitSlow_op_get_by_val):
     25        * jit/JSInterfaceJIT.h:
     26        (JSC::JSInterfaceJIT::emitFastArithImmToInt):
     27
    1282010-05-09  Maciej Stachowiak  <[email protected]>
    229
  • trunk/JavaScriptCore/jit/JIT.h

    r58986 r59056  
    448448#endif
    449449        void emitFastArithReTagImmediate(RegisterID src, RegisterID dest);
    450         void emitFastArithImmToInt(RegisterID);
    451450        void emitFastArithIntToImmNoCheck(RegisterID src, RegisterID dest);
    452451
     
    905904#endif
    906905#endif
     906        static PassRefPtr<NativeExecutable> stringGetByValStubGenerator(JSGlobalData* globalData, ExecutablePool* pool);
    907907    } JIT_CLASS_ALIGNMENT;
    908908
  • trunk/JavaScriptCore/jit/JITInlineMethods.h

    r58902 r59056  
    821821}
    822822
    823 ALWAYS_INLINE void JIT::emitFastArithImmToInt(RegisterID reg)
    824 {
    825 #if USE(JSVALUE64)
    826     UNUSED_PARAM(reg);
    827 #else
    828     rshift32(Imm32(JSImmediate::IntegerPayloadShift), reg);
    829 #endif
    830 }
    831 
    832823// operand is int32_t, must have been zero-extended if register is 64-bit.
    833824ALWAYS_INLINE void JIT::emitFastArithIntToImmNoCheck(RegisterID src, RegisterID dest)
  • trunk/JavaScriptCore/jit/JITOpcodes.cpp

    r59040 r59056  
    14081408}
    14091409
    1410 void JIT::emitSlow_op_get_by_val(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
    1411 {
    1412     unsigned dst = currentInstruction[1].u.operand;
    1413     unsigned base = currentInstruction[2].u.operand;
    1414     unsigned property = currentInstruction[3].u.operand;
    1415 
    1416     linkSlowCase(iter); // property int32 check
    1417     linkSlowCaseIfNotJSCell(iter, base); // base cell check
    1418     linkSlowCase(iter); // base array check
    1419     linkSlowCase(iter); // vector length check
    1420     linkSlowCase(iter); // empty value
    1421 
    1422     JITStubCall stubCall(this, cti_op_get_by_val);
    1423     stubCall.addArgument(base, regT2);
    1424     stubCall.addArgument(property, regT2);
    1425     stubCall.call(dst);
    1426 }
    1427 
    14281410void JIT::emitSlow_op_loop_if_lesseq(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
    14291411{
  • trunk/JavaScriptCore/jit/JITPropertyAccess.cpp

    r55564 r59056  
    5353namespace JSC {
    5454
     55PassRefPtr<NativeExecutable> JIT::stringGetByValStubGenerator(JSGlobalData* globalData, ExecutablePool* pool)
     56{
     57    JSInterfaceJIT jit;
     58    JumpList failures;
     59    failures.append(jit.branchPtr(NotEqual, Address(regT0), ImmPtr(globalData->jsStringVPtr)));
     60    failures.append(jit.branchTest32(NonZero, Address(regT0, OBJECT_OFFSETOF(JSString, m_fiberCount))));
     61#if USE(JSVALUE64)
     62    jit.zeroExtend32ToPtr(regT1, regT1);
     63#else
     64    jit.emitFastArithImmToInt(regT1);
     65#endif
     66
     67    // Load string length to regT1, and start the process of loading the data pointer into regT0
     68    jit.load32(Address(regT0, ThunkHelpers::jsStringLengthOffset()), regT2);
     69    jit.loadPtr(Address(regT0, ThunkHelpers::jsStringValueOffset()), regT0);
     70    jit.loadPtr(Address(regT0, ThunkHelpers::stringImplDataOffset()), regT0);
     71   
     72    // Do an unsigned compare to simultaneously filter negative indices as well as indices that are too large
     73    failures.append(jit.branch32(AboveOrEqual, regT1, regT2));
     74   
     75    // Load the character
     76    jit.load16(BaseIndex(regT0, regT1, TimesTwo, 0), regT0);
     77   
     78    failures.append(jit.branch32(AboveOrEqual, regT0, Imm32(0x100)));
     79    jit.move(ImmPtr(globalData->smallStrings.singleCharacterStrings()), regT1);
     80    jit.loadPtr(BaseIndex(regT1, regT0, ScalePtr, 0), regT0);
     81    jit.ret();
     82   
     83    failures.link(&jit);
     84    jit.move(Imm32(0), regT0);
     85    jit.ret();
     86   
     87    LinkBuffer patchBuffer(&jit, pool);
     88    return adoptRef(new NativeExecutable(patchBuffer.finalizeCode()));
     89}
     90
    5591void JIT::emit_op_get_by_val(Instruction* currentInstruction)
    5692{
     
    82118
    83119    emitPutVirtualRegister(dst);
     120}
     121
     122void JIT::emitSlow_op_get_by_val(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
     123{
     124    unsigned dst = currentInstruction[1].u.operand;
     125    unsigned base = currentInstruction[2].u.operand;
     126    unsigned property = currentInstruction[3].u.operand;
     127   
     128    linkSlowCase(iter); // property int32 check
     129    linkSlowCaseIfNotJSCell(iter, base); // base cell check
     130    Jump nonCell = jump();
     131    linkSlowCase(iter); // base array check
     132    Jump notString = branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsStringVPtr));
     133    emitNakedCall(m_globalData->getThunk(stringGetByValStubGenerator)->generatedJITCode().addressForCall());
     134    Jump failed = branchTestPtr(Zero, regT0);
     135    emitPutVirtualRegister(dst, regT0);
     136    emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_get_by_val));
     137    failed.link(this);
     138    notString.link(this);
     139    nonCell.link(this);
     140   
     141    linkSlowCase(iter); // vector length check
     142    linkSlowCase(iter); // empty value
     143   
     144    JITStubCall stubCall(this, cti_op_get_by_val);
     145    stubCall.addArgument(base, regT2);
     146    stubCall.addArgument(property, regT2);
     147    stubCall.call(dst);
    84148}
    85149
  • trunk/JavaScriptCore/jit/JITPropertyAccess32_64.cpp

    r55564 r59056  
    270270#endif
    271271
     272PassRefPtr<NativeExecutable> JIT::stringGetByValStubGenerator(JSGlobalData* globalData, ExecutablePool* pool)
     273{
     274    JSInterfaceJIT jit;
     275    JumpList failures;
     276    failures.append(jit.branchPtr(NotEqual, Address(regT0), ImmPtr(globalData->jsStringVPtr)));
     277    failures.append(jit.branchTest32(NonZero, Address(regT0, OBJECT_OFFSETOF(JSString, m_fiberCount))));
     278   
     279    // Load string length to regT1, and start the process of loading the data pointer into regT0
     280    jit.load32(Address(regT0, ThunkHelpers::jsStringLengthOffset()), regT1);
     281    jit.loadPtr(Address(regT0, ThunkHelpers::jsStringValueOffset()), regT0);
     282    jit.loadPtr(Address(regT0, ThunkHelpers::stringImplDataOffset()), regT0);
     283   
     284    // Do an unsigned compare to simultaneously filter negative indices as well as indices that are too large
     285    failures.append(jit.branch32(AboveOrEqual, regT2, regT1));
     286   
     287    // Load the character
     288    jit.load16(BaseIndex(regT0, regT2, TimesTwo, 0), regT0);
     289   
     290    failures.append(jit.branch32(AboveOrEqual, regT0, Imm32(0x100)));
     291    jit.move(ImmPtr(globalData->smallStrings.singleCharacterStrings()), regT1);
     292    jit.loadPtr(BaseIndex(regT1, regT0, ScalePtr, 0), regT0);
     293    jit.move(Imm32(JSValue::CellTag), regT1); // We null check regT0 on return so this is safe
     294    jit.ret();
     295
     296    failures.link(&jit);
     297    jit.move(Imm32(0), regT0);
     298    jit.ret();
     299   
     300    LinkBuffer patchBuffer(&jit, pool);
     301    return adoptRef(new NativeExecutable(patchBuffer.finalizeCode()));
     302}
     303
    272304void JIT::emit_op_get_by_val(Instruction* currentInstruction)
    273305{
     
    301333    linkSlowCase(iter); // property int32 check
    302334    linkSlowCaseIfNotJSCell(iter, base); // base cell check
     335
     336    Jump nonCell = jump();
    303337    linkSlowCase(iter); // base array check
     338    Jump notString = branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsStringVPtr));
     339    emitNakedCall(m_globalData->getThunk(stringGetByValStubGenerator)->generatedJITCode().addressForCall());
     340    Jump failed = branchTestPtr(Zero, regT0);
     341    emitStore(dst, regT1, regT0);
     342    emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_get_by_val));
     343    failed.link(this);
     344    notString.link(this);
     345    nonCell.link(this);
     346
    304347    linkSlowCase(iter); // vector length check
    305348    linkSlowCase(iter); // empty value
  • trunk/JavaScriptCore/jit/JSInterfaceJIT.h

    r58902 r59056  
    170170        Jump emitJumpIfImmediateNumber(RegisterID reg);
    171171        Jump emitJumpIfNotImmediateNumber(RegisterID reg);
     172        void emitFastArithImmToInt(RegisterID reg);
    172173#endif
    173174
     
    261262        return notNumber;
    262263    }
    263 
     264   
     265    ALWAYS_INLINE void JSInterfaceJIT::emitFastArithImmToInt(RegisterID)
     266    {
     267    }
     268   
    264269#endif
    265270
     
    284289        return jump();
    285290    }
     291   
     292    ALWAYS_INLINE void JSInterfaceJIT::emitFastArithImmToInt(RegisterID reg)
     293    {
     294        rshift32(Imm32(JSImmediate::IntegerPayloadShift), reg);
     295    }
     296   
    286297#endif
    287298
Note: See TracChangeset for help on using the changeset viewer.