Commit 7698e9be authored by Camillo Bruni's avatar Camillo Bruni Committed by V8 LUCI CQ

[modules] Fix AsyncModuleExecutionFulfilled with pending error

This is a partial fix to mitigate immediate issues. The code needs some
overhaul to match the recent spec changes.

Drive-by-fix: Partially update comments to match spec

Bug: v8:11949
Change-Id: I6b03d38c758176e29e8951af21c43d030bbb684d
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3075360
Commit-Queue: Camillo Bruni <cbruni@chromium.org>
Reviewed-by: 's avatarShu-yu Guo <syg@chromium.org>
Cr-Commit-Position: refs/heads/master@{#76172}
parent 112e924d
...@@ -768,21 +768,25 @@ MaybeHandle<Object> SourceTextModule::Evaluate( ...@@ -768,21 +768,25 @@ MaybeHandle<Object> SourceTextModule::Evaluate(
void SourceTextModule::AsyncModuleExecutionFulfilled( void SourceTextModule::AsyncModuleExecutionFulfilled(
Isolate* isolate, Handle<SourceTextModule> module) { Isolate* isolate, Handle<SourceTextModule> module) {
// 1. Assert: module.[[AsyncEvaluating]] is true. // 1. If module.[[Status]] is evaluated, then
if (module->status() == kErrored) {
// a. Assert: module.[[EvaluationError]] is not empty.
DCHECK(!module->exception().IsTheHole(isolate));
// b. Return.
return;
}
// 3. Assert: module.[[AsyncEvaluating]] is true.
DCHECK(module->IsAsyncEvaluating()); DCHECK(module->IsAsyncEvaluating());
// 4. Assert: module.[[EvaluationError]] is empty.
// 2. Assert: module.[[EvaluationError]] is undefined.
CHECK_EQ(module->status(), kEvaluated); CHECK_EQ(module->status(), kEvaluated);
// 5. Set module.[[AsyncEvaluating]] to false.
// 3. Set module.[[AsyncEvaluating]] to false.
isolate->DidFinishModuleAsyncEvaluation(module->async_evaluating_ordinal()); isolate->DidFinishModuleAsyncEvaluation(module->async_evaluating_ordinal());
module->set_async_evaluating_ordinal(kAsyncEvaluateDidFinish); module->set_async_evaluating_ordinal(kAsyncEvaluateDidFinish);
// TODO(cbruni): update to match spec.
// 4. If module.[[TopLevelCapability]] is not empty, then // 7. If module.[[TopLevelCapability]] is not empty, then
if (!module->top_level_capability().IsUndefined(isolate)) { if (!module->top_level_capability().IsUndefined(isolate)) {
// a. Assert: module.[[CycleRoot]] is equal to module. // a. Assert: module.[[CycleRoot]] is equal to module.
DCHECK_EQ(*module->GetCycleRoot(isolate), *module); DCHECK_EQ(*module->GetCycleRoot(isolate), *module);
// i. Perform ! Call(module.[[TopLevelCapability]].[[Resolve]], undefined, // i. Perform ! Call(module.[[TopLevelCapability]].[[Resolve]], undefined,
// «undefined»). // «undefined»).
Handle<JSPromise> capability( Handle<JSPromise> capability(
...@@ -791,21 +795,21 @@ void SourceTextModule::AsyncModuleExecutionFulfilled( ...@@ -791,21 +795,21 @@ void SourceTextModule::AsyncModuleExecutionFulfilled(
.ToHandleChecked(); .ToHandleChecked();
} }
// 5. Let execList be a new empty List. // 8. Let execList be a new empty List.
Zone zone(isolate->allocator(), ZONE_NAME); Zone zone(isolate->allocator(), ZONE_NAME);
AsyncParentCompletionSet exec_list(&zone); AsyncParentCompletionSet exec_list(&zone);
// 6. Perform ! GatherAsyncParentCompletions(module, execList). // 9. Perform ! GatherAsyncParentCompletions(module, execList).
GatherAsyncParentCompletions(isolate, &zone, module, &exec_list); GatherAsyncParentCompletions(isolate, &zone, module, &exec_list);
// 7. Let sortedExecList be a List of elements that are the elements of // 10. Let sortedExecList be a List of elements that are the elements of
// execList, in the order in which they had their [[AsyncEvaluating]] // execList, in the order in which they had their [[AsyncEvaluating]]
// fields set to true in InnerModuleEvaluation. // fields set to true in InnerModuleEvaluation.
// //
// This step is implemented by AsyncParentCompletionSet, which is a set // This step is implemented by AsyncParentCompletionSet, which is a set
// ordered on async_evaluating_ordinal. // ordered on async_evaluating_ordinal.
// 8. Assert: All elements of sortedExecList have their [[AsyncEvaluating]] // 11. Assert: All elements of sortedExecList have their [[AsyncEvaluating]]
// field set to true, [[PendingAsyncDependencies]] field set to 0 and // field set to true, [[PendingAsyncDependencies]] field set to 0 and
// [[EvaluationError]] field set to undefined. // [[EvaluationError]] field set to undefined.
#ifdef DEBUG #ifdef DEBUG
...@@ -816,7 +820,7 @@ void SourceTextModule::AsyncModuleExecutionFulfilled( ...@@ -816,7 +820,7 @@ void SourceTextModule::AsyncModuleExecutionFulfilled(
} }
#endif #endif
// 9. For each Module m of sortedExecList, do // 12. For each Module m of sortedExecList, do
for (Handle<SourceTextModule> m : exec_list) { for (Handle<SourceTextModule> m : exec_list) {
// i. If m.[[AsyncEvaluating]] is false, then // i. If m.[[AsyncEvaluating]] is false, then
if (!m->IsAsyncEvaluating()) { if (!m->IsAsyncEvaluating()) {
...@@ -864,31 +868,37 @@ void SourceTextModule::AsyncModuleExecutionFulfilled( ...@@ -864,31 +868,37 @@ void SourceTextModule::AsyncModuleExecutionFulfilled(
void SourceTextModule::AsyncModuleExecutionRejected( void SourceTextModule::AsyncModuleExecutionRejected(
Isolate* isolate, Handle<SourceTextModule> module, Isolate* isolate, Handle<SourceTextModule> module,
Handle<Object> exception) { Handle<Object> exception) {
DCHECK(isolate->is_catchable_by_javascript(*exception)); // 1. If module.[[Status]] is evaluated, then
if (module->status() == kErrored) {
// a. Assert: module.[[EvaluationError]] is not empty.
DCHECK(!module->exception().IsTheHole(isolate));
// b. Return.
return;
}
// TODO(cbruni): update to match spec.
DCHECK(isolate->is_catchable_by_javascript(*exception));
// 1. Assert: module.[[Status]] is "evaluated". // 1. Assert: module.[[Status]] is "evaluated".
CHECK(module->status() == kEvaluated || module->status() == kErrored); CHECK(module->status() == kEvaluated || module->status() == kErrored);
// 2. If module.[[AsyncEvaluating]] is false, // 2. If module.[[AsyncEvaluating]] is false,
if (!module->IsAsyncEvaluating()) { if (!module->IsAsyncEvaluating()) {
// a. Assert: module.[[EvaluationError]] is not undefined. // a. Assert: module.[[EvaluationError]] is not empty.
CHECK_EQ(module->status(), kErrored); CHECK_EQ(module->status(), kErrored);
// b. Return undefined. // b. Return undefined.
return; return;
} }
// 4. Set module.[[EvaluationError]] to ThrowCompletion(error). // 5. Set module.[[EvaluationError]] to ThrowCompletion(error).
Module::RecordError(isolate, module, exception); Module::RecordError(isolate, module, exception);
// 5. Set module.[[AsyncEvaluating]] to false. // 6. Set module.[[AsyncEvaluating]] to false.
isolate->DidFinishModuleAsyncEvaluation(module->async_evaluating_ordinal()); isolate->DidFinishModuleAsyncEvaluation(module->async_evaluating_ordinal());
module->set_async_evaluating_ordinal(kAsyncEvaluateDidFinish); module->set_async_evaluating_ordinal(kAsyncEvaluateDidFinish);
// 6. For each Module m of module.[[AsyncParentModules]], do // 7. For each Module m of module.[[AsyncParentModules]], do
for (int i = 0; i < module->AsyncParentModuleCount(); i++) { for (int i = 0; i < module->AsyncParentModuleCount(); i++) {
Handle<SourceTextModule> m = module->GetAsyncParentModule(isolate, i); Handle<SourceTextModule> m = module->GetAsyncParentModule(isolate, i);
// TODO(cbruni): update to match spec.
// a. If module.[[DFSIndex]] is not equal to module.[[DFSAncestorIndex]], // a. If module.[[DFSIndex]] is not equal to module.[[DFSAncestorIndex]],
// then // then
if (module->dfs_index() != module->dfs_ancestor_index()) { if (module->dfs_index() != module->dfs_ancestor_index()) {
...@@ -900,19 +910,16 @@ void SourceTextModule::AsyncModuleExecutionRejected( ...@@ -900,19 +910,16 @@ void SourceTextModule::AsyncModuleExecutionRejected(
AsyncModuleExecutionRejected(isolate, m, exception); AsyncModuleExecutionRejected(isolate, m, exception);
} }
// 7. If module.[[TopLevelCapability]] is not undefined, then // 8. If module.[[TopLevelCapability]] is not empty, then
if (!module->top_level_capability().IsUndefined(isolate)) { if (!module->top_level_capability().IsUndefined(isolate)) {
// a. Assert: module.[[CycleRoot]] is equal to module. // a. Assert: module.[[CycleRoot]] is equal to module.
DCHECK_EQ(*module->GetCycleRoot(isolate), *module); DCHECK_EQ(*module->GetCycleRoot(isolate), *module);
// b. Perform ! Call(module.[[TopLevelCapability]].[[Reject]], // b. Perform ! Call(module.[[TopLevelCapability]].[[Reject]],
// undefined, «error»). // undefined, «error»).
Handle<JSPromise> capability( Handle<JSPromise> capability(
JSPromise::cast(module->top_level_capability()), isolate); JSPromise::cast(module->top_level_capability()), isolate);
JSPromise::Reject(capability, exception); JSPromise::Reject(capability, exception);
} }
// 8. Return undefined.
} }
void SourceTextModule::ExecuteAsyncModule(Isolate* isolate, void SourceTextModule::ExecuteAsyncModule(Isolate* isolate,
......
// Copyright 2021 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import "./modules-skip-top-level-await-cycle-error.mjs";
await Promise.resolve();
// Copyright 2021 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
throw new Error("Error in modules-skip-top-level-await-cycle-error-throwing.mjs");
// Copyright 2021 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import "./modules-skip-top-level-await-cycle-error-indirection.mjs";
import "./modules-skip-top-level-await-cycle-error-throwing.mjs";
export function error() {}
// Copyright 2021 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags:--harmony-top-level-await --ignore-unhandled-promises
try {
await import('./modules-skip-top-level-await-cycle-error.mjs');
assertUnreachable();
} catch(e) {
assertEquals(e.message, 'Error in modules-skip-top-level-await-cycle-error-throwing.mjs');
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment