--- a/caps/nsJSPrincipals.cpp
+++ b/caps/nsJSPrincipals.cpp
@@ -12,16 +12,18 @@
#include "nsCOMPtr.h"
#include "nsIServiceManager.h"
#include "nsMemory.h"
#include "nsStringBuffer.h"
#include "mozilla/dom/StructuredCloneTags.h"
// for mozilla::dom::workers::kJSPrincipalsDebugToken
#include "mozilla/dom/workers/Workers.h"
+// for mozilla::dom::worklet::kJSPrincipalsDebugToken
+#include "mozilla/dom/WorkletPrincipal.h"
#include "mozilla/ipc/BackgroundUtils.h"
using namespace mozilla;
using namespace mozilla::ipc;
NS_IMETHODIMP_(MozExternalRefCountType)
nsJSPrincipals::AddRef()
{
@@ -87,16 +89,18 @@ JSPrincipals::dump()
{
if (debugToken == nsJSPrincipals::DEBUG_TOKEN) {
nsAutoCString str;
nsresult rv = static_cast<nsJSPrincipals *>(this)->GetScriptLocation(str);
fprintf(stderr, "nsIPrincipal (%p) = %s\n", static_cast<void*>(this),
NS_SUCCEEDED(rv) ? str.get() : "(unknown)");
} else if (debugToken == dom::workers::kJSPrincipalsDebugToken) {
fprintf(stderr, "Web Worker principal singleton (%p)\n", this);
+ } else if (debugToken == mozilla::dom::WorkletPrincipal::kJSPrincipalsDebugToken) {
+ fprintf(stderr, "Web Worklet principal singleton (%p)\n", this);
} else {
fprintf(stderr,
"!!! JSPrincipals (%p) is not nsJSPrincipals instance - bad token: "
"actual=0x%x expected=0x%x\n",
this, unsigned(debugToken), unsigned(nsJSPrincipals::DEBUG_TOKEN));
}
}
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -54,16 +54,17 @@
#include "mozilla/dom/IPCBlobUtils.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/ScriptSettings.h"
#include "mozilla/dom/TabParent.h"
#include "mozilla/dom/TouchEvent.h"
#include "mozilla/dom/ShadowRoot.h"
#include "mozilla/dom/XULCommandEvent.h"
#include "mozilla/dom/WorkerPrivate.h"
+#include "mozilla/dom/WorkletThread.h"
#include "mozilla/dom/workers/ServiceWorkerManager.h"
#include "mozilla/EventDispatcher.h"
#include "mozilla/EventListenerManager.h"
#include "mozilla/EventStateManager.h"
#include "mozilla/gfx/DataSurfaceHelpers.h"
#include "mozilla/HTMLEditor.h"
#include "mozilla/IMEStateManager.h"
#include "mozilla/InternalMutationEvent.h"
@@ -6192,16 +6193,21 @@ nsContentUtils::GetCurrentJSContext()
/* static */
JSContext *
nsContentUtils::GetCurrentJSContextForThread()
{
MOZ_ASSERT(IsInitialized());
if (MOZ_LIKELY(NS_IsMainThread())) {
return GetCurrentJSContext();
}
+
+ if (WorkletThread::IsOnWorkletThread()) {
+ return WorkletThread::Get()->GetJSContext();
+ }
+
return workers::GetCurrentThreadJSContext();
}
template<typename StringType, typename CharType>
void
_ASCIIToLowerInSitu(StringType& aStr)
{
CharType* iter = aStr.BeginWriting();
--- a/dom/console/Console.cpp
+++ b/dom/console/Console.cpp
@@ -11,16 +11,17 @@
#include "mozilla/dom/Exceptions.h"
#include "mozilla/dom/File.h"
#include "mozilla/dom/FunctionBinding.h"
#include "mozilla/dom/Performance.h"
#include "mozilla/dom/ScriptSettings.h"
#include "mozilla/dom/StructuredCloneHolder.h"
#include "mozilla/dom/ToJSValue.h"
#include "mozilla/dom/WorkletGlobalScope.h"
+#include "mozilla/dom/WorkletThread.h"
#include "mozilla/Maybe.h"
#include "nsCycleCollectionParticipant.h"
#include "nsDocument.h"
#include "nsDOMNavigationTiming.h"
#include "nsGlobalWindow.h"
#include "nsJSUtils.h"
#include "nsNetUtil.h"
#include "WorkerPrivate.h"
@@ -2436,37 +2437,36 @@ Console::GetConsole(const GlobalObject&
}
return console.forget();
}
/* static */ Console*
Console::GetConsoleInternal(const GlobalObject& aGlobal, ErrorResult& aRv)
{
- // Worklet
- if (NS_IsMainThread()) {
- nsCOMPtr<WorkletGlobalScope> workletScope =
- do_QueryInterface(aGlobal.GetAsSupports());
- if (workletScope) {
- return workletScope->GetConsole(aRv);
- }
- }
-
// Window
if (NS_IsMainThread()) {
nsCOMPtr<nsPIDOMWindowInner> innerWindow =
do_QueryInterface(aGlobal.GetAsSupports());
if (NS_WARN_IF(!innerWindow)) {
return nullptr;
}
nsGlobalWindowInner* window = nsGlobalWindowInner::Cast(innerWindow);
return window->GetConsole(aRv);
}
+ // Worklet
+ nsCOMPtr<WorkletGlobalScope> workletScope =
+ do_QueryInterface(aGlobal.GetAsSupports());
+ if (workletScope) {
+ WorkletThread::AssertIsOnWorkletThread();
+ return workletScope->GetConsole(aRv);
+ }
+
// Workers
MOZ_ASSERT(!NS_IsMainThread());
JSContext* cx = aGlobal.Context();
WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx);
MOZ_ASSERT(workerPrivate);
nsCOMPtr<nsIGlobalObject> global =
--- a/dom/worklet/AudioWorkletGlobalScope.cpp
+++ b/dom/worklet/AudioWorkletGlobalScope.cpp
@@ -1,34 +1,34 @@
/* -*- 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 "AudioWorkletGlobalScope.h"
+#include "WorkletPrincipal.h"
#include "mozilla/dom/AudioWorkletGlobalScopeBinding.h"
#include "mozilla/dom/FunctionBinding.h"
namespace mozilla {
namespace dom {
AudioWorkletGlobalScope::AudioWorkletGlobalScope()
{
}
bool
AudioWorkletGlobalScope::WrapGlobalObject(JSContext* aCx,
- nsIPrincipal* aPrincipal,
JS::MutableHandle<JSObject*> aReflector)
{
JS::CompartmentOptions options;
return AudioWorkletGlobalScopeBinding::Wrap(aCx, this, this,
options,
- nsJSPrincipals::get(aPrincipal),
+ WorkletPrincipal::GetWorkletPrincipal(),
true, aReflector);
}
void
AudioWorkletGlobalScope::RegisterProcessor(const nsAString& aType,
VoidFunction& aProcessorCtor)
{
// Nothing to do here.
--- a/dom/worklet/AudioWorkletGlobalScope.h
+++ b/dom/worklet/AudioWorkletGlobalScope.h
@@ -15,17 +15,17 @@ namespace dom {
class VoidFunction;
class AudioWorkletGlobalScope final : public WorkletGlobalScope
{
public:
AudioWorkletGlobalScope();
bool
- WrapGlobalObject(JSContext* aCx, nsIPrincipal* aPrincipal,
+ WrapGlobalObject(JSContext* aCx,
JS::MutableHandle<JSObject*> aReflector) override;
void
RegisterProcessor(const nsAString& aType,
VoidFunction& aProcessorCtor);
private:
~AudioWorkletGlobalScope() = default;
--- a/dom/worklet/PaintWorkletGlobalScope.cpp
+++ b/dom/worklet/PaintWorkletGlobalScope.cpp
@@ -1,34 +1,34 @@
/* -*- 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 "PaintWorkletGlobalScope.h"
+#include "WorkletPrincipal.h"
#include "mozilla/dom/PaintWorkletGlobalScopeBinding.h"
#include "mozilla/dom/FunctionBinding.h"
namespace mozilla {
namespace dom {
PaintWorkletGlobalScope::PaintWorkletGlobalScope()
{
}
bool
PaintWorkletGlobalScope::WrapGlobalObject(JSContext* aCx,
- nsIPrincipal* aPrincipal,
JS::MutableHandle<JSObject*> aReflector)
{
JS::CompartmentOptions options;
return PaintWorkletGlobalScopeBinding::Wrap(aCx, this, this,
options,
- nsJSPrincipals::get(aPrincipal),
+ WorkletPrincipal::GetWorkletPrincipal(),
true, aReflector);
}
void
PaintWorkletGlobalScope::RegisterPaint(const nsAString& aType,
VoidFunction& aProcessorCtor)
{
// Nothing to do here, yet.
--- a/dom/worklet/PaintWorkletGlobalScope.h
+++ b/dom/worklet/PaintWorkletGlobalScope.h
@@ -15,17 +15,17 @@ namespace dom {
class VoidFunction;
class PaintWorkletGlobalScope final : public WorkletGlobalScope
{
public:
PaintWorkletGlobalScope();
bool
- WrapGlobalObject(JSContext* aCx, nsIPrincipal* aPrincipal,
+ WrapGlobalObject(JSContext* aCx,
JS::MutableHandle<JSObject*> aReflector) override;
void
RegisterPaint(const nsAString& aType, VoidFunction& aProcessorCtor);
private:
~PaintWorkletGlobalScope() = default;
};
--- a/dom/worklet/Worklet.cpp
+++ b/dom/worklet/Worklet.cpp
@@ -1,15 +1,16 @@
/* -*- 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 "Worklet.h"
+#include "WorkletThread.h"
#include "AudioWorkletGlobalScope.h"
#include "PaintWorkletGlobalScope.h"
#include "mozilla/dom/WorkletBinding.h"
#include "mozilla/dom/BlobBinding.h"
#include "mozilla/dom/Fetch.h"
#include "mozilla/dom/PromiseNativeHandler.h"
#include "mozilla/dom/RegisterWorkletBindings.h"
@@ -19,30 +20,61 @@
#include "nsIInputStreamPump.h"
#include "nsIThreadRetargetableRequest.h"
#include "nsNetUtil.h"
#include "xpcprivate.h"
namespace mozilla {
namespace dom {
+class ExecutionRunnable final : public Runnable
+{
+public:
+ ExecutionRunnable(WorkletFetchHandler* aHandler, Worklet::WorkletType aType,
+ char16_t* aScriptBuffer, size_t aScriptLength)
+ : mHandler(aHandler)
+ , mWorkletType(aType)
+ , mBuffer(aScriptBuffer, aScriptLength,
+ JS::SourceBufferHolder::GiveOwnership)
+ , mResult(NS_ERROR_FAILURE)
+ {
+ MOZ_ASSERT(NS_IsMainThread());
+ }
+
+ NS_IMETHOD
+ Run() override;
+
+private:
+ void
+ RunOnWorkletThread();
+
+ void
+ RunOnMainThread();
+
+ RefPtr<WorkletFetchHandler> mHandler;
+ Worklet::WorkletType mWorkletType;
+ JS::SourceBufferHolder mBuffer;
+ nsresult mResult;
+};
+
// ---------------------------------------------------------------------------
// WorkletFetchHandler
-class WorkletFetchHandler : public PromiseNativeHandler
- , public nsIStreamLoaderObserver
+class WorkletFetchHandler final : public PromiseNativeHandler
+ , public nsIStreamLoaderObserver
{
public:
- NS_DECL_ISUPPORTS
+ NS_DECL_THREADSAFE_ISUPPORTS
static already_AddRefed<Promise>
Fetch(Worklet* aWorklet, const nsAString& aModuleURL, CallerType aCallerType,
ErrorResult& aRv)
{
MOZ_ASSERT(aWorklet);
+ MOZ_ASSERT(NS_IsMainThread());
nsCOMPtr<nsIGlobalObject> global =
do_QueryInterface(aWorklet->GetParentObject());
MOZ_ASSERT(global);
RefPtr<Promise> promise = Promise::Create(global, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
@@ -55,17 +87,18 @@ public:
doc = window->GetExtantDoc();
if (!doc) {
promise->MaybeReject(NS_ERROR_FAILURE);
return promise.forget();
}
nsCOMPtr<nsIURI> baseURI = doc->GetBaseURI();
nsCOMPtr<nsIURI> resolvedURI;
- nsresult rv = NS_NewURI(getter_AddRefs(resolvedURI), aModuleURL, nullptr, baseURI);
+ nsresult rv = NS_NewURI(getter_AddRefs(resolvedURI), aModuleURL, nullptr,
+ baseURI);
if (NS_WARN_IF(NS_FAILED(rv))) {
promise->MaybeReject(rv);
return promise.forget();
}
nsAutoCString spec;
rv = resolvedURI->GetSpec(spec);
if (NS_WARN_IF(NS_FAILED(rv))) {
@@ -100,16 +133,18 @@ public:
aWorklet->AddImportFetchHandler(spec, handler);
return promise.forget();
}
virtual void
ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
{
+ MOZ_ASSERT(NS_IsMainThread());
+
if (!aValue.isObject()) {
RejectPromises(NS_ERROR_FAILURE);
return;
}
RefPtr<Response> response;
nsresult rv = UNWRAP_OBJECT(Response, &aValue.toObject(), response);
if (NS_WARN_IF(NS_FAILED(rv))) {
@@ -179,85 +214,83 @@ public:
NS_LITERAL_STRING("UTF-8"), nullptr,
scriptTextBuf, scriptTextLength);
if (NS_WARN_IF(NS_FAILED(rv))) {
RejectPromises(rv);
return NS_OK;
}
// Moving the ownership of the buffer
- JS::SourceBufferHolder buffer(scriptTextBuf, scriptTextLength,
- JS::SourceBufferHolder::GiveOwnership);
-
- AutoJSAPI jsapi;
- jsapi.Init();
-
- RefPtr<WorkletGlobalScope> globalScope =
- mWorklet->GetOrCreateGlobalScope(jsapi.cx());
- MOZ_ASSERT(globalScope);
-
- AutoEntryScript aes(globalScope, "Worklet");
- JSContext* cx = aes.cx();
-
- JS::Rooted<JSObject*> globalObj(cx, globalScope->GetGlobalJSObject());
-
- (void) new XPCWrappedNativeScope(cx, globalObj);
+ nsCOMPtr<nsIRunnable> runnable =
+ new ExecutionRunnable(this, mWorklet->Type(), scriptTextBuf,
+ scriptTextLength);
- NS_ConvertUTF16toUTF8 url(mURL);
-
- JS::CompileOptions compileOptions(cx);
- compileOptions.setIntroductionType("Worklet");
- compileOptions.setFileAndLine(url.get(), 0);
- compileOptions.setVersion(JSVERSION_DEFAULT);
- compileOptions.setIsRunOnce(true);
- compileOptions.setNoScriptRval(true);
-
- JSAutoCompartment comp(cx, globalObj);
-
- JS::Rooted<JS::Value> unused(cx);
- if (!JS::Evaluate(cx, compileOptions, buffer, &unused)) {
- ErrorResult error;
- error.MightThrowJSException();
- error.StealExceptionFromJSContext(cx);
- RejectPromises(error.StealNSResult());
+ RefPtr<WorkletThread> thread = mWorklet->GetOrCreateThread();
+ if (!thread) {
+ RejectPromises(NS_ERROR_FAILURE);
return NS_OK;
}
- // All done.
- ResolvePromises();
+ if (NS_FAILED(thread->DispatchRunnable(runnable.forget()))) {
+ RejectPromises(NS_ERROR_FAILURE);
+ return NS_OK;
+ }
+
return NS_OK;
}
virtual void
RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
{
+ MOZ_ASSERT(NS_IsMainThread());
RejectPromises(NS_ERROR_DOM_NETWORK_ERR);
}
+ const nsString& URL() const
+ {
+ return mURL;
+ }
+
+ void
+ ExecutionFailed(nsresult aRv)
+ {
+ MOZ_ASSERT(NS_IsMainThread());
+ RejectPromises(aRv);
+ }
+
+ void
+ ExecutionSucceeded()
+ {
+ MOZ_ASSERT(NS_IsMainThread());
+ ResolvePromises();
+ }
+
private:
WorkletFetchHandler(Worklet* aWorklet, const nsAString& aURL,
Promise* aPromise)
: mWorklet(aWorklet)
, mStatus(ePending)
, mErrorStatus(NS_OK)
, mURL(aURL)
{
MOZ_ASSERT(aWorklet);
MOZ_ASSERT(aPromise);
+ MOZ_ASSERT(NS_IsMainThread());
mPromises.AppendElement(aPromise);
}
~WorkletFetchHandler()
{}
void
AddPromise(Promise* aPromise)
{
MOZ_ASSERT(aPromise);
+ MOZ_ASSERT(NS_IsMainThread());
switch (mStatus) {
case ePending:
mPromises.AppendElement(aPromise);
return;
case eRejected:
MOZ_ASSERT(NS_FAILED(mErrorStatus));
@@ -270,31 +303,33 @@ private:
}
}
void
RejectPromises(nsresult aResult)
{
MOZ_ASSERT(mStatus == ePending);
MOZ_ASSERT(NS_FAILED(aResult));
+ MOZ_ASSERT(NS_IsMainThread());
for (uint32_t i = 0; i < mPromises.Length(); ++i) {
mPromises[i]->MaybeReject(aResult);
}
mPromises.Clear();
mStatus = eRejected;
mErrorStatus = aResult;
mWorklet = nullptr;
}
void
ResolvePromises()
{
MOZ_ASSERT(mStatus == ePending);
+ MOZ_ASSERT(NS_IsMainThread());
for (uint32_t i = 0; i < mPromises.Length(); ++i) {
mPromises[i]->MaybeResolveWithUndefined();
}
mPromises.Clear();
mStatus = eResolved;
mWorklet = nullptr;
@@ -311,98 +346,218 @@ private:
nsresult mErrorStatus;
nsString mURL;
};
NS_IMPL_ISUPPORTS(WorkletFetchHandler, nsIStreamLoaderObserver)
+NS_IMETHODIMP
+ExecutionRunnable::Run()
+{
+ if (WorkletThread::IsOnWorkletThread()) {
+ RunOnWorkletThread();
+ return NS_DispatchToMainThread(this);
+ }
+
+ MOZ_ASSERT(NS_IsMainThread());
+ RunOnMainThread();
+ return NS_OK;
+}
+
+void
+ExecutionRunnable::RunOnWorkletThread()
+{
+ WorkletThread::AssertIsOnWorkletThread();
+
+ WorkletThread* workletThread = WorkletThread::Get();
+ MOZ_ASSERT(workletThread);
+
+ JSContext* cx = workletThread->GetJSContext();
+ JSAutoRequest ar(cx);
+
+ AutoJSAPI jsapi;
+ jsapi.Init();
+
+ RefPtr<WorkletGlobalScope> globalScope =
+ Worklet::CreateGlobalScope(jsapi.cx(), mWorkletType);
+ MOZ_ASSERT(globalScope);
+
+ AutoEntryScript aes(globalScope, "Worklet");
+ cx = aes.cx();
+
+ JS::Rooted<JSObject*> globalObj(cx, globalScope->GetGlobalJSObject());
+
+ JS::CompileOptions compileOptions(cx);
+ compileOptions.setIntroductionType("Worklet");
+ compileOptions.setFileAndLine(NS_ConvertUTF16toUTF8(mHandler->URL()).get(), 0);
+ compileOptions.setVersion(JSVERSION_DEFAULT);
+ compileOptions.setIsRunOnce(true);
+
+ // We only need the setNoScriptRval bit when compiling off-thread here,
+ // since otherwise nsJSUtils::EvaluateString will set it up for us.
+ compileOptions.setNoScriptRval(true);
+
+ JSAutoCompartment comp(cx, globalObj);
+
+ JS::Rooted<JS::Value> unused(cx);
+ if (!JS::Evaluate(cx, compileOptions, mBuffer, &unused)) {
+ ErrorResult error;
+ error.MightThrowJSException();
+ error.StealExceptionFromJSContext(cx);
+ mResult = error.StealNSResult();
+ return;
+ }
+
+ // All done.
+ mResult = NS_OK;
+}
+
+void
+ExecutionRunnable::RunOnMainThread()
+{
+ MOZ_ASSERT(NS_IsMainThread());
+
+ if (NS_FAILED(mResult)) {
+ mHandler->ExecutionFailed(mResult);
+ return;
+ }
+
+ mHandler->ExecutionSucceeded();
+}
+
// ---------------------------------------------------------------------------
// Worklet
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Worklet, mWindow, mScope)
+NS_IMPL_CYCLE_COLLECTION_CLASS(Worklet)
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Worklet)
+ NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow)
+ tmp->TerminateThread();
+ NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Worklet)
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(Worklet)
+
NS_IMPL_CYCLE_COLLECTING_ADDREF(Worklet)
NS_IMPL_CYCLE_COLLECTING_RELEASE(Worklet)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Worklet)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
Worklet::Worklet(nsPIDOMWindowInner* aWindow, nsIPrincipal* aPrincipal,
WorkletType aWorkletType)
: mWindow(aWindow)
, mPrincipal(aPrincipal)
, mWorkletType(aWorkletType)
{
MOZ_ASSERT(aWindow);
MOZ_ASSERT(aPrincipal);
+ MOZ_ASSERT(NS_IsMainThread());
#ifdef RELEASE_OR_BETA
MOZ_CRASH("This code should not go to release/beta yet!");
#endif
}
Worklet::~Worklet()
-{}
+{
+ TerminateThread();
+}
JSObject*
Worklet::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
+ MOZ_ASSERT(NS_IsMainThread());
return WorkletBinding::Wrap(aCx, this, aGivenProto);
}
already_AddRefed<Promise>
Worklet::Import(const nsAString& aModuleURL, CallerType aCallerType,
ErrorResult& aRv)
{
+ MOZ_ASSERT(NS_IsMainThread());
return WorkletFetchHandler::Fetch(this, aModuleURL, aCallerType, aRv);
}
-WorkletGlobalScope*
-Worklet::GetOrCreateGlobalScope(JSContext* aCx)
+/* static */ already_AddRefed<WorkletGlobalScope>
+Worklet::CreateGlobalScope(JSContext* aCx, WorkletType aWorkletType)
{
- if (!mScope) {
- switch (mWorkletType) {
- case eAudioWorklet:
- mScope = new AudioWorkletGlobalScope();
- break;
- case ePaintWorklet:
- mScope = new PaintWorkletGlobalScope();
- break;
- }
+ WorkletThread::AssertIsOnWorkletThread();
+
+ RefPtr<WorkletGlobalScope> scope;
- JS::Rooted<JSObject*> global(aCx);
- NS_ENSURE_TRUE(mScope->WrapGlobalObject(aCx, mPrincipal, &global), nullptr);
-
- JSAutoCompartment ac(aCx, global);
-
- // Init Web IDL bindings
- if (!RegisterWorkletBindings(aCx, global)) {
- mScope = nullptr;
- return nullptr;
- }
-
- JS_FireOnNewGlobalObject(aCx, global);
+ switch (aWorkletType) {
+ case eAudioWorklet:
+ scope = new AudioWorkletGlobalScope();
+ break;
+ case ePaintWorklet:
+ scope = new PaintWorkletGlobalScope();
+ break;
}
- return mScope;
+ JS::Rooted<JSObject*> global(aCx);
+ NS_ENSURE_TRUE(scope->WrapGlobalObject(aCx, &global), nullptr);
+
+ JSAutoCompartment ac(aCx, global);
+
+ // Init Web IDL bindings
+ if (!RegisterWorkletBindings(aCx, global)) {
+ return nullptr;
+ }
+
+ JS_FireOnNewGlobalObject(aCx, global);
+
+ return scope.forget();
}
WorkletFetchHandler*
Worklet::GetImportFetchHandler(const nsACString& aURI)
{
+ MOZ_ASSERT(NS_IsMainThread());
return mImportHandlers.GetWeak(aURI);
}
void
Worklet::AddImportFetchHandler(const nsACString& aURI,
WorkletFetchHandler* aHandler)
{
MOZ_ASSERT(aHandler);
MOZ_ASSERT(!mImportHandlers.GetWeak(aURI));
+ MOZ_ASSERT(NS_IsMainThread());
mImportHandlers.Put(aURI, aHandler);
}
+WorkletThread*
+Worklet::GetOrCreateThread()
+{
+ MOZ_ASSERT(NS_IsMainThread());
+
+ if (!mWorkletThread) {
+ // Thread creation. FIXME: this will change.
+ mWorkletThread = WorkletThread::Create();
+ }
+
+ return mWorkletThread;
+}
+
+void
+Worklet::TerminateThread()
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ if (!mWorkletThread) {
+ return;
+ }
+
+ mWorkletThread->Terminate();
+ mWorkletThread = nullptr;
+}
+
} // dom namespace
} // mozilla namespace
--- a/dom/worklet/Worklet.h
+++ b/dom/worklet/Worklet.h
@@ -15,18 +15,19 @@
class nsPIDOMWindowInner;
class nsIPrincipal;
namespace mozilla {
namespace dom {
class Promise;
+class WorkletFetchHandler;
class WorkletGlobalScope;
-class WorkletFetchHandler;
+class WorkletThread;
enum class CallerType : uint32_t;
class Worklet final : public nsISupports
, public nsWrapperCache
{
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Worklet)
@@ -48,33 +49,47 @@ public:
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
already_AddRefed<Promise>
Import(const nsAString& aModuleURL, CallerType aCallerType,
ErrorResult& aRv);
WorkletGlobalScope*
GetOrCreateGlobalScope(JSContext* aCx);
+ WorkletType Type() const
+ {
+ return mWorkletType;
+ }
+
+ static already_AddRefed<WorkletGlobalScope>
+ CreateGlobalScope(JSContext* aCx, WorkletType aWorkletType);
+
+ WorkletThread*
+ GetOrCreateThread();
private:
~Worklet();
WorkletFetchHandler*
GetImportFetchHandler(const nsACString& aURI);
void
AddImportFetchHandler(const nsACString& aURI, WorkletFetchHandler* aHandler);
+ void
+ TerminateThread();
+
nsCOMPtr<nsPIDOMWindowInner> mWindow;
nsCOMPtr<nsIPrincipal> mPrincipal;
WorkletType mWorkletType;
- RefPtr<WorkletGlobalScope> mScope;
nsRefPtrHashtable<nsCStringHashKey, WorkletFetchHandler> mImportHandlers;
+ RefPtr<WorkletThread> mWorkletThread;
+
friend class WorkletFetchHandler;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_Worklet_h
--- a/dom/worklet/WorkletGlobalScope.h
+++ b/dom/worklet/WorkletGlobalScope.h
@@ -12,18 +12,16 @@
#include "mozilla/dom/BindingDeclarations.h"
#include "nsIGlobalObject.h"
#include "nsWrapperCache.h"
#define WORKLET_IID \
{ 0x1b3f62e7, 0xe357, 0x44be, \
{ 0xbf, 0xe0, 0xdf, 0x85, 0xe6, 0x56, 0x85, 0xac } }
-class nsIPrincipal;
-
namespace mozilla {
namespace dom {
class Console;
class WorkletGlobalScope : public nsIGlobalObject
, public nsWrapperCache
{
@@ -39,18 +37,17 @@ public:
{
return nullptr;
}
virtual JSObject*
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
virtual bool
- WrapGlobalObject(JSContext* aCx, nsIPrincipal* aPrincipal,
- JS::MutableHandle<JSObject*> aReflector) = 0;
+ WrapGlobalObject(JSContext* aCx, JS::MutableHandle<JSObject*> aReflector) = 0;
virtual JSObject*
GetGlobalJSObject() override
{
return GetWrapper();
}
Console*
new file mode 100644
--- /dev/null
+++ b/dom/worklet/WorkletPrincipal.cpp
@@ -0,0 +1,48 @@
+/* -*- 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 "WorkletPrincipal.h"
+#include "jsapi.h"
+#include "mozilla/Assertions.h"
+
+namespace mozilla {
+namespace dom {
+namespace WorkletPrincipal {
+
+struct WorkletPrincipal final : public JSPrincipals
+{
+ bool write(JSContext* aCx, JSStructuredCloneWriter* aWriter) override {
+ MOZ_CRASH("WorkletPrincipal::write not implemented");
+ return false;
+ }
+};
+
+JSPrincipals*
+GetWorkletPrincipal()
+{
+ static WorkletPrincipal sPrincipal;
+
+ /*
+ * To make sure the the principals refcount is initialized to one, atomically
+ * increment it on every pass though this function. If we discover this wasn't
+ * the first time, decrement it again. This avoids the need for
+ * synchronization.
+ */
+ int32_t prevRefcount = sPrincipal.refcount++;
+ if (prevRefcount > 0) {
+ --sPrincipal.refcount;
+ } else {
+#ifdef DEBUG
+ sPrincipal.debugToken = kJSPrincipalsDebugToken;
+#endif
+ }
+
+ return &sPrincipal;
+}
+
+} // namespace WorkletPrincipal
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/worklet/WorkletPrincipal.h
@@ -0,0 +1,25 @@
+/* -*- 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_worklet_WorkletPrincipal_h
+#define mozilla_dom_worklet_WorkletPrincipal_h
+
+namespace mozilla {
+namespace dom {
+
+namespace WorkletPrincipal {
+
+JSPrincipals*
+GetWorkletPrincipal();
+
+static const uint32_t kJSPrincipalsDebugToken = 0x7e2df9f4;
+
+} // WorkletPrincipal
+
+} // dom namespace
+} // mozilla namespace
+
+#endif // mozilla_dom_worklet_WorkletPrincipal_h
new file mode 100644
--- /dev/null
+++ b/dom/worklet/WorkletThread.cpp
@@ -0,0 +1,428 @@
+/* -*- 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 "WorkletThread.h"
+#include "prthread.h"
+#include "nsCycleCollector.h"
+#include "mozilla/dom/AtomList.h"
+
+namespace mozilla {
+namespace dom {
+
+namespace {
+
+// The size of the worklet runtime heaps in bytes.
+#define WORKLET_DEFAULT_RUNTIME_HEAPSIZE 32 * 1024 * 1024
+
+// The size of the generational GC nursery for worklet, in bytes.
+#define WORKLET_DEFAULT_NURSERY_SIZE 1 * 1024 * 1024
+
+// The C stack size. We use the same stack size on all platforms for
+// consistency.
+const uint32_t kWorkletStackSize = 256 * sizeof(size_t) * 1024;
+
+// This class is allocated per thread and can be retrieved from CC.
+// It's used to get the current WorketThread object.
+class WorkletThreadContextPrivate : private PerThreadAtomCache
+{
+public:
+ explicit
+ WorkletThreadContextPrivate(WorkletThread* aWorkletThread)
+ : mWorkletThread(aWorkletThread)
+ {
+ MOZ_ASSERT(!NS_IsMainThread());
+
+ // Zero out the base class members.
+ memset(this, 0, sizeof(PerThreadAtomCache));
+
+ MOZ_ASSERT(mWorkletThread);
+ }
+
+ ~WorkletThreadContextPrivate()
+ {
+ MOZ_ASSERT(!NS_IsMainThread());
+ }
+
+ WorkletThread*
+ GetWorkletThread() const
+ {
+ MOZ_ASSERT(!NS_IsMainThread());
+ MOZ_ASSERT(mWorkletThread);
+ return mWorkletThread;
+ }
+
+private:
+ WorkletThreadContextPrivate(const WorkletThreadContextPrivate&) = delete;
+ WorkletThreadContextPrivate& operator=(const WorkletThreadContextPrivate&) = delete;
+
+ RefPtr<WorkletThread> mWorkletThread;
+};
+
+// Helper functions
+
+bool
+PreserveWrapper(JSContext *cx, JSObject *obj)
+{
+ MOZ_ASSERT(cx);
+ MOZ_ASSERT(obj);
+ MOZ_ASSERT(mozilla::dom::IsDOMObject(obj));
+ return mozilla::dom::TryPreserveWrapper(obj);
+}
+
+void
+DestroyWorkletPrincipals(JSPrincipals* aPrincipals)
+{
+ MOZ_ASSERT_UNREACHABLE("Worklet principals refcount should never fall below one");
+}
+
+JSObject*
+Wrap(JSContext *cx, JS::HandleObject existing, JS::HandleObject obj)
+{
+ if (existing) {
+ js::Wrapper::Renew(cx, existing, obj,
+ &js::OpaqueCrossCompartmentWrapper::singleton);
+ }
+
+ return js::Wrapper::New(cx, obj,
+ &js::OpaqueCrossCompartmentWrapper::singleton);
+}
+
+const JSWrapObjectCallbacks WrapObjectCallbacks =
+{
+ Wrap,
+ nullptr,
+};
+
+} // namespace
+
+// This class controls CC in the worklet thread.
+class WorkletJSContext final : public CycleCollectedJSContext
+{
+public:
+ explicit WorkletJSContext(WorkletThread* aWorkletThread)
+ : mWorkletThread(aWorkletThread)
+ {
+ MOZ_ASSERT(aWorkletThread);
+ MOZ_ASSERT(!NS_IsMainThread());
+
+ nsCycleCollector_startup();
+ }
+
+ ~WorkletJSContext()
+ {
+ MOZ_ASSERT(!NS_IsMainThread());
+
+ JSContext* cx = MaybeContext();
+ if (!cx) {
+ return; // Initialize() must have failed
+ }
+
+ delete static_cast<WorkletThreadContextPrivate*>(JS_GetContextPrivate(cx));
+ JS_SetContextPrivate(cx, nullptr);
+
+ nsCycleCollector_shutdown();
+ }
+
+ nsresult
+ Initialize(JSContext* aParentContext)
+ {
+ MOZ_ASSERT(!NS_IsMainThread());
+
+ nsresult rv =
+ CycleCollectedJSContext::Initialize(aParentContext,
+ WORKLET_DEFAULT_RUNTIME_HEAPSIZE,
+ WORKLET_DEFAULT_NURSERY_SIZE);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+
+ JSContext* cx = Context();
+
+ JS_SetContextPrivate(cx, new WorkletThreadContextPrivate(mWorkletThread));
+
+ js::SetPreserveWrapperCallback(cx, PreserveWrapper);
+ JS_InitDestroyPrincipalsCallback(cx, DestroyWorkletPrincipals);
+ JS_SetWrapObjectCallbacks(cx, &WrapObjectCallbacks);
+ JS_SetFutexCanWait(cx);
+
+ return NS_OK;
+ }
+
+ void
+ PrepareForForgetSkippable() override
+ {
+ }
+
+ void
+ BeginCycleCollectionCallback() override
+ {
+ }
+
+ void
+ EndCycleCollectionCallback(CycleCollectorResults &aResults) override
+ {
+ }
+
+ void
+ DispatchDeferredDeletion(bool aContinuation, bool aPurge) override
+ {
+ MOZ_ASSERT(!aContinuation);
+ nsCycleCollector_doDeferredDeletion();
+ }
+
+ void
+ CustomGCCallback(JSGCStatus aStatus) override
+ {
+ if (aStatus == JSGC_END) {
+ nsCycleCollector_collect(nullptr);
+ }
+ }
+
+ void
+ AfterProcessTask(uint32_t aRecursionDepth) override
+ {
+ CycleCollectedJSContext::AfterProcessTask(aRecursionDepth);
+ }
+
+ void
+ DispatchToMicroTask(already_AddRefed<nsIRunnable> aRunnable) override
+ {
+ RefPtr<nsIRunnable> runnable(aRunnable);
+
+ MOZ_ASSERT(!NS_IsMainThread());
+ MOZ_ASSERT(runnable);
+
+ WorkletThread* workletThread = WorkletThread::Get();
+ MOZ_ASSERT(workletThread);
+
+ JSContext* cx = workletThread->GetJSContext();
+ MOZ_ASSERT(cx);
+
+ JS::Rooted<JSObject*> global(cx, JS::CurrentGlobalOrNull(cx));
+ MOZ_ASSERT(global);
+
+ mPromiseMicroTaskQueue.push(runnable.forget());
+ }
+
+private:
+ RefPtr<WorkletThread> mWorkletThread;
+};
+
+// This is the first runnable to be dispatched. It calls the RunEventLoop() so
+// basically everything happens into this runnable. The reason behind this
+// approach is that, when the Worklet is terminated, it must not have any JS in
+// stack, but, because we have CC, nsIThread creates an AutoNoJSAPI object by
+// default. Using this runnable, CC exists only into it.
+class WorkletThread::PrimaryRunnable final : public Runnable
+{
+public:
+ explicit PrimaryRunnable(WorkletThread* aWorkletThread)
+ : mWorkletThread(aWorkletThread)
+ {
+ MOZ_ASSERT(aWorkletThread);
+ MOZ_ASSERT(NS_IsMainThread());
+
+ mParentContext =
+ JS_GetParentContext(CycleCollectedJSContext::Get()->Context());
+ MOZ_ASSERT(mParentContext);
+ }
+
+ NS_IMETHOD
+ Run() override
+ {
+ mWorkletThread->RunEventLoop(mParentContext);
+ return NS_OK;
+ }
+
+private:
+ RefPtr<WorkletThread> mWorkletThread;
+ JSContext* mParentContext;
+};
+
+// This is the last runnable to be dispatched. It calls the TerminateInternal()
+class WorkletThread::TerminateRunnable final : public Runnable
+{
+public:
+ explicit TerminateRunnable(WorkletThread* aWorkletThread)
+ : mWorkletThread(aWorkletThread)
+ {
+ MOZ_ASSERT(aWorkletThread);
+ MOZ_ASSERT(NS_IsMainThread());
+ }
+
+ NS_IMETHOD
+ Run() override
+ {
+ mWorkletThread->TerminateInternal();
+ return NS_OK;
+ }
+
+private:
+ RefPtr<WorkletThread> mWorkletThread;
+};
+
+WorkletThread::WorkletThread()
+ : nsThread(nsThread::NOT_MAIN_THREAD, kWorkletStackSize)
+ , mJSContext(nullptr)
+{
+}
+
+WorkletThread::~WorkletThread()
+{
+ // This should be gone during the termination step.
+ MOZ_ASSERT(!mJSContext);
+}
+
+// static
+already_AddRefed<WorkletThread>
+WorkletThread::Create()
+{
+ RefPtr<WorkletThread> thread = new WorkletThread();
+ if (NS_WARN_IF(NS_FAILED(thread->Init()))) {
+ return nullptr;
+ }
+
+ RefPtr<PrimaryRunnable> runnable = new PrimaryRunnable(thread);
+ if (NS_WARN_IF(NS_FAILED(thread->DispatchRunnable(runnable.forget())))) {
+ return nullptr;
+ }
+
+ return thread.forget();
+}
+
+nsresult
+WorkletThread::DispatchRunnable(already_AddRefed<nsIRunnable> aRunnable)
+{
+ nsCOMPtr<nsIRunnable> runnable(aRunnable);
+ return nsThread::Dispatch(runnable.forget(), NS_DISPATCH_NORMAL);
+}
+
+NS_IMETHODIMP
+WorkletThread::DispatchFromScript(nsIRunnable* aRunnable, uint32_t aFlags)
+{
+ nsCOMPtr<nsIRunnable> runnable(aRunnable);
+ return Dispatch(runnable.forget(), aFlags);
+}
+
+NS_IMETHODIMP
+WorkletThread::Dispatch(already_AddRefed<nsIRunnable> aRunnable,
+ uint32_t aFlags)
+{
+ nsCOMPtr<nsIRunnable> runnable(aRunnable);
+
+ // Worklet only supports asynchronous dispatch.
+ if (NS_WARN_IF(aFlags != NS_DISPATCH_NORMAL)) {
+ return NS_ERROR_UNEXPECTED;
+ }
+
+ return nsThread::Dispatch(runnable.forget(), NS_DISPATCH_NORMAL);
+}
+
+NS_IMETHODIMP
+WorkletThread::DelayedDispatch(already_AddRefed<nsIRunnable>, uint32_t aFlags)
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+void
+WorkletThread::RunEventLoop(JSContext* aParentContext)
+{
+ MOZ_ASSERT(!NS_IsMainThread());
+
+ PR_SetCurrentThreadName("worklet");
+
+ WorkletJSContext context(this);
+ nsresult rv = context.Initialize(aParentContext);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ // TODO: error propagation
+ return;
+ }
+
+ // FIXME: JS_SetDefaultLocale
+ // FIXME: JSSettings
+ // FIXME: JS_SetNativeStackQuota
+ // FIXME: JS_SetSecurityCallbacks
+ // FIXME: JS::SetAsmJSCacheOps
+ // FIXME: JS::SetAsyncTaskCallbacks
+ // FIXME: JS_AddInterruptCallback
+ // FIXME: JS::SetCTypesActivityCallback
+ // FIXME: JS_SetGCZeal
+
+ if (!JS::InitSelfHostedCode(context.Context())) {
+ // TODO: error propagation
+ return;
+ }
+
+ mJSContext = context.Context();
+
+ while (mJSContext) {
+ MOZ_ALWAYS_TRUE(NS_ProcessNextEvent(this, /* wait: */ true));
+ }
+
+ MOZ_ASSERT(mJSContext == nullptr);
+}
+
+void
+WorkletThread::Terminate()
+{
+ MOZ_ASSERT(NS_IsMainThread());
+
+ RefPtr<TerminateRunnable> runnable = new TerminateRunnable(this);
+ DispatchRunnable(runnable.forget());
+}
+
+void
+WorkletThread::TerminateInternal()
+{
+ AssertIsOnWorkletThread();
+
+ mJSContext = nullptr;
+
+ nsCOMPtr<nsIRunnable> runnable =
+ NewRunnableMethod(this, &WorkletThread::Shutdown);
+ NS_DispatchToMainThread(runnable);
+}
+
+JSContext*
+WorkletThread::GetJSContext() const
+{
+ AssertIsOnWorkletThread();
+ MOZ_ASSERT(mJSContext);
+ return mJSContext;
+}
+
+/* static */ bool
+WorkletThread::IsOnWorkletThread()
+{
+ const char* threadName = PR_GetThreadName(PR_GetCurrentThread());
+ return threadName && !strcmp(threadName, "worklet");
+}
+
+/* static */ void
+WorkletThread::AssertIsOnWorkletThread()
+{
+ MOZ_ASSERT(IsOnWorkletThread());
+}
+
+/* static */ WorkletThread*
+WorkletThread::Get()
+{
+ AssertIsOnWorkletThread();
+
+ CycleCollectedJSContext* ccjscx = CycleCollectedJSContext::Get();
+ MOZ_ASSERT(ccjscx);
+
+ void* cxPrivate = JS_GetContextPrivate(ccjscx->Context());
+ MOZ_ASSERT(cxPrivate);
+
+ return
+ static_cast<WorkletThreadContextPrivate*>(cxPrivate)->GetWorkletThread();
+}
+
+NS_IMPL_ISUPPORTS_INHERITED0(WorkletThread, nsThread)
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/worklet/WorkletThread.h
@@ -0,0 +1,83 @@
+/* -*- 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_worklet_WorkletThread_h
+#define mozilla_dom_worklet_WorkletThread_h
+
+#include "mozilla/Attributes.h"
+#include "mozilla/CondVar.h"
+#include "mozilla/RefPtr.h"
+#include "mozilla/UniquePtr.h"
+#include "nsThread.h"
+
+class JSContext;
+class JSPrincipals;
+class nsIRunnable;
+
+namespace mozilla {
+namespace dom {
+
+class WorkletThread final : public nsThread
+{
+public:
+ NS_DECL_ISUPPORTS_INHERITED
+
+ static already_AddRefed<WorkletThread>
+ Create();
+
+ static WorkletThread*
+ Get();
+
+ static bool
+ IsOnWorkletThread();
+
+ static void
+ AssertIsOnWorkletThread();
+
+ static JSPrincipals*
+ GetWorkerPrincipal();
+
+ JSContext*
+ GetJSContext() const;
+
+ nsresult
+ DispatchRunnable(already_AddRefed<nsIRunnable> aRunnable);
+
+ void
+ Terminate();
+
+private:
+ WorkletThread();
+ ~WorkletThread();
+
+ void
+ RunEventLoop(JSContext* aParentContext);
+ class PrimaryRunnable;
+
+ void
+ TerminateInternal();
+ class TerminateRunnable;
+
+ // This should only be called by consumers that have an
+ // nsIEventTarget/nsIThread pointer.
+ NS_IMETHOD
+ Dispatch(already_AddRefed<nsIRunnable> aRunnable, uint32_t aFlags) override;
+
+ NS_IMETHOD
+ DispatchFromScript(nsIRunnable* aRunnable, uint32_t aFlags) override;
+
+ NS_IMETHOD
+ DelayedDispatch(already_AddRefed<nsIRunnable>, uint32_t) override;
+
+ // Touched only on the worklet thread. This is a raw pointer because it's set
+ // and nullified by RunEventLoop().
+ JSContext* mJSContext;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_worklet_WorkletThread_h
--- a/dom/worklet/moz.build
+++ b/dom/worklet/moz.build
@@ -7,23 +7,27 @@
with Files("**"):
BUG_COMPONENT = ("Core", "DOM")
EXPORTS.mozilla.dom += [
'AudioWorkletGlobalScope.h',
'PaintWorkletGlobalScope.h',
'Worklet.h',
'WorkletGlobalScope.h',
+ 'WorkletPrincipal.h',
+ 'WorkletThread.h',
]
UNIFIED_SOURCES += [
'AudioWorkletGlobalScope.cpp',
'PaintWorkletGlobalScope.cpp',
'Worklet.cpp',
'WorkletGlobalScope.cpp',
+ 'WorkletPrincipal.cpp',
+ 'WorkletThread.cpp',
]
LOCAL_INCLUDES += [
'/js/xpconnect/src',
]
include('/ipc/chromium/chromium-config.mozbuild')