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

[heap] Run cleaning of string table in parallel to other cleaning

Bug: v8:12813
Change-Id: I27bbf5190165a0d919f021bbcf089e203dfed83f
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3592955Reviewed-by: 's avatarDominik Inführ <dinfuehr@chromium.org>
Commit-Queue: Michael Lippautz <mlippautz@chromium.org>
Cr-Commit-Position: refs/heads/main@{#80072}
parent d0c147ab
......@@ -908,13 +908,14 @@ void GCTracer::PrintNVP() const {
"heap.external.epilogue=%.1f "
"heap.external.weak_global_handles=%.1f "
"clear=%1.f "
"clear.external_string_table=%.1f "
"clear.dependent_code=%.1f "
"clear.maps=%.1f "
"clear.slots_buffer=%.1f "
"clear.string_table=%.1f "
"clear.weak_collections=%.1f "
"clear.weak_lists=%.1f "
"clear.weak_references=%.1f "
"clear.join_job=%.1f "
"complete.sweep_array_buffers=%.1f "
"epilogue=%.1f "
"evacuate=%.1f "
......@@ -998,13 +999,14 @@ void GCTracer::PrintNVP() const {
current_scope(Scope::HEAP_EXTERNAL_EPILOGUE),
current_scope(Scope::HEAP_EXTERNAL_WEAK_GLOBAL_HANDLES),
current_scope(Scope::MC_CLEAR),
current_scope(Scope::MC_CLEAR_EXTERNAL_STRING_TABLE),
current_scope(Scope::MC_CLEAR_DEPENDENT_CODE),
current_scope(Scope::MC_CLEAR_MAPS),
current_scope(Scope::MC_CLEAR_SLOTS_BUFFER),
current_scope(Scope::MC_CLEAR_STRING_TABLE),
current_scope(Scope::MC_CLEAR_WEAK_COLLECTIONS),
current_scope(Scope::MC_CLEAR_WEAK_LISTS),
current_scope(Scope::MC_CLEAR_WEAK_REFERENCES),
current_scope(Scope::MC_CLEAR_JOIN_JOB),
current_scope(Scope::MC_COMPLETE_SWEEP_ARRAY_BUFFERS),
current_scope(Scope::MC_EPILOGUE), current_scope(Scope::MC_EVACUATE),
current_scope(Scope::MC_EVACUATE_CANDIDATES),
......
......@@ -4,6 +4,7 @@
#include "src/heap/mark-compact.h"
#include <memory>
#include <unordered_map>
#include <unordered_set>
......@@ -1314,10 +1315,9 @@ class MarkCompactCollector::SharedHeapObjectVisitor final
MarkCompactCollector* const collector_;
};
class InternalizedStringTableCleaner : public RootVisitor {
class InternalizedStringTableCleaner final : public RootVisitor {
public:
explicit InternalizedStringTableCleaner(Heap* heap)
: heap_(heap), pointers_removed_(0) {}
explicit InternalizedStringTableCleaner(Heap* heap) : heap_(heap) {}
void VisitRootPointers(Root root, const char* description,
FullObjectSlot start, FullObjectSlot end) override {
......@@ -1329,8 +1329,7 @@ class InternalizedStringTableCleaner : public RootVisitor {
OffHeapObjectSlot end) override {
DCHECK_EQ(root, Root::kStringTable);
// Visit all HeapObject pointers in [start, end).
MarkCompactCollector::NonAtomicMarkingState* marking_state =
heap_->mark_compact_collector()->non_atomic_marking_state();
auto* marking_state = heap_->mark_compact_collector()->marking_state();
Isolate* isolate = heap_->isolate();
for (OffHeapObjectSlot p = start; p < end; ++p) {
Object o = p.load(isolate);
......@@ -1346,11 +1345,11 @@ class InternalizedStringTableCleaner : public RootVisitor {
}
}
int PointersRemoved() { return pointers_removed_; }
int PointersRemoved() const { return pointers_removed_; }
private:
Heap* heap_;
int pointers_removed_;
int pointers_removed_ = 0;
};
class ExternalStringTableCleaner : public RootVisitor {
......@@ -1390,7 +1389,7 @@ class ExternalStringTableCleaner : public RootVisitor {
class MarkCompactWeakObjectRetainer : public WeakObjectRetainer {
public:
explicit MarkCompactWeakObjectRetainer(
MarkCompactCollector::NonAtomicMarkingState* marking_state)
MarkCompactCollector::MarkingState* marking_state)
: marking_state_(marking_state) {}
Object RetainAs(Object object) override {
......@@ -1420,7 +1419,7 @@ class MarkCompactWeakObjectRetainer : public WeakObjectRetainer {
}
private:
MarkCompactCollector::NonAtomicMarkingState* marking_state_;
MarkCompactCollector::MarkingState* const marking_state_;
};
class RecordMigratedSlotVisitor : public ObjectVisitorWithCageBases {
......@@ -2495,31 +2494,94 @@ void MarkCompactCollector::MarkLiveObjects() {
epoch_++;
}
namespace {
class ParallelClearingJob final : public v8::JobTask {
public:
class ClearingItem {
public:
virtual ~ClearingItem() = default;
virtual void Run(JobDelegate* delegate) = 0;
};
ParallelClearingJob() = default;
~ParallelClearingJob() override = default;
ParallelClearingJob(const ParallelClearingJob&) = delete;
ParallelClearingJob& operator=(const ParallelClearingJob&) = delete;
// v8::JobTask overrides.
void Run(JobDelegate* delegate) override {
std::unique_ptr<ClearingItem> item;
{
base::MutexGuard guard(&items_mutex_);
item = std::move(items_.back());
items_.pop_back();
}
item->Run(delegate);
}
size_t GetMaxConcurrency(size_t worker_count) const override {
base::MutexGuard guard(&items_mutex_);
return items_.size();
}
void Add(std::unique_ptr<ClearingItem> item) {
items_.push_back(std::move(item));
}
private:
mutable base::Mutex items_mutex_;
std::vector<std::unique_ptr<ClearingItem>> items_;
};
class ClearStringTableJobItem final : public ParallelClearingJob::ClearingItem {
public:
explicit ClearStringTableJobItem(Isolate* isolate) : isolate_(isolate) {}
void Run(JobDelegate* delegate) final {
if (isolate_->OwnsStringTable()) {
TRACE_GC1(isolate_->heap()->tracer(),
GCTracer::Scope::MC_CLEAR_STRING_TABLE,
delegate->IsJoiningThread() ? ThreadKind::kMain
: ThreadKind::kBackground);
// Prune the string table removing all strings only pointed to by the
// string table. Cannot use string_table() here because the string
// table is marked.
StringTable* string_table = isolate_->string_table();
InternalizedStringTableCleaner internalized_visitor(isolate_->heap());
string_table->DropOldData();
string_table->IterateElements(&internalized_visitor);
string_table->NotifyElementsRemoved(
internalized_visitor.PointersRemoved());
}
}
private:
Isolate* const isolate_;
};
} // namespace
void MarkCompactCollector::ClearNonLiveReferences() {
TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_CLEAR);
if (isolate()->OwnsStringTable()) {
TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_CLEAR_STRING_TABLE);
auto clearing_job = std::make_unique<ParallelClearingJob>();
clearing_job->Add(std::make_unique<ClearStringTableJobItem>(isolate()));
auto clearing_job_handle = V8::GetCurrentPlatform()->PostJob(
TaskPriority::kUserBlocking, std::move(clearing_job));
// Prune the string table removing all strings only pointed to by the
// string table. Cannot use string_table() here because the string
// table is marked.
StringTable* string_table = isolate()->string_table();
InternalizedStringTableCleaner internalized_visitor(heap());
string_table->DropOldData();
string_table->IterateElements(&internalized_visitor);
string_table->NotifyElementsRemoved(internalized_visitor.PointersRemoved());
{
TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_CLEAR_EXTERNAL_STRING_TABLE);
ExternalStringTableCleaner external_visitor(heap());
heap()->external_string_table_.IterateAll(&external_visitor);
heap()->external_string_table_.CleanUpAll();
}
ExternalStringTableCleaner external_visitor(heap());
heap()->external_string_table_.IterateAll(&external_visitor);
heap()->external_string_table_.CleanUpAll();
{
TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_CLEAR_FLUSHABLE_BYTECODE);
// ProcessFlusheBaselineCandidates should be called after clearing bytecode
// so that we flush any bytecode if needed so we could correctly set the
// code object on the JSFunction.
// `ProcessFlusheBaselineCandidates()` must be called after
// `ProcessOldCodeCandidates()` so that we correctly set the code object on
// the JSFunction after flushing.
ProcessOldCodeCandidates();
ProcessFlushedBaselineCandidates();
}
......@@ -2532,8 +2594,7 @@ void MarkCompactCollector::ClearNonLiveReferences() {
{
TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_CLEAR_WEAK_LISTS);
// Process the weak references.
MarkCompactWeakObjectRetainer mark_compact_object_retainer(
non_atomic_marking_state());
MarkCompactWeakObjectRetainer mark_compact_object_retainer(marking_state());
heap()->ProcessAllWeakReferences(&mark_compact_object_retainer);
}
......@@ -2562,6 +2623,11 @@ void MarkCompactCollector::ClearNonLiveReferences() {
}
#endif // V8_SANDBOXED_EXTERNAL_POINTERS
{
TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_CLEAR_JOIN_JOB);
clearing_job_handle->Join();
}
DCHECK(weak_objects_.transition_arrays.IsEmpty());
DCHECK(weak_objects_.weak_references.IsEmpty());
DCHECK(weak_objects_.weak_objects_in_code.IsEmpty());
......@@ -2676,8 +2742,8 @@ void MarkCompactCollector::FlushBytecodeFromSFI(
// Mark the uncompiled data as black, and ensure all fields have already been
// marked.
DCHECK(non_atomic_marking_state()->IsBlackOrGrey(inferred_name));
non_atomic_marking_state()->WhiteToBlack(uncompiled_data);
DCHECK(marking_state()->IsBlackOrGrey(inferred_name));
marking_state()->WhiteToBlack(uncompiled_data);
// Use the raw function data setter to avoid validity checks, since we're
// performing the unusual task of decompiling.
......
......@@ -535,8 +535,10 @@
F(MARK_COMPACTOR) \
TOP_MC_SCOPES(F) \
F(MC_CLEAR_DEPENDENT_CODE) \
F(MC_CLEAR_EXTERNAL_STRING_TABLE) \
F(MC_CLEAR_FLUSHABLE_BYTECODE) \
F(MC_CLEAR_FLUSHED_JS_FUNCTIONS) \
F(MC_CLEAR_JOIN_JOB) \
F(MC_CLEAR_MAPS) \
F(MC_CLEAR_SLOTS_BUFFER) \
F(MC_CLEAR_STRING_TABLE) \
......
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