Give JSScope a proper flags member, without increasing its size (part of 196097, r=shaver).

This commit is contained in:
brendan%mozilla.org 2003-03-11 20:30:55 +00:00
Родитель d0f8bd9264
Коммит 67444da79d
3 изменённых файлов: 34 добавлений и 38 удалений

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

@ -1109,7 +1109,7 @@ JS_GetObjectTotalSize(JSContext *cx, JSObject *obj)
scope = OBJ_SCOPE(obj); scope = OBJ_SCOPE(obj);
if (scope->object == obj) { if (scope->object == obj) {
nbytes += sizeof *scope; nbytes += sizeof *scope;
nbytes += JS_BIT(scope->sizeLog2) * sizeof(JSScopeProperty *); nbytes += SCOPE_CAPACITY(scope) * sizeof(JSScopeProperty *);
} }
} }
return nbytes; return nbytes;

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

@ -90,7 +90,6 @@ static void
InitMinimalScope(JSScope *scope) InitMinimalScope(JSScope *scope)
{ {
scope->hashShift = JS_DHASH_BITS - MIN_SCOPE_SIZE_LOG2; scope->hashShift = JS_DHASH_BITS - MIN_SCOPE_SIZE_LOG2;
scope->sizeLog2 = MIN_SCOPE_SIZE_LOG2;
scope->entryCount = scope->removedCount = 0; scope->entryCount = scope->removedCount = 0;
scope->table = NULL; scope->table = NULL;
scope->lastProp = NULL; scope->lastProp = NULL;
@ -111,7 +110,9 @@ CreateScopeTable(JSScope *scope)
* overallocating to hold at least twice the current population. * overallocating to hold at least twice the current population.
*/ */
sizeLog2 = JS_CeilingLog2(2 * scope->entryCount); sizeLog2 = JS_CeilingLog2(2 * scope->entryCount);
scope->hashShift = JS_DHASH_BITS - sizeLog2;
} else { } else {
JS_ASSERT(scope->hashShift == JS_DHASH_BITS - MIN_SCOPE_SIZE_LOG2);
sizeLog2 = MIN_SCOPE_SIZE_LOG2; sizeLog2 = MIN_SCOPE_SIZE_LOG2;
} }
@ -120,7 +121,6 @@ CreateScopeTable(JSScope *scope)
if (!scope->table) if (!scope->table)
return JS_FALSE; return JS_FALSE;
scope->sizeLog2 = sizeLog2;
scope->hashShift = JS_DHASH_BITS - sizeLog2; scope->hashShift = JS_DHASH_BITS - sizeLog2;
for (sprop = scope->lastProp; sprop; sprop = sprop->parent) { for (sprop = scope->lastProp; sprop; sprop = sprop->parent) {
spp = js_SearchScope(scope, sprop->id, JS_TRUE); spp = js_SearchScope(scope, sprop->id, JS_TRUE);
@ -141,6 +141,7 @@ js_NewScope(JSContext *cx, jsrefcount nrefs, JSObjectOps *ops, JSClass *clasp,
js_InitObjectMap(&scope->map, nrefs, ops, clasp); js_InitObjectMap(&scope->map, nrefs, ops, clasp);
scope->object = obj; scope->object = obj;
scope->flags = 0;
InitMinimalScope(scope); InitMinimalScope(scope);
#ifdef JS_THREADSAFE #ifdef JS_THREADSAFE
@ -279,7 +280,7 @@ js_SearchScope(JSScope *scope, jsid id, JSBool adding)
} }
/* Collision: double hash. */ /* Collision: double hash. */
sizeLog2 = scope->sizeLog2; sizeLog2 = JS_DHASH_BITS - hashShift;
hash2 = SCOPE_HASH2(hash0, sizeLog2, hashShift); hash2 = SCOPE_HASH2(hash0, sizeLog2, hashShift);
sizeMask = JS_BITMASK(sizeLog2); sizeMask = JS_BITMASK(sizeLog2);
@ -331,7 +332,7 @@ ChangeScope(JSContext *cx, JSScope *scope, int change)
JSScopeProperty **table, **oldtable, **spp, **oldspp, *sprop; JSScopeProperty **table, **oldtable, **spp, **oldspp, *sprop;
/* Grow, shrink, or compress by changing scope->table. */ /* Grow, shrink, or compress by changing scope->table. */
oldlog2 = scope->sizeLog2; oldlog2 = JS_DHASH_BITS - scope->hashShift;
newlog2 = oldlog2 + change; newlog2 = oldlog2 + change;
oldsize = JS_BIT(oldlog2); oldsize = JS_BIT(oldlog2);
newsize = JS_BIT(newlog2); newsize = JS_BIT(newlog2);
@ -344,7 +345,6 @@ ChangeScope(JSContext *cx, JSScope *scope, int change)
/* Now that we have a new table allocated, update scope members. */ /* Now that we have a new table allocated, update scope members. */
scope->hashShift = JS_DHASH_BITS - newlog2; scope->hashShift = JS_DHASH_BITS - newlog2;
scope->sizeLog2 = newlog2;
scope->removedCount = 0; scope->removedCount = 0;
oldtable = scope->table; oldtable = scope->table;
scope->table = table; scope->table = table;
@ -810,7 +810,7 @@ CheckAncestorLine(JSScope *scope, JSBool sparse)
JS_ASSERT(SCOPE_HAS_PROPERTY(scope, ancestorLine)); JS_ASSERT(SCOPE_HAS_PROPERTY(scope, ancestorLine));
entryCount = 0; entryCount = 0;
size = JS_BIT(scope->sizeLog2); size = SCOPE_CAPACITY(scope);
start = scope->table; start = scope->table;
for (spp = start, end = start + size; spp < end; spp++) { for (spp = start, end = start + size; spp < end; spp++) {
sprop = SPROP_FETCH(spp); sprop = SPROP_FETCH(spp);
@ -869,7 +869,7 @@ js_AddScopeProperty(JSContext *cx, JSScope *scope, jsid id,
if (!sprop) { if (!sprop) {
/* Check whether we need to grow, if the load factor is >= .75. */ /* Check whether we need to grow, if the load factor is >= .75. */
JS_ASSERT(JS_IS_SCOPE_LOCKED(scope)); JS_ASSERT(JS_IS_SCOPE_LOCKED(scope));
size = JS_BIT(scope->sizeLog2); size = SCOPE_CAPACITY(scope);
if (scope->entryCount + scope->removedCount >= size - (size >> 2)) { if (scope->entryCount + scope->removedCount >= size - (size >> 2)) {
if (scope->removedCount >= size >> 2) { if (scope->removedCount >= size >> 2) {
METER(compresses); METER(compresses);
@ -986,7 +986,7 @@ js_AddScopeProperty(JSContext *cx, JSScope *scope, jsid id,
splen = scope->entryCount; splen = scope->entryCount;
if (splen == 0) { if (splen == 0) {
scope->lastProp = NULL; JS_ASSERT(scope->lastProp == NULL);
} else { } else {
/* /*
* Enumerate live entries in scope->table using a temporary * Enumerate live entries in scope->table using a temporary
@ -1075,6 +1075,8 @@ js_AddScopeProperty(JSContext *cx, JSScope *scope, jsid id,
CHECK_ANCESTOR_LINE(scope, JS_FALSE); CHECK_ANCESTOR_LINE(scope, JS_FALSE);
JS_RUNTIME_METER(cx->runtime, middleDeleteFixups); JS_RUNTIME_METER(cx->runtime, middleDeleteFixups);
} }
SCOPE_CLR_MIDDLE_DELETE(scope);
} }
/* /*
@ -1165,12 +1167,12 @@ fail_overwrite:
if (!sprop) { if (!sprop) {
sprop = SCOPE_LAST_PROP(scope); sprop = SCOPE_LAST_PROP(scope);
if (overwriting->parent == sprop) { if (overwriting->parent == sprop) {
SCOPE_SET_LAST_PROP(scope, overwriting); scope->lastProp = overwriting;
} else { } else {
sprop = GetPropertyTreeChild(cx, sprop, overwriting); sprop = GetPropertyTreeChild(cx, sprop, overwriting);
if (sprop) { if (sprop) {
JS_ASSERT(sprop != overwriting); JS_ASSERT(sprop != overwriting);
SCOPE_SET_LAST_PROP(scope, sprop); scope->lastProp = sprop;
} }
overwriting = sprop; overwriting = sprop;
} }
@ -1241,7 +1243,7 @@ js_ChangeScopePropertyAttrs(JSContext *cx, JSScope *scope,
if (scope->table) if (scope->table)
SPROP_STORE_PRESERVING_COLLISION(spp, newsprop); SPROP_STORE_PRESERVING_COLLISION(spp, newsprop);
SCOPE_SET_LAST_PROP(scope, newsprop); scope->lastProp = newsprop;
CHECK_ANCESTOR_LINE(scope, JS_TRUE); CHECK_ANCESTOR_LINE(scope, JS_TRUE);
} }
} else { } else {
@ -1309,7 +1311,7 @@ js_RemoveScopeProperty(JSContext *cx, JSScope *scope, jsid id)
scope->entryCount--; scope->entryCount--;
JS_RUNTIME_UNMETER(cx->runtime, liveScopeProps); JS_RUNTIME_UNMETER(cx->runtime, liveScopeProps);
/* Update scope->lastProp directly, or set its deferred update tag. */ /* Update scope->lastProp directly, or set its deferred update flag. */
if (sprop == SCOPE_LAST_PROP(scope)) { if (sprop == SCOPE_LAST_PROP(scope)) {
do { do {
SCOPE_REMOVE_LAST_PROP(scope); SCOPE_REMOVE_LAST_PROP(scope);
@ -1323,7 +1325,7 @@ js_RemoveScopeProperty(JSContext *cx, JSScope *scope, jsid id)
CHECK_ANCESTOR_LINE(scope, JS_TRUE); CHECK_ANCESTOR_LINE(scope, JS_TRUE);
/* Last, consider shrinking scope's table if its load factor is <= .25. */ /* Last, consider shrinking scope's table if its load factor is <= .25. */
size = JS_BIT(scope->sizeLog2); size = SCOPE_CAPACITY(scope);
if (size > MIN_SCOPE_SIZE && scope->entryCount <= size >> 2) { if (size > MIN_SCOPE_SIZE && scope->entryCount <= size >> 2) {
METER(shrinks); METER(shrinks);
(void) ChangeScope(cx, scope, -1); (void) ChangeScope(cx, scope, -1);
@ -1343,6 +1345,7 @@ js_ClearScope(JSContext *cx, JSScope *scope)
if (scope->table) if (scope->table)
free(scope->table); free(scope->table);
SCOPE_CLR_MIDDLE_DELETE(scope);
InitMinimalScope(scope); InitMinimalScope(scope);
} }

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

@ -106,10 +106,8 @@
* What if we add Y again? X->Y->Z->Y is wrong and we'll enumerate Y twice. * What if we add Y again? X->Y->Z->Y is wrong and we'll enumerate Y twice.
* Therefore we must fork in such a case, if not earlier. Because delete is * Therefore we must fork in such a case, if not earlier. Because delete is
* "bursty", we should not fork eagerly. Delaying a fork till we are at risk * "bursty", we should not fork eagerly. Delaying a fork till we are at risk
* of adding Y after it was deleted already requires a flag in the JSScope, at * of adding Y after it was deleted already requires a flag in the JSScope, to
* least. So we tag the scope->lastProp pointer with SCOPE_MIDDLE_DELETE_TAG, * wit, SCOPE_MIDDLE_DELETE.
* to avoid expanding the size of JSScope, and to penalize only the code that
* already must care about forking (js_{Add,Remove}ScopeProperty).
* *
* What about thread safety? If the property tree operations done by requests * What about thread safety? If the property tree operations done by requests
* are find-node and insert-node, then the only hazard is duplicate insertion. * are find-node and insert-node, then the only hazard is duplicate insertion.
@ -198,8 +196,8 @@
struct JSScope { struct JSScope {
JSObjectMap map; /* base class state */ JSObjectMap map; /* base class state */
JSObject *object; /* object that owns this scope */ JSObject *object; /* object that owns this scope */
uint16 flags; /* flags, see below */
int16 hashShift; /* multiplicative hash shift */ int16 hashShift; /* multiplicative hash shift */
int16 sizeLog2; /* log2(table size) */
uint32 entryCount; /* number of entries in table */ uint32 entryCount; /* number of entries in table */
uint32 removedCount; /* removed entry sentinels in table */ uint32 removedCount; /* removed entry sentinels in table */
JSScopeProperty **table; /* table of ptrs to shared tree nodes */ JSScopeProperty **table; /* table of ptrs to shared tree nodes */
@ -220,28 +218,23 @@ struct JSScope {
#define OBJ_SCOPE(obj) ((JSScope *)(obj)->map) #define OBJ_SCOPE(obj) ((JSScope *)(obj)->map)
#define SCOPE_MIDDLE_DELETE_TAG ((jsuword)1) /* By definition, hashShift = JS_DHASH_BITS - log2(capacity). */
#define SCOPE_LAST_PROP_WORD(scope) ((jsuword)(scope)->lastProp) #define SCOPE_CAPACITY(scope) JS_BIT(JS_DHASH_BITS-(scope)->hashShift)
#define SCOPE_LAST_PROP(scope) \ /* Scope flags and some macros to hide them from other files than jsscope.c. */
((JSScopeProperty *) (SCOPE_LAST_PROP_WORD(scope) & \ #define SCOPE_MIDDLE_DELETE 0x0001
~SCOPE_MIDDLE_DELETE_TAG))
#define SCOPE_HAD_MIDDLE_DELETE(scope) \ #define SCOPE_HAD_MIDDLE_DELETE(scope) ((scope)->flags & SCOPE_MIDDLE_DELETE)
(SCOPE_LAST_PROP_WORD(scope) & SCOPE_MIDDLE_DELETE_TAG) #define SCOPE_SET_MIDDLE_DELETE(scope) ((scope)->flags |= SCOPE_MIDDLE_DELETE)
#define SCOPE_CLR_MIDDLE_DELETE(scope) ((scope)->flags &= ~SCOPE_MIDDLE_DELETE)
#define SCOPE_SET_LAST_PROP(scope, sprop) \ /*
((scope)->lastProp = (JSScopeProperty *) \ * A little information hiding for scope->lastProp, in case it ever becomes
((jsuword) (sprop) | \ * a tagged pointer again.
SCOPE_HAD_MIDDLE_DELETE(scope))) */
#define SCOPE_LAST_PROP(scope) ((scope)->lastProp)
#define SCOPE_REMOVE_LAST_PROP(scope) \ #define SCOPE_REMOVE_LAST_PROP(scope) ((scope)->lastProp = \
SCOPE_SET_LAST_PROP(scope, SCOPE_LAST_PROP(scope)->parent) (scope)->lastProp->parent)
#define SCOPE_SET_MIDDLE_DELETE(scope) \
((scope)->lastProp = (JSScopeProperty *) \
(SCOPE_LAST_PROP_WORD(scope) | \
SCOPE_MIDDLE_DELETE_TAG))
struct JSScopeProperty { struct JSScopeProperty {
jsid id; /* int-tagged jsval/untagged JSAtom* */ jsid id; /* int-tagged jsval/untagged JSAtom* */