diff --git a/js/src/jsiter.c b/js/src/jsiter.c index c9e6bb658dc3..2ba89fb4c252 100644 --- a/js/src/jsiter.c +++ b/js/src/jsiter.c @@ -122,10 +122,43 @@ JSClass js_IteratorClass = { }; static JSBool -Iterator(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +InitNativeIterator(JSContext *cx, JSObject *iterobj, JSObject *obj, uintN flags) { + jsval state; + JSBool ok; + + JS_ASSERT(JSVAL_TO_PRIVATE(iterobj->slots[JSSLOT_CLASS]) == + &js_IteratorClass); + + /* Initialize iterobj in case of enumerate hook failure. */ + iterobj->slots[JSSLOT_PARENT] = OBJECT_TO_JSVAL(obj); + iterobj->slots[JSSLOT_ITER_STATE] = JSVAL_NULL; + iterobj->slots[JSSLOT_ITER_FLAGS] = INT_TO_JSVAL(flags); + if (!js_RegisterCloseableIterator(cx, iterobj)) + return JS_FALSE; + + ok = +#if JS_HAS_XML_SUPPORT + ((flags & JSITER_FOREACH) && OBJECT_IS_XML(cx, obj)) + ? ((JSXMLObjectOps *) obj->map->ops)-> + enumerateValues(cx, obj, JSENUMERATE_INIT, &state, NULL, NULL) + : +#endif + OBJ_ENUMERATE(cx, obj, JSENUMERATE_INIT, &state, NULL); + if (!ok) + return JS_FALSE; + + iterobj->slots[JSSLOT_ITER_STATE] = state; + return JS_TRUE; +} + +static JSBool +Iterator(JSContext *cx, JSObject *iterobj, uintN argc, jsval *argv, jsval *rval) +{ + JSObject *obj; + JSBool keyonly; + jsid id; jsval fval; - const jsid id = ATOM_TO_JSID(cx->runtime->atomState.iteratorAtom); /* XXX work around old valueOf call hidden beneath js_ValueToObject */ if (!JSVAL_IS_PRIMITIVE(argv[0])) { @@ -134,8 +167,17 @@ Iterator(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) obj = js_ValueToNonNullObject(cx, argv[0]); if (!obj) return JS_FALSE; + argv[0] = OBJECT_TO_JSVAL(obj); } + if (cx->fp->flags & JSFRAME_CONSTRUCTING) { + keyonly = JS_FALSE; + return js_ValueToBoolean(cx, argv[1], &keyonly) && + InitNativeIterator(cx, iterobj, obj, + keyonly ? 0 : JSITER_FOREACH); + } + + id = ATOM_TO_JSID(cx->runtime->atomState.iteratorAtom); return JS_GetMethodById(cx, obj, id, &obj, &fval) && js_InternalCall(cx, obj, fval, argc - 1, argv + 1, rval); } @@ -287,8 +329,6 @@ JSBool js_NewNativeIterator(JSContext *cx, JSObject *obj, uintN flags, jsval *vp) { JSObject *iterobj; - jsval state; - JSBool ok; /* * Create iterobj with a NULL parent to ensure that we use the correct @@ -302,26 +342,7 @@ js_NewNativeIterator(JSContext *cx, JSObject *obj, uintN flags, jsval *vp) /* Store iterobj in *vp to protect it from GC (callers must root vp). */ *vp = OBJECT_TO_JSVAL(iterobj); - /* Initialize iterobj in case of enumerate hook failure. */ - iterobj->slots[JSSLOT_PARENT] = OBJECT_TO_JSVAL(obj); - iterobj->slots[JSSLOT_ITER_STATE] = JSVAL_NULL; - iterobj->slots[JSSLOT_ITER_FLAGS] = INT_TO_JSVAL(flags); - if (!js_RegisterCloseableIterator(cx, iterobj)) - return JS_FALSE; - - ok = -#if JS_HAS_XML_SUPPORT - ((flags & JSITER_FOREACH) && OBJECT_IS_XML(cx, obj)) - ? ((JSXMLObjectOps *) obj->map->ops)-> - enumerateValues(cx, obj, JSENUMERATE_INIT, &state, NULL, NULL) - : -#endif - OBJ_ENUMERATE(cx, obj, JSENUMERATE_INIT, &state, NULL); - if (!ok) - return JS_FALSE; - - iterobj->slots[JSSLOT_ITER_STATE] = state; - return JS_TRUE; + return InitNativeIterator(cx, iterobj, obj, flags); } uintN @@ -363,23 +384,6 @@ js_CloseNativeIterator(JSContext *cx, JSObject *iterobj) js_CloseIteratorState(cx, iterobj); } -JSBool -js_DefaultIterator(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - JSBool keyonly; - - if (OBJ_GET_CLASS(cx, obj) == &js_IteratorClass) { - *rval = OBJECT_TO_JSVAL(obj); - return JS_TRUE; - } - - keyonly = JS_FALSE; - if (argc != 0 && !js_ValueToBoolean(cx, argv[0], &keyonly)) - return JS_FALSE; - return js_NewNativeIterator(cx, obj, keyonly ? 0 : JSITER_FOREACH, rval); -} - /* * Inline expansion of Iterator, with extra logic to constrain the result of * ToObject(v).__iterator__. @@ -402,29 +406,26 @@ js_ValueToIterator(JSContext *cx, jsval v, uintN flags) return NULL; } - arg = BOOLEAN_TO_JSVAL((flags & JSITER_FOREACH) == 0); - JS_PUSH_SINGLE_TEMP_ROOT(cx, obj, &tvr); if (!JS_GetMethodById(cx, obj, ATOM_TO_JSID(atom), &obj, &fval)) goto bad; if (JSVAL_IS_VOID(fval)) { - /* Fail over to the default native iterator, called directly. */ - if (!js_DefaultIterator(cx, obj, 1, &arg, &rval)) + /* Fail over to the default enumerating native iterator. */ + if (!js_NewNativeIterator(cx, obj, + (flags & JSITER_FOREACH) | JSITER_ENUMERATE, + &rval)) { goto bad; + } + } else { + arg = BOOLEAN_TO_JSVAL((flags & JSITER_FOREACH) == 0); + if (!js_InternalInvoke(cx, obj, fval, JSINVOKE_ITERATOR, 1, &arg, + &rval)) { + goto bad; + } if (JSVAL_IS_PRIMITIVE(rval)) goto bad_iterator; - iterobj = JSVAL_TO_OBJECT(rval); - JS_ASSERT(OBJ_GET_CLASS(cx, iterobj) == &js_IteratorClass); - iterobj->slots[JSSLOT_ITER_FLAGS] |= INT_TO_JSVAL(JSITER_ENUMERATE); - goto out; } - if (!js_InternalInvoke(cx, obj, fval, JSINVOKE_ITERATOR, 1, &arg, &rval)) - goto bad; - - if (JSVAL_IS_PRIMITIVE(rval)) - goto bad_iterator; - iterobj = JSVAL_TO_OBJECT(rval); out: diff --git a/js/src/jsiter.h b/js/src/jsiter.h index f1e312aca3f2..9c41409e8706 100644 --- a/js/src/jsiter.h +++ b/js/src/jsiter.h @@ -61,10 +61,6 @@ js_CloseNativeIterator(JSContext *cx, JSObject *iterobj); extern void js_CloseIteratorState(JSContext *cx, JSObject *iterobj); -extern JSBool -js_DefaultIterator(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval); - extern JSObject * js_ValueToIterator(JSContext *cx, jsval v, uintN flags);