mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-21 01:05:45 +00:00
Bug 1225717. Make AutoJSAPI::TakeOwnershipOfErrorReporting actually work on workers as long as no one calls JS_ReportPendingException manually. r=bholley
This commit is contained in:
parent
71b052b436
commit
6ecbcec387
@ -305,14 +305,13 @@ AutoJSAPI::AutoJSAPI()
|
||||
: mCx(nullptr)
|
||||
, mOwnErrorReporting(false)
|
||||
, mOldAutoJSAPIOwnsErrorReporting(false)
|
||||
, mIsMainThread(false) // For lack of anything better
|
||||
{
|
||||
}
|
||||
|
||||
AutoJSAPI::~AutoJSAPI()
|
||||
{
|
||||
if (mOwnErrorReporting) {
|
||||
MOZ_ASSERT(NS_IsMainThread(), "See corresponding assertion in TakeOwnershipOfErrorReporting()");
|
||||
|
||||
ReportException();
|
||||
|
||||
// We need to do this _after_ processing the existing exception, because the
|
||||
@ -332,7 +331,10 @@ void
|
||||
AutoJSAPI::InitInternal(JSObject* aGlobal, JSContext* aCx, bool aIsMainThread)
|
||||
{
|
||||
MOZ_ASSERT(aCx);
|
||||
MOZ_ASSERT(aIsMainThread == NS_IsMainThread());
|
||||
|
||||
mCx = aCx;
|
||||
mIsMainThread = aIsMainThread;
|
||||
if (aIsMainThread) {
|
||||
// This Rooted<> is necessary only as long as AutoCxPusher::AutoCxPusher
|
||||
// can GC, which is only possible because XPCJSContextStack::Push calls
|
||||
@ -357,11 +359,12 @@ AutoJSAPI::AutoJSAPI(nsIGlobalObject* aGlobalObject,
|
||||
JSContext* aCx)
|
||||
: mOwnErrorReporting(false)
|
||||
, mOldAutoJSAPIOwnsErrorReporting(false)
|
||||
, mIsMainThread(aIsMainThread)
|
||||
{
|
||||
MOZ_ASSERT(aGlobalObject);
|
||||
MOZ_ASSERT(aGlobalObject->GetGlobalJSObject(), "Must have a JS global");
|
||||
MOZ_ASSERT(aCx);
|
||||
MOZ_ASSERT_IF(aIsMainThread, NS_IsMainThread());
|
||||
MOZ_ASSERT(aIsMainThread == NS_IsMainThread());
|
||||
|
||||
InitInternal(aGlobalObject->GetGlobalJSObject(), aCx, aIsMainThread);
|
||||
}
|
||||
@ -460,7 +463,9 @@ AutoJSAPI::InitWithLegacyErrorReporting(nsGlobalWindow* aWindow)
|
||||
void
|
||||
WarningOnlyErrorReporter(JSContext* aCx, const char* aMessage, JSErrorReport* aRep)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(JSREPORT_IS_WARNING(aRep->flags));
|
||||
|
||||
RefPtr<xpc::ErrorReport> xpcReport = new xpc::ErrorReport();
|
||||
nsPIDOMWindow* win = xpc::CurrentWindowOrNull(aCx);
|
||||
xpcReport->Init(aRep, aMessage, nsContentUtils::IsCallerChrome(),
|
||||
@ -471,14 +476,19 @@ WarningOnlyErrorReporter(JSContext* aCx, const char* aMessage, JSErrorReport* aR
|
||||
void
|
||||
AutoJSAPI::TakeOwnershipOfErrorReporting()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Can't own error reporting off-main-thread yet");
|
||||
MOZ_ASSERT(!mOwnErrorReporting);
|
||||
mOwnErrorReporting = true;
|
||||
|
||||
JSRuntime *rt = JS_GetRuntime(cx());
|
||||
mOldAutoJSAPIOwnsErrorReporting = JS::ContextOptionsRef(cx()).autoJSAPIOwnsErrorReporting();
|
||||
JS::ContextOptionsRef(cx()).setAutoJSAPIOwnsErrorReporting(true);
|
||||
JS_SetErrorReporter(rt, WarningOnlyErrorReporter);
|
||||
// Workers have their own error reporting mechanism which deals with warnings
|
||||
// as well, so don't change the worker error reporter for now. Once we switch
|
||||
// all of workers to TakeOwnershipOfErrorReporting(), we will just make the
|
||||
// default worker error reporter assert that it only sees warnings.
|
||||
if (mIsMainThread) {
|
||||
JS_SetErrorReporter(rt, WarningOnlyErrorReporter);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@ -498,18 +508,35 @@ AutoJSAPI::ReportException()
|
||||
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)) {
|
||||
RefPtr<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);
|
||||
if (mIsMainThread) {
|
||||
RefPtr<xpc::ErrorReport> xpcReport = new xpc::ErrorReport();
|
||||
nsCOMPtr<nsPIDOMWindow> win = xpc::WindowGlobalOrNull(errorGlobal);
|
||||
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 {
|
||||
xpcReport->LogToConsole();
|
||||
// On a worker, we just use the worker error reporting mechanism and don't
|
||||
// bother with xpc::ErrorReport. This will ensure that all the right
|
||||
// events (which are a lot more complicated than in the window case) get
|
||||
// fired.
|
||||
workers::WorkerPrivate* worker = workers::GetCurrentThreadWorkerPrivate();
|
||||
MOZ_ASSERT(worker);
|
||||
MOZ_ASSERT(worker->GetJSContext() == cx());
|
||||
// Before invoking ReportError, put the exception back on the context,
|
||||
// because it may want to put it in its error events and has no other way
|
||||
// to get hold of it. After we invoke ReportError, clear the exception on
|
||||
// cx(), just in case ReportError didn't.
|
||||
JS_SetPendingException(cx(), exn);
|
||||
worker->ReportError(cx(), jsReport.message(), jsReport.report());
|
||||
ClearException();
|
||||
}
|
||||
} else {
|
||||
NS_WARNING("OOMed while acquiring uncaught exception from JSAPI");
|
||||
@ -519,7 +546,7 @@ AutoJSAPI::ReportException()
|
||||
bool
|
||||
AutoJSAPI::StealException(JS::MutableHandle<JS::Value> aVal)
|
||||
{
|
||||
MOZ_ASSERT(CxPusherIsStackTop());
|
||||
MOZ_ASSERT_IF(mIsMainThread, CxPusherIsStackTop());
|
||||
MOZ_ASSERT(HasException());
|
||||
MOZ_ASSERT(js::GetContextCompartment(cx()));
|
||||
if (!JS_GetPendingException(cx(), aVal)) {
|
||||
|
@ -262,7 +262,7 @@ public:
|
||||
|
||||
JSContext* cx() const {
|
||||
MOZ_ASSERT(mCx, "Must call Init before using an AutoJSAPI");
|
||||
MOZ_ASSERT_IF(NS_IsMainThread(), CxPusherIsStackTop());
|
||||
MOZ_ASSERT_IF(mIsMainThread, CxPusherIsStackTop());
|
||||
return mCx;
|
||||
}
|
||||
|
||||
@ -279,7 +279,7 @@ public:
|
||||
void ReportException();
|
||||
|
||||
bool HasException() const {
|
||||
MOZ_ASSERT(CxPusherIsStackTop());
|
||||
MOZ_ASSERT_IF(NS_IsMainThread(), CxPusherIsStackTop());
|
||||
return JS_IsExceptionPending(cx());
|
||||
};
|
||||
|
||||
@ -292,7 +292,7 @@ public:
|
||||
bool StealException(JS::MutableHandle<JS::Value> aVal);
|
||||
|
||||
void ClearException() {
|
||||
MOZ_ASSERT(CxPusherIsStackTop());
|
||||
MOZ_ASSERT_IF(NS_IsMainThread(), CxPusherIsStackTop());
|
||||
JS_ClearPendingException(cx());
|
||||
}
|
||||
|
||||
@ -312,6 +312,8 @@ private:
|
||||
// Track state between the old and new error reporting modes.
|
||||
bool mOwnErrorReporting;
|
||||
bool mOldAutoJSAPIOwnsErrorReporting;
|
||||
// Whether we're mainthread or not; set when we're initialized.
|
||||
bool mIsMainThread;
|
||||
Maybe<JSErrorReporter> mOldErrorReporter;
|
||||
|
||||
void InitInternal(JSObject* aGlobal, JSContext* aCx, bool aIsMainThread);
|
||||
|
Loading…
Reference in New Issue
Block a user