void PropertyMap::put(const Identifier &name, JSValue *value, int attributes, bool roCheck) { assert(!name.isNull()); assert(value != 0); checkConsistency(); UString::Rep *rep = name._ustring.rep(); #if DEBUG_PROPERTIES printf("adding property %s, attributes = 0x%08x (", name.ascii(), attributes); printAttributes(attributes); printf(")\n"); #endif #if USE_SINGLE_ENTRY if (!_table) { UString::Rep *key = _singleEntry.key; if (key) { if (rep == key && !(roCheck && (_singleEntry.attributes & ReadOnly))) { _singleEntry.value = value; return; } } else { rep->ref(); _singleEntry.key = rep; _singleEntry.value = value; _singleEntry.attributes = static_cast<short>(attributes); checkConsistency(); return; } } #endif if (!_table || _table->keyCount * 2 >= _table->size) expand(); unsigned h = rep->hash(); int sizeMask = _table->sizeMask; Entry *entries = _table->entries; int i = h & sizeMask; int k = 0; bool foundDeletedElement = false; int deletedElementIndex = 0; /* initialize to make the compiler happy */ #if DUMP_STATISTICS ++numProbes; numCollisions += entries[i].key && entries[i].key != rep; #endif while (UString::Rep *key = entries[i].key) { if (rep == key) { if (roCheck && (_table->entries[i].attributes & ReadOnly)) return; // Put a new value in an existing hash table entry. entries[i].value = value; // Attributes are intentionally not updated. return; } // If we find the deleted-element sentinel, remember it for use later. if (key == deletedSentinel() && !foundDeletedElement) { foundDeletedElement = true; deletedElementIndex = i; } if (k == 0) k = 1 | (h % sizeMask); i = (i + k) & sizeMask; #if DUMP_STATISTICS ++numRehashes; #endif } // Use either the deleted element or the 0 at the end of the chain. if (foundDeletedElement) { i = deletedElementIndex; --_table->sentinelCount; } // Create a new hash table entry. rep->ref(); entries[i].key = rep; entries[i].value = value; entries[i].attributes = static_cast<short>(attributes); entries[i].index = ++_table->lastIndexUsed; ++_table->keyCount; checkConsistency(); }
size_t Structure::put(const Identifier& propertyName, unsigned attributes) { ASSERT(!propertyName.isNull()); ASSERT(get(propertyName) == notFound); checkConsistency(); UString::Rep* rep = propertyName._ustring.rep(); if (!m_propertyTable) createPropertyMapHashTable(); // FIXME: Consider a fast case for tables with no deleted sentinels. unsigned i = rep->computedHash(); unsigned k = 0; bool foundDeletedElement = false; unsigned deletedElementIndex = 0; // initialize to make the compiler happy #if DUMP_PROPERTYMAP_STATS ++numProbes; #endif while (1) { unsigned entryIndex = m_propertyTable->entryIndices[i & m_propertyTable->sizeMask]; if (entryIndex == emptyEntryIndex) break; if (entryIndex == deletedSentinelIndex) { // If we find a deleted-element sentinel, remember it for use later. if (!foundDeletedElement) { foundDeletedElement = true; deletedElementIndex = i; } } if (k == 0) { k = 1 | doubleHash(rep->computedHash()); #if DUMP_PROPERTYMAP_STATS ++numCollisions; #endif } i += k; #if DUMP_PROPERTYMAP_STATS ++numRehashes; #endif } // Figure out which entry to use. unsigned entryIndex = m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount + 2; if (foundDeletedElement) { i = deletedElementIndex; --m_propertyTable->deletedSentinelCount; // Since we're not making the table bigger, we can't use the entry one past // the end that we were planning on using, so search backwards for the empty // slot that we can use. We know it will be there because we did at least one // deletion in the past that left an entry empty. while (m_propertyTable->entries()[--entryIndex - 1].key) { } } // Create a new hash table entry. m_propertyTable->entryIndices[i & m_propertyTable->sizeMask] = entryIndex; // Create a new hash table entry. rep->ref(); m_propertyTable->entries()[entryIndex - 1].key = rep; m_propertyTable->entries()[entryIndex - 1].attributes = attributes; m_propertyTable->entries()[entryIndex - 1].index = ++m_propertyTable->lastIndexUsed; unsigned newOffset; if (m_propertyTable->deletedOffsets && !m_propertyTable->deletedOffsets->isEmpty()) { newOffset = m_propertyTable->deletedOffsets->last(); m_propertyTable->deletedOffsets->removeLast(); } else newOffset = m_propertyTable->keyCount; m_propertyTable->entries()[entryIndex - 1].offset = newOffset; ++m_propertyTable->keyCount; if ((m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount) * 2 >= m_propertyTable->size) expandPropertyMapHashTable(); checkConsistency(); return newOffset; }
JSStringRef JSStringRetain(JSStringRef string) { JSLock lock; UString::Rep* rep = toJS(string); return toRef(rep->ref()); }