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 75425 8e85ef78e47f901e48a4efc9099b3dfab7feaad2
parent 75424 c5e84e1e62daf3e196e1aadcba60c89ea75f3c3a
child 75426 9c338d07d7f836a9e1e60cc90f30ada4b150f232
push id21023
push usermak77@bonardo.net
push dateThu, 18 Aug 2011 09:39:20 +0000
treeherdermozilla-central@f69a10f23bf3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjorendorff
bugs679019
milestone9.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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;