summaryrefslogtreecommitdiffstats
path: root/JavaScriptCore/runtime/Structure.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'JavaScriptCore/runtime/Structure.cpp')
-rw-r--r--JavaScriptCore/runtime/Structure.cpp140
1 files changed, 122 insertions, 18 deletions
diff --git a/JavaScriptCore/runtime/Structure.cpp b/JavaScriptCore/runtime/Structure.cpp
index 546e2bf..d06a239 100644
--- a/JavaScriptCore/runtime/Structure.cpp
+++ b/JavaScriptCore/runtime/Structure.cpp
@@ -79,6 +79,106 @@ static HashSet<Structure*>& liveStructureSet = *(new HashSet<Structure*>);
static int comparePropertyMapEntryIndices(const void* a, const void* b);
+inline void Structure::setTransitionTable(TransitionTable* table)
+{
+ ASSERT(m_isUsingSingleSlot);
+#ifndef NDEBUG
+ setSingleTransition(0);
+#endif
+ m_isUsingSingleSlot = false;
+ m_transitions.m_table = table;
+ // This implicitly clears the flag that indicates we're using a single transition
+ ASSERT(!m_isUsingSingleSlot);
+}
+
+// The contains and get methods accept imprecise matches, so if an unspecialised transition exists
+// for the given key they will consider that transition to be a match. If a specialised transition
+// exists and it matches the provided specificValue, get will return the specific transition.
+inline bool Structure::transitionTableContains(const StructureTransitionTableHash::Key& key, JSCell* specificValue)
+{
+ if (m_isUsingSingleSlot) {
+ Structure* existingTransition = singleTransition();
+ return existingTransition && existingTransition->m_nameInPrevious.get() == key.first
+ && existingTransition->m_attributesInPrevious == key.second
+ && (existingTransition->m_specificValueInPrevious == specificValue || existingTransition->m_specificValueInPrevious == 0);
+ }
+ TransitionTable::iterator find = transitionTable()->find(key);
+ if (find == transitionTable()->end())
+ return false;
+
+ return find->second.first || find->second.second->transitionedFor(specificValue);
+}
+
+inline Structure* Structure::transitionTableGet(const StructureTransitionTableHash::Key& key, JSCell* specificValue) const
+{
+ if (m_isUsingSingleSlot) {
+ Structure* existingTransition = singleTransition();
+ if (existingTransition && existingTransition->m_nameInPrevious.get() == key.first
+ && existingTransition->m_attributesInPrevious == key.second
+ && (existingTransition->m_specificValueInPrevious == specificValue || existingTransition->m_specificValueInPrevious == 0))
+ return existingTransition;
+ return 0;
+ }
+
+ Transition transition = transitionTable()->get(key);
+ if (transition.second && transition.second->transitionedFor(specificValue))
+ return transition.second;
+ return transition.first;
+}
+
+inline bool Structure::transitionTableHasTransition(const StructureTransitionTableHash::Key& key) const
+{
+ if (m_isUsingSingleSlot) {
+ Structure* transition = singleTransition();
+ return transition && transition->m_nameInPrevious == key.first
+ && transition->m_attributesInPrevious == key.second;
+ }
+ return transitionTable()->contains(key);
+}
+
+inline void Structure::transitionTableRemove(const StructureTransitionTableHash::Key& key, JSCell* specificValue)
+{
+ if (m_isUsingSingleSlot) {
+ ASSERT(transitionTableContains(key, specificValue));
+ setSingleTransition(0);
+ return;
+ }
+ TransitionTable::iterator find = transitionTable()->find(key);
+ if (!specificValue)
+ find->second.first = 0;
+ else
+ find->second.second = 0;
+ if (!find->second.first && !find->second.second)
+ transitionTable()->remove(find);
+}
+
+inline void Structure::transitionTableAdd(const StructureTransitionTableHash::Key& key, Structure* structure, JSCell* specificValue)
+{
+ if (m_isUsingSingleSlot) {
+ if (!singleTransition()) {
+ setSingleTransition(structure);
+ return;
+ }
+ Structure* existingTransition = singleTransition();
+ TransitionTable* transitionTable = new TransitionTable;
+ setTransitionTable(transitionTable);
+ if (existingTransition)
+ transitionTableAdd(std::make_pair(existingTransition->m_nameInPrevious.get(), existingTransition->m_attributesInPrevious), existingTransition, existingTransition->m_specificValueInPrevious);
+ }
+ if (!specificValue) {
+ TransitionTable::iterator find = transitionTable()->find(key);
+ if (find == transitionTable()->end())
+ transitionTable()->add(key, Transition(structure, static_cast<Structure*>(0)));
+ else
+ find->second.first = structure;
+ } else {
+ // If we're adding a transition to a specific value, then there cannot be
+ // an existing transition
+ ASSERT(!transitionTable()->contains(key));
+ transitionTable()->add(key, Transition(static_cast<Structure*>(0), structure));
+ }
+}
+
void Structure::dumpStatistics()
{
#if DUMP_STRUCTURE_ID_STATISTICS
@@ -136,7 +236,10 @@ Structure::Structure(JSValue prototype, const TypeInfo& typeInfo, unsigned anony
, m_attributesInPrevious(0)
, m_specificFunctionThrashCount(0)
, m_anonymousSlotCount(anonymousSlotCount)
+ , m_isUsingSingleSlot(true)
{
+ m_transitions.m_singleTransition = 0;
+
ASSERT(m_prototype);
ASSERT(m_prototype.isObject() || m_prototype.isNull());
@@ -159,17 +262,15 @@ Structure::~Structure()
{
if (m_previous) {
ASSERT(m_nameInPrevious);
- m_previous->table.remove(make_pair(m_nameInPrevious.get(), m_attributesInPrevious), m_specificValueInPrevious);
+ m_previous->transitionTableRemove(make_pair(m_nameInPrevious.get(), m_attributesInPrevious), m_specificValueInPrevious);
}
-
- if (m_enumerationCache)
- m_enumerationCache->setCachedStructure(0);
+ ASSERT(!m_enumerationCache.hasDeadObject());
if (m_propertyTable) {
unsigned entryCount = m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount;
for (unsigned i = 1; i <= entryCount; i++) {
- if (UString::Rep* key = m_propertyTable->entries()[i].key)
+ if (StringImpl* key = m_propertyTable->entries()[i].key)
key->deref();
}
@@ -177,6 +278,9 @@ Structure::~Structure()
fastFree(m_propertyTable);
}
+ if (!m_isUsingSingleSlot)
+ delete transitionTable();
+
#ifndef NDEBUG
#if ENABLE(JSC_MULTIPLE_THREADS)
MutexLocker protect(ignoreSetMutex);
@@ -291,7 +395,7 @@ void Structure::growPropertyStorageCapacity()
void Structure::despecifyDictionaryFunction(const Identifier& propertyName)
{
- const UString::Rep* rep = propertyName._ustring.rep();
+ const StringImpl* rep = propertyName.impl();
materializePropertyMapIfNecessary();
@@ -340,7 +444,7 @@ PassRefPtr<Structure> Structure::addPropertyTransitionToExistingStructure(Struct
ASSERT(!structure->isDictionary());
ASSERT(structure->typeInfo().type() == ObjectType);
- if (Structure* existingTransition = structure->table.get(make_pair(propertyName.ustring().rep(), attributes), specificValue)) {
+ if (Structure* existingTransition = structure->transitionTableGet(make_pair(propertyName.impl(), attributes), specificValue)) {
ASSERT(existingTransition->m_offset != noOffset);
offset = existingTransition->m_offset + existingTransition->m_anonymousSlotCount;
ASSERT(offset >= structure->m_anonymousSlotCount);
@@ -375,7 +479,7 @@ PassRefPtr<Structure> Structure::addPropertyTransition(Structure* structure, con
transition->m_cachedPrototypeChain = structure->m_cachedPrototypeChain;
transition->m_previous = structure;
- transition->m_nameInPrevious = propertyName.ustring().rep();
+ transition->m_nameInPrevious = propertyName.impl();
transition->m_attributesInPrevious = attributes;
transition->m_specificValueInPrevious = specificValue;
transition->m_propertyStorageCapacity = structure->m_propertyStorageCapacity;
@@ -405,7 +509,7 @@ PassRefPtr<Structure> Structure::addPropertyTransition(Structure* structure, con
transition->m_offset = offset - structure->m_anonymousSlotCount;
ASSERT(structure->anonymousSlotCount() == transition->anonymousSlotCount());
- structure->table.add(make_pair(propertyName.ustring().rep(), attributes), transition.get(), specificValue);
+ structure->transitionTableAdd(make_pair(propertyName.impl(), attributes), transition.get(), specificValue);
return transition.release();
}
@@ -634,7 +738,7 @@ PropertyMapHashTable* Structure::copyPropertyTable()
unsigned entryCount = m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount;
for (unsigned i = 1; i <= entryCount; ++i) {
- if (UString::Rep* key = newTable->entries()[i].key)
+ if (StringImpl* key = newTable->entries()[i].key)
key->ref();
}
@@ -645,7 +749,7 @@ PropertyMapHashTable* Structure::copyPropertyTable()
return newTable;
}
-size_t Structure::get(const UString::Rep* rep, unsigned& attributes, JSCell*& specificValue)
+size_t Structure::get(const StringImpl* rep, unsigned& attributes, JSCell*& specificValue)
{
materializePropertyMapIfNecessary();
if (!m_propertyTable)
@@ -702,7 +806,7 @@ bool Structure::despecifyFunction(const Identifier& propertyName)
if (!m_propertyTable)
return false;
- UString::Rep* rep = propertyName._ustring.rep();
+ StringImpl* rep = propertyName.impl();
unsigned i = rep->existingHash();
@@ -766,7 +870,7 @@ size_t Structure::put(const Identifier& propertyName, unsigned attributes, JSCel
if (attributes & DontEnum)
m_hasNonEnumerableProperties = true;
- UString::Rep* rep = propertyName._ustring.rep();
+ StringImpl* rep = propertyName.impl();
if (!m_propertyTable)
createPropertyMapHashTable();
@@ -850,9 +954,9 @@ size_t Structure::put(const Identifier& propertyName, unsigned attributes, JSCel
return newOffset;
}
-bool Structure::hasTransition(UString::Rep* rep, unsigned attributes)
+bool Structure::hasTransition(StringImpl* rep, unsigned attributes)
{
- return table.hasTransition(make_pair(rep, attributes));
+ return transitionTableHasTransition(make_pair(rep, attributes));
}
size_t Structure::remove(const Identifier& propertyName)
@@ -861,7 +965,7 @@ size_t Structure::remove(const Identifier& propertyName)
checkConsistency();
- UString::Rep* rep = propertyName._ustring.rep();
+ StringImpl* rep = propertyName.impl();
if (!m_propertyTable)
return notFound;
@@ -875,7 +979,7 @@ size_t Structure::remove(const Identifier& propertyName)
unsigned i = rep->existingHash();
unsigned k = 0;
unsigned entryIndex;
- UString::Rep* key = 0;
+ StringImpl* key = 0;
while (1) {
entryIndex = m_propertyTable->entryIndices[i & m_propertyTable->sizeMask];
if (entryIndex == emptyEntryIndex)
@@ -1137,7 +1241,7 @@ void Structure::checkConsistency()
unsigned nonEmptyEntryCount = 0;
for (unsigned c = 1; c <= m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount; ++c) {
ASSERT(m_hasNonEnumerableProperties || !(m_propertyTable->entries()[c].attributes & DontEnum));
- UString::Rep* rep = m_propertyTable->entries()[c].key;
+ StringImpl* rep = m_propertyTable->entries()[c].key;
ASSERT(m_propertyTable->entries()[c].offset >= m_anonymousSlotCount);
if (!rep)
continue;