diff --git a/dom/bindings/Bindings.conf b/dom/bindings/Bindings.conf index 0e9652c59507..604dc094211f 100644 --- a/dom/bindings/Bindings.conf +++ b/dom/bindings/Bindings.conf @@ -144,11 +144,6 @@ DOMInterfaces = { 'concrete': False }, -'ChromeWorker': { - 'headerFile': 'mozilla/dom/WorkerPrivate.h', - 'nativeType': 'mozilla::dom::ChromeWorkerPrivate', -}, - 'console': { 'nativeType': 'mozilla::dom::Console', }, @@ -1351,11 +1346,6 @@ DOMInterfaces = { 'nativeType': 'nsWindowRoot' }, -'Worker': { - 'headerFile': 'mozilla/dom/WorkerPrivate.h', - 'nativeType': 'mozilla::dom::WorkerPrivate', -}, - 'WorkerDebuggerGlobalScope': { 'headerFile': 'mozilla/dom/WorkerScope.h', 'implicitJSContext': [ diff --git a/dom/webidl/Worker.webidl b/dom/webidl/Worker.webidl index c53223f55ce7..b4ce05003fc7 100644 --- a/dom/webidl/Worker.webidl +++ b/dom/webidl/Worker.webidl @@ -4,7 +4,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * The origin of this IDL file is - * http://www.whatwg.org/specs/web-apps/current-work/multipage/workers.html + * https://html.spec.whatwg.org/multipage/workers.html * * © Copyright 2004-2011 Apple Computer, Inc., Mozilla Foundation, and Opera * Software ASA. @@ -33,7 +33,7 @@ dictionary WorkerOptions { }; [Constructor(USVString scriptURL), - Func="mozilla::dom::ChromeWorkerPrivate::WorkerAvailable", + Func="mozilla::dom::ChromeWorker::WorkerAvailable", Exposed=(Window,DedicatedWorker,SharedWorker,System)] interface ChromeWorker : Worker { }; diff --git a/dom/workers/ChromeWorker.cpp b/dom/workers/ChromeWorker.cpp new file mode 100644 index 000000000000..bd363c5aaae5 --- /dev/null +++ b/dom/workers/ChromeWorker.cpp @@ -0,0 +1,78 @@ +/* -*- 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 "ChromeWorker.h" + +#include "mozilla/dom/WorkerBinding.h" +#include "nsContentUtils.h" +#include "WorkerPrivate.h" + +namespace mozilla { +namespace dom { + +/* static */ already_AddRefed +ChromeWorker::Constructor(const GlobalObject& aGlobal, + const nsAString& aScriptURL, + ErrorResult& aRv) +{ + JSContext* cx = aGlobal.Context(); + + RefPtr workerPrivate = + WorkerPrivate::Constructor(cx, aScriptURL, true /* aIsChromeWorker */, + WorkerTypeDedicated, EmptyString(), + VoidCString(), nullptr /*aLoadInfo */, aRv); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } + + nsCOMPtr globalObject = + do_QueryInterface(aGlobal.GetAsSupports()); + + RefPtr worker = + new ChromeWorker(globalObject, workerPrivate.forget()); + return worker.forget(); +} + +/* static */ bool +ChromeWorker::WorkerAvailable(JSContext* aCx, JSObject* /* unused */) +{ + // Chrome is always allowed to use workers, and content is never + // allowed to use ChromeWorker, so all we have to check is the + // caller. However, chrome workers apparently might not have a + // system principal, so we have to check for them manually. + if (NS_IsMainThread()) { + return nsContentUtils::IsSystemCaller(aCx); + } + + return GetWorkerPrivateFromContext(aCx)->IsChromeWorker(); +} + +ChromeWorker::ChromeWorker(nsIGlobalObject* aGlobalObject, + already_AddRefed aWorkerPrivate) + : Worker(aGlobalObject, Move(aWorkerPrivate)) +{} + +ChromeWorker::~ChromeWorker() = default; + +JSObject* +ChromeWorker::WrapObject(JSContext* aCx, JS::Handle aGivenProto) +{ + JS::Rooted wrapper(aCx, + ChromeWorkerBinding::Wrap(aCx, this, aGivenProto)); + if (wrapper) { + // Most DOM objects don't assume they have a reflector. If they don't have + // one and need one, they create it. But in workers code, we assume that the + // reflector is always present. In order to guarantee that it's always + // present, we have to preserve it. Otherwise the GC will happily collect it + // as needed. + MOZ_ALWAYS_TRUE(TryPreserveWrapper(wrapper)); + } + + return wrapper; +} + +} // dom namespace +} // mozilla namespace diff --git a/dom/workers/ChromeWorker.h b/dom/workers/ChromeWorker.h new file mode 100644 index 000000000000..19e03f397309 --- /dev/null +++ b/dom/workers/ChromeWorker.h @@ -0,0 +1,37 @@ +/* -*- 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/. */ + +#ifndef mozilla_dom_ChromeWorker_h +#define mozilla_dom_ChromeWorker_h + +#include "mozilla/dom/Worker.h" + +namespace mozilla { +namespace dom { + +class ChromeWorker final : public Worker +{ +public: + static already_AddRefed + Constructor(const GlobalObject& aGlobal, const nsAString& aScriptURL, + ErrorResult& aRv); + + static bool + WorkerAvailable(JSContext* aCx, JSObject* /* unused */); + + JSObject* + WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; + +private: + ChromeWorker(nsIGlobalObject* aGlobalObject, + already_AddRefed aWorkerPrivate); + ~ChromeWorker(); +}; + +} // dom namespace +} // mozilla namespace + +#endif /* mozilla_dom_ChromeWorker_h */ diff --git a/dom/workers/MessageEventRunnable.cpp b/dom/workers/MessageEventRunnable.cpp index a1804b2093b7..8399f9770582 100644 --- a/dom/workers/MessageEventRunnable.cpp +++ b/dom/workers/MessageEventRunnable.cpp @@ -126,7 +126,8 @@ MessageEventRunnable::WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) aWorkerPrivate->AssertInnerWindowIsCorrect(); - return DispatchDOMEvent(aCx, aWorkerPrivate, aWorkerPrivate, + return DispatchDOMEvent(aCx, aWorkerPrivate, + aWorkerPrivate->ParentEventTargetRef(), !aWorkerPrivate->GetParent()); } diff --git a/dom/workers/Worker.cpp b/dom/workers/Worker.cpp new file mode 100644 index 000000000000..8b97b4a47ca7 --- /dev/null +++ b/dom/workers/Worker.cpp @@ -0,0 +1,160 @@ +/* -*- 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 "Worker.h" + +#include "MessageEventRunnable.h" +#include "mozilla/dom/WorkerBinding.h" +#include "mozilla/TimelineConsumers.h" +#include "mozilla/WorkerTimelineMarker.h" +#include "nsContentUtils.h" +#include "WorkerPrivate.h" + +namespace mozilla { +namespace dom { + +/* static */ already_AddRefed +Worker::Constructor(const GlobalObject& aGlobal, const nsAString& aScriptURL, + const WorkerOptions& aOptions, ErrorResult& aRv) +{ + JSContext* cx = aGlobal.Context(); + + RefPtr workerPrivate = + WorkerPrivate::Constructor(cx, aScriptURL, false /* aIsChromeWorker */, + WorkerTypeDedicated, aOptions.mName, + VoidCString(), nullptr /*aLoadInfo */, aRv); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } + + nsCOMPtr globalObject = + do_QueryInterface(aGlobal.GetAsSupports()); + + RefPtr worker = new Worker(globalObject, workerPrivate.forget()); + return worker.forget(); +} + +Worker::Worker(nsIGlobalObject* aGlobalObject, + already_AddRefed aWorkerPrivate) + : DOMEventTargetHelper(aGlobalObject) + , mWorkerPrivate(Move(aWorkerPrivate)) +{ + MOZ_ASSERT(mWorkerPrivate); + mWorkerPrivate->SetParentEventTargetRef(this); +} + +Worker::~Worker() +{ + Terminate(); +} + +JSObject* +Worker::WrapObject(JSContext* aCx, JS::Handle aGivenProto) +{ + JS::Rooted wrapper(aCx, + WorkerBinding::Wrap(aCx, this, aGivenProto)); + if (wrapper) { + // Most DOM objects don't assume they have a reflector. If they don't have + // one and need one, they create it. But in workers code, we assume that the + // reflector is always present. In order to guarantee that it's always + // present, we have to preserve it. Otherwise the GC will happily collect it + // as needed. + MOZ_ALWAYS_TRUE(TryPreserveWrapper(wrapper)); + } + + return wrapper; +} + +void +Worker::PostMessage(JSContext* aCx, JS::Handle aMessage, + const Sequence& aTransferable, + ErrorResult& aRv) +{ + NS_ASSERT_OWNINGTHREAD(Worker); + + if (!mWorkerPrivate || + mWorkerPrivate->ParentStatusProtected() > Running) { + return; + } + + JS::Rooted transferable(aCx, JS::UndefinedValue()); + + aRv = nsContentUtils::CreateJSValueFromSequenceOfObject(aCx, aTransferable, + &transferable); + if (NS_WARN_IF(aRv.Failed())) { + return; + } + + RefPtr runnable = + new MessageEventRunnable(mWorkerPrivate, + WorkerRunnable::WorkerThreadModifyBusyCount); + + UniquePtr start; + UniquePtr end; + RefPtr timelines = TimelineConsumers::Get(); + bool isTimelineRecording = timelines && !timelines->IsEmpty(); + + if (isTimelineRecording) { + start = MakeUnique(NS_IsMainThread() + ? ProfileTimelineWorkerOperationType::SerializeDataOnMainThread + : ProfileTimelineWorkerOperationType::SerializeDataOffMainThread, + MarkerTracingType::START); + } + + runnable->Write(aCx, aMessage, transferable, JS::CloneDataPolicy(), aRv); + + if (isTimelineRecording) { + end = MakeUnique(NS_IsMainThread() + ? ProfileTimelineWorkerOperationType::SerializeDataOnMainThread + : ProfileTimelineWorkerOperationType::SerializeDataOffMainThread, + MarkerTracingType::END); + timelines->AddMarkerForAllObservedDocShells(start); + timelines->AddMarkerForAllObservedDocShells(end); + } + + if (NS_WARN_IF(aRv.Failed())) { + return; + } + + if (!runnable->Dispatch()) { + aRv.Throw(NS_ERROR_FAILURE); + } +} + +void +Worker::Terminate() +{ + NS_ASSERT_OWNINGTHREAD(Worker); + + if (mWorkerPrivate) { + mWorkerPrivate->Terminate(); + mWorkerPrivate = nullptr; + } +} + +NS_IMPL_CYCLE_COLLECTION_CLASS(Worker) + +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(Worker, DOMEventTargetHelper) + if (tmp->mWorkerPrivate) { + tmp->mWorkerPrivate->Traverse(cb); + } +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END + +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(Worker, DOMEventTargetHelper) + tmp->Terminate(); +NS_IMPL_CYCLE_COLLECTION_UNLINK_END + +NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(Worker, DOMEventTargetHelper) +NS_IMPL_CYCLE_COLLECTION_TRACE_END + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Worker) +NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper) + +NS_IMPL_ADDREF_INHERITED(Worker, DOMEventTargetHelper) +NS_IMPL_RELEASE_INHERITED(Worker, DOMEventTargetHelper) + +} // dom namespace +} // mozilla namespace diff --git a/dom/workers/Worker.h b/dom/workers/Worker.h new file mode 100644 index 000000000000..c0badbe8b848 --- /dev/null +++ b/dom/workers/Worker.h @@ -0,0 +1,64 @@ +/* -*- 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/. */ + +#ifndef mozilla_dom_Worker_h +#define mozilla_dom_Worker_h + +#include "mozilla/Attributes.h" +#include "mozilla/DOMEventTargetHelper.h" +#include "mozilla/RefPtr.h" +#include "mozilla/WeakPtr.h" + +#ifdef XP_WIN +#undef PostMessage +#endif + +namespace mozilla { +namespace dom { + +struct WorkerOptions; +class WorkerPrivate; + +class Worker : public DOMEventTargetHelper + , public SupportsWeakPtr +{ +public: + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(Worker, + DOMEventTargetHelper) + MOZ_DECLARE_WEAKREFERENCE_TYPENAME(Worker) + + static already_AddRefed + Constructor(const GlobalObject& aGlobal, const nsAString& aScriptURL, + const WorkerOptions& aOptions, ErrorResult& aRv); + + JSObject* + WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; + + void + PostMessage(JSContext* aCx, JS::Handle aMessage, + const Sequence& aTransferable, + ErrorResult& aRv); + + void + Terminate(); + + IMPL_EVENT_HANDLER(error) + IMPL_EVENT_HANDLER(message) + IMPL_EVENT_HANDLER(messageerror) + +protected: + Worker(nsIGlobalObject* aGlobalObject, + already_AddRefed aWorkerPrivate); + ~Worker(); + + RefPtr mWorkerPrivate; +}; + +} // dom namespace +} // mozilla namespace + +#endif /* mozilla_dom_Worker_h */ diff --git a/dom/workers/WorkerError.cpp b/dom/workers/WorkerError.cpp index e7603ccd5ee1..4b796d84117b 100644 --- a/dom/workers/WorkerError.cpp +++ b/dom/workers/WorkerError.cpp @@ -35,7 +35,7 @@ public: // (if any). static void ReportError(JSContext* aCx, WorkerPrivate* aWorkerPrivate, - bool aFireAtScope, WorkerPrivate* aTarget, + bool aFireAtScope, DOMEventTargetHelper* aTarget, const WorkerErrorReport& aReport, uint64_t aInnerWindowId, JS::Handle aException = JS::NullHandleValue) { @@ -177,8 +177,6 @@ private: virtual bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override { - JS::Rooted target(aCx, aWorkerPrivate->GetWrapper()); - uint64_t innerWindowId; bool fireAtScope = true; @@ -236,8 +234,9 @@ private: return true; } - ReportError(aCx, parent, fireAtScope, aWorkerPrivate, mReport, - innerWindowId); + ReportError(aCx, parent, fireAtScope, + aWorkerPrivate->ParentEventTargetRef(), + mReport, innerWindowId); return true; } }; diff --git a/dom/workers/WorkerNavigator.cpp b/dom/workers/WorkerNavigator.cpp index 3d1ff44715d0..dfe9f353d998 100644 --- a/dom/workers/WorkerNavigator.cpp +++ b/dom/workers/WorkerNavigator.cpp @@ -28,6 +28,8 @@ namespace mozilla { namespace dom { +using namespace workerinternals; + NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WorkerNavigator, mStorageManager, mConnection); diff --git a/dom/workers/WorkerPrivate.cpp b/dom/workers/WorkerPrivate.cpp index 99c240b848e1..f5556c8f23fe 100644 --- a/dom/workers/WorkerPrivate.cpp +++ b/dom/workers/WorkerPrivate.cpp @@ -249,7 +249,7 @@ private: runtime->UnregisterWorker(mFinishedWorker); - mFinishedWorker->ClearSelfRef(); + mFinishedWorker->ClearSelfAndParentEventTargetRef(); return true; } }; @@ -287,7 +287,7 @@ private: NS_WARNING("Failed to dispatch, going to leak!"); } - mFinishedWorker->ClearSelfRef(); + mFinishedWorker->ClearSelfAndParentEventTargetRef(); return NS_OK; } }; @@ -384,13 +384,15 @@ private: return true; } + RefPtr parentEventTarget = + aWorkerPrivate->ParentEventTargetRef(); RefPtr event = - Event::Constructor(aWorkerPrivate, NS_LITERAL_STRING("error"), + Event::Constructor(parentEventTarget, NS_LITERAL_STRING("error"), EventInit()); event->SetTrusted(true); bool dummy; - aWorkerPrivate->DispatchEvent(event, &dummy); + parentEventTarget->DispatchEvent(event, &dummy); return true; } }; @@ -1546,14 +1548,6 @@ WorkerPrivateParent::SetReferrerPolicyFromHeaderValue( SetReferrerPolicy(policy); } - -// Can't use NS_IMPL_CYCLE_COLLECTION_CLASS(WorkerPrivateParent) because of the -// templates. -template -typename WorkerPrivateParent::cycleCollection - WorkerPrivateParent::_cycleCollectorGlobal = - WorkerPrivateParent::cycleCollection(); - template WorkerPrivateParent::WorkerPrivateParent( WorkerPrivate* aParent, @@ -1576,11 +1570,6 @@ WorkerPrivateParent::WorkerPrivateParent( { MOZ_ASSERT_IF(!IsDedicatedWorker(), NS_IsMainThread()); - if (aLoadInfo.mWindow) { - AssertIsOnMainThread(); - BindToOwner(aLoadInfo.mWindow); - } - mLoadInfo.StealFrom(aLoadInfo); if (aParent) { @@ -1644,23 +1633,23 @@ WorkerPrivateParent::~WorkerPrivateParent() } template -JSObject* -WorkerPrivateParent::WrapObject(JSContext* aCx, JS::Handle aGivenProto) +void +WorkerPrivateParent::Traverse(nsCycleCollectionTraversalCallback& aCb) { - MOZ_ASSERT(!IsSharedWorker(), - "We should never wrap a WorkerPrivate for a SharedWorker"); - AssertIsOnParentThread(); - // XXXkhuey this should not need to be rooted, the analysis is dumb. - // See bug 980181. - JS::Rooted wrapper(aCx, - WorkerBinding::Wrap(aCx, ParentAsWorkerPrivate(), aGivenProto)); - if (wrapper) { - MOZ_ALWAYS_TRUE(TryPreserveWrapper(wrapper)); + // The WorkerPrivate::mParentEventTargetRef has a reference to the exposed + // Worker object, which is really held by the worker thread. We traverse this + // reference if and only if our busy count is zero and we have not released + // the main thread reference. We do not unlink it. This allows the CC to + // break cycles involving the Worker and begin shutting it down (which does + // happen in unlink) but ensures that the WorkerPrivate won't be deleted + // before we're done shutting down the thread. + if (!mBusyCount && !mMainThreadObjectsForgotten) { + nsCycleCollectionTraversalCallback& cb = aCb; + WorkerPrivateParent* tmp = this; + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParentEventTargetRef); } - - return wrapper; } template @@ -2145,76 +2134,6 @@ WorkerPrivateParent::ProxyReleaseMainThreadObjects() return result; } -template -void -WorkerPrivateParent::PostMessageInternal(JSContext* aCx, - JS::Handle aMessage, - const Sequence& aTransferable, - ErrorResult& aRv) -{ - AssertIsOnParentThread(); - - { - MutexAutoLock lock(mMutex); - if (mParentStatus > Running) { - return; - } - } - - JS::Rooted transferable(aCx, JS::UndefinedValue()); - - aRv = nsContentUtils::CreateJSValueFromSequenceOfObject(aCx, aTransferable, - &transferable); - if (NS_WARN_IF(aRv.Failed())) { - return; - } - - RefPtr runnable = - new MessageEventRunnable(ParentAsWorkerPrivate(), - WorkerRunnable::WorkerThreadModifyBusyCount); - - UniquePtr start; - UniquePtr end; - RefPtr timelines = TimelineConsumers::Get(); - bool isTimelineRecording = timelines && !timelines->IsEmpty(); - - if (isTimelineRecording) { - start = MakeUnique(NS_IsMainThread() - ? ProfileTimelineWorkerOperationType::SerializeDataOnMainThread - : ProfileTimelineWorkerOperationType::SerializeDataOffMainThread, - MarkerTracingType::START); - } - - runnable->Write(aCx, aMessage, transferable, JS::CloneDataPolicy(), aRv); - - if (isTimelineRecording) { - end = MakeUnique(NS_IsMainThread() - ? ProfileTimelineWorkerOperationType::SerializeDataOnMainThread - : ProfileTimelineWorkerOperationType::SerializeDataOffMainThread, - MarkerTracingType::END); - timelines->AddMarkerForAllObservedDocShells(start); - timelines->AddMarkerForAllObservedDocShells(end); - } - - if (NS_WARN_IF(aRv.Failed())) { - return; - } - - if (!runnable->Dispatch()) { - aRv.Throw(NS_ERROR_FAILURE); - } -} - -template -void -WorkerPrivateParent::PostMessage( - JSContext* aCx, JS::Handle aMessage, - const Sequence& aTransferable, - ErrorResult& aRv) -{ - PostMessageInternal(aCx, aMessage, aTransferable, aRv); -} - template void WorkerPrivateParent::UpdateContextOptions( @@ -2780,48 +2699,6 @@ WorkerPrivateParent::FlushReportsToSharedWorkers( aReporter->ClearConsoleReports(); } -template -NS_IMPL_ADDREF_INHERITED(WorkerPrivateParent, DOMEventTargetHelper) - -template -NS_IMPL_RELEASE_INHERITED(WorkerPrivateParent, DOMEventTargetHelper) - -template -NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WorkerPrivateParent) -NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper) - -template -NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(WorkerPrivateParent, - DOMEventTargetHelper) - tmp->AssertIsOnParentThread(); - - // The WorkerPrivate::mSelfRef has a reference to itself, which is really - // held by the worker thread. We traverse this reference if and only if our - // busy count is zero and we have not released the main thread reference. - // We do not unlink it. This allows the CC to break cycles involving the - // WorkerPrivate and begin shutting it down (which does happen in unlink) but - // ensures that the WorkerPrivate won't be deleted before we're done shutting - // down the thread. - - if (!tmp->mBusyCount && !tmp->mMainThreadObjectsForgotten) { - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSelfRef) - } - - // The various strong references in LoadInfo are managed manually and cannot - // be cycle collected. -NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END - -template -NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(WorkerPrivateParent, - DOMEventTargetHelper) - tmp->Terminate(); -NS_IMPL_CYCLE_COLLECTION_UNLINK_END - -template -NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(WorkerPrivateParent, - DOMEventTargetHelper) -NS_IMPL_CYCLE_COLLECTION_TRACE_END - #ifdef DEBUG template @@ -2954,58 +2831,6 @@ WorkerPrivate::~WorkerPrivate() mWorkerHybridEventTarget->ForgetWorkerPrivate(this); } -// static -already_AddRefed -WorkerPrivate::Constructor(const GlobalObject& aGlobal, - const nsAString& aScriptURL, - const WorkerOptions& aOptions, - ErrorResult& aRv) -{ - return WorkerPrivate::Constructor(aGlobal, aScriptURL, false, - WorkerTypeDedicated, - aOptions.mName, nullptr, aRv); -} - -// static -already_AddRefed -ChromeWorkerPrivate::Constructor(const GlobalObject& aGlobal, - const nsAString& aScriptURL, - ErrorResult& aRv) -{ - return WorkerPrivate::Constructor(aGlobal, aScriptURL, true, - WorkerTypeDedicated, EmptyString(), - nullptr, aRv) - .downcast(); -} - -// static -bool -ChromeWorkerPrivate::WorkerAvailable(JSContext* aCx, JSObject* /* unused */) -{ - // Chrome is always allowed to use workers, and content is never - // allowed to use ChromeWorker, so all we have to check is the - // caller. However, chrome workers apparently might not have a - // system principal, so we have to check for them manually. - if (NS_IsMainThread()) { - return nsContentUtils::IsSystemCaller(aCx); - } - - return GetWorkerPrivateFromContext(aCx)->IsChromeWorker(); -} - -// static -already_AddRefed -WorkerPrivate::Constructor(const GlobalObject& aGlobal, - const nsAString& aScriptURL, - bool aIsChromeWorker, WorkerType aWorkerType, - const nsAString& aWorkerName, - WorkerLoadInfo* aLoadInfo, ErrorResult& aRv) -{ - JSContext* cx = aGlobal.Context(); - return Constructor(cx, aScriptURL, aIsChromeWorker, aWorkerType, - aWorkerName, VoidCString(), aLoadInfo, aRv); -} - // static already_AddRefed WorkerPrivate::Constructor(JSContext* aCx, diff --git a/dom/workers/WorkerPrivate.h b/dom/workers/WorkerPrivate.h index f9702650af10..e4ae27ee8ddf 100644 --- a/dom/workers/WorkerPrivate.h +++ b/dom/workers/WorkerPrivate.h @@ -14,15 +14,12 @@ #include "nsIEventTarget.h" #include "nsTObserverArray.h" +#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" -#ifdef XP_WIN -#undef PostMessage -#endif - class nsIConsoleReportCollector; class nsIThreadInternal; @@ -51,7 +48,6 @@ class WorkerDebuggerGlobalScope; class WorkerErrorReport; class WorkerEventTarget; class WorkerGlobalScope; -struct WorkerOptions; class WorkerRunnable; class WorkerThread; @@ -105,7 +101,7 @@ public: }; template -class WorkerPrivateParent : public DOMEventTargetHelper +class WorkerPrivateParent { protected: class EventTarget; @@ -184,8 +180,9 @@ private: protected: // The worker is owned by its thread, which is represented here. This is set - // in Construct() and emptied by WorkerFinishedRunnable, and conditionally + // in Constructor() and emptied by WorkerFinishedRunnable, and conditionally // traversed by the cycle collector if the busy count is zero. + RefPtr mParentEventTargetRef; RefPtr mSelfRef; WorkerPrivateParent(WorkerPrivate* aParent, @@ -195,7 +192,7 @@ protected: const nsACString& aServiceWorkerScope, WorkerLoadInfo& aLoadInfo); - ~WorkerPrivateParent(); + virtual ~WorkerPrivateParent(); private: Derived* @@ -213,21 +210,14 @@ private: return NotifyPrivate(Terminating); } - void - PostMessageInternal(JSContext* aCx, JS::Handle aMessage, - const Sequence& aTransferable, - ErrorResult& aRv); - nsresult DispatchPrivate(already_AddRefed aRunnable, nsIEventTarget* aSyncLoopTarget); public: - virtual JSObject* - WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; + NS_INLINE_DECL_REFCOUNTING(WorkerPrivateParent) - NS_DECL_ISUPPORTS_INHERITED - NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(WorkerPrivateParent, - DOMEventTargetHelper) + void + Traverse(nsCycleCollectionTraversalCallback& aCb); void EnableDebugger(); @@ -236,10 +226,11 @@ public: DisableDebugger(); void - ClearSelfRef() + ClearSelfAndParentEventTargetRef() { AssertIsOnParentThread(); MOZ_ASSERT(mSelfRef); + mParentEventTargetRef = nullptr; mSelfRef = nullptr; } @@ -318,11 +309,6 @@ public: bool ProxyReleaseMainThreadObjects(); - void - PostMessage(JSContext* aCx, JS::Handle aMessage, - const Sequence& aTransferable, - ErrorResult& aRv); - void UpdateContextOptions(const JS::ContextOptions& aContextOptions); @@ -394,7 +380,15 @@ public: MutexAutoLock lock(mMutex); return mParentStatus < Terminating; - } + } + + WorkerStatus + ParentStatusProtected() + { + AssertIsOnParentThread(); + MutexAutoLock lock(mMutex); + return mParentStatus; + } WorkerStatus ParentStatus() const @@ -829,10 +823,6 @@ public: void FlushReportsToSharedWorkers(nsIConsoleReportCollector* aReporter); - IMPL_EVENT_HANDLER(message) - IMPL_EVENT_HANDLER(messageerror) - IMPL_EVENT_HANDLER(error) - // Check whether this worker is a secure context. For use from the parent // thread only; the canonical "is secure context" boolean is stored on the // compartment of the worker global. The only reason we don't @@ -968,17 +958,6 @@ protected: ~WorkerPrivate(); public: - static already_AddRefed - Constructor(const GlobalObject& aGlobal, const nsAString& aScriptURL, - const WorkerOptions& aOptions, - ErrorResult& aRv); - - static already_AddRefed - Constructor(const GlobalObject& aGlobal, const nsAString& aScriptURL, - bool aIsChromeWorker, WorkerType aWorkerType, - const nsAString& aWorkerName, - WorkerLoadInfo* aLoadInfo, ErrorResult& aRv); - static already_AddRefed Constructor(JSContext* aCx, const nsAString& aScriptURL, bool aIsChromeWorker, WorkerType aWorkerType, const nsAString& aWorkerName, @@ -1389,6 +1368,21 @@ public: PerformanceStorage* GetPerformanceStorage(); + Worker* + ParentEventTargetRef() const + { + MOZ_DIAGNOSTIC_ASSERT(mParentEventTargetRef); + return mParentEventTargetRef; + } + + void + SetParentEventTargetRef(Worker* aParentEventTargetRef) + { + MOZ_DIAGNOSTIC_ASSERT(aParentEventTargetRef); + MOZ_DIAGNOSTIC_ASSERT(!mParentEventTargetRef); + mParentEventTargetRef = aParentEventTargetRef; + } + private: WorkerPrivate(WorkerPrivate* aParent, const nsAString& aScriptURL, bool aIsChromeWorker, @@ -1491,25 +1485,6 @@ private: } }; -// This class is only used to trick the DOM bindings. We never create -// instances of it, and static_casting to it is fine since it doesn't add -// anything to WorkerPrivate. -class ChromeWorkerPrivate : public WorkerPrivate -{ -public: - static already_AddRefed - Constructor(const GlobalObject& aGlobal, const nsAString& aScriptURL, - ErrorResult& rv); - - static bool - WorkerAvailable(JSContext* aCx, JSObject* /* unused */); - -private: - ChromeWorkerPrivate() = delete; - ChromeWorkerPrivate(const ChromeWorkerPrivate& aRHS) = delete; - ChromeWorkerPrivate& operator =(const ChromeWorkerPrivate& aRHS) = delete; -}; - class AutoSyncLoopHolder { WorkerPrivate* mWorkerPrivate; diff --git a/dom/workers/WorkerRunnable.cpp b/dom/workers/WorkerRunnable.cpp index 305be9284044..e14222e52e5b 100644 --- a/dom/workers/WorkerRunnable.cpp +++ b/dom/workers/WorkerRunnable.cpp @@ -330,7 +330,8 @@ WorkerRunnable::Run() cx = jsapi->cx(); } - // Note that we can't assert anything about mWorkerPrivate->GetWrapper() + // Note that we can't assert anything about + // mWorkerPrivate->ParentEventTargetRef()->GetWrapper() // existing, since it may in fact have been GCed (and we may be one of the // runnables cleaning up the worker as a result). @@ -348,27 +349,31 @@ WorkerRunnable::Run() // the compartment of the worker's reflector if there is one. There might // not be one if we're just starting to compile the script for this worker. Maybe ac; - if (!targetIsWorkerThread && mWorkerPrivate->GetWrapper()) { + if (!targetIsWorkerThread && + mWorkerPrivate->IsDedicatedWorker() && + mWorkerPrivate->ParentEventTargetRef()->GetWrapper()) { + JSObject* wrapper = mWorkerPrivate->ParentEventTargetRef()->GetWrapper(); + // If we're on the parent thread and have a reflector and a globalObject, // then the compartments of cx, globalObject, and the worker's reflector // should all match. MOZ_ASSERT_IF(globalObject, - js::GetObjectCompartment(mWorkerPrivate->GetWrapper()) == + js::GetObjectCompartment(wrapper) == js::GetContextCompartment(cx)); MOZ_ASSERT_IF(globalObject, - js::GetObjectCompartment(mWorkerPrivate->GetWrapper()) == + js::GetObjectCompartment(wrapper) == js::GetObjectCompartment(globalObject->GetGlobalJSObject())); // If we're on the parent thread and have a reflector, then our // JSContext had better be either in the null compartment (and hence // have no globalObject) or in the compartment of our reflector. MOZ_ASSERT(!js::GetContextCompartment(cx) || - js::GetObjectCompartment(mWorkerPrivate->GetWrapper()) == + js::GetObjectCompartment(wrapper) == js::GetContextCompartment(cx), "Must either be in the null compartment or in our reflector " "compartment"); - ac.emplace(cx, mWorkerPrivate->GetWrapper()); + ac.emplace(cx, wrapper); } MOZ_ASSERT(!jsapi->HasException()); diff --git a/dom/workers/moz.build b/dom/workers/moz.build index 0d777ad5a7d8..05144229b1e2 100644 --- a/dom/workers/moz.build +++ b/dom/workers/moz.build @@ -9,7 +9,9 @@ with Files("**"): # Public stuff. EXPORTS.mozilla.dom += [ + 'ChromeWorker.h', 'SharedWorker.h', + 'Worker.h', 'WorkerCommon.h', 'WorkerDebugger.h', 'WorkerDebuggerManager.h', @@ -38,6 +40,7 @@ XPIDL_SOURCES += [ ] UNIFIED_SOURCES += [ + 'ChromeWorker.cpp', 'ChromeWorkerScope.cpp', 'MessageEventRunnable.cpp', 'Principal.cpp', @@ -45,6 +48,7 @@ UNIFIED_SOURCES += [ 'RuntimeService.cpp', 'ScriptLoader.cpp', 'SharedWorker.cpp', + 'Worker.cpp', 'WorkerDebugger.cpp', 'WorkerDebuggerManager.cpp', 'WorkerError.cpp',