Bug 911258: Part 4 - Refactor exception implementations. r=bz

This commit is contained in:
Kyle Huey 2013-09-08 20:28:50 -07:00
parent 025c388bda
commit 6a6c67829f
34 changed files with 1419 additions and 1308 deletions

View File

@ -6,9 +6,14 @@
#include "mozilla/dom/DOMError.h" #include "mozilla/dom/DOMError.h"
#include "mozilla/dom/DOMErrorBinding.h" #include "mozilla/dom/DOMErrorBinding.h"
#include "nsDOMException.h"
#include "nsPIDOMWindow.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 mozilla {
namespace dom { namespace dom {

708
dom/base/DOMException.cpp Normal file
View File

@ -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<nsIXPCException> e =
do_CreateInstance(XPC_EXCEPTION_CONTRACTID);
sEverMadeOneFromFactory = true;
}
nsCOMPtr<nsIStackFrame> 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<nsIStackFrame> 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<nsIStackFrame> 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<nsISupports> 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<nsIException> 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[] = "<no message>";
static const char defaultLocation[] = "<unknown>";
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 = "<unknown>";
}
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<JSObject*> scope)
{
return ExceptionBinding::Wrap(cx, scope, this);
}
void
Exception::GetMessageMoz(nsString& retval)
{
char* str = nullptr;
#ifdef DEBUG
DebugOnly<nsresult> 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<nsresult> 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<nsresult> 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<nsIStackFrame>
Exception::GetLocation() const
{
nsCOMPtr<nsIStackFrame> location = mLocation;
return location.forget();
}
already_AddRefed<nsISupports>
Exception::GetInner() const
{
nsCOMPtr<nsIException> inner = mInner;
return inner.forget();
}
already_AddRefed<nsISupports>
Exception::GetData() const
{
nsCOMPtr<nsISupports> data = mData;
return data.forget();
}
void
Exception::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);
}
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<nsIDocument> doc = nsContentUtils::GetDocumentFromCaller();
if (doc) {
doc->WarnOnceAbout(nsIDocument::eDOMExceptionCode);
}
}
return NS_OK;
}
NS_IMETHODIMP
DOMException::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[] =
"[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<JSObject*> aScope)
{
return DOMExceptionBinding::Wrap(aCx, aScope, this);
}
/* static */already_AddRefed<DOMException>
DOMException::Create(nsresult aRv)
{
const char* name;
const char* message;
uint16_t code;
NSResultToNameAndMessage(aRv, &name, &message, &code);
nsRefPtr<DOMException> inst =
new DOMException(aRv, message, name, code);
return inst.forget();
}
} // namespace dom
} // namespace mozilla

161
dom/base/DOMException.h Normal file
View File

@ -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 <stdint.h>
#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<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);
// 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<nsIStackFrame> mLocation;
nsCOMPtr<nsISupports> mData;
char* mFilename;
int mLineNumber;
nsCOMPtr<nsIException> mInner;
bool mInitialized;
bool mHoldingJSVal;
JS::Heap<JS::Value> 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<JSObject*> 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<DOMException>
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

View File

@ -22,7 +22,6 @@ EXPORTS += [
'nsDOMCID.h', 'nsDOMCID.h',
'nsDOMClassInfoClasses.h', 'nsDOMClassInfoClasses.h',
'nsDOMClassInfoID.h', 'nsDOMClassInfoID.h',
'nsDOMException.h',
'nsDOMJSUtils.h', 'nsDOMJSUtils.h',
'nsDOMNavigationTiming.h', 'nsDOMNavigationTiming.h',
'nsDOMString.h', 'nsDOMString.h',
@ -54,6 +53,7 @@ EXPORTS.mozilla.dom += [
'BarProps.h', 'BarProps.h',
'DOMCursor.h', 'DOMCursor.h',
'DOMError.h', 'DOMError.h',
'DOMException.h',
'DOMRequest.h', 'DOMRequest.h',
'MessageChannel.h', 'MessageChannel.h',
'MessagePort.h', 'MessagePort.h',
@ -67,13 +67,13 @@ CPP_SOURCES += [
'Crypto.cpp', 'Crypto.cpp',
'DOMCursor.cpp', 'DOMCursor.cpp',
'DOMError.cpp', 'DOMError.cpp',
'DOMException.cpp',
'DOMRequest.cpp', 'DOMRequest.cpp',
'Navigator.cpp', 'Navigator.cpp',
'MessageChannel.cpp', 'MessageChannel.cpp',
'MessagePort.cpp', 'MessagePort.cpp',
'nsContentPermissionHelper.cpp', 'nsContentPermissionHelper.cpp',
'nsDOMClassInfo.cpp', 'nsDOMClassInfo.cpp',
'nsDOMException.cpp',
'nsDOMNavigationTiming.cpp', 'nsDOMNavigationTiming.cpp',
'nsDOMScriptObjectFactory.cpp', 'nsDOMScriptObjectFactory.cpp',
'nsDOMWindowList.cpp', 'nsDOMWindowList.cpp',

View File

@ -77,7 +77,6 @@
// DOM core includes // DOM core includes
#include "nsError.h" #include "nsError.h"
#include "nsIDOMDOMException.h"
#include "nsIDOMDOMStringList.h" #include "nsIDOMDOMStringList.h"
#include "nsIDOMUserDataHandler.h" #include "nsIDOMUserDataHandler.h"
#include "nsIDOMLoadStatus.h" #include "nsIDOMLoadStatus.h"
@ -338,10 +337,6 @@ static nsDOMClassInfoData sClassInfoData[] = {
nsIXPCScriptable::WANT_CONSTRUCT | nsIXPCScriptable::WANT_CONSTRUCT |
nsIXPCScriptable::DONT_ENUM_QUERY_INTERFACE) nsIXPCScriptable::DONT_ENUM_QUERY_INTERFACE)
// Core classes
NS_DEFINE_CLASSINFO_DATA(DOMException, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
// Misc Core related classes // Misc Core related classes
NS_DEFINE_CLASSINFO_DATA(DeviceAcceleration, nsDOMGenericSH, NS_DEFINE_CLASSINFO_DATA(DeviceAcceleration, nsDOMGenericSH,
@ -1110,11 +1105,6 @@ nsDOMClassInfo::Init()
DOM_CLASSINFO_MAP_ENTRY(nsIDOMDOMConstructor) DOM_CLASSINFO_MAP_ENTRY(nsIDOMDOMConstructor)
DOM_CLASSINFO_MAP_END 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_BEGIN(DeviceAcceleration, nsIDOMDeviceAcceleration)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMDeviceAcceleration) DOM_CLASSINFO_MAP_ENTRY(nsIDOMDeviceAcceleration)
DOM_CLASSINFO_MAP_END DOM_CLASSINFO_MAP_END

View File

@ -9,9 +9,6 @@ DOMCI_CLASS(Location)
DOMCI_CLASS(DOMPrototype) DOMCI_CLASS(DOMPrototype)
DOMCI_CLASS(DOMConstructor) DOMCI_CLASS(DOMConstructor)
// Core classes
DOMCI_CLASS(DOMException)
DOMCI_CLASS(DeviceAcceleration) DOMCI_CLASS(DeviceAcceleration)
DOMCI_CLASS(DeviceRotationRate) DOMCI_CLASS(DeviceRotationRate)

View File

@ -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<nsDOMException>
NS_NewDOMException(nsresult aNSResult)
{
const char* name;
const char* message;
uint16_t code;
NSResultToNameAndMessage(aNSResult, &name, &message, &code);
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;
// 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<nsIDocument> doc = nsContentUtils::GetDocumentFromCaller();
if (doc) {
doc->WarnOnceAbout(nsIDocument::eDOMExceptionCode);
}
}
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[] =
"[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<JSObject*> aScope)
{
return DOMExceptionBinding::Wrap(aCx, aScope, this);
}

View File

@ -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<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);
already_AddRefed<nsDOMException>
NS_NewDOMException(nsresult aNSResult);
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif

View File

@ -24,7 +24,6 @@
#include "nsIObserverService.h" #include "nsIObserverService.h"
#include "nsJSEnvironment.h" #include "nsJSEnvironment.h"
#include "nsGlobalWindow.h" #include "nsGlobalWindow.h"
#include "nsDOMException.h"
#include "nsCRT.h" #include "nsCRT.h"
#ifdef MOZ_XUL #ifdef MOZ_XUL
#include "nsXULPrototypeCache.h" #include "nsXULPrototypeCache.h"

View File

@ -320,7 +320,6 @@ DOMInterfaces = {
}, },
'DOMException': { 'DOMException': {
'nativeType': 'nsDOMException',
'binaryNames': { 'binaryNames': {
'message': 'messageMoz', 'message': 'messageMoz',
}, },
@ -399,8 +398,7 @@ DOMInterfaces = {
}], }],
'Exception': { 'Exception': {
'nativeType': 'nsXPCException', 'headerFile': 'mozilla/dom/DOMException.h',
'headerFile': 'xpcprivate.h',
'binaryNames': { 'binaryNames': {
'message': 'messageMoz', 'message': 'messageMoz',
} }

410
dom/bindings/Exceptions.cpp Normal file
View File

@ -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<nsIScriptSecurityManager> 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> 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<nsIXPConnectJSObjectHolder> 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<nsIException> existingException = runtime->GetPendingException();
if (existingException) {
nsresult nr;
if (NS_SUCCEEDED(existingException->GetResult(&nr)) &&
rv == nr) {
// Just reuse the existing exception.
return;
}
}
nsRefPtr<Exception> 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<nsIStackFrame>
CreateStack(JSContext* cx);
static already_AddRefed<nsIStackFrame>
CreateStackFrameLocation(uint32_t aLanguage,
const char* aFilename,
const char* aFunctionName,
int32_t aLineNumber,
nsIStackFrame* aCaller);
private:
bool IsJSFrame() const {
return mLanguage == nsIProgrammingLanguage::JAVASCRIPT;
}
nsCOMPtr<nsIStackFrame> 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 : "<unknown filename>";
const char* funname = mFunname ? mFunname : "<TOP_LEVEL>";
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<nsIStackFrame>
JSStackFrame::CreateStack(JSContext* cx)
{
static const unsigned MAX_FRAMES = 100;
nsRefPtr<JSStackFrame> first = new JSStackFrame();
nsRefPtr<JSStackFrame> 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<char *>(nsMemory::Alloc(length + 1));
if (self->mFunname) {
JS_EncodeStringToBuffer(cx, funid, self->mFunname, length);
self->mFunname[length] = '\0';
}
}
}
}
nsRefPtr<JSStackFrame> frame = new JSStackFrame();
self->mCaller = frame;
self = frame.forget();
}
JS::FreeStackDescription(cx, desc);
return first.forget();
}
/* static */ already_AddRefed<nsIStackFrame>
JSStackFrame::CreateStackFrameLocation(uint32_t aLanguage,
const char* aFilename,
const char* aFunctionName,
int32_t aLineNumber,
nsIStackFrame* aCaller)
{
nsRefPtr<JSStackFrame> 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<nsIStackFrame>
CreateStack(JSContext* cx)
{
return JSStackFrame::CreateStack(cx);
}
already_AddRefed<nsIStackFrame>
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

50
dom/bindings/Exceptions.h Normal file
View File

@ -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 <stdint.h>
#include "jspubtd.h"
#include "nsIException.h"
class nsIStackFrame;
template <class T>
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<nsIStackFrame>
CreateStack(JSContext* cx);
already_AddRefed<nsIStackFrame>
CreateStackFrameLocation(uint32_t aLanguage,
const char* aFilename,
const char* aFunctionName,
int32_t aLineNumber,
nsIStackFrame* aCaller);
} // namespace exceptions
} // namespace dom
} // namespace mozilla
#endif

View File

@ -60,6 +60,7 @@ CPPSRCS = \
CallbackObject.cpp \ CallbackObject.cpp \
DOMJSProxyHandler.cpp \ DOMJSProxyHandler.cpp \
Date.cpp \ Date.cpp \
Exceptions.cpp \
$(NULL) $(NULL)
endif endif

View File

@ -21,6 +21,7 @@ EXPORTS.mozilla.dom += [
'DOMJSProxyHandler.h', 'DOMJSProxyHandler.h',
'Date.h', 'Date.h',
'Errors.msg', 'Errors.msg',
'Exceptions.h',
'JSSlots.h', 'JSSlots.h',
'NonRefcountedDOMObject.h', 'NonRefcountedDOMObject.h',
'Nullable.h', 'Nullable.h',

View File

@ -1116,7 +1116,7 @@ bool
IsCurrentThreadRunningChromeWorker() IsCurrentThreadRunningChromeWorker()
{ {
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
CycleCollectedJSRuntime* ccrt = nsCycleCollector_currentJSRuntime(); CycleCollectedJSRuntime* ccrt = CycleCollectedJSRuntime::Get();
if (!ccrt) { if (!ccrt) {
return false; return false;
} }

View File

@ -7,14 +7,7 @@
#include "nsISupports.idl" #include "nsISupports.idl"
#include "nsIException.idl" #include "nsIException.idl"
%{ C++ [scriptable, uuid(ce83229c-0a82-4ba4-937b-7fd4cd45f34b)]
#include "js/TypeDecls.h"
%}
[ptr] native xpcexJSContextPtr(JSContext);
native xpcexJSVal(JS::Value);
[scriptable, uuid(cac29630-7bf2-4e22-811b-46855a7d5af0)]
interface nsIXPCException : nsIException interface nsIXPCException : nsIException
{ {
// inherits methods from nsIException // inherits methods from nsIException
@ -25,10 +18,6 @@ interface nsIXPCException : nsIException
in nsIStackFrame aLocation, in nsIStackFrame aLocation,
in nsISupports aData, in nsISupports aData,
in nsIException aInner); in nsIException aInner);
[noscript] xpcexJSVal stealJSVal();
[noscript] void stowJSVal(in xpcexJSContextPtr cx,
in xpcexJSVal val);
}; };
/* this goes into the C++ header verbatim. */ /* this goes into the C++ header verbatim. */

View File

@ -39,12 +39,14 @@
#include "mozilla/XPTInterfaceInfoManager.h" #include "mozilla/XPTInterfaceInfoManager.h"
#include "nsDOMClassInfoID.h" #include "nsDOMClassInfoID.h"
#include "nsGlobalWindow.h" #include "nsGlobalWindow.h"
#include "mozilla/dom/DOMException.h"
#include "mozilla/dom/DOMExceptionBinding.h" #include "mozilla/dom/DOMExceptionBinding.h"
using namespace mozilla; using namespace mozilla;
using namespace JS; using namespace JS;
using namespace js; using namespace js;
using namespace xpc; using namespace xpc;
using mozilla::dom::Exception;
/***************************************************************************/ /***************************************************************************/
// stuff used by all // stuff used by all
@ -1946,7 +1948,7 @@ nsXPCComponents_Exception::CallOrConstruct(nsIXPConnectWrappedNative *wrapper,
// Do the security check if necessary // Do the security check if necessary
nsIXPCSecurityManager* sm = xpc->GetDefaultSecurityManager(); 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. // the security manager vetoed. It should have set an exception.
*_retval = false; *_retval = false;
return NS_OK; return NS_OK;
@ -1957,11 +1959,9 @@ nsXPCComponents_Exception::CallOrConstruct(nsIXPConnectWrappedNative *wrapper,
if (!parser.parse(args)) if (!parser.parse(args))
return ThrowAndFail(NS_ERROR_XPC_BAD_CONVERT_JS, cx, _retval); return ThrowAndFail(NS_ERROR_XPC_BAD_CONVERT_JS, cx, _retval);
nsCOMPtr<nsIException> e = new nsXPCException(parser.eMsg, parser.eResult, nsCOMPtr<nsIException> e = new Exception(parser.eMsg, parser.eResult,
nullptr, parser.eStack, nullptr, parser.eStack,
parser.eData); parser.eData);
if (!e)
return ThrowAndFail(NS_ERROR_XPC_UNEXPECTED, cx, _retval);
nsCOMPtr<nsIXPConnectJSObjectHolder> holder; nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
RootedObject newObj(cx); RootedObject newObj(cx);
@ -1988,7 +1988,7 @@ nsXPCComponents_Exception::HasInstance(nsIXPConnectWrappedNative *wrapper,
RootedValue v(cx, val); RootedValue v(cx, val);
if (bp) { if (bp) {
nsXPCException* e; Exception* e;
*bp = NS_SUCCEEDED(UNWRAP_OBJECT(Exception, cx, v.toObjectOrNull(), e)) || *bp = NS_SUCCEEDED(UNWRAP_OBJECT(Exception, cx, v.toObjectOrNull(), e)) ||
JSValIsInterfaceOfType(cx, v, NS_GET_IID(nsIException)); JSValIsInterfaceOfType(cx, v, NS_GET_IID(nsIException));
} }

View File

@ -27,6 +27,7 @@
#include "JavaScriptParent.h" #include "JavaScriptParent.h"
#include "mozilla/dom/BindingUtils.h" #include "mozilla/dom/BindingUtils.h"
#include "mozilla/dom/DOMException.h"
#include "mozilla/dom/PrimitiveConversions.h" #include "mozilla/dom/PrimitiveConversions.h"
using namespace xpc; using namespace xpc;
@ -1080,14 +1081,14 @@ XPCConvert::ConstructException(nsresult rv, const char* message,
if (ifaceName && methodName) if (ifaceName && methodName)
msg = sz = JS_smprintf(format, msg, ifaceName, methodName); msg = sz = JS_smprintf(format, msg, ifaceName, methodName);
nsCOMPtr<nsIException> e = new nsXPCException(msg, rv, nullptr, nullptr, data); nsRefPtr<Exception> e = new Exception(msg, rv, nullptr, nullptr, data);
if (cx && jsExceptionPtr && *exceptn) { if (cx && jsExceptionPtr) {
nsCOMPtr<nsIXPCException> xpcEx = do_QueryInterface(*exceptn); e->StowJSVal(*jsExceptionPtr);
if (xpcEx)
xpcEx->StowJSVal(cx, *jsExceptionPtr);
} }
e.forget(exceptn);
if (sz) if (sz)
JS_smprintf_free(sz); JS_smprintf_free(sz);
return NS_OK; return NS_OK;

View File

@ -7,12 +7,7 @@
/* An implementaion of nsIException. */ /* An implementaion of nsIException. */
#include "xpcprivate.h" #include "xpcprivate.h"
#include "jsprf.h"
#include "nsError.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 /* Quick and dirty mapping of well known result codes to strings. We only
@ -83,462 +78,3 @@ nsXPCException::GetNSResultCount()
{ {
return RESULT_COUNT; 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<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)
{ }
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[] = "<no message>";
static const char defaultLocation[] = "<unknown>";
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 = "<unknown>";
}
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<JSObject*> scope)
{
return ExceptionBinding::Wrap(cx, scope, this);
}
void
nsXPCException::GetMessageMoz(nsString& retval)
{
char* str = nullptr;
#ifdef DEBUG
DebugOnly<nsresult> 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<nsresult> 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<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;
}
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();
}
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;

View File

@ -17,7 +17,6 @@ class XPCContext;
class XPCCallContext; class XPCCallContext;
class XPCJSThrower; class XPCJSThrower;
class XPCJSStack;
class nsXPCWrappedJS; class nsXPCWrappedJS;
class nsXPCWrappedJSClass; class nsXPCWrappedJSClass;

View File

@ -1393,6 +1393,10 @@ void XPCJSRuntime::SystemIsBeingShutDown()
XPCJSRuntime::~XPCJSRuntime() 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); JS::SetGCSliceCallback(Runtime(), mPrevGCSliceCallback);
xpc_DelocalizeRuntime(Runtime()); xpc_DelocalizeRuntime(Runtime());

View File

@ -21,7 +21,6 @@
#define MOZJSSUBSCRIPTLOADER_CONTRACTID "@mozilla.org/moz/jssubscript-loader;1" #define MOZJSSUBSCRIPTLOADER_CONTRACTID "@mozilla.org/moz/jssubscript-loader;1"
NS_GENERIC_FACTORY_CONSTRUCTOR(nsJSID) NS_GENERIC_FACTORY_CONSTRUCTOR(nsJSID)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsXPCException)
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsIXPConnect, NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsIXPConnect,
nsXPConnect::GetSingleton) nsXPConnect::GetSingleton)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsScriptError) NS_GENERIC_FACTORY_CONSTRUCTOR(nsScriptError)
@ -39,7 +38,6 @@ NS_DEFINE_NAMED_CID(MOZ_JSSUBSCRIPTLOADER_CID);
#define XPCONNECT_CIDENTRIES \ #define XPCONNECT_CIDENTRIES \
{ &kNS_JS_ID_CID, false, NULL, nsJSIDConstructor }, \ { &kNS_JS_ID_CID, false, NULL, nsJSIDConstructor }, \
{ &kNS_XPCONNECT_CID, false, NULL, nsIXPConnectConstructor }, \ { &kNS_XPCONNECT_CID, false, NULL, nsIXPConnectConstructor }, \
{ &kNS_XPCEXCEPTION_CID, false, NULL, nsXPCExceptionConstructor }, \
{ &kNS_SCRIPTERROR_CID, false, NULL, nsScriptErrorConstructor }, \ { &kNS_SCRIPTERROR_CID, false, NULL, nsScriptErrorConstructor }, \
{ &kMOZJSCOMPONENTLOADER_CID, false, NULL, mozJSComponentLoaderConstructor },\ { &kMOZJSCOMPONENTLOADER_CID, false, NULL, mozJSComponentLoaderConstructor },\
{ &kMOZ_JSSUBSCRIPTLOADER_CID, false, NULL, mozJSSubScriptLoaderConstructor }, { &kMOZ_JSSUBSCRIPTLOADER_CID, false, NULL, mozJSSubScriptLoaderConstructor },
@ -49,7 +47,6 @@ NS_DEFINE_NAMED_CID(MOZ_JSSUBSCRIPTLOADER_CID);
{ XPC_XPCONNECT_CONTRACTID, &kNS_XPCONNECT_CID }, \ { XPC_XPCONNECT_CONTRACTID, &kNS_XPCONNECT_CID }, \
{ XPC_CONTEXT_STACK_CONTRACTID, &kNS_XPCONNECT_CID }, \ { XPC_CONTEXT_STACK_CONTRACTID, &kNS_XPCONNECT_CID }, \
{ XPC_RUNTIME_CONTRACTID, &kNS_XPCONNECT_CID }, \ { XPC_RUNTIME_CONTRACTID, &kNS_XPCONNECT_CID }, \
{ XPC_EXCEPTION_CONTRACTID, &kNS_XPCEXCEPTION_CID }, \
{ NS_SCRIPTERROR_CONTRACTID, &kNS_SCRIPTERROR_CID }, \ { NS_SCRIPTERROR_CONTRACTID, &kNS_SCRIPTERROR_CID }, \
{ MOZJSCOMPONENTLOADER_CONTRACTID, &kMOZJSCOMPONENTLOADER_CID }, \ { MOZJSCOMPONENTLOADER_CONTRACTID, &kMOZJSCOMPONENTLOADER_CID }, \
{ MOZJSSUBSCRIPTLOADER_CONTRACTID, &kMOZ_JSSUBSCRIPTLOADER_CID }, { MOZJSSUBSCRIPTLOADER_CONTRACTID, &kMOZ_JSSUBSCRIPTLOADER_CID },

View File

@ -13,6 +13,7 @@
#include "XPCInlines.h" #include "XPCInlines.h"
#include "XPCQuickStubs.h" #include "XPCQuickStubs.h"
#include "mozilla/dom/BindingUtils.h" #include "mozilla/dom/BindingUtils.h"
#include "mozilla/dom/Exceptions.h"
using namespace mozilla; using namespace mozilla;
using namespace JS; using namespace JS;
@ -250,7 +251,7 @@ ThrowCallFailed(JSContext *cx, nsresult rv,
format, rv, ifaceName, memberName); format, rv, ifaceName, memberName);
} }
XPCThrower::BuildAndThrowException(cx, rv, sz); dom::Throw(cx, rv, sz);
if (sz) if (sz)
JS_smprintf_free(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]", sz = JS_smprintf("%s arg %u [%s.%s]",
format, (unsigned int) paramnum, ifaceName, memberName); format, (unsigned int) paramnum, ifaceName, memberName);
XPCThrower::BuildAndThrowException(cx, rv, sz); dom::Throw(cx, rv, sz);
if (sz) if (sz)
JS_smprintf_free(sz); JS_smprintf_free(sz);

View File

@ -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<nsIStackFrame> 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<XPCJSStackFrame> first = new XPCJSStackFrame();
nsRefPtr<XPCJSStackFrame> 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<char *>(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 : "<unknown filename>";
const char* funname = mFunname ? mFunname : "<TOP_LEVEL>";
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;
}

View File

@ -10,8 +10,11 @@
#include "xpcpublic.h" #include "xpcpublic.h"
#include "XPCWrapper.h" #include "XPCWrapper.h"
#include "jsprf.h" #include "jsprf.h"
#include "nsDOMException.h"
#include "mozilla/dom/BindingUtils.h" #include "mozilla/dom/BindingUtils.h"
#include "mozilla/dom/Exceptions.h"
using namespace mozilla;
using namespace mozilla::dom;
bool XPCThrower::sVerbose = true; bool XPCThrower::sVerbose = true;
@ -24,7 +27,7 @@ XPCThrower::Throw(nsresult rv, JSContext* cx)
return; return;
if (!nsXPCException::NameAndFormatForNSResult(rv, nullptr, &format)) if (!nsXPCException::NameAndFormatForNSResult(rv, nullptr, &format))
format = ""; format = "";
BuildAndThrowException(cx, rv, format); dom::Throw(cx, rv, format);
} }
namespace xpc { namespace xpc {
@ -56,7 +59,7 @@ XPCThrower::CheckForPendingException(nsresult result, JSContext *cx)
if (NS_FAILED(e->GetResult(&e_result)) || e_result != result) if (NS_FAILED(e->GetResult(&e_result)) || e_result != result)
return false; return false;
if (!ThrowExceptionObject(cx, static_cast<nsXPCException*>(e.get()))) if (!ThrowExceptionObject(cx, e))
JS_ReportOutOfMemory(cx); JS_ReportOutOfMemory(cx);
return true; return true;
} }
@ -79,7 +82,7 @@ XPCThrower::Throw(nsresult rv, XPCCallContext& ccx)
if (sz && sVerbose) if (sz && sVerbose)
Verbosify(ccx, &sz, false); Verbosify(ccx, &sz, false);
BuildAndThrowException(ccx, rv, sz); dom::Throw(ccx, rv, sz);
if (sz && sz != format) if (sz && sz != format)
JS_smprintf_free(sz); JS_smprintf_free(sz);
@ -117,7 +120,7 @@ XPCThrower::ThrowBadResult(nsresult rv, nsresult result, XPCCallContext& ccx)
if (sz && sVerbose) if (sz && sVerbose)
Verbosify(ccx, &sz, true); Verbosify(ccx, &sz, true);
BuildAndThrowException(ccx, result, sz); dom::Throw(ccx, result, sz);
if (sz) if (sz)
JS_smprintf_free(sz); JS_smprintf_free(sz);
@ -138,7 +141,7 @@ XPCThrower::ThrowBadParam(nsresult rv, unsigned paramNum, XPCCallContext& ccx)
if (sz && sVerbose) if (sz && sVerbose)
Verbosify(ccx, &sz, true); Verbosify(ccx, &sz, true);
BuildAndThrowException(ccx, rv, sz); dom::Throw(ccx, rv, sz);
if (sz) if (sz)
JS_smprintf_free(sz); JS_smprintf_free(sz);
@ -169,104 +172,3 @@ XPCThrower::Verbosify(XPCCallContext& ccx,
*psz = sz; *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<nsIException> existingException = runtime->GetPendingException();
if (existingException) {
nsresult nr;
if (NS_SUCCEEDED(existingException->GetResult(&nr)) &&
rv == nr) {
// Just reuse the existing exception.
return;
}
}
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()) {
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<nsIScriptSecurityManager> 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;
}

View File

@ -17,6 +17,7 @@
#include "nsJSUtils.h" #include "nsJSUtils.h"
#include "mozilla/Attributes.h" #include "mozilla/Attributes.h"
#include "mozilla/dom/BindingUtils.h" #include "mozilla/dom/BindingUtils.h"
#include "mozilla/dom/DOMException.h"
#include "mozilla/dom/DOMExceptionBinding.h" #include "mozilla/dom/DOMExceptionBinding.h"
#include "jsapi.h" #include "jsapi.h"
@ -264,7 +265,7 @@ nsXPCWrappedJSClass::CallQueryInterfaceOnJSObject(JSContext* cx,
// XPConnect may have constructed an object to represent a // XPConnect may have constructed an object to represent a
// C++ QI failure. See if that is the case. // C++ QI failure. See if that is the case.
using namespace mozilla::dom; using namespace mozilla::dom;
nsXPCException *e = nullptr; Exception *e = nullptr;
UNWRAP_OBJECT(Exception, cx, &jsexception.toObject(), e); UNWRAP_OBJECT(Exception, cx, &jsexception.toObject(), e);
if (e && if (e &&

View File

@ -34,7 +34,6 @@ CPP_SOURCES += [
'XPCModule.cpp', 'XPCModule.cpp',
'XPCQuickStubs.cpp', 'XPCQuickStubs.cpp',
'XPCRuntimeService.cpp', 'XPCRuntimeService.cpp',
'XPCStack.cpp',
'XPCString.cpp', 'XPCString.cpp',
'XPCThrower.cpp', 'XPCThrower.cpp',
'XPCVariant.cpp', 'XPCVariant.cpp',

View File

@ -36,6 +36,7 @@
#include "XPCQuickStubs.h" #include "XPCQuickStubs.h"
#include "mozilla/dom/BindingUtils.h" #include "mozilla/dom/BindingUtils.h"
#include "mozilla/dom/Exceptions.h"
#include "mozilla/dom/IDBIndexBinding.h" #include "mozilla/dom/IDBIndexBinding.h"
#include "mozilla/dom/IDBObjectStoreBinding.h" #include "mozilla/dom/IDBObjectStoreBinding.h"
#include "mozilla/dom/IDBOpenDBRequestBinding.h" #include "mozilla/dom/IDBOpenDBRequestBinding.h"
@ -863,12 +864,14 @@ nsXPConnect::CreateStackFrameLocation(uint32_t aLanguage,
{ {
MOZ_ASSERT(_retval, "bad param"); MOZ_ASSERT(_retval, "bad param");
return XPCJSStack::CreateStackFrameLocation(aLanguage, nsCOMPtr<nsIStackFrame> stackFrame =
aFilename, exceptions::CreateStackFrameLocation(aLanguage,
aFunctionName, aFilename,
aLineNumber, aFunctionName,
aCaller, aLineNumber,
_retval); aCaller);
stackFrame.forget(_retval);
return NS_OK;
} }
/* readonly attribute nsIStackFrame CurrentJSStack; */ /* readonly attribute nsIStackFrame CurrentJSStack; */
@ -880,8 +883,7 @@ nsXPConnect::GetCurrentJSStack(nsIStackFrame * *aCurrentJSStack)
// is there a current context available? // is there a current context available?
if (JSContext *cx = GetCurrentJSContext()) { if (JSContext *cx = GetCurrentJSContext()) {
nsCOMPtr<nsIStackFrame> stack; nsCOMPtr<nsIStackFrame> stack = exceptions::CreateStack(cx);
XPCJSStack::CreateStack(cx, getter_AddRefs(stack));
if (stack) { if (stack) {
// peel off native frames... // peel off native frames...
uint32_t language; uint32_t language;

View File

@ -739,17 +739,6 @@ public:
~XPCJSRuntime(); ~XPCJSRuntime();
already_AddRefed<nsIException> GetPendingException()
{
nsCOMPtr<nsIException> out = mPendingException;
return out.forget();
}
void SetPendingException(nsIException* aException)
{
mPendingException = aException;
}
XPCReadableJSStringWrapper *NewStringWrapper(const PRUnichar *str, uint32_t len); XPCReadableJSStringWrapper *NewStringWrapper(const PRUnichar *str, uint32_t len);
void DeleteString(nsAString *string); void DeleteString(nsAString *string);
@ -831,8 +820,6 @@ private:
mozilla::TimeStamp mSlowScriptCheckpoint; mozilla::TimeStamp mSlowScriptCheckpoint;
nsCOMPtr<nsIException> mPendingException;
#define XPCCCX_STRING_CACHE_SIZE 2 #define XPCCCX_STRING_CACHE_SIZE 2
// String wrapper entry, holds a string, and a boolean that tells // String wrapper entry, holds a string, and a boolean that tells
@ -2943,54 +2930,21 @@ public:
static bool SetVerbosity(bool state) static bool SetVerbosity(bool state)
{bool old = sVerbose; sVerbose = state; return old;} {bool old = sVerbose; sVerbose = state; return old;}
static void BuildAndThrowException(JSContext* cx, nsresult rv, const char* sz);
static bool CheckForPendingException(nsresult result, JSContext *cx); static bool CheckForPendingException(nsresult result, JSContext *cx);
private: private:
static void Verbosify(XPCCallContext& ccx, static void Verbosify(XPCCallContext& ccx,
char** psz, bool own); char** psz, bool own);
static bool ThrowExceptionObject(JSContext* cx, nsXPCException* e);
private: private:
static bool sVerbose; static bool sVerbose;
}; };
/***************************************************************************/ /***************************************************************************/
class XPCJSStack class nsXPCException
{ {
public: 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, static bool NameAndFormatForNSResult(nsresult rv,
const char** name, const char** name,
const char** format); const char** format);
@ -3001,58 +2955,6 @@ public:
const void** iterp); const void** iterp);
static uint32_t GetNSResultCount(); 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<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();
char* mMessage;
nsresult mResult;
char* mName;
nsIStackFrame* mLocation;
nsISupports* mData;
char* mFilename;
int mLineNumber;
nsIException* mInner;
bool mInitialized;
nsAutoJSValHolder mThrownJSVal;
private:
static bool sEverMadeOneFromFactory;
}; };
/***************************************************************************/ /***************************************************************************/

View File

@ -68,7 +68,6 @@
// DOM includes // DOM includes
#include "nsDOMBlobBuilder.h" #include "nsDOMBlobBuilder.h"
#include "nsDOMException.h"
#include "nsDOMFileReader.h" #include "nsDOMFileReader.h"
#include "nsFormData.h" #include "nsFormData.h"
@ -85,6 +84,7 @@
#include "mozIApplicationClearPrivateDataParams.h" #include "mozIApplicationClearPrivateDataParams.h"
#include "mozilla/Attributes.h" #include "mozilla/Attributes.h"
#include "mozilla/dom/Activity.h" #include "mozilla/dom/Activity.h"
#include "mozilla/dom/DOMException.h"
#include "mozilla/dom/DOMRequest.h" #include "mozilla/dom/DOMRequest.h"
#include "mozilla/dom/EventSource.h" #include "mozilla/dom/EventSource.h"
#include "mozilla/dom/indexedDB/IndexedDatabaseManager.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(nsFontTableProtocolHandler)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsHostObjectURI) NS_GENERIC_FACTORY_CONSTRUCTOR(nsHostObjectURI)
NS_GENERIC_FACTORY_CONSTRUCTOR(DOMParser) NS_GENERIC_FACTORY_CONSTRUCTOR(DOMParser)
NS_GENERIC_FACTORY_CONSTRUCTOR(Exception)
NS_GENERIC_FACTORY_CONSTRUCTOR(DOMSessionStorageManager) NS_GENERIC_FACTORY_CONSTRUCTOR(DOMSessionStorageManager)
NS_GENERIC_FACTORY_CONSTRUCTOR(DOMLocalStorageManager) NS_GENERIC_FACTORY_CONSTRUCTOR(DOMLocalStorageManager)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsChannelPolicy) NS_GENERIC_FACTORY_CONSTRUCTOR(nsChannelPolicy)
@ -1027,6 +1028,7 @@ static const mozilla::Module::CIDEntry kLayoutCIDs[] = {
{ &kNS_EVENTSOURCE_CID, false, NULL, EventSourceConstructor }, { &kNS_EVENTSOURCE_CID, false, NULL, EventSourceConstructor },
{ &kNS_DOMACTIVITY_CID, false, NULL, ActivityConstructor }, { &kNS_DOMACTIVITY_CID, false, NULL, ActivityConstructor },
{ &kNS_DOMPARSER_CID, false, NULL, DOMParserConstructor }, { &kNS_DOMPARSER_CID, false, NULL, DOMParserConstructor },
{ &kNS_XPCEXCEPTION_CID, false, NULL, ExceptionConstructor },
{ &kNS_DOMSESSIONSTORAGEMANAGER_CID, false, NULL, DOMSessionStorageManagerConstructor }, { &kNS_DOMSESSIONSTORAGEMANAGER_CID, false, NULL, DOMSessionStorageManagerConstructor },
{ &kNS_DOMLOCALSTORAGEMANAGER_CID, false, NULL, DOMLocalStorageManagerConstructor }, { &kNS_DOMLOCALSTORAGEMANAGER_CID, false, NULL, DOMLocalStorageManagerConstructor },
{ &kNS_DOMJSON_CID, false, NULL, NS_NewJSON }, { &kNS_DOMJSON_CID, false, NULL, NS_NewJSON },
@ -1181,6 +1183,7 @@ static const mozilla::Module::ContractIDEntry kLayoutContracts[] = {
{ NS_EVENTSOURCE_CONTRACTID, &kNS_EVENTSOURCE_CID }, { NS_EVENTSOURCE_CONTRACTID, &kNS_EVENTSOURCE_CID },
{ NS_DOMACTIVITY_CONTRACTID, &kNS_DOMACTIVITY_CID }, { NS_DOMACTIVITY_CONTRACTID, &kNS_DOMACTIVITY_CID },
{ NS_DOMPARSER_CONTRACTID, &kNS_DOMPARSER_CID }, { NS_DOMPARSER_CONTRACTID, &kNS_DOMPARSER_CID },
{ XPC_EXCEPTION_CONTRACTID, &kNS_XPCEXCEPTION_CID },
{ "@mozilla.org/dom/localStorage-manager;1", &kNS_DOMLOCALSTORAGEMANAGER_CID }, { "@mozilla.org/dom/localStorage-manager;1", &kNS_DOMLOCALSTORAGEMANAGER_CID },
// Keeping the old ContractID for backward compatibility // Keeping the old ContractID for backward compatibility
{ "@mozilla.org/dom/storagemanager;1", &kNS_DOMLOCALSTORAGEMANAGER_CID }, { "@mozilla.org/dom/storagemanager;1", &kNS_DOMLOCALSTORAGEMANAGER_CID },

View File

@ -64,6 +64,7 @@
#include "nsCycleCollectionParticipant.h" #include "nsCycleCollectionParticipant.h"
#include "nsCycleCollector.h" #include "nsCycleCollector.h"
#include "nsDOMJSUtils.h" #include "nsDOMJSUtils.h"
#include "nsIException.h"
#include "nsThreadUtils.h" #include "nsThreadUtils.h"
#include "xpcpublic.h" #include "xpcpublic.h"
@ -463,6 +464,9 @@ CycleCollectedJSRuntime::~CycleCollectedJSRuntime()
MOZ_ASSERT(!mDeferredFinalizerTable.Count()); MOZ_ASSERT(!mDeferredFinalizerTable.Count());
MOZ_ASSERT(!mDeferredSupports.Length()); MOZ_ASSERT(!mDeferredSupports.Length());
// Clear mPendingException first, since it might be cycle collected.
mPendingException = nullptr;
nsCycleCollector_forgetJSRuntime(); nsCycleCollector_forgetJSRuntime();
JS_DestroyRuntime(mJSRuntime); JS_DestroyRuntime(mJSRuntime);
@ -828,6 +832,19 @@ CycleCollectedJSRuntime::AssertNoObjectsToTrace(void* aPossibleJSHolder)
} }
#endif #endif
already_AddRefed<nsIException>
CycleCollectedJSRuntime::GetPendingException() const
{
nsCOMPtr<nsIException> out = mPendingException;
return out.forget();
}
void
CycleCollectedJSRuntime::SetPendingException(nsIException* aException)
{
mPendingException = aException;
}
nsCycleCollectionParticipant* nsCycleCollectionParticipant*
CycleCollectedJSRuntime::GCThingParticipant() CycleCollectedJSRuntime::GCThingParticipant()
{ {

View File

@ -19,6 +19,7 @@
class nsCycleCollectionNoteRootCallback; class nsCycleCollectionNoteRootCallback;
class nsScriptObjectTracer; class nsScriptObjectTracer;
class nsIException;
namespace mozilla { namespace mozilla {
@ -172,6 +173,9 @@ public:
void AssertNoObjectsToTrace(void* aPossibleJSHolder); void AssertNoObjectsToTrace(void* aPossibleJSHolder);
#endif #endif
already_AddRefed<nsIException> GetPendingException() const;
void SetPendingException(nsIException* aException);
nsCycleCollectionParticipant* GCThingParticipant(); nsCycleCollectionParticipant* GCThingParticipant();
nsCycleCollectionParticipant* ZoneParticipant(); nsCycleCollectionParticipant* ZoneParticipant();
@ -198,6 +202,12 @@ public:
MOZ_ASSERT(mJSRuntime); MOZ_ASSERT(mJSRuntime);
return mJSRuntime; return mJSRuntime;
} }
// Get the current thread's CycleCollectedJSRuntime. Returns null if there
// isn't one.
static CycleCollectedJSRuntime*
Get();
private: private:
JSGCThingParticipant mGCThingCycleCollectorGlobal; JSGCThingParticipant mGCThingCycleCollectorGlobal;
@ -214,6 +224,8 @@ private:
nsRefPtr<IncrementalFinalizeRunnable> mFinalizeRunnable; nsRefPtr<IncrementalFinalizeRunnable> mFinalizeRunnable;
nsCOMPtr<nsIException> mPendingException;
#ifdef DEBUG #ifdef DEBUG
void* mObjectToUnlink; void* mObjectToUnlink;
#endif #endif

View File

@ -2903,8 +2903,8 @@ nsCycleCollector_forgetJSRuntime()
} }
} }
mozilla::CycleCollectedJSRuntime* /* static */ CycleCollectedJSRuntime*
nsCycleCollector_currentJSRuntime() CycleCollectedJSRuntime::Get()
{ {
CollectorData* data = sCollectorData.get(); CollectorData* data = sCollectorData.get();
if (data) { if (data) {

View File

@ -64,7 +64,6 @@ void nsCycleCollector_shutdown();
// Helpers for interacting with JS // Helpers for interacting with JS
void nsCycleCollector_registerJSRuntime(mozilla::CycleCollectedJSRuntime *aRt); void nsCycleCollector_registerJSRuntime(mozilla::CycleCollectedJSRuntime *aRt);
void nsCycleCollector_forgetJSRuntime(); void nsCycleCollector_forgetJSRuntime();
mozilla::CycleCollectedJSRuntime* nsCycleCollector_currentJSRuntime();
#define NS_CYCLE_COLLECTOR_LOGGER_CID \ #define NS_CYCLE_COLLECTOR_LOGGER_CID \
{ 0x58be81b4, 0x39d2, 0x437c, \ { 0x58be81b4, 0x39d2, 0x437c, \