Bug 1777972 - Part 2: Add evaluating-async module status r=yulia

This adds ModuleStatus::EvaluatingAsync, splitting it off from
ModuleStatus::Evaluated. This allows us to rewrite parts of the code to be
closer to the spec.

Depends on D151506

Differential Revision: https://phabricator.services.mozilla.com/D151507
This commit is contained in:
Jon Coppeard 2022-07-11 16:54:02 +00:00
Родитель 066629e396
Коммит 62b2edbd3b
4 изменённых файлов: 45 добавлений и 27 удалений

Просмотреть файл

@ -45,7 +45,9 @@ using mozilla::Some;
static_assert(ModuleStatus::Unlinked < ModuleStatus::Linking &&
ModuleStatus::Linking < ModuleStatus::Linked &&
ModuleStatus::Linked < ModuleStatus::Evaluated &&
ModuleStatus::Linked < ModuleStatus::Evaluating &&
ModuleStatus::Evaluating < ModuleStatus::EvaluatingAsync &&
ModuleStatus::EvaluatingAsync < ModuleStatus::Evaluated &&
ModuleStatus::Evaluated < ModuleStatus::Evaluated_Error,
"Module statuses are ordered incorrectly");
@ -1213,6 +1215,7 @@ bool ModuleObject::instantiateFunctionDeclarations(JSContext* cx,
bool ModuleObject::execute(JSContext* cx, Handle<ModuleObject*> self) {
#ifdef DEBUG
MOZ_ASSERT(self->status() == ModuleStatus::Evaluating ||
self->status() == ModuleStatus::EvaluatingAsync ||
self->status() == ModuleStatus::Evaluated);
MOZ_ASSERT(!self->hadEvaluationError());
if (!AssertFrozen(cx, self)) {
@ -2391,7 +2394,8 @@ static bool OnResolvedDynamicModule(JSContext* cx, unsigned argc, Value* vp) {
}
Rooted<ModuleObject*> module(cx, &result->as<ModuleObject>());
if (module->status() != ModuleStatus::Evaluated) {
if (module->status() != ModuleStatus::EvaluatingAsync &&
module->status() != ModuleStatus::Evaluated) {
JS_ReportErrorASCII(
cx, "Unevaluated or errored module returned by module resolve hook");
return RejectPromiseWithPendingError(cx, promise);

Просмотреть файл

@ -255,6 +255,7 @@ enum class ModuleStatus : int32_t {
Linking,
Linked,
Evaluating,
EvaluatingAsync,
Evaluated,
// Sub-state of Evaluated with error value set.

Просмотреть файл

@ -33,7 +33,7 @@ testGetter(a, "namespace");
// ==== status getter ====
const MODULE_STATUS_UNLINKED = 0;
const MODULE_STATUS_LINKED = 2;
const MODULE_STATUS_EVALUATED = 4;
const MODULE_STATUS_EVALUATED = 5;
const c = registerModule('c', parseModule(`
`));

Просмотреть файл

@ -1075,6 +1075,7 @@ bool js::ModuleLink(JSContext* cx, Handle<ModuleObject*> module) {
// Step 5. Assert: module.[[Status]] is linked, evaluating-async, or
// evaluated.
MOZ_ASSERT(module->status() == ModuleStatus::Linked ||
module->status() == ModuleStatus::EvaluatingAsync ||
module->status() == ModuleStatus::Evaluated);
// Step 6. Assert: stack is empty.
@ -1093,6 +1094,7 @@ static bool InnerModuleLinking(JSContext* cx, Handle<ModuleObject*> module,
// evaluated, then:
if (module->status() == ModuleStatus::Linking ||
module->status() == ModuleStatus::Linked ||
module->status() == ModuleStatus::EvaluatingAsync ||
module->status() == ModuleStatus::Evaluated) {
// Step 2.a. Return index.
*indexOut = index;
@ -1155,6 +1157,7 @@ static bool InnerModuleLinking(JSContext* cx, Handle<ModuleObject*> module,
// evaluating-async, or evaluated.
MOZ_ASSERT(requiredModule->status() == ModuleStatus::Linking ||
requiredModule->status() == ModuleStatus::Linked ||
requiredModule->status() == ModuleStatus::EvaluatingAsync ||
requiredModule->status() == ModuleStatus::Evaluated);
// Step 9.c.ii. Assert: requiredModule.[[Status]] is linking if and only if
@ -1217,6 +1220,7 @@ bool js::ModuleEvaluate(JSContext* cx, Handle<ModuleObject*> moduleArg,
// Step 2. Assert: module.[[Status]] is linked, evaluating-async, or
// evaluated.
if (module->status() != ModuleStatus::Linked &&
module->status() != ModuleStatus::EvaluatingAsync &&
module->status() != ModuleStatus::Evaluated) {
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
JSMSG_BAD_MODULE_STATUS);
@ -1228,7 +1232,8 @@ bool js::ModuleEvaluate(JSContext* cx, Handle<ModuleObject*> moduleArg,
//
// Note: we don't attempt to get the cycle root if there was an error during
// evaluation as it may not be set.
if (module->status() == ModuleStatus::Evaluated &&
if ((module->status() == ModuleStatus::EvaluatingAsync ||
module->status() == ModuleStatus::Evaluated) &&
!module->hadEvaluationError()) {
module = module->getCycleRoot();
}
@ -1297,10 +1302,12 @@ bool js::ModuleEvaluate(JSContext* cx, Handle<ModuleObject*> moduleArg,
} else {
// Step 10. Else:
// Step 10.a. Assert: module.[[Status]] is evaluating-async or evaluated.
// Step 10.b. Assert: module.[[EvaluationError]] is empty.
MOZ_ASSERT(module->status() == ModuleStatus::Evaluating ||
MOZ_ASSERT(module->status() == ModuleStatus::EvaluatingAsync ||
module->status() == ModuleStatus::Evaluated);
// Step 10.b. Assert: module.[[EvaluationError]] is empty.
MOZ_ASSERT(!module->hadEvaluationError());
// Step 10.c. If module.[[AsyncEvaluation]] is false, then:
if (!module->isAsyncEvaluating()) {
// Step 10.c.i. Assert: module.[[Status]] is evaluated.
@ -1328,19 +1335,22 @@ static bool InnerModuleEvaluation(JSContext* cx, Handle<ModuleObject*> module,
MutableHandle<ModuleVector> stack,
size_t index, size_t* indexOut) {
// Step 2. If module.[[Status]] is evaluating-async or evaluated, then:
// Step 2.a. If module.[[EvaluationError]] is empty, return index.
// Step 2.b. Otherwise, return ? module.[[EvaluationError]].
// Step 3. If module.[[Status]] is evaluating, return index.
if (module->status() == ModuleStatus::EvaluatingAsync ||
module->status() == ModuleStatus::Evaluated) {
// Step 2.a. If module.[[EvaluationError]] is empty, return index.
if (!module->hadEvaluationError()) {
*indexOut = index;
return true;
}
// This section is rearranged since we don't have an evaluating-async state
// but we do have an 'evaluation produced an error' state.
if (module->hadEvaluationError()) {
// Step 2.b. Otherwise, return ? module.[[EvaluationError]].
Rooted<Value> error(cx, module->evaluationError());
cx->setPendingException(error, ShouldCaptureStack::Maybe);
return false;
}
if (module->status() == ModuleStatus::Evaluating ||
module->status() == ModuleStatus::Evaluated) {
// Step 3. If module.[[Status]] is evaluating, return index.
if (module->status() == ModuleStatus::Evaluating) {
*indexOut = index;
return true;
}
@ -1401,6 +1411,7 @@ static bool InnerModuleEvaluation(JSContext* cx, Handle<ModuleObject*> module,
// Step 11.d.i. Assert: requiredModule.[[Status]] is either evaluating,
// evaluating-async, or evaluated.
MOZ_ASSERT(requiredModule->status() == ModuleStatus::Evaluating ||
requiredModule->status() == ModuleStatus::EvaluatingAsync ||
requiredModule->status() == ModuleStatus::Evaluated);
// Step 11.d.ii. Assert: requiredModule.[[Status]] is evaluating if and only
@ -1422,7 +1433,8 @@ static bool InnerModuleEvaluation(JSContext* cx, Handle<ModuleObject*> module,
// Step 11.d.iv.2. Assert: requiredModule.[[Status]] is evaluating-async
// or evaluated.
MOZ_ASSERT(requiredModule->status() == ModuleStatus::Evaluated);
MOZ_ASSERT(requiredModule->status() >= ModuleStatus::EvaluatingAsync ||
requiredModule->status() == ModuleStatus::Evaluated);
// Step 11.d.iv.3. If requiredModule.[[EvaluationError]] is not empty,
// return ? requiredModule.[[EvaluationError]].
@ -1493,11 +1505,13 @@ static bool InnerModuleEvaluation(JSContext* cx, Handle<ModuleObject*> module,
// Step 16.b.iv. If requiredModule.[[AsyncEvaluation]] is false, set
// requiredModule.[[Status]] to evaluated.
// Step 16.b.v. Otherwise, set requiredModule.[[Status]] to
// evaluating-async.
// Bug 1777972: We don't have a separate evaluating-async state.
requiredModule->setStatus(ModuleStatus::Evaluated);
if (!requiredModule->isAsyncEvaluating()) {
requiredModule->setStatus(ModuleStatus::Evaluated);
} else {
// Step 16.b.v. Otherwise, set requiredModule.[[Status]] to
// evaluating-async.
requiredModule->setStatus(ModuleStatus::EvaluatingAsync);
}
// Step 16.b.vi. If requiredModule and module are the same Module Record,
// set done to true.
@ -1518,7 +1532,7 @@ static bool InnerModuleEvaluation(JSContext* cx, Handle<ModuleObject*> module,
static bool ExecuteAsyncModule(JSContext* cx, Handle<ModuleObject*> module) {
// Step 1. Assert: module.[[Status]] is evaluating or evaluating-async.
MOZ_ASSERT(module->status() == ModuleStatus::Evaluating ||
module->status() == ModuleStatus::Evaluated);
module->status() == ModuleStatus::EvaluatingAsync);
// Step 2. Assert: module.[[HasTLA]] is true.
MOZ_ASSERT(module->hasTopLevelAwait());
@ -1539,10 +1553,11 @@ struct EvalOrderComparator {
}
};
// 16.2.1.5.2.3 GatherAvailableAncestors
bool js::GatherAvailableModuleAncestors(
JSContext* cx, Handle<ModuleObject*> module,
MutableHandle<ModuleVector> sortedList) {
MOZ_ASSERT(module->status() == ModuleStatus::Evaluated);
MOZ_ASSERT(module->status() == ModuleStatus::EvaluatingAsync);
MOZ_ASSERT(sortedList.empty());
if (!::GatherAvailableModuleAncestors(cx, module, sortedList)) {
@ -1583,9 +1598,7 @@ static bool GatherAvailableModuleAncestors(
if (!m->getCycleRoot()->hadEvaluationError() &&
!ContainsElement(execList, m)) {
// Step 1.a.i. Assert: m.[[Status]] is evaluating-async.
// Bug 1777972: We don't have a separate evaluating-async state.
MOZ_ASSERT(m->status() == ModuleStatus::Evaluated);
MOZ_ASSERT(m->status() == ModuleStatus::EvaluatingAsync);
// Step 1.a.ii. Assert: m.[[EvaluationError]] is empty.
MOZ_ASSERT(!m->hadEvaluationError());
@ -1625,7 +1638,7 @@ static bool GatherAvailableModuleAncestors(
void js::AsyncModuleExecutionFulfilled(JSContext* cx,
Handle<ModuleObject*> module) {
// Step 1.
MOZ_ASSERT(module->status() == ModuleStatus::Evaluated);
MOZ_ASSERT(module->status() == ModuleStatus::EvaluatingAsync);
// Step 2.
MOZ_ASSERT(module->isAsyncEvaluating());
@ -1704,7 +1717,7 @@ void js::AsyncModuleExecutionRejected(JSContext* cx,
Handle<ModuleObject*> module,
HandleValue error) {
// Step 1.
MOZ_ASSERT(module->status() == ModuleStatus::Evaluated);
MOZ_ASSERT(module->status() == ModuleStatus::EvaluatingAsync);
// Step 2.
if (!module->isAsyncEvaluating()) {