[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/+/3592955 Reviewed-by: Dominik Inführ <dinfuehr@chromium.org> Commit-Queue: Michael Lippautz <mlippautz@chromium.org> Cr-Commit-Position: refs/heads/main@{#80072}
This commit is contained in:
parent
d0c147ab10
commit
7a96ceccb8
@ -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) \
|
||||
|
Loading…
Reference in New Issue
Block a user