Bug 739659 - Try duck typing in js_ReportUncaughtException. r=luke
authorMasatoshi Kimura <VYV03354@nifty.ne.jp>
Tue, 03 Apr 2012 20:08:28 -0400
changeset 94697 725a2ff9d08cad537cdae58afeeab12063b9accb
parent 94696 d42869982bf23c544c79eb01e238fbd00aecb2a0
child 94698 553c1d8965ca8daec27843f920ea928736b6281c
push id160
push userlsblakk@mozilla.com
push dateFri, 13 Jul 2012 18:18:57 +0000
treeherdermozilla-release@228ba1a111fc [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersluke
bugs739659
milestone14.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 739659 - Try duck typing in js_ReportUncaughtException. r=luke
dom/workers/test/test_errorPropagation.html
dom/workers/test/test_newError.html
dom/workers/test/test_recursiveOnerror.html
js/src/jsexn.cpp
--- a/dom/workers/test/test_errorPropagation.html
+++ b/dom/workers/test/test_errorPropagation.html
@@ -11,17 +11,17 @@
     <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
   </head>
   <body>
     <iframe id="workerFrame" src="errorPropagation_iframe.html"
             onload="workerFrameLoaded();"></iframe>
     <script type="text/javascript">
       const workerCount = 3;
 
-      const errorMessage = "expectedError";
+      const errorMessage = "Error: expectedError";
       const errorFilename = "http://mochi.test:8888/tests/dom/workers/test/" +
                             "errorPropagation_worker.js";
       const errorLineno = 48;
 
       var workerFrame;
 
       scopeErrorCount = 0;
       workerErrorCount = 0;
--- a/dom/workers/test/test_newError.html
+++ b/dom/workers/test/test_newError.html
@@ -15,17 +15,17 @@
   var worker = new Worker("newError_worker.js");
 
   worker.onmessage = function(event) {
     ok(false, "Shouldn't get a message!");
     SimpleTest.finish();
   }
 
   worker.onerror = function(event) {
-    is(event.message, "foo!", "Got wrong error message!");
+    is(event.message, "Error: foo!", "Got wrong error message!");
     event.preventDefault();
     SimpleTest.finish();
   }
 
   SimpleTest.waitForExplicitFinish();
 
 </script>
 </pre>
--- a/dom/workers/test/test_recursiveOnerror.html
+++ b/dom/workers/test/test_recursiveOnerror.html
@@ -9,18 +9,18 @@
     </script>
     <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
   </head>
   <body>
     <script type="text/javascript">
       const filename = "http://mochi.test:8888/tests/dom/workers/test/" +
                        "recursiveOnerror_worker.js";
       const errors = [
-        { message: "2", lineno: 6 },
-        { message: "1", lineno: 10 }
+        { message: "Error: 2", lineno: 6 },
+        { message: "Error: 1", lineno: 10 }
       ]
 
       var errorCount = 0;
 
       var worker = new Worker("recursiveOnerror_worker.js");
       worker.postMessage("go");
 
       worker.onerror = function(event) {
--- a/js/src/jsexn.cpp
+++ b/js/src/jsexn.cpp
@@ -1184,25 +1184,46 @@ js_ErrorToException(JSContext *cx, const
 
     JS_SetPendingException(cx, OBJECT_TO_JSVAL(errObject));
 
     /* Flag the error report passed in to indicate an exception was raised. */
     reportp->flags |= JSREPORT_EXCEPTION;
     return true;
 }
 
+static bool
+IsDuckTypedErrorObject(JSContext *cx, JSObject *exnObject, const char **filename_strp)
+{
+    JSBool found;
+    if (!JS_HasProperty(cx, exnObject, js_message_str, &found) || !found)
+        return false;
+
+    const char *filename_str = *filename_strp;
+    if (!JS_HasProperty(cx, exnObject, filename_str, &found) || !found) {
+        /* DOMException duck quacks "filename" (all lowercase) */
+        filename_str = "filename";
+        if (!JS_HasProperty(cx, exnObject, filename_str, &found) || !found)
+            return false;
+    }
+
+    if (!JS_HasProperty(cx, exnObject, js_lineNumber_str, &found) || !found)
+        return false;
+
+    *filename_strp = filename_str;
+    return true;
+}
+
 JSBool
 js_ReportUncaughtException(JSContext *cx)
 {
     jsval exn;
     JSObject *exnObject;
-    jsval roots[5];
+    jsval roots[6];
     JSErrorReport *reportp, report;
     JSString *str;
-    const char *bytes;
 
     if (!JS_IsExceptionPending(cx))
         return true;
 
     if (!JS_GetPendingException(cx, &exn))
         return false;
 
     PodArrayZero(roots);
@@ -1221,61 +1242,85 @@ js_ReportUncaughtException(JSContext *cx
         roots[0] = exn;
     }
 
     JS_ClearPendingException(cx);
     reportp = js_ErrorFromException(cx, exn);
 
     /* XXX L10N angels cry once again. see also everywhere else */
     str = ToString(cx, exn);
-    JSAutoByteString bytesStorage;
-    if (!str) {
-        bytes = "unknown (can't convert to string)";
-    } else {
+    if (str)
         roots[1] = StringValue(str);
-        if (!bytesStorage.encode(cx, str))
-            return false;
-        bytes = bytesStorage.ptr();
-    }
 
+    const char *filename_str = js_fileName_str;
     JSAutoByteString filename;
-    if (!reportp && exnObject && exnObject->isError()) {
-        if (!JS_GetProperty(cx, exnObject, js_message_str, &roots[2]))
-            return false;
-        if (JSVAL_IS_STRING(roots[2])) {
-            bytesStorage.clear();
-            if (!bytesStorage.encode(cx, str))
-                return false;
-            bytes = bytesStorage.ptr();
+    if (!reportp && exnObject &&
+        (exnObject->isError() ||
+         IsDuckTypedErrorObject(cx, exnObject, &filename_str)))
+    {
+        JSString *name = NULL;
+        if (JS_GetProperty(cx, exnObject, js_name_str, &roots[2]) &&
+            JSVAL_IS_STRING(roots[2]))
+        {
+            name = JSVAL_TO_STRING(roots[2]);
+        }
+
+        JSString *msg = NULL;
+        if (JS_GetProperty(cx, exnObject, js_message_str, &roots[3]) &&
+            JSVAL_IS_STRING(roots[3]))
+        {
+            msg = JSVAL_TO_STRING(roots[3]);
         }
 
-        if (!JS_GetProperty(cx, exnObject, js_fileName_str, &roots[3]))
-            return false;
-        str = ToString(cx, roots[3]);
-        if (!str || !filename.encode(cx, str))
-            return false;
+        if (name && msg) {
+            JSString *colon = JS_NewStringCopyZ(cx, ": ");
+            if (!colon)
+                return false;
+            JSString *nameColon = JS_ConcatStrings(cx, name, colon);
+            if (!nameColon)
+                return false;
+            str = JS_ConcatStrings(cx, nameColon, msg);
+            if (!str)
+                return false;
+        } else if (name) {
+            str = name;
+        } else if (msg) {
+            str = msg;
+        }
 
-        if (!JS_GetProperty(cx, exnObject, js_lineNumber_str, &roots[4]))
-            return false;
+        if (JS_GetProperty(cx, exnObject, filename_str, &roots[4])) {
+            JSString *tmp = ToString(cx, roots[4]);
+            if (tmp)
+                filename.encode(cx, tmp);
+        }
+
         uint32_t lineno;
-        if (!ToUint32(cx, roots[4], &lineno))
-            return false;
+        if (!JS_GetProperty(cx, exnObject, js_lineNumber_str, &roots[5]) ||
+            !ToUint32(cx, roots[5], &lineno))
+        {
+            lineno = 0;
+        }
 
         reportp = &report;
         PodZero(&report);
         report.filename = filename.ptr();
         report.lineno = (unsigned) lineno;
-        if (JSVAL_IS_STRING(roots[2])) {
-            JSFixedString *fixed = JSVAL_TO_STRING(roots[2])->ensureFixed(cx);
-            if (!fixed)
-                return false;
-            report.ucmessage = fixed->chars();
+        if (str) {
+            if (JSFixedString *fixed = str->ensureFixed(cx))
+                report.ucmessage = fixed->chars();
         }
     }
 
+    JSAutoByteString bytesStorage;
+    const char *bytes = NULL;
+    if (str)
+        bytes = bytesStorage.encode(cx, str);
+    if (!bytes)
+        bytes = "unknown (can't convert to string)";
+
     if (!reportp) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                              JSMSG_UNCAUGHT_EXCEPTION, bytes);
     } else {
         /* Flag the error as an exception. */
         reportp->flags |= JSREPORT_EXCEPTION;
 
         /* Pass the exception object. */