зеркало из https://github.com/mozilla/pjs.git
Bug 443746 – Optimizing the enumeration state allocation. r=brendan
This commit is contained in:
Родитель
e6ae905711
Коммит
dbdb00824b
|
@ -1628,6 +1628,36 @@ JS_EnumerateStandardClasses(JSContext *cx, JSObject *obj)
|
|||
return JS_TRUE;
|
||||
}
|
||||
|
||||
static JSIdArray *
|
||||
NewIdArray(JSContext *cx, jsint length)
|
||||
{
|
||||
JSIdArray *ida;
|
||||
|
||||
ida = (JSIdArray *)
|
||||
JS_malloc(cx, offsetof(JSIdArray, vector) + length * sizeof(jsval));
|
||||
if (ida)
|
||||
ida->length = length;
|
||||
return ida;
|
||||
}
|
||||
|
||||
/*
|
||||
* Unlike realloc(3), this function frees ida on failure.
|
||||
*/
|
||||
static JSIdArray *
|
||||
SetIdArrayLength(JSContext *cx, JSIdArray *ida, jsint length)
|
||||
{
|
||||
JSIdArray *rida;
|
||||
|
||||
rida = (JSIdArray *)
|
||||
JS_realloc(cx, ida,
|
||||
offsetof(JSIdArray, vector) + length * sizeof(jsval));
|
||||
if (!rida)
|
||||
JS_DestroyIdArray(cx, ida);
|
||||
else
|
||||
rida->length = length;
|
||||
return rida;
|
||||
}
|
||||
|
||||
static JSIdArray *
|
||||
AddAtomToArray(JSContext *cx, JSAtom *atom, JSIdArray *ida, jsint *ip)
|
||||
{
|
||||
|
@ -1636,7 +1666,7 @@ AddAtomToArray(JSContext *cx, JSAtom *atom, JSIdArray *ida, jsint *ip)
|
|||
i = *ip;
|
||||
length = ida->length;
|
||||
if (i >= length) {
|
||||
ida = js_SetIdArrayLength(cx, ida, JS_MAX(length * 2, 8));
|
||||
ida = SetIdArrayLength(cx, ida, JS_MAX(length * 2, 8));
|
||||
if (!ida)
|
||||
return NULL;
|
||||
JS_ASSERT(i < ida->length);
|
||||
|
@ -1671,7 +1701,7 @@ JS_EnumerateResolvedStandardClasses(JSContext *cx, JSObject *obj,
|
|||
if (ida) {
|
||||
i = ida->length;
|
||||
} else {
|
||||
ida = js_NewIdArray(cx, 8);
|
||||
ida = NewIdArray(cx, 8);
|
||||
if (!ida)
|
||||
return NULL;
|
||||
i = 0;
|
||||
|
@ -1713,8 +1743,8 @@ JS_EnumerateResolvedStandardClasses(JSContext *cx, JSObject *obj,
|
|||
}
|
||||
}
|
||||
|
||||
/* Trim to exact length via js_SetIdArrayLength. */
|
||||
return js_SetIdArrayLength(cx, ida, i);
|
||||
/* Trim to exact length. */
|
||||
return SetIdArrayLength(cx, ida, i);
|
||||
}
|
||||
|
||||
#undef CLASP
|
||||
|
@ -3921,7 +3951,7 @@ JS_Enumerate(JSContext *cx, JSObject *obj)
|
|||
n = 8;
|
||||
|
||||
/* Create an array of jsids large enough to hold all the properties */
|
||||
ida = js_NewIdArray(cx, n);
|
||||
ida = NewIdArray(cx, n);
|
||||
if (!ida)
|
||||
goto error;
|
||||
|
||||
|
@ -3936,14 +3966,14 @@ JS_Enumerate(JSContext *cx, JSObject *obj)
|
|||
break;
|
||||
|
||||
if (i == ida->length) {
|
||||
ida = js_SetIdArrayLength(cx, ida, ida->length * 2);
|
||||
ida = SetIdArrayLength(cx, ida, ida->length * 2);
|
||||
if (!ida)
|
||||
goto error;
|
||||
vector = &ida->vector[0];
|
||||
}
|
||||
vector[i++] = id;
|
||||
}
|
||||
return js_SetIdArrayLength(cx, ida, i);
|
||||
return SetIdArrayLength(cx, ida, i);
|
||||
|
||||
error:
|
||||
if (iter_state != JSVAL_NULL)
|
||||
|
|
|
@ -164,16 +164,6 @@ typedef struct JSPropertyTreeEntry {
|
|||
JSScopeProperty *child;
|
||||
} JSPropertyTreeEntry;
|
||||
|
||||
/*
|
||||
* Private type used to enumerate properties of a native JS object.
|
||||
*/
|
||||
struct JSNativeEnumerator {
|
||||
jsint next_index; /* index into jsid array */
|
||||
JSIdArray *ida; /* all property ids in enumeration */
|
||||
JSNativeEnumerator *next; /* double-linked list support */
|
||||
JSNativeEnumerator **prevp;
|
||||
};
|
||||
|
||||
typedef struct JSSetSlotRequest JSSetSlotRequest;
|
||||
|
||||
struct JSSetSlotRequest {
|
||||
|
|
207
js/src/jsobj.cpp
207
js/src/jsobj.cpp
|
@ -4126,31 +4126,19 @@ out:
|
|||
return JS_TRUE;
|
||||
}
|
||||
|
||||
JSIdArray *
|
||||
js_NewIdArray(JSContext *cx, jsint length)
|
||||
{
|
||||
JSIdArray *ida;
|
||||
|
||||
ida = (JSIdArray *)
|
||||
JS_malloc(cx, sizeof(JSIdArray) + (length-1) * sizeof(jsval));
|
||||
if (ida)
|
||||
ida->length = length;
|
||||
return ida;
|
||||
}
|
||||
|
||||
JSIdArray *
|
||||
js_SetIdArrayLength(JSContext *cx, JSIdArray *ida, jsint length)
|
||||
{
|
||||
JSIdArray *rida;
|
||||
|
||||
rida = (JSIdArray *)
|
||||
JS_realloc(cx, ida, sizeof(JSIdArray) + (length-1) * sizeof(jsval));
|
||||
if (!rida)
|
||||
JS_DestroyIdArray(cx, ida);
|
||||
else
|
||||
rida->length = length;
|
||||
return rida;
|
||||
}
|
||||
/*
|
||||
* Private type used to enumerate properties of a native JS object. It is not
|
||||
* allocated when there are no enumerable properties in the object. Instead
|
||||
* for empty enumerators the code uses JSVAL_ZERO as the enumeration state.
|
||||
*/
|
||||
struct JSNativeEnumerator {
|
||||
uint32 cursor; /* index into ids array, runs from
|
||||
length down to 0 */
|
||||
uint32 length; /* length of ids array */
|
||||
JSNativeEnumerator *next; /* double-linked list support */
|
||||
JSNativeEnumerator **prevp;
|
||||
jsid ids[1]; /* enumeration id array */
|
||||
};
|
||||
|
||||
/*
|
||||
* This function is used to enumerate the properties of native JSObjects
|
||||
|
@ -4161,17 +4149,14 @@ JSBool
|
|||
js_Enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
|
||||
jsval *statep, jsid *idp)
|
||||
{
|
||||
JSRuntime *rt;
|
||||
JSObject *proto;
|
||||
JSClass *clasp;
|
||||
JSEnumerateOp enumerate;
|
||||
JSScopeProperty *sprop, *lastProp;
|
||||
jsint i, length;
|
||||
JSNativeEnumerator *ne;
|
||||
uint32 length;
|
||||
JSScope *scope;
|
||||
JSIdArray *ida;
|
||||
JSNativeEnumerator *state;
|
||||
JSScopeProperty *sprop;
|
||||
jsid *ids;
|
||||
|
||||
rt = cx->runtime;
|
||||
clasp = OBJ_GET_CLASS(cx, obj);
|
||||
enumerate = clasp->enumerate;
|
||||
if (clasp->flags & JSCLASS_NEW_ENUMERATE) {
|
||||
|
@ -4183,32 +4168,30 @@ js_Enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
|
|||
case JSENUMERATE_INIT:
|
||||
if (!enumerate(cx, obj))
|
||||
return JS_FALSE;
|
||||
length = 0;
|
||||
|
||||
/*
|
||||
* The set of all property ids is pre-computed when the iterator
|
||||
* is initialized so as to avoid problems with properties being
|
||||
* deleted during the iteration.
|
||||
* The set of all property ids is pre-computed when the iterator is
|
||||
* initialized to avoid problems caused by properties being deleted
|
||||
* during the iteration.
|
||||
*
|
||||
* Use a do-while(0) loop to avoid too many nested ifs. If ne is null
|
||||
* after the loop, it indicates an empty enumerator.
|
||||
*/
|
||||
ne = NULL;
|
||||
length = 0;
|
||||
JS_LOCK_OBJ(cx, obj);
|
||||
scope = OBJ_SCOPE(obj);
|
||||
do {
|
||||
/*
|
||||
* If this object shares a scope with its prototype, don't
|
||||
* enumerate its properties. Otherwise they will be enumerated
|
||||
* a second time when the prototype object is enumerated.
|
||||
*/
|
||||
if (scope->object != obj)
|
||||
break;
|
||||
|
||||
/*
|
||||
* If this object shares a scope with its prototype, don't enumerate
|
||||
* its properties. Otherwise they will be enumerated a second time
|
||||
* when the prototype object is enumerated.
|
||||
*/
|
||||
proto = OBJ_GET_PROTO(cx, obj);
|
||||
if (proto && scope == OBJ_SCOPE(proto)) {
|
||||
ida = js_NewIdArray(cx, 0);
|
||||
if (!ida) {
|
||||
JS_UNLOCK_OBJ(cx, obj);
|
||||
return JS_FALSE;
|
||||
}
|
||||
} else {
|
||||
/* Object has a private scope; Enumerate all props in scope. */
|
||||
for (sprop = lastProp = SCOPE_LAST_PROP(scope); sprop;
|
||||
sprop = sprop->parent) {
|
||||
/* Count all enumerable properties in object's scope. */
|
||||
for (sprop = SCOPE_LAST_PROP(scope); sprop; sprop = sprop->parent) {
|
||||
if ((sprop->attrs & JSPROP_ENUMERATE) &&
|
||||
!(sprop->flags & SPROP_IS_ALIAS) &&
|
||||
(!SCOPE_HAD_MIDDLE_DELETE(scope) ||
|
||||
|
@ -4216,70 +4199,70 @@ js_Enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
|
|||
length++;
|
||||
}
|
||||
}
|
||||
ida = js_NewIdArray(cx, length);
|
||||
if (!ida) {
|
||||
JS_UNLOCK_OBJ(cx, obj);
|
||||
if (length == 0)
|
||||
break;
|
||||
|
||||
ne = (JSNativeEnumerator *)
|
||||
JS_malloc(cx, offsetof(JSNativeEnumerator, ids) +
|
||||
length * sizeof(jsid));
|
||||
if (!ne) {
|
||||
JS_UNLOCK_SCOPE(cx, scope);
|
||||
return JS_FALSE;
|
||||
}
|
||||
i = length;
|
||||
for (sprop = lastProp; sprop; sprop = sprop->parent) {
|
||||
ne->cursor = length;
|
||||
ne->length = length;
|
||||
ids = ne->ids;
|
||||
for (sprop = SCOPE_LAST_PROP(scope); sprop; sprop = sprop->parent) {
|
||||
if ((sprop->attrs & JSPROP_ENUMERATE) &&
|
||||
!(sprop->flags & SPROP_IS_ALIAS) &&
|
||||
(!SCOPE_HAD_MIDDLE_DELETE(scope) ||
|
||||
SCOPE_HAS_PROPERTY(scope, sprop))) {
|
||||
JS_ASSERT(i > 0);
|
||||
ida->vector[--i] = sprop->id;
|
||||
JS_ASSERT(ids < ne->ids + length);
|
||||
*ids++ = sprop->id;
|
||||
}
|
||||
}
|
||||
}
|
||||
JS_UNLOCK_OBJ(cx, obj);
|
||||
JS_ASSERT(ids == ne->ids + length);
|
||||
} while (0);
|
||||
JS_UNLOCK_SCOPE(cx, scope);
|
||||
|
||||
state = (JSNativeEnumerator *)JS_malloc(cx, sizeof(JSNativeEnumerator));
|
||||
if (!state) {
|
||||
JS_DestroyIdArray(cx, ida);
|
||||
return JS_FALSE;
|
||||
}
|
||||
state->ida = ida;
|
||||
state->next_index = 0;
|
||||
|
||||
JS_LOCK_RUNTIME(rt);
|
||||
state->next = rt->nativeEnumerators;
|
||||
if (state->next)
|
||||
state->next->prevp = &state->next;
|
||||
state->prevp = &rt->nativeEnumerators;
|
||||
*state->prevp = state;
|
||||
JS_UNLOCK_RUNTIME(rt);
|
||||
|
||||
*statep = PRIVATE_TO_JSVAL(state);
|
||||
if (idp)
|
||||
*idp = INT_TO_JSVAL(length);
|
||||
if (!ne) {
|
||||
JS_ASSERT(length == 0);
|
||||
*statep = JSVAL_ZERO;
|
||||
} else {
|
||||
JS_ASSERT(length != 0);
|
||||
JS_LOCK_GC(cx->runtime);
|
||||
ne->next = cx->runtime->nativeEnumerators;
|
||||
if (ne->next)
|
||||
ne->next->prevp = &ne->next;
|
||||
ne->prevp = &cx->runtime->nativeEnumerators;
|
||||
*ne->prevp = ne;
|
||||
JS_UNLOCK_GC(cx->runtime);
|
||||
*statep = PRIVATE_TO_JSVAL(ne);
|
||||
}
|
||||
break;
|
||||
|
||||
case JSENUMERATE_NEXT:
|
||||
state = (JSNativeEnumerator *) JSVAL_TO_PRIVATE(*statep);
|
||||
ida = state->ida;
|
||||
length = ida->length;
|
||||
if (state->next_index != length) {
|
||||
*idp = ida->vector[state->next_index++];
|
||||
break;
|
||||
}
|
||||
/* FALL THROUGH */
|
||||
|
||||
case JSENUMERATE_DESTROY:
|
||||
state = (JSNativeEnumerator *) JSVAL_TO_PRIVATE(*statep);
|
||||
|
||||
JS_LOCK_RUNTIME(rt);
|
||||
JS_ASSERT(rt->nativeEnumerators);
|
||||
JS_ASSERT(*state->prevp == state);
|
||||
if (state->next) {
|
||||
JS_ASSERT(state->next->prevp == &state->next);
|
||||
state->next->prevp = state->prevp;
|
||||
if (*statep != JSVAL_ZERO) {
|
||||
ne = (JSNativeEnumerator *) JSVAL_TO_PRIVATE(*statep);
|
||||
JS_ASSERT(ne->length >= 1);
|
||||
if (ne->cursor != 0 && enum_op == JSENUMERATE_NEXT) {
|
||||
*idp = ne->ids[--ne->cursor];
|
||||
break;
|
||||
}
|
||||
JS_LOCK_GC(cx->runtime);
|
||||
JS_ASSERT(cx->runtime->nativeEnumerators);
|
||||
JS_ASSERT(*ne->prevp == ne);
|
||||
if (ne->next) {
|
||||
JS_ASSERT(ne->next->prevp == &ne->next);
|
||||
ne->next->prevp = ne->prevp;
|
||||
}
|
||||
*ne->prevp = ne->next;
|
||||
JS_UNLOCK_GC(cx->runtime);
|
||||
JS_free(cx, ne);
|
||||
}
|
||||
*state->prevp = state->next;
|
||||
JS_UNLOCK_RUNTIME(rt);
|
||||
|
||||
JS_DestroyIdArray(cx, state->ida);
|
||||
JS_free(cx, state);
|
||||
*statep = JSVAL_NULL;
|
||||
break;
|
||||
}
|
||||
|
@ -4289,22 +4272,16 @@ js_Enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
|
|||
void
|
||||
js_TraceNativeEnumerators(JSTracer *trc)
|
||||
{
|
||||
JSNativeEnumerator *state;
|
||||
jsid *cursor, *end, id;
|
||||
JSNativeEnumerator *ne;
|
||||
jsid *cursor, *end;
|
||||
|
||||
state = trc->context->runtime->nativeEnumerators;
|
||||
if (!state)
|
||||
return;
|
||||
|
||||
do {
|
||||
JS_ASSERT(*state->prevp == state);
|
||||
cursor = state->ida->vector;
|
||||
end = cursor + state->ida->length;
|
||||
for (; cursor != end; ++cursor) {
|
||||
id = *cursor;
|
||||
TRACE_ID(trc, id);
|
||||
}
|
||||
} while ((state = state->next) != NULL);
|
||||
for (ne = trc->context->runtime->nativeEnumerators; ne; ne = ne->next) {
|
||||
JS_ASSERT(ne->length >= 1);
|
||||
JS_ASSERT(*ne->prevp == ne);
|
||||
end = ne->ids + ne->length;
|
||||
for (cursor = ne->ids; cursor != end; ++cursor)
|
||||
TRACE_ID(trc, *cursor);
|
||||
}
|
||||
}
|
||||
|
||||
JSBool
|
||||
|
|
|
@ -607,15 +607,6 @@ js_DeleteProperty(JSContext *cx, JSObject *obj, jsid id, jsval *rval);
|
|||
extern JSBool
|
||||
js_DefaultValue(JSContext *cx, JSObject *obj, JSType hint, jsval *vp);
|
||||
|
||||
extern JSIdArray *
|
||||
js_NewIdArray(JSContext *cx, jsint length);
|
||||
|
||||
/*
|
||||
* Unlike realloc(3), this function frees ida on failure.
|
||||
*/
|
||||
extern JSIdArray *
|
||||
js_SetIdArrayLength(JSContext *cx, JSIdArray *ida, jsint length);
|
||||
|
||||
extern JSBool
|
||||
js_Enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
|
||||
jsval *statep, jsid *idp);
|
||||
|
|
Загрузка…
Ссылка в новой задаче