From b57ad02d74185ea111565a1b3b3656da14edbcec Mon Sep 17 00:00:00 2001
From: Peter Marshall
Date: Tue, 26 Jun 2018 18:37:43 +0200
Subject: [PATCH] deps: V8: backport 14 CPU profiler commits from upstream
[cpu-profiler] Fix bugs and add tests for JITLineInfoTable
https://chromium.googlesource.com/v8/v8/+/4feb5ce7fd5ef8c933f3f5dff2eca1173f85c1e9
[cpu-profiler] Fix incorrect line number calculation.
https://chromium.googlesource.com/v8/v8/+/ddb2856f39632f9e9f623d3cdb4600e636172031
[cpu-profiler] Use std::unordered_map for hashmaps.
https://chromium.googlesource.com/v8/v8/+/35985ce6abc80b85264fe3b87b246fed5f1806e6
[cpu-profiler] Do not store CodeEntries between profiling sessions.
https://chromium.googlesource.com/v8/v8.git/+/8ec48b2117b8092c4956f1ee11a0c85bec3ba1f8
[cpu-profiler] Remove name_prefix field from CodeEntry
https://chromium.googlesource.com/v8/v8.git/+/6f72af25fe43218b60c68129073ddcddb631566e
[cpu-profiler] Extract rare used fields of CodeEntry to an optional object.
https://chromium.googlesource.com/v8/v8.git/+/fcc1ebb55aab38013855834f556f6e874e0eb8b3
[profiler] Refactoring: decouple StringsStorage from Heap object.
https://chromium.googlesource.com/v8/v8/+/a31320f59c911a277566d6c2fa0b0f2ac83e0748
[cpu-profiler] Add a HandleScope to limit memory consumption.
https://chromium.googlesource.com/v8/v8.git/+/3e9f8a4f635e2d946651d6a4df81378266f32dc9
[cpu-profiler] Lazily create CPU profiler.
https://chromium.googlesource.com/v8/v8/+/1426ea1d6d45be0b4d9476bdb5bf3f27cfe578a0
[cpu-profiler] turn several std::map's into unordered_map's.
https://chromium.googlesource.com/v8/v8/+/3ed5dfb8a3cbc7aa0017bd01c2fdd6227485b8ad
[cpu-profiler] Eagerly delete not used CodeEntry'es
https://chromium.googlesource.com/v8/v8.git/+/c6c28f7a412a88df12055e953630a9e93cc64d49
[cpu-profiler] Move bailout reason into rare_info struct
https://chromium.googlesource.com/v8/v8.git/+/29ea4d1ef5360e71c61ecf8db6a5a0a0c3391fd1
[cpu-profiler] Save space in the SourcePositionTable by using a vector.
https://chromium.googlesource.com/v8/v8.git/+/1cb19f0e0a93adbac8c11bc906f951bd8098722d
[cpu-profiler] Only store deopt inline frames for functions that need it
https://chromium.googlesource.com/v8/v8.git/+/0bfcbdd4726920755e51dab28c18ab93e050819b
PR-URL: https://github.com/nodejs/node/pull/21558
Reviewed-By: Matteo Collina
Reviewed-By: Myles Borins
---
deps/v8/include/v8-version.h | 2 +-
deps/v8/src/api.cc | 12 +-
deps/v8/src/isolate.cc | 8 +-
deps/v8/src/isolate.h | 2 +-
deps/v8/src/log.cc | 21 --
deps/v8/src/log.h | 11 -
deps/v8/src/profiler/cpu-profiler-inl.h | 6 +-
deps/v8/src/profiler/cpu-profiler.cc | 36 +--
deps/v8/src/profiler/cpu-profiler.h | 9 +-
deps/v8/src/profiler/heap-profiler.cc | 4 +-
deps/v8/src/profiler/profile-generator-inl.h | 23 +-
deps/v8/src/profiler/profile-generator.cc | 227 +++++++++---------
deps/v8/src/profiler/profile-generator.h | 150 ++++++------
deps/v8/src/profiler/profiler-listener.cc | 130 +++++-----
deps/v8/src/profiler/profiler-listener.h | 30 +--
deps/v8/src/profiler/strings-storage.cc | 32 ++-
deps/v8/src/profiler/strings-storage.h | 6 +-
deps/v8/test/cctest/test-cpu-profiler.cc | 88 +++++--
deps/v8/test/cctest/test-profile-generator.cc | 70 +++---
19 files changed, 446 insertions(+), 421 deletions(-)
diff --git a/deps/v8/include/v8-version.h b/deps/v8/include/v8-version.h
index f1f29d02de3fb5..ddecda5abe18c5 100644
--- a/deps/v8/include/v8-version.h
+++ b/deps/v8/include/v8-version.h
@@ -11,7 +11,7 @@
#define V8_MAJOR_VERSION 6
#define V8_MINOR_VERSION 2
#define V8_BUILD_NUMBER 414
-#define V8_PATCH_LEVEL 60
+#define V8_PATCH_LEVEL 61
// Use 1 for candidates and 0 otherwise.
// (Boolean macro values are not supported by all preprocessors.)
diff --git a/deps/v8/src/api.cc b/deps/v8/src/api.cc
index 99d79985ef2dae..434454ec67641f 100644
--- a/deps/v8/src/api.cc
+++ b/deps/v8/src/api.cc
@@ -8419,7 +8419,7 @@ HeapProfiler* Isolate::GetHeapProfiler() {
CpuProfiler* Isolate::GetCpuProfiler() {
i::CpuProfiler* cpu_profiler =
- reinterpret_cast(this)->cpu_profiler();
+ reinterpret_cast(this)->EnsureCpuProfiler();
return reinterpret_cast(cpu_profiler);
}
@@ -10139,15 +10139,7 @@ Local CpuProfileNode::GetFunctionName() const {
const i::CodeEntry* entry = node->entry();
i::Handle name =
isolate->factory()->InternalizeUtf8String(entry->name());
- if (!entry->has_name_prefix()) {
- return ToApiHandle(name);
- } else {
- // We do not expect this to fail. Change this if it does.
- i::Handle cons = isolate->factory()->NewConsString(
- isolate->factory()->InternalizeUtf8String(entry->name_prefix()),
- name).ToHandleChecked();
- return ToApiHandle(cons);
- }
+ return ToApiHandle(name);
}
int debug::Coverage::BlockData::StartOffset() const { return block_->start; }
diff --git a/deps/v8/src/isolate.cc b/deps/v8/src/isolate.cc
index 5149a2650e2a10..12fb986952512f 100644
--- a/deps/v8/src/isolate.cc
+++ b/deps/v8/src/isolate.cc
@@ -2689,7 +2689,6 @@ bool Isolate::Init(StartupDeserializer* des) {
call_descriptor_data_ =
new CallInterfaceDescriptorData[CallDescriptors::NUMBER_OF_DESCRIPTORS];
access_compiler_data_ = new AccessCompilerData();
- cpu_profiler_ = new CpuProfiler(this);
heap_profiler_ = new HeapProfiler(heap());
interpreter_ = new interpreter::Interpreter(this);
compiler_dispatcher_ =
@@ -3686,6 +3685,13 @@ void Isolate::PrintWithTimestamp(const char* format, ...) {
va_end(arguments);
}
+CpuProfiler* Isolate::EnsureCpuProfiler() {
+ if (!cpu_profiler_) {
+ cpu_profiler_ = new CpuProfiler(this);
+ }
+ return cpu_profiler_;
+}
+
bool StackLimitCheck::JsHasOverflowed(uintptr_t gap) const {
StackGuard* stack_guard = isolate_->stack_guard();
#ifdef USE_SIMULATOR
diff --git a/deps/v8/src/isolate.h b/deps/v8/src/isolate.h
index c3a0727e84a353..b3796641556a31 100644
--- a/deps/v8/src/isolate.h
+++ b/deps/v8/src/isolate.h
@@ -1449,7 +1449,7 @@ class Isolate {
// TODO(alph): Remove along with the deprecated GetCpuProfiler().
friend v8::CpuProfiler* v8::Isolate::GetCpuProfiler();
- CpuProfiler* cpu_profiler() const { return cpu_profiler_; }
+ CpuProfiler* EnsureCpuProfiler();
base::Atomic32 id_;
EntryStackItem* entry_stack_;
diff --git a/deps/v8/src/log.cc b/deps/v8/src/log.cc
index 0ba024b987189e..493c6ca6f0d6e2 100644
--- a/deps/v8/src/log.cc
+++ b/deps/v8/src/log.cc
@@ -22,7 +22,6 @@
#include "src/log-utils.h"
#include "src/macro-assembler.h"
#include "src/perf-jit.h"
-#include "src/profiler/profiler-listener.h"
#include "src/profiler/tick-sample.h"
#include "src/runtime-profiler.h"
#include "src/source-position-table.h"
@@ -739,7 +738,6 @@ Logger::Logger(Isolate* isolate)
perf_jit_logger_(NULL),
ll_logger_(NULL),
jit_logger_(NULL),
- listeners_(5),
is_initialized_(false) {}
Logger::~Logger() {
@@ -1876,8 +1874,6 @@ bool Logger::SetUp(Isolate* isolate) {
profiler_->Engage();
}
- profiler_listener_.reset();
-
if (is_logging_) {
addCodeEventListener(this);
}
@@ -1905,19 +1901,6 @@ void Logger::SetCodeEventHandler(uint32_t options,
}
}
-void Logger::SetUpProfilerListener() {
- if (!is_initialized_) return;
- if (profiler_listener_.get() == nullptr) {
- profiler_listener_.reset(new ProfilerListener(isolate_));
- }
- addCodeEventListener(profiler_listener_.get());
-}
-
-void Logger::TearDownProfilerListener() {
- if (profiler_listener_->HasObservers()) return;
- removeCodeEventListener(profiler_listener_.get());
-}
-
sampler::Sampler* Logger::sampler() {
return ticker_;
}
@@ -1961,10 +1944,6 @@ FILE* Logger::TearDown() {
jit_logger_ = NULL;
}
- if (profiler_listener_.get() != nullptr) {
- removeCodeEventListener(profiler_listener_.get());
- }
-
return log_->Close();
}
diff --git a/deps/v8/src/log.h b/deps/v8/src/log.h
index 3e4d385527b6d0..33a086c48a0678 100644
--- a/deps/v8/src/log.h
+++ b/deps/v8/src/log.h
@@ -74,7 +74,6 @@ class LowLevelLogger;
class PerfBasicLogger;
class PerfJitLogger;
class Profiler;
-class ProfilerListener;
class RuntimeCallTimer;
class Ticker;
@@ -102,16 +101,8 @@ class Logger : public CodeEventListener {
void SetCodeEventHandler(uint32_t options,
JitCodeEventHandler event_handler);
- // Sets up ProfilerListener.
- void SetUpProfilerListener();
-
- // Tear down ProfilerListener if it has no observers.
- void TearDownProfilerListener();
-
sampler::Sampler* sampler();
- ProfilerListener* profiler_listener() { return profiler_listener_.get(); }
-
// Frees resources acquired in SetUp.
// When a temporary file is used for the log, returns its stream descriptor,
// leaving the file open.
@@ -316,8 +307,6 @@ class Logger : public CodeEventListener {
PerfJitLogger* perf_jit_logger_;
LowLevelLogger* ll_logger_;
JitLogger* jit_logger_;
- std::unique_ptr profiler_listener_;
- List listeners_;
std::set logged_source_code_;
uint32_t next_source_info_id_ = 0;
diff --git a/deps/v8/src/profiler/cpu-profiler-inl.h b/deps/v8/src/profiler/cpu-profiler-inl.h
index 440c6a1cce189b..80ff89bb486f4b 100644
--- a/deps/v8/src/profiler/cpu-profiler-inl.h
+++ b/deps/v8/src/profiler/cpu-profiler-inl.h
@@ -35,7 +35,11 @@ void CodeDisableOptEventRecord::UpdateCodeMap(CodeMap* code_map) {
void CodeDeoptEventRecord::UpdateCodeMap(CodeMap* code_map) {
CodeEntry* entry = code_map->FindEntry(start);
- if (entry != NULL) entry->set_deopt_info(deopt_reason, deopt_id);
+ if (entry == nullptr) return;
+ std::vector frames_vector(
+ deopt_frames, deopt_frames + deopt_frame_count);
+ entry->set_deopt_info(deopt_reason, deopt_id, std::move(frames_vector));
+ delete[] deopt_frames;
}
diff --git a/deps/v8/src/profiler/cpu-profiler.cc b/deps/v8/src/profiler/cpu-profiler.cc
index 80d488f12c527f..3862a49e8187e8 100644
--- a/deps/v8/src/profiler/cpu-profiler.cc
+++ b/deps/v8/src/profiler/cpu-profiler.cc
@@ -4,6 +4,12 @@
#include "src/profiler/cpu-profiler.h"
+#include
+#include
+
+#include "src/base/lazy-instance.h"
+#include "src/base/platform/mutex.h"
+#include "src/base/template-utils.h"
#include "src/debug/debug.h"
#include "src/deoptimizer.h"
#include "src/frames-inl.h"
@@ -275,20 +281,19 @@ void CpuProfiler::set_sampling_interval(base::TimeDelta value) {
void CpuProfiler::ResetProfiles() {
profiles_.reset(new CpuProfilesCollection(isolate_));
profiles_->set_cpu_profiler(this);
+ profiler_listener_.reset();
+ generator_.reset();
}
void CpuProfiler::CreateEntriesForRuntimeCallStats() {
- static_entries_.clear();
RuntimeCallStats* rcs = isolate_->counters()->runtime_call_stats();
CodeMap* code_map = generator_->code_map();
for (int i = 0; i < RuntimeCallStats::counters_count; ++i) {
RuntimeCallCounter* counter = &(rcs->*(RuntimeCallStats::counters[i]));
DCHECK(counter->name());
- std::unique_ptr entry(
- new CodeEntry(CodeEventListener::FUNCTION_TAG, counter->name(),
- CodeEntry::kEmptyNamePrefix, "native V8Runtime"));
- code_map->AddCode(reinterpret_cast(counter), entry.get(), 1);
- static_entries_.push_back(std::move(entry));
+ auto entry = new CodeEntry(CodeEventListener::FUNCTION_TAG, counter->name(),
+ "native V8Runtime");
+ code_map->AddCode(reinterpret_cast(counter), entry, 1);
}
}
@@ -321,13 +326,17 @@ void CpuProfiler::StartProcessorIfNotStarted() {
// Disable logging when using the new implementation.
saved_is_logging_ = logger->is_logging_;
logger->is_logging_ = false;
- generator_.reset(new ProfileGenerator(profiles_.get()));
+ if (!generator_) {
+ generator_.reset(new ProfileGenerator(profiles_.get()));
+ CreateEntriesForRuntimeCallStats();
+ }
processor_.reset(new ProfilerEventsProcessor(isolate_, generator_.get(),
sampling_interval_));
- CreateEntriesForRuntimeCallStats();
- logger->SetUpProfilerListener();
- ProfilerListener* profiler_listener = logger->profiler_listener();
- profiler_listener->AddObserver(this);
+ if (!profiler_listener_) {
+ profiler_listener_.reset(new ProfilerListener(isolate_, this));
+ }
+ logger->addCodeEventListener(profiler_listener_.get());
+
is_profiling_ = true;
isolate_->set_is_profiling(true);
// Enumerate stuff we already have in the heap.
@@ -362,12 +371,9 @@ void CpuProfiler::StopProcessor() {
Logger* logger = isolate_->logger();
is_profiling_ = false;
isolate_->set_is_profiling(false);
- ProfilerListener* profiler_listener = logger->profiler_listener();
- profiler_listener->RemoveObserver(this);
+ logger->removeCodeEventListener(profiler_listener_.get());
processor_->StopSynchronously();
- logger->TearDownProfilerListener();
processor_.reset();
- generator_.reset();
logger->is_logging_ = saved_is_logging_;
}
diff --git a/deps/v8/src/profiler/cpu-profiler.h b/deps/v8/src/profiler/cpu-profiler.h
index 5fd7fa14da1cab..e2e46d2be7f683 100644
--- a/deps/v8/src/profiler/cpu-profiler.h
+++ b/deps/v8/src/profiler/cpu-profiler.h
@@ -86,6 +86,8 @@ class CodeDeoptEventRecord : public CodeEventRecord {
int deopt_id;
void* pc;
int fp_to_sp_delta;
+ CpuProfileDeoptFrame* deopt_frames;
+ int deopt_frame_count;
INLINE(void UpdateCodeMap(CodeMap* code_map));
};
@@ -214,6 +216,10 @@ class CpuProfiler : public CodeEventObserver {
ProfilerEventsProcessor* processor() const { return processor_.get(); }
Isolate* isolate() const { return isolate_; }
+ ProfilerListener* profiler_listener_for_test() {
+ return profiler_listener_.get();
+ }
+
private:
void StartProcessorIfNotStarted();
void StopProcessorIfLastProfile(const char* title);
@@ -227,7 +233,7 @@ class CpuProfiler : public CodeEventObserver {
std::unique_ptr profiles_;
std::unique_ptr generator_;
std::unique_ptr processor_;
- std::vector> static_entries_;
+ std::unique_ptr profiler_listener_;
bool saved_is_logging_;
bool is_profiling_;
@@ -237,5 +243,4 @@ class CpuProfiler : public CodeEventObserver {
} // namespace internal
} // namespace v8
-
#endif // V8_PROFILER_CPU_PROFILER_H_
diff --git a/deps/v8/src/profiler/heap-profiler.cc b/deps/v8/src/profiler/heap-profiler.cc
index 4706b914e7ac40..f587adda497daf 100644
--- a/deps/v8/src/profiler/heap-profiler.cc
+++ b/deps/v8/src/profiler/heap-profiler.cc
@@ -16,7 +16,7 @@ namespace internal {
HeapProfiler::HeapProfiler(Heap* heap)
: ids_(new HeapObjectsMap(heap)),
- names_(new StringsStorage(heap)),
+ names_(new StringsStorage(heap->HashSeed())),
is_tracking_object_moves_(false),
get_retainer_infos_callback_(nullptr) {}
@@ -34,7 +34,7 @@ HeapProfiler::~HeapProfiler() {
void HeapProfiler::DeleteAllSnapshots() {
snapshots_.Iterate(DeleteHeapSnapshot);
snapshots_.Clear();
- names_.reset(new StringsStorage(heap()));
+ names_.reset(new StringsStorage(heap()->HashSeed()));
}
diff --git a/deps/v8/src/profiler/profile-generator-inl.h b/deps/v8/src/profiler/profile-generator-inl.h
index 5a7017ad490767..7ed6d54e172f09 100644
--- a/deps/v8/src/profiler/profile-generator-inl.h
+++ b/deps/v8/src/profiler/profile-generator-inl.h
@@ -11,33 +11,34 @@ namespace v8 {
namespace internal {
CodeEntry::CodeEntry(CodeEventListener::LogEventsAndTags tag, const char* name,
- const char* name_prefix, const char* resource_name,
- int line_number, int column_number,
- JITLineInfoTable* line_info, Address instruction_start)
+ const char* resource_name, int line_number,
+ int column_number,
+ std::unique_ptr line_info,
+ Address instruction_start)
: bit_field_(TagField::encode(tag) |
BuiltinIdField::encode(Builtins::builtin_count)),
- name_prefix_(name_prefix),
name_(name),
resource_name_(resource_name),
line_number_(line_number),
column_number_(column_number),
script_id_(v8::UnboundScript::kNoScriptId),
position_(0),
- bailout_reason_(kEmptyBailoutReason),
- deopt_reason_(kNoDeoptReason),
- deopt_id_(kNoDeoptimizationId),
- line_info_(line_info),
+ line_info_(std::move(line_info)),
instruction_start_(instruction_start) {}
+inline CodeEntry* ProfileGenerator::FindEntry(Address address) {
+ CodeEntry* entry = code_map_.FindEntry(address);
+ if (entry) entry->mark_used();
+ return entry;
+}
+
ProfileNode::ProfileNode(ProfileTree* tree, CodeEntry* entry,
ProfileNode* parent)
: tree_(tree),
entry_(entry),
self_ticks_(0),
- children_(CodeEntriesMatch),
parent_(parent),
- id_(tree->next_node_id()),
- line_ticks_(LineTickMatch) {
+ id_(tree->next_node_id()) {
tree_->EnqueueNode(this);
}
diff --git a/deps/v8/src/profiler/profile-generator.cc b/deps/v8/src/profiler/profile-generator.cc
index 029b6826ec25fa..e8d805562d1b40 100644
--- a/deps/v8/src/profiler/profile-generator.cc
+++ b/deps/v8/src/profiler/profile-generator.cc
@@ -18,33 +18,30 @@
namespace v8 {
namespace internal {
-
-JITLineInfoTable::JITLineInfoTable() {}
-
-
-JITLineInfoTable::~JITLineInfoTable() {}
-
-
-void JITLineInfoTable::SetPosition(int pc_offset, int line) {
- DCHECK(pc_offset >= 0);
- DCHECK(line > 0); // The 1-based number of the source line.
- if (GetSourceLineNumber(pc_offset) != line) {
- pc_offset_map_.insert(std::make_pair(pc_offset, line));
+void SourcePositionTable::SetPosition(int pc_offset, int line) {
+ DCHECK_GE(pc_offset, 0);
+ DCHECK_GT(line, 0); // The 1-based number of the source line.
+ // Check that we are inserting in ascending order, so that the vector remains
+ // sorted.
+ DCHECK(pc_offsets_to_lines_.empty() ||
+ pc_offsets_to_lines_.back().pc_offset < pc_offset);
+ if (pc_offsets_to_lines_.empty() ||
+ pc_offsets_to_lines_.back().line_number != line) {
+ pc_offsets_to_lines_.push_back({pc_offset, line});
}
}
-
-int JITLineInfoTable::GetSourceLineNumber(int pc_offset) const {
- PcOffsetMap::const_iterator it = pc_offset_map_.lower_bound(pc_offset);
- if (it == pc_offset_map_.end()) {
- if (pc_offset_map_.empty()) return v8::CpuProfileNode::kNoLineNumberInfo;
- return (--pc_offset_map_.end())->second;
+int SourcePositionTable::GetSourceLineNumber(int pc_offset) const {
+ if (pc_offsets_to_lines_.empty()) {
+ return v8::CpuProfileNode::kNoLineNumberInfo;
}
- return it->second;
+ auto it =
+ std::upper_bound(pc_offsets_to_lines_.begin(), pc_offsets_to_lines_.end(),
+ PCOffsetAndLineNumber{pc_offset, 0});
+ if (it != pc_offsets_to_lines_.begin()) --it;
+ return it->line_number;
}
-
-const char* const CodeEntry::kEmptyNamePrefix = "";
const char* const CodeEntry::kEmptyResourceName = "";
const char* const CodeEntry::kEmptyBailoutReason = "";
const char* const CodeEntry::kNoDeoptReason = "";
@@ -85,24 +82,12 @@ CodeEntry* CodeEntry::UnresolvedEntryCreateTrait::Create() {
CodeEntry::kUnresolvedFunctionName);
}
-CodeEntry::~CodeEntry() {
- delete line_info_;
- for (auto location : inline_locations_) {
- for (auto entry : location.second) {
- delete entry;
- }
- }
-}
-
-
uint32_t CodeEntry::GetHash() const {
uint32_t hash = ComputeIntegerHash(tag());
if (script_id_ != v8::UnboundScript::kNoScriptId) {
hash ^= ComputeIntegerHash(static_cast(script_id_));
hash ^= ComputeIntegerHash(static_cast(position_));
} else {
- hash ^= ComputeIntegerHash(
- static_cast(reinterpret_cast(name_prefix_)));
hash ^= ComputeIntegerHash(
static_cast(reinterpret_cast(name_)));
hash ^= ComputeIntegerHash(
@@ -112,14 +97,12 @@ uint32_t CodeEntry::GetHash() const {
return hash;
}
-
-bool CodeEntry::IsSameFunctionAs(CodeEntry* entry) const {
+bool CodeEntry::IsSameFunctionAs(const CodeEntry* entry) const {
if (this == entry) return true;
if (script_id_ != v8::UnboundScript::kNoScriptId) {
return script_id_ == entry->script_id_ && position_ == entry->position_;
}
- return name_prefix_ == entry->name_prefix_ && name_ == entry->name_ &&
- resource_name_ == entry->resource_name_ &&
+ return name_ == entry->name_ && resource_name_ == entry->resource_name_ &&
line_number_ == entry->line_number_;
}
@@ -131,30 +114,31 @@ void CodeEntry::SetBuiltinId(Builtins::Name id) {
int CodeEntry::GetSourceLine(int pc_offset) const {
- if (line_info_ && !line_info_->empty()) {
- return line_info_->GetSourceLineNumber(pc_offset);
- }
+ if (line_info_) return line_info_->GetSourceLineNumber(pc_offset);
return v8::CpuProfileNode::kNoLineNumberInfo;
}
-void CodeEntry::AddInlineStack(int pc_offset,
- std::vector inline_stack) {
- inline_locations_.insert(std::make_pair(pc_offset, std::move(inline_stack)));
+void CodeEntry::AddInlineStack(
+ int pc_offset, std::vector> inline_stack) {
+ EnsureRareData()->inline_locations_.insert(
+ std::make_pair(pc_offset, std::move(inline_stack)));
}
-const std::vector* CodeEntry::GetInlineStack(int pc_offset) const {
- auto it = inline_locations_.find(pc_offset);
- return it != inline_locations_.end() ? &it->second : NULL;
+const std::vector>* CodeEntry::GetInlineStack(
+ int pc_offset) const {
+ if (!rare_data_) return nullptr;
+ auto it = rare_data_->inline_locations_.find(pc_offset);
+ return it != rare_data_->inline_locations_.end() ? &it->second : nullptr;
}
-void CodeEntry::AddDeoptInlinedFrames(
- int deopt_id, std::vector inlined_frames) {
- deopt_inlined_frames_.insert(
- std::make_pair(deopt_id, std::move(inlined_frames)));
-}
-
-bool CodeEntry::HasDeoptInlinedFramesFor(int deopt_id) const {
- return deopt_inlined_frames_.find(deopt_id) != deopt_inlined_frames_.end();
+void CodeEntry::set_deopt_info(
+ const char* deopt_reason, int deopt_id,
+ std::vector inlined_frames) {
+ DCHECK(!has_deopt_info());
+ RareData* rare_data = EnsureRareData();
+ rare_data->deopt_reason_ = deopt_reason;
+ rare_data->deopt_id_ = deopt_id;
+ rare_data->deopt_inlined_frames_ = std::move(inlined_frames);
}
void CodeEntry::FillFunctionInfo(SharedFunctionInfo* shared) {
@@ -162,24 +146,32 @@ void CodeEntry::FillFunctionInfo(SharedFunctionInfo* shared) {
Script* script = Script::cast(shared->script());
set_script_id(script->id());
set_position(shared->start_position());
- set_bailout_reason(GetBailoutReason(shared->disable_optimization_reason()));
+ if (shared->optimization_disabled()) {
+ set_bailout_reason(GetBailoutReason(shared->disable_optimization_reason()));
+ }
}
CpuProfileDeoptInfo CodeEntry::GetDeoptInfo() {
DCHECK(has_deopt_info());
CpuProfileDeoptInfo info;
- info.deopt_reason = deopt_reason_;
- DCHECK_NE(kNoDeoptimizationId, deopt_id_);
- if (deopt_inlined_frames_.find(deopt_id_) == deopt_inlined_frames_.end()) {
+ info.deopt_reason = rare_data_->deopt_reason_;
+ DCHECK_NE(kNoDeoptimizationId, rare_data_->deopt_id_);
+ if (rare_data_->deopt_inlined_frames_.empty()) {
info.stack.push_back(CpuProfileDeoptFrame(
{script_id_, static_cast(std::max(0, position()))}));
} else {
- info.stack = deopt_inlined_frames_[deopt_id_];
+ info.stack = rare_data_->deopt_inlined_frames_;
}
return info;
}
+CodeEntry::RareData* CodeEntry::EnsureRareData() {
+ if (!rare_data_) {
+ rare_data_.reset(new RareData());
+ }
+ return rare_data_.get();
+}
void ProfileNode::CollectDeoptInfo(CodeEntry* entry) {
deopt_infos_.push_back(entry->GetDeoptInfo());
@@ -188,23 +180,21 @@ void ProfileNode::CollectDeoptInfo(CodeEntry* entry) {
ProfileNode* ProfileNode::FindChild(CodeEntry* entry) {
- base::HashMap::Entry* map_entry =
- children_.Lookup(entry, CodeEntryHash(entry));
- return map_entry != NULL ?
- reinterpret_cast(map_entry->value) : NULL;
+ auto map_entry = children_.find(entry);
+ return map_entry != children_.end() ? map_entry->second : nullptr;
}
ProfileNode* ProfileNode::FindOrAddChild(CodeEntry* entry) {
- base::HashMap::Entry* map_entry =
- children_.LookupOrInsert(entry, CodeEntryHash(entry));
- ProfileNode* node = reinterpret_cast(map_entry->value);
- if (!node) {
- node = new ProfileNode(tree_, entry, this);
- map_entry->value = node;
+ auto map_entry = children_.find(entry);
+ if (map_entry == children_.end()) {
+ ProfileNode* node = new ProfileNode(tree_, entry, this);
+ children_[entry] = node;
children_list_.push_back(node);
+ return node;
+ } else {
+ return map_entry->second;
}
- return node;
}
@@ -212,10 +202,12 @@ void ProfileNode::IncrementLineTicks(int src_line) {
if (src_line == v8::CpuProfileNode::kNoLineNumberInfo) return;
// Increment a hit counter of a certain source line.
// Add a new source line if not found.
- base::HashMap::Entry* e =
- line_ticks_.LookupOrInsert(reinterpret_cast(src_line), src_line);
- DCHECK(e);
- e->value = reinterpret_cast(reinterpret_cast(e->value) + 1);
+ auto map_entry = line_ticks_.find(src_line);
+ if (map_entry == line_ticks_.end()) {
+ line_ticks_[src_line] = 1;
+ } else {
+ line_ticks_[src_line]++;
+ }
}
@@ -223,19 +215,16 @@ bool ProfileNode::GetLineTicks(v8::CpuProfileNode::LineTick* entries,
unsigned int length) const {
if (entries == NULL || length == 0) return false;
- unsigned line_count = line_ticks_.occupancy();
+ unsigned line_count = static_cast(line_ticks_.size());
if (line_count == 0) return true;
if (length < line_count) return false;
v8::CpuProfileNode::LineTick* entry = entries;
- for (base::HashMap::Entry *p = line_ticks_.Start(); p != NULL;
- p = line_ticks_.Next(p), entry++) {
- entry->line =
- static_cast(reinterpret_cast(p->key));
- entry->hit_count =
- static_cast(reinterpret_cast(p->value));
+ for (auto p = line_ticks_.begin(); p != line_ticks_.end(); p++, entry++) {
+ entry->line = p->first;
+ entry->hit_count = p->second;
}
return true;
@@ -243,9 +232,8 @@ bool ProfileNode::GetLineTicks(v8::CpuProfileNode::LineTick* entries,
void ProfileNode::Print(int indent) {
- base::OS::Print("%5u %*s %s%s %d #%d", self_ticks_, indent, "",
- entry_->name_prefix(), entry_->name(), entry_->script_id(),
- id());
+ base::OS::Print("%5u %*s %s %d #%d", self_ticks_, indent, "", entry_->name(),
+ entry_->script_id(), id());
if (entry_->resource_name()[0] != '\0')
base::OS::Print(" %s:%d", entry_->resource_name(), entry_->line_number());
base::OS::Print("\n");
@@ -268,9 +256,8 @@ void ProfileNode::Print(int indent) {
base::OS::Print("%*s bailed out due to '%s'\n", indent + 10, "",
bailout_reason);
}
- for (base::HashMap::Entry* p = children_.Start(); p != NULL;
- p = children_.Next(p)) {
- reinterpret_cast(p->value)->Print(indent + 2);
+ for (auto child : children_) {
+ child.second->Print(indent + 2);
}
}
@@ -291,8 +278,7 @@ ProfileTree::ProfileTree(Isolate* isolate)
next_node_id_(1),
root_(new ProfileNode(this, &root_entry_, nullptr)),
isolate_(isolate),
- next_function_id_(1),
- function_ids_(ProfileNode::CodeEntriesMatch) {}
+ next_function_id_(1) {}
ProfileTree::~ProfileTree() {
DeleteNodesCallback cb;
@@ -302,12 +288,11 @@ ProfileTree::~ProfileTree() {
unsigned ProfileTree::GetFunctionId(const ProfileNode* node) {
CodeEntry* code_entry = node->entry();
- base::HashMap::Entry* entry =
- function_ids_.LookupOrInsert(code_entry, code_entry->GetHash());
- if (!entry->value) {
- entry->value = reinterpret_cast(next_function_id_++);
+ auto map_entry = function_ids_.find(code_entry);
+ if (map_entry == function_ids_.end()) {
+ return function_ids_[code_entry] = next_function_id_++;
}
- return static_cast(reinterpret_cast(entry->value));
+ return function_ids_[code_entry];
}
ProfileNode* ProfileTree::AddPathFromEnd(const std::vector& path,
@@ -502,19 +487,29 @@ void CpuProfile::Print() {
top_down_.Print();
}
+CodeMap::CodeMap() = default;
+CodeMap::~CodeMap() = default;
+
void CodeMap::AddCode(Address addr, CodeEntry* entry, unsigned size) {
- DeleteAllCoveredCode(addr, addr + size);
- code_map_.insert({addr, CodeEntryInfo(entry, size)});
+ ClearCodesInRange(addr, addr + size);
+ code_map_.emplace(
+ addr, CodeEntryInfo{static_cast(code_entries_.size()), size});
+ code_entries_.push_back(std::unique_ptr(entry));
}
-void CodeMap::DeleteAllCoveredCode(Address start, Address end) {
+void CodeMap::ClearCodesInRange(Address start, Address end) {
auto left = code_map_.upper_bound(start);
if (left != code_map_.begin()) {
--left;
if (left->first + left->second.size <= start) ++left;
}
auto right = left;
- while (right != code_map_.end() && right->first < end) ++right;
+ for (; right != code_map_.end() && right->first < end; ++right) {
+ std::unique_ptr& entry = code_entries_[right->second.index];
+ if (!entry->used()) {
+ entry.reset();
+ }
+ }
code_map_.erase(left, right);
}
@@ -523,7 +518,10 @@ CodeEntry* CodeMap::FindEntry(Address addr) {
if (it == code_map_.begin()) return nullptr;
--it;
Address end_address = it->first + it->second.size;
- return addr < end_address ? it->second.entry : nullptr;
+ if (addr >= end_address) return nullptr;
+ CodeEntry* entry = code_entries_[it->second.index].get();
+ DCHECK(entry);
+ return entry;
}
void CodeMap::MoveCode(Address from, Address to) {
@@ -532,18 +530,20 @@ void CodeMap::MoveCode(Address from, Address to) {
if (it == code_map_.end()) return;
CodeEntryInfo info = it->second;
code_map_.erase(it);
- AddCode(to, info.entry, info.size);
+ DCHECK(from + info.size <= to || to + info.size <= from);
+ ClearCodesInRange(to, to + info.size);
+ code_map_.emplace(to, info);
}
void CodeMap::Print() {
- for (auto it = code_map_.begin(); it != code_map_.end(); ++it) {
- base::OS::Print("%p %5d %s\n", static_cast(it->first),
- it->second.size, it->second.entry->name());
+ for (const auto& pair : code_map_) {
+ base::OS::Print("%p %5d %s\n", reinterpret_cast(pair.first),
+ pair.second.size, code_entries_[pair.second.index]->name());
}
}
CpuProfilesCollection::CpuProfilesCollection(Isolate* isolate)
- : resource_names_(isolate->heap()),
+ : resource_names_(isolate->heap()->HashSeed()),
profiler_(nullptr),
current_profiles_semaphore_(1) {}
@@ -653,14 +653,15 @@ void ProfileGenerator::RecordTickSample(const TickSample& sample) {
// Don't use PC when in external callback code, as it can point
// inside callback's code, and we will erroneously report
// that a callback calls itself.
- entries.push_back(FindEntry(sample.external_callback_entry));
+ entries.push_back(
+ FindEntry(reinterpret_cast(sample.external_callback_entry)));
} else {
- CodeEntry* pc_entry = FindEntry(sample.pc);
+ CodeEntry* pc_entry = FindEntry(reinterpret_cast(sample.pc));
// If there is no pc_entry we're likely in native code.
// Find out, if top of stack was pointing inside a JS function
// meaning that we have encountered a frameless invocation.
if (!pc_entry && !sample.has_external_callback) {
- pc_entry = FindEntry(sample.tos);
+ pc_entry = FindEntry(reinterpret_cast(sample.tos));
}
// If pc is in the function code before it set up stack frame or after the
// frame was destroyed SafeStackFrameIterator incorrectly thinks that
@@ -698,11 +699,13 @@ void ProfileGenerator::RecordTickSample(const TickSample& sample) {
// Find out if the entry has an inlining stack associated.
int pc_offset =
static_cast(stack_pos - entry->instruction_start());
- const std::vector* inline_stack =
+ const std::vector>* inline_stack =
entry->GetInlineStack(pc_offset);
if (inline_stack) {
- entries.insert(entries.end(), inline_stack->rbegin(),
- inline_stack->rend());
+ std::transform(
+ inline_stack->rbegin(), inline_stack->rend(),
+ std::back_inserter(entries),
+ [=](const std::unique_ptr& ptr) { return ptr.get(); });
}
// Skip unresolved frames (e.g. internal frame) and get source line of
// the first JS caller.
@@ -736,10 +739,6 @@ void ProfileGenerator::RecordTickSample(const TickSample& sample) {
sample.update_stats);
}
-CodeEntry* ProfileGenerator::FindEntry(void* address) {
- return code_map_.FindEntry(reinterpret_cast(address));
-}
-
CodeEntry* ProfileGenerator::EntryForVMState(StateTag tag) {
switch (tag) {
case GC:
diff --git a/deps/v8/src/profiler/profile-generator.h b/deps/v8/src/profiler/profile-generator.h
index ddd34b00a47e4b..db148018e41426 100644
--- a/deps/v8/src/profiler/profile-generator.h
+++ b/deps/v8/src/profiler/profile-generator.h
@@ -5,9 +5,14 @@
#ifndef V8_PROFILER_PROFILE_GENERATOR_H_
#define V8_PROFILER_PROFILE_GENERATOR_H_
+#include
#include