Backed out changeset 9d8b4c0b99ed (bug 1945683) for causing btime failures. CLOSED...
[gecko.git] / dom / workers / Worker.cpp
blobade19dc513ff2bf3d657dbfa8dc1da0f233c8350
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/. */
7 #include "Worker.h"
9 #include "MessageEventRunnable.h"
10 #include "mozilla/dom/WorkerBinding.h"
11 #include "mozilla/ProfilerLabels.h"
12 #include "mozilla/ProfilerMarkers.h"
13 #include "mozilla/Unused.h"
14 #include "nsContentUtils.h"
15 #include "nsGlobalWindowInner.h"
16 #include "WorkerPrivate.h"
17 #include "EventWithOptionsRunnable.h"
18 #include "js/RootingAPI.h"
19 #include "mozilla/dom/BindingDeclarations.h"
20 #include "nsISupports.h"
21 #include "nsDebug.h"
22 #include "mozilla/dom/WorkerStatus.h"
23 #include "mozilla/RefPtr.h"
24 #include "mozilla/dom/TrustedScriptURL.h"
25 #include "mozilla/dom/TrustedTypeUtils.h"
26 #include "mozilla/dom/TrustedTypesConstants.h"
28 #ifdef XP_WIN
29 # undef PostMessage
30 #endif
32 namespace mozilla::dom {
34 /* static */
35 already_AddRefed<Worker> Worker::Constructor(
36 const GlobalObject& aGlobal, const TrustedScriptURLOrUSVString& aScriptURL,
37 const WorkerOptions& aOptions, ErrorResult& aRv) {
38 JSContext* cx = aGlobal.Context();
40 nsCOMPtr<nsIGlobalObject> globalObject =
41 do_QueryInterface(aGlobal.GetAsSupports());
43 nsPIDOMWindowInner* innerWindow = globalObject->GetAsInnerWindow();
44 if (innerWindow && !innerWindow->IsCurrentInnerWindow()) {
45 aRv.ThrowInvalidStateError(
46 "Cannot create worker for a going to be discarded document");
47 return nullptr;
50 // The spec only mentions Window and WorkerGlobalScope global objects, but
51 // Gecko can actually call the constructor with other ones, so we just skip
52 // trusted types handling in that case.
53 // https://html.spec.whatwg.org/multipage/workers.html#dedicated-workers-and-the-worker-interface
54 const nsAString* compliantString = nullptr;
55 bool performTrustedTypeConversion = innerWindow;
56 if (!performTrustedTypeConversion) {
57 if (JSObject* globalJSObject = globalObject->GetGlobalJSObject()) {
58 performTrustedTypeConversion = IsWorkerGlobal(globalJSObject);
61 Maybe<nsAutoString> compliantStringHolder;
62 if (performTrustedTypeConversion) {
63 constexpr nsLiteralString sink = u"Worker constructor"_ns;
64 compliantString = TrustedTypeUtils::GetTrustedTypesCompliantString(
65 aScriptURL, sink, kTrustedTypesOnlySinkGroup, *globalObject,
66 compliantStringHolder, aRv);
67 if (aRv.Failed()) {
68 return nullptr;
70 } else {
71 compliantString = aScriptURL.IsUSVString()
72 ? &aScriptURL.GetAsUSVString()
73 : &aScriptURL.GetAsTrustedScriptURL().mData;
75 MOZ_ASSERT(compliantString);
77 RefPtr<WorkerPrivate> workerPrivate = WorkerPrivate::Constructor(
78 cx, *compliantString, false /* aIsChromeWorker */, WorkerKindDedicated,
79 aOptions.mCredentials, aOptions.mType, aOptions.mName, VoidCString(),
80 nullptr /*aLoadInfo */, aRv);
81 if (NS_WARN_IF(aRv.Failed())) {
82 return nullptr;
85 RefPtr<Worker> worker = new Worker(globalObject, workerPrivate.forget());
86 return worker.forget();
89 Worker::Worker(nsIGlobalObject* aGlobalObject,
90 already_AddRefed<WorkerPrivate> aWorkerPrivate)
91 : DOMEventTargetHelper(aGlobalObject),
92 mWorkerPrivate(std::move(aWorkerPrivate)) {
93 MOZ_ASSERT(mWorkerPrivate);
94 mWorkerPrivate->SetParentEventTargetRef(this);
97 Worker::~Worker() { Terminate(); }
99 JSObject* Worker::WrapObject(JSContext* aCx,
100 JS::Handle<JSObject*> aGivenProto) {
101 JS::Rooted<JSObject*> wrapper(aCx,
102 Worker_Binding::Wrap(aCx, this, aGivenProto));
103 if (wrapper) {
104 // Most DOM objects don't assume they have a reflector. If they don't have
105 // one and need one, they create it. But in workers code, we assume that the
106 // reflector is always present. In order to guarantee that it's always
107 // present, we have to preserve it. Otherwise the GC will happily collect it
108 // as needed.
109 MOZ_ALWAYS_TRUE(TryPreserveWrapper(wrapper));
112 return wrapper;
115 bool Worker::IsEligibleForMessaging() {
116 NS_ASSERT_OWNINGTHREAD(Worker);
118 return mWorkerPrivate && mWorkerPrivate->ParentStatusProtected() <= Running;
121 void Worker::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
122 const Sequence<JSObject*>& aTransferable,
123 ErrorResult& aRv) {
124 NS_ASSERT_OWNINGTHREAD(Worker);
126 if (!mWorkerPrivate || mWorkerPrivate->ParentStatusProtected() > Running) {
127 return;
129 RefPtr<WorkerPrivate> workerPrivate = mWorkerPrivate;
130 Unused << workerPrivate;
132 JS::Rooted<JS::Value> transferable(aCx, JS::UndefinedValue());
134 aRv = nsContentUtils::CreateJSValueFromSequenceOfObject(aCx, aTransferable,
135 &transferable);
136 if (NS_WARN_IF(aRv.Failed())) {
137 return;
140 NS_ConvertUTF16toUTF8 nameOrScriptURL(
141 mWorkerPrivate->WorkerName().IsEmpty()
142 ? Substring(
143 mWorkerPrivate->ScriptURL(), 0,
144 std::min(size_t(1024), mWorkerPrivate->ScriptURL().Length()))
145 : Substring(
146 mWorkerPrivate->WorkerName(), 0,
147 std::min(size_t(1024), mWorkerPrivate->WorkerName().Length())));
148 AUTO_PROFILER_MARKER_TEXT("Worker.postMessage", DOM, {}, nameOrScriptURL);
149 uint32_t flags = uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS);
150 if (mWorkerPrivate->IsChromeWorker()) {
151 flags |= uint32_t(js::ProfilingStackFrame::Flags::NONSENSITIVE);
153 mozilla::AutoProfilerLabel PROFILER_RAII(
154 "Worker.postMessage", nameOrScriptURL.get(),
155 JS::ProfilingCategoryPair::DOM, flags);
157 RefPtr<MessageEventRunnable> runnable =
158 new MessageEventRunnable(mWorkerPrivate);
160 JS::CloneDataPolicy clonePolicy;
161 // DedicatedWorkers are always part of the same agent cluster.
162 clonePolicy.allowIntraClusterClonableSharedObjects();
164 if (NS_IsMainThread()) {
165 nsGlobalWindowInner* win = nsContentUtils::IncumbentInnerWindow();
166 if (win && win->IsSharedMemoryAllowed()) {
167 clonePolicy.allowSharedMemoryObjects();
169 } else {
170 WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
171 if (worker && worker->IsSharedMemoryAllowed()) {
172 clonePolicy.allowSharedMemoryObjects();
176 runnable->Write(aCx, aMessage, transferable, clonePolicy, aRv);
178 if (!mWorkerPrivate || mWorkerPrivate->ParentStatusProtected() > Running) {
179 return;
182 if (NS_WARN_IF(aRv.Failed())) {
183 return;
186 // The worker could have closed between the time we entered this function and
187 // checked ParentStatusProtected and now, which could cause the dispatch to
188 // fail.
189 Unused << NS_WARN_IF(!runnable->Dispatch(mWorkerPrivate));
192 void Worker::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
193 const StructuredSerializeOptions& aOptions,
194 ErrorResult& aRv) {
195 PostMessage(aCx, aMessage, aOptions.mTransfer, aRv);
198 void Worker::PostEventWithOptions(JSContext* aCx,
199 JS::Handle<JS::Value> aOptions,
200 const Sequence<JSObject*>& aTransferable,
201 EventWithOptionsRunnable* aRunnable,
202 ErrorResult& aRv) {
203 NS_ASSERT_OWNINGTHREAD(Worker);
205 if (NS_WARN_IF(!mWorkerPrivate ||
206 mWorkerPrivate->ParentStatusProtected() > Running)) {
207 return;
209 RefPtr<WorkerPrivate> workerPrivate = mWorkerPrivate;
210 Unused << workerPrivate;
212 aRunnable->InitOptions(aCx, aOptions, aTransferable, aRv);
214 if (NS_WARN_IF(!mWorkerPrivate ||
215 mWorkerPrivate->ParentStatusProtected() > Running)) {
216 return;
219 if (NS_WARN_IF(aRv.Failed())) {
220 return;
223 Unused << NS_WARN_IF(!aRunnable->Dispatch(mWorkerPrivate));
226 void Worker::Terminate() {
227 NS_ASSERT_OWNINGTHREAD(Worker);
229 if (mWorkerPrivate) {
230 mWorkerPrivate->Cancel();
231 mWorkerPrivate = nullptr;
235 NS_IMPL_CYCLE_COLLECTION_CLASS(Worker)
237 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(Worker, DOMEventTargetHelper)
238 if (tmp->mWorkerPrivate) {
239 tmp->mWorkerPrivate->Traverse(cb);
241 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
243 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(Worker, DOMEventTargetHelper)
244 tmp->Terminate();
245 NS_IMPL_CYCLE_COLLECTION_UNLINK_WEAK_PTR
246 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
248 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(Worker, DOMEventTargetHelper)
249 NS_IMPL_CYCLE_COLLECTION_TRACE_END
251 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Worker)
252 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
254 NS_IMPL_ADDREF_INHERITED(Worker, DOMEventTargetHelper)
255 NS_IMPL_RELEASE_INHERITED(Worker, DOMEventTargetHelper)
257 } // namespace mozilla::dom