mirror of
https://github.com/zebrajr/node.git
synced 2025-12-06 00:20:08 +01:00
deps: backport v8 f19142e6
[top-level-await] Implement the new post-order requirement for
async subgraphs
Refs: f19142e613
PR-URL: https://github.com/nodejs/node/pull/37864
Backport-PR-URL: https://github.com/nodejs/node/pull/37985
Reviewed-By: Michaël Zasso <targos@protonmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
This commit is contained in:
parent
2fd97ce687
commit
f09c033faf
3
deps/v8/src/common/globals.h
vendored
3
deps/v8/src/common/globals.h
vendored
|
|
@ -349,6 +349,9 @@ constexpr int kUC16Size = sizeof(uc16); // NOLINT
|
|||
// 128 bit SIMD value size.
|
||||
constexpr int kSimd128Size = 16;
|
||||
|
||||
// Maximum ordinal used for tracking asynchronous module evaluation order.
|
||||
constexpr unsigned kMaxModuleAsyncEvaluatingOrdinal = (1 << 30) - 1;
|
||||
|
||||
// FUNCTION_ADDR(f) gets the address of a C function f.
|
||||
#define FUNCTION_ADDR(f) (reinterpret_cast<v8::internal::Address>(f))
|
||||
|
||||
|
|
|
|||
3
deps/v8/src/diagnostics/objects-debug.cc
vendored
3
deps/v8/src/diagnostics/objects-debug.cc
vendored
|
|
@ -1390,7 +1390,8 @@ void SourceTextModule::SourceTextModuleVerify(Isolate* isolate) {
|
|||
(status() == kPreInstantiating && code().IsSharedFunctionInfo()) ||
|
||||
(status() == kUninstantiated && code().IsSharedFunctionInfo()));
|
||||
CHECK(top_level_capability().IsUndefined() && !AsyncParentModuleCount() &&
|
||||
!pending_async_dependencies() && !async_evaluating());
|
||||
!pending_async_dependencies());
|
||||
CHECK(!IsAsyncEvaluating());
|
||||
}
|
||||
|
||||
CHECK_EQ(requested_modules().length(), info().module_requests().length());
|
||||
|
|
|
|||
1
deps/v8/src/diagnostics/objects-printer.cc
vendored
1
deps/v8/src/diagnostics/objects-printer.cc
vendored
|
|
@ -1602,6 +1602,7 @@ void SourceTextModule::SourceTextModulePrint(std::ostream& os) { // NOLINT
|
|||
os << "\n - script: " << Brief(script());
|
||||
os << "\n - import_meta: " << Brief(import_meta());
|
||||
os << "\n - cycle_root: " << Brief(cycle_root());
|
||||
os << "\n - async_evaluating_ordinal: " << async_evaluating_ordinal();
|
||||
os << "\n";
|
||||
}
|
||||
|
||||
|
|
|
|||
31
deps/v8/src/execution/isolate-inl.h
vendored
31
deps/v8/src/execution/isolate-inl.h
vendored
|
|
@ -13,6 +13,7 @@
|
|||
#include "src/objects/property-cell.h"
|
||||
#include "src/objects/regexp-match-info.h"
|
||||
#include "src/objects/shared-function-info.h"
|
||||
#include "src/objects/source-text-module.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
|
@ -118,6 +119,36 @@ Isolate::ExceptionScope::~ExceptionScope() {
|
|||
isolate_->set_pending_exception(*pending_exception_);
|
||||
}
|
||||
|
||||
void Isolate::DidFinishModuleAsyncEvaluation(unsigned ordinal) {
|
||||
// To address overflow, the ordinal is reset when the async module with the
|
||||
// largest vended ordinal finishes evaluating. Modules are evaluated in
|
||||
// ascending order of their async_evaluating_ordinal.
|
||||
//
|
||||
// While the specification imposes a global total ordering, the intention is
|
||||
// that for each async module, all its parents are totally ordered by when
|
||||
// they first had their [[AsyncEvaluating]] bit set.
|
||||
//
|
||||
// The module with largest vended ordinal finishes evaluating implies that the
|
||||
// async dependency as well as all other modules in that module's graph
|
||||
// depending on async dependencies are finished evaluating.
|
||||
//
|
||||
// If the async dependency participates in other module graphs (e.g. via
|
||||
// dynamic import, or other <script type=module> tags), those module graphs
|
||||
// must have been evaluated either before or after the async dependency is
|
||||
// settled, as the concrete Evaluate() method on cyclic module records is
|
||||
// neither reentrant nor performs microtask checkpoints during its
|
||||
// evaluation. If before, then all modules that depend on the async
|
||||
// dependencies were given an ordinal that ensure they are relatively ordered,
|
||||
// before the global ordinal was reset. If after, then the async evaluating
|
||||
// ordering does not apply, as the dependency is no longer asynchronous.
|
||||
//
|
||||
// https://tc39.es/ecma262/#sec-moduleevaluation
|
||||
if (ordinal + 1 == next_module_async_evaluating_ordinal_) {
|
||||
next_module_async_evaluating_ordinal_ =
|
||||
SourceTextModule::kFirstAsyncEvaluatingOrdinal;
|
||||
}
|
||||
}
|
||||
|
||||
#define NATIVE_CONTEXT_FIELD_ACCESSOR(index, type, name) \
|
||||
Handle<type> Isolate::name() { \
|
||||
return Handle<type>(raw_native_context().name(), this); \
|
||||
|
|
|
|||
3
deps/v8/src/execution/isolate.cc
vendored
3
deps/v8/src/execution/isolate.cc
vendored
|
|
@ -69,6 +69,7 @@
|
|||
#include "src/objects/prototype.h"
|
||||
#include "src/objects/slots.h"
|
||||
#include "src/objects/smi.h"
|
||||
#include "src/objects/source-text-module.h"
|
||||
#include "src/objects/stack-frame-info-inl.h"
|
||||
#include "src/objects/visitors.h"
|
||||
#include "src/profiler/heap-profiler.h"
|
||||
|
|
@ -2929,6 +2930,8 @@ Isolate::Isolate(std::unique_ptr<i::IsolateAllocator> isolate_allocator)
|
|||
#if V8_SFI_HAS_UNIQUE_ID
|
||||
next_unique_sfi_id_(0),
|
||||
#endif
|
||||
next_module_async_evaluating_ordinal_(
|
||||
SourceTextModule::kFirstAsyncEvaluatingOrdinal),
|
||||
cancelable_task_manager_(new CancelableTaskManager()) {
|
||||
TRACE_ISOLATE(constructor);
|
||||
CheckIsolateLayout();
|
||||
|
|
|
|||
18
deps/v8/src/execution/isolate.h
vendored
18
deps/v8/src/execution/isolate.h
vendored
|
|
@ -1284,6 +1284,22 @@ class V8_EXPORT_PRIVATE Isolate final : private HiddenFactory {
|
|||
return id;
|
||||
}
|
||||
|
||||
// https://github.com/tc39/proposal-top-level-await/pull/159
|
||||
// TODO(syg): Update to actual spec link once merged.
|
||||
//
|
||||
// According to the spec, modules that depend on async modules (i.e. modules
|
||||
// with top-level await) must be evaluated in order in which their
|
||||
// [[AsyncEvaluating]] flags were set to true. V8 tracks this global total
|
||||
// order with next_module_async_evaluating_ordinal_. Each module that sets its
|
||||
// [[AsyncEvaluating]] to true grabs the next ordinal.
|
||||
unsigned NextModuleAsyncEvaluatingOrdinal() {
|
||||
unsigned ordinal = next_module_async_evaluating_ordinal_++;
|
||||
CHECK_LT(ordinal, kMaxModuleAsyncEvaluatingOrdinal);
|
||||
return ordinal;
|
||||
}
|
||||
|
||||
inline void DidFinishModuleAsyncEvaluation(unsigned ordinal);
|
||||
|
||||
void AddNearHeapLimitCallback(v8::NearHeapLimitCallback, void* data);
|
||||
void RemoveNearHeapLimitCallback(v8::NearHeapLimitCallback callback,
|
||||
size_t heap_limit);
|
||||
|
|
@ -1815,6 +1831,8 @@ class V8_EXPORT_PRIVATE Isolate final : private HiddenFactory {
|
|||
std::atomic<int> next_unique_sfi_id_;
|
||||
#endif
|
||||
|
||||
unsigned next_module_async_evaluating_ordinal_;
|
||||
|
||||
// Vector of callbacks before a Call starts execution.
|
||||
std::vector<BeforeCallEnteredCallback> before_call_entered_callbacks_;
|
||||
|
||||
|
|
|
|||
2
deps/v8/src/heap/factory.cc
vendored
2
deps/v8/src/heap/factory.cc
vendored
|
|
@ -2504,7 +2504,7 @@ Handle<SourceTextModule> Factory::NewSourceTextModule(
|
|||
module->set_top_level_capability(roots.undefined_value());
|
||||
module->set_flags(0);
|
||||
module->set_async(IsAsyncModule(code->kind()));
|
||||
module->set_async_evaluating(false);
|
||||
module->set_async_evaluating_ordinal(SourceTextModule::kNotAsyncEvaluated);
|
||||
module->set_cycle_root(roots.the_hole_value());
|
||||
module->set_async_parent_modules(*async_parent_modules);
|
||||
module->set_pending_async_dependencies(0);
|
||||
|
|
|
|||
8
deps/v8/src/objects/module-inl.h
vendored
8
deps/v8/src/objects/module-inl.h
vendored
|
|
@ -37,8 +37,8 @@ SMI_ACCESSORS(Module, status, kStatusOffset)
|
|||
SMI_ACCESSORS(Module, hash, kHashOffset)
|
||||
|
||||
BOOL_ACCESSORS(SourceTextModule, flags, async, AsyncBit::kShift)
|
||||
BOOL_ACCESSORS(SourceTextModule, flags, async_evaluating,
|
||||
AsyncEvaluatingBit::kShift)
|
||||
BIT_FIELD_ACCESSORS(SourceTextModule, flags, async_evaluating_ordinal,
|
||||
SourceTextModule::AsyncEvaluatingOrdinalBits)
|
||||
ACCESSORS(SourceTextModule, async_parent_modules, ArrayList,
|
||||
kAsyncParentModulesOffset)
|
||||
ACCESSORS(SourceTextModule, top_level_capability, HeapObject,
|
||||
|
|
@ -141,6 +141,10 @@ int SourceTextModule::AsyncParentModuleCount() {
|
|||
return async_parent_modules().Length();
|
||||
}
|
||||
|
||||
bool SourceTextModule::IsAsyncEvaluating() const {
|
||||
return async_evaluating_ordinal() >= kFirstAsyncEvaluatingOrdinal;
|
||||
}
|
||||
|
||||
bool SourceTextModule::HasPendingAsyncDependencies() {
|
||||
DCHECK_GE(pending_async_dependencies(), 0);
|
||||
return pending_async_dependencies() > 0;
|
||||
|
|
|
|||
247
deps/v8/src/objects/source-text-module.cc
vendored
247
deps/v8/src/objects/source-text-module.cc
vendored
|
|
@ -76,6 +76,15 @@ class Module::ResolveSet
|
|||
Zone* zone_;
|
||||
};
|
||||
|
||||
struct SourceTextModule::AsyncEvaluatingOrdinalCompare {
|
||||
bool operator()(Handle<SourceTextModule> lhs,
|
||||
Handle<SourceTextModule> rhs) const {
|
||||
DCHECK(lhs->IsAsyncEvaluating());
|
||||
DCHECK(rhs->IsAsyncEvaluating());
|
||||
return lhs->async_evaluating_ordinal() < rhs->async_evaluating_ordinal();
|
||||
}
|
||||
};
|
||||
|
||||
SharedFunctionInfo SourceTextModule::GetSharedFunctionInfo() const {
|
||||
DisallowHeapAllocation no_alloc;
|
||||
switch (status()) {
|
||||
|
|
@ -579,6 +588,58 @@ void SourceTextModule::FetchStarExports(Isolate* isolate,
|
|||
module->set_exports(*exports);
|
||||
}
|
||||
|
||||
void SourceTextModule::GatherAsyncParentCompletions(
|
||||
Isolate* isolate, Zone* zone, Handle<SourceTextModule> start,
|
||||
AsyncParentCompletionSet* exec_list) {
|
||||
// The spec algorithm is recursive. It is transformed to an equivalent
|
||||
// iterative one here.
|
||||
ZoneStack<Handle<SourceTextModule>> worklist(zone);
|
||||
worklist.push(start);
|
||||
|
||||
while (!worklist.empty()) {
|
||||
Handle<SourceTextModule> module = worklist.top();
|
||||
worklist.pop();
|
||||
|
||||
// 1. Assert: module.[[Status]] is evaluated.
|
||||
DCHECK_EQ(module->status(), kEvaluated);
|
||||
|
||||
// 2. For each Module m of module.[[AsyncParentModules]], do
|
||||
for (int i = module->AsyncParentModuleCount(); i-- > 0;) {
|
||||
Handle<SourceTextModule> m = module->GetAsyncParentModule(isolate, i);
|
||||
|
||||
// a. If execList does not contain m and
|
||||
// m.[[CycleRoot]].[[EvaluationError]] is empty, then
|
||||
if (exec_list->find(m) == exec_list->end() &&
|
||||
m->GetCycleRoot(isolate)->status() != kErrored) {
|
||||
// i. Assert: m.[[EvaluationError]] is empty.
|
||||
DCHECK_NE(m->status(), kErrored);
|
||||
|
||||
// ii. Assert: m.[[AsyncEvaluating]] is true.
|
||||
DCHECK(m->IsAsyncEvaluating());
|
||||
|
||||
// iii. Assert: m.[[PendingAsyncDependencies]] > 0.
|
||||
DCHECK(m->HasPendingAsyncDependencies());
|
||||
|
||||
// iv. Set m.[[PendingAsyncDependencies]] to
|
||||
// m.[[PendingAsyncDependencies]] - 1.
|
||||
m->DecrementPendingAsyncDependencies();
|
||||
|
||||
// v. If m.[[PendingAsyncDependencies]] is equal to 0, then
|
||||
if (!m->HasPendingAsyncDependencies()) {
|
||||
// 1. Append m to execList.
|
||||
exec_list->insert(m);
|
||||
|
||||
// 2. If m.[[Async]] is false,
|
||||
// perform ! GatherAsyncParentCompletions(m, execList).
|
||||
if (!m->async()) worklist.push(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Return undefined.
|
||||
}
|
||||
|
||||
Handle<JSModuleNamespace> SourceTextModule::GetModuleNamespace(
|
||||
Isolate* isolate, Handle<SourceTextModule> module, int module_request) {
|
||||
Handle<Module> requested_module(
|
||||
|
|
@ -665,7 +726,7 @@ MaybeHandle<Object> SourceTextModule::EvaluateMaybeAsync(
|
|||
CHECK_EQ(module->status(), kEvaluated);
|
||||
|
||||
// b. If module.[[AsyncEvaluating]] is false, then
|
||||
if (!module->async_evaluating()) {
|
||||
if (!module->IsAsyncEvaluating()) {
|
||||
// i. Perform ! Call(capability.[[Resolve]], undefined,
|
||||
// «undefined»).
|
||||
JSPromise::Resolve(capability, isolate->factory()->undefined_value())
|
||||
|
|
@ -718,81 +779,97 @@ MaybeHandle<Object> SourceTextModule::Evaluate(
|
|||
|
||||
void SourceTextModule::AsyncModuleExecutionFulfilled(
|
||||
Isolate* isolate, Handle<SourceTextModule> module) {
|
||||
// 1. Assert: module.[[Status]] is "evaluated".
|
||||
CHECK(module->status() == kEvaluated || module->status() == kErrored);
|
||||
// 1. Assert: module.[[AsyncEvaluating]] is true.
|
||||
DCHECK(module->IsAsyncEvaluating());
|
||||
|
||||
// 2. If module.[[AsyncEvaluating]] is false,
|
||||
if (!module->async_evaluating()) {
|
||||
// a. Assert: module.[[EvaluationError]] is not undefined.
|
||||
CHECK_EQ(module->status(), kErrored);
|
||||
|
||||
// b. Return undefined.
|
||||
return;
|
||||
}
|
||||
|
||||
// 3. Assert: module.[[EvaluationError]] is undefined.
|
||||
// 2. Assert: module.[[EvaluationError]] is undefined.
|
||||
CHECK_EQ(module->status(), kEvaluated);
|
||||
|
||||
// 4. Set module.[[AsyncEvaluating]] to false.
|
||||
module->set_async_evaluating(false);
|
||||
// 3. Set module.[[AsyncEvaluating]] to false.
|
||||
isolate->DidFinishModuleAsyncEvaluation(module->async_evaluating_ordinal());
|
||||
module->set_async_evaluating_ordinal(kAsyncEvaluateDidFinish);
|
||||
|
||||
// 5. For each Module m of module.[[AsyncParentModules]], do
|
||||
for (int i = 0; i < module->AsyncParentModuleCount(); i++) {
|
||||
Handle<SourceTextModule> m = module->GetAsyncParentModule(isolate, i);
|
||||
|
||||
// a. Decrement m.[[PendingAsyncDependencies]] by 1.
|
||||
m->DecrementPendingAsyncDependencies();
|
||||
|
||||
// b. If m.[[PendingAsyncDependencies]] is 0 and m.[[EvaluationError]] is
|
||||
// undefined, then
|
||||
if (!m->HasPendingAsyncDependencies() && m->status() == kEvaluated) {
|
||||
// i. Assert: m.[[AsyncEvaluating]] is true.
|
||||
DCHECK(m->async_evaluating());
|
||||
|
||||
// ii. If m.[[CycleRoot]].[[EvaluationError]] is not undefined,
|
||||
// return undefined.
|
||||
if (m->GetCycleRoot(isolate)->status() == kErrored) {
|
||||
return;
|
||||
}
|
||||
|
||||
// iii. If m.[[Async]] is true, then
|
||||
if (m->async()) {
|
||||
// 1. Perform ! ExecuteAsyncModule(m).
|
||||
ExecuteAsyncModule(isolate, m);
|
||||
} else {
|
||||
// iv. Otherwise,
|
||||
// 1. Let result be m.ExecuteModule().
|
||||
// 2. If result is a normal completion,
|
||||
Handle<Object> unused_result;
|
||||
if (ExecuteModule(isolate, m).ToHandle(&unused_result)) {
|
||||
// a. Perform ! AsyncModuleExecutionFulfilled(m).
|
||||
AsyncModuleExecutionFulfilled(isolate, m);
|
||||
} else {
|
||||
// 3. Otherwise,
|
||||
// a. Perform ! AsyncModuleExecutionRejected(m,
|
||||
// result.[[Value]]).
|
||||
Handle<Object> exception(isolate->pending_exception(), isolate);
|
||||
isolate->clear_pending_exception();
|
||||
AsyncModuleExecutionRejected(isolate, m, exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 6. If module.[[TopLevelCapability]] is not undefined, then
|
||||
// 4. If module.[[TopLevelCapability]] is not empty, then
|
||||
if (!module->top_level_capability().IsUndefined(isolate)) {
|
||||
// a. Assert: module.[[DFSIndex]] is equal to module.[[DFSAncestorIndex]].
|
||||
DCHECK_EQ(module->dfs_index(), module->dfs_ancestor_index());
|
||||
// a. Assert: module.[[CycleRoot]] is equal to module.
|
||||
DCHECK_EQ(*module->GetCycleRoot(isolate), *module);
|
||||
|
||||
// b. Perform ! Call(module.[[TopLevelCapability]].[[Resolve]],
|
||||
// undefined, «undefined»).
|
||||
// i. Perform ! Call(module.[[TopLevelCapability]].[[Resolve]], undefined,
|
||||
// «undefined»).
|
||||
Handle<JSPromise> capability(
|
||||
JSPromise::cast(module->top_level_capability()), isolate);
|
||||
JSPromise::Resolve(capability, isolate->factory()->undefined_value())
|
||||
.ToHandleChecked();
|
||||
}
|
||||
|
||||
// 7. Return undefined.
|
||||
// 5. Let execList be a new empty List.
|
||||
Zone zone(isolate->allocator(), ZONE_NAME);
|
||||
AsyncParentCompletionSet exec_list(&zone);
|
||||
|
||||
// 6. Perform ! GatherAsyncParentCompletions(module, execList).
|
||||
GatherAsyncParentCompletions(isolate, &zone, module, &exec_list);
|
||||
|
||||
// 7. Let sortedExecList be a List of elements that are the elements of
|
||||
// execList, in the order in which they had their [[AsyncEvaluating]]
|
||||
// fields set to true in InnerModuleEvaluation.
|
||||
//
|
||||
// This step is implemented by AsyncParentCompletionSet, which is a set
|
||||
// ordered on async_evaluating_ordinal.
|
||||
|
||||
// 8. Assert: All elements of sortedExecList have their [[AsyncEvaluating]]
|
||||
// field set to true, [[PendingAsyncDependencies]] field set to 0 and
|
||||
// [[EvaluationError]] field set to undefined.
|
||||
#ifdef DEBUG
|
||||
for (Handle<SourceTextModule> m : exec_list) {
|
||||
DCHECK(m->IsAsyncEvaluating());
|
||||
DCHECK(!m->HasPendingAsyncDependencies());
|
||||
DCHECK_NE(m->status(), kErrored);
|
||||
}
|
||||
#endif
|
||||
|
||||
// 9. For each Module m of sortedExecList, do
|
||||
for (Handle<SourceTextModule> m : exec_list) {
|
||||
// i. If m.[[AsyncEvaluating]] is false, then
|
||||
if (!m->IsAsyncEvaluating()) {
|
||||
// a. Assert: m.[[EvaluatingError]] is not empty.
|
||||
DCHECK_EQ(m->status(), kErrored);
|
||||
} else if (m->async()) {
|
||||
// ii. Otherwise, if m.[[Async]] is *true*, then
|
||||
// a. Perform ! ExecuteAsyncModule(m).
|
||||
ExecuteAsyncModule(isolate, m);
|
||||
} else {
|
||||
// iii. Otherwise,
|
||||
// a. Let _result_ be m.ExecuteModule().
|
||||
Handle<Object> unused_result;
|
||||
// b. If _result_ is an abrupt completion,
|
||||
if (!ExecuteModule(isolate, m).ToHandle(&unused_result)) {
|
||||
// 1. Perform ! AsyncModuleExecutionRejected(m, result.[[Value]]).
|
||||
Handle<Object> exception(isolate->pending_exception(), isolate);
|
||||
isolate->clear_pending_exception();
|
||||
AsyncModuleExecutionRejected(isolate, m, exception);
|
||||
} else {
|
||||
// c. Otherwise,
|
||||
// 1. Set m.[[AsyncEvaluating]] to false.
|
||||
isolate->DidFinishModuleAsyncEvaluation(m->async_evaluating_ordinal());
|
||||
m->set_async_evaluating_ordinal(kAsyncEvaluateDidFinish);
|
||||
|
||||
// 2. If m.[[TopLevelCapability]] is not empty, then
|
||||
if (!m->top_level_capability().IsUndefined(isolate)) {
|
||||
// i. Assert: m.[[CycleRoot]] is equal to m.
|
||||
DCHECK_EQ(*m->GetCycleRoot(isolate), *m);
|
||||
|
||||
// ii. Perform ! Call(m.[[TopLevelCapability]].[[Resolve]],
|
||||
// undefined, «undefined»).
|
||||
Handle<JSPromise> capability(
|
||||
JSPromise::cast(m->top_level_capability()), isolate);
|
||||
JSPromise::Resolve(capability, isolate->factory()->undefined_value())
|
||||
.ToHandleChecked();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 10. Return undefined.
|
||||
}
|
||||
|
||||
void SourceTextModule::AsyncModuleExecutionRejected(
|
||||
|
|
@ -804,7 +881,7 @@ void SourceTextModule::AsyncModuleExecutionRejected(
|
|||
CHECK(module->status() == kEvaluated || module->status() == kErrored);
|
||||
|
||||
// 2. If module.[[AsyncEvaluating]] is false,
|
||||
if (!module->async_evaluating()) {
|
||||
if (!module->IsAsyncEvaluating()) {
|
||||
// a. Assert: module.[[EvaluationError]] is not undefined.
|
||||
CHECK_EQ(module->status(), kErrored);
|
||||
|
||||
|
|
@ -816,7 +893,8 @@ void SourceTextModule::AsyncModuleExecutionRejected(
|
|||
module->RecordError(isolate, exception);
|
||||
|
||||
// 5. Set module.[[AsyncEvaluating]] to false.
|
||||
module->set_async_evaluating(false);
|
||||
isolate->DidFinishModuleAsyncEvaluation(module->async_evaluating_ordinal());
|
||||
module->set_async_evaluating_ordinal(kAsyncEvaluateDidFinish);
|
||||
|
||||
// 6. For each Module m of module.[[AsyncParentModules]], do
|
||||
for (int i = 0; i < module->AsyncParentModuleCount(); i++) {
|
||||
|
|
@ -835,8 +913,8 @@ void SourceTextModule::AsyncModuleExecutionRejected(
|
|||
|
||||
// 7. If module.[[TopLevelCapability]] is not undefined, then
|
||||
if (!module->top_level_capability().IsUndefined(isolate)) {
|
||||
// a. Assert: module.[[DFSIndex]] is equal to module.[[DFSAncestorIndex]].
|
||||
DCHECK(module->dfs_index() == module->dfs_ancestor_index());
|
||||
// a. Assert: module.[[CycleRoot]] is equal to module.
|
||||
DCHECK_EQ(*module->GetCycleRoot(isolate), *module);
|
||||
|
||||
// b. Perform ! Call(module.[[TopLevelCapability]].[[Reject]],
|
||||
// undefined, «error»).
|
||||
|
|
@ -857,7 +935,8 @@ void SourceTextModule::ExecuteAsyncModule(Isolate* isolate,
|
|||
DCHECK(module->async());
|
||||
|
||||
// 3. Set module.[[AsyncEvaluating]] to true.
|
||||
module->set_async_evaluating(true);
|
||||
module->set_async_evaluating_ordinal(
|
||||
isolate->NextModuleAsyncEvaluatingOrdinal());
|
||||
|
||||
// 4. Let capability be ! NewPromiseCapability(%Promise%).
|
||||
Handle<JSPromise> capability = isolate->factory()->NewJSPromise();
|
||||
|
|
@ -1059,7 +1138,7 @@ MaybeHandle<Object> SourceTextModule::InnerModuleEvaluation(
|
|||
}
|
||||
}
|
||||
// v. If requiredModule.[[AsyncEvaluating]] is true, then
|
||||
if (required_module->async_evaluating()) {
|
||||
if (required_module->IsAsyncEvaluating()) {
|
||||
// 1. Set module.[[PendingAsyncDependencies]] to
|
||||
// module.[[PendingAsyncDependencies]] + 1.
|
||||
module->IncrementPendingAsyncDependencies();
|
||||
|
|
@ -1081,16 +1160,26 @@ MaybeHandle<Object> SourceTextModule::InnerModuleEvaluation(
|
|||
// synchronous modules, but return undefined for AsyncModules.
|
||||
Handle<Object> result = isolate->factory()->undefined_value();
|
||||
|
||||
// 14. If module.[[PendingAsyncDependencies]] is > 0, set
|
||||
// module.[[AsyncEvaluating]] to true.
|
||||
if (module->HasPendingAsyncDependencies()) {
|
||||
module->set_async_evaluating(true);
|
||||
} else if (module->async()) {
|
||||
// 15. Otherwise, if module.[[Async]] is true,
|
||||
// perform ! ExecuteAsyncModule(module).
|
||||
SourceTextModule::ExecuteAsyncModule(isolate, module);
|
||||
// 14. If module.[[PendingAsyncDependencies]] > 0 or module.[[Async]] is
|
||||
// true, then
|
||||
if (module->HasPendingAsyncDependencies() || module->async()) {
|
||||
// a. Assert: module.[[AsyncEvaluating]] is false and was never previously
|
||||
// set to true.
|
||||
DCHECK_EQ(module->async_evaluating_ordinal(), kNotAsyncEvaluated);
|
||||
|
||||
// b. Set module.[[AsyncEvaluating]] to true.
|
||||
// NOTE: The order in which modules transition to async evaluating is
|
||||
// significant.
|
||||
module->set_async_evaluating_ordinal(
|
||||
isolate->NextModuleAsyncEvaluatingOrdinal());
|
||||
|
||||
// c. If module.[[PendingAsyncDependencies]] is 0,
|
||||
// perform ! ExecuteAsyncModule(_module_).
|
||||
if (!module->HasPendingAsyncDependencies()) {
|
||||
SourceTextModule::ExecuteAsyncModule(isolate, module);
|
||||
}
|
||||
} else {
|
||||
// 16. Otherwise, perform ? module.ExecuteModule().
|
||||
// 15. Otherwise, perform ? module.ExecuteModule().
|
||||
ASSIGN_RETURN_ON_EXCEPTION(isolate, result, ExecuteModule(isolate, module),
|
||||
Object);
|
||||
}
|
||||
|
|
|
|||
36
deps/v8/src/objects/source-text-module.h
vendored
36
deps/v8/src/objects/source-text-module.h
vendored
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include "src/objects/module.h"
|
||||
#include "src/objects/promise.h"
|
||||
#include "src/zone/zone-containers.h"
|
||||
#include "torque-generated/bit-fields-tq.h"
|
||||
|
||||
// Has to be the last include (doesn't have include guards):
|
||||
|
|
@ -69,10 +70,16 @@ class SourceTextModule
|
|||
SubclassBodyDescriptor<Module::BodyDescriptor,
|
||||
FixedBodyDescriptor<kCodeOffset, kSize, kSize>>;
|
||||
|
||||
static constexpr unsigned kFirstAsyncEvaluatingOrdinal = 2;
|
||||
|
||||
private:
|
||||
friend class Factory;
|
||||
friend class Module;
|
||||
|
||||
struct AsyncEvaluatingOrdinalCompare;
|
||||
using AsyncParentCompletionSet =
|
||||
ZoneSet<Handle<SourceTextModule>, AsyncEvaluatingOrdinalCompare>;
|
||||
|
||||
// Appends a tuple of module and generator to the async parent modules
|
||||
// ArrayList.
|
||||
inline static void AddAsyncParentModule(Isolate* isolate,
|
||||
|
|
@ -90,6 +97,8 @@ class SourceTextModule
|
|||
// Returns the number of async parent modules for a given async child.
|
||||
inline int AsyncParentModuleCount();
|
||||
|
||||
inline bool IsAsyncEvaluating() const;
|
||||
|
||||
inline bool HasPendingAsyncDependencies();
|
||||
inline void IncrementPendingAsyncDependencies();
|
||||
inline void DecrementPendingAsyncDependencies();
|
||||
|
|
@ -97,13 +106,26 @@ class SourceTextModule
|
|||
// Bits for flags.
|
||||
DEFINE_TORQUE_GENERATED_SOURCE_TEXT_MODULE_FLAGS()
|
||||
|
||||
// async_evaluating, top_level_capability, pending_async_dependencies, and
|
||||
// async_parent_modules are used exclusively during evaluation of async
|
||||
// async_evaluating_ordinal, top_level_capability, pending_async_dependencies,
|
||||
// and async_parent_modules are used exclusively during evaluation of async
|
||||
// modules and the modules which depend on them.
|
||||
//
|
||||
// Whether or not this module is async and evaluating or currently evaluating
|
||||
// an async child.
|
||||
DECL_BOOLEAN_ACCESSORS(async_evaluating)
|
||||
// If >1, this module is async and evaluating or currently evaluating an async
|
||||
// child. The integer is an ordinal for when this module first started async
|
||||
// evaluation and is used for sorting async parent modules when determining
|
||||
// which parent module can start executing after an async evaluation
|
||||
// completes.
|
||||
//
|
||||
// If 1, this module has finished async evaluating.
|
||||
//
|
||||
// If 0, this module is not async or has not been async evaluated.
|
||||
static constexpr unsigned kNotAsyncEvaluated = 0;
|
||||
static constexpr unsigned kAsyncEvaluateDidFinish = 1;
|
||||
STATIC_ASSERT(kNotAsyncEvaluated < kAsyncEvaluateDidFinish);
|
||||
STATIC_ASSERT(kAsyncEvaluateDidFinish < kFirstAsyncEvaluatingOrdinal);
|
||||
STATIC_ASSERT(kMaxModuleAsyncEvaluatingOrdinal ==
|
||||
AsyncEvaluatingOrdinalBits::kMax);
|
||||
DECL_PRIMITIVE_ACCESSORS(async_evaluating_ordinal, unsigned)
|
||||
|
||||
// The top level promise capability of this module. Will only be defined
|
||||
// for cycle roots.
|
||||
|
|
@ -149,6 +171,10 @@ class SourceTextModule
|
|||
Handle<SourceTextModule> module, Zone* zone,
|
||||
UnorderedModuleSet* visited);
|
||||
|
||||
static void GatherAsyncParentCompletions(Isolate* isolate, Zone* zone,
|
||||
Handle<SourceTextModule> start,
|
||||
AsyncParentCompletionSet* exec_list);
|
||||
|
||||
// Implementation of spec concrete method Evaluate.
|
||||
static V8_WARN_UNUSED_RESULT MaybeHandle<Object> EvaluateMaybeAsync(
|
||||
Isolate* isolate, Handle<SourceTextModule> module);
|
||||
|
|
|
|||
2
deps/v8/src/objects/source-text-module.tq
vendored
2
deps/v8/src/objects/source-text-module.tq
vendored
|
|
@ -6,7 +6,7 @@ type SourceTextModuleInfo extends FixedArray;
|
|||
|
||||
bitfield struct SourceTextModuleFlags extends uint31 {
|
||||
async: bool: 1 bit;
|
||||
async_evaluating: bool: 1 bit;
|
||||
async_evaluating_ordinal: uint32: 30 bit;
|
||||
}
|
||||
|
||||
@generateCppClass
|
||||
|
|
|
|||
11
deps/v8/test/mjsunit/harmony/modules-import-rqstd-order-async-subgraph.mjs
vendored
Normal file
11
deps/v8/test/mjsunit/harmony/modules-import-rqstd-order-async-subgraph.mjs
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
// 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
|
||||
|
||||
import "modules-skip-async-subgraph-start.mjs"
|
||||
|
||||
assertEquals(globalThis.test_order, [
|
||||
'async before', 'async after', '1', '2', 'x', 'start'
|
||||
]);
|
||||
12
deps/v8/test/mjsunit/harmony/modules-skip-async-subgraph-1.mjs
vendored
Normal file
12
deps/v8/test/mjsunit/harmony/modules-skip-async-subgraph-1.mjs
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
// 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
|
||||
|
||||
import "modules-skip-async-subgraph-async.mjs"
|
||||
|
||||
if (globalThis.test_order === undefined) {
|
||||
globalThis.test_order = [];
|
||||
}
|
||||
globalThis.test_order.push('1');
|
||||
12
deps/v8/test/mjsunit/harmony/modules-skip-async-subgraph-2.mjs
vendored
Normal file
12
deps/v8/test/mjsunit/harmony/modules-skip-async-subgraph-2.mjs
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
// 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
|
||||
|
||||
import "modules-skip-async-subgraph-async.mjs"
|
||||
|
||||
if (globalThis.test_order === undefined) {
|
||||
globalThis.test_order = [];
|
||||
}
|
||||
globalThis.test_order.push('2');
|
||||
12
deps/v8/test/mjsunit/harmony/modules-skip-async-subgraph-async.mjs
vendored
Normal file
12
deps/v8/test/mjsunit/harmony/modules-skip-async-subgraph-async.mjs
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
// 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
|
||||
|
||||
if (globalThis.test_order === undefined) {
|
||||
globalThis.test_order = [];
|
||||
}
|
||||
globalThis.test_order.push('async before');
|
||||
await 0;
|
||||
globalThis.test_order.push('async after');
|
||||
14
deps/v8/test/mjsunit/harmony/modules-skip-async-subgraph-start.mjs
vendored
Normal file
14
deps/v8/test/mjsunit/harmony/modules-skip-async-subgraph-start.mjs
vendored
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
// 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
|
||||
|
||||
import "modules-skip-async-subgraph-1.mjs"
|
||||
import "modules-skip-async-subgraph-2.mjs"
|
||||
import "modules-skip-async-subgraph-x.mjs"
|
||||
|
||||
if (globalThis.test_order === undefined) {
|
||||
globalThis.test_order = [];
|
||||
}
|
||||
globalThis.test_order.push('start');
|
||||
12
deps/v8/test/mjsunit/harmony/modules-skip-async-subgraph-x.mjs
vendored
Normal file
12
deps/v8/test/mjsunit/harmony/modules-skip-async-subgraph-x.mjs
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
// 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
|
||||
|
||||
import "modules-skip-async-subgraph-1.mjs"
|
||||
|
||||
if (globalThis.test_order === undefined) {
|
||||
globalThis.test_order = [];
|
||||
}
|
||||
globalThis.test_order.push('x');
|
||||
Loading…
Reference in New Issue
Block a user