Bug 1540913 - Part 4: Introduce WorkerScriptLoader configuration for dynamic import; r=jonco

Earlier, we introduced GetBaseURI to the module loader. This allows us to get the BaseURI for a
dynamic import even after the importing script/module's ScriptLoader has been cleaned up. However,
we now need to be able to handle the case where we need to run the dynamic import and load it. In
order to do this, we need to create a scriptloader configured for dynamic import. The most important
difference between this scriptloader and the one that is normally used for script loading in workers
is that we *do not have a syncLoopTarget* to which we return. There are a couple of reasons for
this:

* Dynamic import (and modules in general) relies on the event loop to resolve. If we create a
syncLoop here, we will end up pausing execution, and this breaks the StartModuleLoad algorithm. We
will never complete and the result will be that we are in the wrong state when we return here.
* We do not have perfect knowledge of the future, so we cannot keep the existing script loader alive
in the case that it might be used for loading in the future.
* We cannot migrate the ModuleLoader to not use sync loading without significantly changing other
aspects of how loading scripts on workers works. This becomes particularily evident with error
handling
(https://searchfox.org/mozilla-central/rev/00ea1649b59d5f427979e2d6ba42be96f62d6e82/dom/workers/WorkerPrivate.cpp#383-444),
and in addition, for reasons I wasn't able to discern, using the CurrentEventTarget results in hard
to identify errors. When there is time to investigate this fully, the ModuleLoader may move away
from using a syncLoop itself.

For now, all main-script loads (whether they are modules or classic scripts) will use the sync loop,
and all dynamic imports will create a new script loader for their needs that is not using the sync
loop. The book keeping for this is in the next patch.

Differential Revision: https://phabricator.services.mozilla.com/D171685
This commit is contained in:
Yulia 2023-03-14 18:16:31 +00:00
parent 99088fb36f
commit 0350774d47
5 changed files with 37 additions and 7 deletions

View File

@ -477,7 +477,6 @@ WorkerScriptLoader::WorkerScriptLoader(
mCleanedUp(false),
mCleanUpLock("cleanUpLock") {
aWorkerPrivate->AssertIsOnWorkerThread();
MOZ_ASSERT(aSyncLoopTarget);
RefPtr<WorkerScriptLoader> self = this;
@ -515,6 +514,10 @@ ScriptLoadRequest* WorkerScriptLoader::GetMainScript() {
void WorkerScriptLoader::InitModuleLoader() {
mWorkerRef->Private()->AssertIsOnWorkerThread();
if (GetGlobal()->GetModuleLoader(nullptr)) {
return;
}
RefPtr<WorkerModuleLoader> moduleLoader =
new WorkerModuleLoader(this, GetGlobal(), mSyncLoopTarget.get());
@ -1181,8 +1184,11 @@ void WorkerScriptLoader::ShutdownScriptLoader(bool aResult, bool aMutedError) {
}
mWorkerRef->Private()->AssertIsOnWorkerThread();
mWorkerRef->Private()->StopSyncLoop(mSyncLoopTarget,
aResult ? NS_OK : NS_ERROR_FAILURE);
// Module loader doesn't use sync loop for dynamic import
if (mSyncLoopTarget) {
mWorkerRef->Private()->StopSyncLoop(mSyncLoopTarget,
aResult ? NS_OK : NS_ERROR_FAILURE);
}
// Signal cleanup
mCleanedUp = true;
@ -1447,6 +1453,7 @@ void ScriptLoaderRunnable::DispatchProcessPendingRequests() {
mScriptLoader, mWorkerRef->Private(), mScriptLoader->mSyncLoopTarget,
Span<RefPtr<ThreadSafeRequestHandle>>{maybeRangeToExecute->first,
maybeRangeToExecute->second});
if (!runnable->Dispatch()) {
MOZ_ASSERT(false, "This should never fail!");
}

View File

@ -202,6 +202,8 @@ class WorkerScriptLoader : public JS::loader::ScriptLoaderInterface,
bool DispatchLoadScripts();
WorkerScriptType GetWorkerScriptType() { return mWorkerScriptType; }
protected:
nsIURI* GetBaseURI() const override;

View File

@ -61,6 +61,18 @@ already_AddRefed<ModuleLoadRequest> WorkerModuleLoader::CreateStaticImport(
return request.forget();
}
void WorkerModuleLoader::CreateDynamicImportLoader() {
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
workerPrivate->AssertIsOnWorkerThread();
ErrorResult rv;
SetScriptLoader(new loader::WorkerScriptLoader(
workerPrivate, nullptr, nullptr, GetScriptLoader()->GetWorkerScriptType(),
rv));
SetEventTarget(GetCurrentSerialEventTarget());
}
already_AddRefed<ModuleLoadRequest> WorkerModuleLoader::CreateDynamicImport(
JSContext* aCx, nsIURI* aURI, LoadedScript* aMaybeActiveScript,
JS::Handle<JS::Value> aReferencingPrivate, JS::Handle<JSString*> aSpecifier,

View File

@ -8,6 +8,8 @@
#define mozilla_loader_WorkerModuleLoader_h
#include "js/loader/ModuleLoaderBase.h"
#include "mozilla/dom/SerializedStackHolder.h"
#include "mozilla/UniquePtr.h"
namespace mozilla::dom::workerinternals::loader {
class WorkerScriptLoader;
@ -42,6 +44,14 @@ class WorkerModuleLoader : public JS::loader::ModuleLoaderBase {
private:
~WorkerModuleLoader() = default;
void CreateDynamicImportLoader();
void SetScriptLoader(JS::loader::ScriptLoaderInterface* aLoader) {
mLoader = aLoader;
}
void SetEventTarget(nsISerialEventTarget* aEventTarget) {
mEventTarget = aEventTarget;
}
WorkerScriptLoader* GetScriptLoader();
nsIURI* GetBaseURI() const override;

View File

@ -177,16 +177,15 @@ class ModuleLoaderBase : public nsISupports {
nsCOMPtr<nsIGlobalObject> mGlobalObject;
// Event handler used to process MozPromise actions, used internally to wait
// for fetches to finish and for imports to become avilable.
nsCOMPtr<nsISerialEventTarget> mEventTarget;
// https://html.spec.whatwg.org/multipage/webappapis.html#import-maps-allowed
//
// Each Window has an import maps allowed boolean, initially true.
bool mImportMapsAllowed = true;
protected:
// Event handler used to process MozPromise actions, used internally to wait
// for fetches to finish and for imports to become avilable.
nsCOMPtr<nsISerialEventTarget> mEventTarget;
RefPtr<ScriptLoaderInterface> mLoader;
mozilla::UniquePtr<ImportMap> mImportMap;