Bug 884124 (part 4) - Add an ErrorObject class. r=jwalden.
authorNicholas Nethercote <nnethercote@mozilla.com>
Thu, 20 Jun 2013 20:17:14 -0700
changeset 149659 432d6ff55841ebad0ecdf8079ffe3fe45618a03c
parent 149658 56c9a18a4760975ebc8ab2b913635913faea112c
child 149660 5b207f6332442b266d0be788ee93514f044a45e4
push id382
push userakeybl@mozilla.com
push dateMon, 21 Oct 2013 21:47:13 +0000
treeherdermozilla-release@5f1868ee45cb [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjwalden
bugs884124
milestone25.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 884124 (part 4) - Add an ErrorObject class. r=jwalden.
js/src/jsapi.cpp
js/src/jsexn.cpp
js/src/jsobj.h
js/src/jswrapper.cpp
js/src/vm/ErrorObject.h
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -60,16 +60,17 @@
 #include "frontend/FullParseHandler.h"  // for JS_BufferIsCompileableUnit
 #include "frontend/Parser.h" // for JS_BufferIsCompileableUnit
 #include "gc/Marking.h"
 #include "gc/Memory.h"
 #include "ion/AsmJS.h"
 #include "ion/PcScriptCache.h"
 #include "js/CharacterEncoding.h"
 #include "vm/Debugger.h"
+#include "vm/ErrorObject.h"
 #include "vm/Interpreter.h"
 #include "vm/NumericConversions.h"
 #include "vm/Shape.h"
 #include "vm/StopIterationObject.h"
 #include "vm/StringBuffer.h"
 #include "vm/WeakMapObject.h"
 #include "vm/Xdr.h"
 #include "yarr/BumpPointerAllocator.h"
@@ -1804,17 +1805,17 @@ static const JSStdName standard_class_at
     {js_InitFunctionClass,              EAGER_CLASS_ATOM(Function), &JSFunction::class_},
     {js_InitObjectClass,                EAGER_ATOM_AND_CLASP(Object)},
     {js_InitArrayClass,                 EAGER_ATOM_AND_CLASP(Array)},
     {js_InitBooleanClass,               EAGER_ATOM_AND_OCLASP(Boolean)},
     {js_InitDateClass,                  EAGER_ATOM_AND_CLASP(Date)},
     {js_InitMathClass,                  EAGER_ATOM_AND_CLASP(Math)},
     {js_InitNumberClass,                EAGER_ATOM_AND_OCLASP(Number)},
     {js_InitStringClass,                EAGER_ATOM_AND_OCLASP(String)},
-    {js_InitExceptionClasses,           EAGER_ATOM_AND_CLASP(Error)},
+    {js_InitExceptionClasses,           EAGER_ATOM_AND_OCLASP(Error)},
     {js_InitRegExpClass,                EAGER_ATOM_AND_OCLASP(RegExp)},
 #if JS_HAS_GENERATORS
     {js_InitIteratorClasses,            EAGER_ATOM_AND_OCLASP(StopIteration)},
 #endif
     {js_InitJSONClass,                  EAGER_ATOM_AND_CLASP(JSON)},
     {js_InitTypedArrayClasses,          EAGER_CLASS_ATOM(ArrayBuffer), &js::ArrayBufferObject::protoClass},
     {js_InitWeakMapClass,               EAGER_ATOM_AND_OCLASP(WeakMap)},
     {js_InitMapClass,                   EAGER_ATOM_AND_OCLASP(Map)},
@@ -1852,24 +1853,24 @@ static const JSStdName standard_class_na
     {js_InitStringClass,        EAGER_ATOM(encodeURI), OCLASP(String)},
     {js_InitStringClass,        EAGER_ATOM(decodeURIComponent), OCLASP(String)},
     {js_InitStringClass,        EAGER_ATOM(encodeURIComponent), OCLASP(String)},
 #if JS_HAS_UNEVAL
     {js_InitStringClass,        EAGER_ATOM(uneval), OCLASP(String)},
 #endif
 
     /* Exception constructors. */
-    {js_InitExceptionClasses,   EAGER_CLASS_ATOM(Error), CLASP(Error)},
-    {js_InitExceptionClasses,   EAGER_CLASS_ATOM(InternalError), CLASP(Error)},
-    {js_InitExceptionClasses,   EAGER_CLASS_ATOM(EvalError), CLASP(Error)},
-    {js_InitExceptionClasses,   EAGER_CLASS_ATOM(RangeError), CLASP(Error)},
-    {js_InitExceptionClasses,   EAGER_CLASS_ATOM(ReferenceError), CLASP(Error)},
-    {js_InitExceptionClasses,   EAGER_CLASS_ATOM(SyntaxError), CLASP(Error)},
-    {js_InitExceptionClasses,   EAGER_CLASS_ATOM(TypeError), CLASP(Error)},
-    {js_InitExceptionClasses,   EAGER_CLASS_ATOM(URIError), CLASP(Error)},
+    {js_InitExceptionClasses,   EAGER_CLASS_ATOM(Error), OCLASP(Error)},
+    {js_InitExceptionClasses,   EAGER_CLASS_ATOM(InternalError), OCLASP(Error)},
+    {js_InitExceptionClasses,   EAGER_CLASS_ATOM(EvalError), OCLASP(Error)},
+    {js_InitExceptionClasses,   EAGER_CLASS_ATOM(RangeError), OCLASP(Error)},
+    {js_InitExceptionClasses,   EAGER_CLASS_ATOM(ReferenceError), OCLASP(Error)},
+    {js_InitExceptionClasses,   EAGER_CLASS_ATOM(SyntaxError), OCLASP(Error)},
+    {js_InitExceptionClasses,   EAGER_CLASS_ATOM(TypeError), OCLASP(Error)},
+    {js_InitExceptionClasses,   EAGER_CLASS_ATOM(URIError), OCLASP(Error)},
 
     {js_InitIteratorClasses,    EAGER_CLASS_ATOM(Iterator), &PropertyIteratorObject::class_},
 
     /* Typed Arrays */
     {js_InitTypedArrayClasses,  EAGER_CLASS_ATOM(ArrayBuffer),  &ArrayBufferObject::class_},
     {js_InitTypedArrayClasses,  EAGER_CLASS_ATOM(Int8Array),    TYPED_ARRAY_CLASP(TYPE_INT8)},
     {js_InitTypedArrayClasses,  EAGER_CLASS_ATOM(Uint8Array),   TYPED_ARRAY_CLASP(TYPE_UINT8)},
     {js_InitTypedArrayClasses,  EAGER_CLASS_ATOM(Int16Array),   TYPED_ARRAY_CLASP(TYPE_INT16)},
--- a/js/src/jsexn.cpp
+++ b/js/src/jsexn.cpp
@@ -19,44 +19,45 @@
 #include "jsapi.h"
 #include "jscntxt.h"
 #include "jsfun.h"
 #include "jsnum.h"
 #include "jsobj.h"
 #include "jsscript.h"
 
 #include "gc/Marking.h"
+#include "vm/ErrorObject.h"
 #include "vm/GlobalObject.h"
 #include "vm/StringBuffer.h"
 
 #include "jsobjinlines.h"
 
 using namespace js;
 using namespace js::gc;
 using namespace js::types;
 
 using mozilla::ArrayLength;
 using mozilla::PodArrayZero;
 using mozilla::PodZero;
 
-/* Forward declarations for ErrorClass's initializer. */
+/* Forward declarations for ErrorObject::class_'s initializer. */
 static JSBool
 Exception(JSContext *cx, unsigned argc, Value *vp);
 
 static void
 exn_trace(JSTracer *trc, JSObject *obj);
 
 static void
 exn_finalize(FreeOp *fop, JSObject *obj);
 
 static JSBool
 exn_resolve(JSContext *cx, HandleObject obj, HandleId id, unsigned flags,
             MutableHandleObject objp);
 
-Class js::ErrorClass = {
+Class ErrorObject::class_ = {
     js_Error_str,
     JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_NEW_RESOLVE |
     JSCLASS_HAS_CACHED_PROTO(JSProto_Error),
     JS_PropertyStub,         /* addProperty */
     JS_DeletePropertyStub,   /* delProperty */
     JS_PropertyStub,         /* getProperty */
     JS_StrictPropertyStub,   /* setProperty */
     JS_EnumerateStub,
@@ -235,24 +236,24 @@ struct SuppressErrorsGuard
     ~SuppressErrorsGuard()
     {
         JS_RestoreExceptionState(cx, prevState);
         JS_SetErrorReporter(cx, prevReporter);
     }
 };
 
 static void
-SetExnPrivate(JSObject *exnObject, JSExnPrivate *priv);
+SetExnPrivate(ErrorObject &exnObject, JSExnPrivate *priv);
 
 static bool
 InitExnPrivate(JSContext *cx, HandleObject exnObject, HandleString message,
                HandleString filename, unsigned lineno, unsigned column,
                JSErrorReport *report, int exnType)
 {
-    JS_ASSERT(exnObject->isError());
+    JS_ASSERT(exnObject->is<ErrorObject>());
     JS_ASSERT(!exnObject->getPrivate());
 
     JSCheckAccessOp checkAccess = cx->runtime()->securityCallbacks->checkObjectAccess;
 
     Vector<JSStackTraceStackElem> frames(cx);
     {
         SuppressErrorsGuard seg(cx);
         for (NonBuiltinScriptFrameIter i(cx); !i.done(); ++i) {
@@ -324,61 +325,53 @@ InitExnPrivate(JSContext *cx, HandleObje
     for (size_t i = 0; i < frames.length(); ++i) {
         priv->stackElems[i].funName.init(frames[i].funName);
         priv->stackElems[i].filename = JS_strdup(cx, frames[i].filename);
         if (!priv->stackElems[i].filename)
             return false;
         priv->stackElems[i].ulineno = frames[i].ulineno;
     }
 
-    SetExnPrivate(exnObject, priv);
+    SetExnPrivate(exnObject->as<ErrorObject>(), priv);
     return true;
 }
 
-static inline JSExnPrivate *
-GetExnPrivate(JSObject *obj)
-{
-    JS_ASSERT(obj->isError());
-    return (JSExnPrivate *) obj->getPrivate();
-}
-
 static void
 exn_trace(JSTracer *trc, JSObject *obj)
 {
-    if (JSExnPrivate *priv = GetExnPrivate(obj)) {
+    if (JSExnPrivate *priv = obj->as<ErrorObject>().getExnPrivate()) {
         if (priv->message)
             MarkString(trc, &priv->message, "exception message");
         if (priv->filename)
             MarkString(trc, &priv->filename, "exception filename");
 
         for (size_t i = 0; i != priv->stackDepth; ++i) {
             JSStackTraceElem &elem = priv->stackElems[i];
             if (elem.funName)
                 MarkString(trc, &elem.funName, "stack trace function name");
         }
     }
 }
 
 /* NB: An error object's private must be set through this function. */
 static void
-SetExnPrivate(JSObject *exnObject, JSExnPrivate *priv)
+SetExnPrivate(ErrorObject &exnObject, JSExnPrivate *priv)
 {
-    JS_ASSERT(!exnObject->getPrivate());
-    JS_ASSERT(exnObject->isError());
+    JS_ASSERT(!exnObject.getExnPrivate());
     if (JSErrorReport *report = priv->errorReport) {
         if (JSPrincipals *prin = report->originPrincipals)
             JS_HoldPrincipals(prin);
     }
-    exnObject->setPrivate(priv);
+    exnObject.setPrivate(priv);
 }
 
 static void
 exn_finalize(FreeOp *fop, JSObject *obj)
 {
-    if (JSExnPrivate *priv = GetExnPrivate(obj)) {
+    if (JSExnPrivate *priv = obj->as<ErrorObject>().getExnPrivate()) {
         if (JSErrorReport *report = priv->errorReport) {
             /* HOLD called by SetExnPrivate. */
             if (JSPrincipals *prin = report->originPrincipals)
                 JS_DropPrincipals(fop->runtime(), prin);
             fop->free_(report);
         }
         for (size_t i = 0; i < priv->stackDepth; i++)
             js_free(const_cast<char *>(priv->stackElems[i].filename));
@@ -391,17 +384,17 @@ exn_resolve(JSContext *cx, HandleObject 
             MutableHandleObject objp)
 {
     JSExnPrivate *priv;
     const char *prop;
     jsval v;
     unsigned attrs;
 
     objp.set(NULL);
-    priv = GetExnPrivate(obj);
+    priv = obj->as<ErrorObject>().getExnPrivate();
     if (priv && JSID_IS_ATOM(id)) {
         RootedString str(cx, JSID_TO_STRING(id));
 
         RootedAtom atom(cx, cx->names().message);
         if (str == atom) {
             prop = js_message_str;
 
             /*
@@ -470,20 +463,20 @@ js_ErrorFromException(jsval exn)
 
     // It's ok to UncheckedUnwrap here, since all we do is get the
     // JSErrorReport, and consumers are careful with the information they get
     // from that anyway.  Anyone doing things that would expose anything in the
     // JSErrorReport to page script either does a security check on the
     // JSErrorReport's principal or also tries to do toString on our object and
     // will fail if they can't unwrap it.
     JSObject *obj = UncheckedUnwrap(JSVAL_TO_OBJECT(exn));
-    if (!obj->isError())
+    if (!obj->is<ErrorObject>())
         return NULL;
 
-    JSExnPrivate *priv = GetExnPrivate(obj);
+    JSExnPrivate *priv = obj->as<ErrorObject>().getExnPrivate();
     if (!priv)
         return NULL;
 
     return priv->errorReport;
 }
 
 static JSString *
 StackTraceToString(JSContext *cx, JSExnPrivate *priv)
@@ -545,17 +538,18 @@ Exception(JSContext *cx, unsigned argc, 
     if (!JSObject::getProperty(cx, callee, callee, cx->names().classPrototype, &protov))
         return false;
 
     if (!protov.isObject()) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_PROTOTYPE, "Error");
         return false;
     }
 
-    RootedObject obj(cx, NewObjectWithGivenProto(cx, &ErrorClass, &protov.toObject(), NULL));
+    RootedObject obj(cx, NewObjectWithGivenProto(cx, &ErrorObject::class_, &protov.toObject(),
+                     NULL));
     if (!obj)
         return false;
 
     /* Set the 'message' property. */
     RootedString message(cx);
     if (args.hasDefined(0)) {
         message = ToString<CanGC>(cx, args.handleAt(0));
         if (!message)
@@ -778,17 +772,18 @@ 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 JSObject *
 InitErrorClass(JSContext *cx, Handle<GlobalObject*> global, int type, HandleObject proto)
 {
     JSProtoKey key = GetExceptionProtoKey(type);
     RootedAtom name(cx, ClassName(key, cx));
-    RootedObject errorProto(cx, global->createBlankPrototypeInheriting(cx, &ErrorClass, *proto));
+    RootedObject errorProto(cx, global->createBlankPrototypeInheriting(cx, &ErrorObject::class_,
+                            *proto));
     if (!errorProto)
         return NULL;
 
     RootedValue nameValue(cx, StringValue(name));
     RootedValue zeroValue(cx, Int32Value(0));
     RootedValue empty(cx, StringValue(cx->runtime()->emptyString));
     RootedId nameId(cx, NameToId(cx->names().name));
     RootedId messageId(cx, NameToId(cx->names().message));
@@ -951,17 +946,17 @@ js_ErrorToException(JSContext *cx, const
      * exception constructor name in the scope chain of the current context's
      * top stack frame, or in the global object if no frame is active.
      */
     RootedObject errProto(cx);
     if (!js_GetClassPrototype(cx, GetExceptionProtoKey(exn), &errProto))
         return false;
     tv[0] = OBJECT_TO_JSVAL(errProto);
 
-    RootedObject errObject(cx, NewObjectWithGivenProto(cx, &ErrorClass, errProto, NULL));
+    RootedObject errObject(cx, NewObjectWithGivenProto(cx, &ErrorObject::class_, errProto, NULL));
     if (!errObject)
         return false;
     tv[1] = OBJECT_TO_JSVAL(errObject);
 
     RootedString messageStr(cx, reportp->ucmessage ? JS_NewUCStringCopyZ(cx, reportp->ucmessage)
                                                    : JS_NewStringCopyZ(cx, message));
     if (!messageStr)
         return false;
@@ -1042,18 +1037,17 @@ js_ReportUncaughtException(JSContext *cx
     /* XXX L10N angels cry once again. see also everywhere else */
     RootedString str(cx, ToString<CanGC>(cx, exn));
     if (str)
         roots[1] = StringValue(str);
 
     const char *filename_str = js_fileName_str;
     JSAutoByteString filename;
     if (!reportp && exnObject &&
-        (exnObject->isError() ||
-         IsDuckTypedErrorObject(cx, exnObject, &filename_str)))
+        (exnObject->is<ErrorObject>() || IsDuckTypedErrorObject(cx, exnObject, &filename_str)))
     {
         RootedString name(cx);
         if (JS_GetProperty(cx, exnObject, js_name_str, &roots[2]) &&
             JSVAL_IS_STRING(roots[2]))
         {
             name = JSVAL_TO_STRING(roots[2]);
         }
 
@@ -1134,17 +1128,17 @@ js_ReportUncaughtException(JSContext *cx
 
     return true;
 }
 
 extern JSObject *
 js_CopyErrorObject(JSContext *cx, HandleObject errobj, HandleObject scope)
 {
     assertSameCompartment(cx, scope);
-    JSExnPrivate *priv = GetExnPrivate(errobj);
+    JSExnPrivate *priv = errobj->as<ErrorObject>().getExnPrivate();
 
     size_t size = offsetof(JSExnPrivate, stackElems) +
                   priv->stackDepth * sizeof(JSStackTraceElem);
 
     ScopedJSFreePtr<JSExnPrivate> copy(static_cast<JSExnPrivate *>(cx->malloc_(size)));
     if (!copy)
         return NULL;
 
@@ -1169,16 +1163,16 @@ js_CopyErrorObject(JSContext *cx, Handle
     copy->column = priv->column;
     copy->stackDepth = 0;
     copy->exnType = priv->exnType;
 
     // Create the Error object.
     RootedObject proto(cx, scope->global().getOrCreateCustomErrorPrototype(cx, copy->exnType));
     if (!proto)
         return NULL;
-    RootedObject copyobj(cx, NewObjectWithGivenProto(cx, &ErrorClass, proto, NULL));
+    RootedObject copyobj(cx, NewObjectWithGivenProto(cx, &ErrorObject::class_, proto, NULL));
     if (!copyobj)
         return NULL;
-    SetExnPrivate(copyobj, copy);
+    SetExnPrivate(copyobj->as<ErrorObject>(), copy);
     copy.forget();
     autoFreeErrorReport.forget();
     return copyobj;
 }
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -202,17 +202,16 @@ DeleteSpecial(JSContext *cx, HandleObjec
 
 extern JSBool
 DeleteGeneric(JSContext *cx, HandleObject obj, HandleId id, JSBool *succeeded);
 
 } /* namespace js::baseops */
 
 extern Class ArrayClass;
 extern Class DateClass;
-extern Class ErrorClass;
 extern Class IntlClass;
 extern Class JSONClass;
 extern Class MathClass;
 extern Class ObjectClass;
 extern Class ProxyClass;
 extern Class RegExpStaticsClass;
 
 class ArrayBufferObject;
@@ -1073,17 +1072,16 @@ class JSObject : public js::ObjectImpl
     const T &as() const {
         JS_ASSERT(is<T>());
         return *static_cast<const T *>(this);
     }
 
     /* Direct subtypes of JSObject: */
     inline bool isArray()            const { return hasClass(&js::ArrayClass); }
     inline bool isDate()             const { return hasClass(&js::DateClass); }
-    inline bool isError()            const { return hasClass(&js::ErrorClass); }
     inline bool isObject()           const { return hasClass(&js::ObjectClass); }
     using js::ObjectImpl::isProxy;
     inline bool isRegExpStatics()    const { return hasClass(&js::RegExpStaticsClass); }
     inline bool isTypedArray()       const;
 
     /* Subtypes of Proxy. */
     inline bool isWrapper()                 const;
     inline bool isFunctionProxy()           const { return hasClass(&js::FunctionProxyClass); }
--- a/js/src/jswrapper.cpp
+++ b/js/src/jswrapper.cpp
@@ -8,16 +8,18 @@
 
 #include "jsapi.h"
 #include "jscntxt.h"
 #include "jscompartment.h"
 #include "jsexn.h"
 #include "jsgc.h"
 #include "jsiter.h"
 
+#include "vm/ErrorObject.h"
+
 #include "jsobjinlines.h"
 
 #include "builtin/Iterator-inl.h"
 
 using namespace js;
 using namespace js::gc;
 
 int js::sWrapperFamily;
@@ -133,17 +135,19 @@ js::TransparentObjectWrapper(JSContext *
     return Wrapper::New(cx, obj, wrappedProto, parent, &CrossCompartmentWrapper::singleton);
 }
 
 ErrorCopier::~ErrorCopier()
 {
     JSContext *cx = ac.ref().context();
     if (ac.ref().origin() != cx->compartment() && cx->isExceptionPending()) {
         RootedValue exc(cx, cx->getPendingException());
-        if (exc.isObject() && exc.toObject().isError() && exc.toObject().getPrivate()) {
+        if (exc.isObject() && exc.toObject().is<ErrorObject>() &&
+            exc.toObject().as<ErrorObject>().getExnPrivate())
+        {
             cx->clearPendingException();
             ac.destroy();
             Rooted<JSObject*> errObj(cx, &exc.toObject());
             JSObject *copyobj = js_CopyErrorObject(cx, errObj, scope);
             if (copyobj)
                 cx->setPendingException(ObjectValue(*copyobj));
         }
     }
new file mode 100644
--- /dev/null
+++ b/js/src/vm/ErrorObject.h
@@ -0,0 +1,26 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_ErrorObject_h_
+#define vm_ErrorObject_h_
+
+#include "jsobj.h"
+
+class JSExnPrivate;
+
+namespace js {
+
+class ErrorObject : public JSObject
+{
+  public:
+    static Class class_;
+
+    JSExnPrivate *getExnPrivate() { return static_cast<JSExnPrivate*>(getPrivate()); }
+};
+
+} // namespace js
+
+#endif // vm_ErrorObject_h_