Commit 8404216d authored by Andrew Comminos's avatar Andrew Comminos Committed by V8 LUCI CQ

[cpu-profiler] Implement refcounting for inline stacks

This resolves an issue where an inlined CodeEntry may outlive its parent
when translated into a ProfileNode.

Bug: chromium:1223323
Change-Id: I0427fce6a667c16d825f534333d39e463b287e31
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3000682Reviewed-by: 's avatarCamillo Bruni <cbruni@chromium.org>
Commit-Queue: Andrew Comminos <acomminos@fb.com>
Cr-Commit-Position: refs/heads/master@{#75541}
parent 478472d6
......@@ -168,8 +168,7 @@ int CodeEntry::GetSourceLine(int pc_offset) const {
}
void CodeEntry::SetInlineStacks(
std::unordered_set<std::unique_ptr<CodeEntry>, Hasher, Equals>
inline_entries,
std::unordered_set<CodeEntry*, Hasher, Equals> inline_entries,
std::unordered_map<int, std::vector<CodeEntryAndLineNumber>>
inline_stacks) {
EnsureRareData()->inline_entries_ = std::move(inline_entries);
......@@ -241,14 +240,6 @@ void CodeEntry::ReleaseStrings(StringsStorage& strings) {
strings.Release(resource_name_);
resource_name_ = nullptr;
}
if (rare_data_) {
// All inline entries are exclusively owned by the CodeEntry. They'll be
// deallocated when the CodeEntry is deallocated.
for (auto& entry : rare_data_->inline_entries_) {
entry->ReleaseStrings(strings);
}
}
}
void CodeEntry::print() const {
......@@ -752,6 +743,11 @@ void CodeEntryStorage::AddRef(CodeEntry* entry) {
void CodeEntryStorage::DecRef(CodeEntry* entry) {
if (entry->is_ref_counted() && entry->DecRef() == 0) {
if (entry->rare_data_) {
for (auto* inline_entry : entry->rare_data_->inline_entries_) {
DecRef(inline_entry);
}
}
entry->ReleaseStrings(function_and_resource_names_);
delete entry;
}
......
......@@ -146,20 +146,16 @@ class CodeEntry {
int GetSourceLine(int pc_offset) const;
struct Equals {
bool operator()(const std::unique_ptr<CodeEntry>& lhs,
const std::unique_ptr<CodeEntry>& rhs) const {
return lhs.get()->IsSameFunctionAs(rhs.get());
bool operator()(const CodeEntry* lhs, const CodeEntry* rhs) const {
return lhs->IsSameFunctionAs(rhs);
}
};
struct Hasher {
std::size_t operator()(const std::unique_ptr<CodeEntry>& e) const {
return e->GetHash();
}
std::size_t operator()(CodeEntry* e) const { return e->GetHash(); }
};
void SetInlineStacks(
std::unordered_set<std::unique_ptr<CodeEntry>, Hasher, Equals>
inline_entries,
std::unordered_set<CodeEntry*, Hasher, Equals> inline_entries,
std::unordered_map<int, std::vector<CodeEntryAndLineNumber>>
inline_stacks);
const std::vector<CodeEntryAndLineNumber>* GetInlineStack(
......@@ -203,8 +199,7 @@ class CodeEntry {
const char* bailout_reason_ = kEmptyBailoutReason;
int deopt_id_ = kNoDeoptimizationId;
std::unordered_map<int, std::vector<CodeEntryAndLineNumber>> inline_stacks_;
std::unordered_set<std::unique_ptr<CodeEntry>, Hasher, Equals>
inline_entries_;
std::unordered_set<CodeEntry*, Hasher, Equals> inline_entries_;
std::vector<CpuProfileDeoptFrame> deopt_inlined_frames_;
};
......
......@@ -92,17 +92,16 @@ void ProfilerListener::CodeCreateEvent(LogEventsAndTags tag,
namespace {
CodeEntry* GetOrInsertCachedEntry(
std::unordered_set<std::unique_ptr<CodeEntry>, CodeEntry::Hasher,
CodeEntry::Equals>* entries,
std::unique_ptr<CodeEntry> search_value, CodeEntryStorage& storage) {
std::unordered_set<CodeEntry*, CodeEntry::Hasher, CodeEntry::Equals>*
entries,
CodeEntry* search_value, CodeEntryStorage& storage) {
auto it = entries->find(search_value);
if (it != entries->end()) {
search_value->ReleaseStrings(storage.strings());
return it->get();
storage.DecRef(search_value);
return *it;
}
CodeEntry* ret = search_value.get();
entries->insert(std::move(search_value));
return ret;
entries->insert(search_value);
return search_value;
}
} // namespace
......@@ -117,8 +116,7 @@ void ProfilerListener::CodeCreateEvent(LogEventsAndTags tag,
rec->instruction_start = abstract_code->InstructionStart();
std::unique_ptr<SourcePositionTable> line_table;
std::unordered_map<int, std::vector<CodeEntryAndLineNumber>> inline_stacks;
std::unordered_set<std::unique_ptr<CodeEntry>, CodeEntry::Hasher,
CodeEntry::Equals>
std::unordered_set<CodeEntry*, CodeEntry::Hasher, CodeEntry::Equals>
cached_inline_entries;
bool is_shared_cross_origin = false;
if (shared->script().IsScript()) {
......@@ -198,7 +196,7 @@ void ProfilerListener::CodeCreateEvent(LogEventsAndTags tag,
SourcePosition(pos_info.shared->StartPosition()),
pos_info.shared);
std::unique_ptr<CodeEntry> inline_entry = std::make_unique<CodeEntry>(
CodeEntry* inline_entry = code_entries_.Create(
tag, GetFunctionName(*pos_info.shared), resource_name,
start_pos_info.line + 1, start_pos_info.column + 1, nullptr,
inline_is_shared_cross_origin);
......@@ -207,7 +205,7 @@ void ProfilerListener::CodeCreateEvent(LogEventsAndTags tag,
// Create a canonical CodeEntry for each inlined frame and then re-use
// them for subsequent inline stacks to avoid a lot of duplication.
CodeEntry* cached_entry = GetOrInsertCachedEntry(
&cached_inline_entries, std::move(inline_entry), code_entries_);
&cached_inline_entries, inline_entry, code_entries_);
inline_stack.push_back({cached_entry, line_number});
}
......
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