--- 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.
*/