Skip to content

Commit 0c1e878

Browse files
committedApr 14, 2021
deps: backport v8 f19142e6
[top-level-await] Implement the new post-order requirement for async subgraphs Refs: v8/v8@f19142e PR-URL: #37864 Backport-PR-URL: #37973 Reviewed-By: Michaël Zasso <targos@protonmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
1 parent dd5da30 commit 0c1e878

18 files changed

+337
-88
lines changed
 

‎common.gypi

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636

3737
# Reset this number to 0 on major V8 upgrades.
3838
# Increment by one for each non-official patch applied to deps/v8.
39-
'v8_embedder_string': '-node.28',
39+
'v8_embedder_string': '-node.29',
4040

4141
##### V8 defaults for Node.js #####
4242

‎deps/v8/src/common/globals.h

+3
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,9 @@ constexpr int kUC16Size = sizeof(uc16); // NOLINT
334334
// 128 bit SIMD value size.
335335
constexpr int kSimd128Size = 16;
336336

337+
// Maximum ordinal used for tracking asynchronous module evaluation order.
338+
constexpr unsigned kMaxModuleAsyncEvaluatingOrdinal = (1 << 30) - 1;
339+
337340
// FUNCTION_ADDR(f) gets the address of a C function f.
338341
#define FUNCTION_ADDR(f) (reinterpret_cast<v8::internal::Address>(f))
339342

‎deps/v8/src/diagnostics/objects-debug.cc

+2-1
Original file line numberDiff line numberDiff line change
@@ -1351,7 +1351,8 @@ void SourceTextModule::SourceTextModuleVerify(Isolate* isolate) {
13511351
(status() == kPreInstantiating && code().IsSharedFunctionInfo()) ||
13521352
(status() == kUninstantiated && code().IsSharedFunctionInfo()));
13531353
CHECK(top_level_capability().IsUndefined() && !AsyncParentModuleCount() &&
1354-
!pending_async_dependencies() && !async_evaluating());
1354+
!pending_async_dependencies());
1355+
CHECK(!IsAsyncEvaluating());
13551356
}
13561357

13571358
CHECK_EQ(requested_modules().length(), info().module_requests().length());

‎deps/v8/src/diagnostics/objects-printer.cc

+1
Original file line numberDiff line numberDiff line change
@@ -1622,6 +1622,7 @@ void SourceTextModule::SourceTextModulePrint(std::ostream& os) { // NOLINT
16221622
os << "\n - script: " << Brief(script());
16231623
os << "\n - import_meta: " << Brief(import_meta());
16241624
os << "\n - cycle_root: " << Brief(cycle_root());
1625+
os << "\n - async_evaluating_ordinal: " << async_evaluating_ordinal();
16251626
os << "\n";
16261627
}
16271628

‎deps/v8/src/execution/isolate-inl.h

+31
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "src/objects/property-cell.h"
1313
#include "src/objects/regexp-match-info.h"
1414
#include "src/objects/shared-function-info.h"
15+
#include "src/objects/source-text-module.h"
1516

1617
namespace v8 {
1718
namespace internal {
@@ -117,6 +118,36 @@ Isolate::ExceptionScope::~ExceptionScope() {
117118
isolate_->set_pending_exception(*pending_exception_);
118119
}
119120

121+
void Isolate::DidFinishModuleAsyncEvaluation(unsigned ordinal) {
122+
// To address overflow, the ordinal is reset when the async module with the
123+
// largest vended ordinal finishes evaluating. Modules are evaluated in
124+
// ascending order of their async_evaluating_ordinal.
125+
//
126+
// While the specification imposes a global total ordering, the intention is
127+
// that for each async module, all its parents are totally ordered by when
128+
// they first had their [[AsyncEvaluating]] bit set.
129+
//
130+
// The module with largest vended ordinal finishes evaluating implies that the
131+
// async dependency as well as all other modules in that module's graph
132+
// depending on async dependencies are finished evaluating.
133+
//
134+
// If the async dependency participates in other module graphs (e.g. via
135+
// dynamic import, or other <script type=module> tags), those module graphs
136+
// must have been evaluated either before or after the async dependency is
137+
// settled, as the concrete Evaluate() method on cyclic module records is
138+
// neither reentrant nor performs microtask checkpoints during its
139+
// evaluation. If before, then all modules that depend on the async
140+
// dependencies were given an ordinal that ensure they are relatively ordered,
141+
// before the global ordinal was reset. If after, then the async evaluating
142+
// ordering does not apply, as the dependency is no longer asynchronous.
143+
//
144+
// https://tc39.es/ecma262/#sec-moduleevaluation
145+
if (ordinal + 1 == next_module_async_evaluating_ordinal_) {
146+
next_module_async_evaluating_ordinal_ =
147+
SourceTextModule::kFirstAsyncEvaluatingOrdinal;
148+
}
149+
}
150+
120151
#define NATIVE_CONTEXT_FIELD_ACCESSOR(index, type, name) \
121152
Handle<type> Isolate::name() { \
122153
return Handle<type>(raw_native_context().name(), this); \

‎deps/v8/src/execution/isolate.cc

+3
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
#include "src/objects/prototype.h"
6767
#include "src/objects/slots.h"
6868
#include "src/objects/smi.h"
69+
#include "src/objects/source-text-module.h"
6970
#include "src/objects/stack-frame-info-inl.h"
7071
#include "src/objects/visitors.h"
7172
#include "src/profiler/heap-profiler.h"
@@ -2792,6 +2793,8 @@ Isolate::Isolate(std::unique_ptr<i::IsolateAllocator> isolate_allocator)
27922793
#if V8_SFI_HAS_UNIQUE_ID
27932794
next_unique_sfi_id_(0),
27942795
#endif
2796+
next_module_async_evaluating_ordinal_(
2797+
SourceTextModule::kFirstAsyncEvaluatingOrdinal),
27952798
cancelable_task_manager_(new CancelableTaskManager()) {
27962799
TRACE_ISOLATE(constructor);
27972800
CheckIsolateLayout();

‎deps/v8/src/execution/isolate.h

+18
Original file line numberDiff line numberDiff line change
@@ -1264,6 +1264,22 @@ class V8_EXPORT_PRIVATE Isolate final : private HiddenFactory {
12641264
return id;
12651265
}
12661266

1267+
// https://github.com/tc39/proposal-top-level-await/pull/159
1268+
// TODO(syg): Update to actual spec link once merged.
1269+
//
1270+
// According to the spec, modules that depend on async modules (i.e. modules
1271+
// with top-level await) must be evaluated in order in which their
1272+
// [[AsyncEvaluating]] flags were set to true. V8 tracks this global total
1273+
// order with next_module_async_evaluating_ordinal_. Each module that sets its
1274+
// [[AsyncEvaluating]] to true grabs the next ordinal.
1275+
unsigned NextModuleAsyncEvaluatingOrdinal() {
1276+
unsigned ordinal = next_module_async_evaluating_ordinal_++;
1277+
CHECK_LT(ordinal, kMaxModuleAsyncEvaluatingOrdinal);
1278+
return ordinal;
1279+
}
1280+
1281+
inline void DidFinishModuleAsyncEvaluation(unsigned ordinal);
1282+
12671283
void AddNearHeapLimitCallback(v8::NearHeapLimitCallback, void* data);
12681284
void RemoveNearHeapLimitCallback(v8::NearHeapLimitCallback callback,
12691285
size_t heap_limit);
@@ -1788,6 +1804,8 @@ class V8_EXPORT_PRIVATE Isolate final : private HiddenFactory {
17881804
std::atomic<int> next_unique_sfi_id_;
17891805
#endif
17901806

1807+
unsigned next_module_async_evaluating_ordinal_;
1808+
17911809
// Vector of callbacks before a Call starts execution.
17921810
std::vector<BeforeCallEnteredCallback> before_call_entered_callbacks_;
17931811

‎deps/v8/src/heap/factory.cc

+1-1
Original file line numberDiff line numberDiff line change
@@ -2485,7 +2485,7 @@ Handle<SourceTextModule> Factory::NewSourceTextModule(
24852485
module->set_top_level_capability(roots.undefined_value());
24862486
module->set_flags(0);
24872487
module->set_async(IsAsyncModule(code->kind()));
2488-
module->set_async_evaluating(false);
2488+
module->set_async_evaluating_ordinal(SourceTextModule::kNotAsyncEvaluated);
24892489
module->set_cycle_root(roots.the_hole_value());
24902490
module->set_async_parent_modules(*async_parent_modules);
24912491
module->set_pending_async_dependencies(0);

‎deps/v8/src/objects/module-inl.h

+6-2
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ SMI_ACCESSORS(Module, status, kStatusOffset)
3737
SMI_ACCESSORS(Module, hash, kHashOffset)
3838

3939
BOOL_ACCESSORS(SourceTextModule, flags, async, AsyncBit::kShift)
40-
BOOL_ACCESSORS(SourceTextModule, flags, async_evaluating,
41-
AsyncEvaluatingBit::kShift)
40+
BIT_FIELD_ACCESSORS(SourceTextModule, flags, async_evaluating_ordinal,
41+
SourceTextModule::AsyncEvaluatingOrdinalBits)
4242
ACCESSORS(SourceTextModule, async_parent_modules, ArrayList,
4343
kAsyncParentModulesOffset)
4444
ACCESSORS(SourceTextModule, top_level_capability, HeapObject,
@@ -141,6 +141,10 @@ int SourceTextModule::AsyncParentModuleCount() {
141141
return async_parent_modules().Length();
142142
}
143143

144+
bool SourceTextModule::IsAsyncEvaluating() const {
145+
return async_evaluating_ordinal() >= kFirstAsyncEvaluatingOrdinal;
146+
}
147+
144148
bool SourceTextModule::HasPendingAsyncDependencies() {
145149
DCHECK_GE(pending_async_dependencies(), 0);
146150
return pending_async_dependencies() > 0;

‎deps/v8/src/objects/source-text-module.cc

+166-77
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,15 @@ class Module::ResolveSet
7676
Zone* zone_;
7777
};
7878

79+
struct SourceTextModule::AsyncEvaluatingOrdinalCompare {
80+
bool operator()(Handle<SourceTextModule> lhs,
81+
Handle<SourceTextModule> rhs) const {
82+
DCHECK(lhs->IsAsyncEvaluating());
83+
DCHECK(rhs->IsAsyncEvaluating());
84+
return lhs->async_evaluating_ordinal() < rhs->async_evaluating_ordinal();
85+
}
86+
};
87+
7988
SharedFunctionInfo SourceTextModule::GetSharedFunctionInfo() const {
8089
DisallowHeapAllocation no_alloc;
8190
switch (status()) {
@@ -580,6 +589,58 @@ void SourceTextModule::FetchStarExports(Isolate* isolate,
580589
module->set_exports(*exports);
581590
}
582591

592+
void SourceTextModule::GatherAsyncParentCompletions(
593+
Isolate* isolate, Zone* zone, Handle<SourceTextModule> start,
594+
AsyncParentCompletionSet* exec_list) {
595+
// The spec algorithm is recursive. It is transformed to an equivalent
596+
// iterative one here.
597+
ZoneStack<Handle<SourceTextModule>> worklist(zone);
598+
worklist.push(start);
599+
600+
while (!worklist.empty()) {
601+
Handle<SourceTextModule> module = worklist.top();
602+
worklist.pop();
603+
604+
// 1. Assert: module.[[Status]] is evaluated.
605+
DCHECK_EQ(module->status(), kEvaluated);
606+
607+
// 2. For each Module m of module.[[AsyncParentModules]], do
608+
for (int i = module->AsyncParentModuleCount(); i-- > 0;) {
609+
Handle<SourceTextModule> m = module->GetAsyncParentModule(isolate, i);
610+
611+
// a. If execList does not contain m and
612+
// m.[[CycleRoot]].[[EvaluationError]] is empty, then
613+
if (exec_list->find(m) == exec_list->end() &&
614+
m->GetCycleRoot(isolate)->status() != kErrored) {
615+
// i. Assert: m.[[EvaluationError]] is empty.
616+
DCHECK_NE(m->status(), kErrored);
617+
618+
// ii. Assert: m.[[AsyncEvaluating]] is true.
619+
DCHECK(m->IsAsyncEvaluating());
620+
621+
// iii. Assert: m.[[PendingAsyncDependencies]] > 0.
622+
DCHECK(m->HasPendingAsyncDependencies());
623+
624+
// iv. Set m.[[PendingAsyncDependencies]] to
625+
// m.[[PendingAsyncDependencies]] - 1.
626+
m->DecrementPendingAsyncDependencies();
627+
628+
// v. If m.[[PendingAsyncDependencies]] is equal to 0, then
629+
if (!m->HasPendingAsyncDependencies()) {
630+
// 1. Append m to execList.
631+
exec_list->insert(m);
632+
633+
// 2. If m.[[Async]] is false,
634+
// perform ! GatherAsyncParentCompletions(m, execList).
635+
if (!m->async()) worklist.push(m);
636+
}
637+
}
638+
}
639+
}
640+
641+
// 3. Return undefined.
642+
}
643+
583644
Handle<JSModuleNamespace> SourceTextModule::GetModuleNamespace(
584645
Isolate* isolate, Handle<SourceTextModule> module, int module_request) {
585646
Handle<Module> requested_module(
@@ -663,7 +724,7 @@ MaybeHandle<Object> SourceTextModule::EvaluateMaybeAsync(
663724
CHECK_EQ(module->status(), kEvaluated);
664725

665726
// b. If module.[[AsyncEvaluating]] is false, then
666-
if (!module->async_evaluating()) {
727+
if (!module->IsAsyncEvaluating()) {
667728
// i. Perform ! Call(capability.[[Resolve]], undefined,
668729
// «undefined»).
669730
JSPromise::Resolve(capability, isolate->factory()->undefined_value())
@@ -716,81 +777,97 @@ MaybeHandle<Object> SourceTextModule::Evaluate(
716777

717778
void SourceTextModule::AsyncModuleExecutionFulfilled(
718779
Isolate* isolate, Handle<SourceTextModule> module) {
719-
// 1. Assert: module.[[Status]] is "evaluated".
720-
CHECK(module->status() == kEvaluated || module->status() == kErrored);
780+
// 1. Assert: module.[[AsyncEvaluating]] is true.
781+
DCHECK(module->IsAsyncEvaluating());
721782

722-
// 2. If module.[[AsyncEvaluating]] is false,
723-
if (!module->async_evaluating()) {
724-
// a. Assert: module.[[EvaluationError]] is not undefined.
725-
CHECK_EQ(module->status(), kErrored);
726-
727-
// b. Return undefined.
728-
return;
729-
}
730-
731-
// 3. Assert: module.[[EvaluationError]] is undefined.
783+
// 2. Assert: module.[[EvaluationError]] is undefined.
732784
CHECK_EQ(module->status(), kEvaluated);
733785

734-
// 4. Set module.[[AsyncEvaluating]] to false.
735-
module->set_async_evaluating(false);
786+
// 3. Set module.[[AsyncEvaluating]] to false.
787+
isolate->DidFinishModuleAsyncEvaluation(module->async_evaluating_ordinal());
788+
module->set_async_evaluating_ordinal(kAsyncEvaluateDidFinish);
736789

737-
// 5. For each Module m of module.[[AsyncParentModules]], do
738-
for (int i = 0; i < module->AsyncParentModuleCount(); i++) {
739-
Handle<SourceTextModule> m = module->GetAsyncParentModule(isolate, i);
790+
// 4. If module.[[TopLevelCapability]] is not empty, then
791+
if (!module->top_level_capability().IsUndefined(isolate)) {
792+
// a. Assert: module.[[CycleRoot]] is equal to module.
793+
DCHECK_EQ(*module->GetCycleRoot(isolate), *module);
740794

741-
// a. Decrement m.[[PendingAsyncDependencies]] by 1.
742-
m->DecrementPendingAsyncDependencies();
795+
// i. Perform ! Call(module.[[TopLevelCapability]].[[Resolve]], undefined,
796+
// «undefined»).
797+
Handle<JSPromise> capability(
798+
JSPromise::cast(module->top_level_capability()), isolate);
799+
JSPromise::Resolve(capability, isolate->factory()->undefined_value())
800+
.ToHandleChecked();
801+
}
743802

744-
// b. If m.[[PendingAsyncDependencies]] is 0 and m.[[EvaluationError]] is
745-
// undefined, then
746-
if (!m->HasPendingAsyncDependencies() && m->status() == kEvaluated) {
747-
// i. Assert: m.[[AsyncEvaluating]] is true.
748-
DCHECK(m->async_evaluating());
803+
// 5. Let execList be a new empty List.
804+
Zone zone(isolate->allocator(), ZONE_NAME);
805+
AsyncParentCompletionSet exec_list(&zone);
749806

750-
// ii. If m.[[CycleRoot]].[[EvaluationError]] is not undefined,
751-
// return undefined.
752-
if (m->GetCycleRoot(isolate)->status() == kErrored) {
753-
return;
754-
}
807+
// 6. Perform ! GatherAsyncParentCompletions(module, execList).
808+
GatherAsyncParentCompletions(isolate, &zone, module, &exec_list);
809+
810+
// 7. Let sortedExecList be a List of elements that are the elements of
811+
// execList, in the order in which they had their [[AsyncEvaluating]]
812+
// fields set to true in InnerModuleEvaluation.
813+
//
814+
// This step is implemented by AsyncParentCompletionSet, which is a set
815+
// ordered on async_evaluating_ordinal.
755816

756-
// iii. If m.[[Async]] is true, then
757-
if (m->async()) {
758-
// 1. Perform ! ExecuteAsyncModule(m).
759-
ExecuteAsyncModule(isolate, m);
817+
// 8. Assert: All elements of sortedExecList have their [[AsyncEvaluating]]
818+
// field set to true, [[PendingAsyncDependencies]] field set to 0 and
819+
// [[EvaluationError]] field set to undefined.
820+
#ifdef DEBUG
821+
for (Handle<SourceTextModule> m : exec_list) {
822+
DCHECK(m->IsAsyncEvaluating());
823+
DCHECK(!m->HasPendingAsyncDependencies());
824+
DCHECK_NE(m->status(), kErrored);
825+
}
826+
#endif
827+
828+
// 9. For each Module m of sortedExecList, do
829+
for (Handle<SourceTextModule> m : exec_list) {
830+
// i. If m.[[AsyncEvaluating]] is false, then
831+
if (!m->IsAsyncEvaluating()) {
832+
// a. Assert: m.[[EvaluatingError]] is not empty.
833+
DCHECK_EQ(m->status(), kErrored);
834+
} else if (m->async()) {
835+
// ii. Otherwise, if m.[[Async]] is *true*, then
836+
// a. Perform ! ExecuteAsyncModule(m).
837+
ExecuteAsyncModule(isolate, m);
838+
} else {
839+
// iii. Otherwise,
840+
// a. Let _result_ be m.ExecuteModule().
841+
Handle<Object> unused_result;
842+
// b. If _result_ is an abrupt completion,
843+
if (!ExecuteModule(isolate, m).ToHandle(&unused_result)) {
844+
// 1. Perform ! AsyncModuleExecutionRejected(m, result.[[Value]]).
845+
Handle<Object> exception(isolate->pending_exception(), isolate);
846+
isolate->clear_pending_exception();
847+
AsyncModuleExecutionRejected(isolate, m, exception);
760848
} else {
761-
// iv. Otherwise,
762-
// 1. Let result be m.ExecuteModule().
763-
// 2. If result is a normal completion,
764-
Handle<Object> unused_result;
765-
if (ExecuteModule(isolate, m).ToHandle(&unused_result)) {
766-
// a. Perform ! AsyncModuleExecutionFulfilled(m).
767-
AsyncModuleExecutionFulfilled(isolate, m);
768-
} else {
769-
// 3. Otherwise,
770-
// a. Perform ! AsyncModuleExecutionRejected(m,
771-
// result.[[Value]]).
772-
Handle<Object> exception(isolate->pending_exception(), isolate);
773-
isolate->clear_pending_exception();
774-
AsyncModuleExecutionRejected(isolate, m, exception);
849+
// c. Otherwise,
850+
// 1. Set m.[[AsyncEvaluating]] to false.
851+
isolate->DidFinishModuleAsyncEvaluation(m->async_evaluating_ordinal());
852+
m->set_async_evaluating_ordinal(kAsyncEvaluateDidFinish);
853+
854+
// 2. If m.[[TopLevelCapability]] is not empty, then
855+
if (!m->top_level_capability().IsUndefined(isolate)) {
856+
// i. Assert: m.[[CycleRoot]] is equal to m.
857+
DCHECK_EQ(*m->GetCycleRoot(isolate), *m);
858+
859+
// ii. Perform ! Call(m.[[TopLevelCapability]].[[Resolve]],
860+
// undefined, «undefined»).
861+
Handle<JSPromise> capability(
862+
JSPromise::cast(m->top_level_capability()), isolate);
863+
JSPromise::Resolve(capability, isolate->factory()->undefined_value())
864+
.ToHandleChecked();
775865
}
776866
}
777867
}
778868
}
779869

780-
// 6. If module.[[TopLevelCapability]] is not undefined, then
781-
if (!module->top_level_capability().IsUndefined(isolate)) {
782-
// a. Assert: module.[[DFSIndex]] is equal to module.[[DFSAncestorIndex]].
783-
DCHECK_EQ(module->dfs_index(), module->dfs_ancestor_index());
784-
785-
// b. Perform ! Call(module.[[TopLevelCapability]].[[Resolve]],
786-
// undefined, «undefined»).
787-
Handle<JSPromise> capability(
788-
JSPromise::cast(module->top_level_capability()), isolate);
789-
JSPromise::Resolve(capability, isolate->factory()->undefined_value())
790-
.ToHandleChecked();
791-
}
792-
793-
// 7. Return undefined.
870+
// 10. Return undefined.
794871
}
795872

796873
void SourceTextModule::AsyncModuleExecutionRejected(
@@ -802,7 +879,7 @@ void SourceTextModule::AsyncModuleExecutionRejected(
802879
CHECK(module->status() == kEvaluated || module->status() == kErrored);
803880

804881
// 2. If module.[[AsyncEvaluating]] is false,
805-
if (!module->async_evaluating()) {
882+
if (!module->IsAsyncEvaluating()) {
806883
// a. Assert: module.[[EvaluationError]] is not undefined.
807884
CHECK_EQ(module->status(), kErrored);
808885

@@ -814,7 +891,8 @@ void SourceTextModule::AsyncModuleExecutionRejected(
814891
module->RecordError(isolate, exception);
815892

816893
// 5. Set module.[[AsyncEvaluating]] to false.
817-
module->set_async_evaluating(false);
894+
isolate->DidFinishModuleAsyncEvaluation(module->async_evaluating_ordinal());
895+
module->set_async_evaluating_ordinal(kAsyncEvaluateDidFinish);
818896

819897
// 6. For each Module m of module.[[AsyncParentModules]], do
820898
for (int i = 0; i < module->AsyncParentModuleCount(); i++) {
@@ -833,8 +911,8 @@ void SourceTextModule::AsyncModuleExecutionRejected(
833911

834912
// 7. If module.[[TopLevelCapability]] is not undefined, then
835913
if (!module->top_level_capability().IsUndefined(isolate)) {
836-
// a. Assert: module.[[DFSIndex]] is equal to module.[[DFSAncestorIndex]].
837-
DCHECK(module->dfs_index() == module->dfs_ancestor_index());
914+
// a. Assert: module.[[CycleRoot]] is equal to module.
915+
DCHECK_EQ(*module->GetCycleRoot(isolate), *module);
838916

839917
// b. Perform ! Call(module.[[TopLevelCapability]].[[Reject]],
840918
// undefined, «error»).
@@ -855,7 +933,8 @@ void SourceTextModule::ExecuteAsyncModule(Isolate* isolate,
855933
DCHECK(module->async());
856934

857935
// 3. Set module.[[AsyncEvaluating]] to true.
858-
module->set_async_evaluating(true);
936+
module->set_async_evaluating_ordinal(
937+
isolate->NextModuleAsyncEvaluatingOrdinal());
859938

860939
// 4. Let capability be ! NewPromiseCapability(%Promise%).
861940
Handle<JSPromise> capability = isolate->factory()->NewJSPromise();
@@ -1057,7 +1136,7 @@ MaybeHandle<Object> SourceTextModule::InnerModuleEvaluation(
10571136
}
10581137
}
10591138
// v. If requiredModule.[[AsyncEvaluating]] is true, then
1060-
if (required_module->async_evaluating()) {
1139+
if (required_module->IsAsyncEvaluating()) {
10611140
// 1. Set module.[[PendingAsyncDependencies]] to
10621141
// module.[[PendingAsyncDependencies]] + 1.
10631142
module->IncrementPendingAsyncDependencies();
@@ -1079,16 +1158,26 @@ MaybeHandle<Object> SourceTextModule::InnerModuleEvaluation(
10791158
// synchronous modules, but return undefined for AsyncModules.
10801159
Handle<Object> result = isolate->factory()->undefined_value();
10811160

1082-
// 14. If module.[[PendingAsyncDependencies]] is > 0, set
1083-
// module.[[AsyncEvaluating]] to true.
1084-
if (module->HasPendingAsyncDependencies()) {
1085-
module->set_async_evaluating(true);
1086-
} else if (module->async()) {
1087-
// 15. Otherwise, if module.[[Async]] is true,
1088-
// perform ! ExecuteAsyncModule(module).
1089-
SourceTextModule::ExecuteAsyncModule(isolate, module);
1161+
// 14. If module.[[PendingAsyncDependencies]] > 0 or module.[[Async]] is
1162+
// true, then
1163+
if (module->HasPendingAsyncDependencies() || module->async()) {
1164+
// a. Assert: module.[[AsyncEvaluating]] is false and was never previously
1165+
// set to true.
1166+
DCHECK_EQ(module->async_evaluating_ordinal(), kNotAsyncEvaluated);
1167+
1168+
// b. Set module.[[AsyncEvaluating]] to true.
1169+
// NOTE: The order in which modules transition to async evaluating is
1170+
// significant.
1171+
module->set_async_evaluating_ordinal(
1172+
isolate->NextModuleAsyncEvaluatingOrdinal());
1173+
1174+
// c. If module.[[PendingAsyncDependencies]] is 0,
1175+
// perform ! ExecuteAsyncModule(_module_).
1176+
if (!module->HasPendingAsyncDependencies()) {
1177+
SourceTextModule::ExecuteAsyncModule(isolate, module);
1178+
}
10901179
} else {
1091-
// 16. Otherwise, perform ? module.ExecuteModule().
1180+
// 15. Otherwise, perform ? module.ExecuteModule().
10921181
ASSIGN_RETURN_ON_EXCEPTION(isolate, result, ExecuteModule(isolate, module),
10931182
Object);
10941183
}

‎deps/v8/src/objects/source-text-module.h

+31-5
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
#include "src/objects/module.h"
99
#include "src/objects/promise.h"
10+
#include "src/zone/zone-containers.h"
1011
#include "torque-generated/bit-fields-tq.h"
1112

1213
// Has to be the last include (doesn't have include guards):
@@ -69,10 +70,16 @@ class SourceTextModule
6970
SubclassBodyDescriptor<Module::BodyDescriptor,
7071
FixedBodyDescriptor<kCodeOffset, kSize, kSize>>;
7172

73+
static constexpr unsigned kFirstAsyncEvaluatingOrdinal = 2;
74+
7275
private:
7376
friend class Factory;
7477
friend class Module;
7578

79+
struct AsyncEvaluatingOrdinalCompare;
80+
using AsyncParentCompletionSet =
81+
ZoneSet<Handle<SourceTextModule>, AsyncEvaluatingOrdinalCompare>;
82+
7683
// Appends a tuple of module and generator to the async parent modules
7784
// ArrayList.
7885
inline static void AddAsyncParentModule(Isolate* isolate,
@@ -90,20 +97,35 @@ class SourceTextModule
9097
// Returns the number of async parent modules for a given async child.
9198
inline int AsyncParentModuleCount();
9299

100+
inline bool IsAsyncEvaluating() const;
101+
93102
inline bool HasPendingAsyncDependencies();
94103
inline void IncrementPendingAsyncDependencies();
95104
inline void DecrementPendingAsyncDependencies();
96105

97106
// Bits for flags.
98107
DEFINE_TORQUE_GENERATED_SOURCE_TEXT_MODULE_FLAGS()
99108

100-
// async_evaluating, top_level_capability, pending_async_dependencies, and
101-
// async_parent_modules are used exclusively during evaluation of async
109+
// async_evaluating_ordinal, top_level_capability, pending_async_dependencies,
110+
// and async_parent_modules are used exclusively during evaluation of async
102111
// modules and the modules which depend on them.
103112
//
104-
// Whether or not this module is async and evaluating or currently evaluating
105-
// an async child.
106-
DECL_BOOLEAN_ACCESSORS(async_evaluating)
113+
// If >1, this module is async and evaluating or currently evaluating an async
114+
// child. The integer is an ordinal for when this module first started async
115+
// evaluation and is used for sorting async parent modules when determining
116+
// which parent module can start executing after an async evaluation
117+
// completes.
118+
//
119+
// If 1, this module has finished async evaluating.
120+
//
121+
// If 0, this module is not async or has not been async evaluated.
122+
static constexpr unsigned kNotAsyncEvaluated = 0;
123+
static constexpr unsigned kAsyncEvaluateDidFinish = 1;
124+
STATIC_ASSERT(kNotAsyncEvaluated < kAsyncEvaluateDidFinish);
125+
STATIC_ASSERT(kAsyncEvaluateDidFinish < kFirstAsyncEvaluatingOrdinal);
126+
STATIC_ASSERT(kMaxModuleAsyncEvaluatingOrdinal ==
127+
AsyncEvaluatingOrdinalBits::kMax);
128+
DECL_PRIMITIVE_ACCESSORS(async_evaluating_ordinal, unsigned)
107129

108130
// The top level promise capability of this module. Will only be defined
109131
// for cycle roots.
@@ -149,6 +171,10 @@ class SourceTextModule
149171
Handle<SourceTextModule> module, Zone* zone,
150172
UnorderedModuleSet* visited);
151173

174+
static void GatherAsyncParentCompletions(Isolate* isolate, Zone* zone,
175+
Handle<SourceTextModule> start,
176+
AsyncParentCompletionSet* exec_list);
177+
152178
// Implementation of spec concrete method Evaluate.
153179
static V8_WARN_UNUSED_RESULT MaybeHandle<Object> EvaluateMaybeAsync(
154180
Isolate* isolate, Handle<SourceTextModule> module);

‎deps/v8/src/objects/source-text-module.tq

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ type SourceTextModuleInfo extends FixedArray;
66

77
bitfield struct SourceTextModuleFlags extends uint31 {
88
async: bool: 1 bit;
9-
async_evaluating: bool: 1 bit;
9+
async_evaluating_ordinal: uint32: 30 bit;
1010
}
1111

1212
@generateCppClass
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Copyright 2021 the V8 project authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
// Flags: --harmony-top-level-await
6+
7+
import "modules-skip-async-subgraph-start.mjs"
8+
9+
assertEquals(globalThis.test_order, [
10+
'async before', 'async after', '1', '2', 'x', 'start'
11+
]);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Copyright 2021 the V8 project authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
// Flags: --harmony-top-level-await
6+
7+
import "modules-skip-async-subgraph-async.mjs"
8+
9+
if (globalThis.test_order === undefined) {
10+
globalThis.test_order = [];
11+
}
12+
globalThis.test_order.push('1');
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Copyright 2021 the V8 project authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
// Flags: --harmony-top-level-await
6+
7+
import "modules-skip-async-subgraph-async.mjs"
8+
9+
if (globalThis.test_order === undefined) {
10+
globalThis.test_order = [];
11+
}
12+
globalThis.test_order.push('2');
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Copyright 2021 the V8 project authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
// Flags: --harmony-top-level-await
6+
7+
if (globalThis.test_order === undefined) {
8+
globalThis.test_order = [];
9+
}
10+
globalThis.test_order.push('async before');
11+
await 0;
12+
globalThis.test_order.push('async after');
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Copyright 2021 the V8 project authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
// Flags: --harmony-top-level-await
6+
7+
import "modules-skip-async-subgraph-1.mjs"
8+
import "modules-skip-async-subgraph-2.mjs"
9+
import "modules-skip-async-subgraph-x.mjs"
10+
11+
if (globalThis.test_order === undefined) {
12+
globalThis.test_order = [];
13+
}
14+
globalThis.test_order.push('start');
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Copyright 2021 the V8 project authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
// Flags: --harmony-top-level-await
6+
7+
import "modules-skip-async-subgraph-1.mjs"
8+
9+
if (globalThis.test_order === undefined) {
10+
globalThis.test_order = [];
11+
}
12+
globalThis.test_order.push('x');

0 commit comments

Comments
 (0)
Please sign in to comment.