Bug 1245877 - Expose error message names via the debugger object; r=jorendorff
authorMorgan Phillips <winter2718@gmail.com>
Fri, 04 Mar 2016 12:21:57 -0800
changeset 286850 f3281396564ceaf5c45346fe0c71b9129b7c02b3
parent 286849 dfc843963851c884874a199a723efe5a9f9380a5
child 286851 7ce3d296a3fa5f8f074ff5dfa551af40b3707d1b
push id72949
push usermphillips@mozilla.com
push dateSat, 05 Mar 2016 02:16:41 +0000
treeherdermozilla-inbound@f3281396564c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjorendorff
bugs1245877
milestone47.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 1245877 - Expose error message names via the debugger object; r=jorendorff
dom/bindings/BindingUtils.cpp
js/src/ctypes/CTypes.cpp
js/src/doc/Debugger/Debugger.Object.md
js/src/jsapi.h
js/src/jscntxt.cpp
js/src/shell/js.cpp
js/src/vm/Debugger.cpp
js/xpconnect/src/XPCShellImpl.cpp
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -52,17 +52,17 @@
 #include "ipc/ErrorIPCUtils.h"
 #include "mozilla/UseCounter.h"
 
 namespace mozilla {
 namespace dom {
 
 JSErrorFormatString ErrorFormatString[] = {
 #define MSG_DEF(_name, _argc, _exn, _str) \
-  { _str, _argc, _exn },
+  { #_name, _str, _argc, _exn },
 #include "mozilla/dom/Errors.msg"
 #undef MSG_DEF
 };
 
 #define MSG_DEF(_name, _argc, _exn, _str) \
   static_assert(_argc < JS::MaxNumErrorArguments, \
                 #_name " must only have as many error arguments as the JS engine can support");
 #include "mozilla/dom/Errors.msg"
--- a/js/src/ctypes/CTypes.cpp
+++ b/js/src/ctypes/CTypes.cpp
@@ -877,17 +877,17 @@ GetABICode(JSObject* obj)
     return INVALID_ABI;
 
   Value result = JS_GetReservedSlot(obj, SLOT_ABICODE);
   return ABICode(result.toInt32());
 }
 
 static const JSErrorFormatString ErrorFormatString[CTYPESERR_LIMIT] = {
 #define MSG_DEF(name, count, exception, format) \
-  { format, count, exception } ,
+  { #name, format, count, exception } ,
 #include "ctypes/ctypes.msg"
 #undef MSG_DEF
 };
 
 static const JSErrorFormatString*
 GetErrorMessage(void* userRef, const unsigned errorNumber)
 {
   if (0 < errorNumber && errorNumber < CTYPESERR_LIMIT)
--- a/js/src/doc/Debugger/Debugger.Object.md
+++ b/js/src/doc/Debugger/Debugger.Object.md
@@ -543,8 +543,14 @@ code), the call throws a [`Debugger.Debu
     method makes it easier to gradually adapt large code bases to this
     Debugger API: adapted portions of the code can use `Debugger.Object`
     instances, but use this method to pass direct object references to code
     that has not yet been updated.
 
 <code>forceLexicalInitializationByName(<i>binding</i>)</code>
 :  If <i>binding</i> is in an uninitialized state initialize it to undefined
    and return true, otherwise do nothing and return false.
+
+<code>getErrorMessageName(<i>errorObject</i>)</code>
+:  If <i>errorObject</i> was created with an engine internal message template
+   the name of the template is returned as a string. Because they are stable
+   and unique these message names may be used to identify particular kinds of
+   engine produced errors.
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -627,16 +627,19 @@ typedef enum JSExnType {
         JSEXN_SYNTAXERR,
         JSEXN_TYPEERR,
         JSEXN_URIERR,
         JSEXN_DEBUGGEEWOULDRUN,
         JSEXN_LIMIT
 } JSExnType;
 
 typedef struct JSErrorFormatString {
+     /** The error message name in ASCII. */
+    const char* name;
+
     /** The error format string in ASCII. */
     const char* format;
 
     /** The number of arguments to expand in the formatted error message. */
     uint16_t argCount;
 
     /** One of the JSExnType constants above. */
     int16_t exnType;
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -901,17 +901,17 @@ js::ReportValueErrorFlags(JSContext* cx,
 
     ok = JS_ReportErrorFlagsAndNumber(cx, flags, GetErrorMessage,
                                       nullptr, errorNumber, bytes.get(), arg1, arg2);
     return ok;
 }
 
 const JSErrorFormatString js_ErrorFormatString[JSErr_Limit] = {
 #define MSG_DEF(name, count, exception, format) \
-    { format, count, exception } ,
+    { #name, format, count, exception } ,
 #include "js.msg"
 #undef MSG_DEF
 };
 
 JS_FRIEND_API(const JSErrorFormatString*)
 js::GetErrorMessage(void* userRef, const unsigned errorNumber)
 {
     if (errorNumber > 0 && errorNumber < JSErr_Limit)
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -5697,17 +5697,17 @@ Help(JSContext* cx, unsigned argc, Value
     }
 
     args.rval().setUndefined();
     return true;
 }
 
 static const JSErrorFormatString jsShell_ErrorFormatString[JSShellErr_Limit] = {
 #define MSG_DEF(name, count, exception, format) \
-    { format, count, JSEXN_ERR } ,
+    { #name, format, count, JSEXN_ERR } ,
 #include "jsshell.msg"
 #undef MSG_DEF
 };
 
 const JSErrorFormatString*
 js::shell::my_GetErrorMessage(void* userRef, const unsigned errorNumber)
 {
     if (errorNumber == 0 || errorNumber >= JSShellErr_Limit)
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -8066,16 +8066,55 @@ DebuggerObject_forceLexicalInitializatio
             globalLexical->as<NativeObject>().setSlot(shape->slot(), UndefinedValue());
             initialized = true;
         }
     }
     args.rval().setBoolean(initialized);
     return true;
 }
 
+// Returns the "name" field (see js.msg), which may be used as a unique
+// identifier, for any error object with a JSErrorReport or undefined
+// if the error object has no JSErrorReport.
+bool
+DebuggerObject_getErrorMessageName(JSContext *cx, unsigned argc, Value* vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+    if (!args.requireAtLeast(cx, "Debugger.Object.prototype.getErrorMessageName", 1))
+        return false;
+
+    RootedObject obj(cx);
+
+    bool isErrorObject = false;
+    if (args[0].isObject()) {
+        obj = &args[0].toObject();
+        if (IsCrossCompartmentWrapper(obj))
+            obj = UncheckedUnwrap(obj);
+        isErrorObject = obj->is<ErrorObject>();
+    }
+
+    if (!isErrorObject) {
+        JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_UNEXPECTED_TYPE,
+                             "argument", "not an error object");
+        return false;
+    }
+
+    JSErrorReport* report = obj->as<ErrorObject>().getErrorReport();
+
+    if (report) {
+        const JSErrorFormatString* efs = GetErrorMessage(nullptr, report->errorNumber);
+        RootedString str(cx, JS_NewStringCopyZ(cx, efs->name));
+        args.rval().setString(str);
+    } else {
+        args.rval().setUndefined();
+    }
+
+    return true;
+}
+
 static bool
 DebuggerObject_executeInGlobal(JSContext* cx, unsigned argc, Value* vp)
 {
     THIS_DEBUGOBJECT_OWNER_REFERENT(cx, argc, vp, "executeInGlobal", args, dbg, referent);
     if (!args.requireAtLeast(cx, "Debugger.Object.prototype.executeInGlobal", 1))
         return false;
     if (!RequireGlobalObject(cx, args.thisv(), referent))
         return false;
@@ -8186,16 +8225,17 @@ static const JSFunctionSpec DebuggerObje
     JS_FN("defineProperty", DebuggerObject_defineProperty, 2, 0),
     JS_FN("defineProperties", DebuggerObject_defineProperties, 1, 0),
     JS_FN("deleteProperty", DebuggerObject_deleteProperty, 1, 0),
     JS_FN("seal", DebuggerObject_seal, 0, 0),
     JS_FN("freeze", DebuggerObject_freeze, 0, 0),
     JS_FN("preventExtensions", DebuggerObject_preventExtensions, 0, 0),
     JS_FN("isSealed", DebuggerObject_isSealed, 0, 0),
     JS_FN("forceLexicalInitializationByName", DebuggerObject_forceLexicalInitializationByName, 1, 0),
+    JS_FN("getErrorMessageName", DebuggerObject_getErrorMessageName, 1, 0),
     JS_FN("isFrozen", DebuggerObject_isFrozen, 0, 0),
     JS_FN("isExtensible", DebuggerObject_isExtensible, 0, 0),
     JS_FN("apply", DebuggerObject_apply, 0, 0),
     JS_FN("call", DebuggerObject_call, 0, 0),
     JS_FN("makeDebuggeeValue", DebuggerObject_makeDebuggeeValue, 1, 0),
     JS_FN("executeInGlobal", DebuggerObject_executeInGlobal, 1, 0),
     JS_FN("executeInGlobalWithBindings", DebuggerObject_executeInGlobalWithBindings, 2, 0),
     JS_FN("asEnvironment", DebuggerObject_asEnvironment, 0, 0),
--- a/js/xpconnect/src/XPCShellImpl.cpp
+++ b/js/xpconnect/src/XPCShellImpl.cpp
@@ -804,17 +804,17 @@ typedef enum JSShellErrNum {
     name = number,
 #include "jsshell.msg"
 #undef MSG_DEF
     JSShellErr_Limit
 } JSShellErrNum;
 
 static const JSErrorFormatString jsShell_ErrorFormatString[JSShellErr_Limit] = {
 #define MSG_DEF(name, number, count, exception, format) \
-    { format, count } ,
+    { #name, format, count } ,
 #include "jsshell.msg"
 #undef MSG_DEF
 };
 
 static const JSErrorFormatString*
 my_GetErrorMessage(void* userRef, const unsigned errorNumber)
 {
     if (errorNumber == 0 || errorNumber >= JSShellErr_Limit)