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 285287 68ae644667f2a398d10bac8941c4b7ae2193281a
parent 285286 e4be65c87fcc7d04b662f90af45ca6d2f17fa59a
child 285288 138f7c7856b618dfd3f3faafcec9d3e164e188ec
push id30029
push usercbook@mozilla.com
push dateThu, 25 Feb 2016 10:53:34 +0000
treeherdermozilla-central@ad029c4e30b0 [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