зеркало из https://github.com/mozilla/gecko-dev.git
Give JSScope a proper flags member, without increasing its size (part of 196097, r=shaver).
This commit is contained in:
Родитель
d0f8bd9264
Коммит
67444da79d
|
@ -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* */
|
||||||
|
|
Загрузка…
Ссылка в новой задаче