Skip to content

Commit f19142e

Browse files
sygCommit Bot
authored andcommitted
[top-level-await] Implement the new post-order requirement for async subgraphs
This CL implements tc39/proposal-top-level-await#159, which reached consensus at the March 2021 TC39. The high-level intent is for parent modules that depend on async modules to remember the DFS post-order such that when their async dependency finishes, they execute in that original post-order. This aligns the ordering between completely sync module graphs and async module graphs. Bug: v8:11557 Change-Id: I5bd8f38f040115c255ca1ce8253b9686fdb4af03 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2757901 Commit-Queue: Shu-yu Guo <syg@chromium.org> Reviewed-by: Camillo Bruni <cbruni@chromium.org> Reviewed-by: Adam Klein <adamk@chromium.org> Cr-Commit-Position: refs/heads/master@{#73551}
1 parent 341ab4d commit f19142e

17 files changed

Lines changed: 335 additions & 87 deletions

src/common/globals.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,9 @@ constexpr int kUC16Size = sizeof(uc16); // NOLINT
365365
// 128 bit SIMD value size.
366366
constexpr int kSimd128Size = 16;
367367

368+
// Maximum ordinal used for tracking asynchronous module evaluation order.
369+
constexpr unsigned kMaxModuleAsyncEvaluatingOrdinal = (1 << 30) - 1;
370+
368371
// FUNCTION_ADDR(f) gets the address of a C function f.
369372
#define FUNCTION_ADDR(f) (reinterpret_cast<v8::internal::Address>(f))
370373

src/diagnostics/objects-debug.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1519,7 +1519,7 @@ void SourceTextModule::SourceTextModuleVerify(Isolate* isolate) {
15191519
}
15201520
CHECK(!AsyncParentModuleCount());
15211521
CHECK(!pending_async_dependencies());
1522-
CHECK(!async_evaluating());
1522+
CHECK(!IsAsyncEvaluating());
15231523
}
15241524

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

src/diagnostics/objects-printer.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1746,6 +1746,7 @@ void SourceTextModule::SourceTextModulePrint(std::ostream& os) { // NOLINT
17461746
os << "\n - requested_modules: " << Brief(requested_modules());
17471747
os << "\n - import_meta: " << Brief(import_meta());
17481748
os << "\n - cycle_root: " << Brief(cycle_root());
1749+
os << "\n - async_evaluating_ordinal: " << async_evaluating_ordinal();
17491750
os << "\n";
17501751
}
17511752

src/execution/isolate-inl.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "src/objects/property-cell.h"
1515
#include "src/objects/regexp-match-info.h"
1616
#include "src/objects/shared-function-info.h"
17+
#include "src/objects/source-text-module-inl.h"
1718

1819
namespace v8 {
1920
namespace internal {
@@ -120,6 +121,36 @@ bool Isolate::IsAnyInitialArrayPrototype(JSArray array) {
120121
return IsInAnyContext(array, Context::INITIAL_ARRAY_PROTOTYPE_INDEX);
121122
}
122123

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

src/execution/isolate.cc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@
7474
#include "src/objects/prototype.h"
7575
#include "src/objects/slots.h"
7676
#include "src/objects/smi.h"
77+
#include "src/objects/source-text-module-inl.h"
7778
#include "src/objects/stack-frame-info-inl.h"
7879
#include "src/objects/visitors.h"
7980
#include "src/profiler/heap-profiler.h"
@@ -2937,6 +2938,8 @@ Isolate::Isolate(std::unique_ptr<i::IsolateAllocator> isolate_allocator)
29372938
#if V8_SFI_HAS_UNIQUE_ID
29382939
next_unique_sfi_id_(0),
29392940
#endif
2941+
next_module_async_evaluating_ordinal_(
2942+
SourceTextModule::kFirstAsyncEvaluatingOrdinal),
29402943
cancelable_task_manager_(new CancelableTaskManager()) {
29412944
TRACE_ISOLATE(constructor);
29422945
CheckIsolateLayout();

src/execution/isolate.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1374,6 +1374,22 @@ class V8_EXPORT_PRIVATE Isolate final : private HiddenFactory {
13741374
return id;
13751375
}
13761376

1377+
// https://github.com/tc39/proposal-top-level-await/pull/159
1378+
// TODO(syg): Update to actual spec link once merged.
1379+
//
1380+
// According to the spec, modules that depend on async modules (i.e. modules
1381+
// with top-level await) must be evaluated in order in which their
1382+
// [[AsyncEvaluating]] flags were set to true. V8 tracks this global total
1383+
// order with next_module_async_evaluating_ordinal_. Each module that sets its
1384+
// [[AsyncEvaluating]] to true grabs the next ordinal.
1385+
unsigned NextModuleAsyncEvaluatingOrdinal() {
1386+
unsigned ordinal = next_module_async_evaluating_ordinal_++;
1387+
CHECK_LT(ordinal, kMaxModuleAsyncEvaluatingOrdinal);
1388+
return ordinal;
1389+
}
1390+
1391+
inline void DidFinishModuleAsyncEvaluation(unsigned ordinal);
1392+
13771393
void AddNearHeapLimitCallback(v8::NearHeapLimitCallback, void* data);
13781394
void RemoveNearHeapLimitCallback(v8::NearHeapLimitCallback callback,
13791395
size_t heap_limit);
@@ -1979,6 +1995,8 @@ class V8_EXPORT_PRIVATE Isolate final : private HiddenFactory {
19791995
std::atomic<int> next_unique_sfi_id_;
19801996
#endif
19811997

1998+
unsigned next_module_async_evaluating_ordinal_;
1999+
19822000
// Vector of callbacks before a Call starts execution.
19832001
std::vector<BeforeCallEnteredCallback> before_call_entered_callbacks_;
19842002

src/heap/factory.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2416,7 +2416,7 @@ Handle<SourceTextModule> Factory::NewSourceTextModule(
24162416
module.set_dfs_ancestor_index(-1);
24172417
module.set_flags(0);
24182418
module.set_async(IsAsyncModule(sfi->kind()));
2419-
module.set_async_evaluating(false);
2419+
module.set_async_evaluating_ordinal(SourceTextModule::kNotAsyncEvaluated);
24202420
module.set_cycle_root(roots.the_hole_value(), SKIP_WRITE_BARRIER);
24212421
module.set_async_parent_modules(*async_parent_modules);
24222422
module.set_pending_async_dependencies(0);

src/objects/module-inl.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ SMI_ACCESSORS(Module, status, kStatusOffset)
3838
SMI_ACCESSORS(Module, hash, kHashOffset)
3939

4040
BOOL_ACCESSORS(SourceTextModule, flags, async, AsyncBit::kShift)
41-
BOOL_ACCESSORS(SourceTextModule, flags, async_evaluating,
42-
AsyncEvaluatingBit::kShift)
41+
BIT_FIELD_ACCESSORS(SourceTextModule, flags, async_evaluating_ordinal,
42+
SourceTextModule::AsyncEvaluatingOrdinalBits)
4343
ACCESSORS(SourceTextModule, async_parent_modules, ArrayList,
4444
kAsyncParentModulesOffset)
4545

@@ -139,6 +139,10 @@ int SourceTextModule::AsyncParentModuleCount() {
139139
return async_parent_modules().Length();
140140
}
141141

142+
bool SourceTextModule::IsAsyncEvaluating() const {
143+
return async_evaluating_ordinal() >= kFirstAsyncEvaluatingOrdinal;
144+
}
145+
142146
bool SourceTextModule::HasPendingAsyncDependencies() {
143147
DCHECK_GE(pending_async_dependencies(), 0);
144148
return pending_async_dependencies() > 0;

0 commit comments

Comments
 (0)