diff --git a/deps/v8/include/v8-profiler.h b/deps/v8/include/v8-profiler.h index 2363f0514778f0..ba81a8b7d165a1 100644 --- a/deps/v8/include/v8-profiler.h +++ b/deps/v8/include/v8-profiler.h @@ -273,6 +273,16 @@ class V8_EXPORT CpuProfile { void Delete(); }; +enum CpuProfilingMode { + // In the resulting CpuProfile tree, intermediate nodes in a stack trace + // (from the root to a leaf) will have line numbers that point to the start + // line of the function, rather than the line of the callsite of the child. + kLeafNodeLineNumbers, + // In the resulting CpuProfile tree, nodes are separated based on the line + // number of their callsite in their parent. + kCallerLineNumbers, +}; + /** * Interface for controlling CPU profiling. Instance of the * profiler can be created using v8::CpuProfiler::New method. @@ -309,6 +319,13 @@ class V8_EXPORT CpuProfiler { * |record_samples| parameter controls whether individual samples should * be recorded in addition to the aggregated tree. */ + void StartProfiling(Local title, CpuProfilingMode mode, + bool record_samples = false); + /** + * The same as StartProfiling above, but the CpuProfilingMode defaults to + * kLeafNodeLineNumbers mode, which was the previous default behavior of the + * profiler. + */ void StartProfiling(Local title, bool record_samples = false); /** diff --git a/deps/v8/include/v8-version.h b/deps/v8/include/v8-version.h index 890a67c8446d40..f2531abb21f0aa 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 67 +#define V8_PATCH_LEVEL 68 // 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 b22c75704e0f7f..bc5848e939420a 100644 --- a/deps/v8/src/api.cc +++ b/deps/v8/src/api.cc @@ -8418,7 +8418,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); } @@ -10138,15 +10138,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; } @@ -10237,7 +10229,7 @@ const char* CpuProfileNode::GetScriptResourceNameStr() const { } int CpuProfileNode::GetLineNumber() const { - return reinterpret_cast(this)->entry()->line_number(); + return reinterpret_cast(this)->line_number(); } @@ -10370,9 +10362,14 @@ void CpuProfiler::CollectSample() { void CpuProfiler::StartProfiling(Local title, bool record_samples) { reinterpret_cast(this)->StartProfiling( - *Utils::OpenHandle(*title), record_samples); + *Utils::OpenHandle(*title), record_samples, kLeafNodeLineNumbers); } +void CpuProfiler::StartProfiling(Local title, CpuProfilingMode mode, + bool record_samples) { + reinterpret_cast(this)->StartProfiling( + *Utils::OpenHandle(*title), record_samples, mode); +} CpuProfile* CpuProfiler::StopProfiling(Local title) { return reinterpret_cast( diff --git a/deps/v8/src/code-events.h b/deps/v8/src/code-events.h index ca92e2b5e4e624..f26d6327b5cd0d 100644 --- a/deps/v8/src/code-events.h +++ b/deps/v8/src/code-events.h @@ -101,7 +101,7 @@ class CodeEventListener { virtual void GetterCallbackEvent(Name* name, Address entry_point) = 0; virtual void SetterCallbackEvent(Name* name, Address entry_point) = 0; virtual void RegExpCodeCreateEvent(AbstractCode* code, String* source) = 0; - virtual void CodeMoveEvent(AbstractCode* from, Address to) = 0; + virtual void CodeMoveEvent(AbstractCode* from, AbstractCode* to) = 0; virtual void SharedFunctionInfoMoveEvent(Address from, Address to) = 0; virtual void CodeMovingGCEvent() = 0; virtual void CodeDisableOptEvent(AbstractCode* code, @@ -163,7 +163,7 @@ class CodeEventDispatcher { void RegExpCodeCreateEvent(AbstractCode* code, String* source) { CODE_EVENT_DISPATCH(RegExpCodeCreateEvent(code, source)); } - void CodeMoveEvent(AbstractCode* from, Address to) { + void CodeMoveEvent(AbstractCode* from, AbstractCode* to) { CODE_EVENT_DISPATCH(CodeMoveEvent(from, to)); } void SharedFunctionInfoMoveEvent(Address from, Address to) { diff --git a/deps/v8/src/compilation-info.cc b/deps/v8/src/compilation-info.cc index f4566d29bdb328..b639def60f2766 100644 --- a/deps/v8/src/compilation-info.cc +++ b/deps/v8/src/compilation-info.cc @@ -51,7 +51,7 @@ CompilationInfo::CompilationInfo(Zone* zone, Isolate* isolate, // Collect source positions for optimized code when profiling or if debugger // is active, to be able to get more precise source positions at the price of // more memory consumption. - if (isolate_->NeedsSourcePositionsForProfiling()) { + if (isolate_->NeedsDetailedOptimizedCodeLineInfo()) { MarkAsSourcePositionsEnabled(); } } diff --git a/deps/v8/src/flag-definitions.h b/deps/v8/src/flag-definitions.h index bcb5a2c982b5a7..7fc25bcc91b66e 100644 --- a/deps/v8/src/flag-definitions.h +++ b/deps/v8/src/flag-definitions.h @@ -1082,6 +1082,9 @@ DEFINE_BOOL(log_source_code, false, "Log source code.") DEFINE_BOOL(prof, false, "Log statistical profiling information (implies --log-code).") +DEFINE_BOOL(detailed_line_info, true, + "Always generate detailed line information for CPU profiling.") + #if defined(ANDROID) // Phones and tablets have processors that are much slower than desktop // and laptop computers for which current heuristics are tuned. diff --git a/deps/v8/src/heap/mark-compact.cc b/deps/v8/src/heap/mark-compact.cc index 194415e94979de..945c95e13622f5 100644 --- a/deps/v8/src/heap/mark-compact.cc +++ b/deps/v8/src/heap/mark-compact.cc @@ -1484,7 +1484,7 @@ class ProfilingMigrationObserver final : public MigrationObserver { int size) final { if (dest == CODE_SPACE || (dest == OLD_SPACE && dst->IsBytecodeArray())) { PROFILE(heap_->isolate(), - CodeMoveEvent(AbstractCode::cast(src), dst->address())); + CodeMoveEvent(AbstractCode::cast(src), AbstractCode::cast(dst))); } heap_->OnMoveEvent(dst, src, size); } diff --git a/deps/v8/src/isolate.cc b/deps/v8/src/isolate.cc index 02f7d1df64e288..bccd0cb0b880e3 100644 --- a/deps/v8/src/isolate.cc +++ b/deps/v8/src/isolate.cc @@ -2697,7 +2697,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_ = @@ -2970,6 +2969,10 @@ bool Isolate::use_optimizer() { !is_precise_count_code_coverage() && !is_block_count_code_coverage(); } +bool Isolate::NeedsDetailedOptimizedCodeLineInfo() const { + return NeedsSourcePositionsForProfiling() || FLAG_detailed_line_info; +} + bool Isolate::NeedsSourcePositionsForProfiling() const { return FLAG_trace_deopt || FLAG_trace_turbo || FLAG_trace_turbo_graph || FLAG_turbo_profiling || FLAG_perf_prof || is_profiling() || @@ -3694,6 +3697,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..a98b6bc0eca4e5 100644 --- a/deps/v8/src/isolate.h +++ b/deps/v8/src/isolate.h @@ -1019,6 +1019,8 @@ class Isolate { bool NeedsSourcePositionsForProfiling() const; + bool NeedsDetailedOptimizedCodeLineInfo() const; + bool is_best_effort_code_coverage() const { return code_coverage_mode() == debug::Coverage::kBestEffort; } @@ -1449,7 +1451,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..591338da9aacb2 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" @@ -218,7 +217,7 @@ class PerfBasicLogger : public CodeEventLogger { PerfBasicLogger(); ~PerfBasicLogger() override; - void CodeMoveEvent(AbstractCode* from, Address to) override {} + void CodeMoveEvent(AbstractCode* from, AbstractCode* to) override {} void CodeDisableOptEvent(AbstractCode* code, SharedFunctionInfo* shared) override {} @@ -287,7 +286,7 @@ class LowLevelLogger : public CodeEventLogger { explicit LowLevelLogger(const char* file_name); ~LowLevelLogger() override; - void CodeMoveEvent(AbstractCode* from, Address to) override; + void CodeMoveEvent(AbstractCode* from, AbstractCode* to) override; void CodeDisableOptEvent(AbstractCode* code, SharedFunctionInfo* shared) override {} void SnapshotPositionEvent(HeapObject* obj, int pos); @@ -393,11 +392,10 @@ void LowLevelLogger::LogRecordedBuffer(AbstractCode* code, SharedFunctionInfo*, code->instruction_size()); } -void LowLevelLogger::CodeMoveEvent(AbstractCode* from, Address to) { +void LowLevelLogger::CodeMoveEvent(AbstractCode* from, AbstractCode* to) { CodeMoveStruct event; event.from_address = from->instruction_start(); - size_t header_size = from->instruction_start() - from->address(); - event.to_address = to + header_size; + event.to_address = to->instruction_start(); LogWriteStruct(event); } @@ -419,7 +417,7 @@ class JitLogger : public CodeEventLogger { public: explicit JitLogger(JitCodeEventHandler code_event_handler); - void CodeMoveEvent(AbstractCode* from, Address to) override; + void CodeMoveEvent(AbstractCode* from, AbstractCode* to) override; void CodeDisableOptEvent(AbstractCode* code, SharedFunctionInfo* shared) override {} void AddCodeLinePosInfoEvent(void* jit_handler_data, int pc_offset, @@ -460,19 +458,14 @@ void JitLogger::LogRecordedBuffer(AbstractCode* code, code_event_handler_(&event); } -void JitLogger::CodeMoveEvent(AbstractCode* from, Address to) { +void JitLogger::CodeMoveEvent(AbstractCode* from, AbstractCode* to) { base::LockGuard guard(&logger_mutex_); JitCodeEvent event; event.type = JitCodeEvent::CODE_MOVED; - event.code_start = from->instruction_start(); + event.code_start = reinterpret_cast(from->instruction_start()); event.code_len = from->instruction_size(); - - // Calculate the header size. - const size_t header_size = from->instruction_start() - from->address(); - - // Calculate the new start address of the instructions. - event.new_code_start = to + header_size; + event.new_code_start = reinterpret_cast(to->instruction_start()); code_event_handler_(&event); } @@ -739,7 +732,6 @@ Logger::Logger(Isolate* isolate) perf_jit_logger_(NULL), ll_logger_(NULL), jit_logger_(NULL), - listeners_(5), is_initialized_(false) {} Logger::~Logger() { @@ -1297,9 +1289,10 @@ void Logger::RegExpCodeCreateEvent(AbstractCode* code, String* source) { msg.WriteToLogFile(); } -void Logger::CodeMoveEvent(AbstractCode* from, Address to) { +void Logger::CodeMoveEvent(AbstractCode* from, AbstractCode* to) { if (!is_logging_code_events()) return; - MoveEventInternal(CodeEventListener::CODE_MOVE_EVENT, from->address(), to); + MoveEventInternal(CodeEventListener::CODE_MOVE_EVENT, from->address(), + to->address()); } void Logger::CodeLinePosInfoRecordEvent(AbstractCode* code, @@ -1876,8 +1869,6 @@ bool Logger::SetUp(Isolate* isolate) { profiler_->Engage(); } - profiler_listener_.reset(); - if (is_logging_) { addCodeEventListener(this); } @@ -1905,19 +1896,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 +1939,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..931227a1453c2e 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. @@ -177,7 +168,7 @@ class Logger : public CodeEventListener { // Emits a code create event for a RegExp. void RegExpCodeCreateEvent(AbstractCode* code, String* source); // Emits a code move event. - void CodeMoveEvent(AbstractCode* from, Address to); + void CodeMoveEvent(AbstractCode* from, AbstractCode* to); // Emits a code line info record event. void CodeLinePosInfoRecordEvent(AbstractCode* code, ByteArray* source_position_table); @@ -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; @@ -400,7 +389,6 @@ class CodeEventLogger : public CodeEventListener { NameBuffer* name_buffer_; }; - } // namespace internal } // namespace v8 diff --git a/deps/v8/src/perf-jit.cc b/deps/v8/src/perf-jit.cc index 46597a968588c4..5ca1c2ba917a49 100644 --- a/deps/v8/src/perf-jit.cc +++ b/deps/v8/src/perf-jit.cc @@ -376,7 +376,7 @@ void PerfJitLogger::LogWriteUnwindingInfo(Code* code) { LogWriteBytes(padding_bytes, static_cast(padding_size)); } -void PerfJitLogger::CodeMoveEvent(AbstractCode* from, Address to) { +void PerfJitLogger::CodeMoveEvent(AbstractCode* from, AbstractCode* to) { // Code relocation not supported. UNREACHABLE(); } diff --git a/deps/v8/src/perf-jit.h b/deps/v8/src/perf-jit.h index 2b0b4831e0c43d..f68595f29ea6ff 100644 --- a/deps/v8/src/perf-jit.h +++ b/deps/v8/src/perf-jit.h @@ -41,7 +41,7 @@ class PerfJitLogger : public CodeEventLogger { PerfJitLogger(); virtual ~PerfJitLogger(); - void CodeMoveEvent(AbstractCode* from, Address to) override; + void CodeMoveEvent(AbstractCode* from, AbstractCode* to) override; void CodeDisableOptEvent(AbstractCode* code, SharedFunctionInfo* shared) override {} @@ -113,7 +113,7 @@ class PerfJitLogger : public CodeEventLogger { // PerfJitLogger is only implemented on Linux class PerfJitLogger : public CodeEventLogger { public: - void CodeMoveEvent(AbstractCode* from, Address to) override { + void CodeMoveEvent(AbstractCode* from, AbstractCode* to) override { UNIMPLEMENTED(); } diff --git a/deps/v8/src/profiler/cpu-profiler-inl.h b/deps/v8/src/profiler/cpu-profiler-inl.h index 440c6a1cce189b..2beb6f5aab2a94 100644 --- a/deps/v8/src/profiler/cpu-profiler-inl.h +++ b/deps/v8/src/profiler/cpu-profiler-inl.h @@ -16,31 +16,35 @@ namespace v8 { namespace internal { void CodeCreateEventRecord::UpdateCodeMap(CodeMap* code_map) { - code_map->AddCode(start, entry, size); + code_map->AddCode(instruction_start, entry, instruction_size); } void CodeMoveEventRecord::UpdateCodeMap(CodeMap* code_map) { - code_map->MoveCode(from, to); + code_map->MoveCode(from_instruction_start, to_instruction_start); } void CodeDisableOptEventRecord::UpdateCodeMap(CodeMap* code_map) { - CodeEntry* entry = code_map->FindEntry(start); - if (entry != NULL) { + CodeEntry* entry = code_map->FindEntry(instruction_start); + if (entry != nullptr) { entry->set_bailout_reason(bailout_reason); } } void CodeDeoptEventRecord::UpdateCodeMap(CodeMap* code_map) { - CodeEntry* entry = code_map->FindEntry(start); - if (entry != NULL) entry->set_deopt_info(deopt_reason, deopt_id); + CodeEntry* entry = code_map->FindEntry(instruction_start); + 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; } void ReportBuiltinEventRecord::UpdateCodeMap(CodeMap* code_map) { - CodeEntry* entry = code_map->FindEntry(start); + CodeEntry* entry = code_map->FindEntry(instruction_start); if (!entry) { // Code objects for builtins should already have been added to the map but // some of them have been filtered out by CpuProfiler. diff --git a/deps/v8/src/profiler/cpu-profiler.cc b/deps/v8/src/profiler/cpu-profiler.cc index 80d488f12c527f..69021cee344eb2 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); } } @@ -298,20 +303,20 @@ void CpuProfiler::CollectSample() { } } -void CpuProfiler::StartProfiling(const char* title, bool record_samples) { - if (profiles_->StartProfiling(title, record_samples)) { +void CpuProfiler::StartProfiling(const char* title, bool record_samples, + ProfilingMode mode) { + if (profiles_->StartProfiling(title, record_samples, mode)) { TRACE_EVENT0("v8", "CpuProfiler::StartProfiling"); StartProcessorIfNotStarted(); } } - -void CpuProfiler::StartProfiling(String* title, bool record_samples) { - StartProfiling(profiles_->GetName(title), record_samples); +void CpuProfiler::StartProfiling(String* title, bool record_samples, + ProfilingMode mode) { + StartProfiling(profiles_->GetName(title), record_samples, mode); isolate_->debug()->feature_tracker()->Track(DebugFeatureTracker::kProfiler); } - void CpuProfiler::StartProcessorIfNotStarted() { if (processor_) { processor_->AddCurrentStack(isolate_); @@ -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_; } @@ -379,7 +385,7 @@ void CpuProfiler::LogBuiltins() { CodeEventsContainer evt_rec(CodeEventRecord::REPORT_BUILTIN); ReportBuiltinEventRecord* rec = &evt_rec.ReportBuiltinEventRecord_; Builtins::Name id = static_cast(i); - rec->start = builtins->builtin(id)->address(); + rec->instruction_start = builtins->builtin(id)->instruction_start(); rec->builtin_id = id; processor_->Enqueue(evt_rec); } diff --git a/deps/v8/src/profiler/cpu-profiler.h b/deps/v8/src/profiler/cpu-profiler.h index 5fd7fa14da1cab..2672c1b8961cf2 100644 --- a/deps/v8/src/profiler/cpu-profiler.h +++ b/deps/v8/src/profiler/cpu-profiler.h @@ -53,9 +53,9 @@ class CodeEventRecord { class CodeCreateEventRecord : public CodeEventRecord { public: - Address start; + Address instruction_start; CodeEntry* entry; - unsigned size; + unsigned instruction_size; INLINE(void UpdateCodeMap(CodeMap* code_map)); }; @@ -63,8 +63,8 @@ class CodeCreateEventRecord : public CodeEventRecord { class CodeMoveEventRecord : public CodeEventRecord { public: - Address from; - Address to; + Address from_instruction_start; + Address to_instruction_start; INLINE(void UpdateCodeMap(CodeMap* code_map)); }; @@ -72,7 +72,7 @@ class CodeMoveEventRecord : public CodeEventRecord { class CodeDisableOptEventRecord : public CodeEventRecord { public: - Address start; + Address instruction_start; const char* bailout_reason; INLINE(void UpdateCodeMap(CodeMap* code_map)); @@ -81,11 +81,13 @@ class CodeDisableOptEventRecord : public CodeEventRecord { class CodeDeoptEventRecord : public CodeEventRecord { public: - Address start; + Address instruction_start; const char* deopt_reason; int deopt_id; void* pc; int fp_to_sp_delta; + CpuProfileDeoptFrame* deopt_frames; + int deopt_frame_count; INLINE(void UpdateCodeMap(CodeMap* code_map)); }; @@ -93,7 +95,7 @@ class CodeDeoptEventRecord : public CodeEventRecord { class ReportBuiltinEventRecord : public CodeEventRecord { public: - Address start; + Address instruction_start; Builtins::Name builtin_id; INLINE(void UpdateCodeMap(CodeMap* code_map)); @@ -195,10 +197,13 @@ class CpuProfiler : public CodeEventObserver { ~CpuProfiler() override; + typedef v8::CpuProfilingMode ProfilingMode; + void set_sampling_interval(base::TimeDelta value); void CollectSample(); - void StartProfiling(const char* title, bool record_samples = false); - void StartProfiling(String* title, bool record_samples); + void StartProfiling(const char* title, bool record_samples = false, + ProfilingMode mode = ProfilingMode::kLeafNodeLineNumbers); + void StartProfiling(String* title, bool record_samples, ProfilingMode mode); CpuProfile* StopProfiling(const char* title); CpuProfile* StopProfiling(String* title); int GetProfilesCount(); @@ -214,6 +219,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 +236,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 +246,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..31652ba9f98e83 100644 --- a/deps/v8/src/profiler/profile-generator-inl.h +++ b/deps/v8/src/profiler/profile-generator-inl.h @@ -11,33 +11,35 @@ 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) + ProfileNode* parent, int line_number) : tree_(tree), entry_(entry), self_ticks_(0), - children_(CodeEntriesMatch), + line_number_(line_number), 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..c01904b77801b1 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,49 +146,53 @@ 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()); entry->clear_deopt_info(); } - -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; +ProfileNode* ProfileNode::FindChild(CodeEntry* entry, int line_number) { + auto map_entry = children_.find({entry, line_number}); + 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; +ProfileNode* ProfileNode::FindOrAddChild(CodeEntry* entry, int line_number) { + auto map_entry = children_.find({entry, line_number}); + if (map_entry == children_.end()) { + ProfileNode* node = new ProfileNode(tree_, entry, this, line_number); + children_[{entry, line_number}] = node; children_list_.push_back(node); + return node; + } else { + return map_entry->second; } - return node; } @@ -212,10 +200,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 +213,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 +230,9 @@ 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()); + int line_number = line_number_ != 0 ? line_number_ : entry_->line_number(); + base::OS::Print("%5u %*s %s:%d %d #%d", self_ticks_, indent, "", + entry_->name(), line_number, 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 +255,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 +277,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 +287,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, @@ -317,7 +301,33 @@ ProfileNode* ProfileTree::AddPathFromEnd(const std::vector& path, for (auto it = path.rbegin(); it != path.rend(); ++it) { if (*it == NULL) continue; last_entry = *it; - node = node->FindOrAddChild(*it); + node = node->FindOrAddChild(*it, v8::CpuProfileNode::kNoLineNumberInfo); + } + if (last_entry && last_entry->has_deopt_info()) { + node->CollectDeoptInfo(last_entry); + } + if (update_stats) { + node->IncrementSelfTicks(); + if (src_line != v8::CpuProfileNode::kNoLineNumberInfo) { + node->IncrementLineTicks(src_line); + } + } + return node; +} + +ProfileNode* ProfileTree::AddPathFromEnd(const ProfileStackTrace& path, + int src_line, bool update_stats, + ProfilingMode mode) { + ProfileNode* node = root_; + CodeEntry* last_entry = nullptr; + int parent_line_number = v8::CpuProfileNode::kNoLineNumberInfo; + for (auto it = path.rbegin(); it != path.rend(); ++it) { + if ((*it).code_entry == nullptr) continue; + last_entry = (*it).code_entry; + node = node->FindOrAddChild((*it).code_entry, parent_line_number); + parent_line_number = mode == ProfilingMode::kCallerLineNumbers + ? (*it).line_number + : v8::CpuProfileNode::kNoLineNumberInfo; } if (last_entry && last_entry->has_deopt_info()) { node->CollectDeoptInfo(last_entry); @@ -384,9 +394,10 @@ void ProfileTree::TraverseDepthFirst(Callback* callback) { using v8::tracing::TracedValue; CpuProfile::CpuProfile(CpuProfiler* profiler, const char* title, - bool record_samples) + bool record_samples, ProfilingMode mode) : title_(title), record_samples_(record_samples), + mode_(mode), start_time_(base::TimeTicks::HighResolutionNow()), top_down_(profiler->isolate()), profiler_(profiler), @@ -399,14 +410,16 @@ CpuProfile::CpuProfile(CpuProfiler* profiler, const char* title, } void CpuProfile::AddPath(base::TimeTicks timestamp, - const std::vector& path, int src_line, + const ProfileStackTrace& path, int src_line, bool update_stats) { ProfileNode* top_frame_node = - top_down_.AddPathFromEnd(path, src_line, update_stats); + top_down_.AddPathFromEnd(path, src_line, update_stats, mode_); + if (record_samples_ && !timestamp.IsNull()) { timestamps_.Add(timestamp); samples_.Add(top_frame_node); } + const int kSamplesFlushCount = 100; const int kNodesFlushCount = 10; if (samples_.length() - streaming_next_sample_ >= kSamplesFlushCount || @@ -502,19 +515,40 @@ void CpuProfile::Print() { top_down_.Print(); } +CodeMap::CodeMap() = default; + +CodeMap::~CodeMap() { + // First clean the free list as it's otherwise impossible to tell + // the slot type. + unsigned free_slot = free_list_head_; + while (free_slot != kNoFreeSlot) { + unsigned next_slot = code_entries_[free_slot].next_free_slot; + code_entries_[free_slot].entry = nullptr; + free_slot = next_slot; + } + for (auto slot : code_entries_) delete slot.entry; +} + void CodeMap::AddCode(Address addr, CodeEntry* entry, unsigned size) { - DeleteAllCoveredCode(addr, addr + size); - code_map_.insert({addr, CodeEntryInfo(entry, size)}); + ClearCodesInRange(addr, addr + size); + unsigned index = AddCodeEntry(addr, entry); + code_map_.emplace(addr, CodeEntryMapInfo{index, size}); + DCHECK(entry->instruction_start() == kNullAddress || + addr == entry->instruction_start()); } -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) { + if (!entry(right->second.index)->used()) { + DeleteCodeEntry(right->second.index); + } + } code_map_.erase(left, right); } @@ -522,28 +556,56 @@ CodeEntry* CodeMap::FindEntry(Address addr) { auto it = code_map_.upper_bound(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; + Address start_address = it->first; + Address end_address = start_address + it->second.size; + CodeEntry* ret = addr < end_address ? entry(it->second.index) : nullptr; + if (ret && ret->instruction_start() != nullptr) { + DCHECK_EQ(start_address, ret->instruction_start()); + DCHECK(addr >= start_address && addr < end_address); + } + return ret; } void CodeMap::MoveCode(Address from, Address to) { if (from == to) return; auto it = code_map_.find(from); if (it == code_map_.end()) return; - CodeEntryInfo info = it->second; + CodeEntryMapInfo 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); + + CodeEntry* entry = code_entries_[info.index].entry; + entry->set_instruction_start(to); +} + +unsigned CodeMap::AddCodeEntry(Address start, CodeEntry* entry) { + if (free_list_head_ == kNoFreeSlot) { + code_entries_.push_back(CodeEntrySlotInfo{entry}); + return static_cast(code_entries_.size()) - 1; + } + unsigned index = free_list_head_; + free_list_head_ = code_entries_[index].next_free_slot; + code_entries_[index].entry = entry; + return index; +} + +void CodeMap::DeleteCodeEntry(unsigned index) { + delete code_entries_[index].entry; + code_entries_[index].next_free_slot = free_list_head_; + free_list_head_ = index; } 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, entry(pair.second.index)->name()); } } CpuProfilesCollection::CpuProfilesCollection(Isolate* isolate) - : resource_names_(isolate->heap()), + : resource_names_(isolate->heap()->HashSeed()), profiler_(nullptr), current_profiles_semaphore_(1) {} @@ -559,7 +621,8 @@ CpuProfilesCollection::~CpuProfilesCollection() { bool CpuProfilesCollection::StartProfiling(const char* title, - bool record_samples) { + bool record_samples, + ProfilingMode mode) { current_profiles_semaphore_.Wait(); if (current_profiles_.length() >= kMaxSimultaneousProfiles) { current_profiles_semaphore_.Signal(); @@ -573,7 +636,7 @@ bool CpuProfilesCollection::StartProfiling(const char* title, return true; } } - current_profiles_.Add(new CpuProfile(profiler_, title, record_samples)); + current_profiles_.Add(new CpuProfile(profiler_, title, record_samples, mode)); current_profiles_semaphore_.Signal(); return true; } @@ -619,8 +682,8 @@ void CpuProfilesCollection::RemoveProfile(CpuProfile* profile) { } void CpuProfilesCollection::AddPathToCurrentProfiles( - base::TimeTicks timestamp, const std::vector& path, - int src_line, bool update_stats) { + base::TimeTicks timestamp, const ProfileStackTrace& path, int src_line, + bool update_stats) { // As starting / stopping profiles is rare relatively to this // method, we don't bother minimizing the duration of lock holding, // e.g. copying contents of the list to a local vector. @@ -635,46 +698,52 @@ ProfileGenerator::ProfileGenerator(CpuProfilesCollection* profiles) : profiles_(profiles) {} void ProfileGenerator::RecordTickSample(const TickSample& sample) { - std::vector entries; + ProfileStackTrace stack_trace; // Conservatively reserve space for stack frames + pc + function + vm-state. // There could in fact be more of them because of inlined entries. - entries.reserve(sample.frames_count + 3); + stack_trace.reserve(sample.frames_count + 3); // The ProfileNode knows nothing about all versions of generated code for // the same JS function. The line number information associated with // the latest version of generated code is used to find a source line number // for a JS function. Then, the detected source line is passed to // ProfileNode to increase the tick count for this source line. - int src_line = v8::CpuProfileNode::kNoLineNumberInfo; + const int no_line_info = v8::CpuProfileNode::kNoLineNumberInfo; + int src_line = no_line_info; bool src_line_not_found = true; if (sample.pc != nullptr) { if (sample.has_external_callback && sample.state == EXTERNAL) { // Don't use PC when in external callback code, as it can point - // inside callback's code, and we will erroneously report + // inside a callback's code, and we will erroneously report // that a callback calls itself. - entries.push_back(FindEntry(sample.external_callback_entry)); + stack_trace.push_back( + {FindEntry(reinterpret_cast
(sample.external_callback_entry)), + no_line_info}); } else { - CodeEntry* pc_entry = FindEntry(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. + Address attributed_pc = reinterpret_cast
(sample.pc); + CodeEntry* pc_entry = FindEntry(attributed_pc); + // If there is no pc_entry, we're likely in native code. Find out if the + // top of the stack (the return address) 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); + attributed_pc = reinterpret_cast
(sample.tos); + pc_entry = FindEntry(attributed_pc); } // If pc is in the function code before it set up stack frame or after the - // frame was destroyed SafeStackFrameIterator incorrectly thinks that - // ebp contains return address of the current function and skips caller's - // frame. Check for this case and just skip such samples. + // frame was destroyed, SafeStackFrameIterator incorrectly thinks that + // ebp contains the return address of the current function and skips the + // caller's frame. Check for this case and just skip such samples. if (pc_entry) { - int pc_offset = static_cast(reinterpret_cast
(sample.pc) - - pc_entry->instruction_start()); + int pc_offset = + static_cast(attributed_pc - pc_entry->instruction_start()); + DCHECK_GE(pc_offset, 0); src_line = pc_entry->GetSourceLine(pc_offset); if (src_line == v8::CpuProfileNode::kNoLineNumberInfo) { src_line = pc_entry->line_number(); } src_line_not_found = false; - entries.push_back(pc_entry); + stack_trace.push_back({pc_entry, src_line}); if (pc_entry->builtin_id() == Builtins::kFunctionPrototypeApply || pc_entry->builtin_id() == Builtins::kFunctionPrototypeCall) { @@ -685,7 +754,8 @@ void ProfileGenerator::RecordTickSample(const TickSample& sample) { // former case we don't so we simply replace the frame with // 'unresolved' entry. if (!sample.has_external_callback) { - entries.push_back(CodeEntry::unresolved_entry()); + stack_trace.push_back( + {CodeEntry::unresolved_entry(), no_line_info}); } } } @@ -694,15 +764,21 @@ void ProfileGenerator::RecordTickSample(const TickSample& sample) { for (unsigned i = 0; i < sample.frames_count; ++i) { Address stack_pos = reinterpret_cast
(sample.stack[i]); CodeEntry* entry = FindEntry(stack_pos); + int line_number = no_line_info; if (entry) { // 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 = + DCHECK_GE(pc_offset, 0); + 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(stack_trace), + [=](const std::unique_ptr& ptr) { + return CodeEntryAndLineNumber{ptr.get(), no_line_info}; + }); } // Skip unresolved frames (e.g. internal frame) and get source line of // the first JS caller. @@ -713,33 +789,30 @@ void ProfileGenerator::RecordTickSample(const TickSample& sample) { } src_line_not_found = false; } + line_number = entry->GetSourceLine(pc_offset); } - entries.push_back(entry); + stack_trace.push_back({entry, line_number}); } } if (FLAG_prof_browser_mode) { bool no_symbolized_entries = true; - for (auto e : entries) { - if (e != NULL) { + for (auto e : stack_trace) { + if (e.code_entry != nullptr) { no_symbolized_entries = false; break; } } // If no frames were symbolized, put the VM state entry in. if (no_symbolized_entries) { - entries.push_back(EntryForVMState(sample.state)); + stack_trace.push_back({EntryForVMState(sample.state), no_line_info}); } } - profiles_->AddPathToCurrentProfiles(sample.timestamp, entries, src_line, + profiles_->AddPathToCurrentProfiles(sample.timestamp, stack_trace, src_line, 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..f5b8ef39f26e67 100644 --- a/deps/v8/src/profiler/profile-generator.h +++ b/deps/v8/src/profiler/profile-generator.h @@ -5,9 +5,16 @@ #ifndef V8_PROFILER_PROFILE_GENERATOR_H_ #define V8_PROFILER_PROFILE_GENERATOR_H_ +#include +#include #include +#include +#include +#include +#include + +#include "include/v8-profiler.h" #include "src/allocation.h" -#include "src/base/hashmap.h" #include "src/log.h" #include "src/profiler/strings-storage.h" #include "src/source-position.h" @@ -17,65 +24,71 @@ namespace internal { struct TickSample; -// Provides a mapping from the offsets within generated code to -// the source line. -class JITLineInfoTable : public Malloced { +// Provides a mapping from the offsets within generated code or a bytecode array +// to the source line. +class SourcePositionTable : public Malloced { public: - JITLineInfoTable(); - ~JITLineInfoTable(); + SourcePositionTable() = default; void SetPosition(int pc_offset, int line); int GetSourceLineNumber(int pc_offset) const; - bool empty() const { return pc_offset_map_.empty(); } - private: - // pc_offset -> source line - typedef std::map PcOffsetMap; - PcOffsetMap pc_offset_map_; - DISALLOW_COPY_AND_ASSIGN(JITLineInfoTable); + struct PCOffsetAndLineNumber { + bool operator<(const PCOffsetAndLineNumber& other) const { + return pc_offset < other.pc_offset; + } + int pc_offset; + int line_number; + }; + // This is logically a map, but we store it as a vector of pairs, sorted by + // the pc offset, so that we can save space and look up items using binary + // search. + std::vector pc_offsets_to_lines_; + DISALLOW_COPY_AND_ASSIGN(SourcePositionTable); }; - class CodeEntry { public: // CodeEntry doesn't own name strings, just references them. inline CodeEntry(CodeEventListener::LogEventsAndTags tag, const char* name, - const char* name_prefix = CodeEntry::kEmptyNamePrefix, const char* resource_name = CodeEntry::kEmptyResourceName, int line_number = v8::CpuProfileNode::kNoLineNumberInfo, int column_number = v8::CpuProfileNode::kNoColumnNumberInfo, - JITLineInfoTable* line_info = NULL, + std::unique_ptr line_info = nullptr, Address instruction_start = NULL); - ~CodeEntry(); - const char* name_prefix() const { return name_prefix_; } - bool has_name_prefix() const { return name_prefix_[0] != '\0'; } const char* name() const { return name_; } const char* resource_name() const { return resource_name_; } int line_number() const { return line_number_; } int column_number() const { return column_number_; } - const JITLineInfoTable* line_info() const { return line_info_; } + const SourcePositionTable* line_info() const { return line_info_.get(); } int script_id() const { return script_id_; } void set_script_id(int script_id) { script_id_ = script_id; } int position() const { return position_; } void set_position(int position) { position_ = position; } void set_bailout_reason(const char* bailout_reason) { - bailout_reason_ = bailout_reason; + EnsureRareData()->bailout_reason_ = bailout_reason; } - const char* bailout_reason() const { return bailout_reason_; } - - void set_deopt_info(const char* deopt_reason, int deopt_id) { - DCHECK(!has_deopt_info()); - deopt_reason_ = deopt_reason; - deopt_id_ = deopt_id; + const char* bailout_reason() const { + return rare_data_ ? rare_data_->bailout_reason_ : kEmptyBailoutReason; } + + void set_deopt_info(const char* deopt_reason, int deopt_id, + std::vector inlined_frames); + CpuProfileDeoptInfo GetDeoptInfo(); - bool has_deopt_info() const { return deopt_id_ != kNoDeoptimizationId; } + bool has_deopt_info() const { + return rare_data_ && rare_data_->deopt_id_ != kNoDeoptimizationId; + } void clear_deopt_info() { - deopt_reason_ = kNoDeoptReason; - deopt_id_ = kNoDeoptimizationId; + if (!rare_data_) return; + // TODO(alph): Clear rare_data_ if that was the only field in use. + 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_); } void FillFunctionInfo(SharedFunctionInfo* shared); @@ -85,22 +98,22 @@ class CodeEntry { } uint32_t GetHash() const; - bool IsSameFunctionAs(CodeEntry* entry) const; + bool IsSameFunctionAs(const CodeEntry* entry) const; int GetSourceLine(int pc_offset) const; - void AddInlineStack(int pc_offset, std::vector inline_stack); - const std::vector* GetInlineStack(int pc_offset) const; - - void AddDeoptInlinedFrames(int deopt_id, std::vector); - bool HasDeoptInlinedFramesFor(int deopt_id) const; + void AddInlineStack(int pc_offset, + std::vector> inline_stack); + const std::vector>* GetInlineStack( + int pc_offset) const; + void set_instruction_start(Address start) { instruction_start_ = start; } Address instruction_start() const { return instruction_start_; } + CodeEventListener::LogEventsAndTags tag() const { return TagField::decode(bit_field_); } - static const char* const kEmptyNamePrefix; static const char* const kEmptyResourceName; static const char* const kEmptyBailoutReason; static const char* const kNoDeoptReason; @@ -122,6 +135,17 @@ class CodeEntry { } private: + struct RareData { + const char* deopt_reason_ = kNoDeoptReason; + const char* bailout_reason_ = kEmptyBailoutReason; + int deopt_id_ = kNoDeoptimizationId; + std::unordered_map>> + inline_locations_; + std::vector deopt_inlined_frames_; + }; + + RareData* EnsureRareData(); + struct ProgramEntryCreateTrait { static CodeEntry* Create(); }; @@ -144,38 +168,42 @@ class CodeEntry { static base::LazyDynamicInstance::type kUnresolvedEntry; - class TagField : public BitField {}; - class BuiltinIdField : public BitField {}; + using TagField = BitField; + using BuiltinIdField = BitField; + using UsedField = BitField; uint32_t bit_field_; - const char* name_prefix_; const char* name_; const char* resource_name_; int line_number_; int column_number_; int script_id_; int position_; - const char* bailout_reason_; - const char* deopt_reason_; - int deopt_id_; - JITLineInfoTable* line_info_; + std::unique_ptr line_info_; Address instruction_start_; - // Should be an unordered_map, but it doesn't currently work on Win & MacOS. - std::map> inline_locations_; - std::map> deopt_inlined_frames_; + std::unique_ptr rare_data_; DISALLOW_COPY_AND_ASSIGN(CodeEntry); }; +struct CodeEntryAndLineNumber { + CodeEntry* code_entry; + int line_number; +}; + +typedef std::vector ProfileStackTrace; class ProfileTree; class ProfileNode { public: - inline ProfileNode(ProfileTree* tree, CodeEntry* entry, ProfileNode* parent); + inline ProfileNode(ProfileTree* tree, CodeEntry* entry, ProfileNode* parent, + int line_number = 0); - ProfileNode* FindChild(CodeEntry* entry); - ProfileNode* FindOrAddChild(CodeEntry* entry); + ProfileNode* FindChild( + CodeEntry* entry, + int line_number = v8::CpuProfileNode::kNoLineNumberInfo); + ProfileNode* FindOrAddChild(CodeEntry* entry, int line_number = 0); void IncrementSelfTicks() { ++self_ticks_; } void IncreaseSelfTicks(unsigned amount) { self_ticks_ += amount; } void IncrementLineTicks(int src_line); @@ -186,7 +214,13 @@ class ProfileNode { unsigned id() const { return id_; } unsigned function_id() const; ProfileNode* parent() const { return parent_; } - unsigned int GetHitLineCount() const { return line_ticks_.occupancy(); } + int line_number() const { + return line_number_ != 0 ? line_number_ : entry_->line_number(); + } + + unsigned int GetHitLineCount() const { + return static_cast(line_ticks_.size()); + } bool GetLineTicks(v8::CpuProfileNode::LineTick* entries, unsigned int length) const; void CollectDeoptInfo(CodeEntry* entry); @@ -197,25 +231,31 @@ class ProfileNode { void Print(int indent); - static bool CodeEntriesMatch(void* entry1, void* entry2) { - return reinterpret_cast(entry1) - ->IsSameFunctionAs(reinterpret_cast(entry2)); - } - private: - static uint32_t CodeEntryHash(CodeEntry* entry) { return entry->GetHash(); } - - static bool LineTickMatch(void* a, void* b) { return a == b; } + struct Equals { + bool operator()(CodeEntryAndLineNumber lhs, + CodeEntryAndLineNumber rhs) const { + return lhs.code_entry->IsSameFunctionAs(rhs.code_entry) && + lhs.line_number == rhs.line_number; + } + }; + struct Hasher { + std::size_t operator()(CodeEntryAndLineNumber pair) const { + return pair.code_entry->GetHash() ^ ComputeIntegerHash(pair.line_number); + } + }; ProfileTree* tree_; CodeEntry* entry_; unsigned self_ticks_; - // Mapping from CodeEntry* to ProfileNode* - base::CustomMatcherHashMap children_; + std::unordered_map + children_; + int line_number_; std::vector children_list_; ProfileNode* parent_; unsigned id_; - base::CustomMatcherHashMap line_ticks_; + // maps line number --> number of ticks + std::unordered_map line_ticks_; std::vector deopt_infos_; @@ -228,10 +268,17 @@ class ProfileTree { explicit ProfileTree(Isolate* isolate); ~ProfileTree(); + typedef v8::CpuProfilingMode ProfilingMode; + ProfileNode* AddPathFromEnd( const std::vector& path, int src_line = v8::CpuProfileNode::kNoLineNumberInfo, bool update_stats = true); + ProfileNode* AddPathFromEnd( + const ProfileStackTrace& path, + int src_line = v8::CpuProfileNode::kNoLineNumberInfo, + bool update_stats = true, + ProfilingMode mode = ProfilingMode::kLeafNodeLineNumbers); ProfileNode* root() const { return root_; } unsigned next_node_id() { return next_node_id_++; } unsigned GetFunctionId(const ProfileNode* node); @@ -260,7 +307,7 @@ class ProfileTree { Isolate* isolate_; unsigned next_function_id_; - base::CustomMatcherHashMap function_ids_; + std::unordered_map function_ids_; DISALLOW_COPY_AND_ASSIGN(ProfileTree); }; @@ -268,10 +315,13 @@ class ProfileTree { class CpuProfile { public: - CpuProfile(CpuProfiler* profiler, const char* title, bool record_samples); + typedef v8::CpuProfilingMode ProfilingMode; + + CpuProfile(CpuProfiler* profiler, const char* title, bool record_samples, + ProfilingMode mode); // Add pc -> ... -> main() call path to the profile. - void AddPath(base::TimeTicks timestamp, const std::vector& path, + void AddPath(base::TimeTicks timestamp, const ProfileStackTrace& path, int src_line, bool update_stats); void FinishProfile(); @@ -297,6 +347,7 @@ class CpuProfile { const char* title_; bool record_samples_; + ProfilingMode mode_; base::TimeTicks start_time_; base::TimeTicks end_time_; List samples_; @@ -310,7 +361,8 @@ class CpuProfile { class CodeMap { public: - CodeMap() {} + CodeMap(); + ~CodeMap(); void AddCode(Address addr, CodeEntry* entry, unsigned size); void MoveCode(Address from, Address to); @@ -318,16 +370,27 @@ class CodeMap { void Print(); private: - struct CodeEntryInfo { - CodeEntryInfo(CodeEntry* an_entry, unsigned a_size) - : entry(an_entry), size(a_size) { } - CodeEntry* entry; + struct CodeEntryMapInfo { + unsigned index; unsigned size; }; - void DeleteAllCoveredCode(Address start, Address end); + union CodeEntrySlotInfo { + CodeEntry* entry; + unsigned next_free_slot; + }; + + static constexpr unsigned kNoFreeSlot = std::numeric_limits::max(); + + void ClearCodesInRange(Address start, Address end); + unsigned AddCodeEntry(Address start, CodeEntry*); + void DeleteCodeEntry(unsigned index); - std::map code_map_; + CodeEntry* entry(unsigned index) { return code_entries_[index].entry; } + + std::deque code_entries_; + std::map code_map_; + unsigned free_list_head_ = kNoFreeSlot; DISALLOW_COPY_AND_ASSIGN(CodeMap); }; @@ -337,8 +400,11 @@ class CpuProfilesCollection { explicit CpuProfilesCollection(Isolate* isolate); ~CpuProfilesCollection(); + typedef v8::CpuProfilingMode ProfilingMode; + void set_cpu_profiler(CpuProfiler* profiler) { profiler_ = profiler; } - bool StartProfiling(const char* title, bool record_samples); + bool StartProfiling(const char* title, bool record_samples, + ProfilingMode mode = ProfilingMode::kLeafNodeLineNumbers); CpuProfile* StopProfiling(const char* title); List* profiles() { return &finished_profiles_; } const char* GetName(Name* name) { return resource_names_.GetName(name); } @@ -347,8 +413,8 @@ class CpuProfilesCollection { // Called from profile generator thread. void AddPathToCurrentProfiles(base::TimeTicks timestamp, - const std::vector& path, - int src_line, bool update_stats); + const ProfileStackTrace& path, int src_line, + bool update_stats); // Limits the number of profiles that can be simultaneously collected. static const int kMaxSimultaneousProfiles = 100; @@ -365,7 +431,6 @@ class CpuProfilesCollection { DISALLOW_COPY_AND_ASSIGN(CpuProfilesCollection); }; - class ProfileGenerator { public: explicit ProfileGenerator(CpuProfilesCollection* profiles); @@ -375,7 +440,7 @@ class ProfileGenerator { CodeMap* code_map() { return &code_map_; } private: - CodeEntry* FindEntry(void* address); + CodeEntry* FindEntry(Address address); CodeEntry* EntryForVMState(StateTag tag); CpuProfilesCollection* profiles_; @@ -384,7 +449,6 @@ class ProfileGenerator { DISALLOW_COPY_AND_ASSIGN(ProfileGenerator); }; - } // namespace internal } // namespace v8 diff --git a/deps/v8/src/profiler/profiler-listener.cc b/deps/v8/src/profiler/profiler-listener.cc index b90f5a4894fc76..0feb16dc875346 100644 --- a/deps/v8/src/profiler/profiler-listener.cc +++ b/deps/v8/src/profiler/profiler-listener.cc @@ -13,17 +13,20 @@ namespace v8 { namespace internal { -ProfilerListener::ProfilerListener(Isolate* isolate) - : function_and_resource_names_(isolate->heap()) {} +ProfilerListener::ProfilerListener(Isolate* isolate, + CodeEventObserver* observer) + : isolate_(isolate), + observer_(observer), + function_and_resource_names_(isolate->heap()->HashSeed()) {} ProfilerListener::~ProfilerListener() = default; void ProfilerListener::CallbackEvent(Name* name, Address entry_point) { CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION); CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_; - rec->start = entry_point; + rec->instruction_start = entry_point; rec->entry = NewCodeEntry(CodeEventListener::CALLBACK_TAG, GetName(name)); - rec->size = 1; + rec->instruction_size = 1; DispatchCodeEvent(evt_rec); } @@ -31,13 +34,13 @@ void ProfilerListener::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag, AbstractCode* code, const char* name) { CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION); CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_; - rec->start = code->address(); + rec->instruction_start = code->instruction_start(); rec->entry = NewCodeEntry( - tag, GetFunctionName(name), CodeEntry::kEmptyNamePrefix, + tag, GetFunctionName(name), CodeEntry::kEmptyResourceName, CpuProfileNode::kNoLineNumberInfo, - CpuProfileNode::kNoColumnNumberInfo, NULL, code->instruction_start()); + CpuProfileNode::kNoColumnNumberInfo, nullptr, code->instruction_start()); RecordInliningInfo(rec->entry, code); - rec->size = code->ExecutableSize(); + rec->instruction_size = code->instruction_size(); DispatchCodeEvent(evt_rec); } @@ -45,13 +48,13 @@ void ProfilerListener::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag, AbstractCode* code, Name* name) { CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION); CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_; - rec->start = code->address(); + rec->instruction_start = code->instruction_start(); rec->entry = NewCodeEntry( - tag, GetFunctionName(name), CodeEntry::kEmptyNamePrefix, + tag, GetFunctionName(name), CodeEntry::kEmptyResourceName, CpuProfileNode::kNoLineNumberInfo, - CpuProfileNode::kNoColumnNumberInfo, NULL, code->instruction_start()); + CpuProfileNode::kNoColumnNumberInfo, nullptr, code->instruction_start()); RecordInliningInfo(rec->entry, code); - rec->size = code->ExecutableSize(); + rec->instruction_size = code->instruction_size(); DispatchCodeEvent(evt_rec); } @@ -61,15 +64,15 @@ void ProfilerListener::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag, Name* script_name) { CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION); CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_; - rec->start = code->address(); + rec->instruction_start = code->instruction_start(); rec->entry = NewCodeEntry( - tag, GetFunctionName(shared->DebugName()), CodeEntry::kEmptyNamePrefix, + tag, GetFunctionName(shared->DebugName()), GetName(InferScriptName(script_name, shared)), CpuProfileNode::kNoLineNumberInfo, CpuProfileNode::kNoColumnNumberInfo, - NULL, code->instruction_start()); + nullptr, code->instruction_start()); RecordInliningInfo(rec->entry, code); rec->entry->FillFunctionInfo(shared); - rec->size = code->ExecutableSize(); + rec->instruction_size = code->instruction_size(); DispatchCodeEvent(evt_rec); } @@ -80,13 +83,11 @@ void ProfilerListener::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag, int column) { CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION); CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_; - rec->start = abstract_code->address(); - JITLineInfoTable* line_table = NULL; + rec->instruction_start = abstract_code->instruction_start(); + std::unique_ptr line_table; if (shared->script()->IsScript()) { Script* script = Script::cast(shared->script()); - line_table = new JITLineInfoTable(); - int offset = abstract_code->IsCode() ? Code::kHeaderSize - : BytecodeArray::kHeaderSize; + line_table.reset(new SourcePositionTable()); for (SourcePositionTableIterator it(abstract_code->source_position_table()); !it.done(); it.Advance()) { // TODO(alph,tebbi) Skipping inlined positions for now, because they might @@ -95,18 +96,16 @@ void ProfilerListener::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag, continue; int position = it.source_position().ScriptOffset(); int line_number = script->GetLineNumber(position) + 1; - int pc_offset = it.code_offset() + offset; - line_table->SetPosition(pc_offset, line_number); + line_table->SetPosition(it.code_offset(), line_number); } } - rec->entry = NewCodeEntry( - tag, GetFunctionName(shared->DebugName()), CodeEntry::kEmptyNamePrefix, - GetName(InferScriptName(script_name, shared)), line, column, line_table, - abstract_code->instruction_start()); + rec->entry = + NewCodeEntry(tag, GetFunctionName(shared->DebugName()), + GetName(InferScriptName(script_name, shared)), line, column, + std::move(line_table), abstract_code->instruction_start()); RecordInliningInfo(rec->entry, abstract_code); - RecordDeoptInlinedFrames(rec->entry, abstract_code); rec->entry->FillFunctionInfo(shared); - rec->size = abstract_code->ExecutableSize(); + rec->instruction_size = abstract_code->instruction_size(); DispatchCodeEvent(evt_rec); } @@ -114,21 +113,21 @@ void ProfilerListener::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag, AbstractCode* code, int args_count) { CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION); CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_; - rec->start = code->address(); + rec->instruction_start = code->instruction_start(); rec->entry = NewCodeEntry( - tag, GetName(args_count), "args_count: ", CodeEntry::kEmptyResourceName, + tag, GetName(args_count), CodeEntry::kEmptyResourceName, CpuProfileNode::kNoLineNumberInfo, CpuProfileNode::kNoColumnNumberInfo, - NULL, code->instruction_start()); + nullptr, code->instruction_start()); RecordInliningInfo(rec->entry, code); - rec->size = code->ExecutableSize(); + rec->instruction_size = code->instruction_size(); DispatchCodeEvent(evt_rec); } -void ProfilerListener::CodeMoveEvent(AbstractCode* from, Address to) { +void ProfilerListener::CodeMoveEvent(AbstractCode* from, AbstractCode* to) { CodeEventsContainer evt_rec(CodeEventRecord::CODE_MOVE); CodeMoveEventRecord* rec = &evt_rec.CodeMoveEventRecord_; - rec->from = from->address(); - rec->to = to; + rec->from_instruction_start = from->instruction_start(); + rec->to_instruction_start = to->instruction_start(); DispatchCodeEvent(evt_rec); } @@ -136,7 +135,7 @@ void ProfilerListener::CodeDisableOptEvent(AbstractCode* code, SharedFunctionInfo* shared) { CodeEventsContainer evt_rec(CodeEventRecord::CODE_DISABLE_OPT); CodeDisableOptEventRecord* rec = &evt_rec.CodeDisableOptEventRecord_; - rec->start = code->address(); + rec->instruction_start = code->instruction_start(); rec->bailout_reason = GetBailoutReason(shared->disable_optimization_reason()); DispatchCodeEvent(evt_rec); } @@ -146,21 +145,25 @@ void ProfilerListener::CodeDeoptEvent(Code* code, DeoptKind kind, Address pc, CodeEventsContainer evt_rec(CodeEventRecord::CODE_DEOPT); CodeDeoptEventRecord* rec = &evt_rec.CodeDeoptEventRecord_; Deoptimizer::DeoptInfo info = Deoptimizer::GetDeoptInfo(code, pc); - rec->start = code->address(); + rec->instruction_start = code->instruction_start(); rec->deopt_reason = DeoptimizeReasonToString(info.deopt_reason); rec->deopt_id = info.deopt_id; rec->pc = reinterpret_cast(pc); rec->fp_to_sp_delta = fp_to_sp_delta; + + // When a function is deoptimized, we store the deoptimized frame information + // for the use of GetDeoptInfos(). + AttachDeoptInlinedFrames(code, rec); DispatchCodeEvent(evt_rec); } void ProfilerListener::GetterCallbackEvent(Name* name, Address entry_point) { CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION); CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_; - rec->start = entry_point; + rec->instruction_start = entry_point; rec->entry = - NewCodeEntry(CodeEventListener::CALLBACK_TAG, GetName(name), "get "); - rec->size = 1; + NewCodeEntry(CodeEventListener::CALLBACK_TAG, GetConsName("get ", name)); + rec->instruction_size = 1; DispatchCodeEvent(evt_rec); } @@ -168,22 +171,22 @@ void ProfilerListener::RegExpCodeCreateEvent(AbstractCode* code, String* source) { CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION); CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_; - rec->start = code->address(); + rec->instruction_start = code->instruction_start(); rec->entry = NewCodeEntry( - CodeEventListener::REG_EXP_TAG, GetName(source), "RegExp: ", + CodeEventListener::REG_EXP_TAG, GetConsName("RegExp: ", source), CodeEntry::kEmptyResourceName, CpuProfileNode::kNoLineNumberInfo, - CpuProfileNode::kNoColumnNumberInfo, NULL, code->instruction_start()); - rec->size = code->ExecutableSize(); + CpuProfileNode::kNoColumnNumberInfo, nullptr, code->instruction_start()); + rec->instruction_size = code->instruction_size(); DispatchCodeEvent(evt_rec); } void ProfilerListener::SetterCallbackEvent(Name* name, Address entry_point) { CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION); CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_; - rec->start = entry_point; + rec->instruction_start = entry_point; rec->entry = - NewCodeEntry(CodeEventListener::CALLBACK_TAG, GetName(name), "set "); - rec->size = 1; + NewCodeEntry(CodeEventListener::CALLBACK_TAG, GetConsName("set ", name)); + rec->instruction_size = 1; DispatchCodeEvent(evt_rec); } @@ -212,7 +215,7 @@ void ProfilerListener::RecordInliningInfo(CodeEntry* entry, DCHECK_EQ(Translation::BEGIN, opcode); it.Skip(Translation::NumberOfOperandsFor(opcode)); int depth = 0; - std::vector inline_stack; + std::vector> inline_stack; while (it.HasNext() && Translation::BEGIN != (opcode = static_cast(it.Next()))) { @@ -234,12 +237,12 @@ void ProfilerListener::RecordInliningInfo(CodeEntry* entry, CodeEntry* inline_entry = new CodeEntry(entry->tag(), GetFunctionName(shared_info->DebugName()), - CodeEntry::kEmptyNamePrefix, resource_name, + resource_name, CpuProfileNode::kNoLineNumberInfo, CpuProfileNode::kNoColumnNumberInfo, nullptr, code->instruction_start()); inline_entry->FillFunctionInfo(shared_info); - inline_stack.push_back(inline_entry); + inline_stack.emplace_back(inline_entry); } if (!inline_stack.empty()) { entry->AddInlineStack(pc_offset, std::move(inline_stack)); @@ -247,16 +250,18 @@ void ProfilerListener::RecordInliningInfo(CodeEntry* entry, } } -void ProfilerListener::RecordDeoptInlinedFrames(CodeEntry* entry, - AbstractCode* abstract_code) { - if (abstract_code->kind() != AbstractCode::OPTIMIZED_FUNCTION) return; - Handle code(abstract_code->GetCode()); - +void ProfilerListener::AttachDeoptInlinedFrames(Code* code, + CodeDeoptEventRecord* rec) { + int deopt_id = rec->deopt_id; SourcePosition last_position = SourcePosition::Unknown(); int mask = RelocInfo::ModeMask(RelocInfo::DEOPT_ID) | RelocInfo::ModeMask(RelocInfo::DEOPT_SCRIPT_OFFSET) | RelocInfo::ModeMask(RelocInfo::DEOPT_INLINING_ID); - for (RelocIterator it(*code, mask); !it.done(); it.next()) { + + rec->deopt_frames = nullptr; + rec->deopt_frame_count = 0; + + for (RelocIterator it(code, mask); !it.done(); it.next()) { RelocInfo* info = it.rinfo(); if (info->rmode() == RelocInfo::DEOPT_SCRIPT_OFFSET) { int script_offset = static_cast(info->data()); @@ -267,52 +272,39 @@ void ProfilerListener::RecordDeoptInlinedFrames(CodeEntry* entry, continue; } if (info->rmode() == RelocInfo::DEOPT_ID) { - int deopt_id = static_cast(info->data()); + if (deopt_id != static_cast(info->data())) continue; DCHECK(last_position.IsKnown()); - std::vector inlined_frames; - for (SourcePositionInfo& pos_info : last_position.InliningStack(code)) { - DCHECK(pos_info.position.ScriptOffset() != kNoSourcePosition); + + // SourcePosition::InliningStack allocates a handle for the SFI of each + // frame. These don't escape this function, but quickly add up. This + // scope limits their lifetime. + HandleScope scope(isolate_); + std::vector stack = + last_position.InliningStack(handle(code)); + CpuProfileDeoptFrame* deopt_frames = + new CpuProfileDeoptFrame[stack.size()]; + + int deopt_frame_count = 0; + for (SourcePositionInfo& pos_info : stack) { + if (pos_info.position.ScriptOffset() == kNoSourcePosition) continue; if (!pos_info.function->script()->IsScript()) continue; int script_id = Script::cast(pos_info.function->script())->id(); size_t offset = static_cast(pos_info.position.ScriptOffset()); - inlined_frames.push_back(CpuProfileDeoptFrame({script_id, offset})); - } - if (!inlined_frames.empty() && - !entry->HasDeoptInlinedFramesFor(deopt_id)) { - entry->AddDeoptInlinedFrames(deopt_id, std::move(inlined_frames)); + deopt_frames[deopt_frame_count++] = {script_id, offset}; } + rec->deopt_frames = deopt_frames; + rec->deopt_frame_count = deopt_frame_count; + break; } } } CodeEntry* ProfilerListener::NewCodeEntry( 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) { - std::unique_ptr code_entry = base::make_unique( - tag, name, name_prefix, resource_name, line_number, column_number, - line_info, instruction_start); - CodeEntry* raw_code_entry = code_entry.get(); - code_entries_.push_back(std::move(code_entry)); - return raw_code_entry; -} - -void ProfilerListener::AddObserver(CodeEventObserver* observer) { - base::LockGuard guard(&mutex_); - if (observers_.empty()) { - code_entries_.clear(); - } - if (std::find(observers_.begin(), observers_.end(), observer) == - observers_.end()) { - observers_.push_back(observer); - } -} - -void ProfilerListener::RemoveObserver(CodeEventObserver* observer) { - base::LockGuard guard(&mutex_); - auto it = std::find(observers_.begin(), observers_.end(), observer); - if (it == observers_.end()) return; - observers_.erase(it); + const char* resource_name, int line_number, int column_number, + std::unique_ptr line_info, Address instruction_start) { + return new CodeEntry(tag, name, resource_name, line_number, column_number, + std::move(line_info), instruction_start); } } // namespace internal diff --git a/deps/v8/src/profiler/profiler-listener.h b/deps/v8/src/profiler/profiler-listener.h index 440afd87a2e97f..e21bcda28450cc 100644 --- a/deps/v8/src/profiler/profiler-listener.h +++ b/deps/v8/src/profiler/profiler-listener.h @@ -5,6 +5,7 @@ #ifndef V8_PROFILER_PROFILER_LISTENER_H_ #define V8_PROFILER_PROFILER_LISTENER_H_ +#include #include #include "src/code-events.h" @@ -14,16 +15,17 @@ namespace v8 { namespace internal { class CodeEventsContainer; +class CodeDeoptEventRecord; class CodeEventObserver { public: virtual void CodeEventHandler(const CodeEventsContainer& evt_rec) = 0; - virtual ~CodeEventObserver() {} + virtual ~CodeEventObserver() = default; }; class ProfilerListener : public CodeEventListener { public: - explicit ProfilerListener(Isolate* isolate); + ProfilerListener(Isolate*, CodeEventObserver*); ~ProfilerListener() override; void CallbackEvent(Name* name, Address entry_point) override; @@ -40,7 +42,7 @@ class ProfilerListener : public CodeEventListener { void CodeCreateEvent(CodeEventListener::LogEventsAndTags tag, AbstractCode* code, int args_count) override; void CodeMovingGCEvent() override {} - void CodeMoveEvent(AbstractCode* from, Address to) override; + void CodeMoveEvent(AbstractCode* from, AbstractCode* to) override; void CodeDisableOptEvent(AbstractCode* code, SharedFunctionInfo* shared) override; void CodeDeoptEvent(Code* code, DeoptKind kind, Address pc, @@ -52,15 +54,11 @@ class ProfilerListener : public CodeEventListener { CodeEntry* NewCodeEntry( CodeEventListener::LogEventsAndTags tag, const char* name, - const char* name_prefix = CodeEntry::kEmptyNamePrefix, const char* resource_name = CodeEntry::kEmptyResourceName, int line_number = v8::CpuProfileNode::kNoLineNumberInfo, int column_number = v8::CpuProfileNode::kNoColumnNumberInfo, - JITLineInfoTable* line_info = NULL, Address instruction_start = NULL); - - void AddObserver(CodeEventObserver* observer); - void RemoveObserver(CodeEventObserver* observer); - V8_INLINE bool HasObservers() { return !observers_.empty(); } + std::unique_ptr line_info = nullptr, + Address instruction_start = NULL); const char* GetName(Name* name) { return function_and_resource_names_.GetName(name); @@ -68,29 +66,27 @@ class ProfilerListener : public CodeEventListener { const char* GetName(int args_count) { return function_and_resource_names_.GetName(args_count); } + const char* GetConsName(const char* prefix, Name* name) { + return function_and_resource_names_.GetConsName(prefix, name); + } const char* GetFunctionName(Name* name) { return function_and_resource_names_.GetFunctionName(name); } const char* GetFunctionName(const char* name) { return function_and_resource_names_.GetFunctionName(name); } - size_t entries_count_for_test() const { return code_entries_.size(); } private: void RecordInliningInfo(CodeEntry* entry, AbstractCode* abstract_code); - void RecordDeoptInlinedFrames(CodeEntry* entry, AbstractCode* abstract_code); + void AttachDeoptInlinedFrames(Code* code, CodeDeoptEventRecord* rec); Name* InferScriptName(Name* name, SharedFunctionInfo* info); V8_INLINE void DispatchCodeEvent(const CodeEventsContainer& evt_rec) { - base::LockGuard guard(&mutex_); - for (auto observer : observers_) { - observer->CodeEventHandler(evt_rec); - } + observer_->CodeEventHandler(evt_rec); } + Isolate* isolate_; + CodeEventObserver* observer_; StringsStorage function_and_resource_names_; - std::vector> code_entries_; - std::vector observers_; - base::Mutex mutex_; DISALLOW_COPY_AND_ASSIGN(ProfilerListener); }; diff --git a/deps/v8/src/profiler/strings-storage.cc b/deps/v8/src/profiler/strings-storage.cc index 05f47788309b7c..cce5ad176560e5 100644 --- a/deps/v8/src/profiler/strings-storage.cc +++ b/deps/v8/src/profiler/strings-storage.cc @@ -6,21 +6,19 @@ #include +#include "src/allocation.h" #include "src/objects-inl.h" namespace v8 { namespace internal { - bool StringsStorage::StringsMatch(void* key1, void* key2) { return strcmp(reinterpret_cast(key1), reinterpret_cast(key2)) == 0; } - -StringsStorage::StringsStorage(Heap* heap) - : hash_seed_(heap->HashSeed()), names_(StringsMatch) {} - +StringsStorage::StringsStorage(uint32_t hash_seed) + : hash_seed_(hash_seed), names_(StringsMatch) {} StringsStorage::~StringsStorage() { for (base::HashMap::Entry* p = names_.Start(); p != NULL; @@ -29,7 +27,6 @@ StringsStorage::~StringsStorage() { } } - const char* StringsStorage::GetCopy(const char* src) { int len = static_cast(strlen(src)); base::HashMap::Entry* entry = GetEntry(src, len); @@ -43,7 +40,6 @@ const char* StringsStorage::GetCopy(const char* src) { return reinterpret_cast(entry->value); } - const char* StringsStorage::GetFormatted(const char* format, ...) { va_list args; va_start(args, format); @@ -52,7 +48,6 @@ const char* StringsStorage::GetFormatted(const char* format, ...) { return result; } - const char* StringsStorage::AddOrDisposeString(char* str, int len) { base::HashMap::Entry* entry = GetEntry(str, len); if (entry->value == NULL) { @@ -65,7 +60,6 @@ const char* StringsStorage::AddOrDisposeString(char* str, int len) { return reinterpret_cast(entry->value); } - const char* StringsStorage::GetVFormatted(const char* format, va_list args) { Vector str = Vector::New(1024); int len = VSNPrintF(str, format, args); @@ -76,7 +70,6 @@ const char* StringsStorage::GetVFormatted(const char* format, va_list args) { return AddOrDisposeString(str.start(), len); } - const char* StringsStorage::GetName(Name* name) { if (name->IsString()) { String* str = String::cast(name); @@ -95,6 +88,25 @@ const char* StringsStorage::GetName(int index) { return GetFormatted("%d", index); } +const char* StringsStorage::GetConsName(const char* prefix, Name* name) { + if (name->IsString()) { + String* str = String::cast(name); + int length = Min(kMaxNameSize, str->length()); + int actual_length = 0; + std::unique_ptr data = str->ToCString( + DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL, 0, length, &actual_length); + + int cons_length = actual_length + static_cast(strlen(prefix)) + 1; + char* cons_result = NewArray(cons_length); + snprintf(cons_result, cons_length, "%s%s", prefix, data.get()); + + return AddOrDisposeString(cons_result, cons_length); + } else if (name->IsSymbol()) { + return ""; + } + return ""; +} + const char* StringsStorage::GetFunctionName(Name* name) { return GetName(name); } diff --git a/deps/v8/src/profiler/strings-storage.h b/deps/v8/src/profiler/strings-storage.h index d73a9dd208a9fe..246a4033d5ee57 100644 --- a/deps/v8/src/profiler/strings-storage.h +++ b/deps/v8/src/profiler/strings-storage.h @@ -7,18 +7,19 @@ #include -#include "src/allocation.h" #include "src/base/compiler-specific.h" #include "src/base/hashmap.h" namespace v8 { namespace internal { +class Name; + // Provides a storage of strings allocated in C++ heap, to hold them // forever, even if they disappear from JS heap or external storage. class StringsStorage { public: - explicit StringsStorage(Heap* heap); + explicit StringsStorage(uint32_t hash_seed); ~StringsStorage(); const char* GetCopy(const char* src); @@ -27,6 +28,7 @@ class StringsStorage { const char* GetVFormatted(const char* format, va_list args); const char* GetName(Name* name); const char* GetName(int index); + const char* GetConsName(const char* prefix, Name* name); const char* GetFunctionName(Name* name); const char* GetFunctionName(const char* name); diff --git a/deps/v8/src/snapshot/serializer.h b/deps/v8/src/snapshot/serializer.h index a1924b4f7ab469..c964b6cdd810f0 100644 --- a/deps/v8/src/snapshot/serializer.h +++ b/deps/v8/src/snapshot/serializer.h @@ -26,8 +26,8 @@ class CodeAddressMap : public CodeEventLogger { isolate_->logger()->removeCodeEventListener(this); } - void CodeMoveEvent(AbstractCode* from, Address to) override { - address_to_name_map_.Move(from->address(), to); + void CodeMoveEvent(AbstractCode* from, AbstractCode* to) override { + address_to_name_map_.Move(from->address(), to->address()); } void CodeDisableOptEvent(AbstractCode* code, diff --git a/deps/v8/test/cctest/cctest.status b/deps/v8/test/cctest/cctest.status index 2c9117ae802d52..f38894bc9c7515 100644 --- a/deps/v8/test/cctest/cctest.status +++ b/deps/v8/test/cctest/cctest.status @@ -71,8 +71,11 @@ # BUG(5193). The cpu profiler tests are notoriously flaky. 'test-cpu-profiler/CollectCpuProfile': [SKIP], + 'test-cpu-profiler/CollectCpuProfileCallerLineNumbers': [FAIL, PASS], + 'test-cpu-profiler/CollectCpuProfileSamples': [SKIP], 'test-cpu-profiler/CollectDeoptEvents': [SKIP], 'test-cpu-profiler/CpuProfileDeepStack': [SKIP], + 'test-cpu-profiler/DeoptUntrackedFunction': [SKIP], 'test-cpu-profiler/FunctionApplySample': [SKIP], 'test-cpu-profiler/HotDeoptNoFrameEntry': [SKIP], 'test-cpu-profiler/JsNative1JsNative2JsSample': [SKIP], diff --git a/deps/v8/test/cctest/test-cpu-profiler.cc b/deps/v8/test/cctest/test-cpu-profiler.cc index b441d04fdd31db..30cf2d8382b782 100644 --- a/deps/v8/test/cctest/test-cpu-profiler.cc +++ b/deps/v8/test/cctest/test-cpu-profiler.cc @@ -159,7 +159,6 @@ TEST(CodeEvents) { i::AbstractCode* aaa_code = CreateCode(&env); i::AbstractCode* comment_code = CreateCode(&env); - i::AbstractCode* args5_code = CreateCode(&env); i::AbstractCode* comment2_code = CreateCode(&env); i::AbstractCode* moved_code = CreateCode(&env); i::AbstractCode* args3_code = CreateCode(&env); @@ -172,9 +171,8 @@ TEST(CodeEvents) { CpuProfiler profiler(isolate, profiles, generator, processor); profiles->StartProfiling("", false); processor->Start(); - ProfilerListener profiler_listener(isolate); - isolate->code_event_dispatcher()->AddListener(&profiler_listener); - profiler_listener.AddObserver(&profiler); + ProfilerListener profiler_listener(isolate, &profiler); + isolate->logger()->addCodeEventListener(&profiler_listener); // Enqueue code creation events. const char* aaa_str = "aaa"; @@ -183,37 +181,33 @@ TEST(CodeEvents) { *aaa_name); profiler_listener.CodeCreateEvent(i::Logger::BUILTIN_TAG, comment_code, "comment"); - profiler_listener.CodeCreateEvent(i::Logger::STUB_TAG, args5_code, 5); profiler_listener.CodeCreateEvent(i::Logger::BUILTIN_TAG, comment2_code, "comment2"); - profiler_listener.CodeMoveEvent(comment2_code, moved_code->address()); + profiler_listener.CodeMoveEvent(comment2_code, moved_code); profiler_listener.CodeCreateEvent(i::Logger::STUB_TAG, args3_code, 3); profiler_listener.CodeCreateEvent(i::Logger::STUB_TAG, args4_code, 4); // Enqueue a tick event to enable code events processing. - EnqueueTickSampleEvent(processor, aaa_code->address()); + EnqueueTickSampleEvent(processor, aaa_code->instruction_start()); - profiler_listener.RemoveObserver(&profiler); - isolate->code_event_dispatcher()->RemoveListener(&profiler_listener); + isolate->logger()->removeCodeEventListener(&profiler_listener); processor->StopSynchronously(); // Check the state of profile generator. - CodeEntry* aaa = generator->code_map()->FindEntry(aaa_code->address()); + CodeEntry* aaa = + generator->code_map()->FindEntry(aaa_code->instruction_start()); CHECK(aaa); CHECK_EQ(0, strcmp(aaa_str, aaa->name())); CodeEntry* comment = - generator->code_map()->FindEntry(comment_code->address()); + generator->code_map()->FindEntry(comment_code->instruction_start()); CHECK(comment); CHECK_EQ(0, strcmp("comment", comment->name())); - CodeEntry* args5 = generator->code_map()->FindEntry(args5_code->address()); - CHECK(args5); - CHECK_EQ(0, strcmp("5", args5->name())); - - CHECK(!generator->code_map()->FindEntry(comment2_code->address())); + CHECK(!generator->code_map()->FindEntry(comment2_code->instruction_start())); - CodeEntry* comment2 = generator->code_map()->FindEntry(moved_code->address()); + CodeEntry* comment2 = + generator->code_map()->FindEntry(moved_code->instruction_start()); CHECK(comment2); CHECK_EQ(0, strcmp("comment2", comment2->name())); } @@ -241,9 +235,8 @@ TEST(TickEvents) { CpuProfiler profiler(isolate, profiles, generator, processor); profiles->StartProfiling("", false); processor->Start(); - ProfilerListener profiler_listener(isolate); - isolate->code_event_dispatcher()->AddListener(&profiler_listener); - profiler_listener.AddObserver(&profiler); + ProfilerListener profiler_listener(isolate, &profiler); + isolate->logger()->addCodeEventListener(&profiler_listener); profiler_listener.CodeCreateEvent(i::Logger::BUILTIN_TAG, frame1_code, "bbb"); profiler_listener.CodeCreateEvent(i::Logger::STUB_TAG, frame2_code, 5); @@ -258,8 +251,7 @@ TEST(TickEvents) { frame2_code->instruction_end() - 1, frame1_code->instruction_end() - 1); - profiler_listener.RemoveObserver(&profiler); - isolate->code_event_dispatcher()->RemoveListener(&profiler_listener); + isolate->logger()->removeCodeEventListener(&profiler_listener); processor->StopSynchronously(); CpuProfile* profile = profiles->StopProfiling(""); CHECK(profile); @@ -314,23 +306,19 @@ TEST(Issue1398) { CpuProfiler profiler(isolate, profiles, generator, processor); profiles->StartProfiling("", false); processor->Start(); - ProfilerListener profiler_listener(isolate); - isolate->code_event_dispatcher()->AddListener(&profiler_listener); - profiler_listener.AddObserver(&profiler); + ProfilerListener profiler_listener(isolate, &profiler); profiler_listener.CodeCreateEvent(i::Logger::BUILTIN_TAG, code, "bbb"); v8::TickSample* sample = processor->StartTickSample(); - sample->pc = code->address(); - sample->tos = 0; + sample->pc = reinterpret_cast(code->instruction_start()); + sample->tos = nullptr; sample->frames_count = v8::TickSample::kMaxFramesCount; for (unsigned i = 0; i < sample->frames_count; ++i) { - sample->stack[i] = code->address(); + sample->stack[i] = reinterpret_cast(code->instruction_start()); } processor->FinishTickSample(); - profiler_listener.RemoveObserver(&profiler); - isolate->code_event_dispatcher()->RemoveListener(&profiler_listener); processor->StopSynchronously(); CpuProfile* profile = profiles->StopProfiling(""); CHECK(profile); @@ -453,11 +441,14 @@ class ProfilerHelper { profiler_->Dispose(); } + typedef v8::CpuProfilingMode ProfilingMode; + v8::CpuProfile* Run(v8::Local function, v8::Local argv[], int argc, unsigned min_js_samples = 0, unsigned min_external_samples = 0, - bool collect_samples = false); + bool collect_samples = false, + ProfilingMode mode = ProfilingMode::kLeafNodeLineNumbers); v8::CpuProfiler* profiler() { return profiler_; } @@ -470,11 +461,11 @@ v8::CpuProfile* ProfilerHelper::Run(v8::Local function, v8::Local argv[], int argc, unsigned min_js_samples, unsigned min_external_samples, - bool collect_samples) { + bool collect_samples, ProfilingMode mode) { v8::Local profile_name = v8_str("my_profile"); profiler_->SetSamplingInterval(100); - profiler_->StartProfiling(profile_name, collect_samples); + profiler_->StartProfiling(profile_name, mode, collect_samples); v8::internal::CpuProfiler* iprofiler = reinterpret_cast(profiler_); @@ -521,7 +512,6 @@ static const v8::CpuProfileNode* GetChild(v8::Local context, return result; } - static void CheckSimpleBranch(v8::Local context, const v8::CpuProfileNode* node, const char* names[], int length) { @@ -531,7 +521,6 @@ static void CheckSimpleBranch(v8::Local context, } } - static const ProfileNode* GetSimpleBranch(v8::Local context, v8::CpuProfile* profile, const char* names[], int length) { @@ -542,6 +531,43 @@ static const ProfileNode* GetSimpleBranch(v8::Local context, return reinterpret_cast(node); } +struct NameLinePair { + const char* name; + int line_number; +}; + +static const v8::CpuProfileNode* FindChild(const v8::CpuProfileNode* node, + NameLinePair pair) { + for (int i = 0, count = node->GetChildrenCount(); i < count; ++i) { + const v8::CpuProfileNode* child = node->GetChild(i); + // The name and line number must match, or if the requested line number was + // -1, then match any function of the same name. + if (strcmp(child->GetFunctionNameStr(), pair.name) == 0 && + (child->GetLineNumber() == pair.line_number || + pair.line_number == -1)) { + return child; + } + } + return nullptr; +} + +static const v8::CpuProfileNode* GetChild(const v8::CpuProfileNode* node, + NameLinePair pair) { + const v8::CpuProfileNode* result = FindChild(node, pair); + char buffer[100]; + i::SNPrintF(i::ArrayVector(buffer), "Failed to GetChild: %s:%d", pair.name, pair.line_number); + if (!result) FATAL(buffer); + return result; +} + +static void CheckBranch(const v8::CpuProfileNode* node, NameLinePair path[], + int length) { + for (int i = 0; i < length; i++) { + NameLinePair pair = path[i]; + node = GetChild(node, pair); + } +} + static const char* cpu_profiler_test_source = "%NeverOptimizeFunction(loop);\n" "%NeverOptimizeFunction(delay);\n" @@ -622,6 +648,40 @@ TEST(CollectCpuProfile) { profile->Delete(); } +TEST(CollectCpuProfileCallerLineNumbers) { + i::FLAG_allow_natives_syntax = true; + LocalContext env; + v8::HandleScope scope(env->GetIsolate()); + + CompileRun(cpu_profiler_test_source); + v8::Local function = GetFunction(env.local(), "start"); + + int32_t profiling_interval_ms = 200; + v8::Local args[] = { + v8::Integer::New(env->GetIsolate(), profiling_interval_ms)}; + ProfilerHelper helper(env.local()); + helper.Run(function, args, arraysize(args), 1000, 0, false, + v8::CpuProfilingMode::kCallerLineNumbers); + v8::CpuProfile* profile = + helper.Run(function, args, arraysize(args), 1000, 0, false, + v8::CpuProfilingMode::kCallerLineNumbers); + + const v8::CpuProfileNode* root = profile->GetTopDownRoot(); + const v8::CpuProfileNode* start_node = GetChild(root, {"start", 27}); + const v8::CpuProfileNode* foo_node = GetChild(start_node, {"foo", 30}); + + NameLinePair bar_branch[] = {{"bar", 23}, {"delay", 19}, {"loop", 18}}; + CheckBranch(foo_node, bar_branch, arraysize(bar_branch)); + NameLinePair baz_branch[] = {{"baz", 25}, {"delay", 20}, {"loop", 18}}; + CheckBranch(foo_node, baz_branch, arraysize(baz_branch)); + NameLinePair delay_at22_branch[] = {{"delay", 22}, {"loop", 18}}; + CheckBranch(foo_node, delay_at22_branch, arraysize(delay_at22_branch)); + NameLinePair delay_at24_branch[] = {{"delay", 24}, {"loop", 18}}; + CheckBranch(foo_node, delay_at24_branch, arraysize(delay_at24_branch)); + + profile->Delete(); +} + static const char* hot_deopt_no_frame_entry_test_source = "%NeverOptimizeFunction(foo);\n" "%NeverOptimizeFunction(start);\n" @@ -1087,9 +1147,7 @@ static void TickLines(bool optimize) { CpuProfiler profiler(isolate, profiles, generator, processor); profiles->StartProfiling("", false); processor->Start(); - ProfilerListener profiler_listener(isolate); - isolate->code_event_dispatcher()->AddListener(&profiler_listener); - profiler_listener.AddObserver(&profiler); + ProfilerListener profiler_listener(isolate, &profiler); // Enqueue code creation events. i::Handle str = factory->NewStringFromAsciiChecked(func_name); @@ -1101,8 +1159,6 @@ static void TickLines(bool optimize) { // Enqueue a tick event to enable code events processing. EnqueueTickSampleEvent(processor, code_address); - profiler_listener.RemoveObserver(&profiler); - isolate->code_event_dispatcher()->RemoveListener(&profiler_listener); processor->StopSynchronously(); CpuProfile* profile = profiles->StopProfiling(""); @@ -1112,9 +1168,10 @@ static void TickLines(bool optimize) { CodeEntry* func_entry = generator->code_map()->FindEntry(code_address); CHECK(func_entry); CHECK_EQ(0, strcmp(func_name, func_entry->name())); - const i::JITLineInfoTable* line_info = func_entry->line_info(); + const i::SourcePositionTable* line_info = func_entry->line_info(); CHECK(line_info); - CHECK(!line_info->empty()); + CHECK_NE(v8::CpuProfileNode::kNoLineNumberInfo, + line_info->GetSourceLineNumber(100)); // Check the hit source lines using V8 Public APIs. const i::ProfileTree* tree = profile->top_down(); @@ -2293,8 +2350,57 @@ TEST(CodeEntriesMemoryLeak) { v8::CpuProfile* profile = helper.Run(function, nullptr, 0); profile->Delete(); } - ProfilerListener* profiler_listener = - CcTest::i_isolate()->logger()->profiler_listener(); - CHECK_GE(10000ul, profiler_listener->entries_count_for_test()); + i::CpuProfiler* profiler = + reinterpret_cast(helper.profiler()); + CHECK(!profiler->profiler_listener_for_test()); +} + +TEST(SourcePositionTable) { + i::SourcePositionTable info; + + // Newly created tables should return NoLineNumberInfo for any lookup. + int no_info = v8::CpuProfileNode::kNoLineNumberInfo; + CHECK_EQ(no_info, info.GetSourceLineNumber(std::numeric_limits::min())); + CHECK_EQ(no_info, info.GetSourceLineNumber(0)); + CHECK_EQ(no_info, info.GetSourceLineNumber(1)); + CHECK_EQ(no_info, info.GetSourceLineNumber(9)); + CHECK_EQ(no_info, info.GetSourceLineNumber(10)); + CHECK_EQ(no_info, info.GetSourceLineNumber(11)); + CHECK_EQ(no_info, info.GetSourceLineNumber(19)); + CHECK_EQ(no_info, info.GetSourceLineNumber(20)); + CHECK_EQ(no_info, info.GetSourceLineNumber(21)); + CHECK_EQ(no_info, info.GetSourceLineNumber(100)); + CHECK_EQ(no_info, info.GetSourceLineNumber(std::numeric_limits::max())); + + info.SetPosition(10, 1); + info.SetPosition(20, 2); + + // The only valid return values are 1 or 2 - every pc maps to a line number. + CHECK_EQ(1, info.GetSourceLineNumber(std::numeric_limits::min())); + CHECK_EQ(1, info.GetSourceLineNumber(0)); + CHECK_EQ(1, info.GetSourceLineNumber(1)); + CHECK_EQ(1, info.GetSourceLineNumber(9)); + CHECK_EQ(1, info.GetSourceLineNumber(10)); + CHECK_EQ(1, info.GetSourceLineNumber(11)); + CHECK_EQ(1, info.GetSourceLineNumber(19)); + CHECK_EQ(2, info.GetSourceLineNumber(20)); + CHECK_EQ(2, info.GetSourceLineNumber(21)); + CHECK_EQ(2, info.GetSourceLineNumber(100)); + CHECK_EQ(2, info.GetSourceLineNumber(std::numeric_limits::max())); + + // Test SetPosition behavior. + info.SetPosition(25, 3); + CHECK_EQ(2, info.GetSourceLineNumber(21)); + CHECK_EQ(3, info.GetSourceLineNumber(100)); + CHECK_EQ(3, info.GetSourceLineNumber(std::numeric_limits::max())); +} + +TEST(MultipleProfilers) { + std::unique_ptr profiler1(new CpuProfiler(CcTest::i_isolate())); + std::unique_ptr profiler2(new CpuProfiler(CcTest::i_isolate())); + profiler1->StartProfiling("1"); + profiler2->StartProfiling("2"); + profiler1->StopProfiling("1"); + profiler2->StopProfiling("2"); } diff --git a/deps/v8/test/cctest/test-log.cc b/deps/v8/test/cctest/test-log.cc index 03d90b5012a453..46c065722b2e68 100644 --- a/deps/v8/test/cctest/test-log.cc +++ b/deps/v8/test/cctest/test-log.cc @@ -570,7 +570,7 @@ TEST(LogVersion) { TEST(Issue539892) { class : public i::CodeEventLogger { public: - void CodeMoveEvent(i::AbstractCode* from, Address to) override {} + void CodeMoveEvent(i::AbstractCode* from, i::AbstractCode* to) override {} void CodeDisableOptEvent(i::AbstractCode* code, i::SharedFunctionInfo* shared) override {} diff --git a/deps/v8/test/cctest/test-profile-generator.cc b/deps/v8/test/cctest/test-profile-generator.cc index 67d289302495e7..8447ef84c71a6b 100644 --- a/deps/v8/test/cctest/test-profile-generator.cc +++ b/deps/v8/test/cctest/test-profile-generator.cc @@ -72,6 +72,25 @@ TEST(ProfileNodeFindOrAddChild) { CHECK_EQ(childNode3, node->FindOrAddChild(&entry3)); } +TEST(ProfileNodeFindOrAddChildWithLineNumber) { + CcTest::InitializeVM(); + ProfileTree tree(CcTest::i_isolate()); + ProfileNode* root = tree.root(); + CodeEntry a(i::CodeEventListener::FUNCTION_TAG, "a"); + ProfileNode* a_node = root->FindOrAddChild(&a, -1); + + // a --(22)--> child1 + // --(23)--> child1 + + CodeEntry child1(i::CodeEventListener::FUNCTION_TAG, "child1"); + ProfileNode* child1_node = a_node->FindOrAddChild(&child1, 22); + CHECK(child1_node); + CHECK_EQ(child1_node, a_node->FindOrAddChild(&child1, 22)); + + ProfileNode* child2_node = a_node->FindOrAddChild(&child1, 23); + CHECK(child2_node); + CHECK_NE(child1_node, child2_node); +} TEST(ProfileNodeFindOrAddChildForSameFunction) { CcTest::InitializeVM(); @@ -180,6 +199,29 @@ TEST(ProfileTreeAddPathFromEnd) { CHECK_EQ(1u, node4->self_ticks()); } +TEST(ProfileTreeAddPathFromEndWithLineNumbers) { + CcTest::InitializeVM(); + CodeEntry a(i::CodeEventListener::FUNCTION_TAG, "a"); + CodeEntry b(i::CodeEventListener::FUNCTION_TAG, "b"); + CodeEntry c(i::CodeEventListener::FUNCTION_TAG, "c"); + ProfileTree tree(CcTest::i_isolate()); + ProfileTreeTestHelper helper(&tree); + + v8::internal::ProfileStackTrace path = {{&c, 5}, {&b, 3}, {&a, 1}}; + tree.AddPathFromEnd(path, v8::CpuProfileNode::kNoLineNumberInfo, true, + v8::CpuProfilingMode::kCallerLineNumbers); + + ProfileNode* a_node = + tree.root()->FindChild(&a, v8::CpuProfileNode::kNoLineNumberInfo); + tree.Print(); + CHECK(a_node); + + ProfileNode* b_node = a_node->FindChild(&b, 1); + CHECK(b_node); + + ProfileNode* c_node = b_node->FindChild(&c, 3); + CHECK(c_node); +} TEST(ProfileTreeCalculateTotalTicks) { CcTest::InitializeVM(); @@ -278,52 +320,50 @@ static inline i::Address ToAddress(int n) { TEST(CodeMapAddCode) { CodeMap code_map; - CodeEntry entry1(i::CodeEventListener::FUNCTION_TAG, "aaa"); - CodeEntry entry2(i::CodeEventListener::FUNCTION_TAG, "bbb"); - CodeEntry entry3(i::CodeEventListener::FUNCTION_TAG, "ccc"); - CodeEntry entry4(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); - code_map.AddCode(ToAddress(0x1950), &entry4, 0x10); + 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"); + code_map.AddCode(ToAddress(0x1500), entry1, 0x200); + code_map.AddCode(ToAddress(0x1700), entry2, 0x100); + code_map.AddCode(ToAddress(0x1900), entry3, 0x50); + code_map.AddCode(ToAddress(0x1950), entry4, 0x10); CHECK(!code_map.FindEntry(0)); CHECK(!code_map.FindEntry(ToAddress(0x1500 - 1))); - CHECK_EQ(&entry1, code_map.FindEntry(ToAddress(0x1500))); - CHECK_EQ(&entry1, code_map.FindEntry(ToAddress(0x1500 + 0x100))); - CHECK_EQ(&entry1, code_map.FindEntry(ToAddress(0x1500 + 0x200 - 1))); - CHECK_EQ(&entry2, code_map.FindEntry(ToAddress(0x1700))); - CHECK_EQ(&entry2, code_map.FindEntry(ToAddress(0x1700 + 0x50))); - CHECK_EQ(&entry2, code_map.FindEntry(ToAddress(0x1700 + 0x100 - 1))); + CHECK_EQ(entry1, code_map.FindEntry(ToAddress(0x1500))); + CHECK_EQ(entry1, code_map.FindEntry(ToAddress(0x1500 + 0x100))); + CHECK_EQ(entry1, code_map.FindEntry(ToAddress(0x1500 + 0x200 - 1))); + CHECK_EQ(entry2, code_map.FindEntry(ToAddress(0x1700))); + CHECK_EQ(entry2, code_map.FindEntry(ToAddress(0x1700 + 0x50))); + CHECK_EQ(entry2, code_map.FindEntry(ToAddress(0x1700 + 0x100 - 1))); CHECK(!code_map.FindEntry(ToAddress(0x1700 + 0x100))); CHECK(!code_map.FindEntry(ToAddress(0x1900 - 1))); - CHECK_EQ(&entry3, code_map.FindEntry(ToAddress(0x1900))); - CHECK_EQ(&entry3, code_map.FindEntry(ToAddress(0x1900 + 0x28))); - CHECK_EQ(&entry4, code_map.FindEntry(ToAddress(0x1950))); - CHECK_EQ(&entry4, code_map.FindEntry(ToAddress(0x1950 + 0x7))); - CHECK_EQ(&entry4, code_map.FindEntry(ToAddress(0x1950 + 0x10 - 1))); + CHECK_EQ(entry3, code_map.FindEntry(ToAddress(0x1900))); + CHECK_EQ(entry3, code_map.FindEntry(ToAddress(0x1900 + 0x28))); + CHECK_EQ(entry4, code_map.FindEntry(ToAddress(0x1950))); + CHECK_EQ(entry4, code_map.FindEntry(ToAddress(0x1950 + 0x7))); + CHECK_EQ(entry4, code_map.FindEntry(ToAddress(0x1950 + 0x10 - 1))); CHECK(!code_map.FindEntry(ToAddress(0x1950 + 0x10))); CHECK(!code_map.FindEntry(ToAddress(0xFFFFFFFF))); } - TEST(CodeMapMoveAndDeleteCode) { CodeMap code_map; - CodeEntry entry1(i::CodeEventListener::FUNCTION_TAG, "aaa"); - CodeEntry entry2(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))); - CHECK_EQ(&entry2, code_map.FindEntry(ToAddress(0x1700))); + CodeEntry* entry1 = new CodeEntry(i::CodeEventListener::FUNCTION_TAG, "aaa"); + CodeEntry* entry2 = new CodeEntry(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))); + CHECK_EQ(entry2, code_map.FindEntry(ToAddress(0x1700))); code_map.MoveCode(ToAddress(0x1500), ToAddress(0x1700)); // Deprecate bbb. CHECK(!code_map.FindEntry(ToAddress(0x1500))); - CHECK_EQ(&entry1, code_map.FindEntry(ToAddress(0x1700))); - CodeEntry entry3(i::CodeEventListener::FUNCTION_TAG, "ccc"); - code_map.AddCode(ToAddress(0x1750), &entry3, 0x100); + CHECK_EQ(entry1, code_map.FindEntry(ToAddress(0x1700))); + CodeEntry* entry3 = new CodeEntry(i::CodeEventListener::FUNCTION_TAG, "ccc"); + code_map.AddCode(ToAddress(0x1750), entry3, 0x100); CHECK(!code_map.FindEntry(ToAddress(0x1700))); - CHECK_EQ(&entry3, code_map.FindEntry(ToAddress(0x1750))); + CHECK_EQ(entry3, code_map.FindEntry(ToAddress(0x1750))); } - namespace { class TestSetup { @@ -401,10 +441,6 @@ TEST(RecordTickSample) { ProfileNode* node4 = top_down_test_helper.Walk(entry1, entry3, entry1); CHECK(node4); CHECK_EQ(entry1, node4->entry()); - - delete entry1; - delete entry2; - delete entry3; } static void CheckNodeIds(const ProfileNode* node, unsigned* expectedId) { @@ -466,10 +502,6 @@ TEST(SampleIds) { for (int i = 0; i < 3; i++) { CHECK_EQ(expected_id[i], profile->sample(i)->id()); } - - delete entry1; - delete entry2; - delete entry3; } @@ -498,8 +530,6 @@ TEST(NoSamples) { CHECK_EQ(3u, nodeId - 1); CHECK_EQ(0, profile->samples_count()); - - delete entry1; } @@ -656,7 +686,8 @@ int GetFunctionLineNumber(CpuProfiler& profiler, LocalContext& env, i::Handle func = i::Handle::cast( v8::Utils::OpenHandle(*v8::Local::Cast( env->Global()->Get(env.local(), v8_str(name)).ToLocalChecked()))); - CodeEntry* func_entry = code_map->FindEntry(func->abstract_code()->address()); + CodeEntry* func_entry = + code_map->FindEntry(func->abstract_code()->instruction_start()); if (!func_entry) FATAL(name); return func_entry->line_number();