summaryrefslogtreecommitdiffstats
path: root/js/loader/ModuleLoadRequest.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'js/loader/ModuleLoadRequest.cpp')
-rw-r--r--js/loader/ModuleLoadRequest.cpp238
1 files changed, 238 insertions, 0 deletions
diff --git a/js/loader/ModuleLoadRequest.cpp b/js/loader/ModuleLoadRequest.cpp
new file mode 100644
index 0000000000..6b4b578127
--- /dev/null
+++ b/js/loader/ModuleLoadRequest.cpp
@@ -0,0 +1,238 @@
+/* -*- 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 "ModuleLoadRequest.h"
+
+#include "mozilla/HoldDropJSObjects.h"
+#include "mozilla/dom/ScriptLoadContext.h"
+
+#include "LoadedScript.h"
+#include "LoadContextBase.h"
+#include "ModuleLoaderBase.h"
+
+namespace JS::loader {
+
+#undef LOG
+#define LOG(args) \
+ MOZ_LOG(ModuleLoaderBase::gModuleLoaderBaseLog, mozilla::LogLevel::Debug, \
+ args)
+
+NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED_0(ModuleLoadRequest,
+ ScriptLoadRequest)
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(ModuleLoadRequest)
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(ModuleLoadRequest,
+ ScriptLoadRequest)
+ NS_IMPL_CYCLE_COLLECTION_UNLINK(mLoader, mModuleScript, mImports, mRootModule)
+ tmp->ClearDynamicImport();
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ModuleLoadRequest,
+ ScriptLoadRequest)
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLoader, mModuleScript, mImports,
+ mRootModule)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(ModuleLoadRequest,
+ ScriptLoadRequest)
+ NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mDynamicReferencingPrivate)
+ NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mDynamicSpecifier)
+ NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mDynamicPromise)
+NS_IMPL_CYCLE_COLLECTION_TRACE_END
+
+/* static */
+VisitedURLSet* ModuleLoadRequest::NewVisitedSetForTopLevelImport(nsIURI* aURI) {
+ auto set = new VisitedURLSet();
+ set->PutEntry(aURI);
+ return set;
+}
+
+ModuleLoadRequest::ModuleLoadRequest(
+ nsIURI* aURI, ScriptFetchOptions* aFetchOptions,
+ const mozilla::dom::SRIMetadata& aIntegrity, nsIURI* aReferrer,
+ LoadContextBase* aContext, bool aIsTopLevel, bool aIsDynamicImport,
+ ModuleLoaderBase* aLoader, VisitedURLSet* aVisitedSet,
+ ModuleLoadRequest* aRootModule)
+ : ScriptLoadRequest(ScriptKind::eModule, aURI, aFetchOptions, aIntegrity,
+ aReferrer, aContext),
+ mIsTopLevel(aIsTopLevel),
+ mIsDynamicImport(aIsDynamicImport),
+ mLoader(aLoader),
+ mRootModule(aRootModule),
+ mVisitedSet(aVisitedSet) {
+ MOZ_ASSERT(mLoader);
+}
+
+nsIGlobalObject* ModuleLoadRequest::GetGlobalObject() {
+ return mLoader->GetGlobalObject();
+}
+
+bool ModuleLoadRequest::IsErrored() const {
+ return !mModuleScript || mModuleScript->HasParseError();
+}
+
+void ModuleLoadRequest::Cancel() {
+ if (IsCanceled()) {
+ AssertAllImportsCancelled();
+ return;
+ }
+
+ ScriptLoadRequest::Cancel();
+ mModuleScript = nullptr;
+ CancelImports();
+ mReady.RejectIfExists(NS_ERROR_DOM_ABORT_ERR, __func__);
+}
+
+void ModuleLoadRequest::SetReady() {
+ // Mark a module as ready to execute. This means that this module and all it
+ // dependencies have had their source loaded, parsed as a module and the
+ // modules instantiated.
+ //
+ // The mReady promise is used to ensure that when all dependencies of a module
+ // have become ready, DependenciesLoaded is called on that module
+ // request. This is set up in StartFetchingModuleDependencies.
+
+ AssertAllImportsReady();
+
+ ScriptLoadRequest::SetReady();
+ mReady.ResolveIfExists(true, __func__);
+}
+
+void ModuleLoadRequest::ModuleLoaded() {
+ // A module that was found to be marked as fetching in the module map has now
+ // been loaded.
+
+ LOG(("ScriptLoadRequest (%p): Module loaded", this));
+
+ if (IsCanceled()) {
+ AssertAllImportsCancelled();
+ return;
+ }
+
+ MOZ_ASSERT(IsFetching());
+
+ mModuleScript = mLoader->GetFetchedModule(mURI);
+ if (IsErrored()) {
+ ModuleErrored();
+ return;
+ }
+
+ mLoader->StartFetchingModuleDependencies(this);
+}
+
+void ModuleLoadRequest::LoadFailed() {
+ // We failed to load the source text or an error occurred unrelated to the
+ // content of the module (e.g. OOM).
+
+ LOG(("ScriptLoadRequest (%p): Module load failed", this));
+
+ if (IsCanceled()) {
+ AssertAllImportsCancelled();
+ return;
+ }
+
+ MOZ_ASSERT(IsFetching());
+ MOZ_ASSERT(!mModuleScript);
+
+ Cancel();
+ LoadFinished();
+}
+
+void ModuleLoadRequest::ModuleErrored() {
+ // Parse error, failure to resolve imported modules or error loading import.
+
+ LOG(("ScriptLoadRequest (%p): Module errored", this));
+
+ if (IsCanceled()) {
+ return;
+ }
+
+ MOZ_ASSERT(!IsReadyToRun());
+
+ CheckModuleDependenciesLoaded();
+ MOZ_ASSERT(IsErrored());
+
+ CancelImports();
+ SetReady();
+ LoadFinished();
+}
+
+void ModuleLoadRequest::DependenciesLoaded() {
+ // The module and all of its dependencies have been successfully fetched and
+ // compiled.
+
+ LOG(("ScriptLoadRequest (%p): Module dependencies loaded", this));
+
+ if (IsCanceled()) {
+ return;
+ }
+
+ MOZ_ASSERT(IsLoadingImports());
+ MOZ_ASSERT(!IsErrored());
+
+ CheckModuleDependenciesLoaded();
+ SetReady();
+ LoadFinished();
+}
+
+void ModuleLoadRequest::CheckModuleDependenciesLoaded() {
+ LOG(("ScriptLoadRequest (%p): Check dependencies loaded", this));
+
+ if (!mModuleScript || mModuleScript->HasParseError()) {
+ return;
+ }
+ for (const auto& childRequest : mImports) {
+ ModuleScript* childScript = childRequest->mModuleScript;
+ if (!childScript) {
+ mModuleScript = nullptr;
+ LOG(("ScriptLoadRequest (%p): %p failed (load error)", this,
+ childRequest.get()));
+ return;
+ }
+ }
+
+ LOG(("ScriptLoadRequest (%p): all ok", this));
+}
+
+void ModuleLoadRequest::CancelImports() {
+ for (size_t i = 0; i < mImports.Length(); i++) {
+ mImports[i]->Cancel();
+ }
+}
+
+void ModuleLoadRequest::LoadFinished() {
+ RefPtr<ModuleLoadRequest> request(this);
+ if (IsTopLevel() && IsDynamicImport()) {
+ mLoader->RemoveDynamicImport(request);
+ }
+
+ mLoader->OnModuleLoadComplete(request);
+}
+
+void ModuleLoadRequest::ClearDynamicImport() {
+ mDynamicReferencingPrivate = JS::UndefinedValue();
+ mDynamicSpecifier = nullptr;
+ mDynamicPromise = nullptr;
+}
+
+inline void ModuleLoadRequest::AssertAllImportsReady() const {
+#ifdef DEBUG
+ for (const auto& request : mImports) {
+ MOZ_ASSERT(request->IsReadyToRun());
+ }
+#endif
+}
+
+inline void ModuleLoadRequest::AssertAllImportsCancelled() const {
+#ifdef DEBUG
+ for (const auto& request : mImports) {
+ MOZ_ASSERT(request->IsCanceled());
+ }
+#endif
+}
+
+} // namespace JS::loader