Bug 1174486 part 2. Add a way to explicitly report a pending exception on an AutoJSAPI that has taken ownership of error reporting. r=bholley

This is needed for some cases that currently report an exception and then do
some other work on the same cx (specifically, nsXBLProtoImplField::InstallField).
This commit is contained in:
Boris Zbarsky 2015-06-15 20:10:38 -04:00
parent 2f085a9633
commit ff55af02a9
2 changed files with 39 additions and 28 deletions

View File

@ -313,34 +313,7 @@ AutoJSAPI::~AutoJSAPI()
if (mOwnErrorReporting) {
MOZ_ASSERT(NS_IsMainThread(), "See corresponding assertion in TakeOwnershipOfErrorReporting()");
if (HasException()) {
// AutoJSAPI uses a JSAutoNullableCompartment, and may be in a null
// compartment when the destructor is called. However, the JS engine
// requires us to be in a compartment when we fetch the pending exception.
// In this case, we enter the privileged junk scope and don't dispatch any
// error events.
JS::Rooted<JSObject*> errorGlobal(cx(), JS::CurrentGlobalOrNull(cx()));
if (!errorGlobal)
errorGlobal = xpc::PrivilegedJunkScope();
JSAutoCompartment ac(cx(), errorGlobal);
nsCOMPtr<nsPIDOMWindow> win = xpc::WindowGlobalOrNull(errorGlobal);
JS::Rooted<JS::Value> exn(cx());
js::ErrorReport jsReport(cx());
if (StealException(&exn) && jsReport.init(cx(), exn)) {
nsRefPtr<xpc::ErrorReport> xpcReport = new xpc::ErrorReport();
xpcReport->Init(jsReport.report(), jsReport.message(),
nsContentUtils::IsCallerChrome(),
win ? win->WindowID() : 0);
if (win) {
DispatchScriptErrorEvent(win, JS_GetRuntime(cx()), xpcReport, exn);
} else {
xpcReport->LogToConsole();
}
} else {
NS_WARNING("OOMed while acquiring uncaught exception from JSAPI");
}
}
ReportException();
// We need to do this _after_ processing the existing exception, because the
// JS engine can throw while doing that, and uses this bit to determine what
@ -508,6 +481,41 @@ AutoJSAPI::TakeOwnershipOfErrorReporting()
JS_SetErrorReporter(rt, WarningOnlyErrorReporter);
}
void
AutoJSAPI::ReportException()
{
MOZ_ASSERT(OwnsErrorReporting(), "This is not our exception to report!");
if (!HasException()) {
return;
}
// AutoJSAPI uses a JSAutoNullableCompartment, and may be in a null
// compartment when the destructor is called. However, the JS engine
// requires us to be in a compartment when we fetch the pending exception.
// In this case, we enter the privileged junk scope and don't dispatch any
// error events.
JS::Rooted<JSObject*> errorGlobal(cx(), JS::CurrentGlobalOrNull(cx()));
if (!errorGlobal)
errorGlobal = xpc::PrivilegedJunkScope();
JSAutoCompartment ac(cx(), errorGlobal);
nsCOMPtr<nsPIDOMWindow> win = xpc::WindowGlobalOrNull(errorGlobal);
JS::Rooted<JS::Value> exn(cx());
js::ErrorReport jsReport(cx());
if (StealException(&exn) && jsReport.init(cx(), exn)) {
nsRefPtr<xpc::ErrorReport> xpcReport = new xpc::ErrorReport();
xpcReport->Init(jsReport.report(), jsReport.message(),
nsContentUtils::IsCallerChrome(),
win ? win->WindowID() : 0);
if (win) {
DispatchScriptErrorEvent(win, JS_GetRuntime(cx()), xpcReport, exn);
} else {
xpcReport->LogToConsole();
}
} else {
NS_WARNING("OOMed while acquiring uncaught exception from JSAPI");
}
}
bool
AutoJSAPI::StealException(JS::MutableHandle<JS::Value> aVal)
{

View File

@ -274,6 +274,9 @@ public:
// while keeping the old behavior as the default.
void TakeOwnershipOfErrorReporting();
bool OwnsErrorReporting() { return mOwnErrorReporting; }
// If HasException, report it. Otherwise, a no-op. This must be
// called only if OwnsErrorReporting().
void ReportException();
bool HasException() const {
MOZ_ASSERT(CxPusherIsStackTop());