diff --git a/deps/v8/include/v8-version.h b/deps/v8/include/v8-version.h index f1f29d02de3fb5..ddecda5abe18c5 100644 --- a/deps/v8/include/v8-version.h +++ b/deps/v8/include/v8-version.h @@ -11,7 +11,7 @@ #define V8_MAJOR_VERSION 6 #define V8_MINOR_VERSION 2 #define V8_BUILD_NUMBER 414 -#define V8_PATCH_LEVEL 60 +#define V8_PATCH_LEVEL 61 // Use 1 for candidates and 0 otherwise. // (Boolean macro values are not supported by all preprocessors.) diff --git a/deps/v8/src/api.cc b/deps/v8/src/api.cc index 99d79985ef2dae..434454ec67641f 100644 --- a/deps/v8/src/api.cc +++ b/deps/v8/src/api.cc @@ -8419,7 +8419,7 @@ HeapProfiler* Isolate::GetHeapProfiler() { CpuProfiler* Isolate::GetCpuProfiler() { i::CpuProfiler* cpu_profiler = - reinterpret_cast(this)->cpu_profiler(); + reinterpret_cast(this)->EnsureCpuProfiler(); return reinterpret_cast(cpu_profiler); } @@ -10139,15 +10139,7 @@ Local CpuProfileNode::GetFunctionName() const { const i::CodeEntry* entry = node->entry(); i::Handle name = isolate->factory()->InternalizeUtf8String(entry->name()); - if (!entry->has_name_prefix()) { - return ToApiHandle(name); - } else { - // We do not expect this to fail. Change this if it does. - i::Handle cons = isolate->factory()->NewConsString( - isolate->factory()->InternalizeUtf8String(entry->name_prefix()), - name).ToHandleChecked(); - return ToApiHandle(cons); - } + return ToApiHandle(name); } int debug::Coverage::BlockData::StartOffset() const { return block_->start; } diff --git a/deps/v8/src/isolate.cc b/deps/v8/src/isolate.cc index 5149a2650e2a10..12fb986952512f 100644 --- a/deps/v8/src/isolate.cc +++ b/deps/v8/src/isolate.cc @@ -2689,7 +2689,6 @@ bool Isolate::Init(StartupDeserializer* des) { call_descriptor_data_ = new CallInterfaceDescriptorData[CallDescriptors::NUMBER_OF_DESCRIPTORS]; access_compiler_data_ = new AccessCompilerData(); - cpu_profiler_ = new CpuProfiler(this); heap_profiler_ = new HeapProfiler(heap()); interpreter_ = new interpreter::Interpreter(this); compiler_dispatcher_ = @@ -3686,6 +3685,13 @@ void Isolate::PrintWithTimestamp(const char* format, ...) { va_end(arguments); } +CpuProfiler* Isolate::EnsureCpuProfiler() { + if (!cpu_profiler_) { + cpu_profiler_ = new CpuProfiler(this); + } + return cpu_profiler_; +} + bool StackLimitCheck::JsHasOverflowed(uintptr_t gap) const { StackGuard* stack_guard = isolate_->stack_guard(); #ifdef USE_SIMULATOR diff --git a/deps/v8/src/isolate.h b/deps/v8/src/isolate.h index c3a0727e84a353..b3796641556a31 100644 --- a/deps/v8/src/isolate.h +++ b/deps/v8/src/isolate.h @@ -1449,7 +1449,7 @@ class Isolate { // TODO(alph): Remove along with the deprecated GetCpuProfiler(). friend v8::CpuProfiler* v8::Isolate::GetCpuProfiler(); - CpuProfiler* cpu_profiler() const { return cpu_profiler_; } + CpuProfiler* EnsureCpuProfiler(); base::Atomic32 id_; EntryStackItem* entry_stack_; diff --git a/deps/v8/src/log.cc b/deps/v8/src/log.cc index 0ba024b987189e..493c6ca6f0d6e2 100644 --- a/deps/v8/src/log.cc +++ b/deps/v8/src/log.cc @@ -22,7 +22,6 @@ #include "src/log-utils.h" #include "src/macro-assembler.h" #include "src/perf-jit.h" -#include "src/profiler/profiler-listener.h" #include "src/profiler/tick-sample.h" #include "src/runtime-profiler.h" #include "src/source-position-table.h" @@ -739,7 +738,6 @@ Logger::Logger(Isolate* isolate) perf_jit_logger_(NULL), ll_logger_(NULL), jit_logger_(NULL), - listeners_(5), is_initialized_(false) {} Logger::~Logger() { @@ -1876,8 +1874,6 @@ bool Logger::SetUp(Isolate* isolate) { profiler_->Engage(); } - profiler_listener_.reset(); - if (is_logging_) { addCodeEventListener(this); } @@ -1905,19 +1901,6 @@ void Logger::SetCodeEventHandler(uint32_t options, } } -void Logger::SetUpProfilerListener() { - if (!is_initialized_) return; - if (profiler_listener_.get() == nullptr) { - profiler_listener_.reset(new ProfilerListener(isolate_)); - } - addCodeEventListener(profiler_listener_.get()); -} - -void Logger::TearDownProfilerListener() { - if (profiler_listener_->HasObservers()) return; - removeCodeEventListener(profiler_listener_.get()); -} - sampler::Sampler* Logger::sampler() { return ticker_; } @@ -1961,10 +1944,6 @@ FILE* Logger::TearDown() { jit_logger_ = NULL; } - if (profiler_listener_.get() != nullptr) { - removeCodeEventListener(profiler_listener_.get()); - } - return log_->Close(); } diff --git a/deps/v8/src/log.h b/deps/v8/src/log.h index 3e4d385527b6d0..33a086c48a0678 100644 --- a/deps/v8/src/log.h +++ b/deps/v8/src/log.h @@ -74,7 +74,6 @@ class LowLevelLogger; class PerfBasicLogger; class PerfJitLogger; class Profiler; -class ProfilerListener; class RuntimeCallTimer; class Ticker; @@ -102,16 +101,8 @@ class Logger : public CodeEventListener { void SetCodeEventHandler(uint32_t options, JitCodeEventHandler event_handler); - // Sets up ProfilerListener. - void SetUpProfilerListener(); - - // Tear down ProfilerListener if it has no observers. - void TearDownProfilerListener(); - sampler::Sampler* sampler(); - ProfilerListener* profiler_listener() { return profiler_listener_.get(); } - // Frees resources acquired in SetUp. // When a temporary file is used for the log, returns its stream descriptor, // leaving the file open. @@ -316,8 +307,6 @@ class Logger : public CodeEventListener { PerfJitLogger* perf_jit_logger_; LowLevelLogger* ll_logger_; JitLogger* jit_logger_; - std::unique_ptr profiler_listener_; - List listeners_; std::set logged_source_code_; uint32_t next_source_info_id_ = 0; diff --git a/deps/v8/src/profiler/cpu-profiler-inl.h b/deps/v8/src/profiler/cpu-profiler-inl.h index 440c6a1cce189b..80ff89bb486f4b 100644 --- a/deps/v8/src/profiler/cpu-profiler-inl.h +++ b/deps/v8/src/profiler/cpu-profiler-inl.h @@ -35,7 +35,11 @@ void CodeDisableOptEventRecord::UpdateCodeMap(CodeMap* code_map) { void CodeDeoptEventRecord::UpdateCodeMap(CodeMap* code_map) { CodeEntry* entry = code_map->FindEntry(start); - if (entry != NULL) entry->set_deopt_info(deopt_reason, deopt_id); + if (entry == nullptr) return; + std::vector frames_vector( + deopt_frames, deopt_frames + deopt_frame_count); + entry->set_deopt_info(deopt_reason, deopt_id, std::move(frames_vector)); + delete[] deopt_frames; } diff --git a/deps/v8/src/profiler/cpu-profiler.cc b/deps/v8/src/profiler/cpu-profiler.cc index 80d488f12c527f..3862a49e8187e8 100644 --- a/deps/v8/src/profiler/cpu-profiler.cc +++ b/deps/v8/src/profiler/cpu-profiler.cc @@ -4,6 +4,12 @@ #include "src/profiler/cpu-profiler.h" +#include +#include + +#include "src/base/lazy-instance.h" +#include "src/base/platform/mutex.h" +#include "src/base/template-utils.h" #include "src/debug/debug.h" #include "src/deoptimizer.h" #include "src/frames-inl.h" @@ -275,20 +281,19 @@ void CpuProfiler::set_sampling_interval(base::TimeDelta value) { void CpuProfiler::ResetProfiles() { profiles_.reset(new CpuProfilesCollection(isolate_)); profiles_->set_cpu_profiler(this); + profiler_listener_.reset(); + generator_.reset(); } void CpuProfiler::CreateEntriesForRuntimeCallStats() { - static_entries_.clear(); RuntimeCallStats* rcs = isolate_->counters()->runtime_call_stats(); CodeMap* code_map = generator_->code_map(); for (int i = 0; i < RuntimeCallStats::counters_count; ++i) { RuntimeCallCounter* counter = &(rcs->*(RuntimeCallStats::counters[i])); DCHECK(counter->name()); - std::unique_ptr entry( - new CodeEntry(CodeEventListener::FUNCTION_TAG, counter->name(), - CodeEntry::kEmptyNamePrefix, "native V8Runtime")); - code_map->AddCode(reinterpret_cast
(counter), entry.get(), 1); - static_entries_.push_back(std::move(entry)); + auto entry = new CodeEntry(CodeEventListener::FUNCTION_TAG, counter->name(), + "native V8Runtime"); + code_map->AddCode(reinterpret_cast
(counter), entry, 1); } } @@ -321,13 +326,17 @@ void CpuProfiler::StartProcessorIfNotStarted() { // Disable logging when using the new implementation. saved_is_logging_ = logger->is_logging_; logger->is_logging_ = false; - generator_.reset(new ProfileGenerator(profiles_.get())); + if (!generator_) { + generator_.reset(new ProfileGenerator(profiles_.get())); + CreateEntriesForRuntimeCallStats(); + } processor_.reset(new ProfilerEventsProcessor(isolate_, generator_.get(), sampling_interval_)); - CreateEntriesForRuntimeCallStats(); - logger->SetUpProfilerListener(); - ProfilerListener* profiler_listener = logger->profiler_listener(); - profiler_listener->AddObserver(this); + if (!profiler_listener_) { + profiler_listener_.reset(new ProfilerListener(isolate_, this)); + } + logger->addCodeEventListener(profiler_listener_.get()); + is_profiling_ = true; isolate_->set_is_profiling(true); // Enumerate stuff we already have in the heap. @@ -362,12 +371,9 @@ void CpuProfiler::StopProcessor() { Logger* logger = isolate_->logger(); is_profiling_ = false; isolate_->set_is_profiling(false); - ProfilerListener* profiler_listener = logger->profiler_listener(); - profiler_listener->RemoveObserver(this); + logger->removeCodeEventListener(profiler_listener_.get()); processor_->StopSynchronously(); - logger->TearDownProfilerListener(); processor_.reset(); - generator_.reset(); logger->is_logging_ = saved_is_logging_; } diff --git a/deps/v8/src/profiler/cpu-profiler.h b/deps/v8/src/profiler/cpu-profiler.h index 5fd7fa14da1cab..e2e46d2be7f683 100644 --- a/deps/v8/src/profiler/cpu-profiler.h +++ b/deps/v8/src/profiler/cpu-profiler.h @@ -86,6 +86,8 @@ class CodeDeoptEventRecord : public CodeEventRecord { int deopt_id; void* pc; int fp_to_sp_delta; + CpuProfileDeoptFrame* deopt_frames; + int deopt_frame_count; INLINE(void UpdateCodeMap(CodeMap* code_map)); }; @@ -214,6 +216,10 @@ class CpuProfiler : public CodeEventObserver { ProfilerEventsProcessor* processor() const { return processor_.get(); } Isolate* isolate() const { return isolate_; } + ProfilerListener* profiler_listener_for_test() { + return profiler_listener_.get(); + } + private: void StartProcessorIfNotStarted(); void StopProcessorIfLastProfile(const char* title); @@ -227,7 +233,7 @@ class CpuProfiler : public CodeEventObserver { std::unique_ptr profiles_; std::unique_ptr generator_; std::unique_ptr processor_; - std::vector> static_entries_; + std::unique_ptr profiler_listener_; bool saved_is_logging_; bool is_profiling_; @@ -237,5 +243,4 @@ class CpuProfiler : public CodeEventObserver { } // namespace internal } // namespace v8 - #endif // V8_PROFILER_CPU_PROFILER_H_ diff --git a/deps/v8/src/profiler/heap-profiler.cc b/deps/v8/src/profiler/heap-profiler.cc index 4706b914e7ac40..f587adda497daf 100644 --- a/deps/v8/src/profiler/heap-profiler.cc +++ b/deps/v8/src/profiler/heap-profiler.cc @@ -16,7 +16,7 @@ namespace internal { HeapProfiler::HeapProfiler(Heap* heap) : ids_(new HeapObjectsMap(heap)), - names_(new StringsStorage(heap)), + names_(new StringsStorage(heap->HashSeed())), is_tracking_object_moves_(false), get_retainer_infos_callback_(nullptr) {} @@ -34,7 +34,7 @@ HeapProfiler::~HeapProfiler() { void HeapProfiler::DeleteAllSnapshots() { snapshots_.Iterate(DeleteHeapSnapshot); snapshots_.Clear(); - names_.reset(new StringsStorage(heap())); + names_.reset(new StringsStorage(heap()->HashSeed())); } diff --git a/deps/v8/src/profiler/profile-generator-inl.h b/deps/v8/src/profiler/profile-generator-inl.h index 5a7017ad490767..7ed6d54e172f09 100644 --- a/deps/v8/src/profiler/profile-generator-inl.h +++ b/deps/v8/src/profiler/profile-generator-inl.h @@ -11,33 +11,34 @@ namespace v8 { namespace internal { CodeEntry::CodeEntry(CodeEventListener::LogEventsAndTags tag, const char* name, - const char* name_prefix, const char* resource_name, - int line_number, int column_number, - JITLineInfoTable* line_info, Address instruction_start) + const char* resource_name, int line_number, + int column_number, + std::unique_ptr line_info, + Address instruction_start) : bit_field_(TagField::encode(tag) | BuiltinIdField::encode(Builtins::builtin_count)), - name_prefix_(name_prefix), name_(name), resource_name_(resource_name), line_number_(line_number), column_number_(column_number), script_id_(v8::UnboundScript::kNoScriptId), position_(0), - bailout_reason_(kEmptyBailoutReason), - deopt_reason_(kNoDeoptReason), - deopt_id_(kNoDeoptimizationId), - line_info_(line_info), + line_info_(std::move(line_info)), instruction_start_(instruction_start) {} +inline CodeEntry* ProfileGenerator::FindEntry(Address address) { + CodeEntry* entry = code_map_.FindEntry(address); + if (entry) entry->mark_used(); + return entry; +} + ProfileNode::ProfileNode(ProfileTree* tree, CodeEntry* entry, ProfileNode* parent) : tree_(tree), entry_(entry), self_ticks_(0), - children_(CodeEntriesMatch), parent_(parent), - id_(tree->next_node_id()), - line_ticks_(LineTickMatch) { + id_(tree->next_node_id()) { tree_->EnqueueNode(this); } diff --git a/deps/v8/src/profiler/profile-generator.cc b/deps/v8/src/profiler/profile-generator.cc index 029b6826ec25fa..e8d805562d1b40 100644 --- a/deps/v8/src/profiler/profile-generator.cc +++ b/deps/v8/src/profiler/profile-generator.cc @@ -18,33 +18,30 @@ namespace v8 { namespace internal { - -JITLineInfoTable::JITLineInfoTable() {} - - -JITLineInfoTable::~JITLineInfoTable() {} - - -void JITLineInfoTable::SetPosition(int pc_offset, int line) { - DCHECK(pc_offset >= 0); - DCHECK(line > 0); // The 1-based number of the source line. - if (GetSourceLineNumber(pc_offset) != line) { - pc_offset_map_.insert(std::make_pair(pc_offset, line)); +void SourcePositionTable::SetPosition(int pc_offset, int line) { + DCHECK_GE(pc_offset, 0); + DCHECK_GT(line, 0); // The 1-based number of the source line. + // Check that we are inserting in ascending order, so that the vector remains + // sorted. + DCHECK(pc_offsets_to_lines_.empty() || + pc_offsets_to_lines_.back().pc_offset < pc_offset); + if (pc_offsets_to_lines_.empty() || + pc_offsets_to_lines_.back().line_number != line) { + pc_offsets_to_lines_.push_back({pc_offset, line}); } } - -int JITLineInfoTable::GetSourceLineNumber(int pc_offset) const { - PcOffsetMap::const_iterator it = pc_offset_map_.lower_bound(pc_offset); - if (it == pc_offset_map_.end()) { - if (pc_offset_map_.empty()) return v8::CpuProfileNode::kNoLineNumberInfo; - return (--pc_offset_map_.end())->second; +int SourcePositionTable::GetSourceLineNumber(int pc_offset) const { + if (pc_offsets_to_lines_.empty()) { + return v8::CpuProfileNode::kNoLineNumberInfo; } - return it->second; + auto it = + std::upper_bound(pc_offsets_to_lines_.begin(), pc_offsets_to_lines_.end(), + PCOffsetAndLineNumber{pc_offset, 0}); + if (it != pc_offsets_to_lines_.begin()) --it; + return it->line_number; } - -const char* const CodeEntry::kEmptyNamePrefix = ""; const char* const CodeEntry::kEmptyResourceName = ""; const char* const CodeEntry::kEmptyBailoutReason = ""; const char* const CodeEntry::kNoDeoptReason = ""; @@ -85,24 +82,12 @@ CodeEntry* CodeEntry::UnresolvedEntryCreateTrait::Create() { CodeEntry::kUnresolvedFunctionName); } -CodeEntry::~CodeEntry() { - delete line_info_; - for (auto location : inline_locations_) { - for (auto entry : location.second) { - delete entry; - } - } -} - - uint32_t CodeEntry::GetHash() const { uint32_t hash = ComputeIntegerHash(tag()); if (script_id_ != v8::UnboundScript::kNoScriptId) { hash ^= ComputeIntegerHash(static_cast(script_id_)); hash ^= ComputeIntegerHash(static_cast(position_)); } else { - hash ^= ComputeIntegerHash( - static_cast(reinterpret_cast(name_prefix_))); hash ^= ComputeIntegerHash( static_cast(reinterpret_cast(name_))); hash ^= ComputeIntegerHash( @@ -112,14 +97,12 @@ uint32_t CodeEntry::GetHash() const { return hash; } - -bool CodeEntry::IsSameFunctionAs(CodeEntry* entry) const { +bool CodeEntry::IsSameFunctionAs(const CodeEntry* entry) const { if (this == entry) return true; if (script_id_ != v8::UnboundScript::kNoScriptId) { return script_id_ == entry->script_id_ && position_ == entry->position_; } - return name_prefix_ == entry->name_prefix_ && name_ == entry->name_ && - resource_name_ == entry->resource_name_ && + return name_ == entry->name_ && resource_name_ == entry->resource_name_ && line_number_ == entry->line_number_; } @@ -131,30 +114,31 @@ void CodeEntry::SetBuiltinId(Builtins::Name id) { int CodeEntry::GetSourceLine(int pc_offset) const { - if (line_info_ && !line_info_->empty()) { - return line_info_->GetSourceLineNumber(pc_offset); - } + if (line_info_) return line_info_->GetSourceLineNumber(pc_offset); return v8::CpuProfileNode::kNoLineNumberInfo; } -void CodeEntry::AddInlineStack(int pc_offset, - std::vector inline_stack) { - inline_locations_.insert(std::make_pair(pc_offset, std::move(inline_stack))); +void CodeEntry::AddInlineStack( + int pc_offset, std::vector> inline_stack) { + EnsureRareData()->inline_locations_.insert( + std::make_pair(pc_offset, std::move(inline_stack))); } -const std::vector* CodeEntry::GetInlineStack(int pc_offset) const { - auto it = inline_locations_.find(pc_offset); - return it != inline_locations_.end() ? &it->second : NULL; +const std::vector>* CodeEntry::GetInlineStack( + int pc_offset) const { + if (!rare_data_) return nullptr; + auto it = rare_data_->inline_locations_.find(pc_offset); + return it != rare_data_->inline_locations_.end() ? &it->second : nullptr; } -void CodeEntry::AddDeoptInlinedFrames( - int deopt_id, std::vector inlined_frames) { - deopt_inlined_frames_.insert( - std::make_pair(deopt_id, std::move(inlined_frames))); -} - -bool CodeEntry::HasDeoptInlinedFramesFor(int deopt_id) const { - return deopt_inlined_frames_.find(deopt_id) != deopt_inlined_frames_.end(); +void CodeEntry::set_deopt_info( + const char* deopt_reason, int deopt_id, + std::vector inlined_frames) { + DCHECK(!has_deopt_info()); + RareData* rare_data = EnsureRareData(); + rare_data->deopt_reason_ = deopt_reason; + rare_data->deopt_id_ = deopt_id; + rare_data->deopt_inlined_frames_ = std::move(inlined_frames); } void CodeEntry::FillFunctionInfo(SharedFunctionInfo* shared) { @@ -162,24 +146,32 @@ void CodeEntry::FillFunctionInfo(SharedFunctionInfo* shared) { Script* script = Script::cast(shared->script()); set_script_id(script->id()); set_position(shared->start_position()); - set_bailout_reason(GetBailoutReason(shared->disable_optimization_reason())); + if (shared->optimization_disabled()) { + set_bailout_reason(GetBailoutReason(shared->disable_optimization_reason())); + } } CpuProfileDeoptInfo CodeEntry::GetDeoptInfo() { DCHECK(has_deopt_info()); CpuProfileDeoptInfo info; - info.deopt_reason = deopt_reason_; - DCHECK_NE(kNoDeoptimizationId, deopt_id_); - if (deopt_inlined_frames_.find(deopt_id_) == deopt_inlined_frames_.end()) { + info.deopt_reason = rare_data_->deopt_reason_; + DCHECK_NE(kNoDeoptimizationId, rare_data_->deopt_id_); + if (rare_data_->deopt_inlined_frames_.empty()) { info.stack.push_back(CpuProfileDeoptFrame( {script_id_, static_cast(std::max(0, position()))})); } else { - info.stack = deopt_inlined_frames_[deopt_id_]; + info.stack = rare_data_->deopt_inlined_frames_; } return info; } +CodeEntry::RareData* CodeEntry::EnsureRareData() { + if (!rare_data_) { + rare_data_.reset(new RareData()); + } + return rare_data_.get(); +} void ProfileNode::CollectDeoptInfo(CodeEntry* entry) { deopt_infos_.push_back(entry->GetDeoptInfo()); @@ -188,23 +180,21 @@ void ProfileNode::CollectDeoptInfo(CodeEntry* entry) { ProfileNode* ProfileNode::FindChild(CodeEntry* entry) { - base::HashMap::Entry* map_entry = - children_.Lookup(entry, CodeEntryHash(entry)); - return map_entry != NULL ? - reinterpret_cast(map_entry->value) : NULL; + auto map_entry = children_.find(entry); + return map_entry != children_.end() ? map_entry->second : nullptr; } ProfileNode* ProfileNode::FindOrAddChild(CodeEntry* entry) { - base::HashMap::Entry* map_entry = - children_.LookupOrInsert(entry, CodeEntryHash(entry)); - ProfileNode* node = reinterpret_cast(map_entry->value); - if (!node) { - node = new ProfileNode(tree_, entry, this); - map_entry->value = node; + auto map_entry = children_.find(entry); + if (map_entry == children_.end()) { + ProfileNode* node = new ProfileNode(tree_, entry, this); + children_[entry] = node; children_list_.push_back(node); + return node; + } else { + return map_entry->second; } - return node; } @@ -212,10 +202,12 @@ void ProfileNode::IncrementLineTicks(int src_line) { if (src_line == v8::CpuProfileNode::kNoLineNumberInfo) return; // Increment a hit counter of a certain source line. // Add a new source line if not found. - base::HashMap::Entry* e = - line_ticks_.LookupOrInsert(reinterpret_cast(src_line), src_line); - DCHECK(e); - e->value = reinterpret_cast(reinterpret_cast(e->value) + 1); + auto map_entry = line_ticks_.find(src_line); + if (map_entry == line_ticks_.end()) { + line_ticks_[src_line] = 1; + } else { + line_ticks_[src_line]++; + } } @@ -223,19 +215,16 @@ bool ProfileNode::GetLineTicks(v8::CpuProfileNode::LineTick* entries, unsigned int length) const { if (entries == NULL || length == 0) return false; - unsigned line_count = line_ticks_.occupancy(); + unsigned line_count = static_cast(line_ticks_.size()); if (line_count == 0) return true; if (length < line_count) return false; v8::CpuProfileNode::LineTick* entry = entries; - for (base::HashMap::Entry *p = line_ticks_.Start(); p != NULL; - p = line_ticks_.Next(p), entry++) { - entry->line = - static_cast(reinterpret_cast(p->key)); - entry->hit_count = - static_cast(reinterpret_cast(p->value)); + for (auto p = line_ticks_.begin(); p != line_ticks_.end(); p++, entry++) { + entry->line = p->first; + entry->hit_count = p->second; } return true; @@ -243,9 +232,8 @@ bool ProfileNode::GetLineTicks(v8::CpuProfileNode::LineTick* entries, void ProfileNode::Print(int indent) { - base::OS::Print("%5u %*s %s%s %d #%d", self_ticks_, indent, "", - entry_->name_prefix(), entry_->name(), entry_->script_id(), - id()); + base::OS::Print("%5u %*s %s %d #%d", self_ticks_, indent, "", entry_->name(), + entry_->script_id(), id()); if (entry_->resource_name()[0] != '\0') base::OS::Print(" %s:%d", entry_->resource_name(), entry_->line_number()); base::OS::Print("\n"); @@ -268,9 +256,8 @@ void ProfileNode::Print(int indent) { base::OS::Print("%*s bailed out due to '%s'\n", indent + 10, "", bailout_reason); } - for (base::HashMap::Entry* p = children_.Start(); p != NULL; - p = children_.Next(p)) { - reinterpret_cast(p->value)->Print(indent + 2); + for (auto child : children_) { + child.second->Print(indent + 2); } } @@ -291,8 +278,7 @@ ProfileTree::ProfileTree(Isolate* isolate) next_node_id_(1), root_(new ProfileNode(this, &root_entry_, nullptr)), isolate_(isolate), - next_function_id_(1), - function_ids_(ProfileNode::CodeEntriesMatch) {} + next_function_id_(1) {} ProfileTree::~ProfileTree() { DeleteNodesCallback cb; @@ -302,12 +288,11 @@ ProfileTree::~ProfileTree() { unsigned ProfileTree::GetFunctionId(const ProfileNode* node) { CodeEntry* code_entry = node->entry(); - base::HashMap::Entry* entry = - function_ids_.LookupOrInsert(code_entry, code_entry->GetHash()); - if (!entry->value) { - entry->value = reinterpret_cast(next_function_id_++); + auto map_entry = function_ids_.find(code_entry); + if (map_entry == function_ids_.end()) { + return function_ids_[code_entry] = next_function_id_++; } - return static_cast(reinterpret_cast(entry->value)); + return function_ids_[code_entry]; } ProfileNode* ProfileTree::AddPathFromEnd(const std::vector& path, @@ -502,19 +487,29 @@ void CpuProfile::Print() { top_down_.Print(); } +CodeMap::CodeMap() = default; +CodeMap::~CodeMap() = default; + void CodeMap::AddCode(Address addr, CodeEntry* entry, unsigned size) { - DeleteAllCoveredCode(addr, addr + size); - code_map_.insert({addr, CodeEntryInfo(entry, size)}); + ClearCodesInRange(addr, addr + size); + code_map_.emplace( + addr, CodeEntryInfo{static_cast(code_entries_.size()), size}); + code_entries_.push_back(std::unique_ptr(entry)); } -void CodeMap::DeleteAllCoveredCode(Address start, Address end) { +void CodeMap::ClearCodesInRange(Address start, Address end) { auto left = code_map_.upper_bound(start); if (left != code_map_.begin()) { --left; if (left->first + left->second.size <= start) ++left; } auto right = left; - while (right != code_map_.end() && right->first < end) ++right; + for (; right != code_map_.end() && right->first < end; ++right) { + std::unique_ptr& entry = code_entries_[right->second.index]; + if (!entry->used()) { + entry.reset(); + } + } code_map_.erase(left, right); } @@ -523,7 +518,10 @@ CodeEntry* CodeMap::FindEntry(Address addr) { if (it == code_map_.begin()) return nullptr; --it; Address end_address = it->first + it->second.size; - return addr < end_address ? it->second.entry : nullptr; + if (addr >= end_address) return nullptr; + CodeEntry* entry = code_entries_[it->second.index].get(); + DCHECK(entry); + return entry; } void CodeMap::MoveCode(Address from, Address to) { @@ -532,18 +530,20 @@ void CodeMap::MoveCode(Address from, Address to) { if (it == code_map_.end()) return; CodeEntryInfo info = it->second; code_map_.erase(it); - AddCode(to, info.entry, info.size); + DCHECK(from + info.size <= to || to + info.size <= from); + ClearCodesInRange(to, to + info.size); + code_map_.emplace(to, info); } void CodeMap::Print() { - for (auto it = code_map_.begin(); it != code_map_.end(); ++it) { - base::OS::Print("%p %5d %s\n", static_cast(it->first), - it->second.size, it->second.entry->name()); + for (const auto& pair : code_map_) { + base::OS::Print("%p %5d %s\n", reinterpret_cast(pair.first), + pair.second.size, code_entries_[pair.second.index]->name()); } } CpuProfilesCollection::CpuProfilesCollection(Isolate* isolate) - : resource_names_(isolate->heap()), + : resource_names_(isolate->heap()->HashSeed()), profiler_(nullptr), current_profiles_semaphore_(1) {} @@ -653,14 +653,15 @@ void ProfileGenerator::RecordTickSample(const TickSample& sample) { // Don't use PC when in external callback code, as it can point // inside callback's code, and we will erroneously report // that a callback calls itself. - entries.push_back(FindEntry(sample.external_callback_entry)); + entries.push_back( + FindEntry(reinterpret_cast
(sample.external_callback_entry))); } else { - CodeEntry* pc_entry = FindEntry(sample.pc); + CodeEntry* pc_entry = FindEntry(reinterpret_cast
(sample.pc)); // If there is no pc_entry we're likely in native code. // Find out, if top of stack was pointing inside a JS function // meaning that we have encountered a frameless invocation. if (!pc_entry && !sample.has_external_callback) { - pc_entry = FindEntry(sample.tos); + pc_entry = FindEntry(reinterpret_cast
(sample.tos)); } // If pc is in the function code before it set up stack frame or after the // frame was destroyed SafeStackFrameIterator incorrectly thinks that @@ -698,11 +699,13 @@ void ProfileGenerator::RecordTickSample(const TickSample& sample) { // Find out if the entry has an inlining stack associated. int pc_offset = static_cast(stack_pos - entry->instruction_start()); - const std::vector* inline_stack = + const std::vector>* inline_stack = entry->GetInlineStack(pc_offset); if (inline_stack) { - entries.insert(entries.end(), inline_stack->rbegin(), - inline_stack->rend()); + std::transform( + inline_stack->rbegin(), inline_stack->rend(), + std::back_inserter(entries), + [=](const std::unique_ptr& ptr) { return ptr.get(); }); } // Skip unresolved frames (e.g. internal frame) and get source line of // the first JS caller. @@ -736,10 +739,6 @@ void ProfileGenerator::RecordTickSample(const TickSample& sample) { sample.update_stats); } -CodeEntry* ProfileGenerator::FindEntry(void* address) { - return code_map_.FindEntry(reinterpret_cast
(address)); -} - CodeEntry* ProfileGenerator::EntryForVMState(StateTag tag) { switch (tag) { case GC: diff --git a/deps/v8/src/profiler/profile-generator.h b/deps/v8/src/profiler/profile-generator.h index ddd34b00a47e4b..db148018e41426 100644 --- a/deps/v8/src/profiler/profile-generator.h +++ b/deps/v8/src/profiler/profile-generator.h @@ -5,9 +5,14 @@ #ifndef V8_PROFILER_PROFILE_GENERATOR_H_ #define V8_PROFILER_PROFILE_GENERATOR_H_ +#include #include +#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 +22,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 +96,20 @@ 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; 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 +131,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,25 +164,20 @@ 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); }; @@ -186,7 +201,9 @@ class ProfileNode { unsigned id() const { return id_; } unsigned function_id() const; ProfileNode* parent() const { return parent_; } - unsigned int GetHitLineCount() const { return line_ticks_.occupancy(); } + 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 +214,26 @@ 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 CodeEntryEqual { + bool operator()(CodeEntry* entry1, CodeEntry* entry2) const { + return entry1 == entry2 || entry1->IsSameFunctionAs(entry2); + } + }; + struct CodeEntryHash { + std::size_t operator()(CodeEntry* entry) const { return entry->GetHash(); } + }; ProfileTree* tree_; CodeEntry* entry_; unsigned self_ticks_; - // Mapping from CodeEntry* to ProfileNode* - base::CustomMatcherHashMap children_; + std::unordered_map + children_; 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_; @@ -260,7 +278,7 @@ class ProfileTree { Isolate* isolate_; unsigned next_function_id_; - base::CustomMatcherHashMap function_ids_; + std::unordered_map function_ids_; DISALLOW_COPY_AND_ASSIGN(ProfileTree); }; @@ -310,7 +328,8 @@ class CpuProfile { class CodeMap { public: - CodeMap() {} + CodeMap(); + ~CodeMap(); void AddCode(Address addr, CodeEntry* entry, unsigned size); void MoveCode(Address from, Address to); @@ -319,14 +338,13 @@ class CodeMap { private: struct CodeEntryInfo { - CodeEntryInfo(CodeEntry* an_entry, unsigned a_size) - : entry(an_entry), size(a_size) { } - CodeEntry* entry; + unsigned index; unsigned size; }; - void DeleteAllCoveredCode(Address start, Address end); + void ClearCodesInRange(Address start, Address end); + std::deque> code_entries_; std::map code_map_; DISALLOW_COPY_AND_ASSIGN(CodeMap); @@ -365,7 +383,6 @@ class CpuProfilesCollection { DISALLOW_COPY_AND_ASSIGN(CpuProfilesCollection); }; - class ProfileGenerator { public: explicit ProfileGenerator(CpuProfilesCollection* profiles); @@ -375,7 +392,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 +401,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..e50f15ac746cef 100644 --- a/deps/v8/src/profiler/profiler-listener.cc +++ b/deps/v8/src/profiler/profiler-listener.cc @@ -13,8 +13,11 @@ 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; @@ -33,9 +36,9 @@ void ProfilerListener::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag, CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_; rec->start = code->address(); 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(); DispatchCodeEvent(evt_rec); @@ -47,9 +50,9 @@ void ProfilerListener::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag, CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_; rec->start = code->address(); 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(); DispatchCodeEvent(evt_rec); @@ -63,10 +66,10 @@ void ProfilerListener::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag, CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_; rec->start = code->address(); 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(); @@ -81,12 +84,10 @@ void ProfilerListener::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag, CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION); CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_; rec->start = abstract_code->address(); - JITLineInfoTable* line_table = NULL; + 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,16 +96,14 @@ 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(); DispatchCodeEvent(evt_rec); @@ -116,9 +115,9 @@ void ProfilerListener::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag, CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_; rec->start = code->address(); 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(); DispatchCodeEvent(evt_rec); @@ -151,6 +150,10 @@ void ProfilerListener::CodeDeoptEvent(Code* code, DeoptKind kind, Address pc, 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); } @@ -159,7 +162,7 @@ void ProfilerListener::GetterCallbackEvent(Name* name, Address entry_point) { CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_; rec->start = entry_point; rec->entry = - NewCodeEntry(CodeEventListener::CALLBACK_TAG, GetName(name), "get "); + NewCodeEntry(CodeEventListener::CALLBACK_TAG, GetConsName("get ", name)); rec->size = 1; DispatchCodeEvent(evt_rec); } @@ -170,9 +173,9 @@ void ProfilerListener::RegExpCodeCreateEvent(AbstractCode* code, CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_; rec->start = code->address(); 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()); + CpuProfileNode::kNoColumnNumberInfo, nullptr, code->instruction_start()); rec->size = code->ExecutableSize(); DispatchCodeEvent(evt_rec); } @@ -182,7 +185,7 @@ void ProfilerListener::SetterCallbackEvent(Name* name, Address entry_point) { CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_; rec->start = entry_point; rec->entry = - NewCodeEntry(CodeEventListener::CALLBACK_TAG, GetName(name), "set "); + NewCodeEntry(CodeEventListener::CALLBACK_TAG, GetConsName("set ", name)); rec->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..8f5d81d82a217a 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; @@ -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/test/cctest/test-cpu-profiler.cc b/deps/v8/test/cctest/test-cpu-profiler.cc index b441d04fdd31db..c46d8df8658c30 100644 --- a/deps/v8/test/cctest/test-cpu-profiler.cc +++ b/deps/v8/test/cctest/test-cpu-profiler.cc @@ -172,9 +172,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"; @@ -193,8 +192,7 @@ TEST(CodeEvents) { // Enqueue a tick event to enable code events processing. EnqueueTickSampleEvent(processor, aaa_code->address()); - profiler_listener.RemoveObserver(&profiler); - isolate->code_event_dispatcher()->RemoveListener(&profiler_listener); + isolate->logger()->removeCodeEventListener(&profiler_listener); processor->StopSynchronously(); // Check the state of profile generator. @@ -241,9 +239,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 +255,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,9 +310,7 @@ 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"); @@ -329,8 +323,6 @@ TEST(Issue1398) { } processor->FinishTickSample(); - profiler_listener.RemoveObserver(&profiler); - isolate->code_event_dispatcher()->RemoveListener(&profiler_listener); processor->StopSynchronously(); CpuProfile* profile = profiles->StopProfiling(""); CHECK(profile); @@ -1087,9 +1079,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 +1091,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 +1100,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 +2282,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-profile-generator.cc b/deps/v8/test/cctest/test-profile-generator.cc index 67d289302495e7..4daa675a70adff 100644 --- a/deps/v8/test/cctest/test-profile-generator.cc +++ b/deps/v8/test/cctest/test-profile-generator.cc @@ -278,52 +278,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 +399,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 +460,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 +488,6 @@ TEST(NoSamples) { CHECK_EQ(3u, nodeId - 1); CHECK_EQ(0, profile->samples_count()); - - delete entry1; } diff --git a/lib/_http_agent.js b/lib/_http_agent.js index 7586a48680bb6a..5f1e56caeab981 100644 --- a/lib/_http_agent.js +++ b/lib/_http_agent.js @@ -277,7 +277,6 @@ function installListeners(agent, s, options) { s.removeListener('close', onClose); s.removeListener('free', onFree); s.removeListener('agentRemove', onRemove); - s._httpMessage = null; } s.on('agentRemove', onRemove); } diff --git a/lib/_http_client.js b/lib/_http_client.js index dfab2fce131122..135d31acaaec2d 100644 --- a/lib/_http_client.js +++ b/lib/_http_client.js @@ -470,6 +470,7 @@ function socketOnData(d) { // TODO(isaacs): Need a way to reset a stream to fresh state // IE, not flowing, and not explicitly paused. socket._readableState.flowing = null; + socket._httpMessage = null; req.emit(eventName, res, socket, bodyHead); req.emit('close'); diff --git a/test/parallel/test-error-reporting.js b/test/parallel/test-error-reporting.js index 57b647df792c90..b9d78b181aef47 100644 --- a/test/parallel/test-error-reporting.js +++ b/test/parallel/test-error-reporting.js @@ -32,17 +32,14 @@ function errExec(script, callback) { assert.ok(err); // More than one line of error output. - assert.ok(stderr.split('\n').length > 2); - - // Assert the script is mentioned in error output. - assert.ok(stderr.includes(script)); + assert.ok(stderr.split('\n').length); // Proxy the args for more tests. callback(err, stdout, stderr); }); } -const syntaxErrorMessage = /SyntaxError/; +const syntaxErrorMessage = /\bSyntaxError\b/; // Simple throw error @@ -65,7 +62,6 @@ errExec('throws_error3.js', common.mustCall(function(err, stdout, stderr) { // throw ILLEGAL error errExec('throws_error4.js', common.mustCall(function(err, stdout, stderr) { - assert.ok(/\/\*\*/.test(stderr)); assert.ok(syntaxErrorMessage.test(stderr)); })); diff --git a/test/parallel/test-http-agent-remove.js b/test/parallel/test-http-agent-remove.js new file mode 100644 index 00000000000000..24fc7fcb8282fe --- /dev/null +++ b/test/parallel/test-http-agent-remove.js @@ -0,0 +1,21 @@ +'use strict'; +const { mustCall } = require('../common'); + +const http = require('http'); +const { strictEqual } = require('assert'); + +const server = http.createServer(mustCall((req, res) => { + res.flushHeaders(); +})); + +server.listen(0, mustCall(() => { + const req = http.get({ + port: server.address().port + }, mustCall(() => { + const { socket } = req; + socket.emit('agentRemove'); + strictEqual(socket._httpMessage, req); + socket.destroy(); + server.close(); + })); +}));