Bug 911258: Part 3 - Convert exceptions to WebIDL. r=bz
authorKyle Huey <khuey@kylehuey.com>
Sun, 08 Sep 2013 20:28:49 -0700
changeset 147405 16cf9da0d24282153c9ea53e49439dcb3aac194f
parent 147404 c04e927b631b053fc9e8d26840bac101869c550e
child 147406 3f4223fab461f9a4e5b4fe646db5a0625cedd31e
push id2961
push userlsblakk@mozilla.com
push dateMon, 28 Oct 2013 21:59:28 +0000
treeherdermozilla-esr52@73ef4f13486f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs911258
milestone26.0a1
Bug 911258: Part 3 - Convert exceptions to WebIDL. r=bz
dom/base/nsDOMException.cpp
dom/base/nsDOMException.h
dom/bindings/Bindings.conf
dom/indexedDB/IDBEvents.cpp
dom/webidl/DOMException.webidl
dom/webidl/WebIDL.mk
dom/workers/Exceptions.cpp
js/xpconnect/src/XPCComponents.cpp
js/xpconnect/src/XPCConvert.cpp
js/xpconnect/src/XPCException.cpp
js/xpconnect/src/XPCModule.cpp
js/xpconnect/src/XPCThrower.cpp
js/xpconnect/src/XPCWrappedJSClass.cpp
js/xpconnect/src/xpcprivate.h
--- a/dom/base/nsDOMException.cpp
+++ b/dom/base/nsDOMException.cpp
@@ -10,19 +10,20 @@
 #include "nsCRTGlue.h"
 #include "nsContentUtils.h"
 #include "nsDOMClassInfoID.h"
 #include "nsError.h"
 #include "nsIDOMDOMException.h"
 #include "nsIDocument.h"
 #include "nsString.h"
 #include "prprf.h"
-#include "nsIException.h"
+#include "mozilla/dom/DOMExceptionBinding.h"
 
 using namespace mozilla;
+namespace DOMExceptionBinding = mozilla::dom::DOMExceptionBinding;
 
 enum DOM4ErrorTypeCodeMap {
   /* DOM4 errors from http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#domexception */
   IndexSizeError             = nsIDOMDOMException::INDEX_SIZE_ERR,
   HierarchyRequestError      = nsIDOMDOMException::HIERARCHY_REQUEST_ERR,
   WrongDocumentError         = nsIDOMDOMException::WRONG_DOCUMENT_ERR,
   InvalidCharacterError      = nsIDOMDOMException::INVALID_CHARACTER_ERR,
   NoModificationAllowedError = nsIDOMDOMException::NO_MODIFICATION_ALLOWED_ERR,
@@ -120,63 +121,45 @@ NS_GetNameAndMessageForDOMNSResult(nsres
       *aCode = code;
     }
     return NS_OK;
   }
 
   return NS_ERROR_NOT_AVAILABLE;
 }
 
-
-class nsDOMException : public nsIException,
-                       public nsIDOMDOMException
-{
-public:
-  nsDOMException() {}
-  virtual ~nsDOMException() {}
-
-  NS_DECL_ISUPPORTS
-  NS_DECL_NSIEXCEPTION
-  NS_IMETHOD Init(nsresult aNSResult, const char* aName,
-                  const char* aMessage, uint16_t aCode,
-                  nsIException* aDefaultException);
-  NS_DECL_NSIDOMDOMEXCEPTION
-
-protected:
-  const char* mName;
-  const char* mMessage;
-  nsCOMPtr<nsIException> mInner;
-  nsresult mResult;
-  uint16_t mCode;
-};
-
 DOMCI_DATA(DOMException, nsDOMException) 
 
-NS_IMPL_ADDREF(nsDOMException)
-NS_IMPL_RELEASE(nsDOMException)
+NS_IMPL_ADDREF_INHERITED(nsDOMException, nsXPCException)
+NS_IMPL_RELEASE_INHERITED(nsDOMException, nsXPCException)
 NS_INTERFACE_MAP_BEGIN(nsDOMException)
-  NS_INTERFACE_MAP_ENTRY(nsIException)
   NS_INTERFACE_MAP_ENTRY(nsIDOMDOMException)
-  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIException)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(DOMException)
-NS_INTERFACE_MAP_END
+NS_INTERFACE_MAP_END_INHERITING(nsXPCException)
 
-nsresult
-NS_NewDOMException(nsresult aNSResult, nsIException* aDefaultException,
-                   nsIException** aException)
+nsDOMException::nsDOMException(nsresult aRv, const char* aMessage,
+                               const char* aName, uint16_t aCode)
+  : nsXPCException(nullptr, aRv, nullptr, nullptr, nullptr),
+    mName(aName),
+    mMessage(aMessage),
+    mCode(aCode)
+{
+  SetIsDOMBinding();
+}
+
+already_AddRefed<nsDOMException>
+NS_NewDOMException(nsresult aNSResult)
 {
   const char* name;
   const char* message;
   uint16_t code;
   NSResultToNameAndMessage(aNSResult, &name, &message, &code);
-  nsDOMException* inst = new nsDOMException();
-  inst->Init(aNSResult, name, message, code, aDefaultException);
-  *aException = inst;
-  NS_ADDREF(*aException);
-  return NS_OK;
+  nsRefPtr<nsDOMException> inst =
+    new nsDOMException(aNSResult, message, name, code);
+  return inst.forget();
 }
 
 NS_IMETHODIMP
 nsDOMException::GetCode(uint16_t* aCode)
 {
   NS_ENSURE_ARG_POINTER(aCode);
   *aCode = mCode;
 
@@ -188,132 +171,16 @@ nsDOMException::GetCode(uint16_t* aCode)
       doc->WarnOnceAbout(nsIDocument::eDOMExceptionCode);
     }
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsDOMException::GetMessageMoz(char **aMessage)
-{
-  if (mMessage) {
-    *aMessage = NS_strdup(mMessage);
-  } else {
-    *aMessage = nullptr;
-  }
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsDOMException::GetResult(nsresult* aResult)
-{
-  NS_ENSURE_ARG_POINTER(aResult);
-
-  *aResult = mResult;
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsDOMException::GetName(char **aName)
-{
-  NS_ENSURE_ARG_POINTER(aName);
-
-  if (mName) {
-    *aName = NS_strdup(mName);
-  } else {
-    *aName = nullptr;
-  }
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsDOMException::GetFilename(char **aFilename)
-{
-  if (mInner) {
-    return mInner->GetFilename(aFilename);
-  }
-
-  NS_ENSURE_ARG_POINTER(aFilename);
-
-  *aFilename = nullptr;
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsDOMException::GetLineNumber(uint32_t *aLineNumber)
-{
-  if (mInner) {
-    return mInner->GetLineNumber(aLineNumber);
-  }
-
-  NS_ENSURE_ARG_POINTER(aLineNumber);
-
-  *aLineNumber = 0;
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsDOMException::GetColumnNumber(uint32_t *aColumnNumber)
-{
-  if (mInner) {
-    return mInner->GetColumnNumber(aColumnNumber);
-  }
-
-  NS_ENSURE_ARG_POINTER(aColumnNumber);
-
-  *aColumnNumber = 0;
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsDOMException::GetLocation(nsIStackFrame **aLocation)
-{
-  if (mInner) {
-    return mInner->GetLocation(aLocation);
-  }
-
-  NS_ENSURE_ARG_POINTER(aLocation);
-
-  *aLocation = nullptr;
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsDOMException::GetInner(nsIException **aInner)
-{
-  NS_ENSURE_ARG_POINTER(aInner);
-
-  *aInner = nullptr;
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsDOMException::GetData(nsISupports **aData)
-{
-  if (mInner) {
-    return mInner->GetData(aData);
-  }
-
-  NS_ENSURE_ARG_POINTER(aData);
-
-  *aData = nullptr;
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP
 nsDOMException::ToString(char **aReturn)
 {
   *aReturn = nullptr;
 
   static const char defaultMsg[] = "<no message>";
   static const char defaultLocation[] = "<unknown>";
   static const char defaultName[] = "<unknown>";
   static const char format[] =
@@ -347,20 +214,25 @@ nsDOMException::ToString(char **aReturn)
   const char* resultName = mName ? mName : defaultName;
 
   *aReturn = PR_smprintf(format, msg, mCode, mResult, resultName,
                          location.get());
 
   return *aReturn ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
 }
 
-NS_IMETHODIMP
-nsDOMException::Init(nsresult aNSResult, const char* aName,
-                     const char* aMessage, uint16_t aCode,
-                     nsIException* aDefaultException)
+void
+nsDOMException::GetName(nsString& retval)
+{
+  CopyUTF8toUTF16(mName, retval);
+}
+
+void
+nsDOMException::GetMessageMoz(nsString& retval)
 {
-  mResult = aNSResult;
-  mName = aName;
-  mMessage = aMessage;
-  mCode = aCode;
-  mInner = aDefaultException;
-  return NS_OK;
+  CopyUTF8toUTF16(mMessage, retval);
 }
+
+JSObject*
+nsDOMException::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
+{
+  return DOMExceptionBinding::Wrap(aCx, aScope, this);
+}
--- a/dom/base/nsDOMException.h
+++ b/dom/base/nsDOMException.h
@@ -1,17 +1,67 @@
 /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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/. */
 
+// We intentionally shadow non-virtual methods, but gcc gets confused.
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Woverloaded-virtual"
+#endif
+
 #include "mozilla/NullPtr.h"
 #include "nsError.h"
-class nsIException;
+#include "nsIDOMDOMException.h"
+#include "nsIException.h"
+#include "nsCOMPtr.h"
+#include "xpcprivate.h"
+
+template<typename> class already_AddRefed;
+
+class nsDOMException : public nsXPCException,
+                       public nsIDOMDOMException
+{
+public:
+  nsDOMException(nsresult aRv, const char* aMessage,
+                 const char* aName, uint16_t aCode);
+
+  NS_DECL_ISUPPORTS_INHERITED
+  NS_DECL_NSIDOMDOMEXCEPTION
+
+  // nsIException overrides
+  NS_IMETHOD ToString(char **aReturn) MOZ_OVERRIDE;
+
+  // nsWrapperCache overrides
+  virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
+    MOZ_OVERRIDE;
+
+  uint16_t Code() const {
+    return mCode;
+  }
+
+  // Intentionally shadow the nsXPCException version.
+  void GetMessageMoz(nsString& retval);
+  void GetName(nsString& retval);
+
+protected:
+
+  virtual ~nsDOMException() {}
+
+  // Intentionally shadow the nsXPCException version.
+  const char* mName;
+  const char* mMessage;
+
+  uint16_t mCode;
+};
 
 nsresult
 NS_GetNameAndMessageForDOMNSResult(nsresult aNSResult, const char** aName,
                                    const char** aMessage,
                                    uint16_t* aCode = nullptr);
 
-nsresult
-NS_NewDOMException(nsresult aNSResult, nsIException* aDefaultException,
-                   nsIException** aException);
+already_AddRefed<nsDOMException>
+NS_NewDOMException(nsresult aNSResult);
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -314,16 +314,23 @@ DOMInterfaces = {
     'workers': True,
     'skipGen': True
 }],
 
 'DocumentFragment': {
     'resultNotAddRefed': [ 'querySelector' ]
 },
 
+'DOMException': {
+    'nativeType': 'nsDOMException',
+    'binaryNames': {
+        'message': 'messageMoz',
+    },
+},
+
 'DOMSettableTokenList': {
     'nativeType': 'nsDOMSettableTokenList',
 },
 
 'DOMStringMap': {
     'nativeType': 'nsDOMStringMap'
 },
 
@@ -386,16 +393,24 @@ DOMInterfaces = {
     'concrete': False,
     'jsImplParent': 'nsDOMEventTargetHelper'
 },
 {
     'workers': True,
     'concrete': False
 }],
 
+'Exception': {
+    'nativeType': 'nsXPCException',
+    'headerFile': 'xpcprivate.h',
+    'binaryNames': {
+        'message': 'messageMoz',
+    }
+},
+
 'FileHandle': {
     'nativeType': 'mozilla::dom::file::FileHandle'
 },
 
 'FileList': {
     'nativeType': 'nsDOMFileList',
     'headerFile': 'nsDOMFile.h',
     'resultNotAddRefed': [ 'item' ]
@@ -1807,16 +1822,18 @@ addExternalIface('nsIEditor', nativeType
 addExternalIface('nsIVariant', nativeType='nsIVariant', notflattened=True)
 addExternalIface('OutputStream', nativeType='nsIOutputStream',
                  notflattened=True)
 addExternalIface('Principal', nativeType='nsIPrincipal',
                  headerFile='nsIPrincipal.h', notflattened=True)
 addExternalIface('PrintCallback', nativeType='nsIPrintCallback',
                  headerFile='nsIDOMHTMLCanvasElement.h')
 addExternalIface('Selection', nativeType='nsISelection')
+addExternalIface('StackFrame', nativeType='nsIStackFrame',
+                 headerFile='nsIException.h', notflattened=True)
 addExternalIface('StyleSheetList')
 addExternalIface('SVGLength')
 addExternalIface('SVGNumber')
 addExternalIface('URI', nativeType='nsIURI', headerFile='nsIURI.h',
                  notflattened=True)
 addExternalIface('UserDataHandler')
 addExternalIface('Window')
 addExternalIface('XPathResult', nativeType='nsISupports')
--- a/dom/indexedDB/IDBEvents.cpp
+++ b/dom/indexedDB/IDBEvents.cpp
@@ -1,17 +1,16 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* 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/. */
 
 #include "IDBEvents.h"
 
-#include "nsDOMException.h"
 #include "nsJSON.h"
 #include "nsThreadUtils.h"
 
 #include "IDBRequest.h"
 #include "IDBTransaction.h"
 
 USING_INDEXEDDB_NAMESPACE
 using namespace mozilla::dom;
new file mode 100644
--- /dev/null
+++ b/dom/webidl/DOMException.webidl
@@ -0,0 +1,97 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/.
+ *
+ * The origin of this IDL file is
+ * http://dom.spec.whatwg.org/#exception-domexception
+ *
+ * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
+ * liability, trademark and document use rules apply.
+ */
+
+
+// This is the WebIDL version of nsIException.  This is mostly legacy stuff.
+
+interface StackFrame;
+
+[NoInterfaceObject]
+interface ExceptionMembers
+{
+  // A custom message set by the thrower.
+  readonly attribute DOMString               message;
+  // The nsresult associated with this exception.
+  readonly attribute unsigned long           result;
+  // The name of the error code (ie, a string repr of |result|)
+  readonly attribute DOMString               name;
+
+  // Filename location.  This is the location that caused the
+  // error, which may or may not be a source file location.
+  // For example, standard language errors would generally have
+  // the same location as their top stack entry.  File
+  // parsers may put the location of the file they were parsing,
+  // etc.
+
+  // null indicates "no data"
+  readonly attribute DOMString               filename;
+  // Valid line numbers begin at '1'. '0' indicates unknown.
+  readonly attribute unsigned long           lineNumber;
+  // Valid column numbers begin at 0. 
+  // We don't have an unambiguous indicator for unknown.
+  readonly attribute unsigned long           columnNumber;
+
+  // A stack trace, if available.  nsIStackFrame does not have classinfo so
+  // this was only ever usefully available to chrome JS.
+  [ChromeOnly]
+  readonly attribute StackFrame?             location;
+  // An inner exception that triggered this, if available.
+  readonly attribute nsISupports?            inner;
+
+  // Arbitary data for the implementation.
+  readonly attribute nsISupports?            data;
+
+  // A generic formatter - make it suitable to print, etc.
+  stringifier;
+};
+
+[NoInterfaceObject]
+interface Exception {
+};
+
+Exception implements ExceptionMembers;
+
+// XXXkhuey this is an 'exception', not an interface, but we don't have any
+// parser or codegen mechanisms for dealing with exceptions.
+interface DOMException {
+  const unsigned short INDEX_SIZE_ERR = 1;
+  const unsigned short DOMSTRING_SIZE_ERR = 2; // historical
+  const unsigned short HIERARCHY_REQUEST_ERR = 3;
+  const unsigned short WRONG_DOCUMENT_ERR = 4;
+  const unsigned short INVALID_CHARACTER_ERR = 5;
+  const unsigned short NO_DATA_ALLOWED_ERR = 6; // historical
+  const unsigned short NO_MODIFICATION_ALLOWED_ERR = 7;
+  const unsigned short NOT_FOUND_ERR = 8;
+  const unsigned short NOT_SUPPORTED_ERR = 9;
+  const unsigned short INUSE_ATTRIBUTE_ERR = 10; // historical
+  const unsigned short INVALID_STATE_ERR = 11;
+  const unsigned short SYNTAX_ERR = 12;
+  const unsigned short INVALID_MODIFICATION_ERR = 13;
+  const unsigned short NAMESPACE_ERR = 14;
+  const unsigned short INVALID_ACCESS_ERR = 15;
+  const unsigned short VALIDATION_ERR = 16; // historical
+  const unsigned short TYPE_MISMATCH_ERR = 17; // historical; use JavaScript's TypeError instead
+  const unsigned short SECURITY_ERR = 18;
+  const unsigned short NETWORK_ERR = 19;
+  const unsigned short ABORT_ERR = 20;
+  const unsigned short URL_MISMATCH_ERR = 21;
+  const unsigned short QUOTA_EXCEEDED_ERR = 22;
+  const unsigned short TIMEOUT_ERR = 23;
+  const unsigned short INVALID_NODE_TYPE_ERR = 24;
+  const unsigned short DATA_CLONE_ERR = 25;
+
+  readonly attribute unsigned short code;
+};
+
+// XXXkhuey copy all of Gecko's non-standard stuff onto DOMException, but leave
+// the prototype chain sane.
+DOMException implements ExceptionMembers;
--- a/dom/webidl/WebIDL.mk
+++ b/dom/webidl/WebIDL.mk
@@ -64,16 +64,17 @@ webidl_files = \
   DesktopNotification.webidl \
   DeviceMotionEvent.webidl \
   DeviceStorage.webidl \
   Document.webidl \
   DocumentFragment.webidl \
   DocumentType.webidl \
   DOMCursor.webidl \
   DOMError.webidl \
+  DOMException.webidl \
   DOMImplementation.webidl \
   DOMMMIError.webidl \
   DOMParser.webidl \
   DOMRequest.webidl \
   DOMSettableTokenList.webidl \
   DOMStringMap.webidl \
   DOMTokenList.webidl \
   DOMTransaction.webidl \
--- a/dom/workers/Exceptions.cpp
+++ b/dom/workers/Exceptions.cpp
@@ -4,21 +4,25 @@
  * 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/. */
 
 #include "Exceptions.h"
 
 #include "jsapi.h"
 #include "jsfriendapi.h"
 #include "mozilla/Util.h"
-#include "nsDOMException.h"
 #include "nsTraceRefcnt.h"
 
 #include "WorkerInlines.h"
 
+nsresult
+NS_GetNameAndMessageForDOMNSResult(nsresult aNSResult, const char** aName,
+                                   const char** aMessage,
+                                   uint16_t* aCode = nullptr);
+
 #define PROPERTY_FLAGS \
   (JSPROP_ENUMERATE | JSPROP_SHARED)
 
 #define CONSTANT_FLAGS \
   JSPROP_ENUMERATE | JSPROP_SHARED | JSPROP_PERMANENT | JSPROP_READONLY
 
 using namespace mozilla;
 USING_WORKERS_NAMESPACE
--- a/js/xpconnect/src/XPCComponents.cpp
+++ b/js/xpconnect/src/XPCComponents.cpp
@@ -34,16 +34,17 @@
 #include "mozilla/Attributes.h"
 #include "nsIScriptContext.h"
 #include "nsJSEnvironment.h"
 #include "nsXMLHttpRequest.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/XPTInterfaceInfoManager.h"
 #include "nsDOMClassInfoID.h"
 #include "nsGlobalWindow.h"
+#include "mozilla/dom/DOMExceptionBinding.h"
 
 using namespace mozilla;
 using namespace JS;
 using namespace js;
 using namespace xpc;
 
 /***************************************************************************/
 // stuff used by all
@@ -1951,19 +1952,19 @@ nsXPCComponents_Exception::CallOrConstru
         return NS_OK;
     }
 
     // Parse the arguments to the Exception constructor.
     ExceptionArgParser parser(cx, xpc);
     if (!parser.parse(args))
         return ThrowAndFail(NS_ERROR_XPC_BAD_CONVERT_JS, cx, _retval);
 
-    nsCOMPtr<nsIException> e;
-    nsXPCException::NewException(parser.eMsg, parser.eResult, parser.eStack,
-                                 parser.eData, getter_AddRefs(e));
+    nsCOMPtr<nsIException> e = new nsXPCException(parser.eMsg, parser.eResult,
+                                                  nullptr, parser.eStack,
+                                                  parser.eData);
     if (!e)
         return ThrowAndFail(NS_ERROR_XPC_UNEXPECTED, cx, _retval);
 
     nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
     RootedObject newObj(cx);
 
     if (NS_FAILED(xpc->WrapNative(cx, obj, e, NS_GET_IID(nsIXPCException),
                                   getter_AddRefs(holder))) || !holder ||
@@ -1978,19 +1979,24 @@ nsXPCComponents_Exception::CallOrConstru
 
 /* bool hasInstance (in nsIXPConnectWrappedNative wrapper, in JSContextPtr cx, in JSObjectPtr obj, in jsval val, out bool bp); */
 NS_IMETHODIMP
 nsXPCComponents_Exception::HasInstance(nsIXPConnectWrappedNative *wrapper,
                                        JSContext * cx, JSObject * obj,
                                        const jsval &val, bool *bp,
                                        bool *_retval)
 {
+    using namespace mozilla::dom;
+
     RootedValue v(cx, val);
-    if (bp)
-        *bp = JSValIsInterfaceOfType(cx, v, NS_GET_IID(nsIException));
+    if (bp) {
+        nsXPCException* e;
+        *bp = NS_SUCCEEDED(UNWRAP_OBJECT(Exception, cx, v.toObjectOrNull(), e)) ||
+              JSValIsInterfaceOfType(cx, v, NS_GET_IID(nsIException));
+    }
     return NS_OK;
 }
 
 /***************************************************************************/
 // This class is for the thing returned by "new Component.Constructor".
 
 // XXXjband we use this CID for security check, but security system can't see
 // it since it has no registed factory. Security really kicks in when we try
--- a/js/xpconnect/src/XPCConvert.cpp
+++ b/js/xpconnect/src/XPCConvert.cpp
@@ -1075,27 +1075,27 @@ XPCConvert::ConstructException(nsresult 
         }
     }
     if (!msg)
         if (!nsXPCException::NameAndFormatForNSResult(rv, nullptr, &msg) || ! msg)
             msg = "<error>";
     if (ifaceName && methodName)
         msg = sz = JS_smprintf(format, msg, ifaceName, methodName);
 
-    nsresult res = nsXPCException::NewException(msg, rv, nullptr, data, exceptn);
+    nsCOMPtr<nsIException> e = new nsXPCException(msg, rv, nullptr, nullptr, data);
 
-    if (NS_SUCCEEDED(res) && cx && jsExceptionPtr && *exceptn) {
+    if (cx && jsExceptionPtr && *exceptn) {
         nsCOMPtr<nsIXPCException> xpcEx = do_QueryInterface(*exceptn);
         if (xpcEx)
             xpcEx->StowJSVal(cx, *jsExceptionPtr);
     }
 
     if (sz)
         JS_smprintf_free(sz);
-    return res;
+    return NS_OK;
 }
 
 /********************************/
 
 class MOZ_STACK_CLASS AutoExceptionRestorer
 {
 public:
     AutoExceptionRestorer(JSContext *cx, Value v)
--- a/js/xpconnect/src/XPCException.cpp
+++ b/js/xpconnect/src/XPCException.cpp
@@ -4,17 +4,20 @@
  * 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/. */
 
 /* An implementaion of nsIException. */
 
 #include "xpcprivate.h"
 #include "jsprf.h"
 #include "nsError.h"
-#include "nsIUnicodeDecoder.h"
+#include "mozilla/dom/DOMExceptionBinding.h"
+
+namespace ExceptionBinding = mozilla::dom::ExceptionBinding;
+using mozilla::DebugOnly;
 
 /***************************************************************************/
 /* Quick and dirty mapping of well known result codes to strings. We only
 *  call this when building an exception object, so iterating the short array
 *  is not too bad.
 *
 *  It sure would be nice to have exceptions declared in idl and available
 *  in some more global way at runtime.
@@ -80,45 +83,120 @@ nsXPCException::GetNSResultCount()
 {
     return RESULT_COUNT;
 }
 
 /***************************************************************************/
 
 NS_IMPL_CLASSINFO(nsXPCException, NULL, nsIClassInfo::DOM_OBJECT,
                   NS_XPCEXCEPTION_CID)
-NS_INTERFACE_MAP_BEGIN(nsXPCException)
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsXPCException)
   NS_INTERFACE_MAP_ENTRY(nsIException)
   NS_INTERFACE_MAP_ENTRY(nsIXPCException)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIException)
   NS_IMPL_QUERY_CLASSINFO(nsXPCException)
-NS_INTERFACE_MAP_END_THREADSAFE
+NS_INTERFACE_MAP_END
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(nsXPCException)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(nsXPCException)
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(nsXPCException)
 
-NS_IMPL_ADDREF(nsXPCException)
-NS_IMPL_RELEASE(nsXPCException)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsXPCException)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(nsXPCException)
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsXPCException)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CI_INTERFACE_GETTER1(nsXPCException, nsIXPCException)
 
+nsXPCException::nsXPCException(const char *aMessage,
+                               nsresult aResult,
+                               const char *aName,
+                               nsIStackFrame *aLocation,
+                               nsISupports *aData)
+    : mMessage(nullptr),
+      mResult(NS_OK),
+      mName(nullptr),
+      mLocation(nullptr),
+      mData(nullptr),
+      mFilename(nullptr),
+      mLineNumber(0),
+      mInner(nullptr),
+      mInitialized(false)
+{
+    SetIsDOMBinding();
+
+    // A little hack... The nsIGenericModule nsIClassInfo scheme relies on there
+    // having been at least one instance made via the factory. Otherwise, the
+    // shared factory/classinsance object never gets created and our QI getter
+    // for our instance's pointer to our nsIClassInfo will always return null.
+    // This is bad because it means that wrapped exceptions will never have a
+    // shared prototype. So... We force one to be created via the factory
+    // *once* and then go about our business.
+    if (!sEverMadeOneFromFactory) {
+        nsCOMPtr<nsIXPCException> e =
+            do_CreateInstance(XPC_EXCEPTION_CONTRACTID);
+        sEverMadeOneFromFactory = true;
+    }
+
+    nsIStackFrame* location;
+    if (aLocation) {
+        location = aLocation;
+        NS_ADDREF(location);
+    } else {
+        nsXPConnect* xpc = nsXPConnect::XPConnect();
+        xpc->GetCurrentJSStack(&location);
+        // it is legal for there to be no active JS stack, if C++ code
+        // is operating on a JS-implemented interface pointer without
+        // having been called in turn by JS.  This happens in the JS
+        // component loader, and will become more common as additional
+        // components are implemented in JS.
+    }
+    // We want to trim off any leading native 'dataless' frames
+    if (location) {
+        while (1) {
+            uint32_t language;
+            int32_t lineNumber;
+            if (NS_FAILED(location->GetLanguage(&language)) ||
+                language == nsIProgrammingLanguage::JAVASCRIPT ||
+                NS_FAILED(location->GetLineNumber(&lineNumber)) ||
+                lineNumber) {
+                break;
+            }
+            nsCOMPtr<nsIStackFrame> caller;
+            if (NS_FAILED(location->GetCaller(getter_AddRefs(caller))) || !caller)
+                break;
+            NS_RELEASE(location);
+            caller->QueryInterface(NS_GET_IID(nsIStackFrame), (void **)&location);
+        }
+    }
+
+    Initialize(aMessage, aResult, aName, location, aData, nullptr);
+    NS_IF_RELEASE(location);
+}
+
 nsXPCException::nsXPCException()
     : mMessage(nullptr),
       mResult(NS_OK),
       mName(nullptr),
       mLocation(nullptr),
       mData(nullptr),
       mFilename(nullptr),
       mLineNumber(0),
       mInner(nullptr),
       mInitialized(false)
-{
-    MOZ_COUNT_CTOR(nsXPCException);
-}
+{ }
 
 nsXPCException::~nsXPCException()
 {
-    MOZ_COUNT_DTOR(nsXPCException);
     Reset();
 }
 
 /* [noscript] xpcexJSVal stealJSVal (); */
 NS_IMETHODIMP
 nsXPCException::StealJSVal(jsval *vp)
 {
     if (mThrownJSVal.IsHeld()) {
@@ -361,84 +439,106 @@ nsXPCException::ToString(char **_retval)
         final = (char*) nsMemory::Clone(temp, sizeof(char)*(strlen(temp)+1));
         JS_smprintf_free(temp);
     }
 
     *_retval = final;
     return final ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
 }
 
-bool nsXPCException::sEverMadeOneFromFactory = false;
+JSObject*
+nsXPCException::WrapObject(JSContext* cx, JS::Handle<JSObject*> scope)
+{
+    return ExceptionBinding::Wrap(cx, scope, this);
+}
 
-// static
-nsresult
-nsXPCException::NewException(const char *aMessage,
-                             nsresult aResult,
-                             nsIStackFrame *aLocation,
-                             nsISupports *aData,
-                             nsIException** exceptn)
+void
+nsXPCException::GetMessageMoz(nsString& retval)
 {
-    // A little hack... The nsIGenericModule nsIClassInfo scheme relies on there
-    // having been at least one instance made via the factory. Otherwise, the
-    // shared factory/classinsance object never gets created and our QI getter
-    // for our instance's pointer to our nsIClassInfo will always return null.
-    // This is bad because it means that wrapped exceptions will never have a
-    // shared prototype. So... We force one to be created via the factory
-    // *once* and then go about our business.
-    if (!sEverMadeOneFromFactory) {
-        nsCOMPtr<nsIXPCException> e =
-            do_CreateInstance(XPC_EXCEPTION_CONTRACTID);
-        sEverMadeOneFromFactory = true;
-    }
+    char* str = nullptr;
+#ifdef DEBUG
+    DebugOnly<nsresult> rv = 
+#endif
+    GetMessageMoz(&str);
+    MOZ_ASSERT(NS_SUCCEEDED(rv));
+    CopyUTF8toUTF16(str, retval);
+    nsMemory::Free(str);
+}
 
-    nsresult rv;
-    nsXPCException* e = new nsXPCException();
-    if (e) {
-        NS_ADDREF(e);
+uint32_t
+nsXPCException::Result() const
+{
+    return (uint32_t)mResult;
+}
+
+void
+nsXPCException::GetName(nsString& retval)
+{
+    char* str = nullptr;
+#ifdef DEBUG
+    DebugOnly<nsresult> rv =
+#endif
+    GetName(&str);
+    MOZ_ASSERT(NS_SUCCEEDED(rv));
+    CopyUTF8toUTF16(str, retval);
+    nsMemory::Free(str);
+}
 
-        nsIStackFrame* location;
-        if (aLocation) {
-            location = aLocation;
-            NS_ADDREF(location);
-        } else {
-            nsXPConnect* xpc = nsXPConnect::XPConnect();
-            rv = xpc->GetCurrentJSStack(&location);
-            if (NS_FAILED(rv)) {
-                NS_RELEASE(e);
-                return NS_ERROR_FAILURE;
-            }
-            // it is legal for there to be no active JS stack, if C++ code
-            // is operating on a JS-implemented interface pointer without
-            // having been called in turn by JS.  This happens in the JS
-            // component loader, and will become more common as additional
-            // components are implemented in JS.
-        }
-        // We want to trim off any leading native 'dataless' frames
-        if (location)
-            while (1) {
-                uint32_t language;
-                int32_t lineNumber;
-                if (NS_FAILED(location->GetLanguage(&language)) ||
-                    language == nsIProgrammingLanguage::JAVASCRIPT ||
-                    NS_FAILED(location->GetLineNumber(&lineNumber)) ||
-                    lineNumber) {
-                    break;
-                }
-                nsCOMPtr<nsIStackFrame> caller;
-                if (NS_FAILED(location->GetCaller(getter_AddRefs(caller))) || !caller)
-                    break;
-                NS_RELEASE(location);
-                caller->QueryInterface(NS_GET_IID(nsIStackFrame), (void **)&location);
-            }
-        // at this point we have non-null location with one extra addref,
-        // or no location at all
-        rv = e->Initialize(aMessage, aResult, nullptr, location, aData, nullptr);
-        NS_IF_RELEASE(location);
-        if (NS_FAILED(rv))
-            NS_RELEASE(e);
-    }
+void
+nsXPCException::GetFilename(nsString& retval)
+{
+    char* str = nullptr;
+#ifdef DEBUG
+    DebugOnly<nsresult> rv =
+#endif
+    GetFilename(&str);
+    MOZ_ASSERT(NS_SUCCEEDED(rv));
+    CopyUTF8toUTF16(str, retval);
+    nsMemory::Free(str);
+}
+
+uint32_t
+nsXPCException::LineNumber() const
+{
+    return mLineNumber;
+}
+
+uint32_t
+nsXPCException::ColumnNumber() const
+{
+    return 0;
+}
 
-    if (!e)
-        return NS_ERROR_FAILURE;
+already_AddRefed<nsIStackFrame>
+nsXPCException::GetLocation() const
+{
+    nsCOMPtr<nsIStackFrame> location = mLocation;
+    return location.forget();
+}
+
+already_AddRefed<nsISupports>
+nsXPCException::GetInner() const
+{
+    nsCOMPtr<nsISupports> inner = mInner;
+    return inner.forget();
+}
 
-    *exceptn = static_cast<nsIXPCException*>(e);
-    return NS_OK;
+already_AddRefed<nsISupports>
+nsXPCException::GetData() const
+{
+    nsCOMPtr<nsISupports> data = mData;
+    return data.forget();
 }
+
+void
+nsXPCException::Stringify(nsString& retval)
+{
+    char* str = nullptr;
+#ifdef DEBUG
+    DebugOnly<nsresult> rv =
+#endif
+    ToString(&str);
+    MOZ_ASSERT(NS_SUCCEEDED(rv));
+    CopyUTF8toUTF16(str, retval);
+    nsMemory::Free(str);
+}
+
+bool nsXPCException::sEverMadeOneFromFactory = false;
--- a/js/xpconnect/src/XPCModule.cpp
+++ b/js/xpconnect/src/XPCModule.cpp
@@ -6,17 +6,16 @@
 
 #define XPCONNECT_MODULE
 #include "xpcprivate.h"
 
 nsresult
 xpcModuleCtor()
 {
     nsXPConnect::InitStatics();
-    nsXPCException::InitStatics();
     XPCWrappedNativeScope::InitStatics();
 
     return NS_OK;
 }
 
 void
 xpcModuleDtor()
 {
--- a/js/xpconnect/src/XPCThrower.cpp
+++ b/js/xpconnect/src/XPCThrower.cpp
@@ -6,16 +6,17 @@
 
 /* Code for throwing errors into JavaScript. */
 
 #include "xpcprivate.h"
 #include "xpcpublic.h"
 #include "XPCWrapper.h"
 #include "jsprf.h"
 #include "nsDOMException.h"
+#include "mozilla/dom/BindingUtils.h"
 
 bool XPCThrower::sVerbose = true;
 
 // static
 void
 XPCThrower::Throw(nsresult rv, JSContext* cx)
 {
     const char* format;
@@ -50,17 +51,17 @@ XPCThrower::CheckForPendingException(nsr
     if (!e)
         return false;
     XPCJSRuntime::Get()->SetPendingException(nullptr);
 
     nsresult e_result;
     if (NS_FAILED(e->GetResult(&e_result)) || e_result != result)
         return false;
 
-    if (!ThrowExceptionObject(cx, e))
+    if (!ThrowExceptionObject(cx, static_cast<nsXPCException*>(e.get())))
         JS_ReportOutOfMemory(cx);
     return true;
 }
 
 // static
 void
 XPCThrower::Throw(nsresult rv, XPCCallContext& ccx)
 {
@@ -185,41 +186,37 @@ XPCThrower::BuildAndThrowException(JSCon
         nsresult nr;
         if (NS_SUCCEEDED(existingException->GetResult(&nr)) && 
             rv == nr) {
             // Just reuse the existing exception.
             return;
         }
     }
 
-    nsCOMPtr<nsIException> finalException;
-    nsCOMPtr<nsIException> defaultException;
-    nsXPCException::NewException(sz, rv, nullptr, nullptr,
-                                 getter_AddRefs(defaultException));
+    nsRefPtr<nsXPCException> finalException;
 
     // Do we use DOM exceptions for this error code?
     switch (NS_ERROR_GET_MODULE(rv)) {
     case NS_ERROR_MODULE_DOM:
     case NS_ERROR_MODULE_SVG:
     case NS_ERROR_MODULE_DOM_XPATH:
     case NS_ERROR_MODULE_DOM_INDEXEDDB:
     case NS_ERROR_MODULE_DOM_FILEHANDLE:
         if (NS_IsMainThread()) {
-            NS_NewDOMException(rv, defaultException,
-                               getter_AddRefs(finalException));
+            finalException = NS_NewDOMException(rv);
         }
         break;
 
     default:
         break;
     }
 
     // If not, use the default.
     if (finalException == nullptr) {
-        finalException = defaultException;
+        finalException = new nsXPCException(sz, rv, nullptr, nullptr, nullptr);
     }
 
     MOZ_ASSERT(finalException);
     success = ThrowExceptionObject(cx, finalException);
     // If we weren't able to throw an exception we're
     // most likely out of memory
     if (!success) {
         JS_ReportOutOfMemory(cx);
@@ -239,46 +236,37 @@ IsCallerChrome(JSContext* cx)
 
     bool isChrome;
     rv = secMan->SubjectPrincipalIsSystem(&isChrome);
     return NS_SUCCEEDED(rv) && isChrome;
 }
 
 // static
 bool
-XPCThrower::ThrowExceptionObject(JSContext* cx, nsIException* e)
+XPCThrower::ThrowExceptionObject(JSContext* cx, nsXPCException* e)
 {
     bool success = false;
     if (e) {
-        nsCOMPtr<nsIXPCException> xpcEx;
         JS::RootedValue thrown(cx);
-        nsXPConnect* xpc;
 
         // If we stored the original thrown JS value in the exception
         // (see XPCConvert::ConstructException) and we are in a web
         // context (i.e., not chrome), rethrow the original value.
         if (!IsCallerChrome(cx) &&
-            (xpcEx = do_QueryInterface(e)) &&
-            NS_SUCCEEDED(xpcEx->StealJSVal(thrown.address()))) {
+            NS_SUCCEEDED(e->StealJSVal(thrown.address()))) {
             if (!JS_WrapValue(cx, thrown.address()))
                 return false;
             JS_SetPendingException(cx, thrown);
             success = true;
-        } else if ((xpc = nsXPConnect::XPConnect())) {
+        } else {
             JS::RootedObject glob(cx, JS::CurrentGlobalOrNull(cx));
             if (!glob)
                 return false;
 
-            nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
-            nsresult rv = xpc->WrapNative(cx, glob, e,
-                                          NS_GET_IID(nsIException),
-                                          getter_AddRefs(holder));
-            if (NS_SUCCEEDED(rv) && holder) {
-                JS::RootedObject obj(cx, holder->GetJSObject());
-                if (obj) {
-                    JS_SetPendingException(cx, OBJECT_TO_JSVAL(obj));
-                    success = true;
-                }
+            JS::RootedValue val(cx);
+            if (mozilla::dom::WrapNewBindingObject(cx, glob, e, &val)) {
+                JS_SetPendingException(cx, val);
+                success = true;
             }
         }
     }
     return success;
 }
--- a/js/xpconnect/src/XPCWrappedJSClass.cpp
+++ b/js/xpconnect/src/XPCWrappedJSClass.cpp
@@ -11,16 +11,18 @@
 #include "jsprf.h"
 #include "nsArrayEnumerator.h"
 #include "nsContentUtils.h"
 #include "nsWrapperCache.h"
 #include "XPCWrapper.h"
 #include "AccessCheck.h"
 #include "nsJSUtils.h"
 #include "mozilla/Attributes.h"
+#include "mozilla/dom/BindingUtils.h"
+#include "mozilla/dom/DOMExceptionBinding.h"
 
 #include "jsapi.h"
 #include "jsfriendapi.h"
 
 using namespace xpc;
 using namespace JS;
 
 NS_IMPL_ISUPPORTS1(nsXPCWrappedJSClass, nsIXPCWrappedJSClass)
@@ -256,31 +258,24 @@ nsXPCWrappedJSClass::CallQueryInterfaceO
 
             RootedValue jsexception(cx, NullValue());
 
             if (JS_GetPendingException(cx, jsexception.address())) {
                 nsresult rv;
                 if (jsexception.isObject()) {
                     // XPConnect may have constructed an object to represent a
                     // C++ QI failure. See if that is the case.
-                    nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
-
-                    nsXPConnect::XPConnect()->
-                        GetWrappedNativeOfJSObject(cx,
-                                                   &jsexception.toObject(),
-                                                   getter_AddRefs(wrapper));
+                    using namespace mozilla::dom;
+                    nsXPCException *e = nullptr;
+                    UNWRAP_OBJECT(Exception, cx, &jsexception.toObject(), e);
 
-                    if (wrapper) {
-                        nsCOMPtr<nsIException> exception =
-                            do_QueryWrappedNative(wrapper);
-                        if (exception &&
-                            NS_SUCCEEDED(exception->GetResult(&rv)) &&
-                            rv == NS_NOINTERFACE) {
-                            JS_ClearPendingException(cx);
-                        }
+                    if (e &&
+                        NS_SUCCEEDED(e->GetResult(&rv)) &&
+                        rv == NS_NOINTERFACE) {
+                        JS_ClearPendingException(cx);
                     }
                 } else if (JSVAL_IS_NUMBER(jsexception)) {
                     // JS often throws an nsresult.
                     if (JSVAL_IS_DOUBLE(jsexception))
                         // Visual Studio 9 doesn't allow casting directly from
                         // a double to an enumeration type, contrary to
                         // 5.2.9(10) of C++11, so add an intermediate cast.
                         rv = (nsresult)(uint32_t)(JSVAL_TO_DOUBLE(jsexception));
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -2926,16 +2926,18 @@ public:
 private:
     XPCConvert(); // not implemented
 
 };
 
 /***************************************************************************/
 // code for throwing exceptions into JS
 
+class nsXPCException;
+
 class XPCThrower
 {
 public:
     static void Throw(nsresult rv, JSContext* cx);
     static void Throw(nsresult rv, XPCCallContext& ccx);
     static void ThrowBadResult(nsresult rv, nsresult result, XPCCallContext& ccx);
     static void ThrowBadParam(nsresult rv, unsigned paramNum, XPCCallContext& ccx);
     static bool SetVerbosity(bool state)
@@ -2943,17 +2945,17 @@ public:
 
     static void BuildAndThrowException(JSContext* cx, nsresult rv, const char* sz);
     static bool CheckForPendingException(nsresult result, JSContext *cx);
 
 private:
     static void Verbosify(XPCCallContext& ccx,
                           char** psz, bool own);
 
-    static bool ThrowExceptionObject(JSContext* cx, nsIException* e);
+    static bool ThrowExceptionObject(JSContext* cx, nsXPCException* e);
 
 private:
     static bool sVerbose;
 };
 
 
 /***************************************************************************/
 
@@ -2972,62 +2974,89 @@ public:
                              nsIStackFrame** stack);
 private:
     XPCJSStack();   // not implemented
 };
 
 /***************************************************************************/
 
 class nsXPCException :
-            public nsIXPCException
+            public nsIXPCException,
+            public nsWrapperCache
 {
 public:
     NS_DEFINE_STATIC_CID_ACCESSOR(NS_XPCEXCEPTION_CID)
 
-    NS_DECL_THREADSAFE_ISUPPORTS
+    NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsXPCException)
+
+    NS_DECL_CYCLE_COLLECTING_ISUPPORTS
     NS_DECL_NSIEXCEPTION
     NS_DECL_NSIXPCEXCEPTION
 
-    static nsresult NewException(const char *aMessage,
-                                 nsresult aResult,
-                                 nsIStackFrame *aLocation,
-                                 nsISupports *aData,
-                                 nsIException** exception);
-
     static bool NameAndFormatForNSResult(nsresult rv,
                                          const char** name,
                                          const char** format);
 
     static const void* IterateNSResults(nsresult* rv,
                                         const char** name,
                                         const char** format,
                                         const void** iterp);
 
     static uint32_t GetNSResultCount();
 
+    nsXPCException(const char *aMessage,
+                   nsresult aResult,
+                   const char *aName,
+                   nsIStackFrame *aLocation,
+                   nsISupports *aData);
+    // XPCOM factory ctor.
     nsXPCException();
     virtual ~nsXPCException();
 
-    static void InitStatics() { sEverMadeOneFromFactory = false; }
+    virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> scope)
+      MOZ_OVERRIDE;
+
+    nsISupports* GetParentObject() const { return nullptr; }
+
+    void GetMessageMoz(nsString& retval);
+
+    uint32_t Result() const;
+
+    void GetName(nsString& retval);
+
+    void GetFilename(nsString& retval);
+
+    uint32_t LineNumber() const;
+
+    uint32_t ColumnNumber() const;
+
+    already_AddRefed<nsIStackFrame> GetLocation() const;
+
+    already_AddRefed<nsISupports> GetInner() const;
+
+    already_AddRefed<nsISupports> GetData() const;
+
+    void Stringify(nsString& retval);
 
 protected:
     void Reset();
-private:
+
     char*           mMessage;
     nsresult        mResult;
     char*           mName;
     nsIStackFrame*  mLocation;
     nsISupports*    mData;
     char*           mFilename;
     int             mLineNumber;
     nsIException*   mInner;
     bool            mInitialized;
 
     nsAutoJSValHolder mThrownJSVal;
 
+private:
     static bool sEverMadeOneFromFactory;
 };
 
 /***************************************************************************/
 /*
 * nsJSID implements nsIJSID. It is also used by nsJSIID and nsJSCID as a
 * member (as a hidden implementaion detail) to which they delegate many calls.
 */