From 6a6c67829fde41d218bda72d8fa36643e3185143 Mon Sep 17 00:00:00 2001 From: Kyle Huey Date: Sun, 8 Sep 2013 20:28:50 -0700 Subject: [PATCH] Bug 911258: Part 4 - Refactor exception implementations. r=bz --- dom/base/DOMError.cpp | 7 +- dom/base/DOMException.cpp | 708 +++++++++++++++++++++++++ dom/base/DOMException.h | 161 ++++++ dom/base/moz.build | 4 +- dom/base/nsDOMClassInfo.cpp | 10 - dom/base/nsDOMClassInfoClasses.h | 3 - dom/base/nsDOMException.cpp | 238 --------- dom/base/nsDOMException.h | 67 --- dom/base/nsDOMScriptObjectFactory.cpp | 1 - dom/bindings/Bindings.conf | 4 +- dom/bindings/Exceptions.cpp | 410 ++++++++++++++ dom/bindings/Exceptions.h | 50 ++ dom/bindings/Makefile.in | 1 + dom/bindings/moz.build | 1 + dom/workers/RuntimeService.cpp | 2 +- js/xpconnect/idl/xpcexception.idl | 13 +- js/xpconnect/src/XPCComponents.cpp | 14 +- js/xpconnect/src/XPCConvert.cpp | 11 +- js/xpconnect/src/XPCException.cpp | 464 ---------------- js/xpconnect/src/XPCForwards.h | 1 - js/xpconnect/src/XPCJSRuntime.cpp | 4 + js/xpconnect/src/XPCModule.h | 3 - js/xpconnect/src/XPCQuickStubs.cpp | 5 +- js/xpconnect/src/XPCStack.cpp | 268 ---------- js/xpconnect/src/XPCThrower.cpp | 116 +--- js/xpconnect/src/XPCWrappedJSClass.cpp | 3 +- js/xpconnect/src/moz.build | 1 - js/xpconnect/src/nsXPConnect.cpp | 18 +- js/xpconnect/src/xpcprivate.h | 100 +--- layout/build/nsLayoutModule.cpp | 5 +- xpcom/base/CycleCollectedJSRuntime.cpp | 17 + xpcom/base/CycleCollectedJSRuntime.h | 12 + xpcom/base/nsCycleCollector.cpp | 4 +- xpcom/base/nsCycleCollector.h | 1 - 34 files changed, 1419 insertions(+), 1308 deletions(-) create mode 100644 dom/base/DOMException.cpp create mode 100644 dom/base/DOMException.h delete mode 100644 dom/base/nsDOMException.cpp delete mode 100644 dom/base/nsDOMException.h create mode 100644 dom/bindings/Exceptions.cpp create mode 100644 dom/bindings/Exceptions.h delete mode 100644 js/xpconnect/src/XPCStack.cpp diff --git a/dom/base/DOMError.cpp b/dom/base/DOMError.cpp index ff295330e51..e1b101d3946 100644 --- a/dom/base/DOMError.cpp +++ b/dom/base/DOMError.cpp @@ -6,9 +6,14 @@ #include "mozilla/dom/DOMError.h" #include "mozilla/dom/DOMErrorBinding.h" -#include "nsDOMException.h" #include "nsPIDOMWindow.h" +// Implemented in DOMException.cpp +nsresult +NS_GetNameAndMessageForDOMNSResult(nsresult aNSResult, const char** aName, + const char** aMessage, + uint16_t* aCode = nullptr); + namespace mozilla { namespace dom { diff --git a/dom/base/DOMException.cpp b/dom/base/DOMException.cpp new file mode 100644 index 00000000000..51c63788139 --- /dev/null +++ b/dom/base/DOMException.cpp @@ -0,0 +1,708 @@ +/* -*- Mode: C++; 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/. */ + +#include "mozilla/dom/DOMException.h" + +#include "jsapi.h" +#include "jsprf.h" +#include "js/OldDebugAPI.h" +#include "mozilla/Util.h" +#include "nsContentUtils.h" +#include "nsCOMPtr.h" +#include "nsCycleCollectionHoldDrop.h" +#include "nsIClassInfoImpl.h" +#include "nsIDocument.h" +#include "nsIDOMDOMException.h" +#include "nsIException.h" +#include "nsMemory.h" +#include "prprf.h" +#include "xpcprivate.h" + +#include "mozilla/dom/DOMExceptionBinding.h" + +using namespace mozilla; + +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, + NotFoundError = nsIDOMDOMException::NOT_FOUND_ERR, + NotSupportedError = nsIDOMDOMException::NOT_SUPPORTED_ERR, + // Can't remove until setNamedItem is removed + InUseAttributeError = nsIDOMDOMException::INUSE_ATTRIBUTE_ERR, + InvalidStateError = nsIDOMDOMException::INVALID_STATE_ERR, + SyntaxError = nsIDOMDOMException::SYNTAX_ERR, + InvalidModificationError = nsIDOMDOMException::INVALID_MODIFICATION_ERR, + NamespaceError = nsIDOMDOMException::NAMESPACE_ERR, + InvalidAccessError = nsIDOMDOMException::INVALID_ACCESS_ERR, + TypeMismatchError = nsIDOMDOMException::TYPE_MISMATCH_ERR, + SecurityError = nsIDOMDOMException::SECURITY_ERR, + NetworkError = nsIDOMDOMException::NETWORK_ERR, + AbortError = nsIDOMDOMException::ABORT_ERR, + URLMismatchError = nsIDOMDOMException::URL_MISMATCH_ERR, + QuotaExceededError = nsIDOMDOMException::QUOTA_EXCEEDED_ERR, + TimeoutError = nsIDOMDOMException::TIMEOUT_ERR, + InvalidNodeTypeError = nsIDOMDOMException::INVALID_NODE_TYPE_ERR, + DataCloneError = nsIDOMDOMException::DATA_CLONE_ERR, + EncodingError = 0, + + /* XXX Should be JavaScript native errors */ + TypeError = 0, + RangeError = 0, + + /* IndexedDB errors http://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html#exceptions */ + UnknownError = 0, + ConstraintError = 0, + DataError = 0, + TransactionInactiveError = 0, + ReadOnlyError = 0, + VersionError = 0, + + /* File API errors http://dev.w3.org/2006/webapi/FileAPI/#ErrorAndException */ + NotReadableError = 0, + + /* FileHandle API errors */ + LockedFileInactiveError = 0, +}; + +#define DOM4_MSG_DEF(name, message, nsresult) {(nsresult), name, #name, message}, +#define DOM_MSG_DEF(val, message) {(val), NS_ERROR_GET_CODE(val), #val, message}, + +static const struct ResultStruct +{ + nsresult mNSResult; + uint16_t mCode; + const char* mName; + const char* mMessage; +} sDOMErrorMsgMap[] = { +#include "domerr.msg" +}; + +#undef DOM4_MSG_DEF +#undef DOM_MSG_DEF + +static void +NSResultToNameAndMessage(nsresult aNSResult, + const char** aName, + const char** aMessage, + uint16_t* aCode) +{ + *aName = nullptr; + *aMessage = nullptr; + *aCode = 0; + for (uint32_t idx = 0; idx < ArrayLength(sDOMErrorMsgMap); idx++) { + if (aNSResult == sDOMErrorMsgMap[idx].mNSResult) { + *aName = sDOMErrorMsgMap[idx].mName; + *aMessage = sDOMErrorMsgMap[idx].mMessage; + *aCode = sDOMErrorMsgMap[idx].mCode; + return; + } + } + + NS_WARNING("Huh, someone is throwing non-DOM errors using the DOM module!"); + + return; +} + +nsresult +NS_GetNameAndMessageForDOMNSResult(nsresult aNSResult, const char** aName, + const char** aMessage, uint16_t* aCode) +{ + const char* name = nullptr; + const char* message = nullptr; + uint16_t code = 0; + NSResultToNameAndMessage(aNSResult, &name, &message, &code); + + if (name && message) { + *aName = name; + *aMessage = message; + if (aCode) { + *aCode = code; + } + return NS_OK; + } + + return NS_ERROR_NOT_AVAILABLE; +} + +namespace mozilla { +namespace dom { + +bool Exception::sEverMadeOneFromFactory = false; + +NS_IMPL_CLASSINFO(Exception, nullptr, nsIClassInfo::DOM_OBJECT, + NS_XPCEXCEPTION_CID) +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Exception) + NS_INTERFACE_MAP_ENTRY(nsIException) + NS_INTERFACE_MAP_ENTRY(nsIXPCException) + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIException) + NS_IMPL_QUERY_CLASSINFO(Exception) +NS_INTERFACE_MAP_END + +NS_IMPL_CYCLE_COLLECTING_ADDREF(Exception) +NS_IMPL_CYCLE_COLLECTING_RELEASE(Exception) + +NS_IMPL_CYCLE_COLLECTION_CLASS(Exception) + +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Exception) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END + +NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(Exception) + NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER + NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mThrownJSVal); +NS_IMPL_CYCLE_COLLECTION_TRACE_END + +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Exception) + NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER +NS_IMPL_CYCLE_COLLECTION_UNLINK_END + +NS_IMPL_CI_INTERFACE_GETTER1(Exception, nsIXPCException) + +Exception::Exception(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), + mHoldingJSVal(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 e = + do_CreateInstance(XPC_EXCEPTION_CONTRACTID); + sEverMadeOneFromFactory = true; + } + + nsCOMPtr location; + if (aLocation) { + location = aLocation; + } else { + nsXPConnect* xpc = nsXPConnect::XPConnect(); + xpc->GetCurrentJSStack(getter_AddRefs(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 caller; + if (NS_FAILED(location->GetCaller(getter_AddRefs(caller))) || !caller) { + break; + } + location = caller; + } + } + + Initialize(aMessage, aResult, aName, location, aData, nullptr); +} + +Exception::Exception() + : mMessage(nullptr), + mResult(NS_OK), + mName(nullptr), + mFilename(nullptr), + mLineNumber(-1), + mInitialized(false), + mHoldingJSVal(false) +{ +} + +Exception::~Exception() +{ + if (mMessage) { + nsMemory::Free(mMessage); + mMessage = nullptr; + } + if (mName) { + nsMemory::Free(mName); + mName = nullptr; + } + if (mFilename) { + nsMemory::Free(mFilename); + mFilename = nullptr; + } + + if (mHoldingJSVal) { + MOZ_ASSERT(NS_IsMainThread()); + + mozilla::DropJSObjects(this); + } +} + +bool +Exception::StealJSVal(JS::Value* aVp) +{ + MOZ_ASSERT(NS_IsMainThread()); + + if (mHoldingJSVal) { + *aVp = mThrownJSVal; + mThrownJSVal = JSVAL_NULL; + + mozilla::DropJSObjects(this); + mHoldingJSVal = false; + return true; + } + + return false; +} + +void +Exception::StowJSVal(JS::Value& aVp) +{ + MOZ_ASSERT(NS_IsMainThread()); + + mThrownJSVal = aVp; + if (!mHoldingJSVal) { + mozilla::HoldJSObjects(this); + mHoldingJSVal = true; + } +} + +/* readonly attribute string message; */ +NS_IMETHODIMP +Exception::GetMessageMoz(char** aMessage) +{ + NS_ENSURE_ARG_POINTER(aMessage); + NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED); + + if (mMessage) { + *aMessage = + (char*) nsMemory::Clone(mMessage, sizeof(char)*(strlen(mMessage)+1)); + } else { + *aMessage = nullptr; + } + + return NS_OK; +} + +/* readonly attribute nsresult result; */ +NS_IMETHODIMP +Exception::GetResult(nsresult* aResult) +{ + NS_ENSURE_ARG_POINTER(aResult); + NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED); + + *aResult = mResult; + return NS_OK; +} + +/* readonly attribute string name; */ +NS_IMETHODIMP +Exception::GetName(char** aName) +{ + NS_ENSURE_ARG_POINTER(aName); + NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED); + + const char* name = mName; + if (!name) { + nsXPCException::NameAndFormatForNSResult(mResult, &name, nullptr); + } + + if (name) { + *aName = (char*) nsMemory::Clone(name, sizeof(char)*(strlen(name)+1)); + } else { + *aName = nullptr; + } + + return NS_OK; +} + +/* readonly attribute string filename; */ +NS_IMETHODIMP +Exception::GetFilename(char** aFilename) +{ + NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED); + XPC_STRING_GETTER_BODY(aFilename, mFilename); +} + +/* readonly attribute uint32_t lineNumber; */ +NS_IMETHODIMP +Exception::GetLineNumber(uint32_t *aLineNumber) +{ + NS_ENSURE_ARG_POINTER(aLineNumber); + NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED); + + *aLineNumber = mLineNumber; + return NS_OK; +} + +/* readonly attribute uint32_t columnNumber; */ +NS_IMETHODIMP +Exception::GetColumnNumber(uint32_t* aColumnNumber) +{ + NS_ENSURE_ARG_POINTER(aColumnNumber); + NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED); + + *aColumnNumber = 0; + return NS_OK; +} + +/* readonly attribute nsIStackFrame location; */ +NS_IMETHODIMP +Exception::GetLocation(nsIStackFrame** aLocation) +{ + NS_ENSURE_ARG_POINTER(aLocation); + NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED); + + nsCOMPtr location = mLocation; + location.forget(aLocation); + return NS_OK; +} + +/* readonly attribute nsISupports data; */ +NS_IMETHODIMP +Exception::GetData(nsISupports** aData) +{ + NS_ENSURE_ARG_POINTER(aData); + NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED); + + nsCOMPtr data = mData; + data.forget(aData); + return NS_OK; +} + +/* readonly attribute nsIException inner; */ +NS_IMETHODIMP +Exception::GetInner(nsIException** aException) +{ + NS_ENSURE_ARG_POINTER(aException); + NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED); + + nsCOMPtr inner = mInner; + inner.forget(aException); + return NS_OK; +} + +/* string toString (); */ +NS_IMETHODIMP +Exception::ToString(char **_retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED); + + static const char defaultMsg[] = ""; + static const char defaultLocation[] = ""; + static const char format[] = +"[Exception... \"%s\" nsresult: \"0x%x (%s)\" location: \"%s\" data: %s]"; + + char* indicatedLocation = nullptr; + + if (mLocation) { + // we need to free this if it does not fail + nsresult rv = mLocation->ToString(&indicatedLocation); + NS_ENSURE_SUCCESS(rv, rv); + } + + const char* msg = mMessage ? mMessage : nullptr; + const char* location = indicatedLocation ? + indicatedLocation : defaultLocation; + const char* resultName = mName; + if (!resultName && + !nsXPCException::NameAndFormatForNSResult(mResult, &resultName, + (!msg) ? &msg : nullptr)) { + if (!msg) { + msg = defaultMsg; + } + resultName = ""; + } + const char* data = mData ? "yes" : "no"; + + char* temp = JS_smprintf(format, msg, mResult, resultName, location, data); + if (indicatedLocation) { + nsMemory::Free(indicatedLocation); + } + + char* final = nullptr; + if (temp) { + 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; +} + +/* void initialize (in string aMessage, in nsresult aResult, in string aName, in nsIStackFrame aLocation, in nsISupports aData, in nsIException aInner); */ +NS_IMETHODIMP +Exception::Initialize(const char *aMessage, nsresult aResult, const char *aName, nsIStackFrame *aLocation, nsISupports *aData, nsIException *aInner) +{ + NS_ENSURE_FALSE(mInitialized, NS_ERROR_ALREADY_INITIALIZED); + + if (aMessage) { + mMessage = + (char*) nsMemory::Clone(aMessage, sizeof(char)*(strlen(aMessage)+1)); + } + + if (aName) { + mName = (char*) nsMemory::Clone(aName, sizeof(char)*(strlen(aName)+1)); + } + + mResult = aResult; + + if (aLocation) { + mLocation = aLocation; + // For now, fill in our location details from our stack frame. + // Later we may allow other locations? + nsresult rc; + if (NS_FAILED(rc = aLocation->GetFilename(&mFilename))) { + return rc; + } + if (NS_FAILED(rc = aLocation->GetLineNumber(&mLineNumber))) { + return rc; + } + } else { + nsresult rv; + nsXPConnect* xpc = nsXPConnect::XPConnect(); + rv = xpc->GetCurrentJSStack(getter_AddRefs(mLocation)); + if (NS_FAILED(rv)) { + return rv; + } + } + + mData = aData; + mInner = aInner; + + mInitialized = true; + return NS_OK; +} + +JSObject* +Exception::WrapObject(JSContext* cx, JS::Handle scope) +{ + return ExceptionBinding::Wrap(cx, scope, this); +} + +void +Exception::GetMessageMoz(nsString& retval) +{ + char* str = nullptr; +#ifdef DEBUG + DebugOnly rv = +#endif + GetMessageMoz(&str); + MOZ_ASSERT(NS_SUCCEEDED(rv)); + CopyUTF8toUTF16(str, retval); + nsMemory::Free(str); +} + +uint32_t +Exception::Result() const +{ + return (uint32_t)mResult; +} + +void +Exception::GetName(nsString& retval) +{ + char* str = nullptr; +#ifdef DEBUG + DebugOnly rv = +#endif + GetName(&str); + MOZ_ASSERT(NS_SUCCEEDED(rv)); + CopyUTF8toUTF16(str, retval); + nsMemory::Free(str); +} + +void +Exception::GetFilename(nsString& retval) +{ + char* str = nullptr; +#ifdef DEBUG + DebugOnly rv = +#endif + GetFilename(&str); + MOZ_ASSERT(NS_SUCCEEDED(rv)); + CopyUTF8toUTF16(str, retval); + nsMemory::Free(str); +} + +uint32_t +Exception::LineNumber() const +{ + return mLineNumber; +} + +uint32_t +Exception::ColumnNumber() const +{ + return 0; +} + +already_AddRefed +Exception::GetLocation() const +{ + nsCOMPtr location = mLocation; + return location.forget(); +} + +already_AddRefed +Exception::GetInner() const +{ + nsCOMPtr inner = mInner; + return inner.forget(); +} + +already_AddRefed +Exception::GetData() const +{ + nsCOMPtr data = mData; + return data.forget(); +} + +void +Exception::Stringify(nsString& retval) +{ + char* str = nullptr; +#ifdef DEBUG + DebugOnly rv = +#endif + ToString(&str); + MOZ_ASSERT(NS_SUCCEEDED(rv)); + CopyUTF8toUTF16(str, retval); + nsMemory::Free(str); +} + +NS_IMPL_ADDREF_INHERITED(DOMException, Exception) +NS_IMPL_RELEASE_INHERITED(DOMException, Exception) +NS_INTERFACE_MAP_BEGIN(DOMException) + NS_INTERFACE_MAP_ENTRY(nsIDOMDOMException) +NS_INTERFACE_MAP_END_INHERITING(Exception) + +DOMException::DOMException(nsresult aRv, const char* aMessage, + const char* aName, uint16_t aCode) + : Exception(nullptr, aRv, nullptr, nullptr, nullptr), + mName(aName), + mMessage(aMessage), + mCode(aCode) +{ + SetIsDOMBinding(); +} + +NS_IMETHODIMP +DOMException::GetCode(uint16_t* aCode) +{ + NS_ENSURE_ARG_POINTER(aCode); + *aCode = mCode; + + // Warn only when the code was changed (other than DOM Core) + // or the code is useless (zero) + if (NS_ERROR_GET_MODULE(mResult) != NS_ERROR_MODULE_DOM || !mCode) { + nsCOMPtr doc = nsContentUtils::GetDocumentFromCaller(); + if (doc) { + doc->WarnOnceAbout(nsIDocument::eDOMExceptionCode); + } + } + + return NS_OK; +} + +NS_IMETHODIMP +DOMException::ToString(char **aReturn) +{ + *aReturn = nullptr; + + static const char defaultMsg[] = ""; + static const char defaultLocation[] = ""; + static const char defaultName[] = ""; + static const char format[] = + "[Exception... \"%s\" code: \"%d\" nsresult: \"0x%x (%s)\" location: \"%s\"]"; + + nsAutoCString location; + + if (mInner) { + nsXPIDLCString filename; + + mInner->GetFilename(getter_Copies(filename)); + + if (!filename.IsEmpty()) { + uint32_t line_nr = 0; + + mInner->GetLineNumber(&line_nr); + + char *temp = PR_smprintf("%s Line: %d", filename.get(), line_nr); + if (temp) { + location.Assign(temp); + PR_smprintf_free(temp); + } + } + } + + if (location.IsEmpty()) { + location = defaultLocation; + } + + const char* msg = mMessage ? mMessage : defaultMsg; + 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; +} + +void +DOMException::GetName(nsString& retval) +{ + CopyUTF8toUTF16(mName, retval); +} + +void +DOMException::GetMessageMoz(nsString& retval) +{ + CopyUTF8toUTF16(mMessage, retval); +} + +JSObject* +DOMException::WrapObject(JSContext* aCx, JS::Handle aScope) +{ + return DOMExceptionBinding::Wrap(aCx, aScope, this); +} + +/* static */already_AddRefed +DOMException::Create(nsresult aRv) +{ + const char* name; + const char* message; + uint16_t code; + NSResultToNameAndMessage(aRv, &name, &message, &code); + nsRefPtr inst = + new DOMException(aRv, message, name, code); + return inst.forget(); +} + +} // namespace dom +} // namespace mozilla diff --git a/dom/base/DOMException.h b/dom/base/DOMException.h new file mode 100644 index 00000000000..7504ed46b76 --- /dev/null +++ b/dom/base/DOMException.h @@ -0,0 +1,161 @@ +/* -*- Mode: C++; 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/. */ + +#ifndef mozilla_dom_DOMException_h__ +#define mozilla_dom_DOMException_h__ + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Woverloaded-virtual" +#endif + +#include +#include "jspubtd.h" +#include "js/GCAPI.h" +#include "nsCOMPtr.h" +#include "nsCycleCollectionParticipant.h" +#include "nsID.h" +#include "nsIDOMDOMException.h" +#include "nsWrapperCache.h" +#include "xpcexception.h" + +class nsIStackFrame; +class nsString; + +nsresult +NS_GetNameAndMessageForDOMNSResult(nsresult aNSResult, const char** aName, + const char** aMessage, + uint16_t* aCode = nullptr); + +namespace mozilla { +namespace dom { + +#define MOZILLA_DOM_EXCEPTION_IID \ +{ 0x55eda557, 0xeba0, 0x4fe3, \ + { 0xae, 0x2e, 0xf3, 0x94, 0x49, 0x23, 0x62, 0xd6 } } + +class Exception : public nsIXPCException, + public nsWrapperCache +{ +public: + NS_DECLARE_STATIC_IID_ACCESSOR(MOZILLA_DOM_EXCEPTION_IID) + + NS_DEFINE_STATIC_CID_ACCESSOR(NS_XPCEXCEPTION_CID) + + NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Exception) + + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_NSIEXCEPTION + NS_DECL_NSIXPCEXCEPTION + + // Cruft used by XPConnect for exceptions originating in JS implemented + // components. + bool StealJSVal(JS::Value* aVp); + void StowJSVal(JS::Value& aVp); + + // WebIDL API + virtual JSObject* WrapObject(JSContext* cx, JS::Handle 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 GetLocation() const; + + already_AddRefed GetInner() const; + + already_AddRefed GetData() const; + + void Stringify(nsString& retval); + + // XPCOM factory ctor. + Exception(); + + Exception(const char *aMessage, + nsresult aResult, + const char *aName, + nsIStackFrame *aLocation, + nsISupports *aData); + +protected: + virtual ~Exception(); + + char* mMessage; + nsresult mResult; + char* mName; + nsCOMPtr mLocation; + nsCOMPtr mData; + char* mFilename; + int mLineNumber; + nsCOMPtr mInner; + bool mInitialized; + + bool mHoldingJSVal; + JS::Heap mThrownJSVal; + +private: + static bool sEverMadeOneFromFactory; +}; + +NS_DEFINE_STATIC_IID_ACCESSOR(Exception, MOZILLA_DOM_EXCEPTION_IID) + +class DOMException : public Exception, + public nsIDOMDOMException +{ +public: + DOMException(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 aScope) + MOZ_OVERRIDE; + + uint16_t Code() const { + return mCode; + } + + // Intentionally shadow the nsXPCException version. + void GetMessageMoz(nsString& retval); + void GetName(nsString& retval); + + static already_AddRefed + Create(nsresult aRv); + +protected: + + virtual ~DOMException() {} + + // Intentionally shadow the nsXPCException version. + const char* mName; + const char* mMessage; + + uint16_t mCode; +}; + +} // namespace dom +} // namespace mozilla + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif + +#endif diff --git a/dom/base/moz.build b/dom/base/moz.build index 0f84ca35e42..33bfe18b465 100644 --- a/dom/base/moz.build +++ b/dom/base/moz.build @@ -22,7 +22,6 @@ EXPORTS += [ 'nsDOMCID.h', 'nsDOMClassInfoClasses.h', 'nsDOMClassInfoID.h', - 'nsDOMException.h', 'nsDOMJSUtils.h', 'nsDOMNavigationTiming.h', 'nsDOMString.h', @@ -54,6 +53,7 @@ EXPORTS.mozilla.dom += [ 'BarProps.h', 'DOMCursor.h', 'DOMError.h', + 'DOMException.h', 'DOMRequest.h', 'MessageChannel.h', 'MessagePort.h', @@ -67,13 +67,13 @@ CPP_SOURCES += [ 'Crypto.cpp', 'DOMCursor.cpp', 'DOMError.cpp', + 'DOMException.cpp', 'DOMRequest.cpp', 'Navigator.cpp', 'MessageChannel.cpp', 'MessagePort.cpp', 'nsContentPermissionHelper.cpp', 'nsDOMClassInfo.cpp', - 'nsDOMException.cpp', 'nsDOMNavigationTiming.cpp', 'nsDOMScriptObjectFactory.cpp', 'nsDOMWindowList.cpp', diff --git a/dom/base/nsDOMClassInfo.cpp b/dom/base/nsDOMClassInfo.cpp index 8bf96d7508a..9cca51b39f2 100644 --- a/dom/base/nsDOMClassInfo.cpp +++ b/dom/base/nsDOMClassInfo.cpp @@ -77,7 +77,6 @@ // DOM core includes #include "nsError.h" -#include "nsIDOMDOMException.h" #include "nsIDOMDOMStringList.h" #include "nsIDOMUserDataHandler.h" #include "nsIDOMLoadStatus.h" @@ -338,10 +337,6 @@ static nsDOMClassInfoData sClassInfoData[] = { nsIXPCScriptable::WANT_CONSTRUCT | nsIXPCScriptable::DONT_ENUM_QUERY_INTERFACE) - // Core classes - NS_DEFINE_CLASSINFO_DATA(DOMException, nsDOMGenericSH, - DOM_DEFAULT_SCRIPTABLE_FLAGS) - // Misc Core related classes NS_DEFINE_CLASSINFO_DATA(DeviceAcceleration, nsDOMGenericSH, @@ -1110,11 +1105,6 @@ nsDOMClassInfo::Init() DOM_CLASSINFO_MAP_ENTRY(nsIDOMDOMConstructor) DOM_CLASSINFO_MAP_END - DOM_CLASSINFO_MAP_BEGIN(DOMException, nsIDOMDOMException) - DOM_CLASSINFO_MAP_ENTRY(nsIDOMDOMException) - DOM_CLASSINFO_MAP_ENTRY(nsIException) - DOM_CLASSINFO_MAP_END - DOM_CLASSINFO_MAP_BEGIN(DeviceAcceleration, nsIDOMDeviceAcceleration) DOM_CLASSINFO_MAP_ENTRY(nsIDOMDeviceAcceleration) DOM_CLASSINFO_MAP_END diff --git a/dom/base/nsDOMClassInfoClasses.h b/dom/base/nsDOMClassInfoClasses.h index 723f7e988bb..394769a116a 100644 --- a/dom/base/nsDOMClassInfoClasses.h +++ b/dom/base/nsDOMClassInfoClasses.h @@ -9,9 +9,6 @@ DOMCI_CLASS(Location) DOMCI_CLASS(DOMPrototype) DOMCI_CLASS(DOMConstructor) -// Core classes -DOMCI_CLASS(DOMException) - DOMCI_CLASS(DeviceAcceleration) DOMCI_CLASS(DeviceRotationRate) diff --git a/dom/base/nsDOMException.cpp b/dom/base/nsDOMException.cpp deleted file mode 100644 index c3df76d8797..00000000000 --- a/dom/base/nsDOMException.cpp +++ /dev/null @@ -1,238 +0,0 @@ -/* -*- Mode: C++; 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/. */ - -#include "nsDOMException.h" - -#include "mozilla/Util.h" -#include "nsCOMPtr.h" -#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 "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, - NotFoundError = nsIDOMDOMException::NOT_FOUND_ERR, - NotSupportedError = nsIDOMDOMException::NOT_SUPPORTED_ERR, - // Can't remove until setNamedItem is removed - InUseAttributeError = nsIDOMDOMException::INUSE_ATTRIBUTE_ERR, - InvalidStateError = nsIDOMDOMException::INVALID_STATE_ERR, - SyntaxError = nsIDOMDOMException::SYNTAX_ERR, - InvalidModificationError = nsIDOMDOMException::INVALID_MODIFICATION_ERR, - NamespaceError = nsIDOMDOMException::NAMESPACE_ERR, - InvalidAccessError = nsIDOMDOMException::INVALID_ACCESS_ERR, - TypeMismatchError = nsIDOMDOMException::TYPE_MISMATCH_ERR, - SecurityError = nsIDOMDOMException::SECURITY_ERR, - NetworkError = nsIDOMDOMException::NETWORK_ERR, - AbortError = nsIDOMDOMException::ABORT_ERR, - URLMismatchError = nsIDOMDOMException::URL_MISMATCH_ERR, - QuotaExceededError = nsIDOMDOMException::QUOTA_EXCEEDED_ERR, - TimeoutError = nsIDOMDOMException::TIMEOUT_ERR, - InvalidNodeTypeError = nsIDOMDOMException::INVALID_NODE_TYPE_ERR, - DataCloneError = nsIDOMDOMException::DATA_CLONE_ERR, - EncodingError = 0, - - /* XXX Should be JavaScript native errors */ - TypeError = 0, - RangeError = 0, - - /* IndexedDB errors http://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html#exceptions */ - UnknownError = 0, - ConstraintError = 0, - DataError = 0, - TransactionInactiveError = 0, - ReadOnlyError = 0, - VersionError = 0, - - /* File API errors http://dev.w3.org/2006/webapi/FileAPI/#ErrorAndException */ - NotReadableError = 0, - - /* FileHandle API errors */ - LockedFileInactiveError = 0, -}; - -#define DOM4_MSG_DEF(name, message, nsresult) {(nsresult), name, #name, message}, -#define DOM_MSG_DEF(val, message) {(val), NS_ERROR_GET_CODE(val), #val, message}, - -static const struct ResultStruct -{ - nsresult mNSResult; - uint16_t mCode; - const char* mName; - const char* mMessage; -} sDOMErrorMsgMap[] = { -#include "domerr.msg" -}; - -#undef DOM4_MSG_DEF -#undef DOM_MSG_DEF - -static void -NSResultToNameAndMessage(nsresult aNSResult, - const char** aName, - const char** aMessage, - uint16_t* aCode) -{ - *aName = nullptr; - *aMessage = nullptr; - *aCode = 0; - for (uint32_t idx = 0; idx < ArrayLength(sDOMErrorMsgMap); idx++) { - if (aNSResult == sDOMErrorMsgMap[idx].mNSResult) { - *aName = sDOMErrorMsgMap[idx].mName; - *aMessage = sDOMErrorMsgMap[idx].mMessage; - *aCode = sDOMErrorMsgMap[idx].mCode; - return; - } - } - - NS_WARNING("Huh, someone is throwing non-DOM errors using the DOM module!"); - - return; -} - -nsresult -NS_GetNameAndMessageForDOMNSResult(nsresult aNSResult, const char** aName, - const char** aMessage, uint16_t* aCode) -{ - const char* name = nullptr; - const char* message = nullptr; - uint16_t code = 0; - NSResultToNameAndMessage(aNSResult, &name, &message, &code); - - if (name && message) { - *aName = name; - *aMessage = message; - if (aCode) { - *aCode = code; - } - return NS_OK; - } - - return NS_ERROR_NOT_AVAILABLE; -} - -DOMCI_DATA(DOMException, nsDOMException) - -NS_IMPL_ADDREF_INHERITED(nsDOMException, nsXPCException) -NS_IMPL_RELEASE_INHERITED(nsDOMException, nsXPCException) -NS_INTERFACE_MAP_BEGIN(nsDOMException) - NS_INTERFACE_MAP_ENTRY(nsIDOMDOMException) - NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(DOMException) -NS_INTERFACE_MAP_END_INHERITING(nsXPCException) - -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 -NS_NewDOMException(nsresult aNSResult) -{ - const char* name; - const char* message; - uint16_t code; - NSResultToNameAndMessage(aNSResult, &name, &message, &code); - nsRefPtr inst = - new nsDOMException(aNSResult, message, name, code); - return inst.forget(); -} - -NS_IMETHODIMP -nsDOMException::GetCode(uint16_t* aCode) -{ - NS_ENSURE_ARG_POINTER(aCode); - *aCode = mCode; - - // Warn only when the code was changed (other than DOM Core) - // or the code is useless (zero) - if (NS_ERROR_GET_MODULE(mResult) != NS_ERROR_MODULE_DOM || !mCode) { - nsCOMPtr doc = nsContentUtils::GetDocumentFromCaller(); - if (doc) { - doc->WarnOnceAbout(nsIDocument::eDOMExceptionCode); - } - } - - return NS_OK; -} - -NS_IMETHODIMP -nsDOMException::ToString(char **aReturn) -{ - *aReturn = nullptr; - - static const char defaultMsg[] = ""; - static const char defaultLocation[] = ""; - static const char defaultName[] = ""; - static const char format[] = - "[Exception... \"%s\" code: \"%d\" nsresult: \"0x%x (%s)\" location: \"%s\"]"; - - nsAutoCString location; - - if (mInner) { - nsXPIDLCString filename; - - mInner->GetFilename(getter_Copies(filename)); - - if (!filename.IsEmpty()) { - uint32_t line_nr = 0; - - mInner->GetLineNumber(&line_nr); - - char *temp = PR_smprintf("%s Line: %d", filename.get(), line_nr); - if (temp) { - location.Assign(temp); - PR_smprintf_free(temp); - } - } - } - - if (location.IsEmpty()) { - location = defaultLocation; - } - - const char* msg = mMessage ? mMessage : defaultMsg; - 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; -} - -void -nsDOMException::GetName(nsString& retval) -{ - CopyUTF8toUTF16(mName, retval); -} - -void -nsDOMException::GetMessageMoz(nsString& retval) -{ - CopyUTF8toUTF16(mMessage, retval); -} - -JSObject* -nsDOMException::WrapObject(JSContext* aCx, JS::Handle aScope) -{ - return DOMExceptionBinding::Wrap(aCx, aScope, this); -} diff --git a/dom/base/nsDOMException.h b/dom/base/nsDOMException.h deleted file mode 100644 index c3295b625ad..00000000000 --- a/dom/base/nsDOMException.h +++ /dev/null @@ -1,67 +0,0 @@ -/* -*- 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" -#include "nsIDOMDOMException.h" -#include "nsIException.h" -#include "nsCOMPtr.h" -#include "xpcprivate.h" - -template 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 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); - -already_AddRefed -NS_NewDOMException(nsresult aNSResult); - -#ifdef __GNUC__ -#pragma GCC diagnostic pop -#endif diff --git a/dom/base/nsDOMScriptObjectFactory.cpp b/dom/base/nsDOMScriptObjectFactory.cpp index dd48b8e0b01..8a0e1c62541 100644 --- a/dom/base/nsDOMScriptObjectFactory.cpp +++ b/dom/base/nsDOMScriptObjectFactory.cpp @@ -24,7 +24,6 @@ #include "nsIObserverService.h" #include "nsJSEnvironment.h" #include "nsGlobalWindow.h" -#include "nsDOMException.h" #include "nsCRT.h" #ifdef MOZ_XUL #include "nsXULPrototypeCache.h" diff --git a/dom/bindings/Bindings.conf b/dom/bindings/Bindings.conf index 3c3f3e5e3ca..6287febba1c 100644 --- a/dom/bindings/Bindings.conf +++ b/dom/bindings/Bindings.conf @@ -320,7 +320,6 @@ DOMInterfaces = { }, 'DOMException': { - 'nativeType': 'nsDOMException', 'binaryNames': { 'message': 'messageMoz', }, @@ -399,8 +398,7 @@ DOMInterfaces = { }], 'Exception': { - 'nativeType': 'nsXPCException', - 'headerFile': 'xpcprivate.h', + 'headerFile': 'mozilla/dom/DOMException.h', 'binaryNames': { 'message': 'messageMoz', } diff --git a/dom/bindings/Exceptions.cpp b/dom/bindings/Exceptions.cpp new file mode 100644 index 00000000000..5319c3352eb --- /dev/null +++ b/dom/bindings/Exceptions.cpp @@ -0,0 +1,410 @@ +/* -*- Mode: C++; 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/. */ + +#include "mozilla/dom/Exceptions.h" + +#include "js/GCAPI.h" +#include "js/OldDebugAPI.h" +#include "jsapi.h" +#include "jsprf.h" +#include "mozilla/CycleCollectedJSRuntime.h" +#include "mozilla/dom/BindingUtils.h" +#include "mozilla/dom/DOMException.h" +#include "nsThreadUtils.h" +#include "XPCWrapper.h" + +namespace { + +// We can't use nsContentUtils::IsCallerChrome because it might not exist in +// xpcshell. +bool +IsCallerChrome() +{ + nsCOMPtr secMan; + secMan = XPCWrapper::GetSecurityManager(); + + if (!secMan) { + return false; + } + + bool isChrome; + return NS_SUCCEEDED(secMan->SubjectPrincipalIsSystem(&isChrome)) && isChrome; +} + +} // anonymous namespace + +namespace mozilla { +namespace dom { + +bool +ThrowExceptionObject(JSContext* aCx, nsIException* aException) +{ + // See if we really have an Exception. + nsCOMPtr exception = do_QueryInterface(aException); + if (exception) { + return ThrowExceptionObject(aCx, exception); + } + + // We only have an nsIException (probably an XPCWrappedJS). Fall back on old + // wrapping. + MOZ_ASSERT(NS_IsMainThread()); + + JS::RootedObject glob(aCx, JS::CurrentGlobalOrNull(aCx)); + if (!glob) { + return false; + } + + nsCOMPtr holder; + nsresult rv = nsContentUtils::XPConnect()->WrapNative(aCx, glob, aException, + NS_GET_IID(nsIException), + getter_AddRefs(holder)); + if (NS_FAILED(rv) ||! holder) { + return false; + } + + JS::RootedObject obj(aCx, holder->GetJSObject()); + if (!obj) { + return false; + } + + JS_SetPendingException(aCx, OBJECT_TO_JSVAL(obj)); + + return true; +} + +bool +ThrowExceptionObject(JSContext* aCx, Exception* aException) +{ + JS::RootedValue thrown(aCx); + + // 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. This only applies to JS + // implemented components so we only need to check for this on the main + // thread. + if (NS_IsMainThread() && !IsCallerChrome() && + aException->StealJSVal(thrown.address())) { + if (!JS_WrapValue(aCx, thrown.address())) { + return false; + } + JS_SetPendingException(aCx, thrown); + return true; + } + + JS::RootedObject glob(aCx, JS::CurrentGlobalOrNull(aCx)); + if (!glob) { + return false; + } + + JS::RootedValue val(aCx); + if (!mozilla::dom::WrapNewBindingObject(aCx, glob, aException, &val)) { + return false; + } + + JS_SetPendingException(aCx, val); + return true; +} + +void +Throw(JSContext* cx, nsresult rv, const char* sz) +{ + bool success = false; + + if (JS_IsExceptionPending(cx)) { + // Don't clobber the existing exception. + return; + } + + /* no need to set an expection if the security manager already has */ + if (rv == NS_ERROR_XPC_SECURITY_MANAGER_VETO && JS_IsExceptionPending(cx)) { + // This should only ever happen on the main thread. + MOZ_ASSERT(NS_IsMainThread()); + return; + } + + CycleCollectedJSRuntime* runtime = CycleCollectedJSRuntime::Get(); + nsCOMPtr existingException = runtime->GetPendingException(); + if (existingException) { + nsresult nr; + if (NS_SUCCEEDED(existingException->GetResult(&nr)) && + rv == nr) { + // Just reuse the existing exception. + return; + } + } + + nsRefPtr 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()) { + finalException = DOMException::Create(rv); + } + break; + + default: + break; + } + + // If not, use the default. + if (finalException == nullptr) { + finalException = new Exception(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); + } +} + +namespace exceptions { + +class JSStackFrame : public nsIStackFrame +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISTACKFRAME + + JSStackFrame(); + virtual ~JSStackFrame(); + + static already_AddRefed + CreateStack(JSContext* cx); + static already_AddRefed + CreateStackFrameLocation(uint32_t aLanguage, + const char* aFilename, + const char* aFunctionName, + int32_t aLineNumber, + nsIStackFrame* aCaller); + +private: + bool IsJSFrame() const { + return mLanguage == nsIProgrammingLanguage::JAVASCRIPT; + } + + nsCOMPtr mCaller; + + char* mFilename; + char* mFunname; + int32_t mLineno; + uint32_t mLanguage; +}; + +JSStackFrame::JSStackFrame() + : mFilename(nullptr), + mFunname(nullptr), + mLineno(0), + mLanguage(nsIProgrammingLanguage::UNKNOWN) +{} + +JSStackFrame::~JSStackFrame() +{ + if (mFilename) { + nsMemory::Free(mFilename); + } + if (mFunname) { + nsMemory::Free(mFunname); + } +} + +NS_IMPL_ISUPPORTS1(JSStackFrame, nsIStackFrame) + +/* readonly attribute uint32_t language; */ +NS_IMETHODIMP JSStackFrame::GetLanguage(uint32_t* aLanguage) +{ + *aLanguage = mLanguage; + return NS_OK; +} + +/* readonly attribute string languageName; */ +NS_IMETHODIMP JSStackFrame::GetLanguageName(char** aLanguageName) +{ + static const char js[] = "JavaScript"; + static const char cpp[] = "C++"; + + if (IsJSFrame()) { + *aLanguageName = (char*) nsMemory::Clone(js, sizeof(js)); + } else { + *aLanguageName = (char*) nsMemory::Clone(cpp, sizeof(cpp)); + } + + return NS_OK; +} + +/* readonly attribute string filename; */ +NS_IMETHODIMP JSStackFrame::GetFilename(char** aFilename) +{ + NS_ENSURE_ARG_POINTER(aFilename); + + if (mFilename) { + *aFilename = (char*) nsMemory::Clone(mFilename, + sizeof(char)*(strlen(mFilename)+1)); + } else { + *aFilename = nullptr; + } + + return NS_OK; +} + +/* readonly attribute string name; */ +NS_IMETHODIMP JSStackFrame::GetName(char** aFunction) +{ + NS_ENSURE_ARG_POINTER(aFunction); + + if (mFunname) { + *aFunction = (char*) nsMemory::Clone(mFunname, + sizeof(char)*(strlen(mFunname)+1)); + } else { + *aFunction = nullptr; + } + + return NS_OK; +} + +/* readonly attribute int32_t lineNumber; */ +NS_IMETHODIMP JSStackFrame::GetLineNumber(int32_t* aLineNumber) +{ + *aLineNumber = mLineno; + return NS_OK; +} + +/* readonly attribute string sourceLine; */ +NS_IMETHODIMP JSStackFrame::GetSourceLine(char** aSourceLine) +{ + *aSourceLine = nullptr; + return NS_OK; +} + +/* readonly attribute nsIStackFrame caller; */ +NS_IMETHODIMP JSStackFrame::GetCaller(nsIStackFrame** aCaller) +{ + NS_IF_ADDREF(*aCaller = mCaller); + return NS_OK; +} + +/* string toString (); */ +NS_IMETHODIMP JSStackFrame::ToString(char** _retval) +{ + const char* frametype = IsJSFrame() ? "JS" : "native"; + const char* filename = mFilename ? mFilename : ""; + const char* funname = mFunname ? mFunname : ""; + static const char format[] = "%s frame :: %s :: %s :: line %d"; + int len = sizeof(char)* + (strlen(frametype) + strlen(filename) + strlen(funname)) + + sizeof(format) + 6 /* space for lineno */; + + char* buf = (char*) nsMemory::Alloc(len); + JS_snprintf(buf, len, format, frametype, filename, funname, mLineno); + *_retval = buf; + return NS_OK; +} + +/* static */ already_AddRefed +JSStackFrame::CreateStack(JSContext* cx) +{ + static const unsigned MAX_FRAMES = 100; + + nsRefPtr first = new JSStackFrame(); + nsRefPtr self = first; + + JS::StackDescription* desc = JS::DescribeStack(cx, MAX_FRAMES); + if (!desc) { + return nullptr; + } + + for (size_t i = 0; i < desc->nframes && self; i++) { + self->mLanguage = nsIProgrammingLanguage::JAVASCRIPT; + + JSAutoCompartment ac(cx, desc->frames[i].script); + const char* filename = JS_GetScriptFilename(cx, desc->frames[i].script); + if (filename) { + self->mFilename = + (char*)nsMemory::Clone(filename, sizeof(char)*(strlen(filename)+1)); + } + + self->mLineno = desc->frames[i].lineno; + + JSFunction* fun = desc->frames[i].fun; + if (fun) { + JS::RootedString funid(cx, JS_GetFunctionDisplayId(fun)); + if (funid) { + size_t length = JS_GetStringEncodingLength(cx, funid); + if (length != size_t(-1)) { + self->mFunname = static_cast(nsMemory::Alloc(length + 1)); + if (self->mFunname) { + JS_EncodeStringToBuffer(cx, funid, self->mFunname, length); + self->mFunname[length] = '\0'; + } + } + } + } + + nsRefPtr frame = new JSStackFrame(); + self->mCaller = frame; + self = frame.forget(); + } + + JS::FreeStackDescription(cx, desc); + + return first.forget(); +} + +/* static */ already_AddRefed +JSStackFrame::CreateStackFrameLocation(uint32_t aLanguage, + const char* aFilename, + const char* aFunctionName, + int32_t aLineNumber, + nsIStackFrame* aCaller) +{ + nsRefPtr self = new JSStackFrame(); + + self->mLanguage = aLanguage; + self->mLineno = aLineNumber; + + if (aFilename) { + self->mFilename = + (char*)nsMemory::Clone(aFilename, sizeof(char)*(strlen(aFilename)+1)); + } + + if (aFunctionName) { + self->mFunname = + (char*)nsMemory::Clone(aFunctionName, + sizeof(char)*(strlen(aFunctionName)+1)); + } + + self->mCaller = aCaller; + + return self.forget(); +} + +already_AddRefed +CreateStack(JSContext* cx) +{ + return JSStackFrame::CreateStack(cx); +} + +already_AddRefed +CreateStackFrameLocation(uint32_t aLanguage, + const char* aFilename, + const char* aFunctionName, + int32_t aLineNumber, + nsIStackFrame* aCaller) +{ + return JSStackFrame::CreateStackFrameLocation(aLanguage, aFilename, + aFunctionName, aLineNumber, + aCaller); +} + +} // namespace exceptions +} // namespace dom +} // namespace mozilla diff --git a/dom/bindings/Exceptions.h b/dom/bindings/Exceptions.h new file mode 100644 index 00000000000..5364d90bd13 --- /dev/null +++ b/dom/bindings/Exceptions.h @@ -0,0 +1,50 @@ +/* -*- Mode: C++; 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/. */ + +#ifndef mozilla_dom_Exceptions_h__ +#define mozilla_dom_Exceptions_h__ + +// DOM exception throwing machinery (for both main thread and workers). + +#include +#include "jspubtd.h" +#include "nsIException.h" + +class nsIStackFrame; +template +class already_AddRefed; + +namespace mozilla { +namespace dom { + +class Exception; + +void +Throw(JSContext* cx, nsresult rv, const char* sz); + +bool +ThrowExceptionObject(JSContext* aCx, Exception* aException); + +bool +ThrowExceptionObject(JSContext* aCx, nsIException* aException); + +// Internal stuff not intended to be widely used. +namespace exceptions { + +already_AddRefed +CreateStack(JSContext* cx); + +already_AddRefed +CreateStackFrameLocation(uint32_t aLanguage, + const char* aFilename, + const char* aFunctionName, + int32_t aLineNumber, + nsIStackFrame* aCaller); + +} // namespace exceptions +} // namespace dom +} // namespace mozilla + +#endif diff --git a/dom/bindings/Makefile.in b/dom/bindings/Makefile.in index 28ff3288958..f39a3b474de 100644 --- a/dom/bindings/Makefile.in +++ b/dom/bindings/Makefile.in @@ -60,6 +60,7 @@ CPPSRCS = \ CallbackObject.cpp \ DOMJSProxyHandler.cpp \ Date.cpp \ + Exceptions.cpp \ $(NULL) endif diff --git a/dom/bindings/moz.build b/dom/bindings/moz.build index 3368a276e81..49da494785a 100644 --- a/dom/bindings/moz.build +++ b/dom/bindings/moz.build @@ -21,6 +21,7 @@ EXPORTS.mozilla.dom += [ 'DOMJSProxyHandler.h', 'Date.h', 'Errors.msg', + 'Exceptions.h', 'JSSlots.h', 'NonRefcountedDOMObject.h', 'Nullable.h', diff --git a/dom/workers/RuntimeService.cpp b/dom/workers/RuntimeService.cpp index 9557dc13547..365932f471b 100644 --- a/dom/workers/RuntimeService.cpp +++ b/dom/workers/RuntimeService.cpp @@ -1116,7 +1116,7 @@ bool IsCurrentThreadRunningChromeWorker() { NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); - CycleCollectedJSRuntime* ccrt = nsCycleCollector_currentJSRuntime(); + CycleCollectedJSRuntime* ccrt = CycleCollectedJSRuntime::Get(); if (!ccrt) { return false; } diff --git a/js/xpconnect/idl/xpcexception.idl b/js/xpconnect/idl/xpcexception.idl index 6c31e424b83..79db29aced9 100644 --- a/js/xpconnect/idl/xpcexception.idl +++ b/js/xpconnect/idl/xpcexception.idl @@ -7,14 +7,7 @@ #include "nsISupports.idl" #include "nsIException.idl" -%{ C++ -#include "js/TypeDecls.h" -%} - -[ptr] native xpcexJSContextPtr(JSContext); - native xpcexJSVal(JS::Value); - -[scriptable, uuid(cac29630-7bf2-4e22-811b-46855a7d5af0)] +[scriptable, uuid(ce83229c-0a82-4ba4-937b-7fd4cd45f34b)] interface nsIXPCException : nsIException { // inherits methods from nsIException @@ -25,10 +18,6 @@ interface nsIXPCException : nsIException in nsIStackFrame aLocation, in nsISupports aData, in nsIException aInner); - - [noscript] xpcexJSVal stealJSVal(); - [noscript] void stowJSVal(in xpcexJSContextPtr cx, - in xpcexJSVal val); }; /* this goes into the C++ header verbatim. */ diff --git a/js/xpconnect/src/XPCComponents.cpp b/js/xpconnect/src/XPCComponents.cpp index 9e007b871f4..98c844d0345 100644 --- a/js/xpconnect/src/XPCComponents.cpp +++ b/js/xpconnect/src/XPCComponents.cpp @@ -39,12 +39,14 @@ #include "mozilla/XPTInterfaceInfoManager.h" #include "nsDOMClassInfoID.h" #include "nsGlobalWindow.h" +#include "mozilla/dom/DOMException.h" #include "mozilla/dom/DOMExceptionBinding.h" using namespace mozilla; using namespace JS; using namespace js; using namespace xpc; +using mozilla::dom::Exception; /***************************************************************************/ // stuff used by all @@ -1946,7 +1948,7 @@ nsXPCComponents_Exception::CallOrConstruct(nsIXPConnectWrappedNative *wrapper, // Do the security check if necessary nsIXPCSecurityManager* sm = xpc->GetDefaultSecurityManager(); - if (sm && NS_FAILED(sm->CanCreateInstance(cx, nsXPCException::GetCID()))) { + if (sm && NS_FAILED(sm->CanCreateInstance(cx, Exception::GetCID()))) { // the security manager vetoed. It should have set an exception. *_retval = false; return NS_OK; @@ -1957,11 +1959,9 @@ nsXPCComponents_Exception::CallOrConstruct(nsIXPConnectWrappedNative *wrapper, if (!parser.parse(args)) return ThrowAndFail(NS_ERROR_XPC_BAD_CONVERT_JS, cx, _retval); - nsCOMPtr e = new nsXPCException(parser.eMsg, parser.eResult, - nullptr, parser.eStack, - parser.eData); - if (!e) - return ThrowAndFail(NS_ERROR_XPC_UNEXPECTED, cx, _retval); + nsCOMPtr e = new Exception(parser.eMsg, parser.eResult, + nullptr, parser.eStack, + parser.eData); nsCOMPtr holder; RootedObject newObj(cx); @@ -1988,7 +1988,7 @@ nsXPCComponents_Exception::HasInstance(nsIXPConnectWrappedNative *wrapper, RootedValue v(cx, val); if (bp) { - nsXPCException* e; + Exception* e; *bp = NS_SUCCEEDED(UNWRAP_OBJECT(Exception, cx, v.toObjectOrNull(), e)) || JSValIsInterfaceOfType(cx, v, NS_GET_IID(nsIException)); } diff --git a/js/xpconnect/src/XPCConvert.cpp b/js/xpconnect/src/XPCConvert.cpp index cbb8efb4690..bbe0d53483c 100644 --- a/js/xpconnect/src/XPCConvert.cpp +++ b/js/xpconnect/src/XPCConvert.cpp @@ -27,6 +27,7 @@ #include "JavaScriptParent.h" #include "mozilla/dom/BindingUtils.h" +#include "mozilla/dom/DOMException.h" #include "mozilla/dom/PrimitiveConversions.h" using namespace xpc; @@ -1080,14 +1081,14 @@ XPCConvert::ConstructException(nsresult rv, const char* message, if (ifaceName && methodName) msg = sz = JS_smprintf(format, msg, ifaceName, methodName); - nsCOMPtr e = new nsXPCException(msg, rv, nullptr, nullptr, data); + nsRefPtr e = new Exception(msg, rv, nullptr, nullptr, data); - if (cx && jsExceptionPtr && *exceptn) { - nsCOMPtr xpcEx = do_QueryInterface(*exceptn); - if (xpcEx) - xpcEx->StowJSVal(cx, *jsExceptionPtr); + if (cx && jsExceptionPtr) { + e->StowJSVal(*jsExceptionPtr); } + e.forget(exceptn); + if (sz) JS_smprintf_free(sz); return NS_OK; diff --git a/js/xpconnect/src/XPCException.cpp b/js/xpconnect/src/XPCException.cpp index b6aef5f4845..d913aa5c0f2 100644 --- a/js/xpconnect/src/XPCException.cpp +++ b/js/xpconnect/src/XPCException.cpp @@ -7,12 +7,7 @@ /* An implementaion of nsIException. */ #include "xpcprivate.h" -#include "jsprf.h" #include "nsError.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 @@ -83,462 +78,3 @@ nsXPCException::GetNSResultCount() { return RESULT_COUNT; } - -/***************************************************************************/ - -NS_IMPL_CLASSINFO(nsXPCException, NULL, nsIClassInfo::DOM_OBJECT, - NS_XPCEXCEPTION_CID) -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 - -NS_IMPL_CYCLE_COLLECTING_ADDREF(nsXPCException) -NS_IMPL_CYCLE_COLLECTING_RELEASE(nsXPCException) - -NS_IMPL_CYCLE_COLLECTION_CLASS(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 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 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) -{ } - -nsXPCException::~nsXPCException() -{ - Reset(); -} - -/* [noscript] xpcexJSVal stealJSVal (); */ -NS_IMETHODIMP -nsXPCException::StealJSVal(jsval *vp) -{ - if (mThrownJSVal.IsHeld()) { - *vp = mThrownJSVal.Release(); - return NS_OK; - } - return NS_ERROR_FAILURE; -} - -/* [noscript] void stowJSVal (in xpcexJSContextPtr cx, in xpcexJSVal val); */ -NS_IMETHODIMP -nsXPCException::StowJSVal(JSContext* cx, jsval v) -{ - if (mThrownJSVal.Hold(cx)) { - mThrownJSVal = v; - return NS_OK; - } - return NS_ERROR_FAILURE; -} - -void -nsXPCException::Reset() -{ - if (mMessage) { - nsMemory::Free(mMessage); - mMessage = nullptr; - } - if (mName) { - nsMemory::Free(mName); - mName = nullptr; - } - if (mFilename) { - nsMemory::Free(mFilename); - mFilename = nullptr; - } - mLineNumber = (uint32_t)-1; - NS_IF_RELEASE(mLocation); - NS_IF_RELEASE(mData); - NS_IF_RELEASE(mInner); -} - -/* readonly attribute string message; */ -NS_IMETHODIMP -nsXPCException::GetMessageMoz(char * *aMessage) -{ - if (!mInitialized) - return NS_ERROR_NOT_INITIALIZED; - XPC_STRING_GETTER_BODY(aMessage, mMessage); -} - -/* readonly attribute nsresult result; */ -NS_IMETHODIMP -nsXPCException::GetResult(nsresult *aResult) -{ - if (!aResult) - return NS_ERROR_NULL_POINTER; - if (!mInitialized) - return NS_ERROR_NOT_INITIALIZED; - *aResult = mResult; - return NS_OK; -} - -/* readonly attribute string name; */ -NS_IMETHODIMP -nsXPCException::GetName(char * *aName) -{ - if (!mInitialized) - return NS_ERROR_NOT_INITIALIZED; - - const char* name = mName; - if (!name) - NameAndFormatForNSResult(mResult, &name, nullptr); - - XPC_STRING_GETTER_BODY(aName, name); -} - -/* readonly attribute string filename; */ -NS_IMETHODIMP nsXPCException::GetFilename(char * *aFilename) -{ - if (!mInitialized) - return NS_ERROR_NOT_INITIALIZED; - XPC_STRING_GETTER_BODY(aFilename, mFilename); -} - -/* readonly attribute uint32_t lineNumber; */ -NS_IMETHODIMP nsXPCException::GetLineNumber(uint32_t *aLineNumber) -{ - if (!aLineNumber) - return NS_ERROR_NULL_POINTER; - if (!mInitialized) - return NS_ERROR_NOT_INITIALIZED; - *aLineNumber = mLineNumber; - return NS_OK; -} - -/* readonly attribute uint32_t columnNumber; */ -NS_IMETHODIMP nsXPCException::GetColumnNumber(uint32_t *aColumnNumber) -{ - NS_ENSURE_ARG_POINTER(aColumnNumber); - if (!mInitialized) - return NS_ERROR_NOT_INITIALIZED; - *aColumnNumber = 0; - return NS_OK; -} - -/* readonly attribute nsIStackFrame location; */ -NS_IMETHODIMP -nsXPCException::GetLocation(nsIStackFrame * *aLocation) -{ - if (!aLocation) - return NS_ERROR_NULL_POINTER; - if (!mInitialized) - return NS_ERROR_NOT_INITIALIZED; - *aLocation = mLocation; - NS_IF_ADDREF(mLocation); - return NS_OK; -} - -/* readonly attribute nsISupports data; */ -NS_IMETHODIMP -nsXPCException::GetData(nsISupports * *aData) -{ - if (!aData) - return NS_ERROR_NULL_POINTER; - if (!mInitialized) - return NS_ERROR_NOT_INITIALIZED; - *aData = mData; - NS_IF_ADDREF(mData); - return NS_OK; -} - -/* readonly attribute nsIException inner; */ -NS_IMETHODIMP -nsXPCException::GetInner(nsIException* *aException) -{ - if (!aException) - return NS_ERROR_NULL_POINTER; - if (!mInitialized) - return NS_ERROR_NOT_INITIALIZED; - *aException = mInner; - NS_IF_ADDREF(mInner); - return NS_OK; -} - -/* void initialize (in string aMessage, in nsresult aResult, in string aName, in nsIStackFrame aLocation, in nsISupports aData, in nsIException aInner); */ -NS_IMETHODIMP -nsXPCException::Initialize(const char *aMessage, nsresult aResult, const char *aName, nsIStackFrame *aLocation, nsISupports *aData, nsIException *aInner) -{ - if (mInitialized) - return NS_ERROR_ALREADY_INITIALIZED; - - Reset(); - - if (aMessage) { - if (!(mMessage = (char*) nsMemory::Clone(aMessage, - sizeof(char)*(strlen(aMessage)+1)))) - return NS_ERROR_OUT_OF_MEMORY; - } - - if (aName) { - if (!(mName = (char*) nsMemory::Clone(aName, - sizeof(char)*(strlen(aName)+1)))) - return NS_ERROR_OUT_OF_MEMORY; - } - - mResult = aResult; - - if (aLocation) { - mLocation = aLocation; - NS_ADDREF(mLocation); - // For now, fill in our location details from our stack frame. - // Later we may allow other locations? - nsresult rc; - if (NS_FAILED(rc = aLocation->GetFilename(&mFilename))) - return rc; - if (NS_FAILED(rc = aLocation->GetLineNumber(&mLineNumber))) - return rc; - } else { - nsresult rv; - nsXPConnect* xpc = nsXPConnect::XPConnect(); - rv = xpc->GetCurrentJSStack(&mLocation); - if (NS_FAILED(rv)) - return rv; - } - - if (aData) { - mData = aData; - NS_ADDREF(mData); - } - if (aInner) { - mInner = aInner; - NS_ADDREF(mInner); - } - - mInitialized = true; - return NS_OK; -} - -/* string toString (); */ -NS_IMETHODIMP -nsXPCException::ToString(char **_retval) -{ - if (!_retval) - return NS_ERROR_NULL_POINTER; - if (!mInitialized) - return NS_ERROR_NOT_INITIALIZED; - - static const char defaultMsg[] = ""; - static const char defaultLocation[] = ""; - static const char format[] = - "[Exception... \"%s\" nsresult: \"0x%x (%s)\" location: \"%s\" data: %s]"; - - char* indicatedLocation = nullptr; - - if (mLocation) { - // we need to free this if it does not fail - nsresult rv = mLocation->ToString(&indicatedLocation); - if (NS_FAILED(rv)) - return rv; - } - - const char* msg = mMessage ? mMessage : nullptr; - const char* location = indicatedLocation ? - indicatedLocation : defaultLocation; - const char* resultName = mName; - if (!resultName && !NameAndFormatForNSResult(mResult, &resultName, - (!msg) ? &msg : nullptr)) { - if (!msg) - msg = defaultMsg; - resultName = ""; - } - const char* data = mData ? "yes" : "no"; - - char* temp = JS_smprintf(format, msg, mResult, resultName, location, data); - if (indicatedLocation) - nsMemory::Free(indicatedLocation); - - char* final = nullptr; - if (temp) { - 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; -} - -JSObject* -nsXPCException::WrapObject(JSContext* cx, JS::Handle scope) -{ - return ExceptionBinding::Wrap(cx, scope, this); -} - -void -nsXPCException::GetMessageMoz(nsString& retval) -{ - char* str = nullptr; -#ifdef DEBUG - DebugOnly rv = -#endif - GetMessageMoz(&str); - MOZ_ASSERT(NS_SUCCEEDED(rv)); - CopyUTF8toUTF16(str, retval); - nsMemory::Free(str); -} - -uint32_t -nsXPCException::Result() const -{ - return (uint32_t)mResult; -} - -void -nsXPCException::GetName(nsString& retval) -{ - char* str = nullptr; -#ifdef DEBUG - DebugOnly rv = -#endif - GetName(&str); - MOZ_ASSERT(NS_SUCCEEDED(rv)); - CopyUTF8toUTF16(str, retval); - nsMemory::Free(str); -} - -void -nsXPCException::GetFilename(nsString& retval) -{ - char* str = nullptr; -#ifdef DEBUG - DebugOnly 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; -} - -already_AddRefed -nsXPCException::GetLocation() const -{ - nsCOMPtr location = mLocation; - return location.forget(); -} - -already_AddRefed -nsXPCException::GetInner() const -{ - nsCOMPtr inner = mInner; - return inner.forget(); -} - -already_AddRefed -nsXPCException::GetData() const -{ - nsCOMPtr data = mData; - return data.forget(); -} - -void -nsXPCException::Stringify(nsString& retval) -{ - char* str = nullptr; -#ifdef DEBUG - DebugOnly rv = -#endif - ToString(&str); - MOZ_ASSERT(NS_SUCCEEDED(rv)); - CopyUTF8toUTF16(str, retval); - nsMemory::Free(str); -} - -bool nsXPCException::sEverMadeOneFromFactory = false; diff --git a/js/xpconnect/src/XPCForwards.h b/js/xpconnect/src/XPCForwards.h index 08b36c9c393..769a6b6d34b 100644 --- a/js/xpconnect/src/XPCForwards.h +++ b/js/xpconnect/src/XPCForwards.h @@ -17,7 +17,6 @@ class XPCContext; class XPCCallContext; class XPCJSThrower; -class XPCJSStack; class nsXPCWrappedJS; class nsXPCWrappedJSClass; diff --git a/js/xpconnect/src/XPCJSRuntime.cpp b/js/xpconnect/src/XPCJSRuntime.cpp index 334b62396ab..4d9f8b6c345 100644 --- a/js/xpconnect/src/XPCJSRuntime.cpp +++ b/js/xpconnect/src/XPCJSRuntime.cpp @@ -1393,6 +1393,10 @@ void XPCJSRuntime::SystemIsBeingShutDown() XPCJSRuntime::~XPCJSRuntime() { + // Clear any pending exception. It might be an XPCWrappedJS, and if we try + // to destroy it later we will crash. + SetPendingException(nullptr); + JS::SetGCSliceCallback(Runtime(), mPrevGCSliceCallback); xpc_DelocalizeRuntime(Runtime()); diff --git a/js/xpconnect/src/XPCModule.h b/js/xpconnect/src/XPCModule.h index e411c4be352..b771351471d 100644 --- a/js/xpconnect/src/XPCModule.h +++ b/js/xpconnect/src/XPCModule.h @@ -21,7 +21,6 @@ #define MOZJSSUBSCRIPTLOADER_CONTRACTID "@mozilla.org/moz/jssubscript-loader;1" NS_GENERIC_FACTORY_CONSTRUCTOR(nsJSID) -NS_GENERIC_FACTORY_CONSTRUCTOR(nsXPCException) NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsIXPConnect, nsXPConnect::GetSingleton) NS_GENERIC_FACTORY_CONSTRUCTOR(nsScriptError) @@ -39,7 +38,6 @@ NS_DEFINE_NAMED_CID(MOZ_JSSUBSCRIPTLOADER_CID); #define XPCONNECT_CIDENTRIES \ { &kNS_JS_ID_CID, false, NULL, nsJSIDConstructor }, \ { &kNS_XPCONNECT_CID, false, NULL, nsIXPConnectConstructor }, \ - { &kNS_XPCEXCEPTION_CID, false, NULL, nsXPCExceptionConstructor }, \ { &kNS_SCRIPTERROR_CID, false, NULL, nsScriptErrorConstructor }, \ { &kMOZJSCOMPONENTLOADER_CID, false, NULL, mozJSComponentLoaderConstructor },\ { &kMOZ_JSSUBSCRIPTLOADER_CID, false, NULL, mozJSSubScriptLoaderConstructor }, @@ -49,7 +47,6 @@ NS_DEFINE_NAMED_CID(MOZ_JSSUBSCRIPTLOADER_CID); { XPC_XPCONNECT_CONTRACTID, &kNS_XPCONNECT_CID }, \ { XPC_CONTEXT_STACK_CONTRACTID, &kNS_XPCONNECT_CID }, \ { XPC_RUNTIME_CONTRACTID, &kNS_XPCONNECT_CID }, \ - { XPC_EXCEPTION_CONTRACTID, &kNS_XPCEXCEPTION_CID }, \ { NS_SCRIPTERROR_CONTRACTID, &kNS_SCRIPTERROR_CID }, \ { MOZJSCOMPONENTLOADER_CONTRACTID, &kMOZJSCOMPONENTLOADER_CID }, \ { MOZJSSUBSCRIPTLOADER_CONTRACTID, &kMOZ_JSSUBSCRIPTLOADER_CID }, diff --git a/js/xpconnect/src/XPCQuickStubs.cpp b/js/xpconnect/src/XPCQuickStubs.cpp index 7d3ddb528da..c98947794d9 100644 --- a/js/xpconnect/src/XPCQuickStubs.cpp +++ b/js/xpconnect/src/XPCQuickStubs.cpp @@ -13,6 +13,7 @@ #include "XPCInlines.h" #include "XPCQuickStubs.h" #include "mozilla/dom/BindingUtils.h" +#include "mozilla/dom/Exceptions.h" using namespace mozilla; using namespace JS; @@ -250,7 +251,7 @@ ThrowCallFailed(JSContext *cx, nsresult rv, format, rv, ifaceName, memberName); } - XPCThrower::BuildAndThrowException(cx, rv, sz); + dom::Throw(cx, rv, sz); if (sz) JS_smprintf_free(sz); @@ -336,7 +337,7 @@ ThrowBadArg(JSContext *cx, nsresult rv, const char *ifaceName, sz = JS_smprintf("%s arg %u [%s.%s]", format, (unsigned int) paramnum, ifaceName, memberName); - XPCThrower::BuildAndThrowException(cx, rv, sz); + dom::Throw(cx, rv, sz); if (sz) JS_smprintf_free(sz); diff --git a/js/xpconnect/src/XPCStack.cpp b/js/xpconnect/src/XPCStack.cpp deleted file mode 100644 index 6c07e8b3e87..00000000000 --- a/js/xpconnect/src/XPCStack.cpp +++ /dev/null @@ -1,268 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * - * 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/. */ - -/* Implements nsIStackFrame. */ - -#include "xpcprivate.h" -#include "jsprf.h" -#include "js/OldDebugAPI.h" - -class XPCJSStackFrame : public nsIStackFrame -{ -public: - NS_DECL_THREADSAFE_ISUPPORTS - NS_DECL_NSISTACKFRAME - - static nsresult CreateStack(JSContext* cx, XPCJSStackFrame** stack); - - static nsresult CreateStackFrameLocation(uint32_t aLanguage, - const char* aFilename, - const char* aFunctionName, - int32_t aLineNumber, - nsIStackFrame* aCaller, - XPCJSStackFrame** stack); - - XPCJSStackFrame(); - virtual ~XPCJSStackFrame(); - - bool IsJSFrame() const - {return mLanguage == nsIProgrammingLanguage::JAVASCRIPT;} - -private: - nsCOMPtr mCaller; - - char* mFilename; - char* mFunname; - int32_t mLineno; - uint32_t mLanguage; -}; - -/**********************************************/ - -// static - -nsresult -XPCJSStack::CreateStack(JSContext* cx, nsIStackFrame** stack) -{ - if (!cx) - return NS_ERROR_FAILURE; - - return XPCJSStackFrame::CreateStack(cx, (XPCJSStackFrame**) stack); -} - -// static -nsresult -XPCJSStack::CreateStackFrameLocation(uint32_t aLanguage, - const char* aFilename, - const char* aFunctionName, - int32_t aLineNumber, - nsIStackFrame* aCaller, - nsIStackFrame** stack) -{ - return XPCJSStackFrame::CreateStackFrameLocation(aLanguage, - aFilename, - aFunctionName, - aLineNumber, - aCaller, - (XPCJSStackFrame**) stack); -} - - -/**********************************************/ - -XPCJSStackFrame::XPCJSStackFrame() - : mFilename(nullptr), - mFunname(nullptr), - mLineno(0), - mLanguage(nsIProgrammingLanguage::UNKNOWN) -{ -} - -XPCJSStackFrame::~XPCJSStackFrame() -{ - if (mFilename) - nsMemory::Free(mFilename); - if (mFunname) - nsMemory::Free(mFunname); -} - -NS_IMPL_ISUPPORTS1(XPCJSStackFrame, nsIStackFrame) - -nsresult -XPCJSStackFrame::CreateStack(JSContext* cx, XPCJSStackFrame** stack) -{ - static const unsigned MAX_FRAMES = 100; - - nsRefPtr first = new XPCJSStackFrame(); - nsRefPtr self = first; - - JS::StackDescription* desc = JS::DescribeStack(cx, MAX_FRAMES); - if (!desc) - return NS_ERROR_FAILURE; - - for (size_t i = 0; i < desc->nframes && self; i++) { - self->mLanguage = nsIProgrammingLanguage::JAVASCRIPT; - - JSAutoCompartment ac(cx, desc->frames[i].script); - const char* filename = JS_GetScriptFilename(cx, desc->frames[i].script); - if (filename) { - self->mFilename = (char*) - nsMemory::Clone(filename, - sizeof(char)*(strlen(filename)+1)); - } - - self->mLineno = desc->frames[i].lineno; - - JSFunction* fun = desc->frames[i].fun; - if (fun) { - JS::RootedString funid(cx, JS_GetFunctionDisplayId(fun)); - if (funid) { - size_t length = JS_GetStringEncodingLength(cx, funid); - if (length != size_t(-1)) { - self->mFunname = static_cast(nsMemory::Alloc(length + 1)); - if (self->mFunname) { - JS_EncodeStringToBuffer(cx, funid, self->mFunname, length); - self->mFunname[length] = '\0'; - } - } - } - } - - XPCJSStackFrame* frame = new XPCJSStackFrame(); - self->mCaller = frame; - self = frame; - } - - JS::FreeStackDescription(cx, desc); - - *stack = first.forget().get(); - return NS_OK; -} - -// static -nsresult -XPCJSStackFrame::CreateStackFrameLocation(uint32_t aLanguage, - const char* aFilename, - const char* aFunctionName, - int32_t aLineNumber, - nsIStackFrame* aCaller, - XPCJSStackFrame** stack) -{ - bool failed = false; - XPCJSStackFrame* self = new XPCJSStackFrame(); - if (self) - NS_ADDREF(self); - else - failed = true; - - if (!failed) { - self->mLanguage = aLanguage; - self->mLineno = aLineNumber; - } - - if (!failed && aFilename) { - self->mFilename = (char*) - nsMemory::Clone(aFilename, - sizeof(char)*(strlen(aFilename)+1)); - if (!self->mFilename) - failed = true; - } - - if (!failed && aFunctionName) { - self->mFunname = (char*) - nsMemory::Clone(aFunctionName, - sizeof(char)*(strlen(aFunctionName)+1)); - if (!self->mFunname) - failed = true; - } - - if (!failed && aCaller) { - self->mCaller = aCaller; - } - - if (failed && self) { - NS_RELEASE(self); // sets self to nullptr - } - - *stack = self; - return self ? NS_OK : NS_ERROR_OUT_OF_MEMORY; -} - -/* readonly attribute uint32_t language; */ -NS_IMETHODIMP XPCJSStackFrame::GetLanguage(uint32_t *aLanguage) -{ - *aLanguage = mLanguage; - return NS_OK; -} - -/* readonly attribute string languageName; */ -NS_IMETHODIMP XPCJSStackFrame::GetLanguageName(char * *aLanguageName) -{ - static const char js[] = "JavaScript"; - static const char cpp[] = "C++"; - char* temp; - - if (IsJSFrame()) - *aLanguageName = temp = (char*) nsMemory::Clone(js, sizeof(js)); - else - *aLanguageName = temp = (char*) nsMemory::Clone(cpp, sizeof(cpp)); - - return temp ? NS_OK : NS_ERROR_OUT_OF_MEMORY; -} - -/* readonly attribute string filename; */ -NS_IMETHODIMP XPCJSStackFrame::GetFilename(char * *aFilename) -{ - XPC_STRING_GETTER_BODY(aFilename, mFilename); -} - -/* readonly attribute string name; */ -NS_IMETHODIMP XPCJSStackFrame::GetName(char * *aFunction) -{ - XPC_STRING_GETTER_BODY(aFunction, mFunname); -} - -/* readonly attribute int32_t lineNumber; */ -NS_IMETHODIMP XPCJSStackFrame::GetLineNumber(int32_t *aLineNumber) -{ - *aLineNumber = mLineno; - return NS_OK; -} - -/* readonly attribute string sourceLine; */ -NS_IMETHODIMP XPCJSStackFrame::GetSourceLine(char * *aSourceLine) -{ - *aSourceLine = nullptr; - return NS_OK; -} - -/* readonly attribute nsIStackFrame caller; */ -NS_IMETHODIMP XPCJSStackFrame::GetCaller(nsIStackFrame * *aCaller) -{ - NS_IF_ADDREF(*aCaller = mCaller); - return NS_OK; -} - -/* string toString (); */ -NS_IMETHODIMP XPCJSStackFrame::ToString(char **_retval) -{ - const char* frametype = IsJSFrame() ? "JS" : "native"; - const char* filename = mFilename ? mFilename : ""; - const char* funname = mFunname ? mFunname : ""; - static const char format[] = "%s frame :: %s :: %s :: line %d"; - int len = sizeof(char)* - (strlen(frametype) + strlen(filename) + strlen(funname)) + - sizeof(format) + 6 /* space for lineno */; - - char* buf = (char*) nsMemory::Alloc(len); - if (!buf) - return NS_ERROR_OUT_OF_MEMORY; - - JS_snprintf(buf, len, format, frametype, filename, funname, mLineno); - *_retval = buf; - return NS_OK; -} - diff --git a/js/xpconnect/src/XPCThrower.cpp b/js/xpconnect/src/XPCThrower.cpp index 1aac4cf5947..200483e13c2 100644 --- a/js/xpconnect/src/XPCThrower.cpp +++ b/js/xpconnect/src/XPCThrower.cpp @@ -10,8 +10,11 @@ #include "xpcpublic.h" #include "XPCWrapper.h" #include "jsprf.h" -#include "nsDOMException.h" #include "mozilla/dom/BindingUtils.h" +#include "mozilla/dom/Exceptions.h" + +using namespace mozilla; +using namespace mozilla::dom; bool XPCThrower::sVerbose = true; @@ -24,7 +27,7 @@ XPCThrower::Throw(nsresult rv, JSContext* cx) return; if (!nsXPCException::NameAndFormatForNSResult(rv, nullptr, &format)) format = ""; - BuildAndThrowException(cx, rv, format); + dom::Throw(cx, rv, format); } namespace xpc { @@ -56,7 +59,7 @@ XPCThrower::CheckForPendingException(nsresult result, JSContext *cx) if (NS_FAILED(e->GetResult(&e_result)) || e_result != result) return false; - if (!ThrowExceptionObject(cx, static_cast(e.get()))) + if (!ThrowExceptionObject(cx, e)) JS_ReportOutOfMemory(cx); return true; } @@ -79,7 +82,7 @@ XPCThrower::Throw(nsresult rv, XPCCallContext& ccx) if (sz && sVerbose) Verbosify(ccx, &sz, false); - BuildAndThrowException(ccx, rv, sz); + dom::Throw(ccx, rv, sz); if (sz && sz != format) JS_smprintf_free(sz); @@ -117,7 +120,7 @@ XPCThrower::ThrowBadResult(nsresult rv, nsresult result, XPCCallContext& ccx) if (sz && sVerbose) Verbosify(ccx, &sz, true); - BuildAndThrowException(ccx, result, sz); + dom::Throw(ccx, result, sz); if (sz) JS_smprintf_free(sz); @@ -138,7 +141,7 @@ XPCThrower::ThrowBadParam(nsresult rv, unsigned paramNum, XPCCallContext& ccx) if (sz && sVerbose) Verbosify(ccx, &sz, true); - BuildAndThrowException(ccx, rv, sz); + dom::Throw(ccx, rv, sz); if (sz) JS_smprintf_free(sz); @@ -169,104 +172,3 @@ XPCThrower::Verbosify(XPCCallContext& ccx, *psz = sz; } } - -// static -void -XPCThrower::BuildAndThrowException(JSContext* cx, nsresult rv, const char* sz) -{ - bool success = false; - - /* no need to set an expection if the security manager already has */ - if (rv == NS_ERROR_XPC_SECURITY_MANAGER_VETO && JS_IsExceptionPending(cx)) - return; - - XPCJSRuntime* runtime = XPCJSRuntime::Get(); - nsCOMPtr existingException = runtime->GetPendingException(); - if (existingException) { - nsresult nr; - if (NS_SUCCEEDED(existingException->GetResult(&nr)) && - rv == nr) { - // Just reuse the existing exception. - return; - } - } - - nsRefPtr 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()) { - finalException = NS_NewDOMException(rv); - } - break; - - default: - break; - } - - // If not, use the default. - if (finalException == nullptr) { - 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); - } -} - -static bool -IsCallerChrome(JSContext* cx) -{ - nsresult rv; - - nsCOMPtr secMan; - secMan = XPCWrapper::GetSecurityManager(); - - if (!secMan) - return false; - - bool isChrome; - rv = secMan->SubjectPrincipalIsSystem(&isChrome); - return NS_SUCCEEDED(rv) && isChrome; -} - -// static -bool -XPCThrower::ThrowExceptionObject(JSContext* cx, nsXPCException* e) -{ - bool success = false; - if (e) { - JS::RootedValue thrown(cx); - - // 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) && - NS_SUCCEEDED(e->StealJSVal(thrown.address()))) { - if (!JS_WrapValue(cx, thrown.address())) - return false; - JS_SetPendingException(cx, thrown); - success = true; - } else { - JS::RootedObject glob(cx, JS::CurrentGlobalOrNull(cx)); - if (!glob) - return false; - - JS::RootedValue val(cx); - if (mozilla::dom::WrapNewBindingObject(cx, glob, e, &val)) { - JS_SetPendingException(cx, val); - success = true; - } - } - } - return success; -} diff --git a/js/xpconnect/src/XPCWrappedJSClass.cpp b/js/xpconnect/src/XPCWrappedJSClass.cpp index dd59eec2c1e..1667bc2b304 100644 --- a/js/xpconnect/src/XPCWrappedJSClass.cpp +++ b/js/xpconnect/src/XPCWrappedJSClass.cpp @@ -17,6 +17,7 @@ #include "nsJSUtils.h" #include "mozilla/Attributes.h" #include "mozilla/dom/BindingUtils.h" +#include "mozilla/dom/DOMException.h" #include "mozilla/dom/DOMExceptionBinding.h" #include "jsapi.h" @@ -264,7 +265,7 @@ nsXPCWrappedJSClass::CallQueryInterfaceOnJSObject(JSContext* cx, // XPConnect may have constructed an object to represent a // C++ QI failure. See if that is the case. using namespace mozilla::dom; - nsXPCException *e = nullptr; + Exception *e = nullptr; UNWRAP_OBJECT(Exception, cx, &jsexception.toObject(), e); if (e && diff --git a/js/xpconnect/src/moz.build b/js/xpconnect/src/moz.build index 5d6ff8bd59c..0bcce0d68cf 100644 --- a/js/xpconnect/src/moz.build +++ b/js/xpconnect/src/moz.build @@ -34,7 +34,6 @@ CPP_SOURCES += [ 'XPCModule.cpp', 'XPCQuickStubs.cpp', 'XPCRuntimeService.cpp', - 'XPCStack.cpp', 'XPCString.cpp', 'XPCThrower.cpp', 'XPCVariant.cpp', diff --git a/js/xpconnect/src/nsXPConnect.cpp b/js/xpconnect/src/nsXPConnect.cpp index 6cfb20410a2..c47168b1b01 100644 --- a/js/xpconnect/src/nsXPConnect.cpp +++ b/js/xpconnect/src/nsXPConnect.cpp @@ -36,6 +36,7 @@ #include "XPCQuickStubs.h" #include "mozilla/dom/BindingUtils.h" +#include "mozilla/dom/Exceptions.h" #include "mozilla/dom/IDBIndexBinding.h" #include "mozilla/dom/IDBObjectStoreBinding.h" #include "mozilla/dom/IDBOpenDBRequestBinding.h" @@ -863,12 +864,14 @@ nsXPConnect::CreateStackFrameLocation(uint32_t aLanguage, { MOZ_ASSERT(_retval, "bad param"); - return XPCJSStack::CreateStackFrameLocation(aLanguage, - aFilename, - aFunctionName, - aLineNumber, - aCaller, - _retval); + nsCOMPtr stackFrame = + exceptions::CreateStackFrameLocation(aLanguage, + aFilename, + aFunctionName, + aLineNumber, + aCaller); + stackFrame.forget(_retval); + return NS_OK; } /* readonly attribute nsIStackFrame CurrentJSStack; */ @@ -880,8 +883,7 @@ nsXPConnect::GetCurrentJSStack(nsIStackFrame * *aCurrentJSStack) // is there a current context available? if (JSContext *cx = GetCurrentJSContext()) { - nsCOMPtr stack; - XPCJSStack::CreateStack(cx, getter_AddRefs(stack)); + nsCOMPtr stack = exceptions::CreateStack(cx); if (stack) { // peel off native frames... uint32_t language; diff --git a/js/xpconnect/src/xpcprivate.h b/js/xpconnect/src/xpcprivate.h index 3082e559ea7..34f65cc978b 100644 --- a/js/xpconnect/src/xpcprivate.h +++ b/js/xpconnect/src/xpcprivate.h @@ -739,17 +739,6 @@ public: ~XPCJSRuntime(); - already_AddRefed GetPendingException() - { - nsCOMPtr out = mPendingException; - return out.forget(); - } - - void SetPendingException(nsIException* aException) - { - mPendingException = aException; - } - XPCReadableJSStringWrapper *NewStringWrapper(const PRUnichar *str, uint32_t len); void DeleteString(nsAString *string); @@ -831,8 +820,6 @@ private: mozilla::TimeStamp mSlowScriptCheckpoint; - nsCOMPtr mPendingException; - #define XPCCCX_STRING_CACHE_SIZE 2 // String wrapper entry, holds a string, and a boolean that tells @@ -2943,54 +2930,21 @@ public: static bool SetVerbosity(bool state) {bool old = sVerbose; sVerbose = state; return old;} - 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, nsXPCException* e); - private: static bool sVerbose; }; - /***************************************************************************/ -class XPCJSStack +class nsXPCException { public: - static nsresult - CreateStack(JSContext* cx, nsIStackFrame** stack); - - static nsresult - CreateStackFrameLocation(uint32_t aLanguage, - const char* aFilename, - const char* aFunctionName, - int32_t aLineNumber, - nsIStackFrame* aCaller, - nsIStackFrame** stack); -private: - XPCJSStack(); // not implemented -}; - -/***************************************************************************/ - -class nsXPCException : - public nsIXPCException, - public nsWrapperCache -{ -public: - NS_DEFINE_STATIC_CID_ACCESSOR(NS_XPCEXCEPTION_CID) - - NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsXPCException) - - NS_DECL_CYCLE_COLLECTING_ISUPPORTS - NS_DECL_NSIEXCEPTION - NS_DECL_NSIXPCEXCEPTION - static bool NameAndFormatForNSResult(nsresult rv, const char** name, const char** format); @@ -3001,58 +2955,6 @@ public: 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(); - - virtual JSObject* WrapObject(JSContext* cx, JS::Handle 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 GetLocation() const; - - already_AddRefed GetInner() const; - - already_AddRefed GetData() const; - - void Stringify(nsString& retval); - -protected: - void Reset(); - - char* mMessage; - nsresult mResult; - char* mName; - nsIStackFrame* mLocation; - nsISupports* mData; - char* mFilename; - int mLineNumber; - nsIException* mInner; - bool mInitialized; - - nsAutoJSValHolder mThrownJSVal; - -private: - static bool sEverMadeOneFromFactory; }; /***************************************************************************/ diff --git a/layout/build/nsLayoutModule.cpp b/layout/build/nsLayoutModule.cpp index 6278d4b8352..ddf3dada2ef 100644 --- a/layout/build/nsLayoutModule.cpp +++ b/layout/build/nsLayoutModule.cpp @@ -68,7 +68,6 @@ // DOM includes #include "nsDOMBlobBuilder.h" -#include "nsDOMException.h" #include "nsDOMFileReader.h" #include "nsFormData.h" @@ -85,6 +84,7 @@ #include "mozIApplicationClearPrivateDataParams.h" #include "mozilla/Attributes.h" #include "mozilla/dom/Activity.h" +#include "mozilla/dom/DOMException.h" #include "mozilla/dom/DOMRequest.h" #include "mozilla/dom/EventSource.h" #include "mozilla/dom/indexedDB/IndexedDatabaseManager.h" @@ -275,6 +275,7 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsMediaSourceProtocolHandler) NS_GENERIC_FACTORY_CONSTRUCTOR(nsFontTableProtocolHandler) NS_GENERIC_FACTORY_CONSTRUCTOR(nsHostObjectURI) NS_GENERIC_FACTORY_CONSTRUCTOR(DOMParser) +NS_GENERIC_FACTORY_CONSTRUCTOR(Exception) NS_GENERIC_FACTORY_CONSTRUCTOR(DOMSessionStorageManager) NS_GENERIC_FACTORY_CONSTRUCTOR(DOMLocalStorageManager) NS_GENERIC_FACTORY_CONSTRUCTOR(nsChannelPolicy) @@ -1027,6 +1028,7 @@ static const mozilla::Module::CIDEntry kLayoutCIDs[] = { { &kNS_EVENTSOURCE_CID, false, NULL, EventSourceConstructor }, { &kNS_DOMACTIVITY_CID, false, NULL, ActivityConstructor }, { &kNS_DOMPARSER_CID, false, NULL, DOMParserConstructor }, + { &kNS_XPCEXCEPTION_CID, false, NULL, ExceptionConstructor }, { &kNS_DOMSESSIONSTORAGEMANAGER_CID, false, NULL, DOMSessionStorageManagerConstructor }, { &kNS_DOMLOCALSTORAGEMANAGER_CID, false, NULL, DOMLocalStorageManagerConstructor }, { &kNS_DOMJSON_CID, false, NULL, NS_NewJSON }, @@ -1181,6 +1183,7 @@ static const mozilla::Module::ContractIDEntry kLayoutContracts[] = { { NS_EVENTSOURCE_CONTRACTID, &kNS_EVENTSOURCE_CID }, { NS_DOMACTIVITY_CONTRACTID, &kNS_DOMACTIVITY_CID }, { NS_DOMPARSER_CONTRACTID, &kNS_DOMPARSER_CID }, + { XPC_EXCEPTION_CONTRACTID, &kNS_XPCEXCEPTION_CID }, { "@mozilla.org/dom/localStorage-manager;1", &kNS_DOMLOCALSTORAGEMANAGER_CID }, // Keeping the old ContractID for backward compatibility { "@mozilla.org/dom/storagemanager;1", &kNS_DOMLOCALSTORAGEMANAGER_CID }, diff --git a/xpcom/base/CycleCollectedJSRuntime.cpp b/xpcom/base/CycleCollectedJSRuntime.cpp index ea74eba3700..13245d2acfd 100644 --- a/xpcom/base/CycleCollectedJSRuntime.cpp +++ b/xpcom/base/CycleCollectedJSRuntime.cpp @@ -64,6 +64,7 @@ #include "nsCycleCollectionParticipant.h" #include "nsCycleCollector.h" #include "nsDOMJSUtils.h" +#include "nsIException.h" #include "nsThreadUtils.h" #include "xpcpublic.h" @@ -463,6 +464,9 @@ CycleCollectedJSRuntime::~CycleCollectedJSRuntime() MOZ_ASSERT(!mDeferredFinalizerTable.Count()); MOZ_ASSERT(!mDeferredSupports.Length()); + // Clear mPendingException first, since it might be cycle collected. + mPendingException = nullptr; + nsCycleCollector_forgetJSRuntime(); JS_DestroyRuntime(mJSRuntime); @@ -828,6 +832,19 @@ CycleCollectedJSRuntime::AssertNoObjectsToTrace(void* aPossibleJSHolder) } #endif +already_AddRefed +CycleCollectedJSRuntime::GetPendingException() const +{ + nsCOMPtr out = mPendingException; + return out.forget(); +} + +void +CycleCollectedJSRuntime::SetPendingException(nsIException* aException) +{ + mPendingException = aException; +} + nsCycleCollectionParticipant* CycleCollectedJSRuntime::GCThingParticipant() { diff --git a/xpcom/base/CycleCollectedJSRuntime.h b/xpcom/base/CycleCollectedJSRuntime.h index 36d3d42c421..230da146761 100644 --- a/xpcom/base/CycleCollectedJSRuntime.h +++ b/xpcom/base/CycleCollectedJSRuntime.h @@ -19,6 +19,7 @@ class nsCycleCollectionNoteRootCallback; class nsScriptObjectTracer; +class nsIException; namespace mozilla { @@ -172,6 +173,9 @@ public: void AssertNoObjectsToTrace(void* aPossibleJSHolder); #endif + already_AddRefed GetPendingException() const; + void SetPendingException(nsIException* aException); + nsCycleCollectionParticipant* GCThingParticipant(); nsCycleCollectionParticipant* ZoneParticipant(); @@ -198,6 +202,12 @@ public: MOZ_ASSERT(mJSRuntime); return mJSRuntime; } + + // Get the current thread's CycleCollectedJSRuntime. Returns null if there + // isn't one. + static CycleCollectedJSRuntime* + Get(); + private: JSGCThingParticipant mGCThingCycleCollectorGlobal; @@ -214,6 +224,8 @@ private: nsRefPtr mFinalizeRunnable; + nsCOMPtr mPendingException; + #ifdef DEBUG void* mObjectToUnlink; #endif diff --git a/xpcom/base/nsCycleCollector.cpp b/xpcom/base/nsCycleCollector.cpp index 91012304dc2..01e1e03ff81 100644 --- a/xpcom/base/nsCycleCollector.cpp +++ b/xpcom/base/nsCycleCollector.cpp @@ -2903,8 +2903,8 @@ nsCycleCollector_forgetJSRuntime() } } -mozilla::CycleCollectedJSRuntime* -nsCycleCollector_currentJSRuntime() +/* static */ CycleCollectedJSRuntime* +CycleCollectedJSRuntime::Get() { CollectorData* data = sCollectorData.get(); if (data) { diff --git a/xpcom/base/nsCycleCollector.h b/xpcom/base/nsCycleCollector.h index 3d2f88625a8..5ee07a53d9d 100644 --- a/xpcom/base/nsCycleCollector.h +++ b/xpcom/base/nsCycleCollector.h @@ -64,7 +64,6 @@ void nsCycleCollector_shutdown(); // Helpers for interacting with JS void nsCycleCollector_registerJSRuntime(mozilla::CycleCollectedJSRuntime *aRt); void nsCycleCollector_forgetJSRuntime(); -mozilla::CycleCollectedJSRuntime* nsCycleCollector_currentJSRuntime(); #define NS_CYCLE_COLLECTOR_LOGGER_CID \ { 0x58be81b4, 0x39d2, 0x437c, \