2 * Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #include "Structure.h"
29 #include "Identifier.h"
31 #include "JSPropertyNameIterator.h"
33 #include "PropertyNameArray.h"
34 #include "StructureChain.h"
35 #include <wtf/RefCountedLeakCounter.h>
36 #include <wtf/RefPtr.h>
37 #include <wtf/Threading.h>
39 #define DUMP_STRUCTURE_ID_STATISTICS 0
42 #define DO_PROPERTYMAP_CONSTENCY_CHECK 0
44 #define DO_PROPERTYMAP_CONSTENCY_CHECK 0
50 #if DUMP_PROPERTYMAP_STATS
61 #if DUMP_STRUCTURE_ID_STATISTICS
62 static HashSet<Structure*>& liveStructureSet = *(new HashSet<Structure*>);
65 bool StructureTransitionTable::contains(StringImpl* rep, unsigned attributes) const
67 if (isUsingSingleSlot()) {
68 Structure* transition = singleTransition();
69 return transition && transition->m_nameInPrevious == rep && transition->m_attributesInPrevious == attributes;
71 return map()->contains(make_pair(rep, attributes));
74 inline Structure* StructureTransitionTable::get(StringImpl* rep, unsigned attributes) const
76 if (isUsingSingleSlot()) {
77 Structure* transition = singleTransition();
78 return (transition && transition->m_nameInPrevious == rep && transition->m_attributesInPrevious == attributes) ? transition : 0;
80 return map()->get(make_pair(rep, attributes));
83 inline void StructureTransitionTable::add(JSGlobalData& globalData, Structure* structure)
85 if (isUsingSingleSlot()) {
86 Structure* existingTransition = singleTransition();
88 // This handles the first transition being added.
89 if (!existingTransition) {
90 setSingleTransition(globalData, structure);
94 // This handles the second transition being added
95 // (or the first transition being despecified!)
96 setMap(new TransitionMap());
97 add(globalData, existingTransition);
100 // Add the structure to the map.
102 // Newer versions of the STL have an std::make_pair function that takes rvalue references.
103 // 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.
104 // See https://bugs.webkit.org/show_bug.cgi?id=59261 for more details
105 std::pair<TransitionMap::iterator, bool> result = map()->add(globalData, make_pair(structure->m_nameInPrevious, +structure->m_attributesInPrevious), structure);
106 if (!result.second) {
107 // There already is an entry! - we should only hit this when despecifying.
108 ASSERT(result.first.get().second->m_specificValueInPrevious);
109 ASSERT(!structure->m_specificValueInPrevious);
110 map()->set(result.first, structure);
114 void Structure::dumpStatistics()
116 #if DUMP_STRUCTURE_ID_STATISTICS
117 unsigned numberLeaf = 0;
118 unsigned numberUsingSingleSlot = 0;
119 unsigned numberSingletons = 0;
120 unsigned numberWithPropertyMaps = 0;
121 unsigned totalPropertyMapsSize = 0;
123 HashSet<Structure*>::const_iterator end = liveStructureSet.end();
124 for (HashSet<Structure*>::const_iterator it = liveStructureSet.begin(); it != end; ++it) {
125 Structure* structure = *it;
127 switch (structure->m_transitionTable.size()) {
130 if (!structure->m_previous)
135 ++numberUsingSingleSlot;
139 if (structure->m_propertyTable) {
140 ++numberWithPropertyMaps;
141 totalPropertyMapsSize += structure->m_propertyTable->sizeInMemory();
145 printf("Number of live Structures: %d\n", liveStructureSet.size());
146 printf("Number of Structures using the single item optimization for transition map: %d\n", numberUsingSingleSlot);
147 printf("Number of Structures that are leaf nodes: %d\n", numberLeaf);
148 printf("Number of Structures that singletons: %d\n", numberSingletons);
149 printf("Number of Structures with PropertyMaps: %d\n", numberWithPropertyMaps);
151 printf("Size of a single Structures: %d\n", static_cast<unsigned>(sizeof(Structure)));
152 printf("Size of sum of all property maps: %d\n", totalPropertyMapsSize);
153 printf("Size of average of all property maps: %f\n", static_cast<double>(totalPropertyMapsSize) / static_cast<double>(liveStructureSet.size()));
155 printf("Dumping Structure statistics is not enabled.\n");
159 Structure::Structure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype, const TypeInfo& typeInfo, const ClassInfo* classInfo)
160 : JSCell(globalData, globalData.structureStructure.get())
161 , m_typeInfo(typeInfo)
162 , m_globalObject(globalData, this, globalObject, WriteBarrier<JSGlobalObject>::MayBeNull)
163 , m_prototype(globalData, this, prototype)
164 , m_classInfo(classInfo)
165 , m_propertyStorageCapacity(typeInfo.isFinalObject() ? JSFinalObject_inlineStorageCapacity : JSNonFinalObject_inlineStorageCapacity)
167 , m_dictionaryKind(NoneDictionaryKind)
168 , m_isPinnedPropertyTable(false)
169 , m_hasGetterSetterProperties(false)
170 , m_hasNonEnumerableProperties(false)
171 , m_attributesInPrevious(0)
172 , m_specificFunctionThrashCount(0)
173 , m_preventExtensions(false)
174 , m_didTransition(false)
175 , m_staticFunctionReified(false)
179 const ClassInfo Structure::s_info = { "Structure", 0, 0, 0, CREATE_METHOD_TABLE(Structure) };
181 Structure::Structure(JSGlobalData& globalData)
182 : JSCell(CreatingEarlyCell)
183 , m_typeInfo(CompoundType, OverridesVisitChildren)
184 , m_prototype(globalData, this, jsNull())
185 , m_classInfo(&s_info)
186 , m_propertyStorageCapacity(0)
188 , m_dictionaryKind(NoneDictionaryKind)
189 , m_isPinnedPropertyTable(false)
190 , m_hasGetterSetterProperties(false)
191 , m_hasNonEnumerableProperties(false)
192 , m_attributesInPrevious(0)
193 , m_specificFunctionThrashCount(0)
194 , m_preventExtensions(false)
195 , m_didTransition(false)
196 , m_staticFunctionReified(false)
200 Structure::Structure(JSGlobalData& globalData, const Structure* previous)
201 : JSCell(globalData, globalData.structureStructure.get())
202 , m_typeInfo(previous->typeInfo())
203 , m_prototype(globalData, this, previous->storedPrototype())
204 , m_classInfo(previous->m_classInfo)
205 , m_propertyStorageCapacity(previous->m_propertyStorageCapacity)
207 , m_dictionaryKind(previous->m_dictionaryKind)
208 , m_isPinnedPropertyTable(false)
209 , m_hasGetterSetterProperties(previous->m_hasGetterSetterProperties)
210 , m_hasNonEnumerableProperties(previous->m_hasNonEnumerableProperties)
211 , m_attributesInPrevious(0)
212 , m_specificFunctionThrashCount(previous->m_specificFunctionThrashCount)
213 , m_preventExtensions(previous->m_preventExtensions)
214 , m_didTransition(true)
215 , m_staticFunctionReified(previous->m_staticFunctionReified)
217 if (previous->m_globalObject)
218 m_globalObject.set(globalData, this, previous->m_globalObject.get());
221 Structure::~Structure()
225 void Structure::materializePropertyMap(JSGlobalData& globalData)
227 ASSERT(structure()->classInfo() == &s_info);
228 ASSERT(!m_propertyTable);
230 Vector<Structure*, 8> structures;
231 structures.append(this);
233 Structure* structure = this;
235 // Search for the last Structure with a property table.
236 while ((structure = structure->previousID())) {
237 if (structure->m_isPinnedPropertyTable) {
238 ASSERT(structure->m_propertyTable);
239 ASSERT(!structure->m_previous);
241 m_propertyTable = structure->m_propertyTable->copy(globalData, 0, m_offset + 1);
245 structures.append(structure);
248 if (!m_propertyTable)
249 createPropertyMap(m_offset + 1);
251 for (ptrdiff_t i = structures.size() - 2; i >= 0; --i) {
252 structure = structures[i];
253 PropertyMapEntry entry(globalData, this, structure->m_nameInPrevious.get(), structure->m_offset, structure->m_attributesInPrevious, structure->m_specificValueInPrevious.get());
254 m_propertyTable->add(entry);
258 void Structure::growPropertyStorageCapacity()
260 if (isUsingInlineStorage())
261 m_propertyStorageCapacity = JSObject::baseExternalStorageCapacity;
263 m_propertyStorageCapacity *= 2;
266 void Structure::despecifyDictionaryFunction(JSGlobalData& globalData, const Identifier& propertyName)
268 StringImpl* rep = propertyName.impl();
270 materializePropertyMapIfNecessary(globalData);
272 ASSERT(isDictionary());
273 ASSERT(m_propertyTable);
275 PropertyMapEntry* entry = m_propertyTable->find(rep).first;
277 entry->specificValue.clear();
280 Structure* Structure::addPropertyTransitionToExistingStructure(Structure* structure, const Identifier& propertyName, unsigned attributes, JSCell* specificValue, size_t& offset)
282 ASSERT(!structure->isDictionary());
283 ASSERT(structure->isObject());
285 if (Structure* existingTransition = structure->m_transitionTable.get(propertyName.impl(), attributes)) {
286 JSCell* specificValueInPrevious = existingTransition->m_specificValueInPrevious.get();
287 if (specificValueInPrevious && specificValueInPrevious != specificValue)
289 ASSERT(existingTransition->m_offset != noOffset);
290 offset = existingTransition->m_offset;
291 return existingTransition;
297 Structure* Structure::addPropertyTransition(JSGlobalData& globalData, Structure* structure, const Identifier& propertyName, unsigned attributes, JSCell* specificValue, size_t& offset)
299 // If we have a specific function, we may have got to this point if there is
300 // already a transition with the correct property name and attributes, but
301 // specialized to a different function. In this case we just want to give up
302 // and despecialize the transition.
303 // In this case we clear the value of specificFunction which will result
304 // in us adding a non-specific transition, and any subsequent lookup in
305 // Structure::addPropertyTransitionToExistingStructure will just use that.
306 if (specificValue && structure->m_transitionTable.contains(propertyName.impl(), attributes))
309 ASSERT(!structure->isDictionary());
310 ASSERT(structure->isObject());
311 ASSERT(!Structure::addPropertyTransitionToExistingStructure(structure, propertyName, attributes, specificValue, offset));
313 if (structure->m_specificFunctionThrashCount == maxSpecificFunctionThrashCount)
316 if (structure->transitionCount() > s_maxTransitionLength) {
317 Structure* transition = toCacheableDictionaryTransition(globalData, structure);
318 ASSERT(structure != transition);
319 offset = transition->putSpecificValue(globalData, propertyName, attributes, specificValue);
320 if (transition->propertyStorageSize() > transition->propertyStorageCapacity())
321 transition->growPropertyStorageCapacity();
325 Structure* transition = create(globalData, structure);
327 transition->m_cachedPrototypeChain.setMayBeNull(globalData, transition, structure->m_cachedPrototypeChain.get());
328 transition->m_previous.set(globalData, transition, structure);
329 transition->m_nameInPrevious = propertyName.impl();
330 transition->m_attributesInPrevious = attributes;
331 transition->m_specificValueInPrevious.setMayBeNull(globalData, transition, specificValue);
333 if (structure->m_propertyTable) {
334 if (structure->m_isPinnedPropertyTable)
335 transition->m_propertyTable = structure->m_propertyTable->copy(globalData, transition, structure->m_propertyTable->size() + 1);
337 transition->m_propertyTable = structure->m_propertyTable.release();
339 if (structure->m_previous)
340 transition->materializePropertyMap(globalData);
342 transition->createPropertyMap();
345 offset = transition->putSpecificValue(globalData, propertyName, attributes, specificValue);
346 if (transition->propertyStorageSize() > transition->propertyStorageCapacity())
347 transition->growPropertyStorageCapacity();
349 transition->m_offset = offset;
350 structure->m_transitionTable.add(globalData, transition);
354 Structure* Structure::removePropertyTransition(JSGlobalData& globalData, Structure* structure, const Identifier& propertyName, size_t& offset)
356 ASSERT(!structure->isUncacheableDictionary());
358 Structure* transition = toUncacheableDictionaryTransition(globalData, structure);
360 offset = transition->remove(propertyName);
365 Structure* Structure::changePrototypeTransition(JSGlobalData& globalData, Structure* structure, JSValue prototype)
367 Structure* transition = create(globalData, structure);
369 transition->m_prototype.set(globalData, transition, prototype);
371 // Don't set m_offset, as one can not transition to this.
373 structure->materializePropertyMapIfNecessary(globalData);
374 transition->m_propertyTable = structure->copyPropertyTableForPinning(globalData, transition);
380 Structure* Structure::despecifyFunctionTransition(JSGlobalData& globalData, Structure* structure, const Identifier& replaceFunction)
382 ASSERT(structure->m_specificFunctionThrashCount < maxSpecificFunctionThrashCount);
383 Structure* transition = create(globalData, structure);
385 ++transition->m_specificFunctionThrashCount;
387 // Don't set m_offset, as one can not transition to this.
389 structure->materializePropertyMapIfNecessary(globalData);
390 transition->m_propertyTable = structure->copyPropertyTableForPinning(globalData, transition);
393 if (transition->m_specificFunctionThrashCount == maxSpecificFunctionThrashCount)
394 transition->despecifyAllFunctions(globalData);
396 bool removed = transition->despecifyFunction(globalData, replaceFunction);
397 ASSERT_UNUSED(removed, removed);
403 Structure* Structure::getterSetterTransition(JSGlobalData& globalData, Structure* structure)
405 Structure* transition = create(globalData, structure);
407 // Don't set m_offset, as one can not transition to this.
409 structure->materializePropertyMapIfNecessary(globalData);
410 transition->m_propertyTable = structure->copyPropertyTableForPinning(globalData, transition);
416 Structure* Structure::toDictionaryTransition(JSGlobalData& globalData, Structure* structure, DictionaryKind kind)
418 ASSERT(!structure->isUncacheableDictionary());
420 Structure* transition = create(globalData, structure);
422 structure->materializePropertyMapIfNecessary(globalData);
423 transition->m_propertyTable = structure->copyPropertyTableForPinning(globalData, transition);
424 transition->m_dictionaryKind = kind;
430 Structure* Structure::toCacheableDictionaryTransition(JSGlobalData& globalData, Structure* structure)
432 return toDictionaryTransition(globalData, structure, CachedDictionaryKind);
435 Structure* Structure::toUncacheableDictionaryTransition(JSGlobalData& globalData, Structure* structure)
437 return toDictionaryTransition(globalData, structure, UncachedDictionaryKind);
440 // In future we may want to cache this transition.
441 Structure* Structure::sealTransition(JSGlobalData& globalData, Structure* structure)
443 Structure* transition = preventExtensionsTransition(globalData, structure);
445 if (transition->m_propertyTable) {
446 PropertyTable::iterator end = transition->m_propertyTable->end();
447 for (PropertyTable::iterator iter = transition->m_propertyTable->begin(); iter != end; ++iter)
448 iter->attributes |= DontDelete;
454 // In future we may want to cache this transition.
455 Structure* Structure::freezeTransition(JSGlobalData& globalData, Structure* structure)
457 Structure* transition = preventExtensionsTransition(globalData, structure);
459 if (transition->m_propertyTable) {
460 PropertyTable::iterator end = transition->m_propertyTable->end();
461 for (PropertyTable::iterator iter = transition->m_propertyTable->begin(); iter != end; ++iter)
462 iter->attributes |= (DontDelete | ReadOnly);
468 // In future we may want to cache this transition.
469 Structure* Structure::preventExtensionsTransition(JSGlobalData& globalData, Structure* structure)
471 Structure* transition = create(globalData, structure);
473 // Don't set m_offset, as one can not transition to this.
475 structure->materializePropertyMapIfNecessary(globalData);
476 transition->m_propertyTable = structure->copyPropertyTableForPinning(globalData, transition);
477 transition->m_preventExtensions = true;
483 // In future we may want to cache this property.
484 bool Structure::isSealed(JSGlobalData& globalData)
489 materializePropertyMapIfNecessary(globalData);
490 if (!m_propertyTable)
493 PropertyTable::iterator end = m_propertyTable->end();
494 for (PropertyTable::iterator iter = m_propertyTable->begin(); iter != end; ++iter) {
495 if ((iter->attributes & DontDelete) != DontDelete)
501 // In future we may want to cache this property.
502 bool Structure::isFrozen(JSGlobalData& globalData)
507 materializePropertyMapIfNecessary(globalData);
508 if (!m_propertyTable)
511 PropertyTable::iterator end = m_propertyTable->end();
512 for (PropertyTable::iterator iter = m_propertyTable->begin(); iter != end; ++iter) {
513 if ((iter->attributes & (DontDelete | ReadOnly)) != (DontDelete | ReadOnly))
519 Structure* Structure::flattenDictionaryStructure(JSGlobalData& globalData, JSObject* object)
521 ASSERT(isDictionary());
522 if (isUncacheableDictionary()) {
523 ASSERT(m_propertyTable);
525 size_t propertyCount = m_propertyTable->size();
526 Vector<JSValue> values(propertyCount);
529 PropertyTable::iterator end = m_propertyTable->end();
530 for (PropertyTable::iterator iter = m_propertyTable->begin(); iter != end; ++iter, ++i) {
531 values[i] = object->getDirectOffset(iter->offset);
532 // Update property table to have the new property offsets
536 // Copy the original property values into their final locations
537 for (unsigned i = 0; i < propertyCount; i++)
538 object->putDirectOffset(globalData, i, values[i]);
540 m_propertyTable->clearDeletedOffsets();
543 m_dictionaryKind = NoneDictionaryKind;
547 size_t Structure::addPropertyWithoutTransition(JSGlobalData& globalData, const Identifier& propertyName, unsigned attributes, JSCell* specificValue)
549 ASSERT(!m_enumerationCache);
551 if (m_specificFunctionThrashCount == maxSpecificFunctionThrashCount)
554 materializePropertyMapIfNecessaryForPinning(globalData);
558 size_t offset = putSpecificValue(globalData, propertyName, attributes, specificValue);
559 if (propertyStorageSize() > propertyStorageCapacity())
560 growPropertyStorageCapacity();
564 size_t Structure::removePropertyWithoutTransition(JSGlobalData& globalData, const Identifier& propertyName)
566 ASSERT(isUncacheableDictionary());
567 ASSERT(!m_enumerationCache);
569 materializePropertyMapIfNecessaryForPinning(globalData);
572 size_t offset = remove(propertyName);
576 void Structure::pin()
578 ASSERT(m_propertyTable);
579 m_isPinnedPropertyTable = true;
581 m_nameInPrevious.clear();
584 #if DUMP_PROPERTYMAP_STATS
586 struct PropertyMapStatisticsExitLogger {
587 ~PropertyMapStatisticsExitLogger();
590 static PropertyMapStatisticsExitLogger logger;
592 PropertyMapStatisticsExitLogger::~PropertyMapStatisticsExitLogger()
594 printf("\nJSC::PropertyMap statistics\n\n");
595 printf("%d probes\n", numProbes);
596 printf("%d collisions (%.1f%%)\n", numCollisions, 100.0 * numCollisions / numProbes);
597 printf("%d rehashes\n", numRehashes);
598 printf("%d removes\n", numRemoves);
603 #if !DO_PROPERTYMAP_CONSTENCY_CHECK
605 inline void Structure::checkConsistency()
611 PassOwnPtr<PropertyTable> Structure::copyPropertyTable(JSGlobalData& globalData, Structure* owner)
613 return adoptPtr(m_propertyTable ? new PropertyTable(globalData, owner, *m_propertyTable) : 0);
616 PassOwnPtr<PropertyTable> Structure::copyPropertyTableForPinning(JSGlobalData& globalData, Structure* owner)
618 return adoptPtr(m_propertyTable ? new PropertyTable(globalData, owner, *m_propertyTable) : new PropertyTable(m_offset == noOffset ? 0 : m_offset));
621 size_t Structure::get(JSGlobalData& globalData, StringImpl* propertyName, unsigned& attributes, JSCell*& specificValue)
623 materializePropertyMapIfNecessary(globalData);
624 if (!m_propertyTable)
625 return WTF::notFound;
627 PropertyMapEntry* entry = m_propertyTable->find(propertyName).first;
629 return WTF::notFound;
631 attributes = entry->attributes;
632 specificValue = entry->specificValue.get();
633 return entry->offset;
636 bool Structure::despecifyFunction(JSGlobalData& globalData, const Identifier& propertyName)
638 materializePropertyMapIfNecessary(globalData);
639 if (!m_propertyTable)
642 ASSERT(!propertyName.isNull());
643 PropertyMapEntry* entry = m_propertyTable->find(propertyName.impl()).first;
647 ASSERT(entry->specificValue);
648 entry->specificValue.clear();
652 void Structure::despecifyAllFunctions(JSGlobalData& globalData)
654 materializePropertyMapIfNecessary(globalData);
655 if (!m_propertyTable)
658 PropertyTable::iterator end = m_propertyTable->end();
659 for (PropertyTable::iterator iter = m_propertyTable->begin(); iter != end; ++iter)
660 iter->specificValue.clear();
663 size_t Structure::putSpecificValue(JSGlobalData& globalData, const Identifier& propertyName, unsigned attributes, JSCell* specificValue)
665 ASSERT(!propertyName.isNull());
666 ASSERT(get(globalData, propertyName) == notFound);
669 if (attributes & DontEnum)
670 m_hasNonEnumerableProperties = true;
672 StringImpl* rep = propertyName.impl();
674 if (!m_propertyTable)
679 if (m_propertyTable->hasDeletedOffset())
680 newOffset = m_propertyTable->getDeletedOffset();
682 newOffset = m_propertyTable->size();
684 m_propertyTable->add(PropertyMapEntry(globalData, this, rep, newOffset, attributes, specificValue));
690 size_t Structure::remove(const Identifier& propertyName)
692 ASSERT(!propertyName.isNull());
696 StringImpl* rep = propertyName.impl();
698 if (!m_propertyTable)
701 PropertyTable::find_iterator position = m_propertyTable->find(rep);
705 size_t offset = position.first->offset;
707 m_propertyTable->remove(position);
708 m_propertyTable->addDeletedOffset(offset);
714 void Structure::createPropertyMap(unsigned capacity)
716 ASSERT(!m_propertyTable);
719 m_propertyTable = adoptPtr(new PropertyTable(capacity));
723 void Structure::getPropertyNamesFromStructure(JSGlobalData& globalData, PropertyNameArray& propertyNames, EnumerationMode mode)
725 materializePropertyMapIfNecessary(globalData);
726 if (!m_propertyTable)
729 bool knownUnique = !propertyNames.size();
731 PropertyTable::iterator end = m_propertyTable->end();
732 for (PropertyTable::iterator iter = m_propertyTable->begin(); iter != end; ++iter) {
733 ASSERT(m_hasNonEnumerableProperties || !(iter->attributes & DontEnum));
734 if (!(iter->attributes & DontEnum) || (mode == IncludeDontEnumProperties)) {
736 propertyNames.addKnownUnique(iter->key);
738 propertyNames.add(iter->key);
743 void Structure::visitChildren(JSCell* cell, SlotVisitor& visitor)
745 Structure* thisObject = jsCast<Structure*>(cell);
746 ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);
747 ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
748 JSCell::visitChildren(thisObject, visitor);
749 if (thisObject->m_globalObject)
750 visitor.append(&thisObject->m_globalObject);
751 if (!thisObject->isObject())
752 thisObject->m_cachedPrototypeChain.clear();
754 if (thisObject->m_prototype)
755 visitor.append(&thisObject->m_prototype);
756 if (thisObject->m_cachedPrototypeChain)
757 visitor.append(&thisObject->m_cachedPrototypeChain);
759 if (thisObject->m_previous)
760 visitor.append(&thisObject->m_previous);
761 if (thisObject->m_specificValueInPrevious)
762 visitor.append(&thisObject->m_specificValueInPrevious);
763 if (thisObject->m_enumerationCache)
764 visitor.append(&thisObject->m_enumerationCache);
765 if (thisObject->m_propertyTable) {
766 PropertyTable::iterator end = thisObject->m_propertyTable->end();
767 for (PropertyTable::iterator ptr = thisObject->m_propertyTable->begin(); ptr != end; ++ptr) {
768 if (ptr->specificValue)
769 visitor.append(&ptr->specificValue);
774 #if DO_PROPERTYMAP_CONSTENCY_CHECK
776 void PropertyTable::checkConsistency()
778 ASSERT(m_indexSize >= PropertyTable::MinimumTableSize);
780 ASSERT(m_indexSize == m_indexMask + 1);
781 ASSERT(!(m_indexSize & m_indexMask));
783 ASSERT(m_keyCount <= m_indexSize / 2);
784 ASSERT(m_keyCount + m_deletedCount <= m_indexSize / 2);
785 ASSERT(m_deletedCount <= m_indexSize / 4);
787 unsigned indexCount = 0;
788 unsigned deletedIndexCount = 0;
789 for (unsigned a = 0; a != m_indexSize; ++a) {
790 unsigned entryIndex = m_index[a];
791 if (entryIndex == PropertyTable::EmptyEntryIndex)
793 if (entryIndex == deletedEntryIndex()) {
797 ASSERT(entryIndex < deletedEntryIndex());
798 ASSERT(entryIndex - 1 <= usedCount());
801 for (unsigned b = a + 1; b != m_indexSize; ++b)
802 ASSERT(m_index[b] != entryIndex);
804 ASSERT(indexCount == m_keyCount);
805 ASSERT(deletedIndexCount == m_deletedCount);
807 ASSERT(!table()[deletedEntryIndex() - 1].key);
809 unsigned nonEmptyEntryCount = 0;
810 for (unsigned c = 0; c < usedCount(); ++c) {
811 StringImpl* rep = table()[c].key;
812 if (rep == PROPERTY_MAP_DELETED_ENTRY_KEY)
814 ++nonEmptyEntryCount;
815 unsigned i = rep->existingHash();
819 entryIndex = m_index[i & m_indexMask];
820 ASSERT(entryIndex != PropertyTable::EmptyEntryIndex);
821 if (rep == table()[entryIndex - 1].key)
824 k = 1 | doubleHash(rep->existingHash());
827 ASSERT(entryIndex == c + 1);
830 ASSERT(nonEmptyEntryCount == m_keyCount);
833 void Structure::checkConsistency()
835 if (!m_propertyTable)
838 if (!m_hasNonEnumerableProperties) {
839 PropertyTable::iterator end = m_propertyTable->end();
840 for (PropertyTable::iterator iter = m_propertyTable->begin(); iter != end; ++iter) {
841 ASSERT(!(iter->attributes & DontEnum));
845 m_propertyTable->checkConsistency();
848 #endif // DO_PROPERTYMAP_CONSTENCY_CHECK