Skip to content

Commit

Permalink
Bug 1842798 - Part 1: Remove use of MozPromise to wait for module fet…
Browse files Browse the repository at this point in the history
…ch r=smaug

This replaces the promise with a list of module requests that are waiting for a
resource to be fetched. When the fetch completes the waiting requests are
resumed appropriately. This now happens immediately rather tha via dispatching
a runnable.

Differential Revision: https://phabricator.services.mozilla.com/D183272
  • Loading branch information
jonco3 committed Aug 3, 2023
1 parent 460072f commit baca1b8
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 44 deletions.
92 changes: 56 additions & 36 deletions js/loader/ModuleLoaderBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,19 @@ mozilla::LazyLogModule ModuleLoaderBase::gModuleLoaderBaseLog(
#define LOG_ENABLED() \
MOZ_LOG_TEST(ModuleLoaderBase::gModuleLoaderBaseLog, mozilla::LogLevel::Debug)

//////////////////////////////////////////////////////////////
// ModuleLoaderBase::WaitingRequests
//////////////////////////////////////////////////////////////

NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ModuleLoaderBase::WaitingRequests)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END

NS_IMPL_CYCLE_COLLECTION(ModuleLoaderBase::WaitingRequests, mWaiting)

NS_IMPL_CYCLE_COLLECTING_ADDREF(ModuleLoaderBase::WaitingRequests)
NS_IMPL_CYCLE_COLLECTING_RELEASE(ModuleLoaderBase::WaitingRequests)

//////////////////////////////////////////////////////////////
// ModuleLoaderBase
//////////////////////////////////////////////////////////////
Expand All @@ -58,7 +71,7 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ModuleLoaderBase)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END

NS_IMPL_CYCLE_COLLECTION(ModuleLoaderBase, mFetchedModules,
NS_IMPL_CYCLE_COLLECTION(ModuleLoaderBase, mFetchingModules, mFetchedModules,
mDynamicImportRequests, mGlobalObject, mEventTarget,
mLoader)

Expand Down Expand Up @@ -408,10 +421,7 @@ nsresult ModuleLoaderBase::StartOrRestartModuleLoad(ModuleLoadRequest* aRequest,

if (aRestart == RestartRequest::No && ModuleMapContainsURL(request->mURI)) {
LOG(("ScriptLoadRequest (%p): Waiting for module fetch", aRequest));
WaitForModuleFetch(request->mURI)
->Then(mEventTarget, __func__, request,
&ModuleLoadRequest::ModuleLoaded,
&ModuleLoadRequest::LoadFailed);
WaitForModuleFetch(request);
return NS_OK;
}

Expand Down Expand Up @@ -471,17 +481,15 @@ void ModuleLoaderBase::SetModuleFetchStarted(ModuleLoadRequest* aRequest) {
MOZ_ASSERT(aRequest->IsFetching());
MOZ_ASSERT(!ModuleMapContainsURL(aRequest->mURI));

mFetchingModules.InsertOrUpdate(
aRequest->mURI, RefPtr<mozilla::GenericNonExclusivePromise::Private>{});
mFetchingModules.InsertOrUpdate(aRequest->mURI, nullptr);
}

void ModuleLoaderBase::SetModuleFetchFinishedAndResumeWaitingRequests(
ModuleLoadRequest* aRequest, nsresult aResult) {
// Update module map with the result of fetching a single module script.
//
// If any requests for the same URL are waiting on this one to complete, they
// will have ModuleLoaded or LoadFailed on them when the promise is
// resolved/rejected. This is set up in StartLoad.
// If any requests for the same URL are waiting on this one to complete, call
// ModuleLoaded or LoadFailed to resume or fail them as appropriate.

MOZ_ASSERT(aRequest->mLoader == this);

Expand All @@ -490,8 +498,9 @@ void ModuleLoaderBase::SetModuleFetchFinishedAndResumeWaitingRequests(
"%u)",
aRequest, aRequest->mModuleScript.get(), unsigned(aResult)));

RefPtr<mozilla::GenericNonExclusivePromise::Private> promise;
if (!mFetchingModules.Remove(aRequest->mURI, getter_AddRefs(promise))) {
RefPtr<WaitingRequests> waitingRequests;
if (!mFetchingModules.Remove(aRequest->mURI,
getter_AddRefs(waitingRequests))) {
LOG(
("ScriptLoadRequest (%p): Key not found in mFetchingModules, "
"assuming we have an inline module or have finished fetching already",
Expand All @@ -504,37 +513,47 @@ void ModuleLoaderBase::SetModuleFetchFinishedAndResumeWaitingRequests(

mFetchedModules.InsertOrUpdate(aRequest->mURI, RefPtr{moduleScript});

if (promise) {
if (moduleScript) {
LOG(("ScriptLoadRequest (%p): resolving %p", aRequest, promise.get()));
promise->Resolve(true, __func__);
} else {
LOG(("ScriptLoadRequest (%p): rejecting %p", aRequest, promise.get()));
promise->Reject(aResult, __func__);
}
if (waitingRequests) {
LOG(("ScriptLoadRequest (%p): Resuming waiting requests", aRequest));
ResumeWaitingRequests(waitingRequests, bool(moduleScript));
}
}

void ModuleLoaderBase::ResumeWaitingRequests(WaitingRequests* aWaitingRequests,
bool aSuccess) {
for (ModuleLoadRequest* request : aWaitingRequests->mWaiting) {
ResumeWaitingRequest(request, aSuccess);
}
}

void ModuleLoaderBase::ResumeWaitingRequest(ModuleLoadRequest* aRequest,
bool aSuccess) {
if (aSuccess) {
aRequest->ModuleLoaded();
} else {
aRequest->LoadFailed();
}
}

RefPtr<mozilla::GenericNonExclusivePromise>
ModuleLoaderBase::WaitForModuleFetch(nsIURI* aURL) {
MOZ_ASSERT(ModuleMapContainsURL(aURL));
void ModuleLoaderBase::WaitForModuleFetch(ModuleLoadRequest* aRequest) {
nsIURI* uri = aRequest->mURI;
MOZ_ASSERT(ModuleMapContainsURL(uri));

nsURIHashKey key(aURL);
if (auto entry = mFetchingModules.Lookup(aURL)) {
if (!entry.Data()) {
entry.Data() = new mozilla::GenericNonExclusivePromise::Private(__func__);
if (auto entry = mFetchingModules.Lookup(uri)) {
RefPtr<WaitingRequests> waitingRequests = entry.Data();
if (!waitingRequests) {
waitingRequests = new WaitingRequests();
mFetchingModules.InsertOrUpdate(uri, waitingRequests);
}
return entry.Data();

waitingRequests->mWaiting.AppendElement(aRequest);
return;
}

RefPtr<ModuleScript> ms;
MOZ_ALWAYS_TRUE(mFetchedModules.Get(aURL, getter_AddRefs(ms)));
if (!ms) {
return mozilla::GenericNonExclusivePromise::CreateAndReject(
NS_ERROR_FAILURE, __func__);
}
MOZ_ALWAYS_TRUE(mFetchedModules.Get(uri, getter_AddRefs(ms)));

return mozilla::GenericNonExclusivePromise::CreateAndResolve(true, __func__);
ResumeWaitingRequest(aRequest, bool(ms));
}

ModuleScript* ModuleLoaderBase::GetFetchedModule(nsIURI* aURL) const {
Expand Down Expand Up @@ -1017,8 +1036,9 @@ void ModuleLoaderBase::Shutdown() {
CancelAndClearDynamicImports();

for (const auto& entry : mFetchingModules) {
if (entry.GetData()) {
entry.GetData()->Reject(NS_ERROR_FAILURE, __func__);
RefPtr<WaitingRequests> waitingRequests(entry.GetData());
if (waitingRequests) {
ResumeWaitingRequests(waitingRequests, false);
}
}

Expand Down
28 changes: 20 additions & 8 deletions js/loader/ModuleLoaderBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -124,9 +124,9 @@ class ScriptLoaderInterface : public nsISupports {
* module map.
*
* The module map is made up of two parts. A module that has been requested but
* has not yet loaded is represented by a promise in the mFetchingModules map. A
* module which has been loaded is represented by a ModuleScript in the
* mFetchedModules map.
* has not finished fetching is represented by an entry in the mFetchingModules
* map. A module which has been fetched and compiled is represented by a
* ModuleScript in the mFetchedModules map.
*
* Module loading typically works as follows:
*
Expand Down Expand Up @@ -163,13 +163,23 @@ class ScriptLoaderInterface : public nsISupports {
* 10. The client calls EvaluateModule() to execute the top-level module.
*/
class ModuleLoaderBase : public nsISupports {
private:
using GenericNonExclusivePromise = mozilla::GenericNonExclusivePromise;
using GenericPromise = mozilla::GenericPromise;

/*
* The set of requests that are waiting for an ongoing fetch to complete.
*/
class WaitingRequests final : public nsISupports {
virtual ~WaitingRequests() = default;

public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_CLASS(WaitingRequests)

nsTArray<RefPtr<ModuleLoadRequest>> mWaiting;
};

// Module map
nsRefPtrHashtable<nsURIHashKey, GenericNonExclusivePromise::Private>
mFetchingModules;
nsRefPtrHashtable<nsURIHashKey, WaitingRequests> mFetchingModules;
nsRefPtrHashtable<nsURIHashKey, ModuleScript> mFetchedModules;

// List of dynamic imports that are currently being loaded.
Expand Down Expand Up @@ -360,7 +370,7 @@ class ModuleLoaderBase : public nsISupports {

bool ModuleMapContainsURL(nsIURI* aURL) const;
bool IsModuleFetching(nsIURI* aURL) const;
RefPtr<GenericNonExclusivePromise> WaitForModuleFetch(nsIURI* aURL);
void WaitForModuleFetch(ModuleLoadRequest* aRequest);
void SetModuleFetchStarted(ModuleLoadRequest* aRequest);

ModuleScript* GetFetchedModule(nsIURI* aURL) const;
Expand All @@ -373,6 +383,8 @@ class ModuleLoaderBase : public nsISupports {

void SetModuleFetchFinishedAndResumeWaitingRequests(
ModuleLoadRequest* aRequest, nsresult aResult);
void ResumeWaitingRequests(WaitingRequests* aWaitingRequests, bool aSuccess);
void ResumeWaitingRequest(ModuleLoadRequest* aRequest, bool aSuccess);

void StartFetchingModuleDependencies(ModuleLoadRequest* aRequest);

Expand Down

0 comments on commit baca1b8

Please sign in to comment.