diff --git a/deps/v8/OWNERS b/deps/v8/OWNERS index f9b23f237f546e..4fcf830fcc2a30 100644 --- a/deps/v8/OWNERS +++ b/deps/v8/OWNERS @@ -27,6 +27,10 @@ per-file codereview.settings=file:INFRA_OWNERS per-file AUTHORS=file:COMMON_OWNERS per-file WATCHLISTS=file:COMMON_OWNERS +# Needed by the auto_tag builder +per-file WATCHLISTS=v8-ci-autoroll-builder@chops-service-accounts.iam.gserviceaccount.com +per-file DEPS=v8-ci-autoroll-builder@chops-service-accounts.iam.gserviceaccount.com + per-file ...-mips*=file:MIPS_OWNERS per-file ...-mips64*=file:MIPS_OWNERS per-file ...-ppc*=file:PPC_OWNERS diff --git a/deps/v8/include/OWNERS b/deps/v8/include/OWNERS index d85849d52a1219..0222513df26cd0 100644 --- a/deps/v8/include/OWNERS +++ b/deps/v8/include/OWNERS @@ -11,6 +11,9 @@ per-file v8-inspector.h=file:../src/inspector/OWNERS per-file v8-inspector-protocol.h=file:../src/inspector/OWNERS per-file js_protocol.pdl=file:../src/inspector/OWNERS +# Needed by the auto_tag builder +per-file v8-version.h=v8-ci-autoroll-builder@chops-service-accounts.iam.gserviceaccount.com + # For branch updates: per-file v8-version.h=file:../INFRA_OWNERS per-file v8-version.h=hablich@chromium.org diff --git a/deps/v8/include/v8-version.h b/deps/v8/include/v8-version.h index 2a87785209c619..a4ef2015e02a3d 100644 --- a/deps/v8/include/v8-version.h +++ b/deps/v8/include/v8-version.h @@ -11,7 +11,7 @@ #define V8_MAJOR_VERSION 9 #define V8_MINOR_VERSION 4 #define V8_BUILD_NUMBER 146 -#define V8_PATCH_LEVEL 19 +#define V8_PATCH_LEVEL 24 // Use 1 for candidates and 0 otherwise. // (Boolean macro values are not supported by all preprocessors.) diff --git a/deps/v8/src/execution/isolate-inl.h b/deps/v8/src/execution/isolate-inl.h index 63f9ea5947c904..48950b673f2227 100644 --- a/deps/v8/src/execution/isolate-inl.h +++ b/deps/v8/src/execution/isolate-inl.h @@ -50,7 +50,7 @@ bool Isolate::has_pending_message() { } Object Isolate::pending_exception() { - DCHECK(has_pending_exception()); + CHECK(has_pending_exception()); DCHECK(!thread_local_top()->pending_exception_.IsException(this)); return thread_local_top()->pending_exception_; } diff --git a/deps/v8/src/heap/cppgc/marker.cc b/deps/v8/src/heap/cppgc/marker.cc index 549a9fe1da8f89..0e5d9ec8f1e2f9 100644 --- a/deps/v8/src/heap/cppgc/marker.cc +++ b/deps/v8/src/heap/cppgc/marker.cc @@ -243,6 +243,7 @@ void MarkerBase::EnterAtomicPause(MarkingConfig::StackState stack_state) { } config_.stack_state = stack_state; config_.marking_type = MarkingConfig::MarkingType::kAtomic; + mutator_marking_state_.set_in_atomic_pause(); // Lock guards against changes to {Weak}CrossThreadPersistent handles, that // may conflict with marking. E.g., a WeakCrossThreadPersistent may be @@ -421,7 +422,9 @@ bool MarkerBase::ProcessWorklistsWithDeadline( size_t marked_bytes_deadline, v8::base::TimeTicks time_deadline) { StatsCollector::EnabledScope stats_scope( heap().stats_collector(), StatsCollector::kMarkTransitiveClosure); + bool saved_did_discover_new_ephemeron_pairs; do { + mutator_marking_state_.ResetDidDiscoverNewEphemeronPairs(); if ((config_.marking_type == MarkingConfig::MarkingType::kAtomic) || schedule_.ShouldFlushEphemeronPairs()) { mutator_marking_state_.FlushDiscoveredEphemeronPairs(); @@ -509,6 +512,8 @@ bool MarkerBase::ProcessWorklistsWithDeadline( } } + saved_did_discover_new_ephemeron_pairs = + mutator_marking_state_.DidDiscoverNewEphemeronPairs(); { StatsCollector::EnabledScope stats_scope( heap().stats_collector(), StatsCollector::kMarkProcessEphemerons); @@ -522,7 +527,8 @@ bool MarkerBase::ProcessWorklistsWithDeadline( return false; } } - } while (!mutator_marking_state_.marking_worklist().IsLocalAndGlobalEmpty()); + } while (!mutator_marking_state_.marking_worklist().IsLocalAndGlobalEmpty() || + saved_did_discover_new_ephemeron_pairs); return true; } diff --git a/deps/v8/src/heap/cppgc/marking-state.h b/deps/v8/src/heap/cppgc/marking-state.h index 17e64e6fbef2e2..5f6f0aba3720ea 100644 --- a/deps/v8/src/heap/cppgc/marking-state.h +++ b/deps/v8/src/heap/cppgc/marking-state.h @@ -9,6 +9,7 @@ #include "include/cppgc/trace-trait.h" #include "include/cppgc/visitor.h" +#include "src/base/logging.h" #include "src/heap/cppgc/compaction-worklists.h" #include "src/heap/cppgc/globals.h" #include "src/heap/cppgc/heap-object-header.h" @@ -115,6 +116,16 @@ class MarkingStateBase { movable_slots_worklist_.reset(); } + bool DidDiscoverNewEphemeronPairs() const { + return discovered_new_ephemeron_pairs_; + } + + void ResetDidDiscoverNewEphemeronPairs() { + discovered_new_ephemeron_pairs_ = false; + } + + void set_in_atomic_pause() { in_atomic_pause_ = true; } + protected: inline void MarkAndPush(HeapObjectHeader&, TraceDescriptor); @@ -150,6 +161,9 @@ class MarkingStateBase { movable_slots_worklist_; size_t marked_bytes_ = 0; + bool in_ephemeron_processing_ = false; + bool discovered_new_ephemeron_pairs_ = false; + bool in_atomic_pause_ = false; }; MarkingStateBase::MarkingStateBase(HeapBase& heap, @@ -286,10 +300,23 @@ void MarkingStateBase::ProcessWeakContainer(const void* object, void MarkingStateBase::ProcessEphemeron(const void* key, const void* value, TraceDescriptor value_desc, Visitor& visitor) { - // Filter out already marked keys. The write barrier for WeakMember - // ensures that any newly set value after this point is kept alive and does - // not require the callback. - if (HeapObjectHeader::FromObject(key).IsMarked()) { + // ProcessEphemeron is not expected to find new ephemerons recursively, which + // would break the main marking loop. + DCHECK(!in_ephemeron_processing_); + in_ephemeron_processing_ = true; + // Keys are considered live even in incremental/concurrent marking settings + // because the write barrier for WeakMember ensures that any newly set value + // after this point is kept alive and does not require the callback. + const bool key_in_construction = + HeapObjectHeader::FromObject(key).IsInConstruction(); + const bool key_considered_as_live = + key_in_construction + ? in_atomic_pause_ + : HeapObjectHeader::FromObject(key).IsMarked(); + DCHECK_IMPLIES( + key_in_construction && in_atomic_pause_, + HeapObjectHeader::FromObject(key).IsMarked()); + if (key_considered_as_live) { if (value_desc.base_object_payload) { MarkAndPush(value_desc.base_object_payload, value_desc); } else { @@ -297,9 +324,11 @@ void MarkingStateBase::ProcessEphemeron(const void* key, const void* value, // should be immediately traced. value_desc.callback(&visitor, value); } - return; + } else { + discovered_ephemeron_pairs_worklist_.Push({key, value, value_desc}); + discovered_new_ephemeron_pairs_ = true; } - discovered_ephemeron_pairs_worklist_.Push({key, value, value_desc}); + in_ephemeron_processing_ = false; } void MarkingStateBase::AccountMarkedBytes(const HeapObjectHeader& header) { diff --git a/deps/v8/src/ic/accessor-assembler.cc b/deps/v8/src/ic/accessor-assembler.cc index 64d64cd017c354..f27e3b7f590a76 100644 --- a/deps/v8/src/ic/accessor-assembler.cc +++ b/deps/v8/src/ic/accessor-assembler.cc @@ -846,8 +846,8 @@ void AccessorAssembler::HandleLoadICSmiHandlerLoadNamedCase( Comment("module export"); TNode index = DecodeWord(handler_word); - TNode module = LoadObjectField( - CAST(p->receiver()), JSModuleNamespace::kModuleOffset); + TNode module = + LoadObjectField(CAST(holder), JSModuleNamespace::kModuleOffset); TNode exports = LoadObjectField(module, Module::kExportsOffset); TNode cell = CAST(LoadFixedArrayElement(exports, index)); diff --git a/deps/v8/src/ic/ic.cc b/deps/v8/src/ic/ic.cc index a2b920a09d1bc7..68eee92cef8335 100644 --- a/deps/v8/src/ic/ic.cc +++ b/deps/v8/src/ic/ic.cc @@ -989,7 +989,13 @@ Handle LoadIC::ComputeHandler(LookupIterator* lookup) { // We found the accessor, so the entry must exist. DCHECK(entry.is_found()); int index = ObjectHashTable::EntryToValueIndex(entry); - return LoadHandler::LoadModuleExport(isolate(), index); + Handle smi_handler = + LoadHandler::LoadModuleExport(isolate(), index); + if (holder_is_lookup_start_object) { + return smi_handler; + } + return LoadHandler::LoadFromPrototype(isolate(), map, holder, + smi_handler); } Handle accessors = lookup->GetAccessors(); diff --git a/deps/v8/src/wasm/module-compiler.cc b/deps/v8/src/wasm/module-compiler.cc index 590c0862bcd1eb..223f51ba14587d 100644 --- a/deps/v8/src/wasm/module-compiler.cc +++ b/deps/v8/src/wasm/module-compiler.cc @@ -3052,13 +3052,13 @@ void CompilationStateImpl::InitializeCompilationProgressAfterDeserialization( } compilation_progress_.assign(module->num_declared_functions, kProgressAfterDeserialization); - uint32_t num_imported_functions = module->num_imported_functions; for (auto func_index : missing_functions) { if (FLAG_wasm_lazy_compilation) { - native_module_->UseLazyStub(num_imported_functions + func_index); + native_module_->UseLazyStub(func_index); } - compilation_progress_[func_index] = SetupCompilationProgressForFunction( - lazy_module, module, enabled_features, func_index); + compilation_progress_[declared_function_index(module, func_index)] = + SetupCompilationProgressForFunction(lazy_module, module, + enabled_features, func_index); } } auto builder = std::make_unique(native_module_); diff --git a/deps/v8/test/mjsunit/wasm/test-serialization-with-lazy-compilation.js b/deps/v8/test/mjsunit/wasm/test-serialization-with-lazy-compilation.js index ad1d54a5942d67..95884c32f6a562 100644 --- a/deps/v8/test/mjsunit/wasm/test-serialization-with-lazy-compilation.js +++ b/deps/v8/test/mjsunit/wasm/test-serialization-with-lazy-compilation.js @@ -10,6 +10,7 @@ const num_functions = 2; function create_builder() { const builder = new WasmModuleBuilder(); + builder.addImport("foo", "bar", kSig_i_v); for (let i = 0; i < num_functions; ++i) { builder.addFunction('f' + i, kSig_i_v) .addBody(wasmI32Const(i)) @@ -37,7 +38,7 @@ gc(); print(arguments.callee.name); const module = %DeserializeWasmModule(serialized_module, wire_bytes); - const instance = new WebAssembly.Instance(module); + const instance = new WebAssembly.Instance(module, {foo: {bar: () => 1}}); assertEquals(0, instance.exports.f0()); assertEquals(1, instance.exports.f1()); })(); diff --git a/deps/v8/test/unittests/heap/cppgc/ephemeron-pair-unittest.cc b/deps/v8/test/unittests/heap/cppgc/ephemeron-pair-unittest.cc index 534f744e7ee1ad..b349b591cac540 100644 --- a/deps/v8/test/unittests/heap/cppgc/ephemeron-pair-unittest.cc +++ b/deps/v8/test/unittests/heap/cppgc/ephemeron-pair-unittest.cc @@ -242,5 +242,50 @@ TEST_F(EphemeronPairTest, EphemeronPairWithEmptyMixinValue) { FinishMarking(); } +namespace { + +class KeyWithCallback final : public GarbageCollected { + public: + template + explicit KeyWithCallback(Callback callback) { + callback(this); + } + void Trace(Visitor*) const {} +}; + +class EphemeronHolderForKeyWithCallback final + : public GarbageCollected { + public: + EphemeronHolderForKeyWithCallback(KeyWithCallback* key, GCed* value) + : ephemeron_pair_(key, value) {} + void Trace(cppgc::Visitor* visitor) const { visitor->Trace(ephemeron_pair_); } + + private: + const EphemeronPair ephemeron_pair_; +}; + +} // namespace + +TEST_F(EphemeronPairTest, EphemeronPairWithKeyInConstruction) { + GCed* value = MakeGarbageCollected(GetAllocationHandle()); + Persistent holder; + InitializeMarker(*Heap::From(GetHeap()), GetPlatformHandle().get()); + FinishSteps(); + MakeGarbageCollected( + GetAllocationHandle(), [this, &holder, value](KeyWithCallback* thiz) { + // The test doesn't use conservative stack scanning to retain key to + // avoid retaining value as a side effect. + EXPECT_TRUE(HeapObjectHeader::FromObject(thiz).TryMarkAtomic()); + holder = MakeGarbageCollected( + GetAllocationHandle(), thiz, value); + // Finishing marking at this point will leave an ephemeron pair + // reachable where the key is still in construction. The GC needs to + // mark the value for such pairs as live in the atomic pause as they key + // is considered live. + FinishMarking(); + }); + EXPECT_TRUE(HeapObjectHeader::FromObject(value).IsMarked()); +} + } // namespace internal } // namespace cppgc diff --git a/deps/v8/test/unittests/heap/cppgc/marker-unittest.cc b/deps/v8/test/unittests/heap/cppgc/marker-unittest.cc index f96e5f4a25fc97..5ed46857c8e3aa 100644 --- a/deps/v8/test/unittests/heap/cppgc/marker-unittest.cc +++ b/deps/v8/test/unittests/heap/cppgc/marker-unittest.cc @@ -7,12 +7,14 @@ #include #include "include/cppgc/allocation.h" +#include "include/cppgc/ephemeron-pair.h" #include "include/cppgc/internal/pointer-policies.h" #include "include/cppgc/member.h" #include "include/cppgc/persistent.h" #include "include/cppgc/trace-trait.h" #include "src/heap/cppgc/heap-object-header.h" #include "src/heap/cppgc/marking-visitor.h" +#include "src/heap/cppgc/object-allocator.h" #include "src/heap/cppgc/stats-collector.h" #include "test/unittests/heap/cppgc/tests.h" #include "testing/gtest/include/gtest/gtest.h" @@ -44,6 +46,8 @@ class MarkerTest : public testing::TestWithHeap { Marker* marker() const { return marker_.get(); } + void ResetMarker() { marker_.reset(); } + private: std::unique_ptr marker_; }; @@ -346,6 +350,50 @@ TEST_F(MarkerTest, SentinelNotClearedOnWeakPersistentHandling) { EXPECT_EQ(kSentinelPointer, root->weak_child()); } +namespace { + +class SimpleObject final : public GarbageCollected { + public: + void Trace(Visitor*) const {} +}; + +class ObjectWithEphemeronPair final + : public GarbageCollected { + public: + explicit ObjectWithEphemeronPair(AllocationHandle& handle) + : ephemeron_pair_(MakeGarbageCollected(handle), + MakeGarbageCollected(handle)) {} + + void Trace(Visitor* visitor) const { + // First trace the ephemeron pair. The key is not yet marked as live, so the + // pair should be recorded for later processing. Then strongly mark the key. + // Marking the key will not trigger another worklist processing iteration, + // as it merely continues the same loop for regular objects and will leave + // the main marking worklist empty. If recording the ephemeron pair doesn't + // as well, we will get a crash when destroying the marker. + visitor->Trace(ephemeron_pair_); + visitor->Trace(const_cast(ephemeron_pair_.key.Get())); + } + + private: + const EphemeronPair ephemeron_pair_; +}; + +} // namespace + +TEST_F(MarkerTest, MarkerProcessesAllEphemeronPairs) { + static const Marker::MarkingConfig config = { + MarkingConfig::CollectionType::kMajor, + MarkingConfig::StackState::kNoHeapPointers, + MarkingConfig::MarkingType::kAtomic}; + Persistent obj = + MakeGarbageCollected(GetAllocationHandle(), + GetAllocationHandle()); + InitializeMarker(*Heap::From(GetHeap()), GetPlatformHandle().get(), config); + marker()->FinishMarking(MarkingConfig::StackState::kNoHeapPointers); + ResetMarker(); +} + // Incremental Marking class IncrementalMarkingTest : public testing::TestWithHeap {