Changeset 38046 in webkit for trunk/JavaScriptCore/runtime/StructureIDChain.cpp
- Timestamp:
- Oct 31, 2008, 12:53:20 PM (17 years ago)
- File:
-
- 1 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk/JavaScriptCore/runtime/StructureIDChain.cpp
r38044 r38046 25 25 26 26 #include "config.h" 27 #include "StructureID .h"27 #include "StructureIDChain.h" 28 28 29 29 #include "JSObject.h" 30 #include "PropertyNameArray.h" 31 #include "identifier.h" 32 #include "lookup.h" 33 #include <wtf/RefCountedLeakCounter.h> 30 #include "StructureID.h" 34 31 #include <wtf/RefPtr.h> 35 32 36 #if ENABLE(JSC_MULTIPLE_THREADS)37 #include <wtf/Threading.h>38 #endif39 40 #ifndef NDEBUG41 #define DO_PROPERTYMAP_CONSTENCY_CHECK 042 #else43 #define DO_PROPERTYMAP_CONSTENCY_CHECK 044 #endif45 46 using namespace std;47 using WTF::doubleHash;48 49 33 namespace JSC { 50 51 // Choose a number for the following so that most property maps are smaller,52 // but it's not going to blow out the stack to allocate this number of pointers.53 static const int smallMapThreshold = 1024;54 55 // The point at which the function call overhead of the qsort implementation56 // becomes small compared to the inefficiency of insertion sort.57 static const unsigned tinyMapThreshold = 20;58 59 #ifndef NDEBUG60 static WTF::RefCountedLeakCounter structureIDCounter("StructureID");61 62 #if ENABLE(JSC_MULTIPLE_THREADS)63 static Mutex ignoreSetMutex;64 #endif65 66 static bool shouldIgnoreLeaks;67 static HashSet<StructureID*> ignoreSet;68 #endif69 70 #if DUMP_STRUCTURE_ID_STATISTICS71 static HashSet<StructureID*> liveStructureIDSet;72 73 void StructureID::dumpStatistics()74 {75 unsigned numberLeaf = 0;76 unsigned numberUsingSingleSlot = 0;77 unsigned numberSingletons = 0;78 unsigned totalPropertyMapsSize = 0;79 80 HashSet<StructureID*>::const_iterator end = liveStructureIDSet.end();81 for (HashSet<StructureID*>::const_iterator it = liveStructureIDSet.begin(); it != end; ++it) {82 StructureID* structureID = *it;83 if (structureID->m_usingSingleTransitionSlot) {84 if (!structureID->m_transitions.singleTransition)85 ++numberLeaf;86 else87 ++numberUsingSingleSlot;88 89 if (!structureID->m_previous && !structureID->m_transitions.singleTransition)90 ++numberSingletons;91 }92 93 if (structureID->m_propertyTable)94 totalPropertyMapsSize += PropertyMapHashTable::allocationSize(m_propertyTable->size);;95 }96 97 printf("Number of live StructureIDs: %d\n", liveStructureIDSet.size());98 printf("Number of StructureIDs using the single item optimization for transition map: %d\n", numberUsingSingleSlot);99 printf("Number of StructureIDs that are leaf nodes: %d\n", numberLeaf);100 printf("Number of StructureIDs that singletons: %d\n", numberSingletons);101 102 printf("Size of a single StructureIDs: %d\n", static_cast<unsigned>(sizeof(StructureID)));103 printf("Size of sum of all property maps: %d\n", totalPropertyMapsSize);104 printf("Size of average of all property maps: %f\n", static_cast<double>(totalPropertyMapsSize) / static_cast<double>(liveStructureIDSet.size()));105 }106 #endif107 108 StructureID::StructureID(JSValue* prototype, const TypeInfo& typeInfo)109 : m_typeInfo(typeInfo)110 , m_prototype(prototype)111 , m_cachedPrototypeChain(0)112 , m_previous(0)113 , m_nameInPrevious(0)114 , m_transitionCount(0)115 , m_propertyTable(0)116 , m_propertyStorageCapacity(JSObject::inlineStorageCapacity)117 , m_cachedTransistionOffset(WTF::notFound)118 , m_isDictionary(false)119 , m_hasGetterSetterProperties(false)120 , m_usingSingleTransitionSlot(true)121 , m_attributesInPrevious(0)122 {123 ASSERT(m_prototype);124 ASSERT(m_prototype->isObject() || m_prototype->isNull());125 126 m_transitions.singleTransition = 0;127 128 #ifndef NDEBUG129 #if ENABLE(JSC_MULTIPLE_THREADS)130 MutexLocker protect(ignoreSetMutex);131 #endif132 if (shouldIgnoreLeaks)133 ignoreSet.add(this);134 else135 structureIDCounter.increment();136 #endif137 138 #if DUMP_STRUCTURE_ID_STATISTICS139 liveStructureIDSet.add(this);140 #endif141 }142 143 StructureID::~StructureID()144 {145 if (m_previous) {146 if (m_previous->m_usingSingleTransitionSlot) {147 m_previous->m_transitions.singleTransition = 0;148 } else {149 ASSERT(m_previous->m_transitions.table->contains(make_pair(m_nameInPrevious, m_attributesInPrevious)));150 m_previous->m_transitions.table->remove(make_pair(m_nameInPrevious, m_attributesInPrevious));151 }152 }153 154 if (m_cachedPropertyNameArrayData)155 m_cachedPropertyNameArrayData->setCachedStructureID(0);156 157 if (!m_usingSingleTransitionSlot)158 delete m_transitions.table;159 160 if (m_propertyTable) {161 unsigned entryCount = m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount;162 for (unsigned i = 1; i <= entryCount; i++) {163 if (UString::Rep* key = m_propertyTable->entries()[i].key)164 key->deref();165 }166 fastFree(m_propertyTable);167 }168 169 #ifndef NDEBUG170 #if ENABLE(JSC_MULTIPLE_THREADS)171 MutexLocker protect(ignoreSetMutex);172 #endif173 HashSet<StructureID*>::iterator it = ignoreSet.find(this);174 if (it != ignoreSet.end())175 ignoreSet.remove(it);176 else177 structureIDCounter.decrement();178 #endif179 180 #if DUMP_STRUCTURE_ID_STATISTICS181 liveStructureIDSet.remove(this);182 #endif183 }184 185 void StructureID::startIgnoringLeaks()186 {187 #ifndef NDEBUG188 shouldIgnoreLeaks = true;189 #endif190 }191 192 void StructureID::stopIgnoringLeaks()193 {194 #ifndef NDEBUG195 shouldIgnoreLeaks = false;196 #endif197 }198 199 void StructureID::getEnumerablePropertyNames(ExecState* exec, PropertyNameArray& propertyNames, JSObject* baseObject)200 {201 bool shouldCache = propertyNames.cacheable() && !(propertyNames.size() || m_isDictionary);202 203 if (shouldCache) {204 if (m_cachedPropertyNameArrayData) {205 if (structureIDChainsAreEqual(m_cachedPropertyNameArrayData->cachedPrototypeChain(), cachedPrototypeChain())) {206 propertyNames.setData(m_cachedPropertyNameArrayData);207 return;208 }209 }210 propertyNames.setCacheable(false);211 }212 213 getEnumerablePropertyNamesInternal(propertyNames);214 215 // Add properties from the static hashtables of properties216 for (const ClassInfo* info = baseObject->classInfo(); info; info = info->parentClass) {217 const HashTable* table = info->propHashTable(exec);218 if (!table)219 continue;220 table->initializeIfNeeded(exec);221 ASSERT(table->table);222 int hashSizeMask = table->hashSizeMask;223 const HashEntry* entry = table->table;224 for (int i = 0; i <= hashSizeMask; ++i, ++entry) {225 if (entry->key() && !(entry->attributes() & DontEnum))226 propertyNames.add(entry->key());227 }228 }229 230 if (m_prototype->isObject())231 asObject(m_prototype)->getPropertyNames(exec, propertyNames);232 233 if (shouldCache) {234 if (m_cachedPropertyNameArrayData)235 m_cachedPropertyNameArrayData->setCachedStructureID(0);236 237 m_cachedPropertyNameArrayData = propertyNames.data();238 239 StructureIDChain* chain = cachedPrototypeChain();240 if (!chain)241 chain = createCachedPrototypeChain();242 m_cachedPropertyNameArrayData->setCachedPrototypeChain(chain);243 m_cachedPropertyNameArrayData->setCachedStructureID(this);244 }245 }246 247 void StructureID::clearEnumerationCache()248 {249 if (m_cachedPropertyNameArrayData)250 m_cachedPropertyNameArrayData->setCachedStructureID(0);251 m_cachedPropertyNameArrayData.clear();252 }253 254 void StructureID::growPropertyStorageCapacity()255 {256 if (m_propertyStorageCapacity == JSObject::inlineStorageCapacity)257 m_propertyStorageCapacity = JSObject::nonInlineBaseStorageCapacity;258 else259 m_propertyStorageCapacity *= 2;260 }261 262 PassRefPtr<StructureID> StructureID::addPropertyTransition(StructureID* structureID, const Identifier& propertyName, unsigned attributes, size_t& offset)263 {264 ASSERT(!structureID->m_isDictionary);265 ASSERT(structureID->typeInfo().type() == ObjectType);266 267 if (structureID->m_usingSingleTransitionSlot) {268 StructureID* existingTransition = structureID->m_transitions.singleTransition;269 if (existingTransition && existingTransition->m_nameInPrevious == propertyName.ustring().rep() && existingTransition->m_attributesInPrevious == attributes) {270 offset = structureID->m_transitions.singleTransition->cachedTransistionOffset();271 ASSERT(offset != WTF::notFound);272 return existingTransition;273 }274 } else {275 if (StructureID* existingTransition = structureID->m_transitions.table->get(make_pair(propertyName.ustring().rep(), attributes))) {276 offset = existingTransition->cachedTransistionOffset();277 ASSERT(offset != WTF::notFound);278 return existingTransition;279 }280 }281 282 if (structureID->m_transitionCount > s_maxTransitionLength) {283 RefPtr<StructureID> transition = toDictionaryTransition(structureID);284 offset = transition->put(propertyName, attributes);285 if (transition->propertyStorageSize() > transition->propertyStorageCapacity())286 transition->growPropertyStorageCapacity();287 return transition.release();288 }289 290 RefPtr<StructureID> transition = create(structureID->m_prototype, structureID->typeInfo());291 transition->m_cachedPrototypeChain = structureID->m_cachedPrototypeChain;292 transition->m_previous = structureID;293 transition->m_nameInPrevious = propertyName.ustring().rep();294 transition->m_attributesInPrevious = attributes;295 transition->m_transitionCount = structureID->m_transitionCount + 1;296 transition->m_propertyTable = structureID->copyPropertyTable();297 transition->m_deletedOffsets = structureID->m_deletedOffsets;298 transition->m_propertyStorageCapacity = structureID->m_propertyStorageCapacity;299 transition->m_hasGetterSetterProperties = structureID->m_hasGetterSetterProperties;300 301 offset = transition->put(propertyName, attributes);302 if (transition->propertyStorageSize() > transition->propertyStorageCapacity())303 transition->growPropertyStorageCapacity();304 305 transition->setCachedTransistionOffset(offset);306 307 if (structureID->m_usingSingleTransitionSlot) {308 if (!structureID->m_transitions.singleTransition) {309 structureID->m_transitions.singleTransition = transition.get();310 return transition.release();311 }312 313 StructureID* existingTransition = structureID->m_transitions.singleTransition;314 structureID->m_usingSingleTransitionSlot = false;315 StructureIDTransitionTable* transitionTable = new StructureIDTransitionTable;316 structureID->m_transitions.table = transitionTable;317 transitionTable->add(make_pair(existingTransition->m_nameInPrevious, existingTransition->m_attributesInPrevious), existingTransition);318 }319 structureID->m_transitions.table->add(make_pair(propertyName.ustring().rep(), attributes), transition.get());320 return transition.release();321 }322 323 PassRefPtr<StructureID> StructureID::removePropertyTransition(StructureID* structureID, const Identifier& propertyName, size_t& offset)324 {325 ASSERT(!structureID->m_isDictionary);326 327 RefPtr<StructureID> transition = create(structureID->m_prototype, structureID->typeInfo());328 transition->m_isDictionary = true;329 transition->m_propertyTable = structureID->copyPropertyTable();330 transition->m_deletedOffsets = structureID->m_deletedOffsets;331 transition->m_propertyStorageCapacity = structureID->m_propertyStorageCapacity;332 transition->m_hasGetterSetterProperties = structureID->m_hasGetterSetterProperties;333 334 offset = transition->remove(propertyName);335 336 return transition.release();337 }338 339 PassRefPtr<StructureID> StructureID::toDictionaryTransition(StructureID* structureID)340 {341 ASSERT(!structureID->m_isDictionary);342 343 RefPtr<StructureID> transition = create(structureID->m_prototype, structureID->typeInfo());344 transition->m_isDictionary = true;345 transition->m_propertyTable = structureID->copyPropertyTable();346 transition->m_deletedOffsets = structureID->m_deletedOffsets;347 transition->m_propertyStorageCapacity = structureID->m_propertyStorageCapacity;348 transition->m_hasGetterSetterProperties = structureID->m_hasGetterSetterProperties;349 return transition.release();350 }351 352 PassRefPtr<StructureID> StructureID::fromDictionaryTransition(StructureID* structureID)353 {354 ASSERT(structureID->m_isDictionary);355 356 // Since dictionary StructureIDs are not shared, and no opcodes specialize357 // for them, we don't need to allocate a new StructureID when transitioning358 // to non-dictionary status.359 structureID->m_isDictionary = false;360 return structureID;361 }362 363 PassRefPtr<StructureID> StructureID::changePrototypeTransition(StructureID* structureID, JSValue* prototype)364 {365 RefPtr<StructureID> transition = create(prototype, structureID->typeInfo());366 transition->m_transitionCount = structureID->m_transitionCount + 1;367 transition->m_propertyTable = structureID->copyPropertyTable();368 transition->m_deletedOffsets = structureID->m_deletedOffsets;369 transition->m_propertyStorageCapacity = structureID->m_propertyStorageCapacity;370 transition->m_hasGetterSetterProperties = structureID->m_hasGetterSetterProperties;371 return transition.release();372 }373 374 PassRefPtr<StructureID> StructureID::getterSetterTransition(StructureID* structureID)375 {376 RefPtr<StructureID> transition = create(structureID->storedPrototype(), structureID->typeInfo());377 transition->m_transitionCount = structureID->m_transitionCount + 1;378 transition->m_propertyTable = structureID->copyPropertyTable();379 transition->m_deletedOffsets = structureID->m_deletedOffsets;380 transition->m_propertyStorageCapacity = structureID->m_propertyStorageCapacity;381 transition->m_hasGetterSetterProperties = transition->m_hasGetterSetterProperties;382 return transition.release();383 }384 385 size_t StructureID::addPropertyWithoutTransition(const Identifier& propertyName, unsigned attributes)386 {387 size_t offset = put(propertyName, attributes);388 if (propertyStorageSize() > propertyStorageCapacity())389 growPropertyStorageCapacity();390 clearEnumerationCache();391 return offset;392 }393 394 size_t StructureID::removePropertyWithoutTransition(const Identifier& propertyName)395 {396 size_t offset = remove(propertyName);397 clearEnumerationCache();398 return offset;399 }400 401 StructureIDChain* StructureID::createCachedPrototypeChain()402 {403 ASSERT(typeInfo().type() == ObjectType);404 ASSERT(!m_cachedPrototypeChain);405 406 JSValue* prototype = storedPrototype();407 if (JSImmediate::isImmediate(prototype))408 return 0;409 410 RefPtr<StructureIDChain> chain = StructureIDChain::create(asObject(prototype)->structureID());411 setCachedPrototypeChain(chain.release());412 return cachedPrototypeChain();413 }414 415 #if DUMP_PROPERTYMAP_STATS416 417 static int numProbes;418 static int numCollisions;419 static int numRehashes;420 static int numRemoves;421 422 struct PropertyMapStatisticsExitLogger {423 ~PropertyMapStatisticsExitLogger();424 };425 426 static PropertyMapStatisticsExitLogger logger;427 428 PropertyMapStatisticsExitLogger::~PropertyMapStatisticsExitLogger()429 {430 printf("\nJSC::PropertyMap statistics\n\n");431 printf("%d probes\n", numProbes);432 printf("%d collisions (%.1f%%)\n", numCollisions, 100.0 * numCollisions / numProbes);433 printf("%d rehashes\n", numRehashes);434 printf("%d removes\n", numRemoves);435 }436 437 #endif438 439 static const unsigned deletedSentinelIndex = 1;440 441 #if !DO_PROPERTYMAP_CONSTENCY_CHECK442 443 inline void StructureID::checkConsistency()444 {445 }446 447 #endif448 449 PropertyMapHashTable* StructureID::copyPropertyTable()450 {451 if (!m_propertyTable)452 return 0;453 454 size_t tableSize = PropertyMapHashTable::allocationSize(m_propertyTable->size);455 PropertyMapHashTable* newTable = static_cast<PropertyMapHashTable*>(fastMalloc(tableSize));456 memcpy(newTable, m_propertyTable, tableSize);457 458 unsigned entryCount = m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount;459 for (unsigned i = 1; i <= entryCount; ++i) {460 if (UString::Rep* key = newTable->entries()[i].key)461 key->ref();462 }463 464 return newTable;465 }466 467 size_t StructureID::get(const Identifier& propertyName, unsigned& attributes) const468 {469 ASSERT(!propertyName.isNull());470 471 if (!m_propertyTable)472 return WTF::notFound;473 474 UString::Rep* rep = propertyName._ustring.rep();475 476 unsigned i = rep->computedHash();477 478 #if DUMP_PROPERTYMAP_STATS479 ++numProbes;480 #endif481 482 unsigned entryIndex = m_propertyTable->entryIndices[i & m_propertyTable->sizeMask];483 if (entryIndex == emptyEntryIndex)484 return WTF::notFound;485 486 if (rep == m_propertyTable->entries()[entryIndex - 1].key) {487 attributes = m_propertyTable->entries()[entryIndex - 1].attributes;488 return m_propertyTable->entries()[entryIndex - 1].offset;489 }490 491 #if DUMP_PROPERTYMAP_STATS492 ++numCollisions;493 #endif494 495 unsigned k = 1 | doubleHash(rep->computedHash());496 497 while (1) {498 i += k;499 500 #if DUMP_PROPERTYMAP_STATS501 ++numRehashes;502 #endif503 504 entryIndex = m_propertyTable->entryIndices[i & m_propertyTable->sizeMask];505 if (entryIndex == emptyEntryIndex)506 return WTF::notFound;507 508 if (rep == m_propertyTable->entries()[entryIndex - 1].key) {509 attributes = m_propertyTable->entries()[entryIndex - 1].attributes;510 return m_propertyTable->entries()[entryIndex - 1].offset;511 }512 }513 }514 515 size_t StructureID::put(const Identifier& propertyName, unsigned attributes)516 {517 ASSERT(!propertyName.isNull());518 ASSERT(get(propertyName) == WTF::notFound);519 520 checkConsistency();521 522 UString::Rep* rep = propertyName._ustring.rep();523 524 if (!m_propertyTable)525 createPropertyMapHashTable();526 527 // FIXME: Consider a fast case for tables with no deleted sentinels.528 529 unsigned i = rep->computedHash();530 unsigned k = 0;531 bool foundDeletedElement = false;532 unsigned deletedElementIndex = 0; // initialize to make the compiler happy533 534 #if DUMP_PROPERTYMAP_STATS535 ++numProbes;536 #endif537 538 while (1) {539 unsigned entryIndex = m_propertyTable->entryIndices[i & m_propertyTable->sizeMask];540 if (entryIndex == emptyEntryIndex)541 break;542 543 if (entryIndex == deletedSentinelIndex) {544 // If we find a deleted-element sentinel, remember it for use later.545 if (!foundDeletedElement) {546 foundDeletedElement = true;547 deletedElementIndex = i;548 }549 }550 551 if (k == 0) {552 k = 1 | doubleHash(rep->computedHash());553 #if DUMP_PROPERTYMAP_STATS554 ++numCollisions;555 #endif556 }557 558 i += k;559 560 #if DUMP_PROPERTYMAP_STATS561 ++numRehashes;562 #endif563 }564 565 // Figure out which entry to use.566 unsigned entryIndex = m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount + 2;567 if (foundDeletedElement) {568 i = deletedElementIndex;569 --m_propertyTable->deletedSentinelCount;570 571 // Since we're not making the table bigger, we can't use the entry one past572 // the end that we were planning on using, so search backwards for the empty573 // slot that we can use. We know it will be there because we did at least one574 // deletion in the past that left an entry empty.575 while (m_propertyTable->entries()[--entryIndex - 1].key) { }576 }577 578 // Create a new hash table entry.579 m_propertyTable->entryIndices[i & m_propertyTable->sizeMask] = entryIndex;580 581 // Create a new hash table entry.582 rep->ref();583 m_propertyTable->entries()[entryIndex - 1].key = rep;584 m_propertyTable->entries()[entryIndex - 1].attributes = attributes;585 m_propertyTable->entries()[entryIndex - 1].index = ++m_propertyTable->lastIndexUsed;586 587 unsigned newOffset;588 if (!m_deletedOffsets.isEmpty()) {589 newOffset = m_deletedOffsets.last();590 m_deletedOffsets.removeLast();591 } else592 newOffset = m_propertyTable->keyCount;593 m_propertyTable->entries()[entryIndex - 1].offset = newOffset;594 595 ++m_propertyTable->keyCount;596 597 if ((m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount) * 2 >= m_propertyTable->size)598 expandPropertyMapHashTable();599 600 checkConsistency();601 return newOffset;602 }603 604 size_t StructureID::remove(const Identifier& propertyName)605 {606 ASSERT(!propertyName.isNull());607 608 checkConsistency();609 610 UString::Rep* rep = propertyName._ustring.rep();611 612 if (!m_propertyTable)613 return WTF::notFound;614 615 #if DUMP_PROPERTYMAP_STATS616 ++numProbes;617 ++numRemoves;618 #endif619 620 // Find the thing to remove.621 unsigned i = rep->computedHash();622 unsigned k = 0;623 unsigned entryIndex;624 UString::Rep* key = 0;625 while (1) {626 entryIndex = m_propertyTable->entryIndices[i & m_propertyTable->sizeMask];627 if (entryIndex == emptyEntryIndex)628 return WTF::notFound;629 630 key = m_propertyTable->entries()[entryIndex - 1].key;631 if (rep == key)632 break;633 634 if (k == 0) {635 k = 1 | doubleHash(rep->computedHash());636 #if DUMP_PROPERTYMAP_STATS637 ++numCollisions;638 #endif639 }640 641 i += k;642 643 #if DUMP_PROPERTYMAP_STATS644 ++numRehashes;645 #endif646 }647 648 // Replace this one element with the deleted sentinel. Also clear out649 // the entry so we can iterate all the entries as needed.650 m_propertyTable->entryIndices[i & m_propertyTable->sizeMask] = deletedSentinelIndex;651 652 size_t offset = m_propertyTable->entries()[entryIndex - 1].offset;653 654 key->deref();655 m_propertyTable->entries()[entryIndex - 1].key = 0;656 m_propertyTable->entries()[entryIndex - 1].attributes = 0;657 m_propertyTable->entries()[entryIndex - 1].offset = 0;658 m_deletedOffsets.append(offset);659 660 ASSERT(m_propertyTable->keyCount >= 1);661 --m_propertyTable->keyCount;662 ++m_propertyTable->deletedSentinelCount;663 664 if (m_propertyTable->deletedSentinelCount * 4 >= m_propertyTable->size)665 rehashPropertyMapHashTable();666 667 checkConsistency();668 return offset;669 }670 671 void StructureID::insertIntoPropertyMapHashTable(const PropertyMapEntry& entry)672 {673 ASSERT(m_propertyTable);674 675 unsigned i = entry.key->computedHash();676 unsigned k = 0;677 678 #if DUMP_PROPERTYMAP_STATS679 ++numProbes;680 #endif681 682 while (1) {683 unsigned entryIndex = m_propertyTable->entryIndices[i & m_propertyTable->sizeMask];684 if (entryIndex == emptyEntryIndex)685 break;686 687 if (k == 0) {688 k = 1 | doubleHash(entry.key->computedHash());689 #if DUMP_PROPERTYMAP_STATS690 ++numCollisions;691 #endif692 }693 694 i += k;695 696 #if DUMP_PROPERTYMAP_STATS697 ++numRehashes;698 #endif699 }700 701 unsigned entryIndex = m_propertyTable->keyCount + 2;702 m_propertyTable->entryIndices[i & m_propertyTable->sizeMask] = entryIndex;703 m_propertyTable->entries()[entryIndex - 1] = entry;704 705 ++m_propertyTable->keyCount;706 }707 708 void StructureID::expandPropertyMapHashTable()709 {710 ASSERT(m_propertyTable);711 rehashPropertyMapHashTable(m_propertyTable->size * 2);712 }713 714 void StructureID::createPropertyMapHashTable()715 {716 const unsigned newTableSize = 16;717 718 ASSERT(!m_propertyTable);719 720 checkConsistency();721 722 m_propertyTable = static_cast<PropertyMapHashTable*>(fastZeroedMalloc(PropertyMapHashTable::allocationSize(newTableSize)));723 m_propertyTable->size = newTableSize;724 m_propertyTable->sizeMask = newTableSize - 1;725 726 checkConsistency();727 }728 729 void StructureID::rehashPropertyMapHashTable()730 {731 ASSERT(m_propertyTable);732 ASSERT(m_propertyTable->size);733 rehashPropertyMapHashTable(m_propertyTable->size);734 }735 736 void StructureID::rehashPropertyMapHashTable(unsigned newTableSize)737 {738 ASSERT(m_propertyTable);739 740 checkConsistency();741 742 PropertyMapHashTable* oldTable = m_propertyTable;743 744 m_propertyTable = static_cast<PropertyMapHashTable*>(fastZeroedMalloc(PropertyMapHashTable::allocationSize(newTableSize)));745 m_propertyTable->size = newTableSize;746 m_propertyTable->sizeMask = newTableSize - 1;747 748 unsigned lastIndexUsed = 0;749 unsigned entryCount = oldTable->keyCount + oldTable->deletedSentinelCount;750 for (unsigned i = 1; i <= entryCount; ++i) {751 if (oldTable->entries()[i].key) {752 lastIndexUsed = max(oldTable->entries()[i].index, lastIndexUsed);753 insertIntoPropertyMapHashTable(oldTable->entries()[i]);754 }755 }756 m_propertyTable->lastIndexUsed = lastIndexUsed;757 758 fastFree(oldTable);759 760 checkConsistency();761 }762 763 static int comparePropertyMapEntryIndices(const void* a, const void* b)764 {765 unsigned ia = static_cast<PropertyMapEntry* const*>(a)[0]->index;766 unsigned ib = static_cast<PropertyMapEntry* const*>(b)[0]->index;767 if (ia < ib)768 return -1;769 if (ia > ib)770 return +1;771 return 0;772 }773 774 void StructureID::getEnumerablePropertyNamesInternal(PropertyNameArray& propertyNames) const775 {776 if (!m_propertyTable)777 return;778 779 if (m_propertyTable->keyCount < tinyMapThreshold) {780 PropertyMapEntry* a[tinyMapThreshold];781 int i = 0;782 unsigned entryCount = m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount;783 for (unsigned k = 1; k <= entryCount; k++) {784 if (m_propertyTable->entries()[k].key && !(m_propertyTable->entries()[k].attributes & DontEnum)) {785 PropertyMapEntry* value = &m_propertyTable->entries()[k];786 int j;787 for (j = i - 1; j >= 0 && a[j]->index > value->index; --j)788 a[j + 1] = a[j];789 a[j + 1] = value;790 ++i;791 }792 }793 if (!propertyNames.size()) {794 for (int k = 0; k < i; ++k)795 propertyNames.addKnownUnique(a[k]->key);796 } else {797 for (int k = 0; k < i; ++k)798 propertyNames.add(a[k]->key);799 }800 801 return;802 }803 804 // Allocate a buffer to use to sort the keys.805 Vector<PropertyMapEntry*, smallMapThreshold> sortedEnumerables(m_propertyTable->keyCount);806 807 // Get pointers to the enumerable entries in the buffer.808 PropertyMapEntry** p = sortedEnumerables.data();809 unsigned entryCount = m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount;810 for (unsigned i = 1; i <= entryCount; i++) {811 if (m_propertyTable->entries()[i].key && !(m_propertyTable->entries()[i].attributes & DontEnum))812 *p++ = &m_propertyTable->entries()[i];813 }814 815 size_t enumerableCount = p - sortedEnumerables.data();816 // Sort the entries by index.817 qsort(sortedEnumerables.data(), enumerableCount, sizeof(PropertyMapEntry*), comparePropertyMapEntryIndices);818 sortedEnumerables.resize(enumerableCount);819 820 // Put the keys of the sorted entries into the list.821 if (!propertyNames.size()) {822 for (size_t i = 0; i < sortedEnumerables.size(); ++i)823 propertyNames.addKnownUnique(sortedEnumerables[i]->key);824 } else {825 for (size_t i = 0; i < sortedEnumerables.size(); ++i)826 propertyNames.add(sortedEnumerables[i]->key);827 }828 }829 830 #if DO_PROPERTYMAP_CONSTENCY_CHECK831 832 void StructureID::checkConsistency()833 {834 if (!m_propertyTable)835 return;836 837 ASSERT(m_propertyTable->size >= 16);838 ASSERT(m_propertyTable->sizeMask);839 ASSERT(m_propertyTable->size == m_propertyTable->sizeMask + 1);840 ASSERT(!(m_propertyTable->size & m_propertyTable->sizeMask));841 842 ASSERT(m_propertyTable->keyCount <= m_propertyTable->size / 2);843 ASSERT(m_propertyTable->deletedSentinelCount <= m_propertyTable->size / 4);844 845 ASSERT(m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount <= m_propertyTable->size / 2);846 847 unsigned indexCount = 0;848 unsigned deletedIndexCount = 0;849 for (unsigned a = 0; a != m_propertyTable->size; ++a) {850 unsigned entryIndex = m_propertyTable->entryIndices[a];851 if (entryIndex == emptyEntryIndex)852 continue;853 if (entryIndex == deletedSentinelIndex) {854 ++deletedIndexCount;855 continue;856 }857 ASSERT(entryIndex > deletedSentinelIndex);858 ASSERT(entryIndex - 1 <= m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount);859 ++indexCount;860 861 for (unsigned b = a + 1; b != m_propertyTable->size; ++b)862 ASSERT(m_propertyTable->entryIndices[b] != entryIndex);863 }864 ASSERT(indexCount == m_propertyTable->keyCount);865 ASSERT(deletedIndexCount == m_propertyTable->deletedSentinelCount);866 867 ASSERT(m_propertyTable->entries()[0].key == 0);868 869 unsigned nonEmptyEntryCount = 0;870 for (unsigned c = 1; c <= m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount; ++c) {871 UString::Rep* rep = m_propertyTable->entries()[c].key;872 if (!rep)873 continue;874 ++nonEmptyEntryCount;875 unsigned i = rep->computedHash();876 unsigned k = 0;877 unsigned entryIndex;878 while (1) {879 entryIndex = m_propertyTable->entryIndices[i & m_propertyTable->sizeMask];880 ASSERT(entryIndex != emptyEntryIndex);881 if (rep == m_propertyTable->entries()[entryIndex - 1].key)882 break;883 if (k == 0)884 k = 1 | doubleHash(rep->computedHash());885 i += k;886 }887 ASSERT(entryIndex == c + 1);888 }889 890 ASSERT(nonEmptyEntryCount == m_propertyTable->keyCount);891 }892 893 #endif // DO_PROPERTYMAP_CONSTENCY_CHECK894 895 // StructureIDChain896 34 897 35 StructureIDChain::StructureIDChain(StructureID* structureID)
Note:
See TracChangeset
for help on using the changeset viewer.