Fix ChangeTable and how it's called (74883, r=gordon, sr=waterson, mcafee approved).

This commit is contained in:
brendan%mozilla.org 2001-05-16 21:41:52 +00:00
Родитель d8636b0c07
Коммит 06f0438169
2 изменённых файлов: 77 добавлений и 98 удалений

Просмотреть файл

@ -286,7 +286,7 @@ SearchTable(JSDHashTable *table, const void *key, JSDHashNumber keyHash)
}
static JSBool
ChangeTable(JSDHashTable *table, int deltaLog2, JSDHashEntryHdr **findEntry)
ChangeTable(JSDHashTable *table, int deltaLog2)
{
int oldLog2, newLog2;
uint32 oldCapacity, newCapacity;
@ -330,8 +330,6 @@ ChangeTable(JSDHashTable *table, int deltaLog2, JSDHashEntryHdr **findEntry)
JS_ASSERT(JS_DHASH_ENTRY_IS_FREE(newEntry));
moveEntry(table, oldEntry, newEntry);
newEntry->keyHash = oldEntry->keyHash;
if (findEntry && *findEntry == oldEntry)
*findEntry = newEntry;
}
oldEntryAddr += entrySize;
}
@ -343,32 +341,54 @@ ChangeTable(JSDHashTable *table, int deltaLog2, JSDHashEntryHdr **findEntry)
JS_PUBLIC_API(JSDHashEntryHdr *)
JS_DHashTableOperate(JSDHashTable *table, const void *key, JSDHashOperator op)
{
int biasedDeltaLog2;
JSDHashNumber keyHash;
JSDHashEntryHdr *entry;
uint32 size;
/*
* Usually we don't grow or shrink the table, so optimize for test-not-zero
* by biasing the deltaLog2 of -1 (shrink), 0 (compress), or 1 (grow) so that
* the biased no-change value is 0.
*/
#define DELTA_LOG2_BIAS 2
biasedDeltaLog2 = 0;
int deltaLog2;
/* Avoid 0 and 1 hash codes, they indicate free and removed entries. */
keyHash = table->ops->hashKey(table, key);
ENSURE_LIVE_KEYHASH(keyHash);
keyHash *= JS_DHASH_GOLDEN_RATIO;
entry = SearchTable(table, key, keyHash);
switch (op) {
case JS_DHASH_LOOKUP:
METER(table->stats.lookups++);
entry = SearchTable(table, key, keyHash);
break;
case JS_DHASH_ADD:
/*
* If alpha is >= .75, grow or compress the table. If key is already
* in the table, we may grow once more than necessary, but only if we
* are on the edge of being overloaded.
*/
size = JS_BIT(table->sizeLog2);
if (table->entryCount + table->removedCount >= size - (size >> 2)) {
if (table->removedCount >= size >> 2) {
METER(table->stats.compresses++);
deltaLog2 = 0;
} else {
METER(table->stats.grows++);
deltaLog2 = 1;
}
/*
* Grow or compress table, returning null if ChangeTable fails and
* falling through might claim the last free entry.
*/
if (!ChangeTable(table, deltaLog2) &&
table->entryCount + table->removedCount == size - 1) {
METER(table->stats.addFailures++);
return NULL;
}
}
/*
* Look for entry after possibly growing, so we don't have to add it,
* then skip it while growing the table and re-add it after.
*/
entry = SearchTable(table, key, keyHash);
if (JS_DHASH_ENTRY_IS_FREE(entry)) {
/* Initialize the entry, indicating that it's no longer free. */
METER(table->stats.addMisses++);
@ -376,23 +396,12 @@ JS_DHashTableOperate(JSDHashTable *table, const void *key, JSDHashOperator op)
table->ops->initEntry(table, entry, key);
entry->keyHash = keyHash;
table->entryCount++;
/* If alpha is >= .75, set biasedDeltaLog2 to trigger growth. */
size = JS_BIT(table->sizeLog2);
if (table->entryCount + table->removedCount >= size - (size >> 2)) {
if (table->removedCount >= size >> 2) {
METER(table->stats.compresses++);
biasedDeltaLog2 = 0 + DELTA_LOG2_BIAS;
} else {
METER(table->stats.grows++);
biasedDeltaLog2 = 1 + DELTA_LOG2_BIAS;
}
}
}
METER(else table->stats.addHits++);
break;
case JS_DHASH_REMOVE:
entry = SearchTable(table, key, keyHash);
if (JS_DHASH_ENTRY_IS_BUSY(entry)) {
/* Clear this entry and mark it as "removed". */
METER(table->stats.removeHits++);
@ -402,7 +411,7 @@ JS_DHashTableOperate(JSDHashTable *table, const void *key, JSDHashOperator op)
size = JS_BIT(table->sizeLog2);
if (size > JS_DHASH_MIN_SIZE && table->entryCount <= size >> 2) {
METER(table->stats.shrinks++);
biasedDeltaLog2 = -1 + DELTA_LOG2_BIAS;
(void) ChangeTable(table, -1);
}
}
METER(else table->stats.removeMisses++);
@ -411,25 +420,9 @@ JS_DHashTableOperate(JSDHashTable *table, const void *key, JSDHashOperator op)
default:
JS_ASSERT(0);
entry = NULL;
}
if (biasedDeltaLog2) {
/* Grow, compress, or shrink table, keeping entry valid if non-null. */
if (!ChangeTable(table, biasedDeltaLog2 - DELTA_LOG2_BIAS, &entry)) {
/* If we just grabbed the last free entry, undo and fail hard. */
if (op == JS_DHASH_ADD &&
table->entryCount + table->removedCount == size) {
METER(table->stats.addFailures++);
table->ops->clearEntry(table, entry);
MARK_ENTRY_FREE(entry);
table->entryCount--;
entry = NULL;
}
}
}
#undef DELTA_LOG2_BIAS
return entry;
}
@ -476,9 +469,7 @@ JS_DHashTableEnumerate(JSDHashTable *table, JSDHashEnumerator etor, void *arg)
capacity += capacity >> 1;
if (capacity < JS_DHASH_MIN_SIZE)
capacity = JS_DHASH_MIN_SIZE;
(void) ChangeTable(table,
JS_CeilingLog2(capacity) - table->sizeLog2,
NULL);
(void) ChangeTable(table, JS_CeilingLog2(capacity) - table->sizeLog2);
}
return i;
}

Просмотреть файл

@ -287,7 +287,7 @@ SearchTable(PLDHashTable *table, const void *key, PLDHashNumber keyHash)
}
static PRBool
ChangeTable(PLDHashTable *table, int deltaLog2, const void *key, PLDHashEntryHdr **findEntry)
ChangeTable(PLDHashTable *table, int deltaLog2)
{
int oldLog2, newLog2;
PRUint32 oldCapacity, newCapacity;
@ -326,16 +326,11 @@ ChangeTable(PLDHashTable *table, int deltaLog2, const void *key, PLDHashEntryHdr
for (i = 0; i < oldCapacity; i++) {
oldEntry = (PLDHashEntryHdr *)oldEntryAddr;
if (ENTRY_IS_LIVE(oldEntry)) {
newEntry = SearchTable(table,
(*findEntry == oldEntry)
? key
: getKey(table, oldEntry),
newEntry = SearchTable(table, getKey(table, oldEntry),
oldEntry->keyHash);
PR_ASSERT(PL_DHASH_ENTRY_IS_FREE(newEntry));
moveEntry(table, oldEntry, newEntry);
newEntry->keyHash = oldEntry->keyHash;
if (findEntry && *findEntry == oldEntry)
*findEntry = newEntry;
}
oldEntryAddr += entrySize;
}
@ -347,32 +342,54 @@ ChangeTable(PLDHashTable *table, int deltaLog2, const void *key, PLDHashEntryHdr
PR_IMPLEMENT(PLDHashEntryHdr *)
PL_DHashTableOperate(PLDHashTable *table, const void *key, PLDHashOperator op)
{
int biasedDeltaLog2;
PLDHashNumber keyHash;
PLDHashEntryHdr *entry;
PRUint32 size;
/*
* Usually we don't grow or shrink the table, so optimize for test-not-zero
* by biasing the deltaLog2 of -1 (shrink), 0 (compress), or 1 (grow) so that
* the biased no-change value is 0.
*/
#define DELTA_LOG2_BIAS 2
biasedDeltaLog2 = 0;
int deltaLog2;
/* Avoid 0 and 1 hash codes, they indicate free and removed entries. */
keyHash = table->ops->hashKey(table, key);
ENSURE_LIVE_KEYHASH(keyHash);
keyHash *= PL_DHASH_GOLDEN_RATIO;
entry = SearchTable(table, key, keyHash);
switch (op) {
case PL_DHASH_LOOKUP:
METER(table->stats.lookups++);
entry = SearchTable(table, key, keyHash);
break;
case PL_DHASH_ADD:
/*
* If alpha is >= .75, grow or compress the table. If key is already
* in the table, we may grow once more than necessary, but only if we
* are on the edge of being overloaded.
*/
size = PR_BIT(table->sizeLog2);
if (table->entryCount + table->removedCount >= size - (size >> 2)) {
if (table->removedCount >= size >> 2) {
METER(table->stats.compresses++);
deltaLog2 = 0;
} else {
METER(table->stats.grows++);
deltaLog2 = 1;
}
/*
* Grow or compress table, returning null if ChangeTable fails and
* falling through might claim the last free entry.
*/
if (!ChangeTable(table, deltaLog2) &&
table->entryCount + table->removedCount == size - 1) {
METER(table->stats.addFailures++);
return NULL;
}
}
/*
* Look for entry after possibly growing, so we don't have to add it,
* then skip it while growing the table and re-add it after.
*/
entry = SearchTable(table, key, keyHash);
if (PL_DHASH_ENTRY_IS_FREE(entry)) {
/* Initialize the entry, indicating that it's no longer free. */
METER(table->stats.addMisses++);
@ -380,23 +397,12 @@ PL_DHashTableOperate(PLDHashTable *table, const void *key, PLDHashOperator op)
table->ops->initEntry(table, entry, key);
entry->keyHash = keyHash;
table->entryCount++;
/* If alpha is >= .75, set biasedDeltaLog2 to trigger growth. */
size = PR_BIT(table->sizeLog2);
if (table->entryCount + table->removedCount >= size - (size >> 2)) {
if (table->removedCount >= size >> 2) {
METER(table->stats.compresses++);
biasedDeltaLog2 = 0 + DELTA_LOG2_BIAS;
} else {
METER(table->stats.grows++);
biasedDeltaLog2 = 1 + DELTA_LOG2_BIAS;
}
}
}
METER(else table->stats.addHits++);
break;
case PL_DHASH_REMOVE:
entry = SearchTable(table, key, keyHash);
if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
/* Clear this entry and mark it as "removed". */
METER(table->stats.removeHits++);
@ -406,7 +412,7 @@ PL_DHashTableOperate(PLDHashTable *table, const void *key, PLDHashOperator op)
size = PR_BIT(table->sizeLog2);
if (size > PL_DHASH_MIN_SIZE && table->entryCount <= size >> 2) {
METER(table->stats.shrinks++);
biasedDeltaLog2 = -1 + DELTA_LOG2_BIAS;
(void) ChangeTable(table, -1);
}
}
METER(else table->stats.removeMisses++);
@ -415,25 +421,9 @@ PL_DHashTableOperate(PLDHashTable *table, const void *key, PLDHashOperator op)
default:
PR_ASSERT(0);
entry = NULL;
}
if (biasedDeltaLog2) {
/* Grow, compress, or shrink table, keeping entry valid if non-null. */
if (!ChangeTable(table, biasedDeltaLog2 - DELTA_LOG2_BIAS, key, &entry)) {
/* If we just grabbed the last free entry, undo and fail hard. */
if (op == PL_DHASH_ADD &&
table->entryCount + table->removedCount == size) {
METER(table->stats.addFailures++);
table->ops->clearEntry(table, entry);
MARK_ENTRY_FREE(entry);
table->entryCount--;
entry = NULL;
}
}
}
#undef DELTA_LOG2_BIAS
return entry;
}
@ -480,9 +470,7 @@ PL_DHashTableEnumerate(PLDHashTable *table, PLDHashEnumerator etor, void *arg)
capacity += capacity >> 1;
if (capacity < PL_DHASH_MIN_SIZE)
capacity = PL_DHASH_MIN_SIZE;
(void) ChangeTable(table,
PR_CeilingLog2(capacity) - table->sizeLog2,
NULL, NULL);
(void) ChangeTable(table, PR_CeilingLog2(capacity) - table->sizeLog2);
}
return i;
}