1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
9 #include "MessageEventRunnable.h"
10 #include "mozilla/dom/WorkerBinding.h"
11 #include "mozilla/ProfilerLabels.h"
12 #include "mozilla/ProfilerMarkers.h"
13 #include "mozilla/TimelineConsumers.h"
14 #include "mozilla/Unused.h"
15 #include "mozilla/WorkerTimelineMarker.h"
16 #include "nsContentUtils.h"
17 #include "nsGlobalWindowOuter.h"
18 #include "WorkerPrivate.h"
28 already_AddRefed
<Worker
> Worker::Constructor(const GlobalObject
& aGlobal
,
29 const nsAString
& aScriptURL
,
30 const WorkerOptions
& aOptions
,
32 JSContext
* cx
= aGlobal
.Context();
34 nsCOMPtr
<nsIGlobalObject
> globalObject
=
35 do_QueryInterface(aGlobal
.GetAsSupports());
37 if (globalObject
->AsInnerWindow() &&
38 !globalObject
->AsInnerWindow()->IsCurrentInnerWindow()) {
39 aRv
.ThrowInvalidStateError(
40 "Cannot create worker for a going to be discarded document");
44 RefPtr
<WorkerPrivate
> workerPrivate
= WorkerPrivate::Constructor(
45 cx
, aScriptURL
, false /* aIsChromeWorker */, WorkerKindDedicated
,
46 aOptions
.mName
, VoidCString(), nullptr /*aLoadInfo */, aRv
);
47 if (NS_WARN_IF(aRv
.Failed())) {
51 RefPtr
<Worker
> worker
= new Worker(globalObject
, workerPrivate
.forget());
52 return worker
.forget();
55 Worker::Worker(nsIGlobalObject
* aGlobalObject
,
56 already_AddRefed
<WorkerPrivate
> aWorkerPrivate
)
57 : DOMEventTargetHelper(aGlobalObject
),
58 mWorkerPrivate(std::move(aWorkerPrivate
)) {
59 MOZ_ASSERT(mWorkerPrivate
);
60 mWorkerPrivate
->SetParentEventTargetRef(this);
63 Worker::~Worker() { Terminate(); }
65 JSObject
* Worker::WrapObject(JSContext
* aCx
,
66 JS::Handle
<JSObject
*> aGivenProto
) {
67 JS::Rooted
<JSObject
*> wrapper(aCx
,
68 Worker_Binding::Wrap(aCx
, this, aGivenProto
));
70 // Most DOM objects don't assume they have a reflector. If they don't have
71 // one and need one, they create it. But in workers code, we assume that the
72 // reflector is always present. In order to guarantee that it's always
73 // present, we have to preserve it. Otherwise the GC will happily collect it
75 MOZ_ALWAYS_TRUE(TryPreserveWrapper(wrapper
));
81 void Worker::PostMessage(JSContext
* aCx
, JS::Handle
<JS::Value
> aMessage
,
82 const Sequence
<JSObject
*>& aTransferable
,
84 NS_ASSERT_OWNINGTHREAD(Worker
);
86 if (!mWorkerPrivate
|| mWorkerPrivate
->ParentStatusProtected() > Running
) {
90 JS::Rooted
<JS::Value
> transferable(aCx
, JS::UndefinedValue());
92 aRv
= nsContentUtils::CreateJSValueFromSequenceOfObject(aCx
, aTransferable
,
94 if (NS_WARN_IF(aRv
.Failed())) {
98 NS_ConvertUTF16toUTF8
nameOrScriptURL(mWorkerPrivate
->WorkerName().IsEmpty()
99 ? mWorkerPrivate
->ScriptURL()
100 : mWorkerPrivate
->WorkerName());
101 AUTO_PROFILER_MARKER_TEXT("Worker.postMessage", DOM
, {}, nameOrScriptURL
);
102 uint32_t flags
= uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS
);
103 if (mWorkerPrivate
->IsChromeWorker()) {
104 flags
|= uint32_t(js::ProfilingStackFrame::Flags::NONSENSITIVE
);
106 mozilla::AutoProfilerLabel
PROFILER_RAII(
107 "Worker.postMessage", nameOrScriptURL
.get(),
108 JS::ProfilingCategoryPair::DOM
, flags
);
110 RefPtr
<MessageEventRunnable
> runnable
= new MessageEventRunnable(
111 mWorkerPrivate
, WorkerRunnable::WorkerThreadModifyBusyCount
);
113 UniquePtr
<AbstractTimelineMarker
> start
;
114 UniquePtr
<AbstractTimelineMarker
> end
;
115 RefPtr
<TimelineConsumers
> timelines
= TimelineConsumers::Get();
116 bool isTimelineRecording
= timelines
&& !timelines
->IsEmpty();
118 if (isTimelineRecording
) {
119 start
= MakeUnique
<WorkerTimelineMarker
>(
121 ? ProfileTimelineWorkerOperationType::SerializeDataOnMainThread
122 : ProfileTimelineWorkerOperationType::SerializeDataOffMainThread
,
123 MarkerTracingType::START
);
126 JS::CloneDataPolicy clonePolicy
;
127 // DedicatedWorkers are always part of the same agent cluster.
128 clonePolicy
.allowIntraClusterClonableSharedObjects();
130 if (NS_IsMainThread()) {
131 nsGlobalWindowInner
* win
= nsContentUtils::CallerInnerWindow();
132 if (win
&& win
->IsSharedMemoryAllowed()) {
133 clonePolicy
.allowSharedMemoryObjects();
136 WorkerPrivate
* worker
= GetCurrentThreadWorkerPrivate();
137 if (worker
&& worker
->IsSharedMemoryAllowed()) {
138 clonePolicy
.allowSharedMemoryObjects();
142 runnable
->Write(aCx
, aMessage
, transferable
, clonePolicy
, aRv
);
144 if (isTimelineRecording
) {
145 end
= MakeUnique
<WorkerTimelineMarker
>(
147 ? ProfileTimelineWorkerOperationType::SerializeDataOnMainThread
148 : ProfileTimelineWorkerOperationType::SerializeDataOffMainThread
,
149 MarkerTracingType::END
);
150 timelines
->AddMarkerForAllObservedDocShells(start
);
151 timelines
->AddMarkerForAllObservedDocShells(end
);
154 if (NS_WARN_IF(aRv
.Failed())) {
158 // The worker could have closed between the time we entered this function and
159 // checked ParentStatusProtected and now, which could cause the dispatch to
161 Unused
<< NS_WARN_IF(!runnable
->Dispatch());
164 void Worker::PostMessage(JSContext
* aCx
, JS::Handle
<JS::Value
> aMessage
,
165 const StructuredSerializeOptions
& aOptions
,
167 PostMessage(aCx
, aMessage
, aOptions
.mTransfer
, aRv
);
170 void Worker::Terminate() {
171 NS_ASSERT_OWNINGTHREAD(Worker
);
173 if (mWorkerPrivate
) {
174 mWorkerPrivate
->Cancel();
175 mWorkerPrivate
= nullptr;
179 NS_IMPL_CYCLE_COLLECTION_CLASS(Worker
)
181 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(Worker
, DOMEventTargetHelper
)
182 if (tmp
->mWorkerPrivate
) {
183 tmp
->mWorkerPrivate
->Traverse(cb
);
185 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
187 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(Worker
, DOMEventTargetHelper
)
189 NS_IMPL_CYCLE_COLLECTION_UNLINK_WEAK_PTR
190 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
192 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(Worker
, DOMEventTargetHelper
)
193 NS_IMPL_CYCLE_COLLECTION_TRACE_END
195 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Worker
)
196 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper
)
198 NS_IMPL_ADDREF_INHERITED(Worker
, DOMEventTargetHelper
)
199 NS_IMPL_RELEASE_INHERITED(Worker
, DOMEventTargetHelper
)
202 } // namespace mozilla