From c76e66fc3d8b2f86f4d406f0700149cc1f4719a5 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sun, 16 Jun 2019 11:27:39 -0400 Subject: 1283712 - Part 8: Add WorkerErrorBase, WorkerErrorNote, and WorkerErrorReport. --- dom/workers/WorkerPrivate.cpp | 226 ++++++++++++++++---------------- dom/workers/WorkerPrivate.h | 46 ++++++- dom/workers/moz.build | 1 + dom/workers/test/test_sharedWorker.html | 2 +- 4 files changed, 158 insertions(+), 117 deletions(-) (limited to 'dom/workers') diff --git a/dom/workers/WorkerPrivate.cpp b/dom/workers/WorkerPrivate.cpp index 6bc5c4f96..27eb570e9 100644 --- a/dom/workers/WorkerPrivate.cpp +++ b/dom/workers/WorkerPrivate.cpp @@ -87,6 +87,7 @@ #include "nsProxyRelease.h" #include "nsQueryObject.h" #include "nsSandboxFlags.h" +#include "nsScriptError.h" #include "nsUTF8Utils.h" #include "prthread.h" #include "xpcpublic.h" @@ -281,27 +282,34 @@ struct WindowAction }; void -LogErrorToConsole(const nsAString& aMessage, - const nsAString& aFilename, - const nsAString& aLine, - uint32_t aLineNumber, - uint32_t aColumnNumber, - uint32_t aFlags, - uint64_t aInnerWindowId) +LogErrorToConsole(const WorkerErrorReport& aReport, uint64_t aInnerWindowId) { AssertIsOnMainThread(); - nsCOMPtr scriptError = - do_CreateInstance(NS_SCRIPTERROR_CONTRACTID); + RefPtr scriptError = new nsScriptError(); NS_WARNING_ASSERTION(scriptError, "Failed to create script error!"); if (scriptError) { - if (NS_FAILED(scriptError->InitWithWindowID(aMessage, aFilename, aLine, - aLineNumber, aColumnNumber, - aFlags, "Web Worker", + nsAutoCString category("Web Worker"); + if (NS_FAILED(scriptError->InitWithWindowID(aReport.mMessage, + aReport.mFilename, + aReport.mLine, + aReport.mLineNumber, + aReport.mColumnNumber, + aReport.mFlags, + category, aInnerWindowId))) { NS_WARNING("Failed to init script error!"); scriptError = nullptr; + + for (size_t i = 0, len = aReport.mNotes.Length(); i < len; i++) { + const WorkerErrorNote& note = aReport.mNotes.ElementAt(i); + + nsScriptErrorNote* noteObject = new nsScriptErrorNote(); + noteObject->Init(note.mMessage, note.mFilename, + note.mLineNumber, note.mColumnNumber); + scriptError->AddNote(noteObject); + } } } @@ -316,23 +324,23 @@ LogErrorToConsole(const nsAString& aMessage, } NS_WARNING("LogMessage failed!"); } else if (NS_SUCCEEDED(consoleService->LogStringMessage( - aMessage.BeginReading()))) { + aReport.mMessage.BeginReading()))) { return; } NS_WARNING("LogStringMessage failed!"); } - NS_ConvertUTF16toUTF8 msg(aMessage); - NS_ConvertUTF16toUTF8 filename(aFilename); + NS_ConvertUTF16toUTF8 msg(aReport.mMessage); + NS_ConvertUTF16toUTF8 filename(aReport.mFilename); static const char kErrorString[] = "JS error in Web Worker: %s [%s:%u]"; #ifdef ANDROID __android_log_print(ANDROID_LOG_INFO, "Gecko", kErrorString, msg.get(), - filename.get(), aLineNumber); + filename.get(), aReport.mLineNumber); #endif - fprintf(stderr, kErrorString, msg.get(), filename.get(), aLineNumber); + fprintf(stderr, kErrorString, msg.get(), filename.get(), aReport.mLineNumber); fflush(stderr); } @@ -536,10 +544,7 @@ private: } if (aWorkerPrivate->IsSharedWorker()) { - aWorkerPrivate->BroadcastErrorToSharedWorkers(aCx, EmptyString(), - EmptyString(), - EmptyString(), 0, 0, - JSREPORT_ERROR, + aWorkerPrivate->BroadcastErrorToSharedWorkers(aCx, nullptr, /* isErrorEvent */ false); return true; } @@ -1060,15 +1065,7 @@ private: class ReportErrorRunnable final : public WorkerRunnable { - nsString mMessage; - nsString mFilename; - nsString mLine; - uint32_t mLineNumber; - uint32_t mColumnNumber; - uint32_t mFlags; - uint32_t mErrorNumber; - JSExnType mExnType; - bool mMutedError; + WorkerErrorReport mReport; public: // aWorkerPrivate is the worker thread we're on (or the main thread, if null) @@ -1077,11 +1074,7 @@ public: static void ReportError(JSContext* aCx, WorkerPrivate* aWorkerPrivate, bool aFireAtScope, WorkerPrivate* aTarget, - const nsString& aMessage, const nsString& aFilename, - const nsString& aLine, uint32_t aLineNumber, - uint32_t aColumnNumber, uint32_t aFlags, - uint32_t aErrorNumber, JSExnType aExnType, - bool aMutedError, uint64_t aInnerWindowId, + const WorkerErrorReport& aReport, uint64_t aInnerWindowId, JS::Handle aException = JS::NullHandleValue) { if (aWorkerPrivate) { @@ -1092,16 +1085,16 @@ public: // We should not fire error events for warnings but instead make sure that // they show up in the error console. - if (!JSREPORT_IS_WARNING(aFlags)) { + if (!JSREPORT_IS_WARNING(aReport.mFlags)) { // First fire an ErrorEvent at the worker. RootedDictionary init(aCx); - if (aMutedError) { + if (aReport.mMutedError) { init.mMessage.AssignLiteral("Script error."); } else { - init.mMessage = aMessage; - init.mFilename = aFilename; - init.mLineno = aLineNumber; + init.mMessage = aReport.mMessage; + init.mFilename = aReport.mFilename; + init.mLineno = aReport.mLineNumber; init.mError = aException; } @@ -1128,7 +1121,8 @@ public: // into an error event on our parent worker! // https://bugzilla.mozilla.org/show_bug.cgi?id=1271441 tracks making this // better. - if (aFireAtScope && (aTarget || aErrorNumber != JSMSG_OVER_RECURSED)) { + if (aFireAtScope && + (aTarget || aReport.mErrorNumber != JSMSG_OVER_RECURSED)) { JS::Rooted global(aCx, JS::CurrentGlobalOrNull(aCx)); NS_ASSERTION(global, "This should never be null!"); @@ -1145,8 +1139,8 @@ public: MOZ_ASSERT_IF(globalScope, globalScope->GetWrapperPreserveColor() == global); if (globalScope || IsDebuggerSandbox(global)) { - aWorkerPrivate->ReportErrorToDebugger(aFilename, aLineNumber, - aMessage); + aWorkerPrivate->ReportErrorToDebugger(aReport.mFilename, aReport.mLineNumber, + aReport.mMessage); return; } @@ -1193,28 +1187,20 @@ public: // Now fire a runnable to do the same on the parent's thread if we can. if (aWorkerPrivate) { RefPtr runnable = - new ReportErrorRunnable(aWorkerPrivate, aMessage, aFilename, aLine, - aLineNumber, aColumnNumber, aFlags, - aErrorNumber, aExnType, aMutedError); + new ReportErrorRunnable(aWorkerPrivate, aReport); runnable->Dispatch(); return; } // Otherwise log an error to the error console. - LogErrorToConsole(aMessage, aFilename, aLine, aLineNumber, aColumnNumber, - aFlags, aInnerWindowId); + LogErrorToConsole(aReport, aInnerWindowId); } private: - ReportErrorRunnable(WorkerPrivate* aWorkerPrivate, const nsString& aMessage, - const nsString& aFilename, const nsString& aLine, - uint32_t aLineNumber, uint32_t aColumnNumber, - uint32_t aFlags, uint32_t aErrorNumber, - JSExnType aExnType, bool aMutedError) + ReportErrorRunnable(WorkerPrivate* aWorkerPrivate, + const WorkerErrorReport& aReport) : WorkerRunnable(aWorkerPrivate, ParentThreadUnchangedBusyCount), - mMessage(aMessage), mFilename(aFilename), mLine(aLine), - mLineNumber(aLineNumber), mColumnNumber(aColumnNumber), mFlags(aFlags), - mErrorNumber(aErrorNumber), mExnType(aExnType), mMutedError(aMutedError) + mReport(aReport) { } virtual void @@ -1251,9 +1237,7 @@ private: } if (aWorkerPrivate->IsSharedWorker()) { - aWorkerPrivate->BroadcastErrorToSharedWorkers(aCx, mMessage, mFilename, - mLine, mLineNumber, - mColumnNumber, mFlags, + aWorkerPrivate->BroadcastErrorToSharedWorkers(aCx, &mReport, /* isErrorEvent */ true); return true; } @@ -1267,9 +1251,10 @@ private: swm->HandleError(aCx, aWorkerPrivate->GetPrincipal(), aWorkerPrivate->WorkerName(), aWorkerPrivate->ScriptURL(), - mMessage, - mFilename, mLine, mLineNumber, - mColumnNumber, mFlags, mExnType); + mReport.mMessage, + mReport.mFilename, mReport.mLine, mReport.mLineNumber, + mReport.mColumnNumber, mReport.mFlags, + mReport.mExnType); } return true; } @@ -1289,9 +1274,8 @@ private: return true; } - ReportError(aCx, parent, fireAtScope, aWorkerPrivate, mMessage, - mFilename, mLine, mLineNumber, mColumnNumber, mFlags, - mErrorNumber, mExnType, mMutedError, innerWindowId); + ReportError(aCx, parent, fireAtScope, aWorkerPrivate, mReport, + innerWindowId); return true; } }; @@ -3314,21 +3298,16 @@ template void WorkerPrivateParent::BroadcastErrorToSharedWorkers( JSContext* aCx, - const nsAString& aMessage, - const nsAString& aFilename, - const nsAString& aLine, - uint32_t aLineNumber, - uint32_t aColumnNumber, - uint32_t aFlags, + const WorkerErrorReport* aReport, bool aIsErrorEvent) { AssertIsOnMainThread(); - if (JSREPORT_IS_WARNING(aFlags)) { + if (aIsErrorEvent && JSREPORT_IS_WARNING(aReport->mFlags)) { // Don't fire any events anywhere. Just log to console. // XXXbz should we log to all the consoles of all the relevant windows? - LogErrorToConsole(aMessage, aFilename, aLine, aLineNumber, aColumnNumber, - aFlags, 0); + MOZ_ASSERT(aReport); + LogErrorToConsole(*aReport, 0); return; } @@ -3357,10 +3336,10 @@ WorkerPrivateParent::BroadcastErrorToSharedWorkers( RootedDictionary errorInit(aCx); errorInit.mBubbles = false; errorInit.mCancelable = true; - errorInit.mMessage = aMessage; - errorInit.mFilename = aFilename; - errorInit.mLineno = aLineNumber; - errorInit.mColno = aColumnNumber; + errorInit.mMessage = aReport->mMessage; + errorInit.mFilename = aReport->mFilename; + errorInit.mLineno = aReport->mLineNumber; + errorInit.mColno = aReport->mColumnNumber; event = ErrorEvent::Constructor(sharedWorker, NS_LITERAL_STRING("error"), errorInit); @@ -3426,9 +3405,9 @@ WorkerPrivateParent::BroadcastErrorToSharedWorkers( MOZ_ASSERT(NS_IsMainThread()); RootedDictionary init(aCx); - init.mLineno = aLineNumber; - init.mFilename = aFilename; - init.mMessage = aMessage; + init.mLineno = aReport->mLineNumber; + init.mFilename = aReport->mFilename; + init.mMessage = aReport->mMessage; init.mCancelable = true; init.mBubbles = true; @@ -3446,8 +3425,8 @@ WorkerPrivateParent::BroadcastErrorToSharedWorkers( // Finally log a warning in the console if no window tried to prevent it. if (shouldLogErrorToConsole) { - LogErrorToConsole(aMessage, aFilename, aLine, aLineNumber, aColumnNumber, - aFlags, 0); + MOZ_ASSERT(aReport); + LogErrorToConsole(*aReport, 0); } } @@ -4120,7 +4099,10 @@ WorkerDebugger::ReportErrorToDebuggerOnMainThread(const nsAString& aFilename, listeners[index]->OnError(aFilename, aLineno, aMessage); } - LogErrorToConsole(aMessage, aFilename, nsString(), aLineno, 0, 0, 0); + WorkerErrorReport report; + report.mMessage = aMessage; + report.mFilename = aFilename; + LogErrorToConsole(report, 0); } WorkerPrivate::WorkerPrivate(WorkerPrivate* aParent, @@ -5925,6 +5907,47 @@ WorkerPrivate::NotifyInternal(JSContext* aCx, Status aStatus) return false; } +void +WorkerErrorBase::AssignErrorBase(JSErrorBase* aReport) +{ + mFilename = NS_ConvertUTF8toUTF16(aReport->filename); + mLineNumber = aReport->lineno; + mColumnNumber = aReport->column; + mErrorNumber = aReport->errorNumber; +} + +void +WorkerErrorNote::AssignErrorNote(JSErrorNotes::Note* aNote) +{ + WorkerErrorBase::AssignErrorBase(aNote); + xpc::ErrorNote::ErrorNoteToMessageString(aNote, mMessage); +} + +void +WorkerErrorReport::AssignErrorReport(JSErrorReport* aReport) +{ + WorkerErrorBase::AssignErrorBase(aReport); + xpc::ErrorReport::ErrorReportToMessageString(aReport, mMessage); + + mLine.Assign(aReport->linebuf(), aReport->linebufLength()); + mFlags = aReport->flags; + MOZ_ASSERT(aReport->exnType >= JSEXN_FIRST && aReport->exnType < JSEXN_LIMIT); + mExnType = JSExnType(aReport->exnType); + mMutedError = aReport->isMuted; + + if (aReport->notes) { + if (!mNotes.SetLength(aReport->notes->length(), fallible)) { + return; + } + + size_t i = 0; + for (auto&& note : *aReport->notes) { + mNotes.ElementAt(i).AssignErrorNote(note.get()); + i++; + } + } +} + void WorkerPrivate::ReportError(JSContext* aCx, JS::ConstUTF8CharsZ aToStringResult, JSErrorReport* aReport) @@ -5947,32 +5970,17 @@ WorkerPrivate::ReportError(JSContext* aCx, JS::ConstUTF8CharsZ aToStringResult, } JS_ClearPendingException(aCx); - nsString message, filename, line; - uint32_t lineNumber, columnNumber, flags, errorNumber; - JSExnType exnType = JSEXN_ERR; - bool mutedError = aReport && aReport->isMuted; - + WorkerErrorReport report; if (aReport) { - // We want the same behavior here as xpc::ErrorReport::init here. - xpc::ErrorReport::ErrorReportToMessageString(aReport, message); - - filename = NS_ConvertUTF8toUTF16(aReport->filename); - line.Assign(aReport->linebuf(), aReport->linebufLength()); - lineNumber = aReport->lineno; - columnNumber = aReport->tokenOffset(); - flags = aReport->flags; - errorNumber = aReport->errorNumber; - MOZ_ASSERT(aReport->exnType >= JSEXN_FIRST && aReport->exnType < JSEXN_LIMIT); - exnType = JSExnType(aReport->exnType); + report.AssignErrorReport(aReport); } else { - lineNumber = columnNumber = errorNumber = 0; - flags = nsIScriptError::errorFlag | nsIScriptError::exceptionFlag; + report.mFlags = nsIScriptError::errorFlag | nsIScriptError::exceptionFlag; } - if (message.IsEmpty() && aToStringResult) { + if (report.mMessage.IsEmpty() && aToStringResult) { nsDependentCString toStringResult(aToStringResult.c_str()); - if (!AppendUTF8toUTF16(toStringResult, message, mozilla::fallible)) { + if (!AppendUTF8toUTF16(toStringResult, report.mMessage, mozilla::fallible)) { // Try again, with only a 1 KB string. Do this infallibly this time. // If the user doesn't have 1 KB to spare we're done anyways. uint32_t index = std::min(uint32_t(1024), toStringResult.Length()); @@ -5982,7 +5990,7 @@ WorkerPrivate::ReportError(JSContext* aCx, JS::ConstUTF8CharsZ aToStringResult, nsDependentCString truncatedToStringResult(aToStringResult.c_str(), index); - AppendUTF8toUTF16(truncatedToStringResult, message); + AppendUTF8toUTF16(truncatedToStringResult, report.mMessage); } } @@ -5991,13 +5999,11 @@ WorkerPrivate::ReportError(JSContext* aCx, JS::ConstUTF8CharsZ aToStringResult, // Don't want to run the scope's error handler if this is a recursive error or // if we ran out of memory. bool fireAtScope = mErrorHandlerRecursionCount == 1 && - errorNumber != JSMSG_OUT_OF_MEMORY && + report.mErrorNumber != JSMSG_OUT_OF_MEMORY && JS::CurrentGlobalOrNull(aCx); - ReportErrorRunnable::ReportError(aCx, this, fireAtScope, nullptr, message, - filename, line, lineNumber, - columnNumber, flags, errorNumber, exnType, - mutedError, 0, exn); + ReportErrorRunnable::ReportError(aCx, this, fireAtScope, nullptr, report, 0, + exn); mErrorHandlerRecursionCount--; } diff --git a/dom/workers/WorkerPrivate.h b/dom/workers/WorkerPrivate.h index 20a530205..885abccd5 100644 --- a/dom/workers/WorkerPrivate.h +++ b/dom/workers/WorkerPrivate.h @@ -140,6 +140,45 @@ public: } }; +class WorkerErrorBase { +public: + nsString mMessage; + nsString mFilename; + uint32_t mLineNumber; + uint32_t mColumnNumber; + uint32_t mErrorNumber; + + WorkerErrorBase() + : mLineNumber(0), + mColumnNumber(0), + mErrorNumber(0) + { } + + void AssignErrorBase(JSErrorBase* aReport); +}; + +class WorkerErrorNote : public WorkerErrorBase { +public: + void AssignErrorNote(JSErrorNotes::Note* aNote); +}; + +class WorkerErrorReport : public WorkerErrorBase { +public: + nsString mLine; + uint32_t mFlags; + JSExnType mExnType; + bool mMutedError; + nsTArray mNotes; + + WorkerErrorReport() + : mFlags(0), + mExnType(JSEXN_ERR), + mMutedError(false) + { } + + void AssignErrorReport(JSErrorReport* aReport); +}; + template class WorkerPrivateParent : public DOMEventTargetHelper { @@ -401,12 +440,7 @@ public: void BroadcastErrorToSharedWorkers(JSContext* aCx, - const nsAString& aMessage, - const nsAString& aFilename, - const nsAString& aLine, - uint32_t aLineNumber, - uint32_t aColumnNumber, - uint32_t aFlags, + const WorkerErrorReport* aReport, bool aIsErrorEvent); void diff --git a/dom/workers/moz.build b/dom/workers/moz.build index 4f4b52e4a..9fea84193 100644 --- a/dom/workers/moz.build +++ b/dom/workers/moz.build @@ -94,6 +94,7 @@ LOCAL_INCLUDES += [ '../base', '../system', '/dom/base', + '/dom/bindings', '/xpcom/build', '/xpcom/threads', ] diff --git a/dom/workers/test/test_sharedWorker.html b/dom/workers/test/test_sharedWorker.html index 3d3d4e2c6..c00c4e586 100644 --- a/dom/workers/test/test_sharedWorker.html +++ b/dom/workers/test/test_sharedWorker.html @@ -23,7 +23,7 @@ const errorFilename = href.substring(0, href.lastIndexOf("/") + 1) + filename; const errorLine = 91; - const errorColumn = 0; + const errorColumn = 11; var worker = new SharedWorker(filename); -- cgit v1.2.3