]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - runtime/Structure.cpp
JavaScriptCore-584.tar.gz
[apple/javascriptcore.git] / runtime / Structure.cpp
index 8133cd2e0c0c48f8e3586d682e3b0fdadd9f12ca..546e2bf6e8cfc35d43b7d3072f3a413cc224fc8f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 
 #include "Identifier.h"
 #include "JSObject.h"
+#include "JSPropertyNameIterator.h"
+#include "Lookup.h"
 #include "PropertyNameArray.h"
 #include "StructureChain.h"
-#include "Lookup.h"
 #include <wtf/RefCountedLeakCounter.h>
 #include <wtf/RefPtr.h>
 
@@ -65,17 +66,19 @@ static const unsigned newTableSize = 16;
 static WTF::RefCountedLeakCounter structureCounter("Structure");
 
 #if ENABLE(JSC_MULTIPLE_THREADS)
-static Mutex ignoreSetMutex;
+static Mutex& ignoreSetMutex = *(new Mutex);
 #endif
 
 static bool shouldIgnoreLeaks;
-static HashSet<Structure*> ignoreSet;
+static HashSet<Structure*>& ignoreSet = *(new HashSet<Structure*>);
 #endif
 
 #if DUMP_STRUCTURE_ID_STATISTICS
-static HashSet<Structure*> liveStructureSet;
+static HashSet<Structure*>& liveStructureSet = *(new HashSet<Structure*>);
 #endif
 
+static int comparePropertyMapEntryIndices(const void* a, const void* b);
+
 void Structure::dumpStatistics()
 {
 #if DUMP_STRUCTURE_ID_STATISTICS
@@ -120,23 +123,23 @@ void Structure::dumpStatistics()
 #endif
 }
 
-Structure::Structure(JSValuePtr prototype, const TypeInfo& typeInfo)
+Structure::Structure(JSValue prototype, const TypeInfo& typeInfo, unsigned anonymousSlotCount)
     : m_typeInfo(typeInfo)
     , m_prototype(prototype)
+    , m_specificValueInPrevious(0)
     , m_propertyTable(0)
     , m_propertyStorageCapacity(JSObject::inlineStorageCapacity)
     , m_offset(noOffset)
-    , m_isDictionary(false)
+    , m_dictionaryKind(NoneDictionaryKind)
     , m_isPinnedPropertyTable(false)
     , m_hasGetterSetterProperties(false)
-    , m_usingSingleTransitionSlot(true)
     , m_attributesInPrevious(0)
+    , m_specificFunctionThrashCount(0)
+    , m_anonymousSlotCount(anonymousSlotCount)
 {
     ASSERT(m_prototype);
     ASSERT(m_prototype.isObject() || m_prototype.isNull());
 
-    m_transitions.singleTransition = 0;
-
 #ifndef NDEBUG
 #if ENABLE(JSC_MULTIPLE_THREADS)
     MutexLocker protect(ignoreSetMutex);
@@ -155,19 +158,13 @@ Structure::Structure(JSValuePtr prototype, const TypeInfo& typeInfo)
 Structure::~Structure()
 {
     if (m_previous) {
-        if (m_previous->m_usingSingleTransitionSlot) {
-            m_previous->m_transitions.singleTransition = 0;
-        } else {
-            ASSERT(m_previous->m_transitions.table->contains(make_pair(m_nameInPrevious.get(), m_attributesInPrevious)));
-            m_previous->m_transitions.table->remove(make_pair(m_nameInPrevious.get(), m_attributesInPrevious));
-        }
-    }
-
-    if (m_cachedPropertyNameArrayData)
-        m_cachedPropertyNameArrayData->setCachedStructure(0);
+        ASSERT(m_nameInPrevious);
+        m_previous->table.remove(make_pair(m_nameInPrevious.get(), m_attributesInPrevious), m_specificValueInPrevious);
 
-    if (!m_usingSingleTransitionSlot)
-        delete m_transitions.table;
+    }
+    
+    if (m_enumerationCache)
+        m_enumerationCache->setCachedStructure(0);
 
     if (m_propertyTable) {
         unsigned entryCount = m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount;
@@ -279,97 +276,112 @@ void Structure::materializePropertyMap()
     for (ptrdiff_t i = structures.size() - 2; i >= 0; --i) {
         structure = structures[i];
         structure->m_nameInPrevious->ref();
-        PropertyMapEntry entry(structure->m_nameInPrevious.get(), structure->m_offset, structure->m_attributesInPrevious, ++m_propertyTable->lastIndexUsed); 
+        PropertyMapEntry entry(structure->m_nameInPrevious.get(), m_anonymousSlotCount + structure->m_offset, structure->m_attributesInPrevious, structure->m_specificValueInPrevious, ++m_propertyTable->lastIndexUsed);
         insertIntoPropertyMapHashTable(entry);
     }
 }
 
-void Structure::getEnumerablePropertyNames(ExecState* exec, PropertyNameArray& propertyNames, JSObject* baseObject)
+void Structure::growPropertyStorageCapacity()
 {
-    bool shouldCache = propertyNames.shouldCache() && !(propertyNames.size() || m_isDictionary);
+    if (m_propertyStorageCapacity == JSObject::inlineStorageCapacity)
+        m_propertyStorageCapacity = JSObject::nonInlineBaseStorageCapacity;
+    else
+        m_propertyStorageCapacity *= 2;
+}
 
-    if (shouldCache && m_cachedPropertyNameArrayData) {
-        if (m_cachedPropertyNameArrayData->cachedPrototypeChain() == prototypeChain(exec)) {
-            propertyNames.setData(m_cachedPropertyNameArrayData);
-            return;
-        }
-        clearEnumerationCache();
-    }
+void Structure::despecifyDictionaryFunction(const Identifier& propertyName)
+{
+    const UString::Rep* rep = propertyName._ustring.rep();
 
-    getEnumerableNamesFromPropertyTable(propertyNames);
-    getEnumerableNamesFromClassInfoTable(exec, baseObject->classInfo(), propertyNames);
+    materializePropertyMapIfNecessary();
 
-    if (m_prototype.isObject()) {
-        propertyNames.setShouldCache(false); // No need for our prototypes to waste memory on caching, since they're not being enumerated directly.
-        asObject(m_prototype)->getPropertyNames(exec, propertyNames);
-    }
+    ASSERT(isDictionary());
+    ASSERT(m_propertyTable);
+
+    unsigned i = rep->existingHash();
+
+#if DUMP_PROPERTYMAP_STATS
+    ++numProbes;
+#endif
 
-    if (shouldCache) {
-        m_cachedPropertyNameArrayData = propertyNames.data();
-        m_cachedPropertyNameArrayData->setCachedPrototypeChain(prototypeChain(exec));
-        m_cachedPropertyNameArrayData->setCachedStructure(this);
+    unsigned entryIndex = m_propertyTable->entryIndices[i & m_propertyTable->sizeMask];
+    ASSERT(entryIndex != emptyEntryIndex);
+
+    if (rep == m_propertyTable->entries()[entryIndex - 1].key) {
+        m_propertyTable->entries()[entryIndex - 1].specificValue = 0;
+        return;
     }
-}
 
-void Structure::clearEnumerationCache()
-{
-    if (m_cachedPropertyNameArrayData)
-        m_cachedPropertyNameArrayData->setCachedStructure(0);
-    m_cachedPropertyNameArrayData.clear();
-}
+#if DUMP_PROPERTYMAP_STATS
+    ++numCollisions;
+#endif
 
-void Structure::growPropertyStorageCapacity()
-{
-    if (m_propertyStorageCapacity == JSObject::inlineStorageCapacity)
-        m_propertyStorageCapacity = JSObject::nonInlineBaseStorageCapacity;
-    else
-        m_propertyStorageCapacity *= 2;
+    unsigned k = 1 | doubleHash(rep->existingHash());
+
+    while (1) {
+        i += k;
+
+#if DUMP_PROPERTYMAP_STATS
+        ++numRehashes;
+#endif
+
+        entryIndex = m_propertyTable->entryIndices[i & m_propertyTable->sizeMask];
+        ASSERT(entryIndex != emptyEntryIndex);
+
+        if (rep == m_propertyTable->entries()[entryIndex - 1].key) {
+            m_propertyTable->entries()[entryIndex - 1].specificValue = 0;
+            return;
+        }
+    }
 }
 
-PassRefPtr<Structure> Structure::addPropertyTransitionToExistingStructure(Structure* structure, const Identifier& propertyName, unsigned attributes, size_t& offset)
+PassRefPtr<Structure> Structure::addPropertyTransitionToExistingStructure(Structure* structure, const Identifier& propertyName, unsigned attributes, JSCell* specificValue, size_t& offset)
 {
-    ASSERT(!structure->m_isDictionary);
+    ASSERT(!structure->isDictionary());
     ASSERT(structure->typeInfo().type() == ObjectType);
 
-    if (structure->m_usingSingleTransitionSlot) {
-        Structure* existingTransition = structure->m_transitions.singleTransition;
-        if (existingTransition && existingTransition->m_nameInPrevious.get() == propertyName.ustring().rep() && existingTransition->m_attributesInPrevious == attributes) {
-            ASSERT(structure->m_transitions.singleTransition->m_offset != noOffset);
-            offset = structure->m_transitions.singleTransition->m_offset;
-            return existingTransition;
-        }
-    } else {
-        if (Structure* existingTransition = structure->m_transitions.table->get(make_pair(propertyName.ustring().rep(), attributes))) {
-            ASSERT(existingTransition->m_offset != noOffset);
-            offset = existingTransition->m_offset;
-            return existingTransition;
-        }
+    if (Structure* existingTransition = structure->table.get(make_pair(propertyName.ustring().rep(), attributes), specificValue)) {
+        ASSERT(existingTransition->m_offset != noOffset);
+        offset = existingTransition->m_offset + existingTransition->m_anonymousSlotCount;
+        ASSERT(offset >= structure->m_anonymousSlotCount);
+        ASSERT(structure->m_anonymousSlotCount == existingTransition->m_anonymousSlotCount);
+        return existingTransition;
     }
 
     return 0;
 }
 
-PassRefPtr<Structure> Structure::addPropertyTransition(Structure* structure, const Identifier& propertyName, unsigned attributes, size_t& offset)
+PassRefPtr<Structure> Structure::addPropertyTransition(Structure* structure, const Identifier& propertyName, unsigned attributes, JSCell* specificValue, size_t& offset)
 {
-    ASSERT(!structure->m_isDictionary);
+    ASSERT(!structure->isDictionary());
     ASSERT(structure->typeInfo().type() == ObjectType);
-    ASSERT(!Structure::addPropertyTransitionToExistingStructure(structure, propertyName, attributes, offset));
+    ASSERT(!Structure::addPropertyTransitionToExistingStructure(structure, propertyName, attributes, specificValue, offset));
+    
+    if (structure->m_specificFunctionThrashCount == maxSpecificFunctionThrashCount)
+        specificValue = 0;
 
     if (structure->transitionCount() > s_maxTransitionLength) {
-        RefPtr<Structure> transition = toDictionaryTransition(structure);
-        offset = transition->put(propertyName, attributes);
+        RefPtr<Structure> transition = toCacheableDictionaryTransition(structure);
+        ASSERT(structure != transition);
+        offset = transition->put(propertyName, attributes, specificValue);
+        ASSERT(offset >= structure->m_anonymousSlotCount);
+        ASSERT(structure->m_anonymousSlotCount == transition->m_anonymousSlotCount);
         if (transition->propertyStorageSize() > transition->propertyStorageCapacity())
             transition->growPropertyStorageCapacity();
         return transition.release();
     }
 
-    RefPtr<Structure> transition = create(structure->m_prototype, structure->typeInfo());
+    RefPtr<Structure> transition = create(structure->m_prototype, structure->typeInfo(), structure->anonymousSlotCount());
+
     transition->m_cachedPrototypeChain = structure->m_cachedPrototypeChain;
     transition->m_previous = structure;
     transition->m_nameInPrevious = propertyName.ustring().rep();
     transition->m_attributesInPrevious = attributes;
+    transition->m_specificValueInPrevious = specificValue;
     transition->m_propertyStorageCapacity = structure->m_propertyStorageCapacity;
     transition->m_hasGetterSetterProperties = structure->m_hasGetterSetterProperties;
+    transition->m_hasNonEnumerableProperties = structure->m_hasNonEnumerableProperties;
+    transition->m_specificFunctionThrashCount = structure->m_specificFunctionThrashCount;
 
     if (structure->m_propertyTable) {
         if (structure->m_isPinnedPropertyTable)
@@ -385,126 +397,195 @@ PassRefPtr<Structure> Structure::addPropertyTransition(Structure* structure, con
             transition->createPropertyMapHashTable();
     }
 
-    offset = transition->put(propertyName, attributes);
+    offset = transition->put(propertyName, attributes, specificValue);
+    ASSERT(offset >= structure->m_anonymousSlotCount);
+    ASSERT(structure->m_anonymousSlotCount == transition->m_anonymousSlotCount);
     if (transition->propertyStorageSize() > transition->propertyStorageCapacity())
         transition->growPropertyStorageCapacity();
 
-    transition->m_offset = offset;
-
-    if (structure->m_usingSingleTransitionSlot) {
-        if (!structure->m_transitions.singleTransition) {
-            structure->m_transitions.singleTransition = transition.get();
-            return transition.release();
-        }
-
-        Structure* existingTransition = structure->m_transitions.singleTransition;
-        structure->m_usingSingleTransitionSlot = false;
-        StructureTransitionTable* transitionTable = new StructureTransitionTable;
-        structure->m_transitions.table = transitionTable;
-        transitionTable->add(make_pair(existingTransition->m_nameInPrevious.get(), existingTransition->m_attributesInPrevious), existingTransition);
-    }
-    structure->m_transitions.table->add(make_pair(propertyName.ustring().rep(), attributes), transition.get());
+    transition->m_offset = offset - structure->m_anonymousSlotCount;
+    ASSERT(structure->anonymousSlotCount() == transition->anonymousSlotCount());
+    structure->table.add(make_pair(propertyName.ustring().rep(), attributes), transition.get(), specificValue);
     return transition.release();
 }
 
 PassRefPtr<Structure> Structure::removePropertyTransition(Structure* structure, const Identifier& propertyName, size_t& offset)
 {
-    ASSERT(!structure->m_isDictionary);
+    ASSERT(!structure->isUncacheableDictionary());
 
-    RefPtr<Structure> transition = toDictionaryTransition(structure);
+    RefPtr<Structure> transition = toUncacheableDictionaryTransition(structure);
 
     offset = transition->remove(propertyName);
+    ASSERT(offset >= structure->m_anonymousSlotCount);
+    ASSERT(structure->m_anonymousSlotCount == transition->m_anonymousSlotCount);
 
     return transition.release();
 }
 
-PassRefPtr<Structure> Structure::changePrototypeTransition(Structure* structure, JSValuePtr prototype)
+PassRefPtr<Structure> Structure::changePrototypeTransition(Structure* structure, JSValue prototype)
 {
-    RefPtr<Structure> transition = create(prototype, structure->typeInfo());
+    RefPtr<Structure> transition = create(prototype, structure->typeInfo(), structure->anonymousSlotCount());
 
     transition->m_propertyStorageCapacity = structure->m_propertyStorageCapacity;
     transition->m_hasGetterSetterProperties = structure->m_hasGetterSetterProperties;
+    transition->m_hasNonEnumerableProperties = structure->m_hasNonEnumerableProperties;
+    transition->m_specificFunctionThrashCount = structure->m_specificFunctionThrashCount;
 
     // Don't set m_offset, as one can not transition to this.
 
     structure->materializePropertyMapIfNecessary();
     transition->m_propertyTable = structure->copyPropertyTable();
     transition->m_isPinnedPropertyTable = true;
+    
+    ASSERT(structure->anonymousSlotCount() == transition->anonymousSlotCount());
+    return transition.release();
+}
+
+PassRefPtr<Structure> Structure::despecifyFunctionTransition(Structure* structure, const Identifier& replaceFunction)
+{
+    ASSERT(structure->m_specificFunctionThrashCount < maxSpecificFunctionThrashCount);
+    RefPtr<Structure> transition = create(structure->storedPrototype(), structure->typeInfo(), structure->anonymousSlotCount());
+
+    transition->m_propertyStorageCapacity = structure->m_propertyStorageCapacity;
+    transition->m_hasGetterSetterProperties = structure->m_hasGetterSetterProperties;
+    transition->m_hasNonEnumerableProperties = structure->m_hasNonEnumerableProperties;
+    transition->m_specificFunctionThrashCount = structure->m_specificFunctionThrashCount + 1;
 
+    // Don't set m_offset, as one can not transition to this.
+
+    structure->materializePropertyMapIfNecessary();
+    transition->m_propertyTable = structure->copyPropertyTable();
+    transition->m_isPinnedPropertyTable = true;
+
+    if (transition->m_specificFunctionThrashCount == maxSpecificFunctionThrashCount)
+        transition->despecifyAllFunctions();
+    else {
+        bool removed = transition->despecifyFunction(replaceFunction);
+        ASSERT_UNUSED(removed, removed);
+    }
+    
+    ASSERT(structure->anonymousSlotCount() == transition->anonymousSlotCount());
     return transition.release();
 }
 
 PassRefPtr<Structure> Structure::getterSetterTransition(Structure* structure)
 {
-    RefPtr<Structure> transition = create(structure->storedPrototype(), structure->typeInfo());
+    RefPtr<Structure> transition = create(structure->storedPrototype(), structure->typeInfo(), structure->anonymousSlotCount());
     transition->m_propertyStorageCapacity = structure->m_propertyStorageCapacity;
     transition->m_hasGetterSetterProperties = transition->m_hasGetterSetterProperties;
+    transition->m_hasNonEnumerableProperties = structure->m_hasNonEnumerableProperties;
+    transition->m_specificFunctionThrashCount = structure->m_specificFunctionThrashCount;
 
     // Don't set m_offset, as one can not transition to this.
 
     structure->materializePropertyMapIfNecessary();
     transition->m_propertyTable = structure->copyPropertyTable();
     transition->m_isPinnedPropertyTable = true;
-
+    
+    ASSERT(structure->anonymousSlotCount() == transition->anonymousSlotCount());
     return transition.release();
 }
 
-PassRefPtr<Structure> Structure::toDictionaryTransition(Structure* structure)
+PassRefPtr<Structure> Structure::toDictionaryTransition(Structure* structure, DictionaryKind kind)
 {
-    ASSERT(!structure->m_isDictionary);
-
-    RefPtr<Structure> transition = create(structure->m_prototype, structure->typeInfo());
-    transition->m_isDictionary = true;
+    ASSERT(!structure->isUncacheableDictionary());
+    
+    RefPtr<Structure> transition = create(structure->m_prototype, structure->typeInfo(), structure->anonymousSlotCount());
+    transition->m_dictionaryKind = kind;
     transition->m_propertyStorageCapacity = structure->m_propertyStorageCapacity;
     transition->m_hasGetterSetterProperties = structure->m_hasGetterSetterProperties;
-
+    transition->m_hasNonEnumerableProperties = structure->m_hasNonEnumerableProperties;
+    transition->m_specificFunctionThrashCount = structure->m_specificFunctionThrashCount;
+    
     structure->materializePropertyMapIfNecessary();
     transition->m_propertyTable = structure->copyPropertyTable();
     transition->m_isPinnedPropertyTable = true;
-
+    
+    ASSERT(structure->anonymousSlotCount() == transition->anonymousSlotCount());
     return transition.release();
 }
 
-PassRefPtr<Structure> Structure::fromDictionaryTransition(Structure* structure)
+PassRefPtr<Structure> Structure::toCacheableDictionaryTransition(Structure* structure)
 {
-    ASSERT(structure->m_isDictionary);
+    return toDictionaryTransition(structure, CachedDictionaryKind);
+}
 
-    // Since dictionary Structures are not shared, and no opcodes specialize
-    // for them, we don't need to allocate a new Structure when transitioning
-    // to non-dictionary status.
+PassRefPtr<Structure> Structure::toUncacheableDictionaryTransition(Structure* structure)
+{
+    return toDictionaryTransition(structure, UncachedDictionaryKind);
+}
 
-    // FIMXE: We can make this more efficient by canonicalizing the Structure (draining the
-    // deleted offsets vector) before transitioning from dictionary. 
-    if (!structure->m_propertyTable || !structure->m_propertyTable->deletedOffsets || structure->m_propertyTable->deletedOffsets->isEmpty())
-        structure->m_isDictionary = false;
+PassRefPtr<Structure> Structure::flattenDictionaryStructure(JSObject* object)
+{
+    ASSERT(isDictionary());
+    if (isUncacheableDictionary()) {
+        ASSERT(m_propertyTable);
+        Vector<PropertyMapEntry*> sortedPropertyEntries(m_propertyTable->keyCount);
+        PropertyMapEntry** p = sortedPropertyEntries.data();
+        unsigned entryCount = m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount;
+        for (unsigned i = 1; i <= entryCount; i++) {
+            if (m_propertyTable->entries()[i].key)
+                *p++ = &m_propertyTable->entries()[i];
+        }
+        size_t propertyCount = p - sortedPropertyEntries.data();
+        qsort(sortedPropertyEntries.data(), propertyCount, sizeof(PropertyMapEntry*), comparePropertyMapEntryIndices);
+        sortedPropertyEntries.resize(propertyCount);
+
+        // We now have the properties currently defined on this object
+        // in the order that they are expected to be in, but we need to
+        // reorder the storage, so we have to copy the current values out
+        Vector<JSValue> values(propertyCount);
+        unsigned anonymousSlotCount = m_anonymousSlotCount;
+        for (unsigned i = 0; i < propertyCount; i++) {
+            PropertyMapEntry* entry = sortedPropertyEntries[i];
+            values[i] = object->getDirectOffset(entry->offset);
+            // Update property table to have the new property offsets
+            entry->offset = anonymousSlotCount + i;
+            entry->index = i;
+        }
+        
+        // Copy the original property values into their final locations
+        for (unsigned i = 0; i < propertyCount; i++)
+            object->putDirectOffset(anonymousSlotCount + i, values[i]);
+
+        if (m_propertyTable->deletedOffsets) {
+            delete m_propertyTable->deletedOffsets;
+            m_propertyTable->deletedOffsets = 0;
+        }
+    }
 
-    return structure;
+    m_dictionaryKind = NoneDictionaryKind;
+    return this;
 }
 
-size_t Structure::addPropertyWithoutTransition(const Identifier& propertyName, unsigned attributes)
+size_t Structure::addPropertyWithoutTransition(const Identifier& propertyName, unsigned attributes, JSCell* specificValue)
 {
-    ASSERT(!m_transitions.singleTransition);
+    ASSERT(!m_enumerationCache);
+
+    if (m_specificFunctionThrashCount == maxSpecificFunctionThrashCount)
+        specificValue = 0;
 
     materializePropertyMapIfNecessary();
 
     m_isPinnedPropertyTable = true;
-    size_t offset = put(propertyName, attributes);
+
+    size_t offset = put(propertyName, attributes, specificValue);
+    ASSERT(offset >= m_anonymousSlotCount);
     if (propertyStorageSize() > propertyStorageCapacity())
         growPropertyStorageCapacity();
-    clearEnumerationCache();
     return offset;
 }
 
 size_t Structure::removePropertyWithoutTransition(const Identifier& propertyName)
 {
-    ASSERT(!m_transitions.singleTransition);
-    ASSERT(m_isDictionary);
+    ASSERT(isUncacheableDictionary());
+    ASSERT(!m_enumerationCache);
 
     materializePropertyMapIfNecessary();
 
     m_isPinnedPropertyTable = true;
     size_t offset = remove(propertyName);
-    clearEnumerationCache();
+    ASSERT(offset >= m_anonymousSlotCount);
     return offset;
 }
 
@@ -564,17 +645,13 @@ PropertyMapHashTable* Structure::copyPropertyTable()
     return newTable;
 }
 
-size_t Structure::get(const Identifier& propertyName, unsigned& attributes)
+size_t Structure::get(const UString::Rep* rep, unsigned& attributes, JSCell*& specificValue)
 {
-    ASSERT(!propertyName.isNull());
-
     materializePropertyMapIfNecessary();
     if (!m_propertyTable)
         return notFound;
 
-    UString::Rep* rep = propertyName._ustring.rep();
-
-    unsigned i = rep->computedHash();
+    unsigned i = rep->existingHash();
 
 #if DUMP_PROPERTYMAP_STATS
     ++numProbes;
@@ -586,6 +663,8 @@ size_t Structure::get(const Identifier& propertyName, unsigned& attributes)
 
     if (rep == m_propertyTable->entries()[entryIndex - 1].key) {
         attributes = m_propertyTable->entries()[entryIndex - 1].attributes;
+        specificValue = m_propertyTable->entries()[entryIndex - 1].specificValue;
+        ASSERT(m_propertyTable->entries()[entryIndex - 1].offset >= m_anonymousSlotCount);
         return m_propertyTable->entries()[entryIndex - 1].offset;
     }
 
@@ -593,7 +672,7 @@ size_t Structure::get(const Identifier& propertyName, unsigned& attributes)
     ++numCollisions;
 #endif
 
-    unsigned k = 1 | doubleHash(rep->computedHash());
+    unsigned k = 1 | doubleHash(rep->existingHash());
 
     while (1) {
         i += k;
@@ -608,18 +687,85 @@ size_t Structure::get(const Identifier& propertyName, unsigned& attributes)
 
         if (rep == m_propertyTable->entries()[entryIndex - 1].key) {
             attributes = m_propertyTable->entries()[entryIndex - 1].attributes;
+            specificValue = m_propertyTable->entries()[entryIndex - 1].specificValue;
+            ASSERT(m_propertyTable->entries()[entryIndex - 1].offset >= m_anonymousSlotCount);
             return m_propertyTable->entries()[entryIndex - 1].offset;
         }
     }
 }
 
-size_t Structure::put(const Identifier& propertyName, unsigned attributes)
+bool Structure::despecifyFunction(const Identifier& propertyName)
+{
+    ASSERT(!propertyName.isNull());
+
+    materializePropertyMapIfNecessary();
+    if (!m_propertyTable)
+        return false;
+
+    UString::Rep* rep = propertyName._ustring.rep();
+
+    unsigned i = rep->existingHash();
+
+#if DUMP_PROPERTYMAP_STATS
+    ++numProbes;
+#endif
+
+    unsigned entryIndex = m_propertyTable->entryIndices[i & m_propertyTable->sizeMask];
+    if (entryIndex == emptyEntryIndex)
+        return false;
+
+    if (rep == m_propertyTable->entries()[entryIndex - 1].key) {
+        ASSERT(m_propertyTable->entries()[entryIndex - 1].specificValue);
+        m_propertyTable->entries()[entryIndex - 1].specificValue = 0;
+        return true;
+    }
+
+#if DUMP_PROPERTYMAP_STATS
+    ++numCollisions;
+#endif
+
+    unsigned k = 1 | doubleHash(rep->existingHash());
+
+    while (1) {
+        i += k;
+
+#if DUMP_PROPERTYMAP_STATS
+        ++numRehashes;
+#endif
+
+        entryIndex = m_propertyTable->entryIndices[i & m_propertyTable->sizeMask];
+        if (entryIndex == emptyEntryIndex)
+            return false;
+
+        if (rep == m_propertyTable->entries()[entryIndex - 1].key) {
+            ASSERT(m_propertyTable->entries()[entryIndex - 1].specificValue);
+            m_propertyTable->entries()[entryIndex - 1].specificValue = 0;
+            return true;
+        }
+    }
+}
+
+void Structure::despecifyAllFunctions()
+{
+    materializePropertyMapIfNecessary();
+    if (!m_propertyTable)
+        return;
+    
+    unsigned entryCount = m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount;
+    for (unsigned i = 1; i <= entryCount; ++i)
+        m_propertyTable->entries()[i].specificValue = 0;
+}
+
+size_t Structure::put(const Identifier& propertyName, unsigned attributes, JSCell* specificValue)
 {
     ASSERT(!propertyName.isNull());
     ASSERT(get(propertyName) == notFound);
 
     checkConsistency();
 
+    if (attributes & DontEnum)
+        m_hasNonEnumerableProperties = true;
+
     UString::Rep* rep = propertyName._ustring.rep();
 
     if (!m_propertyTable)
@@ -627,7 +773,7 @@ size_t Structure::put(const Identifier& propertyName, unsigned attributes)
 
     // FIXME: Consider a fast case for tables with no deleted sentinels.
 
-    unsigned i = rep->computedHash();
+    unsigned i = rep->existingHash();
     unsigned k = 0;
     bool foundDeletedElement = false;
     unsigned deletedElementIndex = 0; // initialize to make the compiler happy
@@ -650,7 +796,7 @@ size_t Structure::put(const Identifier& propertyName, unsigned attributes)
         }
 
         if (k == 0) {
-            k = 1 | doubleHash(rep->computedHash());
+            k = 1 | doubleHash(rep->existingHash());
 #if DUMP_PROPERTYMAP_STATS
             ++numCollisions;
 #endif
@@ -683,6 +829,7 @@ size_t Structure::put(const Identifier& propertyName, unsigned attributes)
     rep->ref();
     m_propertyTable->entries()[entryIndex - 1].key = rep;
     m_propertyTable->entries()[entryIndex - 1].attributes = attributes;
+    m_propertyTable->entries()[entryIndex - 1].specificValue = specificValue;
     m_propertyTable->entries()[entryIndex - 1].index = ++m_propertyTable->lastIndexUsed;
 
     unsigned newOffset;
@@ -690,9 +837,10 @@ size_t Structure::put(const Identifier& propertyName, unsigned attributes)
         newOffset = m_propertyTable->deletedOffsets->last();
         m_propertyTable->deletedOffsets->removeLast();
     } else
-        newOffset = m_propertyTable->keyCount;
+        newOffset = m_propertyTable->keyCount + m_anonymousSlotCount;
     m_propertyTable->entries()[entryIndex - 1].offset = newOffset;
-
+    
+    ASSERT(newOffset >= m_anonymousSlotCount);
     ++m_propertyTable->keyCount;
 
     if ((m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount) * 2 >= m_propertyTable->size)
@@ -702,6 +850,11 @@ size_t Structure::put(const Identifier& propertyName, unsigned attributes)
     return newOffset;
 }
 
+bool Structure::hasTransition(UString::Rep* rep, unsigned attributes)
+{
+    return table.hasTransition(make_pair(rep, attributes));
+}
+
 size_t Structure::remove(const Identifier& propertyName)
 {
     ASSERT(!propertyName.isNull());
@@ -719,7 +872,7 @@ size_t Structure::remove(const Identifier& propertyName)
 #endif
 
     // Find the thing to remove.
-    unsigned i = rep->computedHash();
+    unsigned i = rep->existingHash();
     unsigned k = 0;
     unsigned entryIndex;
     UString::Rep* key = 0;
@@ -733,7 +886,7 @@ size_t Structure::remove(const Identifier& propertyName)
             break;
 
         if (k == 0) {
-            k = 1 | doubleHash(rep->computedHash());
+            k = 1 | doubleHash(rep->existingHash());
 #if DUMP_PROPERTYMAP_STATS
             ++numCollisions;
 #endif
@@ -751,10 +904,12 @@ size_t Structure::remove(const Identifier& propertyName)
     m_propertyTable->entryIndices[i & m_propertyTable->sizeMask] = deletedSentinelIndex;
 
     size_t offset = m_propertyTable->entries()[entryIndex - 1].offset;
+    ASSERT(offset >= m_anonymousSlotCount);
 
     key->deref();
     m_propertyTable->entries()[entryIndex - 1].key = 0;
     m_propertyTable->entries()[entryIndex - 1].attributes = 0;
+    m_propertyTable->entries()[entryIndex - 1].specificValue = 0;
     m_propertyTable->entries()[entryIndex - 1].offset = 0;
 
     if (!m_propertyTable->deletedOffsets)
@@ -775,8 +930,8 @@ size_t Structure::remove(const Identifier& propertyName)
 void Structure::insertIntoPropertyMapHashTable(const PropertyMapEntry& entry)
 {
     ASSERT(m_propertyTable);
-
-    unsigned i = entry.key->computedHash();
+    ASSERT(entry.offset >= m_anonymousSlotCount);
+    unsigned i = entry.key->existingHash();
     unsigned k = 0;
 
 #if DUMP_PROPERTYMAP_STATS
@@ -789,7 +944,7 @@ void Structure::insertIntoPropertyMapHashTable(const PropertyMapEntry& entry)
             break;
 
         if (k == 0) {
-            k = 1 | doubleHash(entry.key->computedHash());
+            k = 1 | doubleHash(entry.key->existingHash());
 #if DUMP_PROPERTYMAP_STATS
             ++numCollisions;
 #endif
@@ -871,7 +1026,7 @@ void Structure::rehashPropertyMapHashTable(unsigned newTableSize)
     checkConsistency();
 }
 
-static int comparePropertyMapEntryIndices(const void* a, const void* b)
+int comparePropertyMapEntryIndices(const void* a, const void* b)
 {
     unsigned ia = static_cast<PropertyMapEntry* const*>(a)[0]->index;
     unsigned ib = static_cast<PropertyMapEntry* const*>(b)[0]->index;
@@ -882,7 +1037,7 @@ static int comparePropertyMapEntryIndices(const void* a, const void* b)
     return 0;
 }
 
-void Structure::getEnumerableNamesFromPropertyTable(PropertyNameArray& propertyNames)
+void Structure::getPropertyNames(PropertyNameArray& propertyNames, EnumerationMode mode)
 {
     materializePropertyMapIfNecessary();
     if (!m_propertyTable)
@@ -893,7 +1048,8 @@ void Structure::getEnumerableNamesFromPropertyTable(PropertyNameArray& propertyN
         int i = 0;
         unsigned entryCount = m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount;
         for (unsigned k = 1; k <= entryCount; k++) {
-            if (m_propertyTable->entries()[k].key && !(m_propertyTable->entries()[k].attributes & DontEnum)) {
+            ASSERT(m_hasNonEnumerableProperties || !(m_propertyTable->entries()[k].attributes & DontEnum));
+            if (m_propertyTable->entries()[k].key && (!(m_propertyTable->entries()[k].attributes & DontEnum) || (mode == IncludeDontEnumProperties))) {
                 PropertyMapEntry* value = &m_propertyTable->entries()[k];
                 int j;
                 for (j = i - 1; j >= 0 && a[j]->index > value->index; --j)
@@ -920,7 +1076,7 @@ void Structure::getEnumerableNamesFromPropertyTable(PropertyNameArray& propertyN
     PropertyMapEntry** p = sortedEnumerables.data();
     unsigned entryCount = m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount;
     for (unsigned i = 1; i <= entryCount; i++) {
-        if (m_propertyTable->entries()[i].key && !(m_propertyTable->entries()[i].attributes & DontEnum))
+        if (m_propertyTable->entries()[i].key && (!(m_propertyTable->entries()[i].attributes & DontEnum) || (mode == IncludeDontEnumProperties)))
             *p++ = &m_propertyTable->entries()[i];
     }
 
@@ -939,28 +1095,6 @@ void Structure::getEnumerableNamesFromPropertyTable(PropertyNameArray& propertyN
     }
 }
 
-void Structure::getEnumerableNamesFromClassInfoTable(ExecState* exec, const ClassInfo* classInfo, PropertyNameArray& propertyNames)
-{
-    // Add properties from the static hashtables of properties
-    for (; classInfo; classInfo = classInfo->parentClass) {
-        const HashTable* table = classInfo->propHashTable(exec);
-        if (!table)
-            continue;
-        table->initializeIfNeeded(exec);
-        ASSERT(table->table);
-#if ENABLE(PERFECT_HASH_SIZE)
-        int hashSizeMask = table->hashSizeMask;
-#else
-        int hashSizeMask = table->compactSize - 1;
-#endif
-        const HashEntry* entry = table->table;
-        for (int i = 0; i <= hashSizeMask; ++i, ++entry) {
-            if (entry->key() && !(entry->attributes() & DontEnum))
-                propertyNames.add(entry->key());
-        }
-    }
-}
-
 #if DO_PROPERTYMAP_CONSTENCY_CHECK
 
 void Structure::checkConsistency()
@@ -1002,11 +1136,13 @@ 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;
+        ASSERT(m_propertyTable->entries()[c].offset >= m_anonymousSlotCount);
         if (!rep)
             continue;
         ++nonEmptyEntryCount;
-        unsigned i = rep->computedHash();
+        unsigned i = rep->existingHash();
         unsigned k = 0;
         unsigned entryIndex;
         while (1) {
@@ -1015,7 +1151,7 @@ void Structure::checkConsistency()
             if (rep == m_propertyTable->entries()[entryIndex - 1].key)
                 break;
             if (k == 0)
-                k = 1 | doubleHash(rep->computedHash());
+                k = 1 | doubleHash(rep->existingHash());
             i += k;
         }
         ASSERT(entryIndex == c + 1);