Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[v14.x] deps: V8 parent ordering fix backport #37973

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion common.gypi
Expand Up @@ -36,7 +36,7 @@

# Reset this number to 0 on major V8 upgrades.
# Increment by one for each non-official patch applied to deps/v8.
'v8_embedder_string': '-node.20',
'v8_embedder_string': '-node.22',

##### V8 defaults for Node.js #####

Expand Down
3 changes: 3 additions & 0 deletions deps/v8/src/common/globals.h
Expand Up @@ -334,6 +334,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))

Expand Down
3 changes: 2 additions & 1 deletion deps/v8/src/diagnostics/objects-debug.cc
Expand Up @@ -1351,7 +1351,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());
Expand Down
1 change: 1 addition & 0 deletions deps/v8/src/diagnostics/objects-printer.cc
Expand Up @@ -1622,6 +1622,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";
}

Expand Down
31 changes: 31 additions & 0 deletions deps/v8/src/execution/isolate-inl.h
Expand Up @@ -12,6 +12,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 {
Expand Down Expand Up @@ -117,6 +118,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); \
Expand Down
3 changes: 3 additions & 0 deletions deps/v8/src/execution/isolate.cc
Expand Up @@ -66,6 +66,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"
Expand Down Expand Up @@ -2792,6 +2793,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();
Expand Down
18 changes: 18 additions & 0 deletions deps/v8/src/execution/isolate.h
Expand Up @@ -1264,6 +1264,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);
Expand Down Expand Up @@ -1788,6 +1804,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_;

Expand Down
2 changes: 1 addition & 1 deletion deps/v8/src/heap/factory.cc
Expand Up @@ -2485,7 +2485,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);
Expand Down
9 changes: 7 additions & 2 deletions deps/v8/src/objects/module-inl.h
Expand Up @@ -36,8 +36,9 @@ ACCESSORS(Module, exception, Object, kExceptionOffset)
SMI_ACCESSORS(Module, status, kStatusOffset)
SMI_ACCESSORS(Module, hash, kHashOffset)

BOOL_ACCESSORS(SourceTextModule, flags, async, kAsyncBit)
BOOL_ACCESSORS(SourceTextModule, flags, async_evaluating, kAsyncEvaluatingBit)
BOOL_ACCESSORS(SourceTextModule, flags, async, AsyncBit::kShift)
BIT_FIELD_ACCESSORS(SourceTextModule, flags, async_evaluating_ordinal,
SourceTextModule::AsyncEvaluatingOrdinalBits)
ACCESSORS(SourceTextModule, async_parent_modules, ArrayList,
kAsyncParentModulesOffset)
ACCESSORS(SourceTextModule, top_level_capability, HeapObject,
Expand Down Expand Up @@ -140,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;
Expand Down