No need to lookup parent/proto for iteration objects used for enumeration, and cache the last free iteration object for re-use (558058, r=brendan).

This commit is contained in:
Andreas Gal 2010-04-08 10:55:58 -07:00
parent edcf471ddb
commit b0f31bea3f
3 changed files with 37 additions and 8 deletions

View File

@ -155,6 +155,8 @@ JSThreadData::mark(JSTracer *trc)
void void
JSThreadData::purge(JSContext *cx) JSThreadData::purge(JSContext *cx)
{ {
cachedIteratorObject = NULL;
purgeGCFreeLists(); purgeGCFreeLists();
js_PurgeGSNCache(&gsnCache); js_PurgeGSNCache(&gsnCache);

View File

@ -567,6 +567,12 @@ struct JSThreadData {
jsuword nativeEnumCache[NATIVE_ENUM_CACHE_SIZE]; jsuword nativeEnumCache[NATIVE_ENUM_CACHE_SIZE];
/*
* One-entry deep cache of iterator objects. We deposit here the last
* iterator that was freed in JSOP_ENDITER.
*/
JSObject *cachedIteratorObject;
bool init(); bool init();
void finish(); void finish();
void mark(JSTracer *trc); void mark(JSTracer *trc);

View File

@ -392,15 +392,29 @@ js_ValueToIterator(JSContext *cx, uintN flags, jsval *vp)
default_iter: default_iter:
/* /*
* Fail over to the default enumerating native iterator. * Fail over to the default enumerating native iterator.
*
* Create iterobj with a NULL parent to ensure that we use the
* correct scope chain to lookup the iterator's constructor. Since
* we use the parent slot to keep track of the iterable, we must
* fix it up after.
*/ */
iterobj = js_NewObject(cx, &js_IteratorClass, NULL, NULL); if (flags & JSITER_ENUMERATE) {
if (!iterobj) /*
return false; * The iterator object for JSITER_ENUMERATE never escapes, so we
* don't care for the proper parent/proto to be set. This also
* allows us to re-use a previous iterator object that was freed
* by JSOP_ENDITER.
*/
if ((iterobj = JS_THREAD_DATA(cx)->cachedIteratorObject) != NULL) {
JS_THREAD_DATA(cx)->cachedIteratorObject = NULL;
} else {
if (!(iterobj = js_NewObjectWithGivenProto(cx, &js_IteratorClass, NULL, NULL)))
return false;
}
} else {
/*
* These objects don't escape either, but we construct a
* StopIteration exception based on the parent of the iterator
* object, so we need the correct parent here.
*/
if (!(iterobj = js_NewObject(cx, &js_IteratorClass, NULL, NULL)))
return false;
}
/* Store in *vp to protect it from GC (callers must root vp). */ /* Store in *vp to protect it from GC (callers must root vp). */
*vp = OBJECT_TO_JSVAL(iterobj); *vp = OBJECT_TO_JSVAL(iterobj);
@ -434,6 +448,13 @@ js_CloseIterator(JSContext *cx, jsval v)
if (clasp == &js_IteratorClass) { if (clasp == &js_IteratorClass) {
js_CloseNativeIterator(cx, obj); js_CloseNativeIterator(cx, obj);
/*
* Note that we don't care what kind of iterator we close here. Even if it
* is not JSITER_ENUMERATE, it is safe to re-use the object later on for a
* JSITER_ENUMERATE iteration.
*/
JS_THREAD_DATA(cx)->cachedIteratorObject = obj;
} }
#if JS_HAS_GENERATORS #if JS_HAS_GENERATORS
else if (clasp == &js_GeneratorClass) { else if (clasp == &js_GeneratorClass) {