Bug 1438945 - Part 4: errors and communications. r=asuth
authorAndrea Marchesini <amarchesini@mozilla.com>
Mon, 19 Nov 2018 15:18:21 -0800
changeset 503566 5de8d2303240d72cbca56a1fd1d50f575ec3b2de
parent 503565 062638f850a0bef1cfd94e62419ac2f00325c40b
child 503567 81c5bdf85bd781ba80d4bfc52aa66c778b248702
push id10290
push userffxbld-merge
push dateMon, 03 Dec 2018 16:23:23 +0000
treeherdermozilla-beta@700bed2445e6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersasuth
bugs1438945
milestone65.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1438945 - Part 4: errors and communications. r=asuth
dom/fetch/Fetch.cpp
dom/workers/RuntimeService.cpp
dom/workers/WorkerError.cpp
dom/workers/WorkerError.h
dom/workers/WorkerPrivate.cpp
dom/workers/WorkerPrivate.h
dom/workers/moz.build
dom/workers/sharedworkers/PSharedWorker.ipdl
dom/workers/sharedworkers/SharedWorker.cpp
dom/workers/sharedworkers/SharedWorkerChild.cpp
dom/workers/sharedworkers/SharedWorkerChild.h
dom/workers/sharedworkers/SharedWorkerManager.cpp
dom/workers/sharedworkers/SharedWorkerManager.h
dom/workers/sharedworkers/SharedWorkerParent.cpp
dom/workers/sharedworkers/SharedWorkerParent.h
dom/workers/sharedworkers/SharedWorkerService.cpp
dom/workers/sharedworkers/SharedWorkerTypes.ipdlh
dom/workers/sharedworkers/moz.build
--- a/dom/fetch/Fetch.cpp
+++ b/dom/fetch/Fetch.cpp
@@ -31,16 +31,17 @@
 #include "mozilla/dom/FormData.h"
 #include "mozilla/dom/Headers.h"
 #include "mozilla/dom/MutableBlobStreamListener.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/PromiseWorkerProxy.h"
 #include "mozilla/dom/Request.h"
 #include "mozilla/dom/Response.h"
 #include "mozilla/dom/ScriptSettings.h"
+#include "mozilla/dom/SharedWorkerManager.h"
 #include "mozilla/dom/URLSearchParams.h"
 #include "mozilla/Telemetry.h"
 
 #include "BodyExtractor.h"
 #include "EmptyBody.h"
 #include "FetchObserver.h"
 #include "InternalRequest.h"
 #include "InternalResponse.h"
@@ -901,17 +902,17 @@ WorkerFetchResolver::FlushConsoleReport(
   if (worker->IsServiceWorker()) {
     // Flush to service worker
     mReporter->FlushReportsToConsoleForServiceWorkerScope(worker->ServiceWorkerScope());
     return;
   }
 
   if (worker->IsSharedWorker()) {
     // Flush to shared worker
-    worker->FlushReportsToSharedWorkers(mReporter);
+    worker->GetSharedWorkerManager()->FlushReportsToActorsOnMainThread(mReporter);
     return;
   }
 
   // Flush to dedicated worker
   mReporter->FlushConsoleReports(worker->GetLoadGroup());
 }
 
 nsresult
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -44,16 +44,17 @@
 #include "mozilla/dom/ErrorEventBinding.h"
 #include "mozilla/dom/EventTargetBinding.h"
 #include "mozilla/dom/FetchUtil.h"
 #include "mozilla/dom/MessageChannel.h"
 #include "mozilla/dom/MessageEventBinding.h"
 #include "mozilla/dom/PerformanceService.h"
 #include "mozilla/dom/WorkerBinding.h"
 #include "mozilla/dom/ScriptSettings.h"
+#include "mozilla/dom/SharedWorkerManager.h"
 #include "mozilla/dom/IndexedDatabaseManager.h"
 #include "mozilla/ipc/BackgroundChild.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/dom/Navigator.h"
 #include "mozilla/Monitor.h"
 #include "mozilla/StaticPrefs.h"
 #include "nsContentUtils.h"
@@ -1525,20 +1526,19 @@ RuntimeService::UnregisterWorker(WorkerP
   }
 
   if (aWorkerPrivate->IsServiceWorker()) {
     AssertIsOnMainThread();
     Telemetry::AccumulateTimeDelta(Telemetry::SERVICE_WORKER_LIFE_TIME,
                                    aWorkerPrivate->CreationTimeStamp());
   }
 
-  if (aWorkerPrivate->IsSharedWorker() ||
-      aWorkerPrivate->IsServiceWorker()) {
+  if (aWorkerPrivate->IsSharedWorker()) {
     AssertIsOnMainThread();
-    aWorkerPrivate->CloseAllSharedWorkers();
+    aWorkerPrivate->GetSharedWorkerManager()->CloseActorsOnMainThread();
   }
 
   if (parent) {
     parent->RemoveChildWorker(aWorkerPrivate);
   }
   else if (aWorkerPrivate->IsSharedWorker()) {
     AssertIsOnMainThread();
 
--- a/dom/workers/WorkerError.cpp
+++ b/dom/workers/WorkerError.cpp
@@ -4,16 +4,18 @@
  * 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 "WorkerError.h"
 
 #include "mozilla/DOMEventTargetHelper.h"
 #include "mozilla/dom/ErrorEvent.h"
 #include "mozilla/dom/ErrorEventBinding.h"
+#include "mozilla/dom/PSharedWorker.h"
+#include "mozilla/dom/SharedWorkerManager.h"
 #include "mozilla/dom/ServiceWorkerManager.h"
 #include "mozilla/dom/SimpleGlobalObject.h"
 #include "mozilla/dom/WorkerDebuggerGlobalScopeBinding.h"
 #include "mozilla/dom/WorkerGlobalScopeBinding.h"
 #include "mozilla/EventDispatcher.h"
 #include "nsGlobalWindowInner.h"
 #include "nsIConsoleService.h"
 #include "nsScriptError.h"
@@ -196,18 +198,19 @@ private:
       // care of naturally.
       MOZ_ASSERT(!aWorkerPrivate->IsFrozen());
 
       // Similarly for paused windows; all its workers should have been informed.
       // (Subworkers are unaffected by paused windows.)
       MOZ_ASSERT(!aWorkerPrivate->IsParentWindowPaused());
 
       if (aWorkerPrivate->IsSharedWorker()) {
-        aWorkerPrivate->BroadcastErrorToSharedWorkers(aCx, &mReport,
-                                                      /* isErrorEvent */ true);
+        aWorkerPrivate->GetSharedWorkerManager()
+                      ->BroadcastErrorToActorsOnMainThread(&mReport,
+                                                           /* isErrorEvent */ true);
         return true;
       }
 
       // Service workers do not have a main thread parent global, so normal
       // worker error reporting will crash.  Instead, pass the error to
       // the ServiceWorkerManager to report on any controlled documents.
       if (aWorkerPrivate->IsServiceWorker()) {
         RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
@@ -286,18 +289,18 @@ private:
     // care of naturally.
     MOZ_ASSERT(!aWorkerPrivate->IsFrozen());
 
     // Similarly for paused windows; all its workers should have been informed.
     // (Subworkers are unaffected by paused windows.)
     MOZ_ASSERT(!aWorkerPrivate->IsParentWindowPaused());
 
     if (aWorkerPrivate->IsSharedWorker()) {
-      aWorkerPrivate->BroadcastErrorToSharedWorkers(aCx, nullptr,
-                                                    /* isErrorEvent */ false);
+      aWorkerPrivate->GetSharedWorkerManager()
+                    ->BroadcastErrorToActorsOnMainThread(nullptr, false);
       return true;
     }
 
     if (aWorkerPrivate->IsServiceWorker()) {
       RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
       if (swm) {
         swm->HandleError(aCx, aWorkerPrivate->GetPrincipal(),
                          aWorkerPrivate->ServiceWorkerScope(),
@@ -493,73 +496,94 @@ WorkerErrorReport::ReportError(JSContext
   // Otherwise log an error to the error console.
   WorkerErrorReport::LogErrorToConsole(aReport, aInnerWindowId);
 }
 
 /* static */ void
 WorkerErrorReport::LogErrorToConsole(const WorkerErrorReport& aReport,
                                      uint64_t aInnerWindowId)
 {
+  nsTArray<ErrorDataNote> notes;
+  for (size_t i = 0, len = aReport.mNotes.Length(); i < len; i++) {
+    const WorkerErrorNote& note = aReport.mNotes.ElementAt(i);
+    notes.AppendElement(ErrorDataNote(note.mLineNumber, note.mColumnNumber,
+                                      note.mMessage, note.mFilename));
+  }
+
+  ErrorData errorData(aReport.mLineNumber,
+                      aReport.mColumnNumber,
+                      aReport.mFlags,
+                      aReport.mMessage,
+                      aReport.mFilename,
+                      aReport.mLine,
+                      notes);
+  LogErrorToConsole(errorData, aInnerWindowId);
+}
+
+/* static */ void
+WorkerErrorReport::LogErrorToConsole(const ErrorData& aReport,
+                                     uint64_t aInnerWindowId)
+{
   AssertIsOnMainThread();
 
   RefPtr<nsScriptErrorBase> scriptError = new nsScriptError();
   NS_WARNING_ASSERTION(scriptError, "Failed to create script error!");
 
   if (scriptError) {
     nsAutoCString category("Web Worker");
-    if (NS_FAILED(scriptError->InitWithWindowID(aReport.mMessage,
-                                                aReport.mFilename,
-                                                aReport.mLine,
-                                                aReport.mLineNumber,
-                                                aReport.mColumnNumber,
-                                                aReport.mFlags,
+    if (NS_FAILED(scriptError->InitWithWindowID(aReport.message(),
+                                                aReport.filename(),
+                                                aReport.line(),
+                                                aReport.lineNumber(),
+                                                aReport.columnNumber(),
+                                                aReport.flags(),
                                                 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);
+    for (size_t i = 0, len = aReport.notes().Length(); i < len; i++) {
+      const ErrorDataNote& note = aReport.notes().ElementAt(i);
 
       nsScriptErrorNote* noteObject = new nsScriptErrorNote();
-      noteObject->Init(note.mMessage, note.mFilename,
-                       note.mLineNumber, note.mColumnNumber);
+      noteObject->Init(note.message(), note.filename(),
+                       note.lineNumber(), note.columnNumber());
       scriptError->AddNote(noteObject);
     }
   }
 
   nsCOMPtr<nsIConsoleService> consoleService =
     do_GetService(NS_CONSOLESERVICE_CONTRACTID);
   NS_WARNING_ASSERTION(consoleService, "Failed to get console service!");
 
   if (consoleService) {
     if (scriptError) {
       if (NS_SUCCEEDED(consoleService->LogMessage(scriptError))) {
         return;
       }
       NS_WARNING("LogMessage failed!");
     } else if (NS_SUCCEEDED(consoleService->LogStringMessage(
-                              aReport.mMessage.BeginReading()))) {
+                              aReport.message().BeginReading()))) {
       return;
     }
     NS_WARNING("LogStringMessage failed!");
   }
 
-  NS_ConvertUTF16toUTF8 msg(aReport.mMessage);
-  NS_ConvertUTF16toUTF8 filename(aReport.mFilename);
+  NS_ConvertUTF16toUTF8 msg(aReport.message());
+  NS_ConvertUTF16toUTF8 filename(aReport.filename());
 
   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(), aReport.mLineNumber);
+                      filename.get(), aReport.lineNumber());
 #endif
 
-  fprintf(stderr, kErrorString, msg.get(), filename.get(), aReport.mLineNumber);
+  fprintf(stderr, kErrorString, msg.get(), filename.get(), aReport.lineNumber());
   fflush(stderr);
 }
 
 /* static */ void
 WorkerErrorReport::CreateAndDispatchGenericErrorRunnableToParent(WorkerPrivate* aWorkerPrivate)
 {
   ReportGenericErrorRunnable::CreateAndDispatch(aWorkerPrivate);
 }
--- a/dom/workers/WorkerError.h
+++ b/dom/workers/WorkerError.h
@@ -2,25 +2,26 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* 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_workers_WorkerError_h
 #define mozilla_dom_workers_WorkerError_h
 
-#include "WorkerCommon.h"
+#include "mozilla/dom/WorkerCommon.h"
 #include "jsapi.h"
 
 namespace mozilla {
 
 class DOMEventTargetHelper;
 
 namespace dom {
 
+class ErrorData;
 class WorkerErrorBase
 {
 public:
   nsString mMessage;
   nsString mFilename;
   uint32_t mLineNumber;
   uint32_t mColumnNumber;
   uint32_t mErrorNumber;
@@ -67,15 +68,18 @@ public:
               bool aFireAtScope, DOMEventTargetHelper* aTarget,
               const WorkerErrorReport& aReport, uint64_t aInnerWindowId,
               JS::Handle<JS::Value> aException = JS::NullHandleValue);
 
   static void
   LogErrorToConsole(const WorkerErrorReport& aReport, uint64_t aInnerWindowId);
 
   static void
+  LogErrorToConsole(const mozilla::dom::ErrorData& aReport, uint64_t aInnerWindowId);
+
+  static void
   CreateAndDispatchGenericErrorRunnableToParent(WorkerPrivate* aWorkerPrivate);
 };
 
 } // dom namespace
 } // mozilla namespace
 
 #endif // mozilla_dom_workers_WorkerError_h
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -14,29 +14,28 @@
 #include "mozilla/ScopeExit.h"
 #include "mozilla/StaticPrefs.h"
 #include "mozilla/dom/BlobURLProtocolHandler.h"
 #include "mozilla/dom/ClientManager.h"
 #include "mozilla/dom/ClientSource.h"
 #include "mozilla/dom/ClientState.h"
 #include "mozilla/dom/Console.h"
 #include "mozilla/dom/DOMTypes.h"
-#include "mozilla/dom/ErrorEvent.h"
-#include "mozilla/dom/ErrorEventBinding.h"
 #include "mozilla/dom/Event.h"
 #include "mozilla/dom/FunctionBinding.h"
 #include "mozilla/dom/IndexedDatabaseManager.h"
 #include "mozilla/dom/MessageEvent.h"
 #include "mozilla/dom/MessageEventBinding.h"
 #include "mozilla/dom/MessagePort.h"
 #include "mozilla/dom/MessagePortBinding.h"
 #include "mozilla/dom/nsCSPUtils.h"
 #include "mozilla/dom/Performance.h"
 #include "mozilla/dom/PerformanceStorageWorker.h"
 #include "mozilla/dom/PromiseDebugging.h"
+#include "mozilla/dom/SharedWorkerManager.h"
 #include "mozilla/dom/WorkerBinding.h"
 #include "mozilla/ThreadEventQueue.h"
 #include "mozilla/ThrottledEventQueue.h"
 #include "mozilla/TimelineConsumers.h"
 #include "mozilla/WorkerTimelineMarker.h"
 #include "nsCycleCollector.h"
 #include "nsGlobalWindowInner.h"
 #include "nsNetUtil.h"
@@ -52,17 +51,16 @@
 #include "nsRFPService.h"
 #include "nsSandboxFlags.h"
 #include "nsUTF8Utils.h"
 
 #include "RuntimeService.h"
 #include "ScriptLoader.h"
 #include "mozilla/dom/ServiceWorkerEvents.h"
 #include "mozilla/dom/ServiceWorkerManager.h"
-#include "mozilla/dom/SharedWorker.h"
 #include "WorkerCSPEventListener.h"
 #include "WorkerDebugger.h"
 #include "WorkerDebuggerManager.h"
 #include "WorkerError.h"
 #include "WorkerEventTarget.h"
 #include "WorkerNavigator.h"
 #include "WorkerRef.h"
 #include "WorkerRunnable.h"
@@ -2080,180 +2078,16 @@ WorkerPrivate::MemoryPressure(bool aDumm
 {
   AssertIsOnParentThread();
 
   RefPtr<MemoryPressureRunnable> runnable = new MemoryPressureRunnable(this);
   Unused << NS_WARN_IF(!runnable->Dispatch());
 }
 
 void
-WorkerPrivate::BroadcastErrorToSharedWorkers(
-                                     JSContext* aCx,
-                                     const WorkerErrorReport* aReport,
-                                     bool aIsErrorEvent)
-{
-  AssertIsOnMainThread();
-
-  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?
-    MOZ_ASSERT(aReport);
-    WorkerErrorReport::LogErrorToConsole(*aReport, 0);
-    return;
-  }
-
-  AutoTArray<RefPtr<SharedWorker>, 10> sharedWorkers;
-  GetAllSharedWorkers(sharedWorkers);
-
-  if (sharedWorkers.IsEmpty()) {
-    return;
-  }
-
-  AutoTArray<WindowAction, 10> windowActions;
-
-  // First fire the error event at all SharedWorker objects. This may include
-  // multiple objects in a single window as well as objects in different
-  // windows.
-  for (size_t index = 0; index < sharedWorkers.Length(); index++) {
-    RefPtr<SharedWorker>& sharedWorker = sharedWorkers[index];
-
-    // May be null.
-    nsPIDOMWindowInner* window = sharedWorker->GetOwner();
-
-    RefPtr<Event> event;
-
-    if (aIsErrorEvent) {
-      RootedDictionary<ErrorEventInit> errorInit(aCx);
-      errorInit.mBubbles = false;
-      errorInit.mCancelable = true;
-      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);
-    } else {
-      event = Event::Constructor(sharedWorker, NS_LITERAL_STRING("error"),
-                                 EventInit());
-    }
-
-    if (!event) {
-      ThrowAndReport(window, NS_ERROR_UNEXPECTED);
-      continue;
-    }
-
-    event->SetTrusted(true);
-
-    ErrorResult res;
-    bool defaultActionEnabled =
-      sharedWorker->DispatchEvent(*event, CallerType::System, res);
-    if (res.Failed()) {
-      ThrowAndReport(window, res.StealNSResult());
-      continue;
-    }
-
-    if (!aIsErrorEvent) {
-      continue;
-    }
-
-    if (defaultActionEnabled) {
-      // Add the owning window to our list so that we will fire an error event
-      // at it later.
-      if (!windowActions.Contains(window)) {
-        windowActions.AppendElement(WindowAction(window));
-      }
-    } else {
-      size_t actionsIndex = windowActions.LastIndexOf(WindowAction(window));
-      if (actionsIndex != windowActions.NoIndex) {
-        // Any listener that calls preventDefault() will prevent the window from
-        // receiving the error event.
-        windowActions[actionsIndex].mDefaultAction = false;
-      }
-    }
-  }
-
-  // If there are no windows to consider further then we're done.
-  if (windowActions.IsEmpty()) {
-    return;
-  }
-
-  bool shouldLogErrorToConsole = true;
-
-  // Now fire error events at all the windows remaining.
-  for (uint32_t index = 0; index < windowActions.Length(); index++) {
-    WindowAction& windowAction = windowActions[index];
-
-    // If there is no window or the script already called preventDefault then
-    // skip this window.
-    if (!windowAction.mWindow || !windowAction.mDefaultAction) {
-      continue;
-    }
-
-    nsCOMPtr<nsIScriptGlobalObject> sgo =
-      do_QueryInterface(windowAction.mWindow);
-    MOZ_ASSERT(sgo);
-
-    MOZ_ASSERT(NS_IsMainThread());
-    RootedDictionary<ErrorEventInit> init(aCx);
-    init.mLineno = aReport->mLineNumber;
-    init.mFilename = aReport->mFilename;
-    init.mMessage = aReport->mMessage;
-    init.mCancelable = true;
-    init.mBubbles = true;
-
-    nsEventStatus status = nsEventStatus_eIgnore;
-    if (!sgo->HandleScriptError(init, &status)) {
-      ThrowAndReport(windowAction.mWindow, NS_ERROR_UNEXPECTED);
-      continue;
-    }
-
-    if (status == nsEventStatus_eConsumeNoDefault) {
-      shouldLogErrorToConsole = false;
-    }
-  }
-
-  // Finally log a warning in the console if no window tried to prevent it.
-  if (shouldLogErrorToConsole) {
-    MOZ_ASSERT(aReport);
-    WorkerErrorReport::LogErrorToConsole(*aReport, 0);
-  }
-}
-
-void
-WorkerPrivate::GetAllSharedWorkers(nsTArray<RefPtr<SharedWorker>>& aSharedWorkers)
-{
-  AssertIsOnMainThread();
-  MOZ_ASSERT(IsSharedWorker() || IsServiceWorker());
-
-  if (!aSharedWorkers.IsEmpty()) {
-    aSharedWorkers.Clear();
-  }
-
-  for (uint32_t i = 0; i < mSharedWorkers.Length(); ++i) {
-    aSharedWorkers.AppendElement(mSharedWorkers[i]);
-  }
-}
-
-void
-WorkerPrivate::CloseAllSharedWorkers()
-{
-  AssertIsOnMainThread();
-  MOZ_ASSERT(IsSharedWorker() || IsServiceWorker());
-
-  for (uint32_t i = 0; i < mSharedWorkers.Length(); ++i) {
-    mSharedWorkers[i]->Close();
-  }
-
-  mSharedWorkers.Clear();
-
-  Cancel();
-}
-
-void
 WorkerPrivate::WorkerScriptLoaded()
 {
   AssertIsOnMainThread();
 
   if (IsSharedWorker() || IsServiceWorker()) {
     // No longer need to hold references to the window or document we came from.
     mLoadInfo.mWindow = nullptr;
     mLoadInfo.mScriptContext = nullptr;
@@ -2353,60 +2187,16 @@ void
 WorkerPrivate::UpdateOverridenLoadGroup(nsILoadGroup* aBaseLoadGroup)
 {
   AssertIsOnMainThread();
 
   // The load group should have been overriden at init time.
   mLoadInfo.mInterfaceRequestor->MaybeAddTabChild(aBaseLoadGroup);
 }
 
-void
-WorkerPrivate::FlushReportsToSharedWorkers(nsIConsoleReportCollector* aReporter)
-{
-  AssertIsOnMainThread();
-
-  AutoTArray<RefPtr<SharedWorker>, 10> sharedWorkers;
-  AutoTArray<WindowAction, 10> windowActions;
-  GetAllSharedWorkers(sharedWorkers);
-
-  // First find out all the shared workers' window.
-  for (size_t index = 0; index < sharedWorkers.Length(); index++) {
-    RefPtr<SharedWorker>& sharedWorker = sharedWorkers[index];
-
-    // May be null.
-    nsPIDOMWindowInner* window = sharedWorker->GetOwner();
-
-    // Add the owning window to our list so that we will flush the reports later.
-    if (window && !windowActions.Contains(window)) {
-      windowActions.AppendElement(WindowAction(window));
-    }
-  }
-
-  bool reportErrorToBrowserConsole = true;
-
-  // Flush the reports.
-  for (uint32_t index = 0; index < windowActions.Length(); index++) {
-    WindowAction& windowAction = windowActions[index];
-
-    aReporter->FlushReportsToConsole(
-      windowAction.mWindow->WindowID(),
-      nsIConsoleReportCollector::ReportAction::Save);
-    reportErrorToBrowserConsole = false;
-  }
-
-  // Finally report to browser console if there is no any window or shared
-  // worker.
-  if (reportErrorToBrowserConsole) {
-    aReporter->FlushReportsToConsole(0);
-    return;
-  }
-
-  aReporter->ClearConsoleReports();
-}
-
 #ifdef DEBUG
 
 void
 WorkerPrivate::AssertIsOnParentThread() const
 {
   if (GetParent()) {
     GetParent()->AssertIsOnWorkerThread();
   } else {
@@ -5279,16 +5069,34 @@ WorkerPrivate::GetPerformanceCounter()
 PerformanceStorage*
 WorkerPrivate::GetPerformanceStorage()
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(mPerformanceStorage);
   return mPerformanceStorage;
 }
 
+void
+WorkerPrivate::SetSharedWorkerManager(SharedWorkerManager* aManager)
+{
+  AssertIsOnMainThread();
+  MOZ_ASSERT(aManager);
+  MOZ_ASSERT(!mSharedWorkerManager);
+
+  mSharedWorkerManager = aManager;
+}
+
+SharedWorkerManager*
+WorkerPrivate::GetSharedWorkerManager()
+{
+  AssertIsOnMainThread();
+  MOZ_ASSERT(mSharedWorkerManager);
+  return mSharedWorkerManager;
+}
+
 NS_IMPL_ADDREF(WorkerPrivate::EventTarget)
 NS_IMPL_RELEASE(WorkerPrivate::EventTarget)
 
 NS_INTERFACE_MAP_BEGIN(WorkerPrivate::EventTarget)
   NS_INTERFACE_MAP_ENTRY(nsISerialEventTarget)
   NS_INTERFACE_MAP_ENTRY(nsIEventTarget)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 #ifdef DEBUG
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -18,17 +18,16 @@
 #include "mozilla/dom/Worker.h"
 #include "mozilla/dom/WorkerHolder.h"
 #include "mozilla/dom/WorkerLoadInfo.h"
 #include "mozilla/dom/workerinternals/JSSettings.h"
 #include "mozilla/dom/workerinternals/Queue.h"
 #include "mozilla/PerformanceCounter.h"
 #include "mozilla/ThreadBound.h"
 
-class nsIConsoleReportCollector;
 class nsIThreadInternal;
 
 namespace mozilla {
 class ThrottledEventQueue;
 namespace dom {
 
 // If you change this, the corresponding list in nsIWorkerDebugger.idl needs
 // to be updated too.
@@ -40,17 +39,17 @@ enum WorkerType
 };
 
 class ClientInfo;
 class ClientSource;
 class Function;
 class MessagePort;
 class MessagePortIdentifier;
 class PerformanceStorage;
-class SharedWorker;
+class SharedWorkerManager;
 class WorkerControlRunnable;
 class WorkerCSPEventListener;
 class WorkerDebugger;
 class WorkerDebuggerGlobalScope;
 class WorkerErrorReport;
 class WorkerEventTarget;
 class WorkerGlobalScope;
 class WorkerRunnable;
@@ -1075,29 +1074,21 @@ public:
   // top level script.
   void
   SetLoadingWorkerScript(bool aLoadingWorkerScript)
   {
     // any thread
     mLoadingWorkerScript = aLoadingWorkerScript;
   }
 
-  void
-  BroadcastErrorToSharedWorkers(JSContext* aCx,
-                                const WorkerErrorReport* aReport,
-                                bool aIsErrorEvent);
+  SharedWorkerManager*
+  GetSharedWorkerManager();
 
   void
-  GetAllSharedWorkers(nsTArray<RefPtr<SharedWorker>>& aSharedWorkers);
-
-  void
-  CloseAllSharedWorkers();
-
-  void
-  FlushReportsToSharedWorkers(nsIConsoleReportCollector* aReporter);
+  SetSharedWorkerManager(SharedWorkerManager* aWorkerManager);
 
   // We can assume that an nsPIDOMWindow will be available for Freeze, Thaw
   // as these are only used for globals going in and out of the bfcache.
   bool
   Freeze(nsPIDOMWindowInner* aWindow);
 
   bool
   Thaw(nsPIDOMWindowInner* aWindow);
@@ -1396,19 +1387,18 @@ private:
 
   RefPtr<PerformanceStorage> mPerformanceStorage;
 
   RefPtr<WorkerCSPEventListener> mCSPEventListener;
 
   // Protected by mMutex.
   nsTArray<RefPtr<WorkerRunnable>> mPreStartRunnables;
 
-  // Only touched on the parent thread (currently this is always the main
-  // thread as SharedWorkers are always top-level).
-  nsTArray<RefPtr<SharedWorker>> mSharedWorkers;
+  // Only touched on the parent thread. This is set only if IsSharedWorker().
+  RefPtr<SharedWorkerManager> mSharedWorkerManager;
 
   JS::UniqueChars mDefaultLocale; // nulled during worker JSContext init
   TimeStamp mKillTime;
   WorkerStatus mParentStatus;
   WorkerStatus mStatus;
 
   // This is touched on parent thread only, but it can be read on a different
   // thread before crashing because hanging.
--- a/dom/workers/moz.build
+++ b/dom/workers/moz.build
@@ -11,16 +11,17 @@ DIRS += ['sharedworkers']
 
 # Public stuff.
 EXPORTS.mozilla.dom += [
     'ChromeWorker.h',
     'Worker.h',
     'WorkerCommon.h',
     'WorkerDebugger.h',
     'WorkerDebuggerManager.h',
+    'WorkerError.h',
     'WorkerHolder.h',
     'WorkerHolderToken.h',
     'WorkerLoadInfo.h',
     'WorkerLocation.h',
     'WorkerNavigator.h',
     'WorkerPrivate.h',
     'WorkerRef.h',
     'WorkerRunnable.h',
--- a/dom/workers/sharedworkers/PSharedWorker.ipdl
+++ b/dom/workers/sharedworkers/PSharedWorker.ipdl
@@ -1,28 +1,31 @@
 /* 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 protocol PBackground;
 
+include SharedWorkerTypes;
+
 namespace mozilla {
 namespace dom {
 
 protocol PSharedWorker
 {
   manager PBackground;
 
 parent:
   async Close();
   async Suspend();
   async Resume();
   async Freeze();
   async Thaw();
 
 child:
-  async Error(nsresult error);
+  async Error(ErrorValue value);
+  async Terminate();
 
   async __delete__();
 };
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/workers/sharedworkers/SharedWorker.cpp
+++ b/dom/workers/sharedworkers/SharedWorker.cpp
@@ -158,17 +158,18 @@ SharedWorker::Constructor(const GlobalOb
   } else {
     ipcClientInfo = void_t();
   }
 
   SharedWorkerLoadInfo sharedWorkerLoadInfo(nsString(aScriptURL), baseURL,
                                             resolvedScriptURL, name,
                                             loadingPrincipalInfo, principalInfo,
                                             loadInfo.mDomain, isSecureContext,
-                                            ipcClientInfo, portIdentifier);
+                                            loadInfo.mWindowID, ipcClientInfo,
+                                            portIdentifier);
 
   PSharedWorkerChild* pActor =
     actorChild->SendPSharedWorkerConstructor(sharedWorkerLoadInfo);
 
   RefPtr<SharedWorkerChild> actor = static_cast<SharedWorkerChild*>(pActor);
   MOZ_ASSERT(actor);
 
   RefPtr<SharedWorker> sharedWorker = new SharedWorker(window, actor,
--- a/dom/workers/sharedworkers/SharedWorkerChild.cpp
+++ b/dom/workers/sharedworkers/SharedWorkerChild.cpp
@@ -1,15 +1,18 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* 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 "SharedWorkerChild.h"
+#include "mozilla/dom/ErrorEvent.h"
+#include "mozilla/dom/ErrorEventBinding.h"
+#include "mozilla/dom/WorkerError.h"
 
 namespace mozilla {
 
 using namespace ipc;
 
 namespace dom {
 
 SharedWorkerChild::SharedWorkerChild()
@@ -64,21 +67,122 @@ void
 SharedWorkerChild::SendThaw()
 {
   if (mActive) {
     PSharedWorkerChild::SendThaw();
   }
 }
 
 IPCResult
-SharedWorkerChild::RecvError(const nsresult& aError)
+SharedWorkerChild::RecvError(const ErrorValue& aValue)
 {
-  MOZ_ASSERT(mActive);
+  if (!mParent) {
+    return IPC_OK();
+  }
+
+  if (aValue.type() == ErrorValue::Tnsresult) {
+    mParent->ErrorPropagation(aValue.get_nsresult());
+    return IPC_OK();
+  }
+
+  if (aValue.type() == ErrorValue::TErrorData &&
+      JSREPORT_IS_WARNING(aValue.get_ErrorData().flags())) {
+    // Don't fire any events anywhere.  Just log to console.
+    // XXXbz should we log to all the consoles of all the relevant windows?
+    WorkerErrorReport::LogErrorToConsole(aValue.get_ErrorData(), 0);
+    return IPC_OK();
+  }
+
+  // May be null.
+  nsPIDOMWindowInner* window = mParent->GetOwner();
+
+  RefPtr<Event> event;
+
+  AutoJSAPI jsapi;
+  jsapi.Init();
+
+  if (aValue.type() == ErrorValue::TErrorData) {
+    const ErrorData& errorData = aValue.get_ErrorData();
+    RootedDictionary<ErrorEventInit> errorInit(jsapi.cx());
+    errorInit.mBubbles = false;
+    errorInit.mCancelable = true;
+    errorInit.mMessage = errorData.message();
+    errorInit.mFilename = errorData.filename();
+    errorInit.mLineno = errorData.lineNumber();
+    errorInit.mColno = errorData.columnNumber();
+
+    event = ErrorEvent::Constructor(mParent, NS_LITERAL_STRING("error"),
+                                    errorInit);
+  } else {
+    event = Event::Constructor(mParent, NS_LITERAL_STRING("error"),
+                               EventInit());
+  }
+
+  if (!event) {
+    ThrowAndReport(window, NS_ERROR_UNEXPECTED);
+    return IPC_OK();
+  }
+
+  event->SetTrusted(true);
 
+  ErrorResult res;
+  bool defaultActionEnabled =
+    mParent->DispatchEvent(*event, CallerType::System, res);
+  if (res.Failed()) {
+    ThrowAndReport(window, res.StealNSResult());
+    return IPC_OK();
+  }
+
+  if (aValue.type() != ErrorValue::TErrorData) {
+     MOZ_ASSERT(aValue.type() == ErrorValue::Tvoid_t);
+     return IPC_OK();
+  }
+
+  if (!defaultActionEnabled) {
+    return IPC_OK();
+  }
+
+  bool shouldLogErrorToConsole = true;
+
+  nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(window);
+  MOZ_ASSERT(sgo);
+
+  const ErrorData& errorData = aValue.get_ErrorData();
+
+  MOZ_ASSERT(NS_IsMainThread());
+  RootedDictionary<ErrorEventInit> errorInit(jsapi.cx());
+  errorInit.mLineno = errorData.lineNumber();
+  errorInit.mColno = errorData.columnNumber();
+  errorInit.mFilename = errorData.filename();
+  errorInit.mMessage = errorData.message();
+  errorInit.mCancelable = true;
+  errorInit.mBubbles = true;
+
+  nsEventStatus status = nsEventStatus_eIgnore;
+  if (!sgo->HandleScriptError(errorInit, &status)) {
+    ThrowAndReport(window, NS_ERROR_UNEXPECTED);
+    return IPC_OK();
+  }
+
+  if (status == nsEventStatus_eConsumeNoDefault) {
+    shouldLogErrorToConsole = false;
+  }
+
+  // Finally log a warning in the console if no window tried to prevent it.
+  if (shouldLogErrorToConsole) {
+    WorkerErrorReport::LogErrorToConsole(aValue.get_ErrorData(), 0);
+  }
+
+  return IPC_OK();
+}
+
+IPCResult
+SharedWorkerChild::RecvTerminate()
+{
   if (mParent) {
-    mParent->ErrorPropagation(aError);
+    mParent->Close();
   }
 
   return IPC_OK();
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/workers/sharedworkers/SharedWorkerChild.h
+++ b/dom/workers/sharedworkers/SharedWorkerChild.h
@@ -42,17 +42,20 @@ public:
 
   void
   SendThaw();
 
 private:
   ~SharedWorkerChild();
 
   mozilla::ipc::IPCResult
-  RecvError(const nsresult& error) override;
+  RecvError(const ErrorValue& aValue) override;
+
+  mozilla::ipc::IPCResult
+  RecvTerminate() override;
 
   void
   ActorDestroy(ActorDestroyReason aWhy) override;
 
   // Raw pointer because mParent is set to null when released.
   SharedWorker* MOZ_NON_OWNING_REF mParent;
   bool mActive;
 };
--- a/dom/workers/sharedworkers/SharedWorkerManager.cpp
+++ b/dom/workers/sharedworkers/SharedWorkerManager.cpp
@@ -3,20 +3,23 @@
 /* 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 "SharedWorkerManager.h"
 #include "SharedWorkerParent.h"
 #include "SharedWorkerService.h"
 #include "mozilla/dom/IndexedDatabaseManager.h"
+#include "mozilla/dom/PSharedWorker.h"
+#include "mozilla/dom/WorkerError.h"
 #include "mozilla/dom/WorkerPrivate.h"
 #include "mozilla/dom/WorkerRunnable.h"
 #include "mozilla/dom/workerinternals/ScriptLoader.h"
 #include "mozilla/ipc/BackgroundParent.h"
+#include "nsIConsoleReportCollector.h"
 #include "nsIPrincipal.h"
 #include "nsNetUtil.h"
 #include "nsProxyRelease.h"
 
 namespace mozilla {
 namespace dom {
 
 using workerinternals::ChannelFromScriptURLMainThread;
@@ -48,20 +51,22 @@ private:
   {
     MessagePort::ForceClose(mPortIdentifier);
     return WorkerRunnable::Cancel();
   }
 };
 
 } // anonymous
 
-SharedWorkerManager::SharedWorkerManager(const SharedWorkerLoadInfo& aInfo,
+SharedWorkerManager::SharedWorkerManager(nsIEventTarget* aPBackgroundEventTarget,
+                                         const SharedWorkerLoadInfo& aInfo,
                                          nsIPrincipal* aPrincipal,
                                          nsIPrincipal* aLoadingPrincipal)
-  : mInfo(aInfo)
+  : mPBackgroundEventTarget(aPBackgroundEventTarget)
+  , mInfo(aInfo)
   , mPrincipal(aPrincipal)
   , mLoadingPrincipal(aLoadingPrincipal)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aPrincipal);
   MOZ_ASSERT(aLoadingPrincipal);
 }
 
@@ -159,16 +164,17 @@ SharedWorkerManager::CreateWorkerOnMainT
                                               WorkerTypeShared,
                                               mInfo.name(),
                                               VoidCString(),
                                               &info, error);
   if (NS_WARN_IF(error.Failed())) {
     return error.StealNSResult();
   }
 
+  mWorkerPrivate->SetSharedWorkerManager(this);
   return NS_OK;
 }
 
 nsresult
 SharedWorkerManager::ConnectPortOnMainThread(const MessagePortIdentifier& aPortIdentifier)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
@@ -308,52 +314,177 @@ SharedWorkerManager::IsSecureContext() c
 {
   return mInfo.isSecureContext();
 }
 
 void
 SharedWorkerManager::FreezeOnMainThread()
 {
   MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(mWorkerPrivate);
+
+  if (!mWorkerPrivate || mWorkerPrivate->IsFrozen()) {
+    // Already released.
+    return;
+  }
 
   mWorkerPrivate->Freeze(nullptr);
 }
 
 void
 SharedWorkerManager::ThawOnMainThread()
 {
   MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(mWorkerPrivate);
+
+  if (!mWorkerPrivate || !mWorkerPrivate->IsFrozen()) {
+    // Already released.
+    return;
+  }
 
   mWorkerPrivate->Thaw(nullptr);
 }
 
 void
 SharedWorkerManager::SuspendOnMainThread()
 {
   MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(mWorkerPrivate);
+
+  if (!mWorkerPrivate) {
+    // Already released.
+    return;
+  }
 
   mWorkerPrivate->ParentWindowPaused();
 }
 
 void
 SharedWorkerManager::ResumeOnMainThread()
 {
   MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(mWorkerPrivate);
+
+  if (!mWorkerPrivate) {
+    // Already released.
+    return;
+  }
 
   mWorkerPrivate->ParentWindowResumed();
 }
 
 void
 SharedWorkerManager::CloseOnMainThread()
 {
   MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(mWorkerPrivate);
+
+  if (!mWorkerPrivate) {
+    // Already released.
+    return;
+  }
 
   mWorkerPrivate->Cancel();
   mWorkerPrivate = nullptr;
 }
 
+void
+SharedWorkerManager::BroadcastErrorToActorsOnMainThread(const WorkerErrorReport* aReport,
+                                                        bool aIsErrorEvent)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  ErrorValue value;
+  if (aIsErrorEvent) {
+    nsTArray<ErrorDataNote> notes;
+    for (size_t i = 0, len = aReport->mNotes.Length(); i < len; i++) {
+      const WorkerErrorNote& note = aReport->mNotes.ElementAt(i);
+      notes.AppendElement(ErrorDataNote(note.mLineNumber, note.mColumnNumber,
+                                        note.mMessage, note.mFilename));
+    }
+
+    ErrorData data(aReport->mLineNumber,
+                   aReport->mColumnNumber,
+                   aReport->mFlags,
+                   aReport->mMessage,
+                   aReport->mFilename,
+                   aReport->mLine,
+                   notes);
+    value = data;
+  } else {
+    value = void_t();
+  }
+
+  RefPtr<SharedWorkerManager> self = this;
+  nsCOMPtr<nsIRunnable> r =
+    NS_NewRunnableFunction("SharedWorkerManager::BroadcastErrorToActorsOnMainThread",
+                           [self, value]() {
+    self->BroadcastErrorToActors(value);
+  });
+
+  mPBackgroundEventTarget->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
+}
+
+void
+SharedWorkerManager::BroadcastErrorToActors(const ErrorValue& aValue)
+{
+  AssertIsOnBackgroundThread();
+
+  for (SharedWorkerParent* actor : mActors) {
+    Unused << actor->SendError(aValue);
+  }
+}
+
+void
+SharedWorkerManager::CloseActorsOnMainThread()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  CloseOnMainThread();
+
+  RefPtr<SharedWorkerManager> self = this;
+  nsCOMPtr<nsIRunnable> r =
+    NS_NewRunnableFunction("SharedWorkerManager::CloseActorsOnMainThread",
+                           [self]() {
+    self->CloseActors();
+  });
+
+  mPBackgroundEventTarget->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
+}
+
+void
+SharedWorkerManager::CloseActors()
+{
+  AssertIsOnBackgroundThread();
+
+  for (SharedWorkerParent* actor : mActors) {
+    Unused << actor->SendTerminate();
+  }
+}
+
+void
+SharedWorkerManager::FlushReportsToActorsOnMainThread(nsIConsoleReportCollector* aReporter)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  AutoTArray<uint64_t, 10> windowIDs;
+  for (SharedWorkerParent* actor : mActors) {
+    uint64_t windowID = actor->WindowID();
+    if (windowID && !windowIDs.Contains(windowID)) {
+      windowIDs.AppendElement(windowID);
+    }
+  }
+
+  bool reportErrorToBrowserConsole = true;
+
+  // Flush the reports.
+  for (uint32_t index = 0; index < windowIDs.Length(); index++) {
+    aReporter->FlushReportsToConsole(windowIDs[index],
+      nsIConsoleReportCollector::ReportAction::Save);
+    reportErrorToBrowserConsole = false;
+  }
+
+  // Finally report to browser console if there is no any window or shared
+  // worker.
+  if (reportErrorToBrowserConsole) {
+    aReporter->FlushReportsToConsole(0);
+    return;
+  }
+
+  aReporter->ClearConsoleReports();
+}
+
 } // dom namespace
 } // mozilla namespace
--- a/dom/workers/sharedworkers/SharedWorkerManager.h
+++ b/dom/workers/sharedworkers/SharedWorkerManager.h
@@ -2,40 +2,45 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* 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_SharedWorkerManager_h
 #define mozilla_dom_SharedWorkerManager_h
 
+#include "mozilla/dom/SharedWorkerTypes.h"
 #include "nsISupportsImpl.h"
 #include "nsTArray.h"
 
+class nsIConsoleReportCollector;
 class nsIPrincipal;
 
 namespace mozilla {
 namespace dom {
 
+class ErrorValue;
 class SharedWorkerLoadInfo;
 class SharedWorkerParent;
+class WorkerErrorReport;
 class WorkerPrivate;
 
 class SharedWorkerManager final
 {
 public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SharedWorkerManager);
 
   // Called on main-thread thread methods
 
-  SharedWorkerManager(const SharedWorkerLoadInfo& aInfo,
+  SharedWorkerManager(nsIEventTarget* aPBackgroundEventTarget,
+                      const SharedWorkerLoadInfo& aInfo,
                       nsIPrincipal* aPrincipal,
                       nsIPrincipal* aLoadingPrincipal);
 
-  nsresult 
+  nsresult
   CreateWorkerOnMainThread();
 
   nsresult
   ConnectPortOnMainThread(const MessagePortIdentifier& aPortIdentifier);
 
   bool
   MatchOnMainThread(const nsACString& aDomain,
                     const nsACString& aScriptURL,
@@ -52,16 +57,26 @@ public:
   ThawOnMainThread();
 
   void
   SuspendOnMainThread();
 
   void
   ResumeOnMainThread();
 
+  void
+  BroadcastErrorToActorsOnMainThread(const WorkerErrorReport* aReport,
+                                     bool aIsErrorEvent);
+
+  void
+  CloseActorsOnMainThread();
+
+  void
+  FlushReportsToActorsOnMainThread(nsIConsoleReportCollector* aReporter);
+
   // Called on PBackground thread methods
 
   void
   AddActor(SharedWorkerParent* aParent);
 
   void
   RemoveActor(SharedWorkerParent* aParent);
 
@@ -69,19 +84,27 @@ public:
   UpdateSuspend();
 
   void
   UpdateFrozen();
 
   bool
   IsSecureContext() const;
 
+  void
+  CloseActors();
+
+  void
+  BroadcastErrorToActors(const ErrorValue& aValue);
+
 private:
   ~SharedWorkerManager();
 
+  nsCOMPtr<nsIEventTarget> mPBackgroundEventTarget;
+
   SharedWorkerLoadInfo mInfo;
   nsCOMPtr<nsIPrincipal> mPrincipal;
   nsCOMPtr<nsIPrincipal> mLoadingPrincipal;
 
   // Raw pointers because SharedWorkerParent unregisters itself in ActorDestroy().
   nsTArray<SharedWorkerParent*> mActors;
 
   // With this patch, SharedWorker are executed on the parent process.
--- a/dom/workers/sharedworkers/SharedWorkerParent.cpp
+++ b/dom/workers/sharedworkers/SharedWorkerParent.cpp
@@ -15,16 +15,17 @@ namespace mozilla {
 
 using namespace ipc;
 
 namespace dom {
 
 SharedWorkerParent::SharedWorkerParent()
   : mBackgroundEventTarget(GetCurrentThreadEventTarget())
   , mStatus(eInit)
+  , mWindowID(0)
   , mSuspended(false)
   , mFrozen(false)
 {
   AssertIsOnBackgroundThread();
 }
 
 SharedWorkerParent::~SharedWorkerParent() = default;
 
@@ -44,16 +45,19 @@ SharedWorkerParent::Initialize(const Sha
 {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(mStatus == eInit);
 
   // Let's keep the service alive.
   mService = SharedWorkerService::GetOrCreate();
   MOZ_ASSERT(mService);
 
+  // This is the only information we currently care.
+  mWindowID = aInfo.windowID();
+
   mStatus = ePending;
   mService->GetOrCreateWorkerManager(this, aInfo);
 }
 
 IPCResult
 SharedWorkerParent::RecvClose()
 {
   AssertIsOnBackgroundThread();
--- a/dom/workers/sharedworkers/SharedWorkerParent.h
+++ b/dom/workers/sharedworkers/SharedWorkerParent.h
@@ -56,16 +56,22 @@ public:
   }
 
   bool
   IsFrozen() const
   {
     return mSuspended;
   }
 
+  uint64_t
+  WindowID() const
+  {
+    return mWindowID;
+  }
+
 private:
   ~SharedWorkerParent();
 
   void
   ActorDestroy(IProtocol::ActorDestroyReason aReason) override;
 
   nsCOMPtr<nsIEventTarget> mBackgroundEventTarget;
   RefPtr<SharedWorkerManager> mWorkerManager;
@@ -73,16 +79,18 @@ private:
 
   enum {
     eInit,
     ePending,
     eActive,
     eClosed,
   } mStatus;
 
+  uint64_t mWindowID;
+
   bool mSuspended;
   bool mFrozen;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_dom_SharedWorkerParent_h
--- a/dom/workers/sharedworkers/SharedWorkerService.cpp
+++ b/dom/workers/sharedworkers/SharedWorkerService.cpp
@@ -215,17 +215,18 @@ SharedWorkerService::GetOrCreateWorkerMa
                                          aInfo.name(), loadingPrincipal)) {
       manager = workerManager;
       break;
     }
   }
 
   // Let's create a new one.
   if (!manager) {
-    manager = new SharedWorkerManager(aInfo, principal, loadingPrincipal);
+    manager = new SharedWorkerManager(aBackgroundEventTarget, aInfo,
+                                      principal, loadingPrincipal);
 
     rv = manager->CreateWorkerOnMainThread();
     if (NS_WARN_IF(NS_FAILED(rv))) {
       ErrorPropagationOnMainThread(aBackgroundEventTarget, aActor, rv);
       return;
     }
 
     mWorkerManagers.AppendElement(manager);
--- a/dom/workers/sharedworkers/SharedWorkerTypes.ipdlh
+++ b/dom/workers/sharedworkers/SharedWorkerTypes.ipdlh
@@ -21,15 +21,46 @@ struct SharedWorkerLoadInfo
 
   PrincipalInfo loadingPrincipalInfo;
   PrincipalInfo principalInfo;
 
   nsCString domain;
 
   bool isSecureContext;
 
+  uint64_t windowID;
+
   OptionalIPCClientInfo clientInfo;
 
   MessagePortIdentifier portIdentifier;
 };
 
+// ErrorData/ErrorDataNote correspond to WorkerErrorReport/WorkerErrorNote
+// which in turn correspond to JSErrorReport/JSErrorNotes which allows JS to
+// report complicated errors such as redeclarations that involve multiple
+// distinct lines.  For more generic error-propagation IPC structures, see bug
+// 1357463 on making ErrorResult usable over IPC.
+
+struct ErrorDataNote {
+  uint32_t lineNumber;
+  uint32_t columnNumber;
+  nsString message;
+  nsString filename;
+};
+
+struct ErrorData {
+  uint32_t lineNumber;
+  uint32_t columnNumber;
+  uint32_t flags;
+  nsString message;
+  nsString filename;
+  nsString line;
+  ErrorDataNote[] notes;
+};
+
+union ErrorValue {
+  nsresult;
+  ErrorData;
+  void_t;
+};
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/workers/sharedworkers/moz.build
+++ b/dom/workers/sharedworkers/moz.build
@@ -2,16 +2,17 @@
 # vim: set filetype=python:
 # 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/.
 
 EXPORTS.mozilla.dom += [
     'SharedWorker.h',
     'SharedWorkerChild.h',
+    'SharedWorkerManager.h',
     'SharedWorkerParent.h',
 ]
 
 UNIFIED_SOURCES += [
     'SharedWorker.cpp',
     'SharedWorkerChild.cpp',
     'SharedWorkerManager.cpp',
     'SharedWorkerParent.cpp',