Changeset 36285 in webkit for trunk/JavaScriptCore/kjs


Ignore:
Timestamp:
Sep 8, 2008, 11:55:39 PM (17 years ago)
Author:
[email protected]
Message:

JavaScriptCore:

2008-09-08 Sam Weinig <[email protected]>

Reviewed by Maciej Stachowiak and Oliver Hunt.

Split storage of properties out of the PropertyMap and into the JSObject
to allow sharing PropertyMap on the StructureID. In order to get this
function correctly, the StructureID's transition mappings were changed to
transition based on property name and attribute pairs, instead of just
property name.

  • Removes the single property optimization now that the PropertyMap is shared. This will be replaced by in-lining some values on the JSObject.

This is a wash on Sunspider and a 6.7% win on the v8 test suite.

  • JavaScriptCore.base.exp:
  • VM/CTI.cpp: (JSC::CTI::privateCompileGetByIdSelf): Get the storage directly off the JSObject. (JSC::CTI::privateCompileGetByIdProto): Ditto. (JSC::CTI::privateCompileGetByIdChain): Ditto. (JSC::CTI::privateCompilePutByIdReplace): Ditto.
  • kjs/JSObject.cpp: (JSC::JSObject::mark): Mark the PropertyStorage. (JSC::JSObject::put): Update to get the propertyMap of the StructureID. (JSC::JSObject::deleteProperty): Ditto. (JSC::JSObject::defineGetter): Return early if the property is already a getter/setter. (JSC::JSObject::defineSetter): Ditto. (JSC::JSObject::getPropertyAttributes): Update to get the propertyMap of the StructureID (JSC::JSObject::getPropertyNames): Ditto. (JSC::JSObject::removeDirect): Ditto.
  • kjs/JSObject.h: Remove PropertyMap and add PropertyStorage. (JSC::JSObject::propertyStorage): return the PropertyStorage. (JSC::JSObject::getDirect): Update to get the propertyMap of the StructureID. (JSC::JSObject::getDirectLocation): Ditto. (JSC::JSObject::offsetForLocation): Compute location directly. (JSC::JSObject::hasCustomProperties): Update to get the propertyMap of the StructureID. (JSC::JSObject::hasGetterSetterProperties): Ditto. (JSC::JSObject::getDirectOffset): Get by indexing into PropertyStorage. (JSC::JSObject::putDirectOffset): Put by indexing into PropertyStorage. (JSC::JSObject::getOwnPropertySlotForWrite): Update to get the propertyMap of the StructureID. (JSC::JSObject::getOwnPropertySlot): Ditto. (JSC::JSObject::putDirect): Move putting into the StructureID unless the property already exists.
  • kjs/PropertyMap.cpp: Use the propertyStorage as the storage for the JSValues. (JSC::PropertyMap::checkConsistency): (JSC::PropertyMap::operator=): (JSC::PropertyMap::~PropertyMap): (JSC::PropertyMap::get): (JSC::PropertyMap::getLocation): (JSC::PropertyMap::put): (JSC::PropertyMap::getOffset): (JSC::PropertyMap::insert): (JSC::PropertyMap::expand): (JSC::PropertyMap::rehash): (JSC::PropertyMap::createTable): (JSC::PropertyMap::resizePropertyStorage): Resize the storage to match the size of the map (JSC::PropertyMap::remove): (JSC::PropertyMap::getEnumerablePropertyNames):
  • kjs/PropertyMap.h: (JSC::PropertyMapEntry::PropertyMapEntry): (JSC::PropertyMap::isEmpty): (JSC::PropertyMap::size): (JSC::PropertyMap::makingCount): (JSC::PropertyMap::PropertyMap):
  • kjs/StructureID.cpp: (JSC::StructureID::addPropertyTransition): Transitions now are based off the property name and attributes. (JSC::StructureID::toDictionaryTransition): Copy the map. (JSC::StructureID::changePrototypeTransition): Copy the map. (JSC::StructureID::getterSetterTransition): Copy the map. (JSC::StructureID::~StructureID):
  • kjs/StructureID.h: (JSC::TransitionTableHash::hash): Custom hash for transition map. (JSC::TransitionTableHash::equal): Ditto. (JSC::TransitionTableHashTraits::emptyValue): Custom traits for transition map (JSC::TransitionTableHashTraits::constructDeletedValue): Ditto. (JSC::TransitionTableHashTraits::isDeletedValue): Ditto. (JSC::StructureID::propertyMap): Added.

JavaScriptGlue:

2008-09-08 Sam Weinig <[email protected]>

Reviewed by Maciej Stachowiak and Oliver Hunt.

Add forwarding headers.

  • ForwardingHeaders/wtf/HashFunctions.h: Added.
  • ForwardingHeaders/wtf/HashTraits.h: Added.

WebCore:

2008-09-08 Sam Weinig <[email protected]>

Reviewed by Maciej Stachowiak and Oliver Hunt.

Add forwarding headers.

  • ForwardingHeaders/wtf/HashFunctions.h: Added.
Location:
trunk/JavaScriptCore/kjs
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/kjs/JSObject.cpp

    r36263 r36285  
    7070    JSCell::mark();
    7171    m_structureID->mark();
    72     m_propertyMap.mark();
     72
     73    unsigned storageSize = m_structureID->propertyMap().makingCount();
     74    if (storageSize) {
     75        for (unsigned i = 1; i <= storageSize; ++i) {
     76            JSValue* v = m_propertyStorage[i];
     77            if (!v->marked())
     78                v->mark();
     79        }
     80    }
    7381
    7482    JSOBJECT_MARK_END();
     
    120128    // Check if there are any setters or getters in the prototype chain
    121129    JSValue* prototype;
    122     for (JSObject* obj = this; !obj->m_propertyMap.hasGetterSetterProperties(); obj = static_cast<JSObject*>(prototype)) {
     130    for (JSObject* obj = this; !obj->structureID()->propertyMap().hasGetterSetterProperties(); obj = static_cast<JSObject*>(prototype)) {
    123131        prototype = obj->prototype();
    124132        if (prototype->isNull()) {
     
    129137   
    130138    unsigned attributes;
    131     if (m_propertyMap.get(propertyName, attributes) && attributes & ReadOnly)
     139    if (m_structureID->propertyMap().get(propertyName, attributes, m_propertyStorage) && attributes & ReadOnly)
    132140        return;
    133141
    134142    for (JSObject* obj = this; ; obj = static_cast<JSObject*>(prototype)) {
    135         if (JSValue* gs = obj->m_propertyMap.get(propertyName)) {
     143        if (JSValue* gs = obj->structureID()->propertyMap().get(propertyName, obj->propertyStorage())) {
    136144            if (gs->isGetterSetter()) {
    137145                JSObject* setterFunc = static_cast<GetterSetter*>(gs)->setter();       
     
    195203{
    196204    unsigned attributes;
    197     JSValue* v = m_propertyMap.get(propertyName, attributes);
     205    JSValue* v = m_structureID->propertyMap().get(propertyName, attributes, m_propertyStorage);
    198206    if (v) {
    199207        if ((attributes & DontDelete))
     
    286294void JSObject::defineGetter(ExecState* exec, const Identifier& propertyName, JSObject* getterFunction)
    287295{
    288     GetterSetter* getterSetter;
     296    JSValue* object = getDirect(propertyName);
     297    if (object && object->isGetterSetter()) {
     298        ASSERT(m_structureID->propertyMap().hasGetterSetterProperties());
     299        GetterSetter* getterSetter = static_cast<GetterSetter*>(object);
     300        getterSetter->setGetter(getterFunction);
     301        return;
     302    }
     303
    289304    PutPropertySlot slot;
    290 
    291     JSValue* object = getDirect(propertyName);
    292     if (object && object->isGetterSetter())
    293         getterSetter = static_cast<GetterSetter*>(object);
    294     else {
    295         getterSetter = new (exec) GetterSetter;
    296         putDirect(propertyName, getterSetter, None, true, slot);
    297     }
     305    GetterSetter* getterSetter = new (exec) GetterSetter;
     306    putDirect(propertyName, getterSetter, None, true, slot);
    298307
    299308    // putDirect will change our StructureID if we add a new property. For
     
    307316    }
    308317
    309     m_propertyMap.setHasGetterSetterProperties(true);
     318    m_structureID->propertyMap().setHasGetterSetterProperties(true);
    310319    getterSetter->setGetter(getterFunction);
    311320}
     
    313322void JSObject::defineSetter(ExecState* exec, const Identifier& propertyName, JSObject* setterFunction)
    314323{
    315     GetterSetter* getterSetter;
     324    JSValue* object = getDirect(propertyName);
     325    if (object && object->isGetterSetter()) {
     326        ASSERT(m_structureID->propertyMap().hasGetterSetterProperties());
     327        GetterSetter* getterSetter = static_cast<GetterSetter*>(object);
     328        getterSetter->setSetter(setterFunction);
     329        return;
     330    }
     331
    316332    PutPropertySlot slot;
    317 
    318     JSValue* object = getDirect(propertyName);
    319     if (object && object->isGetterSetter())
    320         getterSetter = static_cast<GetterSetter*>(object);
    321     else {
    322         getterSetter = new (exec) GetterSetter;
    323         putDirect(propertyName, getterSetter, None, true, slot);
    324     }
     333    GetterSetter* getterSetter = new (exec) GetterSetter;
     334    putDirect(propertyName, getterSetter, None, true, slot);
    325335
    326336    // putDirect will change our StructureID if we add a new property. For
     
    334344    }
    335345
    336     m_propertyMap.setHasGetterSetterProperties(true);
     346    m_structureID->propertyMap().setHasGetterSetterProperties(true);
    337347    getterSetter->setSetter(setterFunction);
    338348}
     
    412422bool JSObject::getPropertyAttributes(ExecState* exec, const Identifier& propertyName, unsigned& attributes) const
    413423{
    414     if (m_propertyMap.get(propertyName, attributes))
     424    if (m_structureID->propertyMap().get(propertyName, attributes, m_propertyStorage))
    415425        return true;
    416426   
     
    427437void JSObject::getPropertyNames(ExecState* exec, PropertyNameArray& propertyNames)
    428438{
    429     m_propertyMap.getEnumerablePropertyNames(propertyNames);
     439    m_structureID->propertyMap().getEnumerablePropertyNames(propertyNames);
    430440
    431441    // Add properties from the static hashtables of properties
     
    486496void JSObject::removeDirect(const Identifier& propertyName)
    487497{
    488     m_propertyMap.remove(propertyName);
    489     if (!m_structureID->isDictionary()) {
    490         RefPtr<StructureID> structureID = StructureID::toDictionaryTransition(m_structureID);
    491         setStructureID(structureID.release());
    492     }
     498    if (m_structureID->isDictionary()) {
     499        m_structureID->propertyMap().remove(propertyName, m_propertyStorage);
     500        return;
     501    }
     502
     503    RefPtr<StructureID> structureID = StructureID::toDictionaryTransition(m_structureID);
     504    structureID->propertyMap().remove(propertyName, m_propertyStorage);
     505    setStructureID(structureID.release());
    493506}
    494507
  • trunk/JavaScriptCore/kjs/JSObject.h

    r36263 r36285  
    7575        StructureID* inheritorID();
    7676
     77        PropertyStorage& propertyStorage() { return m_propertyStorage; }
     78
    7779        virtual UString className() const;
    7880
     
    121123
    122124        // This get function only looks at the property map.
    123         JSValue* getDirect(const Identifier& propertyName) const { return m_propertyMap.get(propertyName); }
    124         JSValue** getDirectLocation(const Identifier& propertyName) { return m_propertyMap.getLocation(propertyName); }
    125         JSValue** getDirectLocation(const Identifier& propertyName, bool& isWriteable) { return m_propertyMap.getLocation(propertyName, isWriteable); }
    126         size_t offsetForLocation(JSValue** location) { return m_propertyMap.offsetForLocation(location); }
     125        JSValue* getDirect(const Identifier& propertyName) const
     126        {
     127            return m_structureID->propertyMap().get(propertyName, m_propertyStorage);
     128        }
     129
     130        JSValue** getDirectLocation(const Identifier& propertyName)
     131        {
     132            return m_structureID->propertyMap().getLocation(propertyName, m_propertyStorage);
     133        }
     134
     135        JSValue** getDirectLocation(const Identifier& propertyName, bool& isWriteable)
     136        {
     137            return m_structureID->propertyMap().getLocation(propertyName, isWriteable, m_propertyStorage);
     138        }
     139
     140        size_t offsetForLocation(JSValue** location)
     141        {
     142            return location - m_propertyStorage.get();
     143        }
     144
    127145        void removeDirect(const Identifier& propertyName);
    128         bool hasCustomProperties() { return !m_propertyMap.isEmpty(); }
    129         bool hasGetterSetterProperties() { return m_propertyMap.hasGetterSetterProperties(); }
     146        bool hasCustomProperties() { return !m_structureID->propertyMap().isEmpty(); }
     147        bool hasGetterSetterProperties() { return m_structureID->propertyMap().hasGetterSetterProperties(); }
    130148
    131149        void putDirect(const Identifier& propertyName, JSValue* value, unsigned attr = 0);
     
    134152
    135153        // Fast access to known property offsets.
    136         JSValue* getDirectOffset(size_t offset) { return m_propertyMap.getOffset(offset); }
    137         void putDirectOffset(size_t offset, JSValue* v) { m_propertyMap.putOffset(offset, v); }
     154        JSValue* getDirectOffset(size_t offset) { return m_propertyStorage[offset]; }
     155        void putDirectOffset(size_t offset, JSValue* value) { m_propertyStorage[offset] = value; }
    138156
    139157        void fillGetterPropertySlot(PropertySlot&, JSValue** location);
     
    159177        StructureID* createInheritorID();
    160178
    161         PropertyMap m_propertyMap;
     179        PropertyStorage m_propertyStorage;
    162180        RefPtr<StructureID> m_inheritorID;
    163181    };
     
    285303{
    286304    if (JSValue** location = getDirectLocation(propertyName, slotIsWriteable)) {
    287         if (m_propertyMap.hasGetterSetterProperties() && location[0]->isGetterSetter()) {
     305        if (m_structureID->propertyMap().hasGetterSetterProperties() && location[0]->isGetterSetter()) {
    288306            slotIsWriteable = false;
    289307            fillGetterPropertySlot(slot, location);
     
    309327{
    310328    if (JSValue** location = getDirectLocation(propertyName)) {
    311         if (m_propertyMap.hasGetterSetterProperties() && location[0]->isGetterSetter())
     329        if (m_structureID->propertyMap().hasGetterSetterProperties() && location[0]->isGetterSetter())
    312330            fillGetterPropertySlot(slot, location);
    313331        else
     
    331349}
    332350
    333 inline void JSObject::putDirect(const Identifier& propertyName, JSValue* value, unsigned attr, bool checkReadOnly, PutPropertySlot& slot)
     351inline void JSObject::putDirect(const Identifier& propertyName, JSValue* value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot)
    334352{
    335353    ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
    336     m_propertyMap.put(propertyName, value, attr, checkReadOnly, this, slot);
    337     if (slot.type() == PutPropertySlot::NewProperty) {
    338         if (!m_structureID->isDictionary()) {
    339             RefPtr<StructureID> structureID = StructureID::addPropertyTransition(m_structureID, propertyName);
    340             setStructureID(structureID.release());
    341         }
    342     }
     354
     355     if (m_structureID->isDictionary()) {
     356         m_structureID->propertyMap().put(propertyName, value, attributes, checkReadOnly, this, slot, m_propertyStorage);
     357         return;
     358     }
     359 
     360     bool isWriteable;
     361     size_t offset = m_structureID->propertyMap().getOffset(propertyName, isWriteable);
     362     if (offset != WTF::notFound) {
     363         if (checkReadOnly && !isWriteable)
     364             return;
     365         m_propertyStorage[offset] = value;
     366         slot.setExistingProperty(this, offset);
     367         return;
     368     }
     369 
     370     RefPtr<StructureID> structureID = StructureID::addPropertyTransition(m_structureID, propertyName, value, attributes, checkReadOnly, this, slot, m_propertyStorage);
     371     setStructureID(structureID.release());
    343372}
    344373
  • trunk/JavaScriptCore/kjs/PropertyMap.cpp

    r36263 r36285  
    4242#endif
    4343
    44 #define USE_SINGLE_ENTRY 1
    45 
    4644namespace JSC {
    4745
     
    8381#if !DO_PROPERTYMAP_CONSTENCY_CHECK
    8482
    85 inline void PropertyMap::checkConsistency()
    86 {
    87 }
    88 
    89 #endif
     83inline void PropertyMap::checkConsistency(PropertyStorage&)
     84{
     85}
     86
     87#endif
     88
     89PropertyMap& PropertyMap::operator=(const PropertyMap& other)
     90{
     91    if (other.m_table) {
     92        size_t tableSize = Table::allocationSize(other.m_table->size);
     93        m_table = static_cast<Table*>(fastMalloc(tableSize));
     94        memcpy(m_table, other.m_table, tableSize);
     95
     96        unsigned entryCount = m_table->keyCount + m_table->deletedSentinelCount;
     97        for (unsigned i = 1; i <= entryCount; ++i) {
     98            if (UString::Rep* key = m_table->entries()[i].key)
     99                key->ref();
     100        }
     101    }
     102
     103    m_getterSetterFlag = other.m_getterSetterFlag;
     104    return *this;
     105}
    90106
    91107PropertyMap::~PropertyMap()
    92108{
    93     if (!m_usingTable) {
    94 #if USE_SINGLE_ENTRY
    95         if (m_singleEntryKey)
    96             m_singleEntryKey->deref();
    97 #endif
     109    if (!m_table)
    98110        return;
    99     }
    100 
    101     unsigned entryCount = m_u.table->keyCount + m_u.table->deletedSentinelCount;
     111
     112    unsigned entryCount = m_table->keyCount + m_table->deletedSentinelCount;
    102113    for (unsigned i = 1; i <= entryCount; i++) {
    103         if (UString::Rep* key = m_u.table->entries()[i].key)
     114        if (UString::Rep* key = m_table->entries()[i].key)
    104115            key->deref();
    105116    }
    106     fastFree(m_u.table);
    107 }
    108 
    109 JSValue* PropertyMap::get(const Identifier& propertyName, unsigned& attributes) const
     117    fastFree(m_table);
     118}
     119
     120JSValue* PropertyMap::get(const Identifier& propertyName, unsigned& attributes, const PropertyStorage& propertyStorage) const
    110121{
    111122    ASSERT(!propertyName.isNull());
     
    113124    UString::Rep* rep = propertyName._ustring.rep();
    114125
    115     if (!m_usingTable) {
    116 #if USE_SINGLE_ENTRY
    117         if (rep == m_singleEntryKey) {
    118             attributes = m_singleEntryAttributes;
    119             return m_u.singleEntryValue;
    120         }
    121 #endif
     126    if (!m_table)
    122127        return 0;
    123     }
    124128
    125129    unsigned i = rep->computedHash();
     
    129133#endif
    130134
    131     unsigned entryIndex = m_u.table->entryIndices[i & m_u.table->sizeMask];
     135    unsigned entryIndex = m_table->entryIndices[i & m_table->sizeMask];
    132136    if (entryIndex == emptyEntryIndex)
    133137        return 0;
    134138
    135     if (rep == m_u.table->entries()[entryIndex - 1].key) {
    136         attributes = m_u.table->entries()[entryIndex - 1].attributes;
    137         return m_u.table->entries()[entryIndex - 1].value;
     139    if (rep == m_table->entries()[entryIndex - 1].key) {
     140        attributes = m_table->entries()[entryIndex - 1].attributes;
     141        return propertyStorage[entryIndex - 1];
    138142    }
    139143
     
    151155#endif
    152156
    153         entryIndex = m_u.table->entryIndices[i & m_u.table->sizeMask];
     157        entryIndex = m_table->entryIndices[i & m_table->sizeMask];
    154158        if (entryIndex == emptyEntryIndex)
    155159            return 0;
    156160
    157         if (rep == m_u.table->entries()[entryIndex - 1].key) {
    158             attributes = m_u.table->entries()[entryIndex - 1].attributes;
    159             return m_u.table->entries()[entryIndex - 1].value;
    160         }
    161     }
    162 }
    163 
    164 JSValue* PropertyMap::get(const Identifier& propertyName) const
     161        if (rep == m_table->entries()[entryIndex - 1].key) {
     162            attributes = m_table->entries()[entryIndex - 1].attributes;
     163            return propertyStorage[entryIndex - 1];
     164        }
     165    }
     166}
     167
     168JSValue* PropertyMap::get(const Identifier& propertyName, const PropertyStorage& propertyStorage) const
    165169{
    166170    ASSERT(!propertyName.isNull());
     
    168172    UString::Rep* rep = propertyName._ustring.rep();
    169173
    170     if (!m_usingTable) {
    171 #if USE_SINGLE_ENTRY
    172         if (rep == m_singleEntryKey)
    173             return m_u.singleEntryValue;
    174 #endif
     174    if (!m_table)
    175175        return 0;
    176     }
    177176
    178177    unsigned i = rep->computedHash();
     
    182181#endif
    183182
    184     unsigned entryIndex = m_u.table->entryIndices[i & m_u.table->sizeMask];
     183    unsigned entryIndex = m_table->entryIndices[i & m_table->sizeMask];
    185184    if (entryIndex == emptyEntryIndex)
    186185        return 0;
    187186
    188     if (rep == m_u.table->entries()[entryIndex - 1].key)
    189         return m_u.table->entries()[entryIndex - 1].value;
     187    if (rep == m_table->entries()[entryIndex - 1].key)
     188        return propertyStorage[entryIndex - 1];
    190189
    191190#if DUMP_PROPERTYMAP_STATS
     
    202201#endif
    203202
    204         entryIndex = m_u.table->entryIndices[i & m_u.table->sizeMask];
     203        entryIndex = m_table->entryIndices[i & m_table->sizeMask];
    205204        if (entryIndex == emptyEntryIndex)
    206205            return 0;
    207206
    208         if (rep == m_u.table->entries()[entryIndex - 1].key)
    209             return m_u.table->entries()[entryIndex - 1].value;
    210     }
    211 }
    212 
    213 JSValue** PropertyMap::getLocation(const Identifier& propertyName)
     207        if (rep == m_table->entries()[entryIndex - 1].key)
     208            return propertyStorage[entryIndex - 1];
     209    }
     210}
     211
     212JSValue** PropertyMap::getLocation(const Identifier& propertyName, const PropertyStorage& propertyStorage)
    214213{
    215214    ASSERT(!propertyName.isNull());
     
    217216    UString::Rep* rep = propertyName._ustring.rep();
    218217
    219     if (!m_usingTable) {
    220 #if USE_SINGLE_ENTRY
    221         if (rep == m_singleEntryKey)
    222             return &m_u.singleEntryValue;
    223 #endif
     218    if (!m_table)
    224219        return 0;
    225     }
    226220
    227221    unsigned i = rep->computedHash();
     
    231225#endif
    232226
    233     unsigned entryIndex = m_u.table->entryIndices[i & m_u.table->sizeMask];
     227    unsigned entryIndex = m_table->entryIndices[i & m_table->sizeMask];
    234228    if (entryIndex == emptyEntryIndex)
    235229        return 0;
    236230
    237     if (rep == m_u.table->entries()[entryIndex - 1].key)
    238         return &m_u.table->entries()[entryIndex - 1].value;
     231    if (rep == m_table->entries()[entryIndex - 1].key)
     232        return &propertyStorage[entryIndex - 1];
    239233
    240234#if DUMP_PROPERTYMAP_STATS
     
    251245#endif
    252246
    253         entryIndex = m_u.table->entryIndices[i & m_u.table->sizeMask];
     247        entryIndex = m_table->entryIndices[i & m_table->sizeMask];
    254248        if (entryIndex == emptyEntryIndex)
    255249            return 0;
    256250
    257         if (rep == m_u.table->entries()[entryIndex - 1].key)
    258             return &m_u.table->entries()[entryIndex - 1].value;
    259     }
    260 }
    261 
    262 JSValue** PropertyMap::getLocation(const Identifier& propertyName, bool& isWriteable)
     251        if (rep == m_table->entries()[entryIndex - 1].key)
     252            return &propertyStorage[entryIndex - 1];
     253    }
     254}
     255
     256JSValue** PropertyMap::getLocation(const Identifier& propertyName, bool& isWriteable, const PropertyStorage& propertyStorage)
    263257{
    264258    ASSERT(!propertyName.isNull());
     
    266260    UString::Rep* rep = propertyName._ustring.rep();
    267261
    268     if (!m_usingTable) {
    269 #if USE_SINGLE_ENTRY
    270         if (rep == m_singleEntryKey) {
    271             isWriteable = !(m_singleEntryAttributes & ReadOnly);
    272             return &m_u.singleEntryValue;
    273         }
    274 #endif
     262    if (!m_table)
    275263        return 0;
    276     }
    277264
    278265    unsigned i = rep->computedHash();
     
    282269#endif
    283270
    284     unsigned entryIndex = m_u.table->entryIndices[i & m_u.table->sizeMask];
     271    unsigned entryIndex = m_table->entryIndices[i & m_table->sizeMask];
    285272    if (entryIndex == emptyEntryIndex)
    286273        return 0;
    287274
    288     if (rep == m_u.table->entries()[entryIndex - 1].key) {
    289         isWriteable = !(m_u.table->entries()[entryIndex - 1].attributes & ReadOnly);
    290         return &m_u.table->entries()[entryIndex - 1].value;
     275    if (rep == m_table->entries()[entryIndex - 1].key) {
     276        isWriteable = !(m_table->entries()[entryIndex - 1].attributes & ReadOnly);
     277        return &propertyStorage[entryIndex - 1];
    291278    }
    292279
     
    304291#endif
    305292
    306         entryIndex = m_u.table->entryIndices[i & m_u.table->sizeMask];
     293        entryIndex = m_table->entryIndices[i & m_table->sizeMask];
    307294        if (entryIndex == emptyEntryIndex)
    308295            return 0;
    309296
    310         if (rep == m_u.table->entries()[entryIndex - 1].key) {
    311             isWriteable = !(m_u.table->entries()[entryIndex - 1].attributes & ReadOnly);
    312             return &m_u.table->entries()[entryIndex - 1].value;
    313         }
    314     }
    315 }
    316 
    317 void PropertyMap::put(const Identifier& propertyName, JSValue* value, unsigned attributes, bool checkReadOnly, JSObject* slotBase, PutPropertySlot& slot)
     297        if (rep == m_table->entries()[entryIndex - 1].key) {
     298            isWriteable = !(m_table->entries()[entryIndex - 1].attributes & ReadOnly);
     299            return &propertyStorage[entryIndex - 1];
     300        }
     301    }
     302}
     303
     304void PropertyMap::put(const Identifier& propertyName, JSValue* value, unsigned attributes, bool checkReadOnly, JSObject* slotBase, PutPropertySlot& slot, PropertyStorage& propertyStorage)
    318305{
    319306    ASSERT(!propertyName.isNull());
    320307    ASSERT(value);
    321308
    322     checkConsistency();
     309    checkConsistency(propertyStorage);
    323310
    324311    UString::Rep* rep = propertyName._ustring.rep();
    325312
    326 #if USE_SINGLE_ENTRY
    327     if (!m_usingTable) {
    328         if (!m_singleEntryKey) {
    329             rep->ref();
    330             m_singleEntryKey = rep;
    331             m_u.singleEntryValue = value;
    332             m_singleEntryAttributes = static_cast<short>(attributes);
    333             checkConsistency();
    334             slot.setNewProperty(slotBase, WTF::notFound);
    335             return;
    336         }
    337         if (rep == m_singleEntryKey && !(checkReadOnly && (m_singleEntryAttributes & ReadOnly))) {
    338             m_u.singleEntryValue = value;
    339             return;
    340         }
    341     }
    342 #endif
    343 
    344     if (!m_usingTable)
    345         expand();
     313    if (!m_table)
     314        expand(propertyStorage);
    346315
    347316    // FIXME: Consider a fast case for tables with no deleted sentinels.
     
    357326
    358327    while (1) {
    359         unsigned entryIndex = m_u.table->entryIndices[i & m_u.table->sizeMask];
     328        unsigned entryIndex = m_table->entryIndices[i & m_table->sizeMask];
    360329        if (entryIndex == emptyEntryIndex)
    361330            break;
    362331
    363         if (m_u.table->entries()[entryIndex - 1].key == rep) {
    364             if (checkReadOnly && (m_u.table->entries()[entryIndex - 1].attributes & ReadOnly))
     332        if (m_table->entries()[entryIndex - 1].key == rep) {
     333            if (checkReadOnly && (m_table->entries()[entryIndex - 1].attributes & ReadOnly))
    365334                return;
    366335            // Put a new value in an existing hash table entry.
    367             m_u.table->entries()[entryIndex - 1].value = value;
     336            propertyStorage[entryIndex - 1] = value;
    368337            // Attributes are intentionally not updated.
    369             slot.setExistingProperty(slotBase, offsetForTableLocation(&m_u.table->entries()[entryIndex - 1].value));
     338            slot.setExistingProperty(slotBase, entryIndex - 1);
    370339            return;
    371340        } else if (entryIndex == deletedSentinelIndex) {
     
    392361
    393362    // Figure out which entry to use.
    394     unsigned entryIndex = m_u.table->keyCount + m_u.table->deletedSentinelCount + 2;
     363    unsigned entryIndex = m_table->keyCount + m_table->deletedSentinelCount + 2;
    395364    if (foundDeletedElement) {
    396365        i = deletedElementIndex;
    397         --m_u.table->deletedSentinelCount;
     366        --m_table->deletedSentinelCount;
    398367
    399368        // Since we're not making the table bigger, we can't use the entry one past
     
    401370        // slot that we can use. We know it will be there because we did at least one
    402371        // deletion in the past that left an entry empty.
    403         while (m_u.table->entries()[--entryIndex - 1].key) { }
     372        while (m_table->entries()[--entryIndex - 1].key) { }
    404373    }
    405374
    406375    // Create a new hash table entry.
    407     m_u.table->entryIndices[i & m_u.table->sizeMask] = entryIndex;
     376    m_table->entryIndices[i & m_table->sizeMask] = entryIndex;
    408377
    409378    // Create a new hash table entry.
    410379    rep->ref();
    411     m_u.table->entries()[entryIndex - 1].key = rep;
    412     m_u.table->entries()[entryIndex - 1].value = value;
    413     m_u.table->entries()[entryIndex - 1].attributes = attributes;
    414     m_u.table->entries()[entryIndex - 1].index = ++m_u.table->lastIndexUsed;
    415     ++m_u.table->keyCount;
    416 
    417     if ((m_u.table->keyCount + m_u.table->deletedSentinelCount) * 2 >= m_u.table->size)
    418         expand();
    419 
    420     checkConsistency();
    421     slot.setNewProperty(slotBase, offsetForTableLocation(&m_u.table->entries()[entryIndex - 1].value));
    422 }
    423 
    424 void PropertyMap::insert(const Entry& entry)
    425 {
    426     ASSERT(m_u.table);
     380    m_table->entries()[entryIndex - 1].key = rep;
     381    m_table->entries()[entryIndex - 1].attributes = attributes;
     382    m_table->entries()[entryIndex - 1].index = ++m_table->lastIndexUsed;
     383    ++m_table->keyCount;
     384
     385    propertyStorage[entryIndex - 1] = value;
     386
     387    if ((m_table->keyCount + m_table->deletedSentinelCount) * 2 >= m_table->size)
     388        expand(propertyStorage);
     389
     390    checkConsistency(propertyStorage);
     391    slot.setNewProperty(slotBase, entryIndex - 1);
     392}
     393
     394size_t PropertyMap::getOffset(const Identifier& propertyName)
     395{
     396    ASSERT(!propertyName.isNull());
     397
     398    if (!m_table)
     399        return WTF::notFound;
     400
     401    UString::Rep* rep = propertyName._ustring.rep();
     402
     403    unsigned i = rep->computedHash();
     404
     405#if DUMP_PROPERTYMAP_STATS
     406    ++numProbes;
     407#endif
     408
     409    unsigned entryIndex = m_table->entryIndices[i & m_table->sizeMask];
     410    if (entryIndex == emptyEntryIndex)
     411        return WTF::notFound;
     412
     413    if (rep == m_table->entries()[entryIndex - 1].key)
     414        return entryIndex - 1;
     415
     416#if DUMP_PROPERTYMAP_STATS
     417    ++numCollisions;
     418#endif
     419
     420    unsigned k = 1 | doubleHash(rep->computedHash());
     421
     422    while (1) {
     423        i += k;
     424
     425#if DUMP_PROPERTYMAP_STATS
     426        ++numRehashes;
     427#endif
     428
     429        entryIndex = m_table->entryIndices[i & m_table->sizeMask];
     430        if (entryIndex == emptyEntryIndex)
     431            return WTF::notFound;
     432
     433        if (rep == m_table->entries()[entryIndex - 1].key)
     434            return entryIndex - 1;
     435    }
     436}
     437
     438size_t PropertyMap::getOffset(const Identifier& propertyName, bool& isWriteable)
     439{
     440    ASSERT(!propertyName.isNull());
     441
     442    if (!m_table)
     443        return WTF::notFound;
     444
     445    UString::Rep* rep = propertyName._ustring.rep();
     446
     447    unsigned i = rep->computedHash();
     448
     449#if DUMP_PROPERTYMAP_STATS
     450    ++numProbes;
     451#endif
     452
     453    unsigned entryIndex = m_table->entryIndices[i & m_table->sizeMask];
     454    if (entryIndex == emptyEntryIndex)
     455        return WTF::notFound;
     456
     457    if (rep == m_table->entries()[entryIndex - 1].key) {
     458        isWriteable = !(m_table->entries()[entryIndex - 1].attributes & ReadOnly);
     459        return entryIndex - 1;
     460    }
     461
     462#if DUMP_PROPERTYMAP_STATS
     463    ++numCollisions;
     464#endif
     465
     466    unsigned k = 1 | doubleHash(rep->computedHash());
     467
     468    while (1) {
     469        i += k;
     470
     471#if DUMP_PROPERTYMAP_STATS
     472        ++numRehashes;
     473#endif
     474
     475        entryIndex = m_table->entryIndices[i & m_table->sizeMask];
     476        if (entryIndex == emptyEntryIndex)
     477            return WTF::notFound;
     478
     479        if (rep == m_table->entries()[entryIndex - 1].key) {
     480            isWriteable = !(m_table->entries()[entryIndex - 1].attributes & ReadOnly);
     481            return entryIndex - 1;
     482        }
     483    }
     484}
     485
     486void PropertyMap::insert(const Entry& entry, JSValue* value, PropertyStorage& propertyStorage)
     487{
     488    ASSERT(m_table);
    427489
    428490    unsigned i = entry.key->computedHash();
     
    434496
    435497    while (1) {
    436         unsigned entryIndex = m_u.table->entryIndices[i & m_u.table->sizeMask];
     498        unsigned entryIndex = m_table->entryIndices[i & m_table->sizeMask];
    437499        if (entryIndex == emptyEntryIndex)
    438500            break;
     
    452514    }
    453515
    454     unsigned entryIndex = m_u.table->keyCount + 2;
    455     m_u.table->entryIndices[i & m_u.table->sizeMask] = entryIndex;
    456     m_u.table->entries()[entryIndex - 1] = entry;
    457     ++m_u.table->keyCount;
    458 }
    459 
    460 void PropertyMap::expand()
    461 {
    462     if (!m_usingTable)
    463         createTable();
     516    unsigned entryIndex = m_table->keyCount + 2;
     517    m_table->entryIndices[i & m_table->sizeMask] = entryIndex;
     518    m_table->entries()[entryIndex - 1] = entry;
     519
     520    propertyStorage[entryIndex - 1] = value;
     521
     522    ++m_table->keyCount;
     523}
     524
     525void PropertyMap::expand(PropertyStorage& propertyStorage)
     526{
     527    if (!m_table)
     528        createTable(propertyStorage);
    464529    else
    465         rehash(m_u.table->size * 2);
    466 }
    467 
    468 void PropertyMap::rehash()
    469 {
    470     ASSERT(m_usingTable);
    471     ASSERT(m_u.table);
    472     ASSERT(m_u.table->size);
    473     rehash(m_u.table->size);
    474 }
    475 
    476 void PropertyMap::createTable()
     530        rehash(m_table->size * 2, propertyStorage);
     531}
     532
     533void PropertyMap::rehash(PropertyStorage& propertyStorage)
     534{
     535    ASSERT(m_table);
     536    ASSERT(m_table->size);
     537    rehash(m_table->size, propertyStorage);
     538}
     539
     540void PropertyMap::createTable(PropertyStorage& propertyStorage)
    477541{
    478542    const unsigned newTableSize = 16;
    479543
    480     ASSERT(!m_usingTable);
    481 
    482     checkConsistency();
    483 
    484 #if USE_SINGLE_ENTRY
    485     JSValue* oldSingleEntryValue = m_u.singleEntryValue;
    486 #endif
    487 
    488     m_u.table = static_cast<Table*>(fastZeroedMalloc(Table::allocationSize(newTableSize)));
    489     m_u.table->size = newTableSize;
    490     m_u.table->sizeMask = newTableSize - 1;
    491     m_usingTable = true;
    492 
    493 #if USE_SINGLE_ENTRY
    494     if (m_singleEntryKey) {
    495         insert(Entry(m_singleEntryKey, oldSingleEntryValue, m_singleEntryAttributes));
    496         m_singleEntryKey = 0;
    497     }
    498 #endif
    499 
    500     checkConsistency();
    501 }
    502 
    503 void PropertyMap::rehash(unsigned newTableSize)
    504 {
    505     ASSERT(!m_singleEntryKey);
    506     ASSERT(m_u.table);
    507     ASSERT(m_usingTable);
    508 
    509     checkConsistency();
    510 
    511     Table* oldTable = m_u.table;
    512 
    513     m_u.table = static_cast<Table*>(fastZeroedMalloc(Table::allocationSize(newTableSize)));
    514     m_u.table->size = newTableSize;
    515     m_u.table->sizeMask = newTableSize - 1;
     544    ASSERT(!m_table);
     545
     546    checkConsistency(propertyStorage);
     547
     548    m_table = static_cast<Table*>(fastZeroedMalloc(Table::allocationSize(newTableSize)));
     549    m_table->size = newTableSize;
     550    m_table->sizeMask = newTableSize - 1;
     551
     552    propertyStorage.set(new JSValue*[m_table->size]);
     553
     554    checkConsistency(propertyStorage);
     555}
     556
     557void PropertyMap::rehash(unsigned newTableSize, PropertyStorage& propertyStorage)
     558{
     559    ASSERT(m_table);
     560
     561    checkConsistency(propertyStorage);
     562
     563    Table* oldTable = m_table;
     564    JSValue** oldPropertStorage = propertyStorage.release();
     565
     566    m_table = static_cast<Table*>(fastZeroedMalloc(Table::allocationSize(newTableSize)));
     567    m_table->size = newTableSize;
     568    m_table->sizeMask = newTableSize - 1;
     569
     570    propertyStorage.set(new JSValue*[m_table->size]);
    516571
    517572    unsigned lastIndexUsed = 0;
     
    520575        if (oldTable->entries()[i].key) {
    521576            lastIndexUsed = max(oldTable->entries()[i].index, lastIndexUsed);
    522             insert(oldTable->entries()[i]);
    523         }
    524     }
    525     m_u.table->lastIndexUsed = lastIndexUsed;
     577            insert(oldTable->entries()[i], oldPropertStorage[i], propertyStorage);
     578        }
     579    }
     580    m_table->lastIndexUsed = lastIndexUsed;
    526581
    527582    fastFree(oldTable);
    528 
    529     checkConsistency();
    530 }
    531 
    532 void PropertyMap::remove(const Identifier& propertyName)
     583    delete [] oldPropertStorage;
     584
     585    checkConsistency(propertyStorage);
     586}
     587
     588void PropertyMap::resizePropertyStorage(PropertyStorage& propertyStorage, unsigned oldSize)
     589{
     590    ASSERT(m_table);
     591
     592    if (propertyStorage) {
     593        JSValue** oldPropertStorage = propertyStorage.release();
     594        propertyStorage.set(new JSValue*[m_table->size]);
     595
     596        // FIXME: this can probalby use memcpy
     597        for (unsigned i = 1; i <= oldSize; ++i)
     598            propertyStorage[i] = oldPropertStorage[i];
     599
     600        delete [] oldPropertStorage;
     601    } else
     602        propertyStorage.set(new JSValue*[m_table->size]);
     603
     604    checkConsistency(propertyStorage);
     605}
     606
     607void PropertyMap::remove(const Identifier& propertyName, PropertyStorage& propertyStorage)
    533608{
    534609    ASSERT(!propertyName.isNull());
    535610
    536     checkConsistency();
     611    checkConsistency(propertyStorage);
    537612
    538613    UString::Rep* rep = propertyName._ustring.rep();
    539614
    540     if (!m_usingTable) {
    541 #if USE_SINGLE_ENTRY
    542         if (rep == m_singleEntryKey) {
    543             m_singleEntryKey->deref();
    544             m_singleEntryKey = 0;
    545             checkConsistency();
    546         }
    547 #endif
     615    if (!m_table)
    548616        return;
    549     }
    550617
    551618#if DUMP_PROPERTYMAP_STATS
     
    560627    UString::Rep* key = 0;
    561628    while (1) {
    562         entryIndex = m_u.table->entryIndices[i & m_u.table->sizeMask];
     629        entryIndex = m_table->entryIndices[i & m_table->sizeMask];
    563630        if (entryIndex == emptyEntryIndex)
    564631            return;
    565632
    566         key = m_u.table->entries()[entryIndex - 1].key;
     633        key = m_table->entries()[entryIndex - 1].key;
    567634        if (rep == key)
    568635            break;
     
    584651    // Replace this one element with the deleted sentinel. Also clear out
    585652    // the entry so we can iterate all the entries as needed.
    586     m_u.table->entryIndices[i & m_u.table->sizeMask] = deletedSentinelIndex;
     653    m_table->entryIndices[i & m_table->sizeMask] = deletedSentinelIndex;
    587654    key->deref();
    588     m_u.table->entries()[entryIndex - 1].key = 0;
    589     m_u.table->entries()[entryIndex - 1].value = jsUndefined();
    590     m_u.table->entries()[entryIndex - 1].attributes = 0;
    591     ASSERT(m_u.table->keyCount >= 1);
    592     --m_u.table->keyCount;
    593     ++m_u.table->deletedSentinelCount;
    594 
    595     if (m_u.table->deletedSentinelCount * 4 >= m_u.table->size)
    596         rehash();
    597 
    598     checkConsistency();
    599 }
    600 
    601 void PropertyMap::mark() const
    602 {
    603     if (!m_usingTable) {
    604 #if USE_SINGLE_ENTRY
    605         if (m_singleEntryKey) {
    606             JSValue* v = m_u.singleEntryValue;
    607             if (!v->marked())
    608                 v->mark();
    609         }
    610 #endif
    611         return;
    612     }
    613 
    614     unsigned entryCount = m_u.table->keyCount + m_u.table->deletedSentinelCount;
    615     for (unsigned i = 1; i <= entryCount; i++) {
    616         JSValue* v = m_u.table->entries()[i].value;
    617         if (!v->marked())
    618             v->mark();
    619     }
     655    m_table->entries()[entryIndex - 1].key = 0;
     656    m_table->entries()[entryIndex - 1].attributes = 0;
     657
     658    propertyStorage[entryIndex - 1] = jsUndefined();
     659
     660    ASSERT(m_table->keyCount >= 1);
     661    --m_table->keyCount;
     662    ++m_table->deletedSentinelCount;
     663
     664    if (m_table->deletedSentinelCount * 4 >= m_table->size)
     665        rehash(propertyStorage);
     666
     667    checkConsistency(propertyStorage);
    620668}
    621669
     
    633681void PropertyMap::getEnumerablePropertyNames(PropertyNameArray& propertyNames) const
    634682{
    635     if (!m_usingTable) {
    636 #if USE_SINGLE_ENTRY
    637         UString::Rep* key = m_singleEntryKey;
    638         if (key && !(m_singleEntryAttributes & DontEnum))
    639             propertyNames.add(key);
    640 #endif
     683    if (!m_table)
    641684        return;
    642     }
    643 
    644     if (m_u.table->keyCount < tinyMapThreshold) {
     685
     686    if (m_table->keyCount < tinyMapThreshold) {
    645687        Entry* a[tinyMapThreshold];
    646688        int i = 0;
    647         unsigned entryCount = m_u.table->keyCount + m_u.table->deletedSentinelCount;
     689        unsigned entryCount = m_table->keyCount + m_table->deletedSentinelCount;
    648690        for (unsigned k = 1; k <= entryCount; k++) {
    649             if (m_u.table->entries()[k].key && !(m_u.table->entries()[k].attributes & DontEnum)) {
    650                 Entry* value = &m_u.table->entries()[k];
     691            if (m_table->entries()[k].key && !(m_table->entries()[k].attributes & DontEnum)) {
     692                Entry* value = &m_table->entries()[k];
    651693                int j;
    652694                for (j = i - 1; j >= 0 && a[j]->index > value->index; --j)
     
    667709
    668710    // Allocate a buffer to use to sort the keys.
    669     Vector<Entry*, smallMapThreshold> sortedEnumerables(m_u.table->keyCount);
     711    Vector<Entry*, smallMapThreshold> sortedEnumerables(m_table->keyCount);
    670712
    671713    // Get pointers to the enumerable entries in the buffer.
    672714    Entry** p = sortedEnumerables.data();
    673     unsigned entryCount = m_u.table->keyCount + m_u.table->deletedSentinelCount;
     715    unsigned entryCount = m_table->keyCount + m_table->deletedSentinelCount;
    674716    for (unsigned i = 1; i <= entryCount; i++) {
    675         if (m_u.table->entries()[i].key && !(m_u.table->entries()[i].attributes & DontEnum))
    676             *p++ = &m_u.table->entries()[i];
     717        if (m_table->entries()[i].key && !(m_table->entries()[i].attributes & DontEnum))
     718            *p++ = &m_table->entries()[i];
    677719    }
    678720
     
    687729#if DO_PROPERTYMAP_CONSTENCY_CHECK
    688730
    689 void PropertyMap::checkConsistency()
    690 {
    691     if (!m_usingTable)
     731void PropertyMap::checkConsistency(PropertyStorage& propertyStorage)
     732{
     733    if (!m_table)
    692734        return;
    693735
    694     ASSERT(m_u.table->size >= 16);
    695     ASSERT(m_u.table->sizeMask);
    696     ASSERT(m_u.table->size == m_u.table->sizeMask + 1);
    697     ASSERT(!(m_u.table->size & m_u.table->sizeMask));
    698 
    699     ASSERT(m_u.table->keyCount <= m_u.table->size / 2);
    700     ASSERT(m_u.table->deletedSentinelCount <= m_u.table->size / 4);
    701 
    702     ASSERT(m_u.table->keyCount + m_u.table->deletedSentinelCount <= m_u.table->size / 2);
     736    ASSERT(m_table->size >= 16);
     737    ASSERT(m_table->sizeMask);
     738    ASSERT(m_table->size == m_table->sizeMask + 1);
     739    ASSERT(!(m_table->size & m_table->sizeMask));
     740
     741    ASSERT(m_table->keyCount <= m_table->size / 2);
     742    ASSERT(m_table->deletedSentinelCount <= m_table->size / 4);
     743
     744    ASSERT(m_table->keyCount + m_table->deletedSentinelCount <= m_table->size / 2);
    703745
    704746    unsigned indexCount = 0;
    705747    unsigned deletedIndexCount = 0;
    706     for (unsigned a = 0; a != m_u.table->size; ++a) {
    707         unsigned entryIndex = m_u.table->entryIndices[a];
     748    for (unsigned a = 0; a != m_table->size; ++a) {
     749        unsigned entryIndex = m_table->entryIndices[a];
    708750        if (entryIndex == emptyEntryIndex)
    709751            continue;
     
    713755        }
    714756        ASSERT(entryIndex > deletedSentinelIndex);
    715         ASSERT(entryIndex - 1 <= m_u.table->keyCount + m_u.table->deletedSentinelCount);
     757        ASSERT(entryIndex - 1 <= m_table->keyCount + m_table->deletedSentinelCount);
    716758        ++indexCount;
    717759
    718         for (unsigned b = a + 1; b != m_u.table->size; ++b)
    719             ASSERT(m_u.table->entryIndices[b] != entryIndex);
    720     }
    721     ASSERT(indexCount == m_u.table->keyCount);
    722     ASSERT(deletedIndexCount == m_u.table->deletedSentinelCount);
    723 
    724     ASSERT(m_u.table->entries()[0].key == 0);
     760        for (unsigned b = a + 1; b != m_table->size; ++b)
     761            ASSERT(m_table->entryIndices[b] != entryIndex);
     762    }
     763    ASSERT(indexCount == m_table->keyCount);
     764    ASSERT(deletedIndexCount == m_table->deletedSentinelCount);
     765
     766    ASSERT(m_table->entries()[0].key == 0);
    725767
    726768    unsigned nonEmptyEntryCount = 0;
    727     for (unsigned c = 1; c <= m_u.table->keyCount + m_u.table->deletedSentinelCount; ++c) {
    728         UString::Rep* rep = m_u.table->entries()[c].key;
     769    for (unsigned c = 1; c <= m_table->keyCount + m_table->deletedSentinelCount; ++c) {
     770        UString::Rep* rep = m_table->entries()[c].key;
    729771        if (!rep) {
    730             ASSERT(m_u.table->entries()[c].value->isUndefined());
     772            ASSERT(propertyStorage[c]->isUndefined());
    731773            continue;
    732774        }
     
    736778        unsigned entryIndex;
    737779        while (1) {
    738             entryIndex = m_u.table->entryIndices[i & m_u.table->sizeMask];
     780            entryIndex = m_table->entryIndices[i & m_table->sizeMask];
    739781            ASSERT(entryIndex != emptyEntryIndex);
    740             if (rep == m_u.table->entries()[entryIndex - 1].key)
     782            if (rep == m_table->entries()[entryIndex - 1].key)
    741783                break;
    742784            if (k == 0)
     
    747789    }
    748790
    749     ASSERT(nonEmptyEntryCount == m_u.table->keyCount);
     791    ASSERT(nonEmptyEntryCount == m_table->keyCount);
    750792}
    751793
  • trunk/JavaScriptCore/kjs/PropertyMap.h

    r36263 r36285  
    2424#include "PropertySlot.h"
    2525#include "identifier.h"
     26#include <wtf/OwnArrayPtr.h>
    2627#include <wtf/NotFound.h>
    2728
     
    3132    class JSValue;
    3233    class PropertyNameArray;
    33     struct PropertyMapEntry;
    34     struct PropertyMapHashTable;
     34
     35    typedef OwnArrayPtr<JSValue*> PropertyStorage;
    3536
    3637    struct PropertyMapEntry {
    3738        UString::Rep* key;
    38         JSValue* value;
    3939        unsigned attributes;
    4040        unsigned index;
    4141
    42         PropertyMapEntry(UString::Rep* k, JSValue* v, int a)
     42        PropertyMapEntry(UString::Rep* k, int a)
    4343            : key(k)
    44             , value(v)
    4544            , attributes(a)
    4645            , index(0)
     
    8180    };
    8281
    83     class PropertyMap : Noncopyable {
     82    class PropertyMap {
    8483        friend class CTI;
    85 
    8684    public:
    8785        PropertyMap();
    8886        ~PropertyMap();
    8987
    90         bool isEmpty() { return !m_usingTable & !m_singleEntryKey; }
     88        PropertyMap& operator=(const PropertyMap&);
    9189
    92         void put(const Identifier& propertyName, JSValue*, unsigned attributes, bool checkReadOnly, JSObject* slotBase, PutPropertySlot&);
    93         void remove(const Identifier& propertyName);
    94         JSValue* get(const Identifier& propertyName) const;
    95         JSValue* get(const Identifier& propertyName, unsigned& attributes) const;
    96         JSValue** getLocation(const Identifier& propertyName);
    97         JSValue** getLocation(const Identifier& propertyName, bool& isWriteable);
    98        
    99         JSValue* getOffset(size_t offset)
    100         {
    101             ASSERT(m_usingTable);
    102             return reinterpret_cast<JSValue**>(m_u.table->entryIndices)[offset];
    103         }
    104         void putOffset(size_t offset, JSValue* v)
    105         {
    106             ASSERT(m_usingTable);
    107             reinterpret_cast<JSValue**>(m_u.table->entryIndices)[offset] = v;
    108         }
     90        bool isEmpty() { return !m_table; }
    10991
    110         size_t offsetForLocation(JSValue** location) { return m_usingTable ? offsetForTableLocation(location) : WTF::notFound; }
     92        void put(const Identifier& propertyName, JSValue*, unsigned attributes, bool checkReadOnly, JSObject* slotBase, PutPropertySlot&, PropertyStorage&);
     93        void remove(const Identifier& propertyName, PropertyStorage&);
     94        JSValue* get(const Identifier& propertyName, const PropertyStorage&) const;
     95        JSValue* get(const Identifier& propertyName, unsigned& attributes, const PropertyStorage&) const;
     96        JSValue** getLocation(const Identifier& propertyName, const PropertyStorage&);
     97        JSValue** getLocation(const Identifier& propertyName, bool& isWriteable, const PropertyStorage&);
    11198
    112         void mark() const;
     99        size_t getOffset(const Identifier& propertyName);
     100        size_t getOffset(const Identifier& propertyName, bool& isWriteable);
     101
    113102        void getEnumerablePropertyNames(PropertyNameArray&) const;
    114103
    115104        bool hasGetterSetterProperties() const { return m_getterSetterFlag; }
    116105        void setHasGetterSetterProperties(bool f) { m_getterSetterFlag = f; }
     106
     107        unsigned size() const { return m_table ? m_table->size : 0; }
     108        unsigned makingCount() const { return m_table ? m_table->keyCount + m_table->deletedSentinelCount : 0; }
     109
     110        void resizePropertyStorage(PropertyStorage&, unsigned oldSize);
    117111
    118112    private:
     
    121115
    122116        static bool keysMatch(const UString::Rep*, const UString::Rep*);
    123         void expand();
    124         void rehash();
    125         void rehash(unsigned newTableSize);
    126         void createTable();
    127        
    128         void insert(const Entry&);
    129        
    130         size_t offsetForTableLocation(JSValue** location)
    131         {
    132             ASSERT(m_usingTable);
    133             return location - reinterpret_cast<JSValue**>(m_u.table->entryIndices);
    134         }
     117        void expand(PropertyStorage&);
     118        void rehash(PropertyStorage&);
     119        void rehash(unsigned newTableSize, PropertyStorage&);
     120        void createTable(PropertyStorage&);
    135121
    136         void checkConsistency();
    137        
    138         UString::Rep* m_singleEntryKey;
    139         union {
    140             JSValue* singleEntryValue;
    141             Table* table;
    142         } m_u;
     122        void insert(const Entry&, JSValue*, PropertyStorage&);
    143123
    144         short m_singleEntryAttributes;
     124        void checkConsistency(PropertyStorage&);
     125
     126        Table* m_table;
    145127        bool m_getterSetterFlag : 1;
    146         bool m_usingTable : 1;
    147128    };
    148129
    149130    inline PropertyMap::PropertyMap()
    150         : m_singleEntryKey(0)
     131        : m_table(0)
    151132        , m_getterSetterFlag(false)
    152         , m_usingTable(false)
    153 
    154133    {
    155134    }
  • trunk/JavaScriptCore/kjs/StructureID.cpp

    r36263 r36285  
    1 // -*- mode: c++; c-basic-offset: 4 -*-
    21/*
    32 * Copyright (C) 2008 Apple Inc. All rights reserved.
     
    3231#include <wtf/RefPtr.h>
    3332
     33using namespace std;
     34
    3435namespace JSC {
    3536
     
    4647}
    4748
    48 PassRefPtr<StructureID> StructureID::addPropertyTransition(StructureID* structureID, const Identifier& name)
     49PassRefPtr<StructureID> StructureID::addPropertyTransition(StructureID* structureID, const Identifier& propertyName, JSValue* value, unsigned attributes, bool checkReadOnly, JSObject* slotBase, PutPropertySlot& slot, PropertyStorage& propertyStorage)
    4950{
    5051    ASSERT(!structureID->m_isDictionary);
    5152
    52     if (StructureID* existingTransition = structureID->m_transitionTable.get(name.ustring().rep()))
     53    if (StructureID* existingTransition = structureID->m_transitionTable.get(make_pair(propertyName.ustring().rep(), attributes))) {
     54        if (structureID->m_propertyMap.size() != existingTransition->m_propertyMap.size())
     55            existingTransition->m_propertyMap.resizePropertyStorage(propertyStorage, structureID->m_propertyMap.size());
     56
     57        size_t offset = existingTransition->propertyMap().getOffset(propertyName);
     58        ASSERT(offset != WTF::notFound);
     59        propertyStorage[offset] = value;
     60        slot.setExistingProperty(slotBase, offset);
     61
    5362        return existingTransition;
     63    }
    5464
    55     if (structureID->m_transitionCount > s_maxTransitionLength)
    56         return toDictionaryTransition(structureID);
     65    if (structureID->m_transitionCount > s_maxTransitionLength) {
     66        RefPtr<StructureID> transition = toDictionaryTransition(structureID);
     67        transition->m_propertyMap.put(propertyName, value, attributes, checkReadOnly, slotBase, slot, propertyStorage);
     68        return transition.release();
     69    }
    5770
    5871    RefPtr<StructureID> transition = create(structureID->m_prototype);
    5972    transition->m_cachedPrototypeChain = structureID->m_cachedPrototypeChain;
    6073    transition->m_previous = structureID;
    61     transition->m_nameInPrevious = name.ustring().rep();
     74    transition->m_nameInPrevious = propertyName.ustring().rep();
     75    transition->m_attributesInPrevious = attributes;
    6276    transition->m_transitionCount = structureID->m_transitionCount + 1;
     77    transition->m_propertyMap = structureID->m_propertyMap;
    6378
    64     structureID->m_transitionTable.add(name.ustring().rep(), transition.get());
     79    transition->m_propertyMap.put(propertyName, value, attributes, checkReadOnly, slotBase, slot, propertyStorage);
     80
     81    structureID->m_transitionTable.add(make_pair(propertyName.ustring().rep(), attributes), transition.get());
    6582    return transition.release();
    6683}
     
    7289    RefPtr<StructureID> transition = create(structureID->m_prototype);
    7390    transition->m_isDictionary = true;
     91    transition->m_propertyMap = structureID->m_propertyMap;
    7492    return transition.release();
    7593}
     
    90108    RefPtr<StructureID> transition = create(prototype);
    91109    transition->m_transitionCount = structureID->m_transitionCount + 1;
     110    transition->m_propertyMap = structureID->m_propertyMap;
    92111    return transition.release();
    93112}
     
    97116    RefPtr<StructureID> transition = create(structureID->prototype());
    98117    transition->m_transitionCount = structureID->m_transitionCount + 1;
     118    transition->m_propertyMap = structureID->m_propertyMap;
    99119    return transition.release();
    100120}
     
    103123{
    104124    if (m_previous) {
    105         ASSERT(m_previous->m_transitionTable.contains(m_nameInPrevious));
    106         m_previous->m_transitionTable.remove(m_nameInPrevious);
     125        ASSERT(m_previous->m_transitionTable.contains(make_pair(m_nameInPrevious, m_attributesInPrevious)));
     126        m_previous->m_transitionTable.remove(make_pair(m_nameInPrevious, m_attributesInPrevious));
    107127    }
    108128}
  • trunk/JavaScriptCore/kjs/StructureID.h

    r36263 r36285  
    1 // -*- mode: c++; c-basic-offset: 4 -*-
    21/*
    32 * Copyright (C) 2008 Apple Inc. All rights reserved.
     
    2827#define StructureID_h
    2928
     29#include "JSValue.h"
     30#include "PropertyMap.h"
     31#include "ustring.h"
     32#include <wtf/HashFunctions.h>
     33#include <wtf/HashTraits.h>
    3034#include <wtf/OwnArrayPtr.h>
    3135#include <wtf/PassRefPtr.h>
    3236#include <wtf/RefCounted.h>
    33 #include "JSValue.h"
    34 #include "ustring.h"
    3537
    3638namespace JSC {
     
    3840    class JSValue;
    3941    class StructureIDChain;
     42
     43    struct TransitionTableHash {
     44        typedef std::pair<RefPtr<UString::Rep>, unsigned> TransitionTableKey;
     45        static unsigned hash(const TransitionTableKey& p)
     46        {
     47            return p.first->computedHash();
     48        }
     49
     50        static bool equal(const TransitionTableKey& a, const TransitionTableKey& b)
     51        {
     52            return a == b;
     53        }
     54
     55        static const bool safeToCompareToEmptyOrDeleted = true;
     56    };
     57
     58    struct TransitionTableHashTraits {
     59        typedef WTF::HashTraits<RefPtr<UString::Rep> > FirstTraits;
     60        typedef WTF::GenericHashTraits<unsigned> SecondTraits;
     61        typedef std::pair<FirstTraits::TraitType, SecondTraits::TraitType> TraitType;
     62
     63        static const bool emptyValueIsZero = FirstTraits::emptyValueIsZero && SecondTraits::emptyValueIsZero;
     64        static TraitType emptyValue() { return std::make_pair(FirstTraits::emptyValue(), SecondTraits::emptyValue()); }
     65
     66        static const bool needsDestruction = FirstTraits::needsDestruction || SecondTraits::needsDestruction;
     67
     68        static void constructDeletedValue(TraitType& slot) { FirstTraits::constructDeletedValue(slot.first); }
     69        static bool isDeletedValue(const TraitType& value) { return FirstTraits::isDeletedValue(value.first); }
     70    };
    4071
    4172    class StructureID : public RefCounted<StructureID> {
     
    4576            return adoptRef(new StructureID(prototype));
    4677        }
    47        
     78
    4879        static PassRefPtr<StructureID> changePrototypeTransition(StructureID*, JSValue* prototype);
    49         static PassRefPtr<StructureID> addPropertyTransition(StructureID*, const Identifier& name);
     80        static PassRefPtr<StructureID> addPropertyTransition(StructureID*, const Identifier& propertyName, JSValue*, unsigned attributes, bool checkReadOnly, JSObject* slotBase, PutPropertySlot&, PropertyStorage&);
    5081        static PassRefPtr<StructureID> getterSetterTransition(StructureID*);
    5182        static PassRefPtr<StructureID> toDictionaryTransition(StructureID*);
     
    6394
    6495        JSValue* prototype() const { return m_prototype; }
    65        
     96
    6697        void setCachedPrototypeChain(PassRefPtr<StructureIDChain> cachedPrototypeChain) { m_cachedPrototypeChain = cachedPrototypeChain; }
    6798        StructureIDChain* cachedPrototypeChain() const { return m_cachedPrototypeChain.get(); }
    6899
     100        const PropertyMap& propertyMap() const { return m_propertyMap; }
     101        PropertyMap& propertyMap() { return m_propertyMap; }
     102
    69103    private:
    70         typedef HashMap<RefPtr<UString::Rep>, StructureID*, IdentifierRepHash, HashTraits<RefPtr<UString::Rep> > > TransitionTable;
    71        
     104        typedef std::pair<RefPtr<UString::Rep>, unsigned> TransitionTableKey;
     105        typedef HashMap<TransitionTableKey, StructureID*, TransitionTableHash, TransitionTableHashTraits> TransitionTable;
     106
    72107        StructureID(JSValue* prototype);
    73108       
     
    81116        RefPtr<StructureID> m_previous;
    82117        UString::Rep* m_nameInPrevious;
     118        unsigned m_attributesInPrevious;
    83119
    84120        size_t m_transitionCount;
    85121        TransitionTable m_transitionTable;
     122
     123        PropertyMap m_propertyMap;
    86124    };
    87125
Note: See TracChangeset for help on using the changeset viewer.