]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - runtime/Structure.cpp
JavaScriptCore-1097.3.tar.gz
[apple/javascriptcore.git] / runtime / Structure.cpp
index a3fda547fddb7f850929b2a1229fe6071b3637d0..074c8b3544f7bc0f92d210eb31e0676918eea2ff 100644 (file)
 #include "StructureChain.h"
 #include <wtf/RefCountedLeakCounter.h>
 #include <wtf/RefPtr.h>
-
-#if ENABLE(JSC_MULTIPLE_THREADS)
 #include <wtf/Threading.h>
-#endif
 
 #define DUMP_STRUCTURE_ID_STATISTICS 0
 
@@ -83,29 +80,6 @@ inline Structure* StructureTransitionTable::get(StringImpl* rep, unsigned attrib
     return map()->get(make_pair(rep, attributes));
 }
 
-inline void StructureTransitionTable::remove(Structure* structure)
-{
-    if (isUsingSingleSlot()) {
-        // If more than one transition had been added, then we wouldn't be in
-        // single slot mode (even despecifying a from a specific value triggers
-        // map mode).
-        // As such, the passed structure *must* be the existing transition.
-        ASSERT(singleTransition() == structure);
-        clearSingleTransition();
-    } else {
-        // Check whether a mapping exists for structure's key, and whether the
-        // entry is structure (the latter check may fail if we initially had a
-        // transition with a specific value, and this has been despecified).
-
-        // Newer versions of the STL have an std::make_pair function that takes rvalue references.
-        // When either of the parameters are bitfields, the C++ compiler will try to bind them as lvalues, which is invalid. To work around this, use unary "+" to make the parameter an rvalue.
-        // See https://bugs.webkit.org/show_bug.cgi?id=59261 for more details
-        TransitionMap::iterator entry = map()->find(make_pair(structure->m_nameInPrevious, +structure->m_attributesInPrevious));
-        if (entry != map()->end() && structure == entry.get().second)
-            map()->remove(entry);
-    }
-}
-
 inline void StructureTransitionTable::add(JSGlobalData& globalData, Structure* structure)
 {
     if (isUsingSingleSlot()) {
@@ -128,12 +102,12 @@ inline void StructureTransitionTable::add(JSGlobalData& globalData, Structure* s
     // Newer versions of the STL have an std::make_pair function that takes rvalue references.
     // When either of the parameters are bitfields, the C++ compiler will try to bind them as lvalues, which is invalid. To work around this, use unary "+" to make the parameter an rvalue.
     // See https://bugs.webkit.org/show_bug.cgi?id=59261 for more details
-    std::pair<TransitionMap::iterator, bool> result = map()->add(globalData, make_pair(structure->m_nameInPrevious, +structure->m_attributesInPrevious), structure);
-    if (!result.second) {
+    TransitionMap::AddResult result = map()->add(globalData, make_pair(structure->m_nameInPrevious, +structure->m_attributesInPrevious), structure);
+    if (!result.isNewEntry) {
         // There already is an entry! - we should only hit this when despecifying.
-        ASSERT(result.first.get().second->m_specificValueInPrevious);
+        ASSERT(result.iterator.get().second->m_specificValueInPrevious);
         ASSERT(!structure->m_specificValueInPrevious);
-        map()->set(result.first, structure);
+        map()->set(globalData, result.iterator.get().first, structure);
     }
 }
 
@@ -168,45 +142,45 @@ void Structure::dumpStatistics()
         }
     }
 
-    printf("Number of live Structures: %d\n", liveStructureSet.size());
-    printf("Number of Structures using the single item optimization for transition map: %d\n", numberUsingSingleSlot);
-    printf("Number of Structures that are leaf nodes: %d\n", numberLeaf);
-    printf("Number of Structures that singletons: %d\n", numberSingletons);
-    printf("Number of Structures with PropertyMaps: %d\n", numberWithPropertyMaps);
+    dataLog("Number of live Structures: %d\n", liveStructureSet.size());
+    dataLog("Number of Structures using the single item optimization for transition map: %d\n", numberUsingSingleSlot);
+    dataLog("Number of Structures that are leaf nodes: %d\n", numberLeaf);
+    dataLog("Number of Structures that singletons: %d\n", numberSingletons);
+    dataLog("Number of Structures with PropertyMaps: %d\n", numberWithPropertyMaps);
 
-    printf("Size of a single Structures: %d\n", static_cast<unsigned>(sizeof(Structure)));
-    printf("Size of sum of all property maps: %d\n", totalPropertyMapsSize);
-    printf("Size of average of all property maps: %f\n", static_cast<double>(totalPropertyMapsSize) / static_cast<double>(liveStructureSet.size()));
+    dataLog("Size of a single Structures: %d\n", static_cast<unsigned>(sizeof(Structure)));
+    dataLog("Size of sum of all property maps: %d\n", totalPropertyMapsSize);
+    dataLog("Size of average of all property maps: %f\n", static_cast<double>(totalPropertyMapsSize) / static_cast<double>(liveStructureSet.size()));
 #else
-    printf("Dumping Structure statistics is not enabled.\n");
+    dataLog("Dumping Structure statistics is not enabled.\n");
 #endif
 }
 
-Structure::Structure(JSGlobalData& globalData, JSValue prototype, const TypeInfo& typeInfo, unsigned anonymousSlotCount, const ClassInfo* classInfo)
+Structure::Structure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype, const TypeInfo& typeInfo, const ClassInfo* classInfo)
     : JSCell(globalData, globalData.structureStructure.get())
     , m_typeInfo(typeInfo)
+    , m_globalObject(globalData, this, globalObject, WriteBarrier<JSGlobalObject>::MayBeNull)
     , m_prototype(globalData, this, prototype)
     , m_classInfo(classInfo)
-    , m_propertyStorageCapacity(typeInfo.isFinal() ? JSFinalObject_inlineStorageCapacity : JSNonFinalObject_inlineStorageCapacity)
+    , m_propertyStorageCapacity(typeInfo.isFinalObject() ? JSFinalObject_inlineStorageCapacity : JSNonFinalObject_inlineStorageCapacity)
     , m_offset(noOffset)
     , m_dictionaryKind(NoneDictionaryKind)
     , m_isPinnedPropertyTable(false)
     , m_hasGetterSetterProperties(false)
+    , m_hasReadOnlyOrGetterSetterPropertiesExcludingProto(false)
     , m_hasNonEnumerableProperties(false)
     , m_attributesInPrevious(0)
     , m_specificFunctionThrashCount(0)
-    , m_anonymousSlotCount(anonymousSlotCount)
     , m_preventExtensions(false)
     , m_didTransition(false)
+    , m_staticFunctionReified(false)
 {
-    ASSERT(m_prototype);
-    ASSERT(m_prototype.isObject() || m_prototype.isNull());
 }
 
-const ClassInfo Structure::s_info = { "Structure", 0, 0, 0 };
+const ClassInfo Structure::s_info = { "Structure", 0, 0, 0, CREATE_METHOD_TABLE(Structure) };
 
 Structure::Structure(JSGlobalData& globalData)
-    : JSCell(globalData, this, CreatingEarlyCell)
+    : JSCell(CreatingEarlyCell)
     , m_typeInfo(CompoundType, OverridesVisitChildren)
     , m_prototype(globalData, this, jsNull())
     , m_classInfo(&s_info)
@@ -215,16 +189,14 @@ Structure::Structure(JSGlobalData& globalData)
     , m_dictionaryKind(NoneDictionaryKind)
     , m_isPinnedPropertyTable(false)
     , m_hasGetterSetterProperties(false)
+    , m_hasReadOnlyOrGetterSetterPropertiesExcludingProto(false)
     , m_hasNonEnumerableProperties(false)
     , m_attributesInPrevious(0)
     , m_specificFunctionThrashCount(0)
-    , m_anonymousSlotCount(0)
     , m_preventExtensions(false)
     , m_didTransition(false)
+    , m_staticFunctionReified(false)
 {
-    ASSERT(m_prototype);
-    ASSERT(m_prototype.isNull());
-    ASSERT(!globalData.structureStructure);
 }
 
 Structure::Structure(JSGlobalData& globalData, const Structure* previous)
@@ -234,22 +206,24 @@ Structure::Structure(JSGlobalData& globalData, const Structure* previous)
     , m_classInfo(previous->m_classInfo)
     , m_propertyStorageCapacity(previous->m_propertyStorageCapacity)
     , m_offset(noOffset)
-    , m_dictionaryKind(NoneDictionaryKind)
+    , m_dictionaryKind(previous->m_dictionaryKind)
     , m_isPinnedPropertyTable(false)
     , m_hasGetterSetterProperties(previous->m_hasGetterSetterProperties)
+    , m_hasReadOnlyOrGetterSetterPropertiesExcludingProto(previous->m_hasReadOnlyOrGetterSetterPropertiesExcludingProto)
     , m_hasNonEnumerableProperties(previous->m_hasNonEnumerableProperties)
     , m_attributesInPrevious(0)
     , m_specificFunctionThrashCount(previous->m_specificFunctionThrashCount)
-    , m_anonymousSlotCount(previous->anonymousSlotCount())
     , m_preventExtensions(previous->m_preventExtensions)
     , m_didTransition(true)
+    , m_staticFunctionReified(previous->m_staticFunctionReified)
 {
-    ASSERT(m_prototype);
-    ASSERT(m_prototype.isObject() || m_prototype.isNull());
+    if (previous->m_globalObject)
+        m_globalObject.set(globalData, this, previous->m_globalObject.get());
 }
 
-Structure::~Structure()
+void Structure::destroy(JSCell* cell)
 {
+    jsCast<Structure*>(cell)->Structure::~Structure();
 }
 
 void Structure::materializePropertyMap(JSGlobalData& globalData)
@@ -280,7 +254,7 @@ void Structure::materializePropertyMap(JSGlobalData& globalData)
 
     for (ptrdiff_t i = structures.size() - 2; i >= 0; --i) {
         structure = structures[i];
-        PropertyMapEntry entry(globalData, this, structure->m_nameInPrevious.get(), m_anonymousSlotCount + structure->m_offset, structure->m_attributesInPrevious, structure->m_specificValueInPrevious.get());
+        PropertyMapEntry entry(globalData, this, structure->m_nameInPrevious.get(), structure->m_offset, structure->m_attributesInPrevious, structure->m_specificValueInPrevious.get());
         m_propertyTable->add(entry);
     }
 }
@@ -293,6 +267,13 @@ void Structure::growPropertyStorageCapacity()
         m_propertyStorageCapacity *= 2;
 }
 
+size_t Structure::suggestedNewPropertyStorageSize()
+{
+    if (isUsingInlineStorage())
+        return JSObject::baseExternalStorageCapacity;
+    return m_propertyStorageCapacity * 2;
+}
+
 void Structure::despecifyDictionaryFunction(JSGlobalData& globalData, const Identifier& propertyName)
 {
     StringImpl* rep = propertyName.impl();
@@ -310,16 +291,14 @@ void Structure::despecifyDictionaryFunction(JSGlobalData& globalData, const Iden
 Structure* Structure::addPropertyTransitionToExistingStructure(Structure* structure, const Identifier& propertyName, unsigned attributes, JSCell* specificValue, size_t& offset)
 {
     ASSERT(!structure->isDictionary());
-    ASSERT(structure->typeInfo().type() == ObjectType);
+    ASSERT(structure->isObject());
 
     if (Structure* existingTransition = structure->m_transitionTable.get(propertyName.impl(), attributes)) {
         JSCell* specificValueInPrevious = existingTransition->m_specificValueInPrevious.get();
         if (specificValueInPrevious && specificValueInPrevious != specificValue)
             return 0;
         ASSERT(existingTransition->m_offset != noOffset);
-        offset = existingTransition->m_offset + existingTransition->m_anonymousSlotCount;
-        ASSERT(offset >= structure->m_anonymousSlotCount);
-        ASSERT(structure->m_anonymousSlotCount == existingTransition->m_anonymousSlotCount);
+        offset = existingTransition->m_offset;
         return existingTransition;
     }
 
@@ -339,7 +318,7 @@ Structure* Structure::addPropertyTransition(JSGlobalData& globalData, Structure*
         specificValue = 0;
 
     ASSERT(!structure->isDictionary());
-    ASSERT(structure->typeInfo().type() == ObjectType);
+    ASSERT(structure->isObject());
     ASSERT(!Structure::addPropertyTransitionToExistingStructure(structure, propertyName, attributes, specificValue, offset));
     
     if (structure->m_specificFunctionThrashCount == maxSpecificFunctionThrashCount)
@@ -349,13 +328,11 @@ Structure* Structure::addPropertyTransition(JSGlobalData& globalData, Structure*
         Structure* transition = toCacheableDictionaryTransition(globalData, structure);
         ASSERT(structure != transition);
         offset = transition->putSpecificValue(globalData, propertyName, attributes, specificValue);
-        ASSERT(offset >= structure->m_anonymousSlotCount);
-        ASSERT(structure->m_anonymousSlotCount == transition->m_anonymousSlotCount);
         if (transition->propertyStorageSize() > transition->propertyStorageCapacity())
             transition->growPropertyStorageCapacity();
         return transition;
     }
-
+    
     Structure* transition = create(globalData, structure);
 
     transition->m_cachedPrototypeChain.setMayBeNull(globalData, transition, structure->m_cachedPrototypeChain.get());
@@ -366,7 +343,7 @@ Structure* Structure::addPropertyTransition(JSGlobalData& globalData, Structure*
 
     if (structure->m_propertyTable) {
         if (structure->m_isPinnedPropertyTable)
-            transition->m_propertyTable = structure->m_propertyTable->copy(globalData, 0, structure->m_propertyTable->size() + 1);
+            transition->m_propertyTable = structure->m_propertyTable->copy(globalData, transition, structure->m_propertyTable->size() + 1);
         else
             transition->m_propertyTable = structure->m_propertyTable.release();
     } else {
@@ -377,13 +354,10 @@ Structure* Structure::addPropertyTransition(JSGlobalData& globalData, Structure*
     }
 
     offset = transition->putSpecificValue(globalData, 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 - structure->m_anonymousSlotCount;
-    ASSERT(structure->anonymousSlotCount() == transition->anonymousSlotCount());
+    transition->m_offset = offset;
     structure->m_transitionTable.add(globalData, transition);
     return transition;
 }
@@ -395,8 +369,6 @@ Structure* Structure::removePropertyTransition(JSGlobalData& globalData, Structu
     Structure* transition = toUncacheableDictionaryTransition(globalData, structure);
 
     offset = transition->remove(propertyName);
-    ASSERT(offset >= structure->m_anonymousSlotCount);
-    ASSERT(structure->m_anonymousSlotCount == transition->m_anonymousSlotCount);
 
     return transition;
 }
@@ -410,10 +382,9 @@ Structure* Structure::changePrototypeTransition(JSGlobalData& globalData, Struct
     // Don't set m_offset, as one can not transition to this.
 
     structure->materializePropertyMapIfNecessary(globalData);
-    transition->m_propertyTable = structure->copyPropertyTable(globalData, transition);
-    transition->m_isPinnedPropertyTable = true;
-    
-    ASSERT(structure->anonymousSlotCount() == transition->anonymousSlotCount());
+    transition->m_propertyTable = structure->copyPropertyTableForPinning(globalData, transition);
+    transition->pin();
+
     return transition;
 }
 
@@ -427,8 +398,8 @@ Structure* Structure::despecifyFunctionTransition(JSGlobalData& globalData, Stru
     // Don't set m_offset, as one can not transition to this.
 
     structure->materializePropertyMapIfNecessary(globalData);
-    transition->m_propertyTable = structure->copyPropertyTable(globalData, transition);
-    transition->m_isPinnedPropertyTable = true;
+    transition->m_propertyTable = structure->copyPropertyTableForPinning(globalData, transition);
+    transition->pin();
 
     if (transition->m_specificFunctionThrashCount == maxSpecificFunctionThrashCount)
         transition->despecifyAllFunctions(globalData);
@@ -436,23 +407,30 @@ Structure* Structure::despecifyFunctionTransition(JSGlobalData& globalData, Stru
         bool removed = transition->despecifyFunction(globalData, replaceFunction);
         ASSERT_UNUSED(removed, removed);
     }
-    
-    ASSERT(structure->anonymousSlotCount() == transition->anonymousSlotCount());
+
     return transition;
 }
 
-Structure* Structure::getterSetterTransition(JSGlobalData& globalData, Structure* structure)
+Structure* Structure::attributeChangeTransition(JSGlobalData& globalData, Structure* structure, const Identifier& propertyName, unsigned attributes)
 {
-    Structure* transition = create(globalData, structure);
+    if (!structure->isUncacheableDictionary()) {
+        Structure* transition = create(globalData, structure);
 
-    // Don't set m_offset, as one can not transition to this.
+        // Don't set m_offset, as one can not transition to this.
 
-    structure->materializePropertyMapIfNecessary(globalData);
-    transition->m_propertyTable = structure->copyPropertyTable(globalData, transition);
-    transition->m_isPinnedPropertyTable = true;
-    
-    ASSERT(structure->anonymousSlotCount() == transition->anonymousSlotCount());
-    return transition;
+        structure->materializePropertyMapIfNecessary(globalData);
+        transition->m_propertyTable = structure->copyPropertyTableForPinning(globalData, transition);
+        transition->pin();
+        
+        structure = transition;
+    }
+
+    ASSERT(structure->m_propertyTable);
+    PropertyMapEntry* entry = structure->m_propertyTable->find(propertyName.impl()).first;
+    ASSERT(entry);
+    entry->attributes = attributes;
+
+    return structure;
 }
 
 Structure* Structure::toDictionaryTransition(JSGlobalData& globalData, Structure* structure, DictionaryKind kind)
@@ -462,11 +440,10 @@ Structure* Structure::toDictionaryTransition(JSGlobalData& globalData, Structure
     Structure* transition = create(globalData, structure);
 
     structure->materializePropertyMapIfNecessary(globalData);
-    transition->m_propertyTable = structure->copyPropertyTable(globalData, transition);
-    transition->m_isPinnedPropertyTable = true;
+    transition->m_propertyTable = structure->copyPropertyTableForPinning(globalData, transition);
     transition->m_dictionaryKind = kind;
-    
-    ASSERT(structure->anonymousSlotCount() == transition->anonymousSlotCount());
+    transition->pin();
+
     return transition;
 }
 
@@ -500,9 +477,12 @@ Structure* Structure::freezeTransition(JSGlobalData& globalData, Structure* stru
     Structure* transition = preventExtensionsTransition(globalData, structure);
 
     if (transition->m_propertyTable) {
+        PropertyTable::iterator iter = transition->m_propertyTable->begin();
         PropertyTable::iterator end = transition->m_propertyTable->end();
-        for (PropertyTable::iterator iter = transition->m_propertyTable->begin(); iter != end; ++iter)
-            iter->attributes |= (DontDelete | ReadOnly);
+        if (iter != end)
+            transition->m_hasReadOnlyOrGetterSetterPropertiesExcludingProto = true;
+        for (; iter != end; ++iter)
+            iter->attributes |= iter->attributes & Accessor ? DontDelete : (DontDelete | ReadOnly);
     }
 
     return transition;
@@ -516,11 +496,10 @@ Structure* Structure::preventExtensionsTransition(JSGlobalData& globalData, Stru
     // Don't set m_offset, as one can not transition to this.
 
     structure->materializePropertyMapIfNecessary(globalData);
-    transition->m_propertyTable = structure->copyPropertyTable(globalData, transition);
-    transition->m_isPinnedPropertyTable = true;
+    transition->m_propertyTable = structure->copyPropertyTableForPinning(globalData, transition);
     transition->m_preventExtensions = true;
+    transition->pin();
 
-    ASSERT(structure->anonymousSlotCount() == transition->anonymousSlotCount());
     return transition;
 }
 
@@ -554,7 +533,9 @@ bool Structure::isFrozen(JSGlobalData& globalData)
 
     PropertyTable::iterator end = m_propertyTable->end();
     for (PropertyTable::iterator iter = m_propertyTable->begin(); iter != end; ++iter) {
-        if ((iter->attributes & (DontDelete | ReadOnly)) != (DontDelete | ReadOnly))
+        if (!(iter->attributes & DontDelete))
+            return false;
+        if (!(iter->attributes & (ReadOnly | Accessor)))
             return false;
     }
     return true;
@@ -566,7 +547,6 @@ Structure* Structure::flattenDictionaryStructure(JSGlobalData& globalData, JSObj
     if (isUncacheableDictionary()) {
         ASSERT(m_propertyTable);
 
-        unsigned anonymousSlotCount = m_anonymousSlotCount;
         size_t propertyCount = m_propertyTable->size();
         Vector<JSValue> values(propertyCount);
 
@@ -575,12 +555,12 @@ Structure* Structure::flattenDictionaryStructure(JSGlobalData& globalData, JSObj
         for (PropertyTable::iterator iter = m_propertyTable->begin(); iter != end; ++iter, ++i) {
             values[i] = object->getDirectOffset(iter->offset);
             // Update property table to have the new property offsets
-            iter->offset = anonymousSlotCount + i;
+            iter->offset = i;
         }
         
         // Copy the original property values into their final locations
         for (unsigned i = 0; i < propertyCount; i++)
-            object->putDirectOffset(globalData, anonymousSlotCount + i, values[i]);
+            object->putDirectOffset(globalData, i, values[i]);
 
         m_propertyTable->clearDeletedOffsets();
     }
@@ -596,12 +576,11 @@ size_t Structure::addPropertyWithoutTransition(JSGlobalData& globalData, const I
     if (m_specificFunctionThrashCount == maxSpecificFunctionThrashCount)
         specificValue = 0;
 
-    materializePropertyMapIfNecessary(globalData);
-
-    m_isPinnedPropertyTable = true;
+    materializePropertyMapIfNecessaryForPinning(globalData);
+    
+    pin();
 
     size_t offset = putSpecificValue(globalData, propertyName, attributes, specificValue);
-    ASSERT(offset >= m_anonymousSlotCount);
     if (propertyStorageSize() > propertyStorageCapacity())
         growPropertyStorageCapacity();
     return offset;
@@ -612,14 +591,21 @@ size_t Structure::removePropertyWithoutTransition(JSGlobalData& globalData, cons
     ASSERT(isUncacheableDictionary());
     ASSERT(!m_enumerationCache);
 
-    materializePropertyMapIfNecessary(globalData);
+    materializePropertyMapIfNecessaryForPinning(globalData);
 
-    m_isPinnedPropertyTable = true;
+    pin();
     size_t offset = remove(propertyName);
-    ASSERT(offset >= m_anonymousSlotCount);
     return offset;
 }
 
+void Structure::pin()
+{
+    ASSERT(m_propertyTable);
+    m_isPinnedPropertyTable = true;
+    m_previous.clear();
+    m_nameInPrevious.clear();
+}
+
 #if DUMP_PROPERTYMAP_STATS
 
 struct PropertyMapStatisticsExitLogger {
@@ -630,11 +616,11 @@ static PropertyMapStatisticsExitLogger logger;
 
 PropertyMapStatisticsExitLogger::~PropertyMapStatisticsExitLogger()
 {
-    printf("\nJSC::PropertyMap statistics\n\n");
-    printf("%d probes\n", numProbes);
-    printf("%d collisions (%.1f%%)\n", numCollisions, 100.0 * numCollisions / numProbes);
-    printf("%d rehashes\n", numRehashes);
-    printf("%d removes\n", numRemoves);
+    dataLog("\nJSC::PropertyMap statistics\n\n");
+    dataLog("%d probes\n", numProbes);
+    dataLog("%d collisions (%.1f%%)\n", numCollisions, 100.0 * numCollisions / numProbes);
+    dataLog("%d rehashes\n", numRehashes);
+    dataLog("%d removes\n", numRemoves);
 }
 
 #endif
@@ -652,6 +638,11 @@ PassOwnPtr<PropertyTable> Structure::copyPropertyTable(JSGlobalData& globalData,
     return adoptPtr(m_propertyTable ? new PropertyTable(globalData, owner, *m_propertyTable) : 0);
 }
 
+PassOwnPtr<PropertyTable> Structure::copyPropertyTableForPinning(JSGlobalData& globalData, Structure* owner)
+{
+    return adoptPtr(m_propertyTable ? new PropertyTable(globalData, owner, *m_propertyTable) : new PropertyTable(m_offset == noOffset ? 0 : m_offset));
+}
+
 size_t Structure::get(JSGlobalData& globalData, StringImpl* propertyName, unsigned& attributes, JSCell*& specificValue)
 {
     materializePropertyMapIfNecessary(globalData);
@@ -664,7 +655,6 @@ size_t Structure::get(JSGlobalData& globalData, StringImpl* propertyName, unsign
 
     attributes = entry->attributes;
     specificValue = entry->specificValue.get();
-    ASSERT(entry->offset >= m_anonymousSlotCount);
     return entry->offset;
 }
 
@@ -714,8 +704,7 @@ size_t Structure::putSpecificValue(JSGlobalData& globalData, const Identifier& p
     if (m_propertyTable->hasDeletedOffset())
         newOffset = m_propertyTable->getDeletedOffset();
     else
-        newOffset = m_propertyTable->size() + m_anonymousSlotCount;
-    ASSERT(newOffset >= m_anonymousSlotCount);
+        newOffset = m_propertyTable->size();
 
     m_propertyTable->add(PropertyMapEntry(globalData, this, rep, newOffset, attributes, specificValue));
 
@@ -739,7 +728,6 @@ size_t Structure::remove(const Identifier& propertyName)
         return notFound;
 
     size_t offset = position.first->offset;
-    ASSERT(offset >= m_anonymousSlotCount);
 
     m_propertyTable->remove(position);
     m_propertyTable->addDeletedOffset(offset);
@@ -757,7 +745,7 @@ void Structure::createPropertyMap(unsigned capacity)
     checkConsistency();
 }
 
-void Structure::getPropertyNames(JSGlobalData& globalData, PropertyNameArray& propertyNames, EnumerationMode mode)
+void Structure::getPropertyNamesFromStructure(JSGlobalData& globalData, PropertyNameArray& propertyNames, EnumerationMode mode)
 {
     materializePropertyMapIfNecessary(globalData);
     if (!m_propertyTable)
@@ -777,28 +765,37 @@ void Structure::getPropertyNames(JSGlobalData& globalData, PropertyNameArray& pr
     }
 }
 
-void Structure::visitChildren(SlotVisitor& visitor)
-{
-    ASSERT_GC_OBJECT_INHERITS(this, &s_info);
-    ASSERT(structure()->typeInfo().overridesVisitChildren());
-    JSCell::visitChildren(visitor);
-    if (m_prototype)
-        visitor.append(&m_prototype);
-    if (m_cachedPrototypeChain)
-        visitor.append(&m_cachedPrototypeChain);
-    if (m_previous)
-        visitor.append(&m_previous);
-    if (m_specificValueInPrevious)
-        visitor.append(&m_specificValueInPrevious);
-    if (m_enumerationCache)
-        visitor.append(&m_enumerationCache);
-    if (m_propertyTable) {
-        PropertyTable::iterator end = m_propertyTable->end();
-        for (PropertyTable::iterator ptr = m_propertyTable->begin(); ptr != end; ++ptr) {
+void Structure::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+    Structure* thisObject = jsCast<Structure*>(cell);
+    ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);
+    ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
+    JSCell::visitChildren(thisObject, visitor);
+    if (thisObject->m_globalObject)
+        visitor.append(&thisObject->m_globalObject);
+    if (!thisObject->isObject())
+        thisObject->m_cachedPrototypeChain.clear();
+    else {
+        if (thisObject->m_prototype)
+            visitor.append(&thisObject->m_prototype);
+        if (thisObject->m_cachedPrototypeChain)
+            visitor.append(&thisObject->m_cachedPrototypeChain);
+    }
+    if (thisObject->m_previous)
+        visitor.append(&thisObject->m_previous);
+    if (thisObject->m_specificValueInPrevious)
+        visitor.append(&thisObject->m_specificValueInPrevious);
+    if (thisObject->m_enumerationCache)
+        visitor.append(&thisObject->m_enumerationCache);
+    if (thisObject->m_propertyTable) {
+        PropertyTable::iterator end = thisObject->m_propertyTable->end();
+        for (PropertyTable::iterator ptr = thisObject->m_propertyTable->begin(); ptr != end; ++ptr) {
             if (ptr->specificValue)
                 visitor.append(&ptr->specificValue);
         }
     }
+    if (thisObject->m_objectToStringValue)
+        visitor.append(&thisObject->m_objectToStringValue);
 }
 
 #if DO_PROPERTYMAP_CONSTENCY_CHECK
@@ -869,7 +866,6 @@ void Structure::checkConsistency()
         PropertyTable::iterator end = m_propertyTable->end();
         for (PropertyTable::iterator iter = m_propertyTable->begin(); iter != end; ++iter) {
             ASSERT(!(iter->attributes & DontEnum));
-            ASSERT(iter->offset >= m_anonymousSlotCount);
         }
     }