Bug 566846 - Make sure the engine knows that wrapper iterators are real iterators. r=gal
authorBlake Kaplan <mrbkap@gmail.com>
Fri, 28 May 2010 15:20:52 -0700
changeset 42913 f8aca3972045c9df78ad70495c2c9e42beea233e
parent 42912 8b5cbcb481bd3bca52cb451037c97ad51214399e
child 42914 62d08a22f3949ea3f067a4823247f4fdfc2a3788
push idunknown
push userunknown
push dateunknown
reviewersgal
bugs566846
milestone1.9.3a5pre
Bug 566846 - Make sure the engine knows that wrapper iterators are real iterators. r=gal
js/src/xpconnect/src/XPCWrapper.cpp
js/src/xpconnect/tests/mochitest/test_wrappers.html
--- 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');
     }