Changeset 43432 in webkit for trunk/JavaScriptCore


Ignore:
Timestamp:
May 9, 2009, 1:35:57 AM (16 years ago)
Author:
[email protected]
Message:

2009-05-09 Maciej Stachowiak <[email protected]>

Reviewed by Gavin Barraclough.


Original patch by John McCall. Updated by Cameron Zwarich. Further refined by me.


  • Assorted speedups to property access


~.3%-1% speedup on SunSpider


1) When we know from the structure ID that an object is using inline storage, plant direct
loads and stores against it; no need to indirect through storage pointer.


2) Also because of the above, union the property storage pointer with the first inline property
slot and add an extra inline property slot.

  • assembler/AbstractMacroAssembler.h: (JSC::AbstractMacroAssembler::CodeLocationInstruction::CodeLocationInstruction): (JSC::AbstractMacroAssembler::CodeLocationInstruction::patchLoadToLEA): (JSC::::CodeLocationCommon::instructionAtOffset):
  • assembler/MacroAssembler.h: (JSC::MacroAssembler::storePtr):
  • assembler/MacroAssemblerX86.h: (JSC::MacroAssemblerX86::store32):
  • assembler/MacroAssemblerX86_64.h: (JSC::MacroAssemblerX86_64::storePtr):
  • assembler/X86Assembler.h: (JSC::X86Assembler::movq_EAXm): (JSC::X86Assembler::movl_rm): (JSC::X86Assembler::patchLoadToLEA):
  • jit/JIT.cpp: (JSC::JIT::privateCompileMainPass):
  • jit/JIT.h:
  • jit/JITPropertyAccess.cpp: (JSC::JIT::compileGetByIdHotPath): (JSC::JIT::compilePutByIdHotPath): (JSC::JIT::compilePutDirectOffset): (JSC::JIT::compileGetDirectOffset): (JSC::JIT::privateCompilePutByIdTransition): (JSC::JIT::patchGetByIdSelf): (JSC::JIT::patchPutByIdReplace): (JSC::JIT::privateCompileGetByIdSelf): (JSC::JIT::privateCompileGetByIdProto): (JSC::JIT::privateCompileGetByIdSelfList): (JSC::JIT::privateCompileGetByIdProtoList): (JSC::JIT::privateCompileGetByIdChainList): (JSC::JIT::privateCompileGetByIdChain): (JSC::JIT::privateCompilePutByIdReplace):
  • runtime/JSObject.cpp: (JSC::JSObject::mark): (JSC::JSObject::removeDirect):
  • runtime/JSObject.h: (JSC::JSObject::propertyStorage): (JSC::JSObject::getDirect): (JSC::JSObject::getOffset): (JSC::JSObject::offsetForLocation): (JSC::JSObject::locationForOffset): (JSC::JSObject::getDirectOffset): (JSC::JSObject::putDirectOffset): (JSC::JSObject::isUsingInlineStorage): (JSC::JSObject::): (JSC::JSObject::JSObject): (JSC::JSObject::~JSObject): (JSC::Structure::isUsingInlineStorage): (JSC::JSObject::putDirect): (JSC::JSObject::putDirectWithoutTransition): (JSC::JSObject::allocatePropertyStorageInline):
  • runtime/Structure.h:
Location:
trunk/JavaScriptCore
Files:
12 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/ChangeLog

    r43431 r43432  
     12009-05-09  Maciej Stachowiak  <[email protected]>
     2
     3        Reviewed by Gavin Barraclough.
     4       
     5        Original patch by John McCall. Updated by Cameron Zwarich. Further refined by me.
     6       
     7        - Assorted speedups to property access
     8       
     9        ~.3%-1% speedup on SunSpider
     10       
     11        1) When we know from the structure ID that an object is using inline storage, plant direct
     12        loads and stores against it; no need to indirect through storage pointer.
     13       
     14        2) Also because of the above, union the property storage pointer with the first inline property
     15        slot and add an extra inline property slot.
     16
     17        * assembler/AbstractMacroAssembler.h:
     18        (JSC::AbstractMacroAssembler::CodeLocationInstruction::CodeLocationInstruction):
     19        (JSC::AbstractMacroAssembler::CodeLocationInstruction::patchLoadToLEA):
     20        (JSC::::CodeLocationCommon::instructionAtOffset):
     21        * assembler/MacroAssembler.h:
     22        (JSC::MacroAssembler::storePtr):
     23        * assembler/MacroAssemblerX86.h:
     24        (JSC::MacroAssemblerX86::store32):
     25        * assembler/MacroAssemblerX86_64.h:
     26        (JSC::MacroAssemblerX86_64::storePtr):
     27        * assembler/X86Assembler.h:
     28        (JSC::X86Assembler::movq_EAXm):
     29        (JSC::X86Assembler::movl_rm):
     30        (JSC::X86Assembler::patchLoadToLEA):
     31        * jit/JIT.cpp:
     32        (JSC::JIT::privateCompileMainPass):
     33        * jit/JIT.h:
     34        * jit/JITPropertyAccess.cpp:
     35        (JSC::JIT::compileGetByIdHotPath):
     36        (JSC::JIT::compilePutByIdHotPath):
     37        (JSC::JIT::compilePutDirectOffset):
     38        (JSC::JIT::compileGetDirectOffset):
     39        (JSC::JIT::privateCompilePutByIdTransition):
     40        (JSC::JIT::patchGetByIdSelf):
     41        (JSC::JIT::patchPutByIdReplace):
     42        (JSC::JIT::privateCompileGetByIdSelf):
     43        (JSC::JIT::privateCompileGetByIdProto):
     44        (JSC::JIT::privateCompileGetByIdSelfList):
     45        (JSC::JIT::privateCompileGetByIdProtoList):
     46        (JSC::JIT::privateCompileGetByIdChainList):
     47        (JSC::JIT::privateCompileGetByIdChain):
     48        (JSC::JIT::privateCompilePutByIdReplace):
     49        * runtime/JSObject.cpp:
     50        (JSC::JSObject::mark):
     51        (JSC::JSObject::removeDirect):
     52        * runtime/JSObject.h:
     53        (JSC::JSObject::propertyStorage):
     54        (JSC::JSObject::getDirect):
     55        (JSC::JSObject::getOffset):
     56        (JSC::JSObject::offsetForLocation):
     57        (JSC::JSObject::locationForOffset):
     58        (JSC::JSObject::getDirectOffset):
     59        (JSC::JSObject::putDirectOffset):
     60        (JSC::JSObject::isUsingInlineStorage):
     61        (JSC::JSObject::):
     62        (JSC::JSObject::JSObject):
     63        (JSC::JSObject::~JSObject):
     64        (JSC::Structure::isUsingInlineStorage):
     65        (JSC::JSObject::putDirect):
     66        (JSC::JSObject::putDirectWithoutTransition):
     67        (JSC::JSObject::allocatePropertyStorageInline):
     68        * runtime/Structure.h:
     69
    1702009-05-09  Geoffrey Garen  <[email protected]>
    271
  • trunk/JavaScriptCore/assembler/AbstractMacroAssembler.h

    r41544 r43432  
    3838    class Jump;
    3939    class PatchBuffer;
     40    class CodeLocationInstruction;
    4041    class CodeLocationLabel;
    4142    class CodeLocationJump;
     
    407408        // methods may be used to recover a handle that has nopw been
    408409        // retained, based on a known fixed relative offset from one that has.
     410        CodeLocationInstruction instructionAtOffset(int offset);
    409411        CodeLocationLabel labelAtOffset(int offset);
    410412        CodeLocationJump jumpAtOffset(int offset);
     
    423425
    424426        void* m_location;
     427    };
     428
     429    // CodeLocationInstruction:
     430    //
     431    // An arbitrary instruction in the JIT code.
     432    class CodeLocationInstruction : public CodeLocationCommon {
     433        friend class CodeLocationCommon;
     434    public:
     435        CodeLocationInstruction()
     436        {
     437        }
     438
     439        void patchLoadToLEA() {
     440            AssemblerType::patchLoadToLEA(reinterpret_cast<intptr_t>(this->m_location));
     441        }
     442
     443    private:
     444        explicit CodeLocationInstruction(void* location)
     445            : CodeLocationCommon(location)
     446        {
     447        }
    425448    };
    426449
     
    805828
    806829template <class AssemblerType>
     830typename AbstractMacroAssembler<AssemblerType>::CodeLocationInstruction AbstractMacroAssembler<AssemblerType>::CodeLocationCommon::instructionAtOffset(int offset)
     831{
     832    return typename AbstractMacroAssembler::CodeLocationInstruction(reinterpret_cast<char*>(m_location) + offset);
     833}
     834
     835template <class AssemblerType>
    807836typename AbstractMacroAssembler<AssemblerType>::CodeLocationLabel AbstractMacroAssembler<AssemblerType>::CodeLocationCommon::labelAtOffset(int offset)
    808837{
  • trunk/JavaScriptCore/assembler/MacroAssembler.h

    r41103 r43432  
    243243    }
    244244
     245    void storePtr(RegisterID src, void* address)
     246    {
     247        store32(src, address);
     248    }
     249
    245250    void storePtr(ImmPtr imm, ImplicitAddress address)
    246251    {
  • trunk/JavaScriptCore/assembler/MacroAssemblerX86.h

    r41089 r43432  
    7171    }
    7272
     73    void store32(RegisterID src, void* address)
     74    {
     75        m_assembler.movl_rm(src, address);
     76    }
     77
    7378    Jump branch32(Condition cond, AbsoluteAddress left, RegisterID right)
    7479    {
  • trunk/JavaScriptCore/assembler/MacroAssemblerX86_64.h

    r43220 r43432  
    242242        m_assembler.movq_rm(src, address.offset, address.base, address.index, address.scale);
    243243    }
     244   
     245    void storePtr(RegisterID src, void* address)
     246    {
     247        if (src == X86::eax)
     248            m_assembler.movq_EAXm(address);
     249        else {
     250            swap(X86::eax, src);
     251            m_assembler.movq_EAXm(address);
     252            swap(X86::eax, src);
     253        }
     254    }
    244255
    245256    void storePtr(ImmPtr imm, ImplicitAddress address)
  • trunk/JavaScriptCore/assembler/X86Assembler.h

    r43220 r43432  
    938938    }
    939939
     940    void movq_EAXm(void* addr)
     941    {
     942        m_formatter.oneByteOp64(OP_MOV_OvEAX);
     943        m_formatter.immediate64(reinterpret_cast<int64_t>(addr));
     944    }
     945
    940946    void movq_mr(int offset, RegisterID base, RegisterID dst)
    941947    {
     
    972978   
    973979#else
     980    void movl_rm(RegisterID src, void* addr)
     981    {
     982        if (src == X86::eax)
     983            movl_EAXm(addr);
     984        else
     985            m_formatter.oneByteOp(OP_MOV_EvGv, src, addr);
     986    }
     987   
    974988    void movl_mr(void* addr, RegisterID dst)
    975989    {
     
    12871301        ASSERT(linkOffset == static_cast<int>(linkOffset));
    12881302        reinterpret_cast<int*>(reinterpret_cast<ptrdiff_t>(code) + from.m_offset)[-1] = linkOffset;
     1303    }
     1304
     1305    static void patchLoadToLEA(intptr_t where)
     1306    {
     1307        char* ptr = reinterpret_cast<char*>(where);
     1308        ptr[0] = OP_LEA;
    12891309    }
    12901310   
  • trunk/JavaScriptCore/jit/JIT.cpp

    r43431 r43432  
    595595
    596596            // Load cached property
    597             loadPtr(Address(regT0, FIELD_OFFSET(JSGlobalObject, m_propertyStorage)), regT0);
     597            // Assume that the global object always uses external storage.
     598            loadPtr(Address(regT0, FIELD_OFFSET(JSGlobalObject, m_externalStorage)), regT0);
    598599            load32(offsetAddr, regT1);
    599600            loadPtr(BaseIndex(regT0, regT1, ScalePtr), regT0);
  • trunk/JavaScriptCore/jit/JIT.h

    r43409 r43432  
    227227        // These architecture specific value are used to enable patching - see comment on op_put_by_id.
    228228        static const int patchOffsetPutByIdStructure = 10;
     229        static const int patchOffsetPutByIdExternalLoad = 20;
     230        static const int patchLengthPutByIdExternalLoad = 4;
    229231        static const int patchOffsetPutByIdPropertyMapOffset = 31;
    230232        // These architecture specific value are used to enable patching - see comment on op_get_by_id.
    231233        static const int patchOffsetGetByIdStructure = 10;
    232234        static const int patchOffsetGetByIdBranchToSlowCase = 20;
     235        static const int patchOffsetGetByIdExternalLoad = 20;
     236        static const int patchLengthGetByIdExternalLoad = 4;
    233237        static const int patchOffsetGetByIdPropertyMapOffset = 31;
    234238        static const int patchOffsetGetByIdPutResult = 31;
     
    242246        // These architecture specific value are used to enable patching - see comment on op_put_by_id.
    243247        static const int patchOffsetPutByIdStructure = 7;
     248        static const int patchOffsetPutByIdExternalLoad = 13;
     249        static const int patchLengthPutByIdExternalLoad = 3;
    244250        static const int patchOffsetPutByIdPropertyMapOffset = 22;
    245251        // These architecture specific value are used to enable patching - see comment on op_get_by_id.
    246252        static const int patchOffsetGetByIdStructure = 7;
    247253        static const int patchOffsetGetByIdBranchToSlowCase = 13;
     254        static const int patchOffsetGetByIdExternalLoad = 13;
     255        static const int patchLengthGetByIdExternalLoad = 3;
    248256        static const int patchOffsetGetByIdPropertyMapOffset = 22;
    249257        static const int patchOffsetGetByIdPutResult = 22;
     
    380388        enum CompileOpStrictEqType { OpStrictEq, OpNStrictEq };
    381389        void compileOpStrictEq(Instruction* instruction, CompileOpStrictEqType type);
     390
     391        void compileGetDirectOffset(RegisterID base, RegisterID result, Structure* structure, size_t cachedOffset);
     392        void compileGetDirectOffset(JSObject* base, RegisterID temp, RegisterID result, size_t cachedOffset);
     393        void compilePutDirectOffset(RegisterID base, RegisterID value, Structure* structure, size_t cachedOffset);
    382394
    383395        void compileFastArith_op_add(Instruction*);
  • trunk/JavaScriptCore/jit/JITPropertyAccess.cpp

    r43409 r43432  
    109109    ASSERT(differenceBetween(hotPathBegin, structureCheck) == patchOffsetGetByIdBranchToSlowCase);
    110110
    111     loadPtr(Address(regT0, FIELD_OFFSET(JSObject, m_propertyStorage)), regT0);
     111    Label externalLoad(this);
     112    loadPtr(Address(regT0, FIELD_OFFSET(JSObject, m_externalStorage)), regT0);
     113    Label externalLoadComplete(this);
     114    ASSERT(differenceBetween(hotPathBegin, externalLoad) == patchOffsetGetByIdExternalLoad);
     115    ASSERT(differenceBetween(externalLoad, externalLoadComplete) == patchLengthGetByIdExternalLoad);
     116
    112117    DataLabel32 displacementLabel = loadPtrWithAddressOffsetPatch(Address(regT0, patchGetByIdDefaultOffset), regT0);
    113118    ASSERT(differenceBetween(hotPathBegin, displacementLabel) == patchOffsetGetByIdPropertyMapOffset);
     
    164169
    165170    // Plant a load from a bogus ofset in the object's property map; we will patch this later, if it is to be used.
    166     loadPtr(Address(regT0, FIELD_OFFSET(JSObject, m_propertyStorage)), regT0);
     171    Label externalLoad(this);
     172    loadPtr(Address(regT0, FIELD_OFFSET(JSObject, m_externalStorage)), regT0);
     173    Label externalLoadComplete(this);
     174    ASSERT(differenceBetween(hotPathBegin, externalLoad) == patchOffsetPutByIdExternalLoad);
     175    ASSERT(differenceBetween(externalLoad, externalLoadComplete) == patchLengthPutByIdExternalLoad);
     176
    167177    DataLabel32 displacementLabel = storePtrWithAddressOffsetPatch(regT1, Address(regT0, patchGetByIdDefaultOffset));
    168178    ASSERT(differenceBetween(hotPathBegin, displacementLabel) == patchOffsetPutByIdPropertyMapOffset);
     
    182192    // Track the location of the call; this will be used to recover patch information.
    183193    m_propertyAccessCompilationInfo[propertyAccessInstructionIndex].callReturnLocation = call;
     194}
     195
     196// Compile a store into an object's property storage.  May overwrite the
     197// value in objectReg.
     198void JIT::compilePutDirectOffset(RegisterID base, RegisterID value, Structure* structure, size_t cachedOffset)
     199{
     200    int offset = cachedOffset * sizeof(JSValue);
     201    if (structure->isUsingInlineStorage())
     202        offset += FIELD_OFFSET(JSObject, m_inlineStorage);
     203    else
     204        loadPtr(Address(base, FIELD_OFFSET(JSObject, m_externalStorage)), base);
     205    storePtr(value, Address(base, offset));
     206}
     207
     208// Compile a load from an object's property storage.  May overwrite base.
     209void JIT::compileGetDirectOffset(RegisterID base, RegisterID result, Structure* structure, size_t cachedOffset)
     210{
     211    int offset = cachedOffset * sizeof(JSValue);
     212    if (structure->isUsingInlineStorage())
     213        offset += FIELD_OFFSET(JSObject, m_inlineStorage);
     214    else
     215        loadPtr(Address(base, FIELD_OFFSET(JSObject, m_externalStorage)), base);
     216    loadPtr(Address(base, offset), result);
     217}
     218
     219void JIT::compileGetDirectOffset(JSObject* base, RegisterID temp, RegisterID result, size_t cachedOffset)
     220{
     221    if (base->isUsingInlineStorage())
     222        loadPtr(static_cast<void*>(&base->m_inlineStorage[cachedOffset]), result);
     223    else {
     224        PropertyStorage* protoPropertyStorage = &base->m_externalStorage;
     225        loadPtr(static_cast<void*>(protoPropertyStorage), temp);
     226        loadPtr(Address(temp, cachedOffset * sizeof(JSValue)), result);
     227    }
    184228}
    185229
     
    254298
    255299    // write the value
    256     loadPtr(Address(regT0, FIELD_OFFSET(JSObject, m_propertyStorage)), regT0);
    257     storePtr(regT1, Address(regT0, cachedOffset * sizeof(JSValue)));
     300    compilePutDirectOffset(regT0, regT1, newStructure, cachedOffset);
    258301
    259302    ret();
     
    283326    returnAddress.relinkCallerToFunction(JITStubs::cti_op_get_by_id_self_fail);
    284327
     328    int offset = sizeof(JSValue) * cachedOffset;
     329
     330    // If we're patching to use inline storage, convert the initial load to a lea; this avoids the extra load
     331    // and makes the subsequent load's offset automatically correct
     332    if (structure->isUsingInlineStorage())
     333        stubInfo->hotPathBegin.instructionAtOffset(patchOffsetGetByIdExternalLoad).patchLoadToLEA();
     334
    285335    // Patch the offset into the propoerty map to load from, then patch the Structure to look for.
    286336    stubInfo->hotPathBegin.dataLabelPtrAtOffset(patchOffsetGetByIdStructure).repatch(structure);
    287     stubInfo->hotPathBegin.dataLabel32AtOffset(patchOffsetGetByIdPropertyMapOffset).repatch(cachedOffset * sizeof(JSValue));
     337    stubInfo->hotPathBegin.dataLabel32AtOffset(patchOffsetGetByIdPropertyMapOffset).repatch(offset);
    288338}
    289339
     
    294344    returnAddress.relinkCallerToFunction(JITStubs::cti_op_put_by_id_generic);
    295345
     346    int offset = sizeof(JSValue) * cachedOffset;
     347
     348    // If we're patching to use inline storage, convert the initial load to a lea; this avoids the extra load
     349    // and makes the subsequent load's offset automatically correct
     350    if (structure->isUsingInlineStorage())
     351        stubInfo->hotPathBegin.instructionAtOffset(patchOffsetGetByIdExternalLoad).patchLoadToLEA();
     352
    296353    // Patch the offset into the propoerty map to load from, then patch the Structure to look for.
    297354    stubInfo->hotPathBegin.dataLabelPtrAtOffset(patchOffsetPutByIdStructure).repatch(structure);
    298     stubInfo->hotPathBegin.dataLabel32AtOffset(patchOffsetPutByIdPropertyMapOffset).repatch(cachedOffset * sizeof(JSValue));
     355    stubInfo->hotPathBegin.dataLabel32AtOffset(patchOffsetPutByIdPropertyMapOffset).repatch(offset);
    299356}
    300357
     
    345402
    346403    // Checks out okay! - getDirectOffset
    347     loadPtr(Address(regT0, FIELD_OFFSET(JSObject, m_propertyStorage)), regT0);
    348     loadPtr(Address(regT0, cachedOffset * sizeof(JSValue)), regT0);
     404    compileGetDirectOffset(regT0, regT0, structure, cachedOffset);
    349405    ret();
    350406
     
    386442
    387443    // Checks out okay! - getDirectOffset
    388     PropertyStorage* protoPropertyStorage = &protoObject->m_propertyStorage;
    389     loadPtr(static_cast<void*>(protoPropertyStorage), regT1);
    390     loadPtr(Address(regT1, cachedOffset * sizeof(JSValue)), regT0);
     444    compileGetDirectOffset(protoObject, regT1, regT0, cachedOffset);
    391445
    392446    Jump success = jump();
     
    424478
    425479    // Checks out okay! - getDirectOffset
    426     PropertyStorage* protoPropertyStorage = &protoObject->m_propertyStorage;
    427     loadPtr(protoPropertyStorage, regT1);
    428     loadPtr(Address(regT1, cachedOffset * sizeof(JSValue)), regT0);
     480    compileGetDirectOffset(protoObject, regT1, regT0, cachedOffset);
    429481
    430482    ret();
     
    447499{
    448500    Jump failureCase = checkStructure(regT0, structure);
    449     loadPtr(Address(regT0, FIELD_OFFSET(JSObject, m_propertyStorage)), regT0);
    450     loadPtr(Address(regT0, cachedOffset * sizeof(JSValue)), regT0);
     501    compileGetDirectOffset(regT0, regT0, structure, cachedOffset);
    451502    Jump success = jump();
    452503
     
    494545
    495546    // Checks out okay! - getDirectOffset
    496     PropertyStorage* protoPropertyStorage = &protoObject->m_propertyStorage;
    497     loadPtr(protoPropertyStorage, regT1);
    498     loadPtr(Address(regT1, cachedOffset * sizeof(JSValue)), regT0);
     547    compileGetDirectOffset(protoObject, regT1, regT0, cachedOffset);
    499548
    500549    Jump success = jump();
     
    550599    ASSERT(protoObject);
    551600
    552     PropertyStorage* protoPropertyStorage = &protoObject->m_propertyStorage;
    553     loadPtr(protoPropertyStorage, regT1);
    554     loadPtr(Address(regT1, cachedOffset * sizeof(JSValue)), regT0);
     601    compileGetDirectOffset(protoObject, regT1, regT0, cachedOffset);
    555602    Jump success = jump();
    556603
     
    610657    ASSERT(protoObject);
    611658
    612     PropertyStorage* protoPropertyStorage = &protoObject->m_propertyStorage;
    613     loadPtr(protoPropertyStorage, regT1);
    614     loadPtr(Address(regT1, cachedOffset * sizeof(JSValue)), regT0);
     659    compileGetDirectOffset(protoObject, regT1, regT0, cachedOffset);
    615660    Jump success = jump();
    616661
     
    658703    ASSERT(protoObject);
    659704
    660     PropertyStorage* protoPropertyStorage = &protoObject->m_propertyStorage;
    661     loadPtr(protoPropertyStorage, regT1);
    662     loadPtr(Address(regT1, cachedOffset * sizeof(JSValue)), regT0);
     705    compileGetDirectOffset(protoObject, regT1, regT0, cachedOffset);
     706    compilePutDirectOffset(regT0, regT1, structure, cachedOffset);
    663707    ret();
    664708
     
    680724
    681725    // checks out okay! - putDirectOffset
    682     loadPtr(Address(regT0, FIELD_OFFSET(JSObject, m_propertyStorage)), regT0);
    683     storePtr(regT1, Address(regT0, cachedOffset * sizeof(JSValue)));
     726    compilePutDirectOffset(regT0, regT1, structure, cachedOffset);
    684727    ret();
    685728
  • trunk/JavaScriptCore/runtime/JSObject.cpp

    r43153 r43432  
    7070    m_structure->mark();
    7171
     72    PropertyStorage storage = propertyStorage();
     73
    7274    size_t storageSize = m_structure->propertyStorageSize();
    7375    for (size_t i = 0; i < storageSize; ++i) {
    74         JSValue v = m_propertyStorage[i];
     76        JSValue v = JSValue::decode(storage[i]);
    7577        if (!v.marked())
    7678            v.mark();
     
    472474        offset = m_structure->removePropertyWithoutTransition(propertyName);
    473475        if (offset != WTF::notFound)
    474             m_propertyStorage[offset] = jsUndefined();
     476            putDirectOffset(offset, jsUndefined());
    475477        return;
    476478    }
    477479
    478480    RefPtr<Structure> structure = Structure::removePropertyTransition(m_structure, propertyName, offset);
     481    setStructure(structure.release());
    479482    if (offset != WTF::notFound)
    480         m_propertyStorage[offset] = jsUndefined();
    481     setStructure(structure.release());
     483        putDirectOffset(offset, jsUndefined());
    482484}
    483485
  • trunk/JavaScriptCore/runtime/JSObject.h

    r43153 r43432  
    5252    };
    5353
    54     typedef JSValue* PropertyStorage;
     54    typedef EncodedJSValue* PropertyStorage;
     55    typedef EncodedJSValue const * ConstPropertyStorage;
    5556
    5657    class JSObject : public JSCell {
     
    7677        Structure* inheritorID();
    7778
    78         PropertyStorage& propertyStorage() { return m_propertyStorage; }
     79        ConstPropertyStorage propertyStorage() const { return (isUsingInlineStorage() ? m_inlineStorage : m_externalStorage); }
     80        PropertyStorage propertyStorage() { return (isUsingInlineStorage() ? m_inlineStorage : m_externalStorage); }
    7981
    8082        virtual UString className() const;
     
    126128        {
    127129            size_t offset = m_structure->get(propertyName);
    128             return offset != WTF::notFound ? m_propertyStorage[offset] : JSValue();
     130            return offset != WTF::notFound ? getDirectOffset(offset) : JSValue();
     131        }
     132
     133        size_t getOffset(const Identifier& propertyName)
     134        {
     135            return m_structure->get(propertyName);
    129136        }
    130137
     
    141148        }
    142149
    143         size_t offsetForLocation(JSValue* location)
    144         {
    145             return location - m_propertyStorage;
     150        size_t offsetForLocation(JSValue* location) const
     151        {
     152            return location - reinterpret_cast<JSValue const *>(propertyStorage());
     153        }
     154
     155        JSValue const * locationForOffset(size_t offset) const
     156        {
     157            return reinterpret_cast<JSValue const *>(&propertyStorage()[offset]);
    146158        }
    147159
    148160        JSValue* locationForOffset(size_t offset)
    149161        {
    150             return &m_propertyStorage[offset];
     162            return reinterpret_cast<JSValue*>(&propertyStorage()[offset]);
    151163        }
    152164
     
    164176
    165177        // Fast access to known property offsets.
    166         JSValue getDirectOffset(size_t offset) { return m_propertyStorage[offset]; }
    167         void putDirectOffset(size_t offset, JSValue value) { m_propertyStorage[offset] = value; }
     178        JSValue getDirectOffset(size_t offset) const { return JSValue::decode(propertyStorage()[offset]); }
     179        void putDirectOffset(size_t offset, JSValue value) { propertyStorage()[offset] = JSValue::encode(value); }
    168180
    169181        void fillGetterPropertySlot(PropertySlot&, JSValue* location);
     
    182194        void allocatePropertyStorage(size_t oldSize, size_t newSize);
    183195        void allocatePropertyStorageInline(size_t oldSize, size_t newSize);
    184         bool usingInlineStorage() const { return m_propertyStorage == m_inlineStorage; }
    185 
    186         static const size_t inlineStorageCapacity = 2;
     196        bool isUsingInlineStorage() const { return m_structure->isUsingInlineStorage(); }
     197
     198        static const size_t inlineStorageCapacity = 3;
    187199        static const size_t nonInlineBaseStorageCapacity = 16;
    188200
     
    203215        RefPtr<Structure> m_inheritorID;
    204216
    205         PropertyStorage m_propertyStorage;       
    206         JSValue m_inlineStorage[inlineStorageCapacity];
     217        union {
     218            PropertyStorage m_externalStorage;
     219            EncodedJSValue m_inlineStorage[inlineStorageCapacity];
     220        };
    207221    };
    208222
     
    219233inline JSObject::JSObject(PassRefPtr<Structure> structure)
    220234    : JSCell(structure.releaseRef()) // ~JSObject balances this ref()
    221     , m_propertyStorage(m_inlineStorage)
    222235{
    223236    ASSERT(m_structure);
     
    230243{
    231244    ASSERT(m_structure);
    232     if (m_propertyStorage != m_inlineStorage)
    233         delete [] m_propertyStorage;
     245    if (!isUsingInlineStorage())
     246        delete [] m_externalStorage;
    234247    m_structure->deref();
    235248}
     
    258271        return m_inheritorID.get();
    259272    return createInheritorID();
     273}
     274
     275inline bool Structure::isUsingInlineStorage() const
     276{
     277    return (propertyStorageCapacity() == JSObject::inlineStorageCapacity);
    260278}
    261279
     
    395413            if (checkReadOnly && currentAttributes & ReadOnly)
    396414                return;
    397             m_propertyStorage[offset] = value;
     415            putDirectOffset(offset, value);
    398416            slot.setExistingProperty(this, offset);
    399417            return;
     
    406424
    407425        ASSERT(offset < m_structure->propertyStorageCapacity());
    408         m_propertyStorage[offset] = value;
     426        putDirectOffset(offset, value);
    409427        slot.setNewProperty(this, offset);
    410428        return;
     
    418436
    419437        ASSERT(offset < structure->propertyStorageCapacity());
    420         m_propertyStorage[offset] = value;
     438        setStructure(structure.release());
     439        putDirectOffset(offset, value);
    421440        slot.setNewProperty(this, offset);
    422441        slot.setWasTransition(true);
    423         setStructure(structure.release());
    424442        return;
    425443    }
     
    430448        if (checkReadOnly && currentAttributes & ReadOnly)
    431449            return;
    432         m_propertyStorage[offset] = value;
     450        putDirectOffset(offset, value);
    433451        slot.setExistingProperty(this, offset);
    434452        return;
     
    440458
    441459    ASSERT(offset < structure->propertyStorageCapacity());
    442     m_propertyStorage[offset] = value;
     460    setStructure(structure.release());
     461    putDirectOffset(offset, value);
    443462    slot.setNewProperty(this, offset);
    444463    slot.setWasTransition(true);
    445     setStructure(structure.release());
    446464}
    447465
     
    452470    if (currentCapacity != m_structure->propertyStorageCapacity())
    453471        allocatePropertyStorage(currentCapacity, m_structure->propertyStorageCapacity());
    454     m_propertyStorage[offset] = value;
     472    putDirectOffset(offset, value);
    455473}
    456474
     
    541559    ASSERT(newSize > oldSize);
    542560
    543     JSValue* oldPropertyStorage = m_propertyStorage;
    544     m_propertyStorage = new JSValue[newSize];
     561    // It's important that this function not rely on m_structure, since
     562    // we might be in the middle of a transition.
     563    bool wasInline = (oldSize == JSObject::inlineStorageCapacity);
     564
     565    PropertyStorage oldPropertyStorage = (wasInline ? m_inlineStorage : m_externalStorage);
     566    PropertyStorage newPropertyStorage = new EncodedJSValue[newSize];
    545567
    546568    for (unsigned i = 0; i < oldSize; ++i)
    547         m_propertyStorage[i] = oldPropertyStorage[i];
    548 
    549     if (oldPropertyStorage != m_inlineStorage)
     569       newPropertyStorage[i] = oldPropertyStorage[i];
     570
     571    if (!wasInline)
    550572        delete [] oldPropertyStorage;
     573
     574    m_externalStorage = newPropertyStorage;
    551575}
    552576
  • trunk/JavaScriptCore/runtime/Structure.h

    r43317 r43432  
    9696        size_t propertyStorageCapacity() const { return m_propertyStorageCapacity; }
    9797        size_t propertyStorageSize() const { return m_propertyTable ? m_propertyTable->keyCount + (m_propertyTable->deletedOffsets ? m_propertyTable->deletedOffsets->size() : 0) : m_offset + 1; }
     98        bool isUsingInlineStorage() const;
    9899
    99100        size_t get(const Identifier& propertyName);
Note: See TracChangeset for help on using the changeset viewer.