+2008-10-07 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Cameron Zwarich.
+
+ Roll r37370 back in with bug fixes.
+
+ - PropertyMap::storageSize() should reflect the number of keys + deletedOffsets
+ and has nothing to do with the internal deletedSentinel count anymore.
+
2008-10-07 Gavin Barraclough <barraclough@apple.com>
Reviewed by Oliver Hunt.
__ZN3JSC11JSImmediate9prototypeEPKNS_7JSValueEPNS_9ExecStateE
__ZN3JSC11ProfileNode4sortEPFbRKN3WTF6RefPtrIS0_EES5_E
__ZN3JSC11ProgramNode6createEPNS_12JSGlobalDataEPNS_14SourceElementsEPN3WTF6VectorISt4pairINS_10IdentifierEjELm16EEEPNS6_INS5_6RefPtrINS_12FuncDeclNodeEEELm16EEERKNS_10SourceCodeEji
-__ZN3JSC11PropertyMap3putERKNS_10IdentifierEPNS_7JSValueEjbPNS_8JSObjectERNS_15PutPropertySlotERPS5_
-__ZN3JSC11PropertyMap9getOffsetERKNS_10IdentifierERj
+__ZN3JSC11PropertyMap3getERKNS_10IdentifierERj
+__ZN3JSC11PropertyMap3putERKNS_10IdentifierEj
__ZN3JSC11PropertyMapD1Ev
-__ZN3JSC11StructureID21addPropertyTransitionEPS0_RKNS_10IdentifierEPNS_7JSValueEjPNS_8JSObjectERNS_15PutPropertySlotERPS6_
+__ZN3JSC11StructureID21addPropertyTransitionEPS0_RKNS_10IdentifierEjRm
__ZN3JSC11StructureID21clearEnumerationCacheEv
__ZN3JSC11StructureID24fromDictionaryTransitionEPS0_
__ZN3JSC11StructureID25changePrototypeTransitionEPS0_PNS_7JSValueE
+__ZN3JSC11StructureID27growPropertyStorageCapacityEv
__ZN3JSC11StructureIDC1EPNS_7JSValueERKNS_8TypeInfoE
__ZN3JSC11StructureIDD1Ev
__ZN3JSC12DateInstance4infoE
static JSValue* SFX_CALL transitionObject(StructureID* newStructureID, size_t cachedOffset, JSObject* baseObject, JSValue* value)
{
- StructureID* oldStructureID = newStructureID->previousID();
-
baseObject->transitionTo(newStructureID);
-
- if (oldStructureID->propertyMap().storageSize() == JSObject::inlineStorageCapacity)
- baseObject->allocatePropertyStorage(oldStructureID->propertyMap().storageSize(), oldStructureID->propertyMap().size());
-
baseObject->putDirectOffset(cachedOffset, value);
return baseObject;
}
static inline bool transitionWillNeedStorageRealloc(StructureID* oldStructureID, StructureID* newStructureID)
{
- if (oldStructureID->propertyMap().storageSize() == JSObject::inlineStorageCapacity)
- return true;
-
- if (oldStructureID->propertyMap().storageSize() < JSObject::inlineStorageCapacity)
- return false;
-
- if (oldStructureID->propertyMap().size() != newStructureID->propertyMap().size())
- return true;
-
- return false;
+ return oldStructureID->propertyStorageCapacity() != newStructureID->propertyStorageCapacity();
}
void CTI::privateCompilePutByIdTransition(StructureID* oldStructureID, StructureID* newStructureID, size_t cachedOffset, StructureIDChain* sIDC, void* returnAddress)
}
baseObject->transitionTo(newStructureID);
- if (oldStructureID->propertyMap().storageSize() == JSObject::inlineStorageCapacity)
- baseObject->allocatePropertyStorage(oldStructureID->propertyMap().storageSize(), oldStructureID->propertyMap().size());
int value = vPC[3].u.operand;
unsigned offset = vPC[7].u.operand;
}
unsigned attributes;
- if ((m_structureID->propertyMap().getOffset(propertyName, attributes) != WTF::notFound) && attributes & ReadOnly)
+ if ((m_structureID->propertyMap().get(propertyName, attributes) != WTF::notFound) && attributes & ReadOnly)
return;
for (JSObject* obj = this; ; obj = static_cast<JSObject*>(prototype)) {
bool JSObject::deleteProperty(ExecState* exec, const Identifier& propertyName)
{
unsigned attributes;
- if (m_structureID->propertyMap().getOffset(propertyName, attributes) != WTF::notFound) {
+ if (m_structureID->propertyMap().get(propertyName, attributes) != WTF::notFound) {
if ((attributes & DontDelete))
return false;
removeDirect(propertyName);
bool JSObject::getPropertyAttributes(ExecState* exec, const Identifier& propertyName, unsigned& attributes) const
{
- if (m_structureID->propertyMap().getOffset(propertyName, attributes) != WTF::notFound)
+ if (m_structureID->propertyMap().get(propertyName, attributes) != WTF::notFound)
return true;
// Look in the static hashtable of properties
void JSObject::removeDirect(const Identifier& propertyName)
{
+ size_t offset;
if (m_structureID->isDictionary()) {
- m_structureID->propertyMap().remove(propertyName, m_propertyStorage);
- m_structureID->clearEnumerationCache();
+ offset = m_structureID->propertyMap().remove(propertyName);
+ if (offset != WTF::notFound) {
+ m_propertyStorage[offset] = jsUndefined();
+ m_structureID->clearEnumerationCache();
+ }
return;
}
RefPtr<StructureID> structureID = StructureID::toDictionaryTransition(m_structureID);
- structureID->propertyMap().remove(propertyName, m_propertyStorage);
+ offset = structureID->propertyMap().remove(propertyName);
+ if (offset != WTF::notFound)
+ m_propertyStorage[offset] = jsUndefined();
setStructureID(structureID.release());
}
void JSObject::allocatePropertyStorage(size_t oldSize, size_t newSize)
{
+ ASSERT(newSize > oldSize);
+
JSValue** oldPropertStorage = m_propertyStorage;
m_propertyStorage = new JSValue*[newSize];
// This get function only looks at the property map.
JSValue* getDirect(const Identifier& propertyName) const
{
- size_t offset = m_structureID->propertyMap().getOffset(propertyName);
+ size_t offset = m_structureID->propertyMap().get(propertyName);
return offset != WTF::notFound ? m_propertyStorage[offset] : 0;
}
JSValue** getDirectLocation(const Identifier& propertyName)
{
- size_t offset = m_structureID->propertyMap().getOffset(propertyName);
+ size_t offset = m_structureID->propertyMap().get(propertyName);
return offset != WTF::notFound ? locationForOffset(offset) : 0;
}
JSValue** getDirectLocation(const Identifier& propertyName, unsigned& attributes)
{
- size_t offset = m_structureID->propertyMap().getOffset(propertyName, attributes);
+ size_t offset = m_structureID->propertyMap().get(propertyName, attributes);
return offset != WTF::notFound ? locationForOffset(offset) : 0;
}
bool usingInlineStorage() const { return m_propertyStorage == m_inlineStorage; }
static const size_t inlineStorageCapacity = 2;
+ static const size_t nonInlineBaseStorageCapacity = 16;
static PassRefPtr<StructureID> createStructureID(JSValue* proto) { return StructureID::create(proto, TypeInfo(ObjectType)); }
{
ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
- if (m_structureID->isDictionary()) {
- unsigned currentAttributes;
- size_t offset = m_structureID->propertyMap().getOffset(propertyName, currentAttributes);
- if (offset != WTF::notFound) {
- if (checkReadOnly && currentAttributes & ReadOnly)
- return;
- m_propertyStorage[offset] = value;
- slot.setExistingProperty(this, offset);
- return;
- }
-
- if (m_structureID->propertyMap().storageSize() == inlineStorageCapacity)
- allocatePropertyStorage(m_structureID->propertyMap().storageSize(), m_structureID->propertyMap().size());
- m_structureID->propertyMap().put(propertyName, value, attributes, checkReadOnly, this, slot, m_propertyStorage);
- m_structureID->clearEnumerationCache();
- return;
- }
+ if (m_structureID->isDictionary()) {
+ unsigned currentAttributes;
+ size_t offset = m_structureID->propertyMap().get(propertyName, currentAttributes);
+ if (offset != WTF::notFound) {
+ if (checkReadOnly && currentAttributes & ReadOnly)
+ return;
+ m_propertyStorage[offset] = value;
+ slot.setExistingProperty(this, offset);
+ return;
+ }
+
+ size_t currentCapacity = m_structureID->propertyStorageCapacity();
+ offset = m_structureID->propertyMap().put(propertyName, attributes);
+ if (m_structureID->propertyMap().storageSize() > m_structureID->propertyStorageCapacity()) {
+ m_structureID->growPropertyStorageCapacity();
+ allocatePropertyStorage(currentCapacity, m_structureID->propertyStorageCapacity());
+ }
+
+ m_propertyStorage[offset] = value;
+ slot.setNewProperty(this, offset);
+ m_structureID->clearEnumerationCache();
+ return;
+ }
unsigned currentAttributes;
- size_t offset = m_structureID->propertyMap().getOffset(propertyName, currentAttributes);
+ size_t offset = m_structureID->propertyMap().get(propertyName, currentAttributes);
if (offset != WTF::notFound) {
if (checkReadOnly && currentAttributes & ReadOnly)
return;
return;
}
- if (m_structureID->propertyMap().storageSize() == inlineStorageCapacity)
- allocatePropertyStorage(m_structureID->propertyMap().storageSize(), m_structureID->propertyMap().size());
+ size_t currentCapacity = m_structureID->propertyStorageCapacity();
+ RefPtr<StructureID> structureID = StructureID::addPropertyTransition(m_structureID, propertyName, attributes, offset);
+ if (currentCapacity != structureID->propertyStorageCapacity())
+ allocatePropertyStorage(currentCapacity, structureID->propertyStorageCapacity());
- RefPtr<StructureID> structureID = StructureID::addPropertyTransition(m_structureID, propertyName, value, attributes, this, slot, m_propertyStorage);
- slot.setWasTransition(true);
- setStructureID(structureID.release());
+ ASSERT(offset < structureID->propertyStorageCapacity());
+ m_propertyStorage[offset] = value;
+ slot.setNewProperty(this, offset);
+ slot.setWasTransition(true);
+ setStructureID(structureID.release());
}
inline void JSObject::transitionTo(StructureID* newStructureID)
{
- StructureID::transitionTo(m_structureID, newStructureID, this);
+ if (m_structureID->propertyStorageCapacity() != newStructureID->propertyStorageCapacity())
+ allocatePropertyStorage(m_structureID->propertyStorageCapacity(), newStructureID->propertyStorageCapacity());
setStructureID(newStructureID);
}
#if !DO_PROPERTYMAP_CONSTENCY_CHECK
-inline void PropertyMap::checkConsistency(PropertyStorage&)
+inline void PropertyMap::checkConsistency()
{
}
}
}
+ m_deletedOffsets = other.m_deletedOffsets;
m_getterSetterFlag = other.m_getterSetterFlag;
return *this;
}
fastFree(m_table);
}
-size_t PropertyMap::put(const Identifier& propertyName, JSValue* value, unsigned attributes, bool checkReadOnly, JSObject* slotBase, PutPropertySlot& slot, PropertyStorage& propertyStorage)
+size_t PropertyMap::put(const Identifier& propertyName, unsigned attributes)
{
ASSERT(!propertyName.isNull());
- ASSERT(value);
+ ASSERT(get(propertyName) == WTF::notFound);
- checkConsistency(propertyStorage);
+ checkConsistency();
UString::Rep* rep = propertyName._ustring.rep();
if (!m_table)
- expand(propertyStorage);
+ createTable();
// FIXME: Consider a fast case for tables with no deleted sentinels.
if (entryIndex == emptyEntryIndex)
break;
- if (m_table->entries()[entryIndex - 1].key == rep) {
- if (checkReadOnly && (m_table->entries()[entryIndex - 1].attributes & ReadOnly))
- return WTF::notFound;
- // Put a new value in an existing hash table entry.
- propertyStorage[entryIndex - 2] = value;
- // Attributes are intentionally not updated.
- slot.setExistingProperty(slotBase, entryIndex - 2);
- return entryIndex - 2;
- } else if (entryIndex == deletedSentinelIndex) {
+ if (entryIndex == deletedSentinelIndex) {
// If we find a deleted-element sentinel, remember it for use later.
if (!foundDeletedElement) {
foundDeletedElement = true;
m_table->entries()[entryIndex - 1].key = rep;
m_table->entries()[entryIndex - 1].attributes = attributes;
m_table->entries()[entryIndex - 1].index = ++m_table->lastIndexUsed;
- ++m_table->keyCount;
- propertyStorage[entryIndex - 2] = value;
+ unsigned newOffset;
+ if (!m_deletedOffsets.isEmpty()) {
+ newOffset = m_deletedOffsets.last();
+ m_deletedOffsets.removeLast();
+ } else
+ newOffset = m_table->keyCount;
+ m_table->entries()[entryIndex - 1].offset = newOffset;
+
+ ++m_table->keyCount;
if ((m_table->keyCount + m_table->deletedSentinelCount) * 2 >= m_table->size)
- expand(propertyStorage);
+ expand();
- checkConsistency(propertyStorage);
- slot.setNewProperty(slotBase, entryIndex - 2);
- return entryIndex - 2;
+ checkConsistency();
+ return newOffset;
}
-void PropertyMap::remove(const Identifier& propertyName, PropertyStorage& propertyStorage)
+size_t PropertyMap::remove(const Identifier& propertyName)
{
ASSERT(!propertyName.isNull());
- checkConsistency(propertyStorage);
+ checkConsistency();
UString::Rep* rep = propertyName._ustring.rep();
if (!m_table)
- return;
+ return WTF::notFound;
#if DUMP_PROPERTYMAP_STATS
++numProbes;
while (1) {
entryIndex = m_table->entryIndices[i & m_table->sizeMask];
if (entryIndex == emptyEntryIndex)
- return;
+ return WTF::notFound;
key = m_table->entries()[entryIndex - 1].key;
if (rep == key)
// Replace this one element with the deleted sentinel. Also clear out
// the entry so we can iterate all the entries as needed.
m_table->entryIndices[i & m_table->sizeMask] = deletedSentinelIndex;
+
+ size_t offset = m_table->entries()[entryIndex - 1].offset;
+
key->deref();
m_table->entries()[entryIndex - 1].key = 0;
m_table->entries()[entryIndex - 1].attributes = 0;
-
- propertyStorage[entryIndex - 2] = jsUndefined();
+ m_table->entries()[entryIndex - 1].offset = 0;
+ m_deletedOffsets.append(offset);
ASSERT(m_table->keyCount >= 1);
--m_table->keyCount;
++m_table->deletedSentinelCount;
if (m_table->deletedSentinelCount * 4 >= m_table->size)
- rehash(propertyStorage);
+ rehash();
- checkConsistency(propertyStorage);
+ checkConsistency();
+ return offset;
}
-size_t PropertyMap::getOffset(const Identifier& propertyName, unsigned& attributes)
+size_t PropertyMap::get(const Identifier& propertyName, unsigned& attributes)
{
ASSERT(!propertyName.isNull());
if (rep == m_table->entries()[entryIndex - 1].key) {
attributes = m_table->entries()[entryIndex - 1].attributes;
- return entryIndex - 2;
+ return m_table->entries()[entryIndex - 1].offset;
}
#if DUMP_PROPERTYMAP_STATS
if (rep == m_table->entries()[entryIndex - 1].key) {
attributes = m_table->entries()[entryIndex - 1].attributes;
- return entryIndex - 2;
+ return m_table->entries()[entryIndex - 1].offset;
}
}
}
-void PropertyMap::insert(const Entry& entry, JSValue* value, PropertyStorage& propertyStorage)
+void PropertyMap::insert(const Entry& entry)
{
ASSERT(m_table);
m_table->entryIndices[i & m_table->sizeMask] = entryIndex;
m_table->entries()[entryIndex - 1] = entry;
- propertyStorage[entryIndex - 2] = value;
-
++m_table->keyCount;
}
-void PropertyMap::expand(PropertyStorage& propertyStorage)
-{
- if (!m_table)
- createTable(propertyStorage);
- else
- rehash(m_table->size * 2, propertyStorage);
-}
-
-void PropertyMap::rehash(PropertyStorage& propertyStorage)
+void PropertyMap::expand()
{
ASSERT(m_table);
- ASSERT(m_table->size);
- rehash(m_table->size, propertyStorage);
+ rehash(m_table->size * 2);
}
-void PropertyMap::createTable(PropertyStorage& propertyStorage)
+void PropertyMap::createTable()
{
const unsigned newTableSize = 16;
ASSERT(!m_table);
- checkConsistency(propertyStorage);
+ checkConsistency();
m_table = static_cast<Table*>(fastZeroedMalloc(Table::allocationSize(newTableSize)));
m_table->size = newTableSize;
m_table->sizeMask = newTableSize - 1;
- checkConsistency(propertyStorage);
+ checkConsistency();
}
-void PropertyMap::rehash(unsigned newTableSize, PropertyStorage& propertyStorage)
+void PropertyMap::rehash()
{
ASSERT(m_table);
+ ASSERT(m_table->size);
+ rehash(m_table->size);
+}
- checkConsistency(propertyStorage);
+void PropertyMap::rehash(unsigned newTableSize)
+{
+ ASSERT(m_table);
+
+ checkConsistency();
Table* oldTable = m_table;
- JSValue** oldPropertStorage = propertyStorage;
m_table = static_cast<Table*>(fastZeroedMalloc(Table::allocationSize(newTableSize)));
m_table->size = newTableSize;
m_table->sizeMask = newTableSize - 1;
- propertyStorage = new JSValue*[m_table->size];
-
unsigned lastIndexUsed = 0;
unsigned entryCount = oldTable->keyCount + oldTable->deletedSentinelCount;
for (unsigned i = 1; i <= entryCount; ++i) {
if (oldTable->entries()[i].key) {
lastIndexUsed = max(oldTable->entries()[i].index, lastIndexUsed);
- insert(oldTable->entries()[i], oldPropertStorage[i - 1], propertyStorage);
+ insert(oldTable->entries()[i]);
}
}
m_table->lastIndexUsed = lastIndexUsed;
fastFree(oldTable);
- delete [] oldPropertStorage;
- checkConsistency(propertyStorage);
+ checkConsistency();
}
static int comparePropertyMapEntryIndices(const void* a, const void* b)
#if DO_PROPERTYMAP_CONSTENCY_CHECK
-void PropertyMap::checkConsistency(PropertyStorage& propertyStorage)
+void PropertyMap::checkConsistency()
{
if (!m_table)
return;
unsigned nonEmptyEntryCount = 0;
for (unsigned c = 1; c <= m_table->keyCount + m_table->deletedSentinelCount; ++c) {
UString::Rep* rep = m_table->entries()[c].key;
- if (!rep) {
- ASSERT(propertyStorage[c - 1]->isUndefined());
+ if (!rep)
continue;
- }
++nonEmptyEntryCount;
unsigned i = rep->computedHash();
unsigned k = 0;
struct PropertyMapEntry {
UString::Rep* key;
+ unsigned offset;
unsigned attributes;
unsigned index;
PropertyMapEntry(UString::Rep* k, int a)
: key(k)
+ , offset(0)
, attributes(a)
, index(0)
{
PropertyMap& operator=(const PropertyMap&);
- bool isEmpty() { return !m_table; }
-
- size_t put(const Identifier& propertyName, JSValue*, unsigned attributes, bool checkReadOnly, JSObject* slotBase, PutPropertySlot&, PropertyStorage&);
- void remove(const Identifier& propertyName, PropertyStorage&);
- size_t getOffset(const Identifier& propertyName);
- size_t getOffset(const Identifier& propertyName, unsigned& attributes);
+ size_t get(const Identifier& propertyName);
+ size_t get(const Identifier& propertyName, unsigned& attributes);
+ size_t put(const Identifier& propertyName, unsigned attributes);
+ size_t remove(const Identifier& propertyName);
void getEnumerablePropertyNames(PropertyNameArray&) const;
bool hasGetterSetterProperties() const { return m_getterSetterFlag; }
void setHasGetterSetterProperties(bool f) { m_getterSetterFlag = f; }
- unsigned size() const { return m_table ? m_table->size : 0; }
- unsigned storageSize() const { return m_table ? m_table->keyCount + m_table->deletedSentinelCount : 0; }
+ bool isEmpty() { return !m_table; }
+ unsigned storageSize() const { return m_table ? m_table->keyCount + m_deletedOffsets.size() : 0; }
static const unsigned emptyEntryIndex = 0;
typedef PropertyMapEntry Entry;
typedef PropertyMapHashTable Table;
- void expand(PropertyStorage&);
- void rehash(PropertyStorage&);
- void rehash(unsigned newTableSize, PropertyStorage&);
- void createTable(PropertyStorage&);
+ void expand();
+ void rehash();
+ void rehash(unsigned newTableSize);
+ void createTable();
- void insert(const Entry&, JSValue*, PropertyStorage&);
+ void insert(const Entry&);
- void checkConsistency(PropertyStorage&);
+ void checkConsistency();
Table* m_table;
+ Vector<unsigned> m_deletedOffsets;
bool m_getterSetterFlag : 1;
};
{
}
- inline size_t PropertyMap::getOffset(const Identifier& propertyName)
+ inline size_t PropertyMap::get(const Identifier& propertyName)
{
ASSERT(!propertyName.isNull());
return WTF::notFound;
if (rep == m_table->entries()[entryIndex - 1].key)
- return entryIndex - 2;
+ return m_table->entries()[entryIndex - 1].offset;
#if DUMP_PROPERTYMAP_STATS
++numCollisions;
return WTF::notFound;
if (rep == m_table->entries()[entryIndex - 1].key)
- return entryIndex - 2;
+ return m_table->entries()[entryIndex - 1].offset;
}
}
, m_previous(0)
, m_nameInPrevious(0)
, m_transitionCount(0)
+ , m_propertyStorageCapacity(JSObject::inlineStorageCapacity)
, m_cachedTransistionOffset(WTF::notFound)
{
ASSERT(m_prototype);
m_cachedPropertyNameArrayData.clear();
}
-void StructureID::transitionTo(StructureID* oldStructureID, StructureID* newStructureID, JSObject* slotBase)
+void StructureID::growPropertyStorageCapacity()
{
- if (!slotBase->usingInlineStorage() && oldStructureID->m_propertyMap.size() != newStructureID->m_propertyMap.size())
- slotBase->allocatePropertyStorage(oldStructureID->m_propertyMap.size(), newStructureID->m_propertyMap.size());
+ if (m_propertyStorageCapacity == JSObject::inlineStorageCapacity)
+ m_propertyStorageCapacity = JSObject::nonInlineBaseStorageCapacity;
+ else
+ m_propertyStorageCapacity *= 2;
}
-PassRefPtr<StructureID> StructureID::addPropertyTransition(StructureID* structureID, const Identifier& propertyName, JSValue* value, unsigned attributes, JSObject* slotBase, PutPropertySlot& slot, PropertyStorage& propertyStorage)
+PassRefPtr<StructureID> StructureID::addPropertyTransition(StructureID* structureID, const Identifier& propertyName, unsigned attributes, size_t& offset)
{
ASSERT(!structureID->m_isDictionary);
ASSERT(structureID->typeInfo().type() == ObjectType);
if (StructureID* existingTransition = structureID->m_transitionTable.get(make_pair(propertyName.ustring().rep(), attributes))) {
- if (!slotBase->usingInlineStorage() && structureID->m_propertyMap.size() != existingTransition->m_propertyMap.size())
- slotBase->allocatePropertyStorage(structureID->m_propertyMap.size(), existingTransition->m_propertyMap.size());
-
- size_t offset = existingTransition->cachedTransistionOffset();
+ offset = existingTransition->cachedTransistionOffset();
ASSERT(offset != WTF::notFound);
- propertyStorage[offset] = value;
- slot.setNewProperty(slotBase, offset);
-
return existingTransition;
}
if (structureID->m_transitionCount > s_maxTransitionLength) {
RefPtr<StructureID> transition = toDictionaryTransition(structureID);
- transition->m_propertyMap.put(propertyName, value, attributes, false, slotBase, slot, propertyStorage);
+ offset = transition->m_propertyMap.put(propertyName, attributes);
+ if (transition->m_propertyMap.storageSize() > transition->propertyStorageCapacity())
+ transition->growPropertyStorageCapacity();
return transition.release();
}
transition->m_attributesInPrevious = attributes;
transition->m_transitionCount = structureID->m_transitionCount + 1;
transition->m_propertyMap = structureID->m_propertyMap;
+ transition->m_propertyStorageCapacity = structureID->m_propertyStorageCapacity;
+
+ offset = transition->m_propertyMap.put(propertyName, attributes);
+ if (transition->m_propertyMap.storageSize() > transition->propertyStorageCapacity())
+ transition->growPropertyStorageCapacity();
- size_t offset = transition->m_propertyMap.put(propertyName, value, attributes, false, slotBase, slot, propertyStorage);
transition->setCachedTransistionOffset(offset);
structureID->m_transitionTable.add(make_pair(propertyName.ustring().rep(), attributes), transition.get());
RefPtr<StructureID> transition = create(structureID->m_prototype, structureID->typeInfo());
transition->m_isDictionary = true;
transition->m_propertyMap = structureID->m_propertyMap;
+ transition->m_propertyStorageCapacity = structureID->m_propertyStorageCapacity;
return transition.release();
}
RefPtr<StructureID> transition = create(prototype, structureID->typeInfo());
transition->m_transitionCount = structureID->m_transitionCount + 1;
transition->m_propertyMap = structureID->m_propertyMap;
+ transition->m_propertyStorageCapacity = structureID->m_propertyStorageCapacity;
return transition.release();
}
RefPtr<StructureID> transition = create(structureID->storedPrototype(), structureID->typeInfo());
transition->m_transitionCount = structureID->m_transitionCount + 1;
transition->m_propertyMap = structureID->m_propertyMap;
+ transition->m_propertyStorageCapacity = structureID->m_propertyStorageCapacity;
return transition.release();
}
}
static PassRefPtr<StructureID> changePrototypeTransition(StructureID*, JSValue* prototype);
- static PassRefPtr<StructureID> addPropertyTransition(StructureID*, const Identifier& propertyName, JSValue*, unsigned attributes, JSObject* slotBase, PutPropertySlot&, PropertyStorage&);
+ static PassRefPtr<StructureID> addPropertyTransition(StructureID*, const Identifier& propertyName, unsigned attributes, size_t& offset);
static PassRefPtr<StructureID> getterSetterTransition(StructureID*);
static PassRefPtr<StructureID> toDictionaryTransition(StructureID*);
static PassRefPtr<StructureID> fromDictionaryTransition(StructureID*);
void setCachedTransistionOffset(size_t offset) { m_cachedTransistionOffset = offset; }
size_t cachedTransistionOffset() const { return m_cachedTransistionOffset; }
+ void growPropertyStorageCapacity();
+ size_t propertyStorageCapacity() const { return m_propertyStorageCapacity; }
+
void getEnumerablePropertyNames(ExecState*, PropertyNameArray&, JSObject*);
void clearEnumerationCache();
- static void transitionTo(StructureID* oldStructureID, StructureID* newStructureID, JSObject* slotBase);
-
private:
typedef std::pair<RefPtr<UString::Rep>, unsigned> TransitionTableKey;
typedef HashMap<TransitionTableKey, StructureID*, TransitionTableHash, TransitionTableHashTraits> TransitionTable;
RefPtr<PropertyNameArrayData> m_cachedPropertyNameArrayData;
PropertyMap m_propertyMap;
+ size_t m_propertyStorageCapacity;
size_t m_cachedTransistionOffset;
};