Bug 679019 - Make initializing the *Error classes non-generic, and combine their initialization with that of Error. r=jorendorff
authorJeff Walden <jwalden@mit.edu>
Mon, 09 May 2011 13:06:52 -0700
changeset 75427 9c2be071d1d6577bdd9bac101bea06bf873b25c3
parent 75426 9c338d07d7f836a9e1e60cc90f30ada4b150f232
child 75428 63f07bd1d64f39f801cb3f38196a788a1ddbc1fb
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 *Error classes non-generic, and combine their initialization with that of Error. r=jorendorff
js/src/jsexn.cpp
js/src/vm/GlobalObject.cpp
js/src/vm/GlobalObject.h
--- a/js/src/jsexn.cpp
+++ b/js/src/jsexn.cpp
@@ -1004,35 +1004,28 @@ JS_STATIC_ASSERT(JSProto_Error + JSEXN_S
 JS_STATIC_ASSERT(JSProto_Error + JSEXN_TYPEERR      == JSProto_TypeError);
 JS_STATIC_ASSERT(JSProto_Error + JSEXN_URIERR       == JSProto_URIError);
 
 static JS_INLINE JSProtoKey
 GetExceptionProtoKey(intN exn)
 {
     JS_ASSERT(JSEXN_ERR <= exn);
     JS_ASSERT(exn < JSEXN_LIMIT);
-    return (JSProtoKey) (JSProto_Error + exn);
+    return JSProtoKey(JSProto_Error + exn);
 }
 
 static JSObject *
-InitErrorClass(JSContext *cx, GlobalObject *global)
+InitErrorClass(JSContext *cx, GlobalObject *global, intN type, JSObject &proto)
 {
-    /* Create Error.prototype. */
-    JSObject *errorProto = global->createBlankPrototype(cx, &js_ErrorClass);
+    JSProtoKey key = GetExceptionProtoKey(type);
+    JSAtom *name = cx->runtime->atomState.classAtoms[key];
+    JSObject *errorProto = global->createBlankPrototypeInheriting(cx, &js_ErrorClass, proto);
     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,
@@ -1040,76 +1033,57 @@ InitErrorClass(JSContext *cx, GlobalObje
         !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;
     }
 
+    /* Create the corresponding constructor. */
+    JSFunction *ctor = global->createConstructor(cx, Exception, &js_ErrorClass, name, 1);
+    if (!ctor)
+        return NULL;
+    ctor->setReservedSlot(JSSLOT_ERROR_EXNTYPE, Int32Value(int32(type)));
+
     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))
+    if (!DefineConstructorAndPrototype(cx, global, key, ctor, errorProto))
         return NULL;
 
     JS_ASSERT(!errorProto->getPrivate());
 
     return errorProto;
 }
 
-static bool
-InitSpecialErrorClass(JSContext *cx, GlobalObject *global, intN type, JSObject &errorProto)
-{
-    JSProtoKey key = GetExceptionProtoKey(type);
-    JSAtom *atom = cx->runtime->atomState.classAtoms[key];
-    JSObject *ctor;
-    JSObject *proto =
-        DefineConstructorAndPrototype(cx, global, key, atom, &errorProto, &js_ErrorClass,
-                                      Exception, 1, NULL, NULL, NULL, NULL, &ctor);
-    if (!proto)
-        return false;
-    JS_ASSERT(proto->getPrivate() == NULL);
-    ctor->setReservedSlot(JSSLOT_ERROR_EXNTYPE, Int32Value(int32(type)));
-
-    /* Add properties to the 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);
-    return 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, Int32Value(0),
-                                PropertyStub, StrictPropertyStub, JSPROP_ENUMERATE, 0, 0);
-}
-
 JSObject *
 js_InitExceptionClasses(JSContext *cx, JSObject *obj)
 {
     JS_ASSERT(obj->isGlobal());
     JS_ASSERT(obj->isNative());
 
     GlobalObject *global = obj->asGlobal();
 
-    JSObject *errorProto = InitErrorClass(cx, global);
+    JSObject *objectProto;
+    if (!js_GetClassPrototype(cx, global, JSProto_Object, &objectProto))
+        return NULL;
+
+    /* Initialize the base Error class first. */
+    JSObject *errorProto = InitErrorClass(cx, global, JSEXN_ERR, *objectProto);
     if (!errorProto)
         return NULL;
 
+    /* |Error.prototype| alone has method properties. */
+    if (!DefinePropertiesAndBrand(cx, errorProto, NULL, exception_methods))
+        return NULL;
+
     /* Define all remaining *Error constructors. */
     for (intN i = JSEXN_ERR + 1; i < JSEXN_LIMIT; i++) {
-        if (!InitSpecialErrorClass(cx, global, i, *errorProto))
+        if (!InitErrorClass(cx, global, i, *errorProto))
             return NULL;
     }
 
     return errorProto;
 }
 
 const JSErrorFormatString*
 js_GetLocalizedErrorMessage(JSContext* cx, void *userRef, const char *locale,
--- a/js/src/vm/GlobalObject.cpp
+++ b/js/src/vm/GlobalObject.cpp
@@ -213,38 +213,50 @@ GlobalObject::createConstructor(JSContex
     /*
      * Remember the class this function is a constructor for so that we know to
      * create an object of this class when we call the constructor.
      */
     FUN_CLASP(fun) = clasp;
     return fun;
 }
 
-JSObject *
-GlobalObject::createBlankPrototype(JSContext *cx, Class *clasp)
+static JSObject *
+CreateBlankProto(JSContext *cx, Class *clasp, JSObject &proto, GlobalObject &global)
 {
     JS_ASSERT(clasp != &js_ObjectClass);
     JS_ASSERT(clasp != &js_FunctionClass);
 
-    JSObject *objectProto;
-    if (!js_GetClassPrototype(cx, this, JSProto_Object, &objectProto))
-        return NULL;
-
-    JSObject *proto = NewNonFunction<WithProto::Given>(cx, clasp, objectProto, this);
-    if (!proto)
+    JSObject *blankProto = NewNonFunction<WithProto::Given>(cx, clasp, &proto, &global);
+    if (!blankProto)
         return NULL;
 
     /*
      * Supply the created prototype object with an empty shape for the benefit
      * of callers of JSObject::initSharingEmptyShape.
      */
-    if (!proto->getEmptyShape(cx, clasp, gc::FINALIZE_OBJECT0))
+    if (!blankProto->getEmptyShape(cx, clasp, gc::FINALIZE_OBJECT0))
         return NULL;
 
-    return proto;
+    return blankProto;
+}
+
+JSObject *
+GlobalObject::createBlankPrototype(JSContext *cx, Class *clasp)
+{
+    JSObject *objectProto;
+    if (!js_GetClassPrototype(cx, this, JSProto_Object, &objectProto))
+        return NULL;
+
+    return CreateBlankProto(cx, clasp, *objectProto, *this);
+}
+
+JSObject *
+GlobalObject::createBlankPrototypeInheriting(JSContext *cx, Class *clasp, JSObject &proto)
+{
+    return CreateBlankProto(cx, clasp, proto, *this);
 }
 
 bool
 LinkConstructorAndPrototype(JSContext *cx, JSObject *ctor, JSObject *proto)
 {
     return ctor->defineProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom),
                                 ObjectValue(*proto), PropertyStub, StrictPropertyStub,
                                 JSPROP_PERMANENT | JSPROP_READONLY) &&
--- a/js/src/vm/GlobalObject.h
+++ b/js/src/vm/GlobalObject.h
@@ -127,16 +127,22 @@ class GlobalObject : public ::JSObject {
      * class, using |Object.prototype| as its [[Prototype]].  Users creating
      * prototype objects with particular internal structure (e.g. reserved
      * slots guaranteed to contain values of particular types) must immediately
      * complete the minimal initialization to make the returned object safe to
      * touch.
      */
     JSObject *createBlankPrototype(JSContext *cx, js::Class *clasp);
 
+    /*
+     * Identical to createBlankPrototype, but uses proto as the [[Prototype]]
+     * of the returned blank prototype.
+     */
+    JSObject *createBlankPrototypeInheriting(JSContext *cx, js::Class *clasp, JSObject &proto);
+
     void setThrowTypeError(JSFunction *fun) {
         // Our bootstrapping code is currently too convoluted to correctly and
         // confidently assert this.
         // JS_ASSERT(v.isUndefined());
         // JS_ASSERT(getSlot(THROWTYPEERROR).isUndefined());
         setSlot(THROWTYPEERROR, ObjectValue(*fun));
     }