Commit bb5c4b51 authored by Michael Lippautz's avatar Michael Lippautz Committed by V8 LUCI CQ

[handles, heap] Process young GlobalHandle nodes in GC

Young GlobalHandle nodes were processed during post processing which
required a logic to defend against recursive GCs. This was originally
designed in a delayed way as the list itself was only treated as an
optimization and could thus be lazily cleared.

Since this still happens in the atomic pause and every node needs to
be visited, there's no advantage over just keeping it correct at all
times.

Bug: chromium:1319213
Change-Id: I199fc0be5e4b6ed5cbb60cf3b1452e37108cd4f8
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3605281Reviewed-by: 's avatarDominik Inführ <dinfuehr@chromium.org>
Commit-Queue: Michael Lippautz <mlippautz@chromium.org>
Cr-Commit-Position: refs/heads/main@{#80161}
parent 69e7f230
......@@ -1304,23 +1304,24 @@ void GlobalHandles::InvokeSecondPassPhantomCallbacks() {
running_second_pass_callbacks_ = false;
}
namespace {
template <typename T>
void GlobalHandles::UpdateAndCompactListOfYoungNode(
std::vector<T*>* node_list) {
void UpdateListOfYoungNodesImpl(Isolate* isolate, std::vector<T*>* node_list) {
size_t last = 0;
for (T* node : *node_list) {
DCHECK(node->is_in_young_list());
if (node->IsInUse()) {
if (node->IsInUse() && node->state() != T::NEAR_DEATH) {
if (ObjectInYoungGeneration(node->object())) {
(*node_list)[last++] = node;
isolate_->heap()->IncrementNodesCopiedInNewSpace();
isolate->heap()->IncrementNodesCopiedInNewSpace();
} else {
node->set_in_young_list(false);
isolate_->heap()->IncrementNodesPromoted();
isolate->heap()->IncrementNodesPromoted();
}
} else {
node->set_in_young_list(false);
isolate_->heap()->IncrementNodesDiedInNewSpace();
isolate->heap()->IncrementNodesDiedInNewSpace(1);
}
}
DCHECK_LE(last, node_list->size());
......@@ -1328,9 +1329,30 @@ void GlobalHandles::UpdateAndCompactListOfYoungNode(
node_list->shrink_to_fit();
}
template <typename T>
void ClearListOfYoungNodesImpl(Isolate* isolate, std::vector<T*>* node_list) {
for (T* node : *node_list) {
DCHECK(node->is_in_young_list());
node->set_in_young_list(false);
DCHECK_IMPLIES(node->IsInUse() && node->state() != T::NEAR_DEATH,
!ObjectInYoungGeneration(node->object()));
}
isolate->heap()->IncrementNodesDiedInNewSpace(
static_cast<int>(node_list->size()));
node_list->clear();
node_list->shrink_to_fit();
}
} // namespace
void GlobalHandles::UpdateListOfYoungNodes() {
UpdateAndCompactListOfYoungNode(&young_nodes_);
UpdateAndCompactListOfYoungNode(&traced_young_nodes_);
UpdateListOfYoungNodesImpl(isolate_, &young_nodes_);
UpdateListOfYoungNodesImpl(isolate_, &traced_young_nodes_);
}
void GlobalHandles::ClearListOfYoungNodes() {
ClearListOfYoungNodesImpl(isolate_, &young_nodes_);
ClearListOfYoungNodesImpl(isolate_, &traced_young_nodes_);
}
template <typename T>
......@@ -1399,26 +1421,18 @@ void GlobalHandles::PendingPhantomCallback::Invoke(Isolate* isolate,
callback(data);
}
bool GlobalHandles::InRecursiveGC(unsigned gc_processing_counter) {
return gc_processing_counter != post_gc_processing_count_;
}
void GlobalHandles::PostGarbageCollectionProcessing(
GarbageCollector collector, const v8::GCCallbackFlags gc_callback_flags) {
// Process weak global handle callbacks. This must be done after the
// GC is completely done, because the callbacks may invoke arbitrary
// API functions.
DCHECK_EQ(Heap::NOT_IN_GC, isolate_->heap()->gc_state());
const unsigned post_processing_count = ++post_gc_processing_count_;
bool synchronous_second_pass =
const bool synchronous_second_pass =
isolate_->heap()->IsTearingDown() ||
(gc_callback_flags &
(kGCCallbackFlagForced | kGCCallbackFlagCollectAllAvailableGarbage |
kGCCallbackFlagSynchronousPhantomCallbackProcessing)) != 0;
InvokeOrScheduleSecondPassPhantomCallbacks(synchronous_second_pass);
if (InRecursiveGC(post_processing_count)) return;
UpdateListOfYoungNodes();
}
void GlobalHandles::IterateStrongRoots(RootVisitor* v) {
......
......@@ -149,6 +149,12 @@ class V8_EXPORT_PRIVATE GlobalHandles final {
void ProcessWeakYoungObjects(RootVisitor* v,
WeakSlotCallbackWithHeap should_reset_handle);
// Updates the list of young nodes that is maintained separately.
void UpdateListOfYoungNodes();
// Clears the list of young nodes, assuming that the young generation is
// empty.
void ClearListOfYoungNodes();
// Computes whether young weak objects should be considered roots for young
// generation garbage collections or just be treated weakly. Per default
// objects are considered as roots. Objects are treated not as root when both
......@@ -193,8 +199,6 @@ class V8_EXPORT_PRIVATE GlobalHandles final {
static GlobalHandles* From(const TracedNode*);
bool InRecursiveGC(unsigned gc_processing_counter);
void InvokeSecondPassPhantomCallbacksFromTask();
void InvokeOrScheduleSecondPassPhantomCallbacks(bool synchronous_second_pass);
......@@ -202,10 +206,6 @@ class V8_EXPORT_PRIVATE GlobalHandles final {
size_t InvokeFirstPassWeakCallbacks(
std::vector<std::pair<T*, PendingPhantomCallback>>* pending);
template <typename T>
void UpdateAndCompactListOfYoungNode(std::vector<T*>* node_list);
void UpdateListOfYoungNodes();
void ApplyPersistentHandleVisitor(v8::PersistentHandleVisitor* visitor,
Node* node);
......@@ -237,9 +237,6 @@ class V8_EXPORT_PRIVATE GlobalHandles final {
std::vector<PendingPhantomCallback> second_pass_callbacks_;
bool second_pass_callbacks_task_posted_ = false;
bool running_second_pass_callbacks_ = false;
// Counter for recursive garbage collections during callback processing.
unsigned post_gc_processing_count_ = 0;
};
class GlobalHandles::PendingPhantomCallback final {
......
......@@ -1367,7 +1367,9 @@ class Heap {
return promoted_objects_size_ + semi_space_copied_object_size_;
}
inline void IncrementNodesDiedInNewSpace() { nodes_died_in_new_space_++; }
inline void IncrementNodesDiedInNewSpace(int count) {
nodes_died_in_new_space_ += count;
}
inline void IncrementNodesCopiedInNewSpace() { nodes_copied_in_new_space_++; }
......
......@@ -1050,6 +1050,8 @@ void MarkCompactCollector::VerifyMarking() {
void MarkCompactCollector::Finish() {
TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_FINISH);
heap()->isolate()->global_handles()->ClearListOfYoungNodes();
SweepArrayBufferExtensions();
#ifdef DEBUG
......@@ -5420,6 +5422,8 @@ void MinorMarkCompactCollector::CollectGarbage() {
CleanupPromotedPages();
SweepArrayBufferExtensions();
heap()->isolate()->global_handles()->UpdateListOfYoungNodes();
}
void MinorMarkCompactCollector::MakeIterable(
......
......@@ -446,6 +446,8 @@ void ScavengerCollector::CollectGarbage() {
SweepArrayBufferExtensions();
}
isolate_->global_handles()->UpdateListOfYoungNodes();
// Update how much has survived scavenge.
heap_->IncrementYoungSurvivorsCounter(heap_->SurvivedYoungObjectSize());
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment