Bug 1842798 - Part 3: Complete dynamic imports asynchronously with a microtask r=smaug

According to the spec this should happen as the result of resolving a promise
(see ContinueDynamicImport). If this happens synchronously it's possible for
the importing module to still be in the evaluating state when trying to
instantiate and evaluate the dynamically imported module which breaks the
module loader invariants.

Differential Revision: https://phabricator.services.mozilla.com/D183876
This commit is contained in:
Jon Coppeard
2023-08-03 08:15:29 +00:00
parent 1e096c450d
commit 5be6a6eed0
2 changed files with 45 additions and 4 deletions

View File

@@ -30,6 +30,7 @@
#include "nsNetUtil.h" // NS_NewURI
#include "xpcpublic.h"
using mozilla::CycleCollectedJSContext;
using mozilla::Err;
using mozilla::Preferences;
using mozilla::UniquePtr;
@@ -1195,12 +1196,50 @@ nsresult ModuleLoaderBase::InitDebuggerDataForModuleGraph(
}
void ModuleLoaderBase::ProcessDynamicImport(ModuleLoadRequest* aRequest) {
// Instantiate and evaluate the imported module.
// See: https://tc39.es/ecma262/#sec-ContinueDynamicImport
//
// Since this is specced as happening on promise resolution (step 8) this must
// at least run as part of a microtask. We don't create the unobservable
// promise.
class DynamicImportMicroTask : public mozilla::MicroTaskRunnable {
public:
explicit DynamicImportMicroTask(ModuleLoadRequest* aRequest)
: MicroTaskRunnable(), mRequest(aRequest) {}
virtual void Run(mozilla::AutoSlowOperation& aAso) override {
mRequest->mLoader->InstantiateAndEvaluateDynamicImport(mRequest);
mRequest = nullptr;
}
virtual bool Suppressed() override {
return mRequest->mLoader->mGlobalObject->IsInSyncOperation();
}
private:
RefPtr<ModuleLoadRequest> mRequest;
};
MOZ_ASSERT(aRequest->mLoader == this);
if (aRequest->mModuleScript) {
if (!InstantiateModuleGraph(aRequest)) {
aRequest->mModuleScript = nullptr;
}
if (!aRequest->mModuleScript) {
FinishDynamicImportAndReject(aRequest, NS_ERROR_FAILURE);
return;
}
CycleCollectedJSContext* context = CycleCollectedJSContext::Get();
RefPtr<DynamicImportMicroTask> runnable =
new DynamicImportMicroTask(aRequest);
context->DispatchToMicroTask(do_AddRef(runnable));
}
void ModuleLoaderBase::InstantiateAndEvaluateDynamicImport(
ModuleLoadRequest* aRequest) {
MOZ_ASSERT(aRequest->mModuleScript);
if (!InstantiateModuleGraph(aRequest)) {
aRequest->mModuleScript = nullptr;
}
nsresult rv = NS_ERROR_FAILURE;