--- a/js/src/xpconnect/src/XPCWrapper.cpp
+++ b/js/src/xpconnect/src/XPCWrapper.cpp
@@ -149,24 +149,38 @@ IteratorNext(JSContext *cx, uintN argc,
return JS_FALSE;
}
}
JS_SetReservedSlot(cx, obj, 1, INT_TO_JSVAL(idx));
return JS_TRUE;
}
-static JSClass IteratorClass = {
- "XOW iterator", JSCLASS_HAS_RESERVED_SLOTS(3),
- JS_PropertyStub, JS_PropertyStub,
- JS_PropertyStub, JS_PropertyStub,
- JS_EnumerateStub, JS_ResolveStub,
- JS_ConvertStub, IteratorFinalize,
+static JSObject *
+IteratorIterator(JSContext *, JSObject *obj, JSBool)
+{
+ return obj;
+}
- JSCLASS_NO_OPTIONAL_MEMBERS
+static JSExtendedClass IteratorClass = {
+ { "Wrapper iterator",
+ JSCLASS_HAS_RESERVED_SLOTS(3) | JSCLASS_IS_EXTENDED,
+ JS_PropertyStub, JS_PropertyStub,
+ JS_PropertyStub, JS_PropertyStub,
+ JS_EnumerateStub, JS_ResolveStub,
+ JS_ConvertStub, IteratorFinalize,
+
+ JSCLASS_NO_OPTIONAL_MEMBERS
+ },
+
+ nsnull, // equality
+ nsnull, nsnull, // innerObject/outerObject
+ IteratorIterator,
+ nsnull, // wrappedObject
+ JSCLASS_NO_RESERVED_MEMBERS
};
JSBool
RewrapObject(JSContext *cx, JSObject *scope, JSObject *obj, WrapperType hint,
jsval *vp)
{
obj = UnsafeUnwrapSecurityWrapper(cx, obj);
if (!obj) {
@@ -312,17 +326,17 @@ CreateIteratorObj(JSContext *cx, JSObjec
{
// This is rather ugly: we want to use the trick seen in Enumerate,
// where we use our wrapper's resolve hook to determine if we should
// enumerate a given property. However, we don't want to pollute the
// identifiers with a next method, so we create an object that
// delegates (via the __proto__ link) to the wrapper.
JSObject *iterObj =
- JS_NewObjectWithGivenProto(cx, &IteratorClass, tempWrapper, wrapperObj);
+ JS_NewObjectWithGivenProto(cx, &IteratorClass.base, tempWrapper, wrapperObj);
if (!iterObj) {
return nsnull;
}
js::AutoObjectRooter tvr(cx, iterObj);
// Do this sooner rather than later to avoid complications in
// IteratorFinalize.
@@ -375,17 +389,17 @@ SimpleEnumerate(JSContext *cx, JSObject
return JS_TRUE;
}
JSObject *
CreateSimpleIterator(JSContext *cx, JSObject *scope, JSBool keysonly,
JSObject *propertyContainer)
{
- JSObject *iterObj = JS_NewObjectWithGivenProto(cx, &IteratorClass,
+ JSObject *iterObj = JS_NewObjectWithGivenProto(cx, &IteratorClass.base,
propertyContainer, scope);
if (!iterObj) {
return nsnull;
}
js::AutoValueRooter tvr(cx, iterObj);
if (!propertyContainer) {
if (!JS_SetReservedSlot(cx, iterObj, 0, PRIVATE_TO_JSVAL(nsnull)) ||
--- a/js/src/xpconnect/tests/mochitest/test_wrappers.html
+++ b/js/src/xpconnect/tests/mochitest/test_wrappers.html
@@ -42,16 +42,28 @@
is(xow_answer.sort().toString(),
expected.sort().toString(),
'enumeration over XOWs walks the prototype chain');
is(xpcnw_answer.sort().toString(),
xpcnw_expected.sort().toString(),
'enumeration over XPCNWs walks the prototype chain');
+ var for_each_expected = [];
+ for each (let i in new XPCNativeWrapper(location))
+ for_each_expected.push(typeof i);
+
+ var for_each_answer = [];
+ for each (let i in Iterator(new XPCNativeWrapper(location)))
+ for_each_answer.push(typeof i);
+
+ is(for_each_answer.sort().toString(),
+ for_each_expected.sort().toString(),
+ 'wrapper iterators are properly iterators');
+
let sjow_answer = [];
let (obj = { a: 3, next:1 }) {
for (let i in XPCSafeJSObjectWrapper({ __proto__: obj}))
sjow_answer.push(i);
is(sjow_answer.sort().toString(), ['a', 'next'].sort().toString(),
'enumeration over SJOWs walks the prototype chain');
}