Bug 1873144 - Disabled test_conformance__textures__misc__texture-npot-video.html...
[gecko.git] / dom / workers / Worker.cpp
blob2348572e65548cdc6d6fec9456e18ebdaecc12d0
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"
25 #ifdef XP_WIN
26 # undef PostMessage
27 #endif
29 namespace mozilla::dom {
31 /* static */
32 already_AddRefed<Worker> Worker::Constructor(const GlobalObject& aGlobal,
33 const nsAString& aScriptURL,
34 const WorkerOptions& aOptions,
35 ErrorResult& aRv) {
36 JSContext* cx = aGlobal.Context();
38 nsCOMPtr<nsIGlobalObject> globalObject =
39 do_QueryInterface(aGlobal.GetAsSupports());
41 if (globalObject->GetAsInnerWindow() &&
42 !globalObject->GetAsInnerWindow()->IsCurrentInnerWindow()) {
43 aRv.ThrowInvalidStateError(
44 "Cannot create worker for a going to be discarded document");
45 return nullptr;
48 RefPtr<WorkerPrivate> workerPrivate = WorkerPrivate::Constructor(
49 cx, aScriptURL, false /* aIsChromeWorker */, WorkerKindDedicated,
50 aOptions.mCredentials, aOptions.mType, aOptions.mName, VoidCString(),
51 nullptr /*aLoadInfo */, aRv);
52 if (NS_WARN_IF(aRv.Failed())) {
53 return nullptr;
56 RefPtr<Worker> worker = new Worker(globalObject, workerPrivate.forget());
57 return worker.forget();
60 Worker::Worker(nsIGlobalObject* aGlobalObject,
61 already_AddRefed<WorkerPrivate> aWorkerPrivate)
62 : DOMEventTargetHelper(aGlobalObject),
63 mWorkerPrivate(std::move(aWorkerPrivate)) {
64 MOZ_ASSERT(mWorkerPrivate);
65 mWorkerPrivate->SetParentEventTargetRef(this);
68 Worker::~Worker() { Terminate(); }
70 JSObject* Worker::WrapObject(JSContext* aCx,
71 JS::Handle<JSObject*> aGivenProto) {
72 JS::Rooted<JSObject*> wrapper(aCx,
73 Worker_Binding::Wrap(aCx, this, aGivenProto));
74 if (wrapper) {
75 // Most DOM objects don't assume they have a reflector. If they don't have
76 // one and need one, they create it. But in workers code, we assume that the
77 // reflector is always present. In order to guarantee that it's always
78 // present, we have to preserve it. Otherwise the GC will happily collect it
79 // as needed.
80 MOZ_ALWAYS_TRUE(TryPreserveWrapper(wrapper));
83 return wrapper;
86 void Worker::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
87 const Sequence<JSObject*>& aTransferable,
88 ErrorResult& aRv) {
89 NS_ASSERT_OWNINGTHREAD(Worker);
91 if (!mWorkerPrivate || mWorkerPrivate->ParentStatusProtected() > Running) {
92 return;
94 RefPtr<WorkerPrivate> workerPrivate = mWorkerPrivate;
95 Unused << workerPrivate;
97 JS::Rooted<JS::Value> transferable(aCx, JS::UndefinedValue());
99 aRv = nsContentUtils::CreateJSValueFromSequenceOfObject(aCx, aTransferable,
100 &transferable);
101 if (NS_WARN_IF(aRv.Failed())) {
102 return;
105 NS_ConvertUTF16toUTF8 nameOrScriptURL(
106 mWorkerPrivate->WorkerName().IsEmpty()
107 ? Substring(
108 mWorkerPrivate->ScriptURL(), 0,
109 std::min(size_t(1024), mWorkerPrivate->ScriptURL().Length()))
110 : Substring(
111 mWorkerPrivate->WorkerName(), 0,
112 std::min(size_t(1024), mWorkerPrivate->WorkerName().Length())));
113 AUTO_PROFILER_MARKER_TEXT("Worker.postMessage", DOM, {}, nameOrScriptURL);
114 uint32_t flags = uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS);
115 if (mWorkerPrivate->IsChromeWorker()) {
116 flags |= uint32_t(js::ProfilingStackFrame::Flags::NONSENSITIVE);
118 mozilla::AutoProfilerLabel PROFILER_RAII(
119 "Worker.postMessage", nameOrScriptURL.get(),
120 JS::ProfilingCategoryPair::DOM, flags);
122 RefPtr<MessageEventRunnable> runnable =
123 new MessageEventRunnable(mWorkerPrivate, WorkerRunnable::WorkerThread);
125 JS::CloneDataPolicy clonePolicy;
126 // DedicatedWorkers are always part of the same agent cluster.
127 clonePolicy.allowIntraClusterClonableSharedObjects();
129 if (NS_IsMainThread()) {
130 nsGlobalWindowInner* win = nsContentUtils::IncumbentInnerWindow();
131 if (win && win->IsSharedMemoryAllowed()) {
132 clonePolicy.allowSharedMemoryObjects();
134 } else {
135 WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
136 if (worker && worker->IsSharedMemoryAllowed()) {
137 clonePolicy.allowSharedMemoryObjects();
141 runnable->Write(aCx, aMessage, transferable, clonePolicy, aRv);
143 if (!mWorkerPrivate || mWorkerPrivate->ParentStatusProtected() > Running) {
144 return;
147 if (NS_WARN_IF(aRv.Failed())) {
148 return;
151 // The worker could have closed between the time we entered this function and
152 // checked ParentStatusProtected and now, which could cause the dispatch to
153 // fail.
154 Unused << NS_WARN_IF(!runnable->Dispatch());
157 void Worker::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
158 const StructuredSerializeOptions& aOptions,
159 ErrorResult& aRv) {
160 PostMessage(aCx, aMessage, aOptions.mTransfer, aRv);
163 void Worker::PostEventWithOptions(JSContext* aCx,
164 JS::Handle<JS::Value> aOptions,
165 const Sequence<JSObject*>& aTransferable,
166 EventWithOptionsRunnable* aRunnable,
167 ErrorResult& aRv) {
168 NS_ASSERT_OWNINGTHREAD(Worker);
170 if (NS_WARN_IF(!mWorkerPrivate ||
171 mWorkerPrivate->ParentStatusProtected() > Running)) {
172 return;
174 RefPtr<WorkerPrivate> workerPrivate = mWorkerPrivate;
175 Unused << workerPrivate;
177 aRunnable->InitOptions(aCx, aOptions, aTransferable, aRv);
179 if (NS_WARN_IF(!mWorkerPrivate ||
180 mWorkerPrivate->ParentStatusProtected() > Running)) {
181 return;
184 if (NS_WARN_IF(aRv.Failed())) {
185 return;
188 Unused << NS_WARN_IF(!aRunnable->Dispatch());
191 void Worker::Terminate() {
192 NS_ASSERT_OWNINGTHREAD(Worker);
194 if (mWorkerPrivate) {
195 mWorkerPrivate->Cancel();
196 mWorkerPrivate = nullptr;
200 NS_IMPL_CYCLE_COLLECTION_CLASS(Worker)
202 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(Worker, DOMEventTargetHelper)
203 if (tmp->mWorkerPrivate) {
204 tmp->mWorkerPrivate->Traverse(cb);
206 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
208 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(Worker, DOMEventTargetHelper)
209 tmp->Terminate();
210 NS_IMPL_CYCLE_COLLECTION_UNLINK_WEAK_PTR
211 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
213 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(Worker, DOMEventTargetHelper)
214 NS_IMPL_CYCLE_COLLECTION_TRACE_END
216 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Worker)
217 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
219 NS_IMPL_ADDREF_INHERITED(Worker, DOMEventTargetHelper)
220 NS_IMPL_RELEASE_INHERITED(Worker, DOMEventTargetHelper)
222 } // namespace mozilla::dom