Files
sousa-gecko/js/loader/ModuleLoadRequest.h
Yoshi Cheng-Hao Huang f8b961dfa3 Bug 2061080 - Part 2: Prevent onFetchComplete from being called twice on failure. r=jonco
If CreateModuleScript fails in OnFetchComplete, LoadFailed() is called
to clear the import data, and then goes back to the ScriptLoader. Later
ScriptLoader calls OnFetchComplete again with the error. This triggers
the assertion of the mPayload is not empty.

Differential Revision: https://phabricator.services.mozilla.com/D320510
2026-09-03 08:38:52 +00:00

167 lines
5.1 KiB
C++

/* 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 js_loader_ModuleLoadRequest_h
#define js_loader_ModuleLoadRequest_h
#include "mozilla/Assertions.h"
#include "mozilla/HoldDropJSObjects.h"
#include "LoadContextBase.h"
#include "ModuleLoaderBase.h"
#include "nsTHashtable.h"
#include "nsURIHashKey.h"
#include "ScriptLoadRequest.h"
#include "js/RootingAPI.h"
#include "js/Value.h"
namespace JS::loader {
class LoadedScript;
class ModuleScript;
class ModuleLoaderBase;
// A load request for a module, created for every top level module script and
// every module import. Load request can share an ModuleScript if there are
// multiple imports of the same module.
class ModuleLoadRequest final : public ScriptLoadRequest {
~ModuleLoadRequest();
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(ModuleLoadRequest,
ScriptLoadRequest)
using SRIMetadata = mozilla::dom::SRIMetadata;
enum class Kind {
// Top-level modules, not imported statically nor dynamically.
TopLevel,
// Modules imported statically with `import` declarations.
StaticImport,
// Modules imported dynamically with dynamic `import()`.
DynamicImport,
};
ModuleLoadRequest(ModuleType aModuleType, const SRIMetadata& aIntegrity,
nsIURI* aReferrer, LoadContextBase* aContext, Kind aKind,
ModuleLoaderBase* aLoader, ModuleLoadRequest* aRootModule);
ModuleLoadRequest(const ModuleLoadRequest& aOther) = delete;
ModuleLoadRequest(ModuleLoadRequest&& aOther) = delete;
bool IsTopLevel() const override { return mKind == Kind::TopLevel; }
bool IsStaticImport() const { return mKind == Kind::StaticImport; }
bool IsDynamicImport() const { return mKind == Kind::DynamicImport; }
bool IsSourcePhaseRequest(JSContext* aCx) const;
bool IsErrored() const;
nsIGlobalObject* GetGlobalObject();
void SetReady() override;
void Cancel() override { mLoader->Cancel(this); };
void SetImport(Handle<JSScript*> aReferrerScript,
Handle<JSObject*> aModuleRequestObj, Handle<Value> aPayload);
void ClearImport();
void ModuleLoaded();
void ModuleErrored();
// Tells the load context that this request stopped waiting on an in-progress
// fetch of the same URL. Must be called whenever that happens, whether the
// fetch resolved or was canceled.
void NotifyModuleWaitFinished();
ModuleLoadRequest* GetRootModule() {
if (!mRootModule) {
return this;
}
return mRootModule;
}
// Convenience methods to call into the module loader for this request.
void CancelDynamicImport(nsresult aResult) {
MOZ_ASSERT(IsDynamicImport());
mLoader->CancelDynamicImport(this, aResult);
}
#ifdef DEBUG
bool IsRegisteredDynamicImport() const {
return IsDynamicImport() && mLoader->HasDynamicImport(this);
}
#endif
nsresult StartModuleLoad() { return mLoader->StartModuleLoad(this); }
nsresult RestartModuleLoad() { return mLoader->RestartModuleLoad(this); }
void OnFetchComplete(nsresult aRv) { mLoader->OnFetchComplete(this, aRv); }
bool InstantiateModuleGraph() {
return mLoader->InstantiateModuleGraph(this);
}
nsresult EvaluateModule() { return mLoader->EvaluateModule(this); }
void ProcessDynamicImport() { mLoader->ProcessDynamicImport(this); }
void LoadFinished();
#ifdef NIGHTLY_BUILD
void SetHasWasmMimeTypeEssence() { mHasWasmMimeTypeEssence = true; }
bool HasWasmMimeTypeEssence() { return mHasWasmMimeTypeEssence; }
#endif
void SetErroredLoadingImports() {
MOZ_ASSERT(IsDynamicImport());
MOZ_ASSERT(IsFetching() || IsCompiling());
mErroredLoadingImports = true;
}
bool IsErroredLoadingImports() const { return mErroredLoadingImports; }
void UpdateReferrerPolicy(mozilla::dom::ReferrerPolicy aReferrerPolicy) {
FetchInfo()->UpdateReferrerPolicy(aReferrerPolicy);
}
public:
// Fields.
const Kind mKind;
// Type of module (JavaScript, JSON)
const ModuleType mModuleType;
// Is this the top level request for a dynamic module import?
const bool mIsDynamicImport;
#ifdef NIGHTLY_BUILD
// We can only distinguish JavaScript and Wasm modules by mime type essence.
bool mHasWasmMimeTypeEssence = false;
#endif
// A flag (for dynamic import) that indicates the module script is
// successfully fetched and compiled, but its dependencies are failed to load.
bool mErroredLoadingImports;
// Pointer to the script loader, used to trigger actions when the module load
// finishes.
RefPtr<ModuleLoaderBase> mLoader;
// Pointer to the top level module of this module graph, nullptr if this is a
// top level module
RefPtr<ModuleLoadRequest> mRootModule;
// Set to a module script object after a successful load or nullptr on
// failure.
RefPtr<ModuleScript> mModuleScript;
Heap<JSScript*> mReferrerScript;
Heap<JSObject*> mModuleRequestObj;
Heap<Value> mPayload;
};
} // namespace JS::loader
#endif // js_loader_ModuleLoadRequest_h