Bug 679019 - Make initializing the single Error class non-generic. r=jorendorff
authorJeff Walden <jwalden@mit.edu>
Mon, 09 May 2011 13:06:51 -0700
changeset 75427 8e85ef78e47f901e48a4efc9099b3dfab7feaad2
parent 75426 c5e84e1e62daf3e196e1aadcba60c89ea75f3c3a
child 75428 9c338d07d7f836a9e1e60cc90f30ada4b150f232
push id2
push userbsmedberg@mozilla.com
push dateFri, 19 Aug 2011 14:38:13 +0000
reviewersjorendorff
bugs679019
milestone9.0a1
Bug 679019 - Make initializing the single Error class non-generic. r=jorendorff
js/src/jsexn.cpp
--- a/js/src/jsexn.cpp
+++ b/js/src/jsexn.cpp
@@ -59,16 +59,18 @@
 #include "jsnum.h"
 #include "jsobj.h"
 #include "jsopcode.h"
 #include "jsscope.h"
 #include "jsscript.h"
 #include "jsstaticcheck.h"
 #include "jswrapper.h"
 
+#include "vm/GlobalObject.h"
+
 #include "jsobjinlines.h"
 
 #include "vm/Stack-inl.h"
 
 using namespace js;
 using namespace js::gc;
 
 /* Forward declarations for js_ErrorClass's initializer. */
@@ -1005,77 +1007,108 @@ JS_STATIC_ASSERT(JSProto_Error + JSEXN_U
 static JS_INLINE JSProtoKey
 GetExceptionProtoKey(intN exn)
 {
     JS_ASSERT(JSEXN_ERR <= exn);
     JS_ASSERT(exn < JSEXN_LIMIT);
     return (JSProtoKey) (JSProto_Error + exn);
 }
 
+static JSObject *
+InitErrorClass(JSContext *cx, GlobalObject *global)
+{
+    /* Create Error.prototype. */
+    JSObject *errorProto = global->createBlankPrototype(cx, &js_ErrorClass);
+    if (!errorProto)
+        return NULL;
+
+    /* Now create the Error function. */
+    JSAtom *name = CLASS_ATOM(cx, Error);
+    JSFunction *ctor = global->createConstructor(cx, Exception, &js_ErrorClass, name, 1);
+    if (!ctor)
+        return NULL;
+    ctor->setReservedSlot(JSSLOT_ERROR_EXNTYPE, Int32Value(int32(JSEXN_ERR)));
+
+    /* Add properties to Error.prototype. */
+    Value empty = StringValue(cx->runtime->emptyString);
+    jsid nameId = ATOM_TO_JSID(cx->runtime->atomState.nameAtom);
+    jsid messageId = ATOM_TO_JSID(cx->runtime->atomState.messageAtom);
+    jsid fileNameId = ATOM_TO_JSID(cx->runtime->atomState.fileNameAtom);
+    jsid lineNumberId = ATOM_TO_JSID(cx->runtime->atomState.lineNumberAtom);
+    if (!DefineNativeProperty(cx, errorProto, nameId, StringValue(name),
+                              PropertyStub, StrictPropertyStub, 0, 0, 0) ||
+        !DefineNativeProperty(cx, errorProto, messageId, empty,
+                              PropertyStub, StrictPropertyStub, 0, 0, 0) ||
+        !DefineNativeProperty(cx, errorProto, fileNameId, empty,
+                              PropertyStub, StrictPropertyStub, JSPROP_ENUMERATE, 0, 0) ||
+        !DefineNativeProperty(cx, errorProto, lineNumberId, Int32Value(0),
+                              PropertyStub, StrictPropertyStub, JSPROP_ENUMERATE, 0, 0))
+    {
+        return NULL;
+    }
+
+    if (!LinkConstructorAndPrototype(cx, ctor, errorProto))
+        return NULL;
+
+    if (!DefinePropertiesAndBrand(cx, errorProto, NULL, exception_methods))
+        return NULL;
+
+    /* Install the fully-constructed Error and Error.prototype. */
+    if (!DefineConstructorAndPrototype(cx, global, JSProto_Error, ctor, errorProto))
+        return NULL;
+
+    return errorProto;
+}
+
 JSObject *
 js_InitExceptionClasses(JSContext *cx, JSObject *obj)
 {
-    /*
-     * If lazy class initialization occurs for any Error subclass, then all
-     * classes are initialized, starting with Error.  To avoid reentry and
-     * redundant initialization, we must not pass a null proto parameter to
-     * NewNonFunction below, when called for the Error superclass.  We need to
-     * ensure that Object.prototype is the proto of Error.prototype.
-     *
-     * See the equivalent code to ensure that parent_proto is non-null when
-     * js_InitClass calls NewObject, in jsobj.cpp.
-     */
-    JSObject *obj_proto;
-    if (!js_GetClassPrototype(cx, obj, JSProto_Object, &obj_proto))
+    JS_ASSERT(obj->isGlobal());
+    JS_ASSERT(obj->isNative());
+
+    GlobalObject *global = obj->asGlobal();
+
+    JSObject *errorProto = InitErrorClass(cx, global);
+    if (!errorProto)
         return NULL;
 
     /* Define all error constructors. */
     Value empty = StringValue(cx->runtime->emptyString);
     jsid nameId = ATOM_TO_JSID(cx->runtime->atomState.nameAtom);
     jsid messageId = ATOM_TO_JSID(cx->runtime->atomState.messageAtom);
     jsid fileNameId = ATOM_TO_JSID(cx->runtime->atomState.fileNameAtom);
     jsid lineNumberId = ATOM_TO_JSID(cx->runtime->atomState.lineNumberAtom);
-    JSObject *error_proto = NULL;
-    for (intN i = JSEXN_ERR; i != JSEXN_LIMIT; i++) {
+    for (intN i = JSEXN_ERR + 1; i < JSEXN_LIMIT; i++) {
         JSProtoKey protoKey = GetExceptionProtoKey(i);
         JSAtom *atom = cx->runtime->atomState.classAtoms[protoKey];
         JSObject *ctor;
         JSObject *proto =
-            DefineConstructorAndPrototype(cx, obj, protoKey, atom,
-                                          (i == JSEXN_ERR) ? obj_proto : error_proto,
-                                          &js_ErrorClass, Exception, 1,
-                                          NULL, (i == JSEXN_ERR) ? exception_methods : NULL,
-                                          NULL, NULL, &ctor);
+            DefineConstructorAndPrototype(cx, global, protoKey, atom, errorProto, &js_ErrorClass,
+                                          Exception, 1, NULL, NULL, NULL, NULL, &ctor);
         if (!proto)
             return NULL;
         JS_ASSERT(proto->getPrivate() == NULL);
 
-        if (i == JSEXN_ERR)
-            error_proto = proto;
-
-        /* Save the exception type in a reserved slot. */
-        if (!ctor->ensureClassReservedSlots(cx))
-            return NULL;
         ctor->setReservedSlot(JSSLOT_ERROR_EXNTYPE, Int32Value(int32(i)));
 
         /* Add properties to the prototype. */
         JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_DECLARING);
         if (!DefineNativeProperty(cx, proto, nameId, StringValue(atom),
                                   PropertyStub, StrictPropertyStub, 0, 0, 0) ||
             !DefineNativeProperty(cx, proto, messageId, empty,
                                   PropertyStub, StrictPropertyStub, 0, 0, 0) ||
             !DefineNativeProperty(cx, proto, fileNameId, empty,
                                   PropertyStub, StrictPropertyStub, JSPROP_ENUMERATE, 0, 0) ||
             !DefineNativeProperty(cx, proto, lineNumberId, Valueify(JSVAL_ZERO),
                                   PropertyStub, StrictPropertyStub, JSPROP_ENUMERATE, 0, 0)) {
             return NULL;
         }
     }
 
-    return error_proto;
+    return errorProto;
 }
 
 const JSErrorFormatString*
 js_GetLocalizedErrorMessage(JSContext* cx, void *userRef, const char *locale,
                             const uintN errorNumber)
 {
     const JSErrorFormatString *errorString = NULL;