diff --git a/src/profiler/cpu-profiler-inl.h b/src/profiler/cpu-profiler-inl.h index ea2b4487a2..b759d85d85 100644 --- a/src/profiler/cpu-profiler-inl.h +++ b/src/profiler/cpu-profiler-inl.h @@ -53,8 +53,8 @@ void ReportBuiltinEventRecord::UpdateCodeMap(CodeMap* code_map) { if (builtin == Builtin::kGenericJSToWasmWrapper) { // Make sure to add the generic js-to-wasm wrapper builtin, because that // one is supposed to show up in profiles. - entry = - new CodeEntry(CodeEventListener::BUILTIN_TAG, Builtins::name(builtin)); + entry = code_map->code_entries().Create(CodeEventListener::BUILTIN_TAG, + Builtins::name(builtin)); code_map->AddCode(instruction_start, entry, instruction_size); } #endif // V8_ENABLE_WEBASSEMBLY diff --git a/src/profiler/cpu-profiler.cc b/src/profiler/cpu-profiler.cc index f5221d67d1..80531dfc20 100644 --- a/src/profiler/cpu-profiler.cc +++ b/src/profiler/cpu-profiler.cc @@ -336,9 +336,11 @@ void* SamplingEventsProcessor::operator new(size_t size) { void SamplingEventsProcessor::operator delete(void* ptr) { AlignedFree(ptr); } -ProfilerCodeObserver::ProfilerCodeObserver(Isolate* isolate) +ProfilerCodeObserver::ProfilerCodeObserver(Isolate* isolate, + CodeEntryStorage& storage) : isolate_(isolate), - code_map_(strings_), + code_entries_(storage), + code_map_(storage), weak_code_registry_(isolate), processor_(nullptr) { CreateEntriesForRuntimeCallStats(); @@ -350,7 +352,7 @@ void ProfilerCodeObserver::ClearCodeMap() { code_map_.Clear(); // We don't currently expect any references to refcounted strings to be // maintained with zero profiles after the code map is cleared. - DCHECK(strings_.empty()); + DCHECK(code_entries_.strings().empty()); } void ProfilerCodeObserver::CodeEventHandler( @@ -385,8 +387,8 @@ void ProfilerCodeObserver::CreateEntriesForRuntimeCallStats() { for (int i = 0; i < RuntimeCallStats::kNumberOfCounters; ++i) { RuntimeCallCounter* counter = rcs->GetCounter(i); DCHECK(counter->name()); - auto entry = new CodeEntry(CodeEventListener::FUNCTION_TAG, counter->name(), - "native V8Runtime"); + auto entry = code_entries_.Create(CodeEventListener::FUNCTION_TAG, + counter->name(), "native V8Runtime"); code_map_.AddCode(reinterpret_cast
(counter), entry, 1); } #endif // V8_RUNTIME_CALL_STATS @@ -473,7 +475,7 @@ CpuProfiler::CpuProfiler(Isolate* isolate, CpuProfilingNamingMode naming_mode, CpuProfilingLoggingMode logging_mode) : CpuProfiler(isolate, naming_mode, logging_mode, new CpuProfilesCollection(isolate), nullptr, nullptr, - new ProfilerCodeObserver(isolate)) {} + new ProfilerCodeObserver(isolate, code_entries_)) {} CpuProfiler::CpuProfiler(Isolate* isolate, CpuProfilingNamingMode naming_mode, CpuProfilingLoggingMode logging_mode, @@ -529,7 +531,7 @@ void CpuProfiler::EnableLogging() { if (!profiler_listener_) { profiler_listener_.reset(new ProfilerListener( - isolate_, code_observer_.get(), *code_observer_->strings(), + isolate_, code_observer_.get(), *code_observer_->code_entries(), *code_observer_->weak_code_registry(), naming_mode_)); } profiling_scope_.reset( diff --git a/src/profiler/cpu-profiler.h b/src/profiler/cpu-profiler.h index 8ffb45c7cf..9fe1e896be 100644 --- a/src/profiler/cpu-profiler.h +++ b/src/profiler/cpu-profiler.h @@ -256,17 +256,17 @@ class V8_EXPORT_PRIVATE SamplingEventsProcessor // low sampling intervals on Windows. }; -// Builds and maintains a CodeMap tracking code objects on the VM heap, as well -// as strings owned by them. While alive, logs generated code, callbacks, and -// builtins from the isolate. Redirects events to the profiler events -// processor when present. +// Builds and maintains a CodeMap tracking code objects on the VM heap. While +// alive, logs generated code, callbacks, and builtins from the isolate. +// Redirects events to the profiler events processor when present. CodeEntry +// lifetime is associated with the given CodeEntryStorage. class V8_EXPORT_PRIVATE ProfilerCodeObserver : public CodeEventObserver { public: - explicit ProfilerCodeObserver(Isolate*); + explicit ProfilerCodeObserver(Isolate*, CodeEntryStorage&); void CodeEventHandler(const CodeEventsContainer& evt_rec) override; + CodeEntryStorage* code_entries() { return &code_entries_; } CodeMap* code_map() { return &code_map_; } - StringsStorage* strings() { return &strings_; } WeakCodeRegistry* weak_code_registry() { return &weak_code_registry_; } void ClearCodeMap(); @@ -290,7 +290,7 @@ class V8_EXPORT_PRIVATE ProfilerCodeObserver : public CodeEventObserver { void clear_processor() { processor_ = nullptr; } Isolate* const isolate_; - StringsStorage strings_; + CodeEntryStorage& code_entries_; CodeMap code_map_; WeakCodeRegistry weak_code_registry_; ProfilerEventsProcessor* processor_; @@ -361,6 +361,7 @@ class V8_EXPORT_PRIVATE CpuProfiler { Symbolizer* symbolizer() const { return symbolizer_.get(); } ProfilerEventsProcessor* processor() const { return processor_.get(); } Isolate* isolate() const { return isolate_; } + CodeEntryStorage* code_entries() { return &code_entries_; } ProfilerListener* profiler_listener_for_test() const { return profiler_listener_.get(); @@ -389,6 +390,11 @@ class V8_EXPORT_PRIVATE CpuProfiler { // Sampling interval to which per-profile sampling intervals will be clamped // to a multiple of, or used as the default if unspecified. base::TimeDelta base_sampling_interval_; + + // Storage for CodeEntry objects allocated by the profiler. May live for + // multiple profiling sessions, independent of heap listener state. + CodeEntryStorage code_entries_; + std::unique_ptr code_observer_; std::unique_ptr profiles_; std::unique_ptr symbolizer_; diff --git a/src/profiler/profile-generator-inl.h b/src/profiler/profile-generator-inl.h index da847a240b..291dd3c028 100644 --- a/src/profiler/profile-generator-inl.h +++ b/src/profiler/profile-generator-inl.h @@ -38,6 +38,7 @@ ProfileNode::ProfileNode(ProfileTree* tree, CodeEntry* entry, parent_(parent), id_(tree->next_node_id()) { tree_->EnqueueNode(this); + if (tree_->code_entries()) tree_->code_entries()->AddRef(entry_); } inline Isolate* ProfileNode::isolate() const { return tree_->isolate(); } diff --git a/src/profiler/profile-generator.cc b/src/profiler/profile-generator.cc index 7d51fa9165..e0573bf6ca 100644 --- a/src/profiler/profile-generator.cc +++ b/src/profiler/profile-generator.cc @@ -231,6 +231,8 @@ CodeEntry::RareData* CodeEntry::EnsureRareData() { } void CodeEntry::ReleaseStrings(StringsStorage& strings) { + DCHECK_EQ(ref_count_, 0UL); + if (name_) { strings.Release(name_); name_ = nullptr; @@ -296,6 +298,10 @@ void CodeEntry::print() const { base::OS::Print("\n"); } +ProfileNode::~ProfileNode() { + if (tree_->code_entries()) tree_->code_entries()->DecRef(entry_); +} + CpuProfileNode::SourceType ProfileNode::source_type() const { // Handle metadata and VM state code entry types. if (entry_ == CodeEntry::program_entry() || @@ -433,10 +439,11 @@ class DeleteNodesCallback { void AfterChildTraversed(ProfileNode*, ProfileNode*) { } }; -ProfileTree::ProfileTree(Isolate* isolate) +ProfileTree::ProfileTree(Isolate* isolate, CodeEntryStorage* storage) : next_node_id_(1), root_(new ProfileNode(this, CodeEntry::root_entry(), nullptr)), - isolate_(isolate) {} + isolate_(isolate), + code_entries_(storage) {} ProfileTree::~ProfileTree() { DeleteNodesCallback cb; @@ -548,7 +555,7 @@ CpuProfile::CpuProfile(CpuProfiler* profiler, const char* title, options_(options), delegate_(std::move(delegate)), start_time_(base::TimeTicks::HighResolutionNow()), - top_down_(profiler->isolate()), + top_down_(profiler->isolate(), profiler->code_entries()), profiler_(profiler), streaming_next_sample_(0), id_(++last_id_) { @@ -739,31 +746,32 @@ void CpuProfile::Print() const { ProfilerStats::Instance()->Clear(); } -CodeMap::CodeMap(StringsStorage& function_and_resource_names) - : function_and_resource_names_(function_and_resource_names) {} +void CodeEntryStorage::AddRef(CodeEntry* entry) { + if (entry->is_ref_counted()) entry->AddRef(); +} + +void CodeEntryStorage::DecRef(CodeEntry* entry) { + if (entry->is_ref_counted() && entry->DecRef() == 0) { + entry->ReleaseStrings(function_and_resource_names_); + delete entry; + } +} + +CodeMap::CodeMap(CodeEntryStorage& storage) : code_entries_(storage) {} CodeMap::~CodeMap() { Clear(); } void CodeMap::Clear() { for (auto& slot : code_map_) { if (CodeEntry* entry = slot.second.entry) { - entry->ReleaseStrings(function_and_resource_names_); - delete entry; + code_entries_.DecRef(entry); } else { // We expect all entries in the code mapping to contain a CodeEntry. UNREACHABLE(); } } - // Free all CodeEntry objects that are no longer in the map, but in a profile. - // TODO(acomminos): Remove this deque after we refcount CodeEntry objects. - for (CodeEntry* entry : used_entries_) { - DCHECK(entry->used()); - DeleteCodeEntry(entry); - } - code_map_.clear(); - used_entries_.clear(); } void CodeMap::AddCode(Address addr, CodeEntry* entry, unsigned size) { @@ -775,11 +783,7 @@ bool CodeMap::RemoveCode(CodeEntry* entry) { auto range = code_map_.equal_range(entry->instruction_start()); for (auto i = range.first; i != range.second; ++i) { if (i->second.entry == entry) { - if (!entry->used()) { - DeleteCodeEntry(entry); - } else { - used_entries_.push_back(entry); - } + code_entries_.DecRef(entry); code_map_.erase(i); return true; } @@ -795,11 +799,7 @@ void CodeMap::ClearCodesInRange(Address start, Address end) { } auto right = left; for (; right != code_map_.end() && right->first < end; ++right) { - if (!right->second.entry->used()) { - DeleteCodeEntry(right->second.entry); - } else { - used_entries_.push_back(right->second.entry); - } + code_entries_.DecRef(right->second.entry); } code_map_.erase(left, right); } @@ -842,11 +842,6 @@ void CodeMap::MoveCode(Address from, Address to) { code_map_.erase(range.first, it); } -void CodeMap::DeleteCodeEntry(CodeEntry* entry) { - entry->ReleaseStrings(function_and_resource_names_); - delete entry; -} - void CodeMap::Print() { for (const auto& pair : code_map_) { base::OS::Print("%p %5d %s\n", reinterpret_cast(pair.first), diff --git a/src/profiler/profile-generator.h b/src/profiler/profile-generator.h index f00306acab..e66a3d0662 100644 --- a/src/profiler/profile-generator.h +++ b/src/profiler/profile-generator.h @@ -76,6 +76,7 @@ class CodeEntry { // No alive handles should be associated with the CodeEntry at time of // destruction. DCHECK(!heap_object_location_); + DCHECK_EQ(ref_count_, 0UL); } const char* name() const { return name_; } @@ -107,8 +108,6 @@ class CodeEntry { rare_data_->deopt_reason_ = kNoDeoptReason; rare_data_->deopt_id_ = kNoDeoptimizationId; } - void mark_used() { bit_field_ = UsedField::update(bit_field_, true); } - bool used() const { return UsedField::decode(bit_field_); } const char* code_type_string() const { switch (CodeTypeField::decode(bit_field_)) { @@ -137,6 +136,10 @@ class CodeEntry { return SharedCrossOriginField::decode(bit_field_); } + // Returns whether or not the lifetime of this CodeEntry is reference + // counted, and managed by a CodeMap. + bool is_ref_counted() const { return RefCountedField::decode(bit_field_); } + uint32_t GetHash() const; bool IsSameFunctionAs(const CodeEntry* entry) const; @@ -193,6 +196,8 @@ class CodeEntry { void print() const; private: + friend class CodeEntryStorage; + struct RareData { const char* deopt_reason_ = kNoDeoptReason; const char* bailout_reason_ = kEmptyBailoutReason; @@ -205,17 +210,35 @@ class CodeEntry { RareData* EnsureRareData(); + void mark_ref_counted() { + bit_field_ = RefCountedField::update(bit_field_, true); + ref_count_ = 1; + } + + size_t AddRef() { + DCHECK(is_ref_counted()); + DCHECK_LT(ref_count_, std::numeric_limits::max()); + ref_count_++; + return ref_count_; + } + + size_t DecRef() { + DCHECK(is_ref_counted()); + DCHECK_GT(ref_count_, 0UL); + ref_count_--; + return ref_count_; + } + using TagField = base::BitField; using BuiltinField = base::BitField; static_assert(Builtins::kBuiltinCount <= BuiltinField::kNumValues, "builtin_count exceeds size of bitfield"); - using CodeTypeField = base::BitField; - using UsedField = base::BitField; + using RefCountedField = base::BitField; + using CodeTypeField = base::BitField; using SharedCrossOriginField = base::BitField; - // Atomic because Used is written from the profiler thread while CodeType is - // read from the main thread. - std::atomic bit_field_; + std::uint32_t bit_field_; + std::atomic ref_count_ = {0}; const char* name_; const char* resource_name_; int line_number_; @@ -266,6 +289,7 @@ class V8_EXPORT_PRIVATE ProfileNode { public: inline ProfileNode(ProfileTree* tree, CodeEntry* entry, ProfileNode* parent, int line_number = 0); + ~ProfileNode(); ProfileNode(const ProfileNode&) = delete; ProfileNode& operator=(const ProfileNode&) = delete; @@ -329,9 +353,11 @@ class V8_EXPORT_PRIVATE ProfileNode { std::vector deopt_infos_; }; +class CodeEntryStorage; + class V8_EXPORT_PRIVATE ProfileTree { public: - explicit ProfileTree(Isolate* isolate); + explicit ProfileTree(Isolate* isolate, CodeEntryStorage* storage = nullptr); ~ProfileTree(); ProfileTree(const ProfileTree&) = delete; ProfileTree& operator=(const ProfileTree&) = delete; @@ -360,6 +386,8 @@ class V8_EXPORT_PRIVATE ProfileTree { return std::move(pending_nodes_); } + CodeEntryStorage* code_entries() { return code_entries_; } + private: template void TraverseDepthFirst(Callback* callback); @@ -369,6 +397,7 @@ class V8_EXPORT_PRIVATE ProfileTree { unsigned next_node_id_; ProfileNode* root_; Isolate* isolate_; + CodeEntryStorage* code_entries_; }; class CpuProfiler; @@ -450,13 +479,13 @@ class CpuProfileMaxSamplesCallbackTask : public v8::Task { class V8_EXPORT_PRIVATE CodeMap { public: - // Creates a new CodeMap with an associated StringsStorage to store the - // strings of CodeEntry objects within. - explicit CodeMap(StringsStorage& function_and_resource_names); + explicit CodeMap(CodeEntryStorage& storage); ~CodeMap(); CodeMap(const CodeMap&) = delete; CodeMap& operator=(const CodeMap&) = delete; + // Adds the given CodeEntry to the CodeMap. The CodeMap takes ownership of + // the CodeEntry. void AddCode(Address addr, CodeEntry* entry, unsigned size); void MoveCode(Address from, Address to); // Attempts to remove the given CodeEntry from the CodeMap. @@ -467,6 +496,8 @@ class V8_EXPORT_PRIVATE CodeMap { void Print(); size_t size() const { return code_map_.size(); } + CodeEntryStorage& code_entries() { return code_entries_; } + void Clear(); private: @@ -475,12 +506,28 @@ class V8_EXPORT_PRIVATE CodeMap { unsigned size; }; - void DeleteCodeEntry(CodeEntry*); - std::multimap code_map_; - std::deque used_entries_; // Entries that are no longer in the - // map, but used by a profile. - StringsStorage& function_and_resource_names_; + CodeEntryStorage& code_entries_; +}; + +// Manages the lifetime of CodeEntry objects, and stores shared resources +// between them. +class V8_EXPORT_PRIVATE CodeEntryStorage { + public: + template + static CodeEntry* Create(Args&&... args) { + CodeEntry* const entry = new CodeEntry(std::forward(args)...); + entry->mark_ref_counted(); + return entry; + } + + void AddRef(CodeEntry*); + void DecRef(CodeEntry*); + + StringsStorage& strings() { return function_and_resource_names_; } + + private: + StringsStorage function_and_resource_names_; }; class V8_EXPORT_PRIVATE CpuProfilesCollection { diff --git a/src/profiler/profiler-listener.cc b/src/profiler/profiler-listener.cc index a2cfb8b07b..3c14e20e66 100644 --- a/src/profiler/profiler-listener.cc +++ b/src/profiler/profiler-listener.cc @@ -29,12 +29,12 @@ namespace internal { ProfilerListener::ProfilerListener(Isolate* isolate, CodeEventObserver* observer, - StringsStorage& function_and_resource_names, + CodeEntryStorage& code_entry_storage, WeakCodeRegistry& weak_code_registry, CpuProfilingNamingMode naming_mode) : isolate_(isolate), observer_(observer), - function_and_resource_names_(function_and_resource_names), + code_entries_(code_entry_storage), weak_code_registry_(weak_code_registry), naming_mode_(naming_mode) {} @@ -46,9 +46,10 @@ void ProfilerListener::CodeCreateEvent(LogEventsAndTags tag, CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION); CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_; rec->instruction_start = code->InstructionStart(); - rec->entry = new CodeEntry(tag, GetName(name), CodeEntry::kEmptyResourceName, - CpuProfileNode::kNoLineNumberInfo, - CpuProfileNode::kNoColumnNumberInfo, nullptr); + rec->entry = + code_entries_.Create(tag, GetName(name), CodeEntry::kEmptyResourceName, + CpuProfileNode::kNoLineNumberInfo, + CpuProfileNode::kNoColumnNumberInfo, nullptr); rec->instruction_size = code->InstructionSize(); weak_code_registry_.Track(rec->entry, code); DispatchCodeEvent(evt_rec); @@ -60,9 +61,10 @@ void ProfilerListener::CodeCreateEvent(LogEventsAndTags tag, CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION); CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_; rec->instruction_start = code->InstructionStart(); - rec->entry = new CodeEntry(tag, GetName(*name), CodeEntry::kEmptyResourceName, - CpuProfileNode::kNoLineNumberInfo, - CpuProfileNode::kNoColumnNumberInfo, nullptr); + rec->entry = + code_entries_.Create(tag, GetName(*name), CodeEntry::kEmptyResourceName, + CpuProfileNode::kNoLineNumberInfo, + CpuProfileNode::kNoColumnNumberInfo, nullptr); rec->instruction_size = code->InstructionSize(); weak_code_registry_.Track(rec->entry, code); DispatchCodeEvent(evt_rec); @@ -75,10 +77,11 @@ void ProfilerListener::CodeCreateEvent(LogEventsAndTags tag, CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION); CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_; rec->instruction_start = code->InstructionStart(); - rec->entry = new CodeEntry(tag, GetName(shared->DebugNameCStr().get()), - GetName(InferScriptName(*script_name, *shared)), - CpuProfileNode::kNoLineNumberInfo, - CpuProfileNode::kNoColumnNumberInfo, nullptr); + rec->entry = + code_entries_.Create(tag, GetName(shared->DebugNameCStr().get()), + GetName(InferScriptName(*script_name, *shared)), + CpuProfileNode::kNoLineNumberInfo, + CpuProfileNode::kNoColumnNumberInfo, nullptr); DCHECK_IMPLIES(code->IsCode(), code->kind() == CodeKind::BASELINE); rec->entry->FillFunctionInfo(*shared); rec->instruction_size = code->InstructionSize(); @@ -91,10 +94,10 @@ namespace { CodeEntry* GetOrInsertCachedEntry( std::unordered_set, CodeEntry::Hasher, CodeEntry::Equals>* entries, - std::unique_ptr search_value, StringsStorage& strings) { + std::unique_ptr search_value, CodeEntryStorage& storage) { auto it = entries->find(search_value); if (it != entries->end()) { - search_value->ReleaseStrings(strings); + search_value->ReleaseStrings(storage.strings()); return it->get(); } CodeEntry* ret = search_value.get(); @@ -204,8 +207,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), - function_and_resource_names_); + &cached_inline_entries, std::move(inline_entry), code_entries_); inline_stack.push_back({cached_entry, line_number}); } @@ -214,10 +216,10 @@ void ProfilerListener::CodeCreateEvent(LogEventsAndTags tag, } } } - rec->entry = - new CodeEntry(tag, GetFunctionName(*shared), - GetName(InferScriptName(*script_name, *shared)), line, - column, std::move(line_table), is_shared_cross_origin); + rec->entry = code_entries_.Create( + tag, GetFunctionName(*shared), + GetName(InferScriptName(*script_name, *shared)), line, column, + std::move(line_table), is_shared_cross_origin); if (!inline_stacks.empty()) { rec->entry->SetInlineStacks(std::move(cached_inline_entries), std::move(inline_stacks)); @@ -238,9 +240,9 @@ void ProfilerListener::CodeCreateEvent(LogEventsAndTags tag, CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION); CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_; rec->instruction_start = code->instruction_start(); - rec->entry = - new CodeEntry(tag, GetName(name), GetName(source_url), 1, code_offset + 1, - nullptr, true, CodeEntry::CodeType::WASM); + rec->entry = code_entries_.Create(tag, GetName(name), GetName(source_url), 1, + code_offset + 1, nullptr, true, + CodeEntry::CodeType::WASM); rec->entry->set_script_id(script_id); rec->entry->set_position(code_offset); rec->instruction_size = code->instructions().length(); @@ -252,7 +254,8 @@ void ProfilerListener::CallbackEvent(Handle name, Address entry_point) { CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION); CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_; rec->instruction_start = entry_point; - rec->entry = new CodeEntry(CodeEventListener::CALLBACK_TAG, GetName(*name)); + rec->entry = + code_entries_.Create(CodeEventListener::CALLBACK_TAG, GetName(*name)); rec->instruction_size = 1; DispatchCodeEvent(evt_rec); } @@ -262,8 +265,8 @@ void ProfilerListener::GetterCallbackEvent(Handle name, CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION); CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_; rec->instruction_start = entry_point; - rec->entry = new CodeEntry(CodeEventListener::CALLBACK_TAG, - GetConsName("get ", *name)); + rec->entry = code_entries_.Create(CodeEventListener::CALLBACK_TAG, + GetConsName("get ", *name)); rec->instruction_size = 1; DispatchCodeEvent(evt_rec); } @@ -273,8 +276,8 @@ void ProfilerListener::SetterCallbackEvent(Handle name, CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION); CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_; rec->instruction_start = entry_point; - rec->entry = new CodeEntry(CodeEventListener::CALLBACK_TAG, - GetConsName("set ", *name)); + rec->entry = code_entries_.Create(CodeEventListener::CALLBACK_TAG, + GetConsName("set ", *name)); rec->instruction_size = 1; DispatchCodeEvent(evt_rec); } @@ -284,7 +287,7 @@ void ProfilerListener::RegExpCodeCreateEvent(Handle code, CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION); CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_; rec->instruction_start = code->InstructionStart(); - rec->entry = new CodeEntry( + rec->entry = code_entries_.Create( CodeEventListener::REG_EXP_TAG, GetConsName("RegExp: ", *source), CodeEntry::kEmptyResourceName, CpuProfileNode::kNoLineNumberInfo, CpuProfileNode::kNoColumnNumberInfo, nullptr); diff --git a/src/profiler/profiler-listener.h b/src/profiler/profiler-listener.h index 50a9b81893..de2d1ec997 100644 --- a/src/profiler/profiler-listener.h +++ b/src/profiler/profiler-listener.h @@ -29,7 +29,7 @@ class V8_EXPORT_PRIVATE ProfilerListener : public CodeEventListener, public WeakCodeRegistry::Listener { public: ProfilerListener(Isolate*, CodeEventObserver*, - StringsStorage& function_and_resource_names, + CodeEntryStorage& code_entry_storage, WeakCodeRegistry& weak_code_registry, CpuProfilingNamingMode mode = kDebugNaming); ~ProfilerListener() override; @@ -76,17 +76,17 @@ class V8_EXPORT_PRIVATE ProfilerListener : public CodeEventListener, void CodeSweepEvent(); const char* GetName(Name name) { - return function_and_resource_names_.GetName(name); + return code_entries_.strings().GetName(name); } const char* GetName(int args_count) { - return function_and_resource_names_.GetName(args_count); + return code_entries_.strings().GetName(args_count); } const char* GetName(const char* name) { - return function_and_resource_names_.GetCopy(name); + return code_entries_.strings().GetCopy(name); } const char* GetName(Vector name); const char* GetConsName(const char* prefix, Name name) { - return function_and_resource_names_.GetConsName(prefix, name); + return code_entries_.strings().GetConsName(prefix, name); } void set_observer(CodeEventObserver* observer) { observer_ = observer; } @@ -102,7 +102,7 @@ class V8_EXPORT_PRIVATE ProfilerListener : public CodeEventListener, Isolate* isolate_; CodeEventObserver* observer_; - StringsStorage& function_and_resource_names_; + CodeEntryStorage& code_entries_; WeakCodeRegistry& weak_code_registry_; const CpuProfilingNamingMode naming_mode_; }; diff --git a/src/profiler/symbolizer.cc b/src/profiler/symbolizer.cc index 61e884265d..d3aa629d25 100644 --- a/src/profiler/symbolizer.cc +++ b/src/profiler/symbolizer.cc @@ -16,9 +16,7 @@ Symbolizer::Symbolizer(CodeMap* code_map) : code_map_(code_map) {} CodeEntry* Symbolizer::FindEntry(Address address, Address* out_instruction_start) { - CodeEntry* entry = code_map_->FindEntry(address, out_instruction_start); - if (entry) entry->mark_used(); - return entry; + return code_map_->FindEntry(address, out_instruction_start); } namespace { diff --git a/test/cctest/test-cpu-profiler.cc b/test/cctest/test-cpu-profiler.cc index 2373fd2f3a..f0a6a06079 100644 --- a/test/cctest/test-cpu-profiler.cc +++ b/test/cctest/test-cpu-profiler.cc @@ -88,8 +88,9 @@ static const char* reason(const i::DeoptimizeReason reason) { TEST(StartStop) { i::Isolate* isolate = CcTest::i_isolate(); + CodeEntryStorage storage; CpuProfilesCollection profiles(isolate); - ProfilerCodeObserver code_observer(isolate); + ProfilerCodeObserver code_observer(isolate, storage); Symbolizer symbolizer(code_observer.code_map()); std::unique_ptr processor( new SamplingEventsProcessor( @@ -171,15 +172,16 @@ TEST(CodeEvents) { i::Handle comment2_code(CreateCode(isolate, &env), isolate); i::Handle moved_code(CreateCode(isolate, &env), isolate); + CodeEntryStorage storage; CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate); - ProfilerCodeObserver code_observer(isolate); + ProfilerCodeObserver code_observer(isolate, storage); Symbolizer* symbolizer = new Symbolizer(code_observer.code_map()); ProfilerEventsProcessor* processor = new SamplingEventsProcessor( isolate, symbolizer, &code_observer, profiles, v8::base::TimeDelta::FromMicroseconds(100), true); CHECK(processor->Start()); ProfilerListener profiler_listener(isolate, processor, - *code_observer.strings(), + *code_observer.code_entries(), *code_observer.weak_code_registry()); isolate->logger()->AddCodeEventListener(&profiler_listener); @@ -234,8 +236,10 @@ TEST(TickEvents) { i::Handle frame2_code(CreateCode(isolate, &env), isolate); i::Handle frame3_code(CreateCode(isolate, &env), isolate); + CodeEntryStorage storage; CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate); - ProfilerCodeObserver* code_observer = new ProfilerCodeObserver(isolate); + ProfilerCodeObserver* code_observer = + new ProfilerCodeObserver(isolate, storage); Symbolizer* symbolizer = new Symbolizer(code_observer->code_map()); ProfilerEventsProcessor* processor = new SamplingEventsProcessor( CcTest::i_isolate(), symbolizer, code_observer, profiles, @@ -245,7 +249,7 @@ TEST(TickEvents) { profiles->StartProfiling(""); CHECK(processor->Start()); ProfilerListener profiler_listener(isolate, processor, - *code_observer->strings(), + *code_observer->code_entries(), *code_observer->weak_code_registry()); isolate->logger()->AddCodeEventListener(&profiler_listener); @@ -396,8 +400,10 @@ TEST(Issue1398) { i::Handle code(CreateCode(isolate, &env), isolate); + CodeEntryStorage storage; CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate); - ProfilerCodeObserver* code_observer = new ProfilerCodeObserver(isolate); + ProfilerCodeObserver* code_observer = + new ProfilerCodeObserver(isolate, storage); Symbolizer* symbolizer = new Symbolizer(code_observer->code_map()); ProfilerEventsProcessor* processor = new SamplingEventsProcessor( CcTest::i_isolate(), symbolizer, code_observer, profiles, @@ -407,7 +413,7 @@ TEST(Issue1398) { profiles->StartProfiling(""); CHECK(processor->Start()); ProfilerListener profiler_listener(isolate, processor, - *code_observer->strings(), + *code_observer->code_entries(), *code_observer->weak_code_registry()); profiler_listener.CodeCreateEvent(i::Logger::BUILTIN_TAG, code, "bbb"); @@ -1262,8 +1268,10 @@ static void TickLines(bool optimize) { i::Address code_address = code->raw_instruction_start(); CHECK_NE(code_address, kNullAddress); + CodeEntryStorage storage; CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate); - ProfilerCodeObserver* code_observer = new ProfilerCodeObserver(isolate); + ProfilerCodeObserver* code_observer = + new ProfilerCodeObserver(isolate, storage); Symbolizer* symbolizer = new Symbolizer(code_observer->code_map()); ProfilerEventsProcessor* processor = new SamplingEventsProcessor( CcTest::i_isolate(), symbolizer, code_observer, profiles, @@ -1278,7 +1286,7 @@ static void TickLines(bool optimize) { isolate->logger()->LogCompiledFunctions(); CHECK(processor->Start()); ProfilerListener profiler_listener(isolate, processor, - *code_observer->strings(), + *code_observer->code_entries(), *code_observer->weak_code_registry()); // Enqueue code creation events. @@ -3474,8 +3482,9 @@ TEST(MaxSimultaneousProfiles) { TEST(LowPrecisionSamplingStartStopInternal) { i::Isolate* isolate = CcTest::i_isolate(); + CodeEntryStorage storage; CpuProfilesCollection profiles(isolate); - ProfilerCodeObserver code_observer(isolate); + ProfilerCodeObserver code_observer(isolate, storage); Symbolizer symbolizer(code_observer.code_map()); std::unique_ptr processor( new SamplingEventsProcessor( @@ -3600,8 +3609,10 @@ TEST(ProflilerSubsampling) { i::Isolate* isolate = CcTest::i_isolate(); i::HandleScope scope(isolate); + CodeEntryStorage storage; CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate); - ProfilerCodeObserver* code_observer = new ProfilerCodeObserver(isolate); + ProfilerCodeObserver* code_observer = + new ProfilerCodeObserver(isolate, storage); Symbolizer* symbolizer = new Symbolizer(code_observer->code_map()); ProfilerEventsProcessor* processor = new SamplingEventsProcessor(isolate, symbolizer, code_observer, profiles, @@ -3644,8 +3655,10 @@ TEST(DynamicResampling) { i::Isolate* isolate = CcTest::i_isolate(); i::HandleScope scope(isolate); + CodeEntryStorage storage; CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate); - ProfilerCodeObserver* code_observer = new ProfilerCodeObserver(isolate); + ProfilerCodeObserver* code_observer = + new ProfilerCodeObserver(isolate, storage); Symbolizer* symbolizer = new Symbolizer(code_observer->code_map()); ProfilerEventsProcessor* processor = new SamplingEventsProcessor(isolate, symbolizer, code_observer, profiles, @@ -3705,8 +3718,10 @@ TEST(DynamicResamplingWithBaseInterval) { i::Isolate* isolate = CcTest::i_isolate(); i::HandleScope scope(isolate); + CodeEntryStorage storage; CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate); - ProfilerCodeObserver* code_observer = new ProfilerCodeObserver(isolate); + ProfilerCodeObserver* code_observer = + new ProfilerCodeObserver(isolate, storage); Symbolizer* symbolizer = new Symbolizer(code_observer->code_map()); ProfilerEventsProcessor* processor = new SamplingEventsProcessor(isolate, symbolizer, code_observer, profiles, diff --git a/test/cctest/test-profile-generator.cc b/test/cctest/test-profile-generator.cc index ab56d6e7cc..aec85635b5 100644 --- a/test/cctest/test-profile-generator.cc +++ b/test/cctest/test-profile-generator.cc @@ -311,12 +311,12 @@ static inline i::Address ToAddress(int n) { return static_cast(n); } static inline void* ToPointer(int n) { return reinterpret_cast(n); } TEST(CodeMapAddCode) { - StringsStorage strings; - CodeMap code_map(strings); - CodeEntry* entry1 = new CodeEntry(i::CodeEventListener::FUNCTION_TAG, "aaa"); - CodeEntry* entry2 = new CodeEntry(i::CodeEventListener::FUNCTION_TAG, "bbb"); - CodeEntry* entry3 = new CodeEntry(i::CodeEventListener::FUNCTION_TAG, "ccc"); - CodeEntry* entry4 = new CodeEntry(i::CodeEventListener::FUNCTION_TAG, "ddd"); + CodeEntryStorage storage; + CodeMap code_map(storage); + CodeEntry* entry1 = storage.Create(i::CodeEventListener::FUNCTION_TAG, "aaa"); + CodeEntry* entry2 = storage.Create(i::CodeEventListener::FUNCTION_TAG, "bbb"); + CodeEntry* entry3 = storage.Create(i::CodeEventListener::FUNCTION_TAG, "ccc"); + CodeEntry* entry4 = storage.Create(i::CodeEventListener::FUNCTION_TAG, "ddd"); code_map.AddCode(ToAddress(0x1500), entry1, 0x200); code_map.AddCode(ToAddress(0x1700), entry2, 0x100); code_map.AddCode(ToAddress(0x1900), entry3, 0x50); @@ -341,10 +341,10 @@ TEST(CodeMapAddCode) { } TEST(CodeMapMoveAndDeleteCode) { - StringsStorage strings; - CodeMap code_map(strings); - CodeEntry* entry1 = new CodeEntry(i::CodeEventListener::FUNCTION_TAG, "aaa"); - CodeEntry* entry2 = new CodeEntry(i::CodeEventListener::FUNCTION_TAG, "bbb"); + CodeEntryStorage storage; + CodeMap code_map(storage); + CodeEntry* entry1 = storage.Create(i::CodeEventListener::FUNCTION_TAG, "aaa"); + CodeEntry* entry2 = storage.Create(i::CodeEventListener::FUNCTION_TAG, "bbb"); code_map.AddCode(ToAddress(0x1500), entry1, 0x200); code_map.AddCode(ToAddress(0x1700), entry2, 0x100); CHECK_EQ(entry1, code_map.FindEntry(ToAddress(0x1500))); @@ -355,10 +355,10 @@ TEST(CodeMapMoveAndDeleteCode) { } TEST(CodeMapClear) { - StringsStorage strings; - CodeMap code_map(strings); - CodeEntry* entry1 = new CodeEntry(i::CodeEventListener::FUNCTION_TAG, "aaa"); - CodeEntry* entry2 = new CodeEntry(i::CodeEventListener::FUNCTION_TAG, "bbb"); + CodeEntryStorage storage; + CodeMap code_map(storage); + CodeEntry* entry1 = storage.Create(i::CodeEventListener::FUNCTION_TAG, "aaa"); + CodeEntry* entry2 = storage.Create(i::CodeEventListener::FUNCTION_TAG, "bbb"); code_map.AddCode(ToAddress(0x1500), entry1, 0x200); code_map.AddCode(ToAddress(0x1700), entry2, 0x100); @@ -391,12 +391,12 @@ class TestSetup { TEST(SymbolizeTickSample) { TestSetup test_setup; - StringsStorage strings; - CodeMap code_map(strings); + CodeEntryStorage storage; + CodeMap code_map(storage); Symbolizer symbolizer(&code_map); - CodeEntry* entry1 = new CodeEntry(i::Logger::FUNCTION_TAG, "aaa"); - CodeEntry* entry2 = new CodeEntry(i::Logger::FUNCTION_TAG, "bbb"); - CodeEntry* entry3 = new CodeEntry(i::Logger::FUNCTION_TAG, "ccc"); + CodeEntry* entry1 = storage.Create(i::Logger::FUNCTION_TAG, "aaa"); + CodeEntry* entry2 = storage.Create(i::Logger::FUNCTION_TAG, "bbb"); + CodeEntry* entry3 = storage.Create(i::Logger::FUNCTION_TAG, "ccc"); symbolizer.code_map()->AddCode(ToAddress(0x1500), entry1, 0x200); symbolizer.code_map()->AddCode(ToAddress(0x1700), entry2, 0x100); symbolizer.code_map()->AddCode(ToAddress(0x1900), entry3, 0x50); @@ -456,16 +456,16 @@ static void CheckNodeIds(const ProfileNode* node, unsigned* expectedId) { TEST(SampleIds) { TestSetup test_setup; i::Isolate* isolate = CcTest::i_isolate(); - CpuProfilesCollection profiles(isolate); CpuProfiler profiler(isolate); + CpuProfilesCollection profiles(isolate); profiles.set_cpu_profiler(&profiler); profiles.StartProfiling("", {CpuProfilingMode::kLeafNodeLineNumbers}); - StringsStorage strings; - CodeMap code_map(strings); + CodeEntryStorage storage; + CodeMap code_map(storage); Symbolizer symbolizer(&code_map); - CodeEntry* entry1 = new CodeEntry(i::Logger::FUNCTION_TAG, "aaa"); - CodeEntry* entry2 = new CodeEntry(i::Logger::FUNCTION_TAG, "bbb"); - CodeEntry* entry3 = new CodeEntry(i::Logger::FUNCTION_TAG, "ccc"); + CodeEntry* entry1 = storage.Create(i::Logger::FUNCTION_TAG, "aaa"); + CodeEntry* entry2 = storage.Create(i::Logger::FUNCTION_TAG, "bbb"); + CodeEntry* entry3 = storage.Create(i::Logger::FUNCTION_TAG, "ccc"); symbolizer.code_map()->AddCode(ToAddress(0x1500), entry1, 0x200); symbolizer.code_map()->AddCode(ToAddress(0x1700), entry2, 0x100); symbolizer.code_map()->AddCode(ToAddress(0x1900), entry3, 0x50); @@ -592,8 +592,8 @@ TEST(MaxSamplesCallback) { MaybeLocal()}, std::move(impl)); - StringsStorage strings; - CodeMap code_map(strings); + CodeEntryStorage storage; + CodeMap code_map(storage); Symbolizer symbolizer(&code_map); TickSample sample1; sample1.timestamp = v8::base::TimeTicks::HighResolutionNow(); @@ -633,14 +633,14 @@ TEST(MaxSamplesCallback) { TEST(NoSamples) { TestSetup test_setup; i::Isolate* isolate = CcTest::i_isolate(); - CpuProfilesCollection profiles(isolate); CpuProfiler profiler(isolate); + CpuProfilesCollection profiles(isolate); profiles.set_cpu_profiler(&profiler); profiles.StartProfiling(""); - StringsStorage strings; - CodeMap code_map(strings); + CodeEntryStorage storage; + CodeMap code_map(storage); Symbolizer symbolizer(&code_map); - CodeEntry* entry1 = new CodeEntry(i::Logger::FUNCTION_TAG, "aaa"); + CodeEntry* entry1 = storage.Create(i::Logger::FUNCTION_TAG, "aaa"); symbolizer.code_map()->AddCode(ToAddress(0x1500), entry1, 0x200); // We are building the following calls tree: @@ -959,10 +959,10 @@ TEST(NodeSourceTypes) { } TEST(CodeMapRemoveCode) { - StringsStorage strings; - CodeMap code_map(strings); + CodeEntryStorage storage; + CodeMap code_map(storage); - CodeEntry* entry = new CodeEntry(i::CodeEventListener::FUNCTION_TAG, "aaa"); + CodeEntry* entry = storage.Create(i::CodeEventListener::FUNCTION_TAG, "aaa"); code_map.AddCode(ToAddress(0x1000), entry, 0x100); CHECK(code_map.RemoveCode(entry)); CHECK(!code_map.FindEntry(ToAddress(0x1000))); @@ -970,9 +970,9 @@ TEST(CodeMapRemoveCode) { // Test that when two entries share the same address, we remove only the // entry that we desired to. CodeEntry* colliding_entry1 = - new CodeEntry(i::CodeEventListener::FUNCTION_TAG, "aaa"); + storage.Create(i::CodeEventListener::FUNCTION_TAG, "aaa"); CodeEntry* colliding_entry2 = - new CodeEntry(i::CodeEventListener::FUNCTION_TAG, "aaa"); + storage.Create(i::CodeEventListener::FUNCTION_TAG, "aaa"); code_map.AddCode(ToAddress(0x1000), colliding_entry1, 0x100); code_map.AddCode(ToAddress(0x1000), colliding_entry2, 0x100); @@ -984,14 +984,14 @@ TEST(CodeMapRemoveCode) { } TEST(CodeMapMoveOverlappingCode) { - StringsStorage strings; - CodeMap code_map(strings); + CodeEntryStorage storage; + CodeMap code_map(storage); CodeEntry* colliding_entry1 = - new CodeEntry(i::CodeEventListener::FUNCTION_TAG, "aaa"); + storage.Create(i::CodeEventListener::FUNCTION_TAG, "aaa"); CodeEntry* colliding_entry2 = - new CodeEntry(i::CodeEventListener::FUNCTION_TAG, "bbb"); + storage.Create(i::CodeEventListener::FUNCTION_TAG, "bbb"); CodeEntry* after_entry = - new CodeEntry(i::CodeEventListener::FUNCTION_TAG, "ccc"); + storage.Create(i::CodeEventListener::FUNCTION_TAG, "ccc"); code_map.AddCode(ToAddress(0x1400), colliding_entry1, 0x200); code_map.AddCode(ToAddress(0x1400), colliding_entry2, 0x200);