Bug 676936 - Refactor js_InitIteratorClasses, and rewrite InitIteratorClass to be much clearer. r=luke
authorJeff Walden <jwalden@mit.edu>
Wed, 04 May 2011 16:54:23 -0400
changeset 74046 a399a694bfad3d1f15cc19c752d3bb7932c381d3
parent 74045 89c17ca55124eb32672e9aae0c130283097fb980
child 74047 aade388e6c6223c34f1220135089c57795303075
push id2
push userbsmedberg@mozilla.com
push dateFri, 19 Aug 2011 14:38:13 +0000
reviewersluke
bugs676936
milestone8.0a1
Bug 676936 - Refactor js_InitIteratorClasses, and rewrite InitIteratorClass to be much clearer. r=luke
js/src/jsiter.cpp
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -70,16 +70,18 @@
 #include "jsscript.h"
 #include "jsstaticcheck.h"
 #include "jsvector.h"
 
 #if JS_HAS_XML_SUPPORT
 #include "jsxml.h"
 #endif
 
+#include "vm/GlobalObject.h"
+
 #include "jsobjinlines.h"
 
 #include "vm/Stack-inl.h"
 #include "vm/String-inl.h"
 
 using namespace js;
 using namespace js::gc;
 
@@ -1401,37 +1403,73 @@ static JSFunctionSpec generator_methods[
     JS_FN(js_send_str,      generator_send,     1,JSPROP_ROPERM),
     JS_FN(js_throw_str,     generator_throw,    1,JSPROP_ROPERM),
     JS_FN(js_close_str,     generator_close,    0,JSPROP_ROPERM),
     JS_FS_END
 };
 
 #endif /* JS_HAS_GENERATORS */
 
+static bool
+InitIteratorClass(JSContext *cx, GlobalObject *global)
+{
+    JSObject *iteratorProto = global->createBlankPrototype(cx, &js_IteratorClass);
+    if (!iteratorProto)
+        return false;
+
+    JSFunction *ctor = global->createConstructor(cx, Iterator, &js_IteratorClass,
+                                                 CLASS_ATOM(cx, Iterator), 2);
+    if (!ctor)
+        return false;
+
+    if (!LinkConstructorAndPrototype(cx, ctor, iteratorProto))
+        return false;
+
+    if (!DefinePropertiesAndBrand(cx, iteratorProto, NULL, iterator_methods))
+        return false;
+
+    return DefineConstructorAndPrototype(cx, global, JSProto_Iterator, ctor, iteratorProto);
+}
+
+static bool
+InitGeneratorClass(JSContext *cx, GlobalObject *global)
+{
+#if JS_HAS_GENERATORS
+    return js_InitClass(cx, global, NULL, &js_GeneratorClass, NULL, 0,
+                        NULL, generator_methods, NULL, NULL);
+#else
+    return true;
+#endif
+}
+
+static JSObject *
+InitStopIterationClass(JSContext *cx, GlobalObject *global)
+{
+    JSObject *proto = js_InitClass(cx, global, NULL, &js_StopIterationClass, NULL, 0,
+                                   NULL, NULL, NULL, NULL);
+    if (proto)
+        MarkStandardClassInitializedNoProto(global, &js_StopIterationClass);
+    return proto;
+}
+
 JSObject *
 js_InitIteratorClasses(JSContext *cx, JSObject *obj)
 {
-    JSObject *proto, *stop;
+    JS_ASSERT(obj->isNative());
 
-    /* Idempotency required: we initialize several things, possibly lazily. */
-    if (!js_GetClassObject(cx, obj, JSProto_StopIteration, &stop))
-        return NULL;
-    if (stop)
-        return stop;
-
-    proto = js_InitClass(cx, obj, NULL, &js_IteratorClass, Iterator, 2,
-                         NULL, iterator_methods, NULL, NULL);
-    if (!proto)
-        return NULL;
+    GlobalObject *global = obj->asGlobal();
 
-#if JS_HAS_GENERATORS
-    /* Initialize the generator internals if configured. */
-    if (!js_InitClass(cx, obj, NULL, &js_GeneratorClass, NULL, 0,
-                      NULL, generator_methods, NULL, NULL)) {
+    /*
+     * Bail if Iterator has already been initialized.  We test for Iterator
+     * rather than for StopIteration because if js_InitIteratorClasses recurs,
+     * as happens when the StopIteration object is frozen, initializing the
+     * Iterator class a second time will assert.
+     */
+    JSObject *iter;
+    if (!js_GetClassObject(cx, global, JSProto_Iterator, &iter))
         return NULL;
-    }
-#endif
+    if (iter)
+        return iter;
 
-    MarkStandardClassInitializedNoProto(obj, &js_StopIterationClass);
-
-    return js_InitClass(cx, obj, NULL, &js_StopIterationClass, NULL, 0,
-                        NULL, NULL, NULL, NULL);
+    if (!InitIteratorClass(cx, global) || !InitGeneratorClass(cx, global))
+        return NULL;
+    return InitStopIterationClass(cx, global);
 }