Bug 1029933 - Make Error use a ClassSpec. r=Waldo
authorBobby Holley <bobbyholley@gmail.com>
Fri, 04 Jul 2014 12:41:29 -0700
changeset 214382 7750f3e24883a7f3ac3a3988122829b50e28026d
parent 214381 a7b254ac4fc4faaff076d9adadd74c21aa794768
child 214383 d54652b755bdab49473b28a5ab495b1af02044a4
push id515
push userraliiev@mozilla.com
push dateMon, 06 Oct 2014 12:51:51 +0000
treeherdermozilla-release@267c7a481bef [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersWaldo
bugs1029933
milestone33.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 1029933 - Make Error use a ClassSpec. r=Waldo
js/src/jsexn.cpp
js/src/jsexn.h
js/src/jsprototypes.h
js/src/vm/ErrorObject.h
--- a/js/src/jsexn.cpp
+++ b/js/src/jsexn.cpp
@@ -40,32 +40,57 @@ using namespace js::types;
 
 using mozilla::ArrayLength;
 using mozilla::PodArrayZero;
 using mozilla::PodZero;
 
 static void
 exn_finalize(FreeOp *fop, JSObject *obj);
 
+bool
+Error(JSContext *cx, unsigned argc, Value *vp);
+
+static bool
+exn_toSource(JSContext *cx, unsigned argc, Value *vp);
+
+static bool
+exn_toString(JSContext *cx, unsigned argc, Value *vp);
+
+static const JSFunctionSpec exception_methods[] = {
+#if JS_HAS_TOSOURCE
+    JS_FN(js_toSource_str, exn_toSource, 0, 0),
+#endif
+    JS_FN(js_toString_str, exn_toString, 0, 0),
+    JS_FS_END
+};
+
+
 const Class ErrorObject::class_ = {
     js_Error_str,
     JSCLASS_IMPLEMENTS_BARRIERS |
     JSCLASS_HAS_CACHED_PROTO(JSProto_Error) |
     JSCLASS_HAS_RESERVED_SLOTS(ErrorObject::RESERVED_SLOTS),
     JS_PropertyStub,         /* addProperty */
     JS_DeletePropertyStub,   /* delProperty */
     JS_PropertyStub,         /* getProperty */
     JS_StrictPropertyStub,   /* setProperty */
     JS_EnumerateStub,
     JS_ResolveStub,
     JS_ConvertStub,
     exn_finalize,
     nullptr,                 /* call        */
     nullptr,                 /* hasInstance */
-    nullptr                  /* construct   */
+    nullptr,                 /* construct   */
+    nullptr,                 /* trace       */
+    {
+        ErrorObject::createConstructor,
+        ErrorObject::createProto,
+        nullptr,
+        exception_methods
+    }
 };
 
 JSErrorReport *
 js::CopyErrorReport(JSContext *cx, JSErrorReport *report)
 {
     /*
      * We use a single malloc block to make a deep copy of JSErrorReport with
      * the following layout:
@@ -285,17 +310,17 @@ js_ErrorFromException(JSContext *cx, Han
     // will fail if they can't unwrap it.
     RootedObject obj(cx, UncheckedUnwrap(objArg));
     if (!obj->is<ErrorObject>())
         return nullptr;
 
     return obj->as<ErrorObject>().getOrCreateErrorReport(cx);
 }
 
-static bool
+bool
 Error(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     /* Compute the error message, if any. */
     RootedString message(cx, nullptr);
     if (args.hasDefined(0)) {
         message = ToString<CanGC>(cx, args[0]);
@@ -501,103 +526,62 @@ exn_toSource(JSContext *cx, unsigned arg
     JSString *str = sb.finishString();
     if (!str)
         return false;
     args.rval().setString(str);
     return true;
 }
 #endif
 
-static const JSFunctionSpec exception_methods[] = {
-#if JS_HAS_TOSOURCE
-    JS_FN(js_toSource_str,   exn_toSource,           0,0),
-#endif
-    JS_FN(js_toString_str,   exn_toString,           0,0),
-    JS_FS_END
-};
-
 /* JSProto_ ordering for exceptions shall match JSEXN_ constants. */
 JS_STATIC_ASSERT(JSEXN_ERR == 0);
 JS_STATIC_ASSERT(JSProto_Error + JSEXN_INTERNALERR  == JSProto_InternalError);
 JS_STATIC_ASSERT(JSProto_Error + JSEXN_EVALERR      == JSProto_EvalError);
 JS_STATIC_ASSERT(JSProto_Error + JSEXN_RANGEERR     == JSProto_RangeError);
 JS_STATIC_ASSERT(JSProto_Error + JSEXN_REFERENCEERR == JSProto_ReferenceError);
 JS_STATIC_ASSERT(JSProto_Error + JSEXN_SYNTAXERR    == JSProto_SyntaxError);
 JS_STATIC_ASSERT(JSProto_Error + JSEXN_TYPEERR      == JSProto_TypeError);
 JS_STATIC_ASSERT(JSProto_Error + JSEXN_URIERR       == JSProto_URIError);
 
-/* static */ ErrorObject *
-ErrorObject::createProto(JSContext *cx, JS::Handle<GlobalObject*> global, JSExnType type,
-                         JS::HandleObject proto)
+/* static */ JSObject *
+ErrorObject::createProto(JSContext *cx, JSProtoKey key)
 {
-    RootedObject errorProto(cx);
-    errorProto = global->createBlankPrototypeInheriting(cx, &ErrorObject::class_, *proto);
+    RootedObject errorProto(cx, GenericCreatePrototype<&ErrorObject::class_>(cx, key));
     if (!errorProto)
         return nullptr;
 
     Rooted<ErrorObject*> err(cx, &errorProto->as<ErrorObject>());
     RootedString emptyStr(cx, cx->names().empty);
+    JSExnType type = ExnTypeFromProtoKey(key);
     if (!ErrorObject::init(cx, err, type, nullptr, emptyStr, emptyStr, 0, 0, emptyStr))
         return nullptr;
 
     // The various prototypes also have .name in addition to the normal error
     // instance properties.
-    JSProtoKey key = GetExceptionProtoKey(type);
     RootedPropertyName name(cx, ClassName(key, cx));
     RootedValue nameValue(cx, StringValue(name));
     if (!JSObject::defineProperty(cx, err, cx->names().name, nameValue,
                                   JS_PropertyStub, JS_StrictPropertyStub, 0))
     {
         return nullptr;
     }
 
-    // Create the corresponding constructor.
-    RootedFunction ctor(cx, global->createConstructor(cx, Error, name, 1,
-                                                      JSFunction::ExtendedFinalizeKind));
-    if (!ctor)
-        return nullptr;
-    ctor->setExtendedSlot(0, Int32Value(int32_t(type)));
-
-    if (!LinkConstructorAndPrototype(cx, ctor, err))
-        return nullptr;
-
-    if (!GlobalObject::initBuiltinConstructor(cx, global, key, ctor, err))
-        return nullptr;
-
-    return err;
+    return errorProto;
 }
 
-JSObject *
-js_InitExceptionClasses(JSContext *cx, HandleObject obj)
+/* static */ JSObject *
+ErrorObject::createConstructor(JSContext *cx, JSProtoKey key)
 {
-    JS_ASSERT(obj->is<GlobalObject>());
-    JS_ASSERT(obj->isNative());
-
-    Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>());
-
-    RootedObject objProto(cx, global->getOrCreateObjectPrototype(cx));
-    if (!objProto)
+    RootedObject ctor(cx);
+    ctor = GenericCreateConstructor<Error, 1, JSFunction::ExtendedFinalizeKind>(cx, key);
+    if (!ctor)
         return nullptr;
 
-    /* Initialize the base Error class first. */
-    RootedObject errorProto(cx, ErrorObject::createProto(cx, global, JSEXN_ERR, objProto));
-    if (!errorProto)
-        return nullptr;
-
-    /* |Error.prototype| alone has method properties. */
-    if (!DefinePropertiesAndFunctions(cx, errorProto, nullptr, exception_methods))
-        return nullptr;
-
-    /* Define all remaining *Error constructors. */
-    for (int i = JSEXN_ERR + 1; i < JSEXN_LIMIT; i++) {
-        if (!ErrorObject::createProto(cx, global, JSExnType(i), errorProto))
-            return nullptr;
-    }
-
-    return errorProto;
+    ctor->as<JSFunction>().setExtendedSlot(0, Int32Value(ExnTypeFromProtoKey(key)));
+    return ctor;
 }
 
 const JSErrorFormatString*
 js_GetLocalizedErrorMessage(ExclusiveContext *cx, void *userRef, const char *locale,
                             const unsigned errorNumber)
 {
     const JSErrorFormatString *errorString = nullptr;
 
--- a/js/src/jsexn.h
+++ b/js/src/jsexn.h
@@ -80,23 +80,32 @@ extern const JSErrorFormatString *
 js_GetLocalizedErrorMessage(js::ExclusiveContext *cx, void *userRef, const char *locale,
                             const unsigned errorNumber);
 
 /*
  * Make a copy of errobj parented to scope.
  *
  * cx must be in the same compartment as scope. errobj may be in a different
  * compartment, but it must be an Error object (not a wrapper of one) and it
- * must not be one of the prototype objects created by js_InitExceptionClasses
+ * must not be one of the standard error prototype objects
  * (errobj->getPrivate() must not be nullptr).
  */
 extern JSObject *
 js_CopyErrorObject(JSContext *cx, JS::Handle<js::ErrorObject*> errobj, js::HandleObject scope);
 
 static inline JSProtoKey
 GetExceptionProtoKey(JSExnType exn)
 {
     JS_ASSERT(JSEXN_ERR <= exn);
     JS_ASSERT(exn < JSEXN_LIMIT);
     return JSProtoKey(JSProto_Error + int(exn));
 }
 
+static inline JSExnType
+ExnTypeFromProtoKey(JSProtoKey key)
+{
+    JSExnType type = static_cast<JSExnType>(key - JSProto_Error);
+    JS_ASSERT(type >= JSEXN_ERR);
+    JS_ASSERT(type < JSEXN_LIMIT);
+    return type;
+}
+
 #endif /* jsexn_h */
--- a/js/src/jsprototypes.h
+++ b/js/src/jsprototypes.h
@@ -67,24 +67,24 @@
     real(Array,                  3,     js_InitViaClassSpec,       OCLASP(Array)) \
     real(Boolean,                4,     js_InitBooleanClass,       OCLASP(Boolean)) \
     real(JSON,                   5,     js_InitJSONClass,          CLASP(JSON)) \
     real(Date,                   6,     js_InitViaClassSpec,       OCLASP(Date)) \
     real(Math,                   7,     js_InitMathClass,          CLASP(Math)) \
     real(Number,                 8,     js_InitNumberClass,        OCLASP(Number)) \
     real(String,                 9,     js_InitStringClass,        OCLASP(String)) \
     real(RegExp,                10,     js_InitRegExpClass,        OCLASP(RegExp)) \
-    real(Error,                 11,     js_InitExceptionClasses,   OCLASP(Error)) \
-    real(InternalError,         12,     js_InitExceptionClasses,   OCLASP(Error)) \
-    real(EvalError,             13,     js_InitExceptionClasses,   OCLASP(Error)) \
-    real(RangeError,            14,     js_InitExceptionClasses,   OCLASP(Error)) \
-    real(ReferenceError,        15,     js_InitExceptionClasses,   OCLASP(Error)) \
-    real(SyntaxError,           16,     js_InitExceptionClasses,   OCLASP(Error)) \
-    real(TypeError,             17,     js_InitExceptionClasses,   OCLASP(Error)) \
-    real(URIError,              18,     js_InitExceptionClasses,   OCLASP(Error)) \
+    real(Error,                 11,     js_InitViaClassSpec,       OCLASP(Error)) \
+    real(InternalError,         12,     js_InitViaClassSpec,       OCLASP(Error)) \
+    real(EvalError,             13,     js_InitViaClassSpec,       OCLASP(Error)) \
+    real(RangeError,            14,     js_InitViaClassSpec,       OCLASP(Error)) \
+    real(ReferenceError,        15,     js_InitViaClassSpec,       OCLASP(Error)) \
+    real(SyntaxError,           16,     js_InitViaClassSpec,       OCLASP(Error)) \
+    real(TypeError,             17,     js_InitViaClassSpec,       OCLASP(Error)) \
+    real(URIError,              18,     js_InitViaClassSpec,       OCLASP(Error)) \
     real(Iterator,              19,     js_InitIteratorClasses,    OCLASP(PropertyIterator)) \
     real(StopIteration,         20,     js_InitIteratorClasses,    OCLASP(StopIteration)) \
     real(ArrayBuffer,           21,     js_InitArrayBufferClass,   &js::ArrayBufferObject::protoClass) \
     real(Int8Array,             22,     js_InitViaClassSpec,       TYPED_ARRAY_CLASP(TYPE_INT8)) \
     real(Uint8Array,            23,     js_InitViaClassSpec,       TYPED_ARRAY_CLASP(TYPE_UINT8)) \
     real(Int16Array,            24,     js_InitViaClassSpec,       TYPED_ARRAY_CLASP(TYPE_INT16)) \
     real(Uint16Array,           25,     js_InitViaClassSpec,       TYPED_ARRAY_CLASP(TYPE_UINT16)) \
     real(Int32Array,            26,     js_InitViaClassSpec,       TYPED_ARRAY_CLASP(TYPE_INT32)) \
--- a/js/src/vm/ErrorObject.h
+++ b/js/src/vm/ErrorObject.h
@@ -18,19 +18,21 @@ struct JSExnPrivate;
  */
 extern JSObject *
 js_InitExceptionClasses(JSContext *cx, JS::HandleObject obj);
 
 namespace js {
 
 class ErrorObject : public JSObject
 {
-    static ErrorObject *
-    createProto(JSContext *cx, JS::Handle<GlobalObject*> global, JSExnType type,
-                JS::HandleObject proto);
+    static JSObject *
+    createProto(JSContext *cx, JSProtoKey key);
+
+    static JSObject *
+    createConstructor(JSContext *cx, JSProtoKey key);
 
     /* For access to createProto. */
     friend JSObject *
     ::js_InitExceptionClasses(JSContext *cx, JS::HandleObject global);
 
     /* For access to assignInitialShape. */
     friend bool
     EmptyShape::ensureInitialCustomShape<ErrorObject>(ExclusiveContext *cx,