Commit 2d1727f5 authored by Michael Lippautz's avatar Michael Lippautz Committed by Commit Bot

heap: Rework ephemeron trace traits and heap snapshot

This patch unifies weak and strong handling of ephemerons and adds support for
"reverse" ephemerons (strong key w/ weak value) to the heap snapshot.

It also removes dependencies on Trait::kWeakHandlingFlag in ephemeron tracing.

Bug: 1019191
Change-Id: Ic3429a6fb45663ab7fe3c59790a72384066a1892
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1897834
Commit-Queue: Michael Lippautz <mlippautz@chromium.org>
Reviewed-by: default avatarOmer Katz <omerkatz@chromium.org>
Reviewed-by: default avatarKentaro Hara <haraken@chromium.org>
Cr-Commit-Position: refs/heads/master@{#712628}
parent 6d423ab2
...@@ -348,18 +348,20 @@ class GC_PLUGIN_IGNORE( ...@@ -348,18 +348,20 @@ class GC_PLUGIN_IGNORE(
key_tracing_callback_(key_tracing_callback), key_tracing_callback_(key_tracing_callback),
value_tracing_callback_(value_tracing_callback) {} value_tracing_callback_(value_tracing_callback) {}
void Process(V8EmbedderGraphBuilder* builder) { bool Process(V8EmbedderGraphBuilder* builder) {
Traceable key = nullptr; Traceable key = nullptr;
{ {
TraceKeysScope scope(builder, &key); TraceKeysScope scope(builder, &key);
key_tracing_callback_(builder, const_cast<void*>(key_)); key_tracing_callback_(builder, const_cast<void*>(key_));
} }
DCHECK(key); DCHECK(key);
DCHECK(builder->GetStateNotNull(key)); if (!builder->StateExists(key))
return false;
{ {
TraceValuesScope scope(builder, key); TraceValuesScope scope(builder, key);
value_tracing_callback_(builder, const_cast<void*>(value_)); value_tracing_callback_(builder, const_cast<void*>(value_));
} }
return true;
} }
private: private:
...@@ -378,6 +380,10 @@ class GC_PLUGIN_IGNORE( ...@@ -378,6 +380,10 @@ class GC_PLUGIN_IGNORE(
return states_.at(traceable); return states_.at(traceable);
} }
bool StateExists(Traceable traceable) const {
return states_.Contains(traceable);
}
State* GetStateNotNull(Traceable traceable) { State* GetStateNotNull(Traceable traceable) {
CHECK(states_.Contains(traceable)); CHECK(states_.Contains(traceable));
return states_.at(traceable); return states_.at(traceable);
...@@ -772,6 +778,12 @@ void V8EmbedderGraphBuilder::VisitTransitiveClosure() { ...@@ -772,6 +778,12 @@ void V8EmbedderGraphBuilder::VisitTransitiveClosure() {
// tracing can record new ephemerons, and tracing an ephemeron can add // tracing can record new ephemerons, and tracing an ephemeron can add
// items to the regular worklist, we need to repeatedly process the worklist // items to the regular worklist, we need to repeatedly process the worklist
// until a fixed point is reached. // until a fixed point is reached.
// Because snapshots are processed in stages, there may be ephemerons that
// where key's do not have yet a state associated with them which prohibits
// them from being processed. Such ephemerons are stashed for later
// processing.
Deque<std::unique_ptr<EphemeronItem>> unprocessed_ephemerons_;
do { do {
// Step 1: Go through all items in the worklist using depth-first search. // Step 1: Go through all items in the worklist using depth-first search.
while (!worklist_.empty()) { while (!worklist_.empty()) {
...@@ -780,15 +792,29 @@ void V8EmbedderGraphBuilder::VisitTransitiveClosure() { ...@@ -780,15 +792,29 @@ void V8EmbedderGraphBuilder::VisitTransitiveClosure() {
item->Process(this); item->Process(this);
} }
// Step 2: Go through ephemeron items. Only process an ephemeron item if // Step 2: Go through ephemeron items.
// its key was already observed.
// Re-add unprocessed ephemerons from last loop iteration.
while (!unprocessed_ephemerons_.empty()) {
ephemeron_worklist_.push_back(unprocessed_ephemerons_.TakeFirst());
}
// Only process an ephemeron item if its key was already observed.
while (!ephemeron_worklist_.empty()) { while (!ephemeron_worklist_.empty()) {
std::unique_ptr<EphemeronItem> item = std::unique_ptr<EphemeronItem> item =
std::move(ephemeron_worklist_.front()); std::move(ephemeron_worklist_.front());
ephemeron_worklist_.pop_front(); ephemeron_worklist_.pop_front();
item->Process(this); if (!item->Process(this)) {
unprocessed_ephemerons_.push_back(std::move(item));
}
} }
} while (!worklist_.empty()); } while (!worklist_.empty());
// Re-add unprocessed ephemerons. A later invocation of VisitTransitiveClosure
// must process them.
while (!unprocessed_ephemerons_.empty()) {
ephemeron_worklist_.push_back(unprocessed_ephemerons_.TakeFirst());
}
} }
} // namespace } // namespace
......
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