Ignore:
Timestamp:
Oct 3, 2009, 10:01:14 AM (16 years ago)
Author:
[email protected]
Message:

Removed the concept of a "fast access cutoff" in arrays, because it
punished some patterns of array access too much, and made things too
complex for inlining in some cases.

Patch by Geoffrey Garen <[email protected]> on 2009-10-02
Reviewed by Sam Weinig.

1.3% speedup on SunSpider.

  • jit/JITOpcodes.cpp:

(JSC::JIT::emitSlow_op_get_by_val):
(JSC::JIT::emitSlow_op_put_by_val):

  • jit/JITPropertyAccess.cpp:

(JSC::JIT::emit_op_get_by_val):
(JSC::JIT::emitSlow_op_get_by_val):
(JSC::JIT::emit_op_put_by_val):
(JSC::JIT::emitSlow_op_put_by_val):

  • jit/JITStubs.cpp:
  • jit/JITStubs.h:

(JSC::): Check m_vectorLength instead of m_fastAccessCutoff when
getting / putting from / to an array. Inline putting past the end of
the array.

  • runtime/JSArray.cpp:

(JSC::JSArray::JSArray):
(JSC::JSArray::getOwnPropertySlot):
(JSC::JSArray::getOwnPropertyDescriptor):
(JSC::JSArray::put):
(JSC::JSArray::putSlowCase):
(JSC::JSArray::deleteProperty):
(JSC::JSArray::getOwnPropertyNames):
(JSC::JSArray::increaseVectorLength):
(JSC::JSArray::setLength):
(JSC::JSArray::pop):
(JSC::JSArray::push):
(JSC::JSArray::sort):
(JSC::JSArray::fillArgList):
(JSC::JSArray::copyToRegisters):
(JSC::JSArray::compactForSorting):
(JSC::JSArray::checkConsistency):

  • runtime/JSArray.h:

(JSC::JSArray::canGetIndex):
(JSC::JSArray::canSetIndex):
(JSC::JSArray::setIndex):
(JSC::JSArray::markChildrenDirect): Removed m_fastAccessCutoff, and
replaced with checks for JSValue() to detect reads and writes from / to
uninitialized parts of the array.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/jit/JITPropertyAccess.cpp

    r49030 r49065  
    274274    emitJumpSlowCaseIfNotJSCell(base, regT1);
    275275    addSlowCase(branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsArrayVPtr)));
    276     addSlowCase(branch32(AboveOrEqual, regT2, Address(regT0, OBJECT_OFFSETOF(JSArray, m_fastAccessCutoff))));
    277 
    278     loadPtr(Address(regT0, OBJECT_OFFSETOF(JSArray, m_storage)), regT0);
    279     load32(BaseIndex(regT0, regT2, TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + 4), regT1); // tag
    280     load32(BaseIndex(regT0, regT2, TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])), regT0); // payload
     276
     277    loadPtr(Address(regT0, OBJECT_OFFSETOF(JSArray, m_storage)), regT3);
     278    addSlowCase(branch32(AboveOrEqual, regT2, Address(regT0, OBJECT_OFFSETOF(JSArray, m_vectorLength))));
     279
     280    load32(BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + 4), regT1); // tag
     281    load32(BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])), regT0); // payload
     282    addSlowCase(branch32(Equal, regT1, Imm32(JSValue::EmptyValueTag)));
     283
    281284    emitStore(dst, regT1, regT0);
    282285    map(m_bytecodeIndex + OPCODE_LENGTH(op_get_by_val), dst, regT1, regT0);
     
    289292    unsigned property = currentInstruction[3].u.operand;
    290293
    291     // The slow void JIT::emitSlow_that handles accesses to arrays (below) may jump back up to here.
    292     Label callGetByValJITStub(this);
    293 
    294294    linkSlowCase(iter); // property int32 check
    295295    linkSlowCaseIfNotJSCell(iter, base); // base cell check
    296296    linkSlowCase(iter); // base array check
     297    linkSlowCase(iter); // vector length check
     298    linkSlowCase(iter); // empty value
    297299
    298300    JITStubCall stubCall(this, cti_op_get_by_val);
     
    300302    stubCall.addArgument(property);
    301303    stubCall.call(dst);
    302 
    303     emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_get_by_val));
    304 
    305     linkSlowCase(iter); // array fast cut-off check
    306 
    307     loadPtr(Address(regT0, OBJECT_OFFSETOF(JSArray, m_storage)), regT0);
    308     branch32(AboveOrEqual, regT2, Address(regT0, OBJECT_OFFSETOF(ArrayStorage, m_vectorLength)), callGetByValJITStub);
    309 
    310     // Missed the fast region, but it is still in the vector.
    311     load32(BaseIndex(regT0, regT2, TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + 4), regT1); // tag
    312     load32(BaseIndex(regT0, regT2, TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])), regT0); // payload
    313     branch32(Equal, regT1, Imm32(JSValue::EmptyValueTag)).linkTo(callGetByValJITStub, this);
    314 
    315     emitStore(dst, regT1, regT0);
    316304}
    317305
     
    327315    emitJumpSlowCaseIfNotJSCell(base, regT1);
    328316    addSlowCase(branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsArrayVPtr)));
     317    addSlowCase(branch32(AboveOrEqual, regT2, Address(regT0, OBJECT_OFFSETOF(JSArray, m_vectorLength))));
     318
    329319    loadPtr(Address(regT0, OBJECT_OFFSETOF(JSArray, m_storage)), regT3);
    330320
    331     Jump inFastVector = branch32(Below, regT2, Address(regT0, OBJECT_OFFSETOF(JSArray, m_fastAccessCutoff)));
    332    
    333     // Check if the access is within the vector.
    334     addSlowCase(branch32(AboveOrEqual, regT2, Address(regT3, OBJECT_OFFSETOF(ArrayStorage, m_vectorLength))));
    335 
    336     // This is a write to the slow part of the vector; first, we have to check if this would be the first write to this location.
    337     // FIXME: should be able to handle initial write to array; increment the the number of items in the array, and potentially update fast access cutoff.
    338     addSlowCase(branch32(Equal, BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + 4), Imm32(JSValue::EmptyValueTag)));
    339 
    340     inFastVector.link(this);
    341 
     321    Jump empty = branch32(Equal, BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + 4), Imm32(JSValue::EmptyValueTag));
     322
     323    Label storeResult(this);
    342324    emitLoad(value, regT1, regT0);
    343325    store32(regT0, BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]))); // payload
    344326    store32(regT1, BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + 4)); // tag
     327    Jump end = jump();
     328
     329    empty.link(this);
     330    add32(Imm32(1), Address(regT3, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector)));
     331    branch32(Below, regT2, Address(regT3, OBJECT_OFFSETOF(ArrayStorage, m_length))).linkTo(storeResult, this);
     332
     333    add32(Imm32(1), regT2, regT0);
     334    store32(regT0, Address(regT3, OBJECT_OFFSETOF(ArrayStorage, m_length)));
     335    jump().linkTo(storeResult, this);
     336
     337    end.link(this);
    345338}
    346339
     
    354347    linkSlowCaseIfNotJSCell(iter, base); // base cell check
    355348    linkSlowCase(iter); // base not array check
     349    linkSlowCase(iter); // in vector check
    356350
    357351    JITStubCall stubPutByValCall(this, cti_op_put_by_val);
     
    360354    stubPutByValCall.addArgument(value);
    361355    stubPutByValCall.call();
    362 
    363     emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_get_by_val));
    364 
    365     // Slow cases for immediate int accesses to arrays.
    366     linkSlowCase(iter); // in vector check
    367     linkSlowCase(iter); // written to slot check
    368 
    369     JITStubCall stubCall(this, cti_op_put_by_val_array);
    370     stubCall.addArgument(regT1, regT0);
    371     stubCall.addArgument(regT2);
    372     stubCall.addArgument(value);
    373     stubCall.call();
    374356}
    375357
     
    953935void JIT::emit_op_get_by_val(Instruction* currentInstruction)
    954936{
    955     emitGetVirtualRegisters(currentInstruction[2].u.operand, regT0, currentInstruction[3].u.operand, regT1);
     937    unsigned dst = currentInstruction[1].u.operand;
     938    unsigned base = currentInstruction[2].u.operand;
     939    unsigned property = currentInstruction[3].u.operand;
     940
     941    emitGetVirtualRegisters(base, regT0, property, regT1);
    956942    emitJumpSlowCaseIfNotImmediateInteger(regT1);
    957943#if USE(JSVALUE64)
    958944    // This is technically incorrect - we're zero-extending an int32.  On the hot path this doesn't matter.
    959     // We check the value as if it was a uint32 against the m_fastAccessCutoff - which will always fail if
    960     // number was signed since m_fastAccessCutoff is always less than intmax (since the total allocation
     945    // We check the value as if it was a uint32 against the m_vectorLength - which will always fail if
     946    // number was signed since m_vectorLength is always less than intmax (since the total allocation
    961947    // size is always less than 4Gb).  As such zero extending wil have been correct (and extending the value
    962948    // to 64-bits is necessary since it's used in the address calculation.  We zero extend rather than sign
     
    966952    emitFastArithImmToInt(regT1);
    967953#endif
    968     emitJumpSlowCaseIfNotJSCell(regT0);
     954    emitJumpSlowCaseIfNotJSCell(regT0, base);
    969955    addSlowCase(branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsArrayVPtr)));
    970956
    971     // This is an array; get the m_storage pointer into ecx, then check if the index is below the fast cutoff
    972957    loadPtr(Address(regT0, OBJECT_OFFSETOF(JSArray, m_storage)), regT2);
    973     addSlowCase(branch32(AboveOrEqual, regT1, Address(regT0, OBJECT_OFFSETOF(JSArray, m_fastAccessCutoff))));
    974 
    975     // Get the value from the vector
     958    addSlowCase(branch32(AboveOrEqual, regT1, Address(regT0, OBJECT_OFFSETOF(JSArray, m_vectorLength))));
     959
    976960    loadPtr(BaseIndex(regT2, regT1, ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])), regT0);
    977     emitPutVirtualRegister(currentInstruction[1].u.operand);
     961    addSlowCase(branchTestPtr(Zero, regT0));
     962
     963    emitPutVirtualRegister(dst);
    978964}
    979965
    980966void JIT::emit_op_put_by_val(Instruction* currentInstruction)
    981967{
    982     emitGetVirtualRegisters(currentInstruction[1].u.operand, regT0, currentInstruction[2].u.operand, regT1);
     968    unsigned base = currentInstruction[1].u.operand;
     969    unsigned property = currentInstruction[2].u.operand;
     970    unsigned value = currentInstruction[3].u.operand;
     971
     972    emitGetVirtualRegisters(base, regT0, property, regT1);
    983973    emitJumpSlowCaseIfNotImmediateInteger(regT1);
    984974#if USE(JSVALUE64)
     
    988978    emitFastArithImmToInt(regT1);
    989979#endif
    990     emitJumpSlowCaseIfNotJSCell(regT0);
     980    emitJumpSlowCaseIfNotJSCell(regT0, base);
    991981    addSlowCase(branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsArrayVPtr)));
    992 
    993     // This is an array; get the m_storage pointer into ecx, then check if the index is below the fast cutoff
     982    addSlowCase(branch32(AboveOrEqual, regT1, Address(regT0, OBJECT_OFFSETOF(JSArray, m_vectorLength))));
     983
    994984    loadPtr(Address(regT0, OBJECT_OFFSETOF(JSArray, m_storage)), regT2);
    995     Jump inFastVector = branch32(Below, regT1, Address(regT0, OBJECT_OFFSETOF(JSArray, m_fastAccessCutoff)));
    996     // No; oh well, check if the access if within the vector - if so, we may still be okay.
    997     addSlowCase(branch32(AboveOrEqual, regT1, Address(regT2, OBJECT_OFFSETOF(ArrayStorage, m_vectorLength))));
    998 
    999     // This is a write to the slow part of the vector; first, we have to check if this would be the first write to this location.
    1000     // FIXME: should be able to handle initial write to array; increment the the number of items in the array, and potentially update fast access cutoff.
    1001     addSlowCase(branchTestPtr(Zero, BaseIndex(regT2, regT1, ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]))));
    1002 
    1003     // All good - put the value into the array.
    1004     inFastVector.link(this);
    1005     emitGetVirtualRegister(currentInstruction[3].u.operand, regT0);
     985
     986    Jump empty = branchTestPtr(Zero, BaseIndex(regT2, regT1, ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])));
     987
     988    Label storeResult(this);
     989    emitGetVirtualRegister(value, regT0);
    1006990    storePtr(regT0, BaseIndex(regT2, regT1, ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])));
     991    Jump end = jump();
     992   
     993    empty.link(this);
     994    add32(Imm32(1), Address(regT2, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector)));
     995    branch32(Below, regT1, Address(regT2, OBJECT_OFFSETOF(ArrayStorage, m_length))).linkTo(storeResult, this);
     996
     997    move(regT1, regT0);
     998    add32(Imm32(1), regT0);
     999    store32(regT0, Address(regT2, OBJECT_OFFSETOF(ArrayStorage, m_length)));
     1000    jump().linkTo(storeResult, this);
     1001
     1002    end.link(this);
    10071003}
    10081004
Note: See TracChangeset for help on using the changeset viewer.