Bug 1208641 - Extract stack from DOM/XPC exception. r=bholley
authorWei-Cheng Pan <wpan@mozilla.com>
Wed, 24 Feb 2016 02:06:42 -0800
changeset 321623 68ae644667f2a398d10bac8941c4b7ae2193281a
parent 321622 e4be65c87fcc7d04b662f90af45ca6d2f17fa59a
child 321624 138f7c7856b618dfd3f3faafcec9d3e164e188ec
push id5913
push userjlund@mozilla.com
push dateMon, 25 Apr 2016 16:57:49 +0000
treeherdermozilla-beta@dcaf0a6fa115 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbholley
bugs1208641
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 1208641 - Extract stack from DOM/XPC exception. r=bholley
dom/base/nsJSEnvironment.cpp
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -47,16 +47,18 @@
 #include "nsIArray.h"
 #include "nsIObjectInputStream.h"
 #include "nsIObjectOutputStream.h"
 #include "prmem.h"
 #include "WrapperFactory.h"
 #include "nsGlobalWindow.h"
 #include "nsScriptNameSpaceManager.h"
 #include "mozilla/AutoRestore.h"
+#include "mozilla/dom/DOMException.h"
+#include "mozilla/dom/DOMExceptionBinding.h"
 #include "mozilla/dom/ErrorEvent.h"
 #include "nsAXPCNativeCallContext.h"
 #include "mozilla/CycleCollectedJSRuntime.h"
 
 #include "nsJSPrincipals.h"
 
 #ifdef XP_MACOSX
 // AssertMacros.h defines 'check' and conflicts with AccessCheck.h
@@ -218,16 +220,51 @@ static const int32_t kPokesBetweenExpens
 
 static const char*
 ProcessNameForCollectorLog()
 {
   return XRE_GetProcessType() == GeckoProcessType_Default ?
     "default" : "content";
 }
 
+// This handles JS Exceptions (via ExceptionStackOrNull), as well as DOM and XPC Exceptions.
+//
+// Note that the returned object is _not_ wrapped into the compartment of cx.
+static JSObject*
+FindExceptionStack(JSContext* cx, JS::HandleObject exceptionObject)
+{
+  JSAutoCompartment ac(cx, exceptionObject);
+  JS::RootedObject stackObject(cx, ExceptionStackOrNull(cx, exceptionObject));
+  if (stackObject) {
+    return stackObject;
+  }
+
+  // It is not a JS Exception, try DOM Exception.
+  RefPtr<Exception> exception;
+  UNWRAP_OBJECT(DOMException, exceptionObject, exception);
+  if (!exception) {
+    // Not a DOM Exception, try XPC Exception.
+    UNWRAP_OBJECT(Exception, exceptionObject, exception);
+    if (!exception) {
+      return nullptr;
+    }
+  }
+
+  nsCOMPtr<nsIStackFrame> stack = exception->GetLocation();
+  if (!stack) {
+    return nullptr;
+  }
+  JS::RootedValue value(cx);
+  stack->GetNativeSavedFrame(&value);
+  if (value.isObject()) {
+    stackObject = &value.toObject();
+  }
+  return stackObject;
+}
+
 static PRTime
 GetCollectionTimeDelta()
 {
   PRTime now = PR_Now();
   if (sFirstCollectionTime) {
     return now - sFirstCollectionTime;
   }
   sFirstCollectionTime = now;
@@ -421,17 +458,17 @@ public:
       if (mError.isObject()) {
         AutoJSAPI jsapi;
         if (NS_WARN_IF(!jsapi.Init(mError.toObjectOrNull()))) {
           mReport->LogToConsole();
           return NS_OK;
         }
         JSContext* cx = jsapi.cx();
         JS::Rooted<JSObject*> exObj(cx, mError.toObjectOrNull());
-        JS::RootedObject stack(cx, ExceptionStackOrNull(cx, exObj));
+        JS::RootedObject stack(cx, FindExceptionStack(cx, exObj));
         mReport->LogToConsoleWithStack(stack);
       } else {
         mReport->LogToConsole();
       }
 
     }
 
     return NS_OK;
@@ -507,17 +544,17 @@ SystemErrorReporter(JSContext *cx, const
     // directly. This includes the case where the error was an OOM, because
     // triggering a scripted event handler is likely to generate further OOMs.
     if (!win || JSREPORT_IS_WARNING(xpcReport->mFlags) ||
         report->errorNumber == JSMSG_OUT_OF_MEMORY)
     {
       if (exception.isObject()) {
         JS::RootedObject exObj(cx, exception.toObjectOrNull());
         JSAutoCompartment ac(cx, exObj);
-        JS::RootedObject stackVal(cx, ExceptionStackOrNull(cx, exObj));
+        JS::RootedObject stackVal(cx, FindExceptionStack(cx, exObj));
         xpcReport->LogToConsoleWithStack(stackVal);
       } else {
         xpcReport->LogToConsole();
       }
       return;
     }
 
     // Otherwise, we need to asynchronously invoke onerror before we can decide