diff options
Diffstat (limited to 'deps/v8/src/profiler')
21 files changed, 912 insertions, 688 deletions
diff --git a/deps/v8/src/profiler/allocation-tracker.cc b/deps/v8/src/profiler/allocation-tracker.cc index 51cb0eb47f..d01060543d 100644 --- a/deps/v8/src/profiler/allocation-tracker.cc +++ b/deps/v8/src/profiler/allocation-tracker.cc @@ -213,7 +213,7 @@ void AllocationTracker::AllocationEvent(Address addr, int size) { JavaScriptFrameIterator it(isolate); while (!it.done() && length < kMaxAllocationTraceLength) { JavaScriptFrame* frame = it.frame(); - SharedFunctionInfo* shared = frame->function()->shared(); + SharedFunctionInfo shared = frame->function()->shared(); SnapshotObjectId id = ids_->FindOrAddEntry( shared->address(), shared->Size(), false); allocation_trace_buffer_[length++] = AddFunctionInfo(shared, id); @@ -237,8 +237,7 @@ static uint32_t SnapshotObjectIdHash(SnapshotObjectId id) { return ComputeUnseededHash(static_cast<uint32_t>(id)); } - -unsigned AllocationTracker::AddFunctionInfo(SharedFunctionInfo* shared, +unsigned AllocationTracker::AddFunctionInfo(SharedFunctionInfo shared, SnapshotObjectId id) { base::HashMap::Entry* entry = id_to_function_info_index_.LookupOrInsert( reinterpret_cast<void*>(id), SnapshotObjectIdHash(id)); @@ -247,9 +246,9 @@ unsigned AllocationTracker::AddFunctionInfo(SharedFunctionInfo* shared, info->name = names_->GetName(shared->DebugName()); info->function_id = id; if (shared->script()->IsScript()) { - Script* script = Script::cast(shared->script()); + Script script = Script::cast(shared->script()); if (script->name()->IsName()) { - Name* name = Name::cast(script->name()); + Name name = Name::cast(script->name()); info->script_name = names_->GetName(name); } info->script_id = script->id(); @@ -264,7 +263,6 @@ unsigned AllocationTracker::AddFunctionInfo(SharedFunctionInfo* shared, return static_cast<unsigned>(reinterpret_cast<intptr_t>((entry->value))); } - unsigned AllocationTracker::functionInfoIndexForVMState(StateTag state) { if (state != OTHER) return 0; if (info_index_for_other_state_ == 0) { @@ -277,20 +275,18 @@ unsigned AllocationTracker::functionInfoIndexForVMState(StateTag state) { return info_index_for_other_state_; } - -AllocationTracker::UnresolvedLocation::UnresolvedLocation( - Script* script, int start, FunctionInfo* info) - : start_position_(start), - info_(info) { +AllocationTracker::UnresolvedLocation::UnresolvedLocation(Script script, + int start, + FunctionInfo* info) + : start_position_(start), info_(info) { script_ = script->GetIsolate()->global_handles()->Create(script); - GlobalHandles::MakeWeak(reinterpret_cast<Object**>(script_.location()), this, - &HandleWeakScript, v8::WeakCallbackType::kParameter); + GlobalHandles::MakeWeak(script_.location(), this, &HandleWeakScript, + v8::WeakCallbackType::kParameter); } - AllocationTracker::UnresolvedLocation::~UnresolvedLocation() { if (!script_.is_null()) { - GlobalHandles::Destroy(reinterpret_cast<Object**>(script_.location())); + GlobalHandles::Destroy(script_.location()); } } @@ -306,7 +302,7 @@ void AllocationTracker::UnresolvedLocation::HandleWeakScript( const v8::WeakCallbackInfo<void>& data) { UnresolvedLocation* loc = reinterpret_cast<UnresolvedLocation*>(data.GetParameter()); - GlobalHandles::Destroy(reinterpret_cast<Object**>(loc->script_.location())); + GlobalHandles::Destroy(loc->script_.location()); loc->script_ = Handle<Script>::null(); } diff --git a/deps/v8/src/profiler/allocation-tracker.h b/deps/v8/src/profiler/allocation-tracker.h index bff9a62750..5305bdbf2d 100644 --- a/deps/v8/src/profiler/allocation-tracker.h +++ b/deps/v8/src/profiler/allocation-tracker.h @@ -120,12 +120,12 @@ class AllocationTracker { AddressToTraceMap* address_to_trace() { return &address_to_trace_; } private: - unsigned AddFunctionInfo(SharedFunctionInfo* info, SnapshotObjectId id); + unsigned AddFunctionInfo(SharedFunctionInfo info, SnapshotObjectId id); unsigned functionInfoIndexForVMState(StateTag state); class UnresolvedLocation { public: - UnresolvedLocation(Script* script, int start, FunctionInfo* info); + UnresolvedLocation(Script script, int start, FunctionInfo* info); ~UnresolvedLocation(); void Resolve(); diff --git a/deps/v8/src/profiler/circular-queue.h b/deps/v8/src/profiler/circular-queue.h index d3df1d9f38..fcbb898571 100644 --- a/deps/v8/src/profiler/circular-queue.h +++ b/deps/v8/src/profiler/circular-queue.h @@ -46,7 +46,7 @@ class SamplingCircularQueue { // completely processed by the consumer. }; - struct V8_ALIGNED(PROCESSOR_CACHE_LINE_SIZE) Entry { + struct alignas(PROCESSOR_CACHE_LINE_SIZE) Entry { Entry() : marker(kEmpty) {} T record; base::Atomic32 marker; @@ -55,8 +55,8 @@ class SamplingCircularQueue { Entry* Next(Entry* entry); Entry buffer_[Length]; - V8_ALIGNED(PROCESSOR_CACHE_LINE_SIZE) Entry* enqueue_pos_; - V8_ALIGNED(PROCESSOR_CACHE_LINE_SIZE) Entry* dequeue_pos_; + alignas(PROCESSOR_CACHE_LINE_SIZE) Entry* enqueue_pos_; + alignas(PROCESSOR_CACHE_LINE_SIZE) Entry* dequeue_pos_; DISALLOW_COPY_AND_ASSIGN(SamplingCircularQueue); }; diff --git a/deps/v8/src/profiler/cpu-profiler-inl.h b/deps/v8/src/profiler/cpu-profiler-inl.h index 9274bc03c6..eb05c5be56 100644 --- a/deps/v8/src/profiler/cpu-profiler-inl.h +++ b/deps/v8/src/profiler/cpu-profiler-inl.h @@ -53,8 +53,7 @@ void ReportBuiltinEventRecord::UpdateCodeMap(CodeMap* code_map) { entry->SetBuiltinId(builtin_id); } - -TickSample* ProfilerEventsProcessor::StartTickSample() { +TickSample* SamplingEventsProcessor::StartTickSample() { void* address = ticks_buffer_.StartEnqueue(); if (address == nullptr) return nullptr; TickSampleEventRecord* evt = @@ -62,8 +61,7 @@ TickSample* ProfilerEventsProcessor::StartTickSample() { return &evt->sample; } - -void ProfilerEventsProcessor::FinishTickSample() { +void SamplingEventsProcessor::FinishTickSample() { ticks_buffer_.FinishEnqueue(); } diff --git a/deps/v8/src/profiler/cpu-profiler.cc b/deps/v8/src/profiler/cpu-profiler.cc index 21d7c9072e..c3fba16879 100644 --- a/deps/v8/src/profiler/cpu-profiler.cc +++ b/deps/v8/src/profiler/cpu-profiler.cc @@ -14,7 +14,7 @@ #include "src/deoptimizer.h" #include "src/frames-inl.h" #include "src/locked-queue-inl.h" -#include "src/log-inl.h" +#include "src/log.h" #include "src/profiler/cpu-profiler-inl.h" #include "src/vm-state-inl.h" @@ -25,7 +25,7 @@ static const int kProfilerStackSize = 64 * KB; class CpuSampler : public sampler::Sampler { public: - CpuSampler(Isolate* isolate, ProfilerEventsProcessor* processor) + CpuSampler(Isolate* isolate, SamplingEventsProcessor* processor) : sampler::Sampler(reinterpret_cast<v8::Isolate*>(isolate)), processor_(processor) {} @@ -42,60 +42,68 @@ class CpuSampler : public sampler::Sampler { } private: - ProfilerEventsProcessor* processor_; + SamplingEventsProcessor* processor_; }; ProfilerEventsProcessor::ProfilerEventsProcessor(Isolate* isolate, - ProfileGenerator* generator, - base::TimeDelta period) + ProfileGenerator* generator) : Thread(Thread::Options("v8:ProfEvntProc", kProfilerStackSize)), generator_(generator), - sampler_(new CpuSampler(isolate, this)), running_(1), - period_(period), last_code_event_id_(0), - last_processed_code_event_id_(0) { - sampler_->IncreaseProfilingDepth(); -} + last_processed_code_event_id_(0), + isolate_(isolate) {} -ProfilerEventsProcessor::~ProfilerEventsProcessor() { - sampler_->DecreaseProfilingDepth(); +SamplingEventsProcessor::SamplingEventsProcessor(Isolate* isolate, + ProfileGenerator* generator, + base::TimeDelta period) + : ProfilerEventsProcessor(isolate, generator), + sampler_(new CpuSampler(isolate, this)), + period_(period) { + sampler_->Start(); } +SamplingEventsProcessor::~SamplingEventsProcessor() { sampler_->Stop(); } + +ProfilerEventsProcessor::~ProfilerEventsProcessor() = default; + void ProfilerEventsProcessor::Enqueue(const CodeEventsContainer& event) { event.generic.order = ++last_code_event_id_; events_buffer_.Enqueue(event); } - -void ProfilerEventsProcessor::AddDeoptStack(Isolate* isolate, Address from, - int fp_to_sp_delta) { +void ProfilerEventsProcessor::AddDeoptStack(Address from, int fp_to_sp_delta) { TickSampleEventRecord record(last_code_event_id_); RegisterState regs; - Address fp = isolate->c_entry_fp(isolate->thread_local_top()); + Address fp = isolate_->c_entry_fp(isolate_->thread_local_top()); regs.sp = reinterpret_cast<void*>(fp - fp_to_sp_delta); regs.fp = reinterpret_cast<void*>(fp); regs.pc = reinterpret_cast<void*>(from); - record.sample.Init(isolate, regs, TickSample::kSkipCEntryFrame, false, false); + record.sample.Init(isolate_, regs, TickSample::kSkipCEntryFrame, false, + false); ticks_from_vm_buffer_.Enqueue(record); } -void ProfilerEventsProcessor::AddCurrentStack(Isolate* isolate, - bool update_stats) { +void ProfilerEventsProcessor::AddCurrentStack(bool update_stats) { TickSampleEventRecord record(last_code_event_id_); RegisterState regs; - StackFrameIterator it(isolate); + StackFrameIterator it(isolate_); if (!it.done()) { StackFrame* frame = it.frame(); regs.sp = reinterpret_cast<void*>(frame->sp()); regs.fp = reinterpret_cast<void*>(frame->fp()); regs.pc = reinterpret_cast<void*>(frame->pc()); } - record.sample.Init(isolate, regs, TickSample::kSkipCEntryFrame, update_stats, + record.sample.Init(isolate_, regs, TickSample::kSkipCEntryFrame, update_stats, false); ticks_from_vm_buffer_.Enqueue(record); } +void ProfilerEventsProcessor::AddSample(TickSample sample) { + TickSampleEventRecord record(last_code_event_id_); + record.sample = sample; + ticks_from_vm_buffer_.Enqueue(record); +} void ProfilerEventsProcessor::StopSynchronously() { if (!base::Relaxed_AtomicExchange(&running_, 0)) return; @@ -123,8 +131,30 @@ bool ProfilerEventsProcessor::ProcessCodeEvent() { return false; } +void ProfilerEventsProcessor::CodeEventHandler( + const CodeEventsContainer& evt_rec) { + switch (evt_rec.generic.type) { + case CodeEventRecord::CODE_CREATION: + case CodeEventRecord::CODE_MOVE: + case CodeEventRecord::CODE_DISABLE_OPT: + Enqueue(evt_rec); + break; + case CodeEventRecord::CODE_DEOPT: { + const CodeDeoptEventRecord* rec = &evt_rec.CodeDeoptEventRecord_; + Address pc = rec->pc; + int fp_to_sp_delta = rec->fp_to_sp_delta; + Enqueue(evt_rec); + AddDeoptStack(pc, fp_to_sp_delta); + break; + } + case CodeEventRecord::NONE: + case CodeEventRecord::REPORT_BUILTIN: + UNREACHABLE(); + } +} + ProfilerEventsProcessor::SampleProcessingResult - ProfilerEventsProcessor::ProcessOneSample() { +SamplingEventsProcessor::ProcessOneSample() { TickSampleEventRecord record1; if (ticks_from_vm_buffer_.Peek(&record1) && (record1.order == last_processed_code_event_id_)) { @@ -147,8 +177,7 @@ ProfilerEventsProcessor::SampleProcessingResult return OneSampleProcessed; } - -void ProfilerEventsProcessor::Run() { +void SamplingEventsProcessor::Run() { while (!!base::Relaxed_Load(&running_)) { base::TimeTicks nextSampleTime = base::TimeTicks::HighResolutionNow() + period_; @@ -180,8 +209,8 @@ void ProfilerEventsProcessor::Run() { } } - // Schedule next sample. sampler_ is nullptr in tests. - if (sampler_) sampler_->DoSample(); + // Schedule next sample. + sampler_->DoSample(); } // Process remaining tick events. @@ -193,16 +222,11 @@ void ProfilerEventsProcessor::Run() { } while (ProcessCodeEvent()); } - -void* ProfilerEventsProcessor::operator new(size_t size) { - return AlignedAlloc(size, V8_ALIGNOF(ProfilerEventsProcessor)); -} - - -void ProfilerEventsProcessor::operator delete(void* ptr) { - AlignedFree(ptr); +void* SamplingEventsProcessor::operator new(size_t size) { + return AlignedAlloc(size, alignof(SamplingEventsProcessor)); } +void SamplingEventsProcessor::operator delete(void* ptr) { AlignedFree(ptr); } int CpuProfiler::GetProfilesCount() { // The count of profiles doesn't depend on a security token. @@ -229,37 +253,17 @@ void CpuProfiler::DeleteProfile(CpuProfile* profile) { } } -void CpuProfiler::CodeEventHandler(const CodeEventsContainer& evt_rec) { - switch (evt_rec.generic.type) { - case CodeEventRecord::CODE_CREATION: - case CodeEventRecord::CODE_MOVE: - case CodeEventRecord::CODE_DISABLE_OPT: - processor_->Enqueue(evt_rec); - break; - case CodeEventRecord::CODE_DEOPT: { - const CodeDeoptEventRecord* rec = &evt_rec.CodeDeoptEventRecord_; - Address pc = rec->pc; - int fp_to_sp_delta = rec->fp_to_sp_delta; - processor_->Enqueue(evt_rec); - processor_->AddDeoptStack(isolate_, pc, fp_to_sp_delta); - break; - } - default: - UNREACHABLE(); - } -} - namespace { class CpuProfilersManager { public: void AddProfiler(Isolate* isolate, CpuProfiler* profiler) { - base::LockGuard<base::Mutex> lock(&mutex_); + base::MutexGuard lock(&mutex_); profilers_.emplace(isolate, profiler); } void RemoveProfiler(Isolate* isolate, CpuProfiler* profiler) { - base::LockGuard<base::Mutex> lock(&mutex_); + base::MutexGuard lock(&mutex_); auto range = profilers_.equal_range(isolate); for (auto it = range.first; it != range.second; ++it) { if (it->second != profiler) continue; @@ -270,7 +274,7 @@ class CpuProfilersManager { } void CallCollectSample(Isolate* isolate) { - base::LockGuard<base::Mutex> lock(&mutex_); + base::MutexGuard lock(&mutex_); auto range = profilers_.equal_range(isolate); for (auto it = range.first; it != range.second; ++it) { it->second->CollectSample(); @@ -282,8 +286,7 @@ class CpuProfilersManager { base::Mutex mutex_; }; -base::LazyInstance<CpuProfilersManager>::type g_profilers_manager = - LAZY_INSTANCE_INITIALIZER; +DEFINE_LAZY_LEAKY_OBJECT_GETTER(CpuProfilersManager, GetProfilersManager); } // namespace @@ -302,12 +305,12 @@ CpuProfiler::CpuProfiler(Isolate* isolate, CpuProfilesCollection* test_profiles, processor_(test_processor), is_profiling_(false) { profiles_->set_cpu_profiler(this); - g_profilers_manager.Pointer()->AddProfiler(isolate, this); + GetProfilersManager()->AddProfiler(isolate, this); } CpuProfiler::~CpuProfiler() { DCHECK(!is_profiling_); - g_profilers_manager.Pointer()->RemoveProfiler(isolate_, this); + GetProfilersManager()->RemoveProfiler(isolate_, this); } void CpuProfiler::set_sampling_interval(base::TimeDelta value) { @@ -336,12 +339,12 @@ void CpuProfiler::CreateEntriesForRuntimeCallStats() { // static void CpuProfiler::CollectSample(Isolate* isolate) { - g_profilers_manager.Pointer()->CallCollectSample(isolate); + GetProfilersManager()->CallCollectSample(isolate); } void CpuProfiler::CollectSample() { if (processor_) { - processor_->AddCurrentStack(isolate_); + processor_->AddCurrentStack(); } } @@ -353,7 +356,7 @@ void CpuProfiler::StartProfiling(const char* title, bool record_samples, } } -void CpuProfiler::StartProfiling(String* title, bool 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); @@ -361,13 +364,13 @@ void CpuProfiler::StartProfiling(String* title, bool record_samples, void CpuProfiler::StartProcessorIfNotStarted() { if (processor_) { - processor_->AddCurrentStack(isolate_); + processor_->AddCurrentStack(); return; } Logger* logger = isolate_->logger(); // Disable logging when using the new implementation. - saved_is_logging_ = logger->is_logging_; - logger->is_logging_ = false; + saved_is_logging_ = logger->is_logging(); + logger->set_is_logging(false); bool codemap_needs_initialization = false; if (!generator_) { @@ -375,10 +378,10 @@ void CpuProfiler::StartProcessorIfNotStarted() { codemap_needs_initialization = true; CreateEntriesForRuntimeCallStats(); } - processor_.reset(new ProfilerEventsProcessor(isolate_, generator_.get(), + processor_.reset(new SamplingEventsProcessor(isolate_, generator_.get(), sampling_interval_)); if (!profiler_listener_) { - profiler_listener_.reset(new ProfilerListener(isolate_, this)); + profiler_listener_.reset(new ProfilerListener(isolate_, processor_.get())); } logger->AddCodeEventListener(profiler_listener_.get()); is_profiling_ = true; @@ -394,7 +397,7 @@ void CpuProfiler::StartProcessorIfNotStarted() { LogBuiltins(); } // Enable stack sampling. - processor_->AddCurrentStack(isolate_); + processor_->AddCurrentStack(); processor_->StartSynchronously(); } @@ -404,7 +407,7 @@ CpuProfile* CpuProfiler::StopProfiling(const char* title) { return profiles_->StopProfiling(title); } -CpuProfile* CpuProfiler::StopProfiling(String* title) { +CpuProfile* CpuProfiler::StopProfiling(String title) { return StopProfiling(profiles_->GetName(title)); } @@ -420,7 +423,7 @@ void CpuProfiler::StopProcessor() { logger->RemoveCodeEventListener(profiler_listener_.get()); processor_->StopSynchronously(); processor_.reset(); - logger->is_logging_ = saved_is_logging_; + logger->set_is_logging(saved_is_logging_); } diff --git a/deps/v8/src/profiler/cpu-profiler.h b/deps/v8/src/profiler/cpu-profiler.h index 6e2acdfde7..ff5975a7a7 100644 --- a/deps/v8/src/profiler/cpu-profiler.h +++ b/deps/v8/src/profiler/cpu-profiler.h @@ -42,7 +42,6 @@ class CodeEventRecord { enum Type { NONE = 0, CODE_EVENTS_TYPE_LIST(DECLARE_TYPE) - NUMBER_OF_TYPES }; #undef DECLARE_TYPE @@ -131,37 +130,27 @@ class CodeEventsContainer { // This class implements both the profile events processor thread and // methods called by event producers: VM and stack sampler threads. -class ProfilerEventsProcessor : public base::Thread { +class ProfilerEventsProcessor : public base::Thread, public CodeEventObserver { public: - ProfilerEventsProcessor(Isolate* isolate, ProfileGenerator* generator, - base::TimeDelta period); - ~ProfilerEventsProcessor() override; + virtual ~ProfilerEventsProcessor(); + + void CodeEventHandler(const CodeEventsContainer& evt_rec) override; // Thread control. - void Run() override; + void Run() override = 0; void StopSynchronously(); V8_INLINE bool running() { return !!base::Relaxed_Load(&running_); } void Enqueue(const CodeEventsContainer& event); - // Puts current stack into tick sample events buffer. - void AddCurrentStack(Isolate* isolate, bool update_stats = false); - void AddDeoptStack(Isolate* isolate, Address from, int fp_to_sp_delta); + // Puts current stack into the tick sample events buffer. + void AddCurrentStack(bool update_stats = false); + void AddDeoptStack(Address from, int fp_to_sp_delta); + // Add a sample into the tick sample events buffer. Used for testing. + void AddSample(TickSample sample); - // Tick sample events are filled directly in the buffer of the circular - // queue (because the structure is of fixed width, but usually not all - // stack frame entries are filled.) This method returns a pointer to the - // next record of the buffer. - inline TickSample* StartTickSample(); - inline void FinishTickSample(); + protected: + ProfilerEventsProcessor(Isolate* isolate, ProfileGenerator* generator); - // SamplingCircularQueue has stricter alignment requirements than a normal new - // can fulfil, so we need to provide our own new/delete here. - void* operator new(size_t size); - void operator delete(void* ptr); - - sampler::Sampler* sampler() { return sampler_.get(); } - - private: // Called from events processing thread (Run() method.) bool ProcessCodeEvent(); @@ -170,24 +159,54 @@ class ProfilerEventsProcessor : public base::Thread { FoundSampleForNextCodeEvent, NoSamplesInQueue }; - SampleProcessingResult ProcessOneSample(); + virtual SampleProcessingResult ProcessOneSample() = 0; ProfileGenerator* generator_; - std::unique_ptr<sampler::Sampler> sampler_; base::Atomic32 running_; - const base::TimeDelta period_; // Samples & code events processing period. LockedQueue<CodeEventsContainer> events_buffer_; - static const size_t kTickSampleBufferSize = 1 * MB; + LockedQueue<TickSampleEventRecord> ticks_from_vm_buffer_; + std::atomic<unsigned> last_code_event_id_; + unsigned last_processed_code_event_id_; + Isolate* isolate_; +}; + +class SamplingEventsProcessor : public ProfilerEventsProcessor { + public: + SamplingEventsProcessor(Isolate* isolate, ProfileGenerator* generator, + base::TimeDelta period); + ~SamplingEventsProcessor() override; + + // SamplingCircularQueue has stricter alignment requirements than a normal new + // can fulfil, so we need to provide our own new/delete here. + void* operator new(size_t size); + void operator delete(void* ptr); + + void Run() override; + + // Tick sample events are filled directly in the buffer of the circular + // queue (because the structure is of fixed width, but usually not all + // stack frame entries are filled.) This method returns a pointer to the + // next record of the buffer. + // These methods are not thread-safe and should only ever be called by one + // producer (from CpuSampler::SampleStack()). For testing, use AddSample. + inline TickSample* StartTickSample(); + inline void FinishTickSample(); + + sampler::Sampler* sampler() { return sampler_.get(); } + + private: + SampleProcessingResult ProcessOneSample() override; + + static const size_t kTickSampleBufferSize = 512 * KB; static const size_t kTickSampleQueueLength = kTickSampleBufferSize / sizeof(TickSampleEventRecord); SamplingCircularQueue<TickSampleEventRecord, kTickSampleQueueLength> ticks_buffer_; - LockedQueue<TickSampleEventRecord> ticks_from_vm_buffer_; - std::atomic<unsigned> last_code_event_id_; - unsigned last_processed_code_event_id_; + std::unique_ptr<sampler::Sampler> sampler_; + const base::TimeDelta period_; // Samples & code events processing period. }; -class CpuProfiler : public CodeEventObserver { +class CpuProfiler { public: explicit CpuProfiler(Isolate* isolate); @@ -195,7 +214,7 @@ class CpuProfiler : public CodeEventObserver { ProfileGenerator* test_generator, ProfilerEventsProcessor* test_processor); - ~CpuProfiler() override; + ~CpuProfiler(); static void CollectSample(Isolate* isolate); @@ -205,16 +224,14 @@ class CpuProfiler : public CodeEventObserver { void CollectSample(); void StartProfiling(const char* title, bool record_samples = false, ProfilingMode mode = ProfilingMode::kLeafNodeLineNumbers); - void StartProfiling(String* title, bool record_samples, ProfilingMode mode); + void StartProfiling(String title, bool record_samples, ProfilingMode mode); CpuProfile* StopProfiling(const char* title); - CpuProfile* StopProfiling(String* title); + CpuProfile* StopProfiling(String title); int GetProfilesCount(); CpuProfile* GetProfile(int index); void DeleteAllProfiles(); void DeleteProfile(CpuProfile* profile); - void CodeEventHandler(const CodeEventsContainer& evt_rec) override; - bool is_profiling() const { return is_profiling_; } ProfileGenerator* generator() const { return generator_.get(); } diff --git a/deps/v8/src/profiler/heap-profiler.cc b/deps/v8/src/profiler/heap-profiler.cc index 58a8f3851f..495baf9b34 100644 --- a/deps/v8/src/profiler/heap-profiler.cc +++ b/deps/v8/src/profiler/heap-profiler.cc @@ -52,12 +52,10 @@ void HeapProfiler::DefineWrapperClass( wrapper_callbacks_[class_id] = callback; } - v8::RetainedObjectInfo* HeapProfiler::ExecuteWrapperClassCallback( - uint16_t class_id, Object** wrapper) { + uint16_t class_id, Handle<Object> wrapper) { if (wrapper_callbacks_.size() <= class_id) return nullptr; - return wrapper_callbacks_[class_id]( - class_id, Utils::ToLocal(Handle<Object>(wrapper))); + return wrapper_callbacks_[class_id](class_id, Utils::ToLocal(wrapper)); } void HeapProfiler::SetGetRetainerInfosCallback( @@ -185,7 +183,7 @@ SnapshotObjectId HeapProfiler::GetSnapshotObjectId(Handle<Object> obj) { } void HeapProfiler::ObjectMoveEvent(Address from, Address to, int size) { - base::LockGuard<base::Mutex> guard(&profiler_mutex_); + base::MutexGuard guard(&profiler_mutex_); bool known_object = ids_->MoveObject(from, to, size); if (!known_object && allocation_tracker_) { allocation_tracker_->address_to_trace()->MoveObject(from, to, size); @@ -205,18 +203,18 @@ void HeapProfiler::UpdateObjectSizeEvent(Address addr, int size) { } Handle<HeapObject> HeapProfiler::FindHeapObjectById(SnapshotObjectId id) { - HeapObject* object = nullptr; + HeapObject object; HeapIterator iterator(heap(), HeapIterator::kFilterUnreachable); // Make sure that object with the given id is still reachable. - for (HeapObject* obj = iterator.next(); obj != nullptr; + for (HeapObject obj = iterator.next(); !obj.is_null(); obj = iterator.next()) { if (ids_->FindEntry(obj->address()) == id) { - DCHECK_NULL(object); + DCHECK(object.is_null()); object = obj; // Can't break -- kFilterUnreachable requires full heap traversal. } } - return object != nullptr ? Handle<HeapObject>(object, isolate()) + return !object.is_null() ? Handle<HeapObject>(object, isolate()) : Handle<HeapObject>(); } @@ -238,8 +236,8 @@ void HeapProfiler::QueryObjects(Handle<Context> context, // collect all garbage first. heap()->CollectAllAvailableGarbage(GarbageCollectionReason::kHeapProfiler); HeapIterator heap_iterator(heap()); - HeapObject* heap_obj; - while ((heap_obj = heap_iterator.next()) != nullptr) { + for (HeapObject heap_obj = heap_iterator.next(); !heap_obj.is_null(); + heap_obj = heap_iterator.next()) { if (!heap_obj->IsJSObject() || heap_obj->IsExternal(isolate())) continue; v8::Local<v8::Object> v8_obj( Utils::ToLocal(handle(JSObject::cast(heap_obj), isolate()))); diff --git a/deps/v8/src/profiler/heap-profiler.h b/deps/v8/src/profiler/heap-profiler.h index 1e3527765e..efeb8f769b 100644 --- a/deps/v8/src/profiler/heap-profiler.h +++ b/deps/v8/src/profiler/heap-profiler.h @@ -65,7 +65,7 @@ class HeapProfiler : public HeapObjectAllocationTracker { uint16_t class_id, v8::HeapProfiler::WrapperInfoCallback callback); v8::RetainedObjectInfo* ExecuteWrapperClassCallback(uint16_t class_id, - Object** wrapper); + Handle<Object> wrapper); void SetGetRetainerInfosCallback( v8::HeapProfiler::GetRetainerInfosCallback callback); diff --git a/deps/v8/src/profiler/heap-snapshot-generator.cc b/deps/v8/src/profiler/heap-snapshot-generator.cc index 57f620f4ec..17daea1964 100644 --- a/deps/v8/src/profiler/heap-snapshot-generator.cc +++ b/deps/v8/src/profiler/heap-snapshot-generator.cc @@ -7,7 +7,7 @@ #include <utility> #include "src/api-inl.h" -#include "src/code-stubs.h" +#include "src/assembler-inl.h" #include "src/conversions.h" #include "src/debug/debug.h" #include "src/global-handles.h" @@ -15,6 +15,8 @@ #include "src/objects-body-descriptors.h" #include "src/objects-inl.h" #include "src/objects/api-callbacks.h" +#include "src/objects/cell-inl.h" +#include "src/objects/feedback-cell-inl.h" #include "src/objects/hash-table-inl.h" #include "src/objects/js-array-buffer-inl.h" #include "src/objects/js-array-inl.h" @@ -23,6 +25,8 @@ #include "src/objects/js-promise-inl.h" #include "src/objects/js-regexp-inl.h" #include "src/objects/literal-objects-inl.h" +#include "src/objects/slots-inl.h" +#include "src/objects/struct-inl.h" #include "src/profiler/allocation-tracker.h" #include "src/profiler/heap-profiler.h" #include "src/profiler/heap-snapshot-generator-inl.h" @@ -177,10 +181,10 @@ const char* HeapEntry::TypeAsString() { HeapSnapshot::HeapSnapshot(HeapProfiler* profiler) : profiler_(profiler) { // It is very important to keep objects that form a heap snapshot // as small as possible. Check assumptions about data structure sizes. - STATIC_ASSERT((kPointerSize == 4 && sizeof(HeapGraphEdge) == 12) || - (kPointerSize == 8 && sizeof(HeapGraphEdge) == 24)); - STATIC_ASSERT((kPointerSize == 4 && sizeof(HeapEntry) == 28) || - (kPointerSize == 8 && sizeof(HeapEntry) == 40)); + STATIC_ASSERT((kTaggedSize == 4 && sizeof(HeapGraphEdge) == 12) || + (kTaggedSize == 8 && sizeof(HeapGraphEdge) == 24)); + STATIC_ASSERT((kTaggedSize == 4 && sizeof(HeapEntry) == 28) || + (kTaggedSize == 8 && sizeof(HeapEntry) == 40)); memset(&gc_subroot_entries_, 0, sizeof(gc_subroot_entries_)); } @@ -389,7 +393,7 @@ void HeapObjectsMap::UpdateHeapObjectsMap() { heap_->PreciseCollectAllGarbage(Heap::kNoGCFlags, GarbageCollectionReason::kHeapProfiler); HeapIterator iterator(heap_); - for (HeapObject* obj = iterator.next(); obj != nullptr; + for (HeapObject obj = iterator.next(); !obj.is_null(); obj = iterator.next()) { FindOrAddEntry(obj->address(), obj->Size()); if (FLAG_heap_profiler_trace_objects) { @@ -511,31 +515,32 @@ V8HeapExplorer::V8HeapExplorer(HeapSnapshot* snapshot, global_object_name_resolver_(resolver) {} HeapEntry* V8HeapExplorer::AllocateEntry(HeapThing ptr) { - return AddEntry(reinterpret_cast<HeapObject*>(ptr)); + return AddEntry(HeapObject::cast(Object(reinterpret_cast<Address>(ptr)))); } -void V8HeapExplorer::ExtractLocation(HeapEntry* entry, HeapObject* object) { +void V8HeapExplorer::ExtractLocation(HeapEntry* entry, HeapObject object) { if (object->IsJSFunction()) { - JSFunction* func = JSFunction::cast(object); + JSFunction func = JSFunction::cast(object); ExtractLocationForJSFunction(entry, func); } else if (object->IsJSGeneratorObject()) { - JSGeneratorObject* gen = JSGeneratorObject::cast(object); + JSGeneratorObject gen = JSGeneratorObject::cast(object); ExtractLocationForJSFunction(entry, gen->function()); } else if (object->IsJSObject()) { - JSObject* obj = JSObject::cast(object); - JSFunction* maybe_constructor = GetConstructor(obj); + JSObject obj = JSObject::cast(object); + JSFunction maybe_constructor = GetConstructor(obj); - if (maybe_constructor) + if (!maybe_constructor.is_null()) { ExtractLocationForJSFunction(entry, maybe_constructor); + } } } void V8HeapExplorer::ExtractLocationForJSFunction(HeapEntry* entry, - JSFunction* func) { + JSFunction func) { if (!func->shared()->script()->IsScript()) return; - Script* script = Script::cast(func->shared()->script()); + Script script = Script::cast(func->shared()->script()); int scriptId = script->id(); int start = func->shared()->StartPosition(); int line = script->GetLineNumber(start); @@ -543,16 +548,16 @@ void V8HeapExplorer::ExtractLocationForJSFunction(HeapEntry* entry, snapshot_->AddLocation(entry, scriptId, line, col); } -HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object) { +HeapEntry* V8HeapExplorer::AddEntry(HeapObject object) { if (object->IsJSFunction()) { - JSFunction* func = JSFunction::cast(object); - SharedFunctionInfo* shared = func->shared(); + JSFunction func = JSFunction::cast(object); + SharedFunctionInfo shared = func->shared(); const char* name = names_->GetName(shared->Name()); return AddEntry(object, HeapEntry::kClosure, name); } else if (object->IsJSBoundFunction()) { return AddEntry(object, HeapEntry::kClosure, "native_bind"); } else if (object->IsJSRegExp()) { - JSRegExp* re = JSRegExp::cast(object); + JSRegExp re = JSRegExp::cast(object); return AddEntry(object, HeapEntry::kRegExp, names_->GetName(re->Pattern())); @@ -567,7 +572,7 @@ HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object) { } return AddEntry(object, HeapEntry::kObject, name); } else if (object->IsString()) { - String* string = String::cast(object); + String string = String::cast(object); if (string->IsConsString()) { return AddEntry(object, HeapEntry::kConsString, "(concatenated string)"); } else if (string->IsSlicedString()) { @@ -586,10 +591,10 @@ HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object) { } else if (object->IsCode()) { return AddEntry(object, HeapEntry::kCode, ""); } else if (object->IsSharedFunctionInfo()) { - String* name = SharedFunctionInfo::cast(object)->Name(); + String name = SharedFunctionInfo::cast(object)->Name(); return AddEntry(object, HeapEntry::kCode, names_->GetName(name)); } else if (object->IsScript()) { - Object* name = Script::cast(object)->name(); + Object name = Script::cast(object)->name(); return AddEntry( object, HeapEntry::kCode, name->IsString() ? names_->GetName(String::cast(name)) : ""); @@ -606,8 +611,7 @@ HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object) { return AddEntry(object, HeapEntry::kHidden, GetSystemEntryName(object)); } -HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object, - HeapEntry::Type type, +HeapEntry* V8HeapExplorer::AddEntry(HeapObject object, HeapEntry::Type type, const char* name) { return AddEntry(object->address(), type, name, object->Size()); } @@ -627,7 +631,7 @@ HeapEntry* V8HeapExplorer::AddEntry(Address address, return snapshot_->AddEntry(type, name, object_id, size, trace_node_id); } -const char* V8HeapExplorer::GetSystemEntryName(HeapObject* object) { +const char* V8HeapExplorer::GetSystemEntryName(HeapObject object) { switch (object->map()->instance_type()) { case MAP_TYPE: switch (Map::cast(object)->instance_type()) { @@ -655,56 +659,72 @@ const char* V8HeapExplorer::GetSystemEntryName(HeapObject* object) { int V8HeapExplorer::EstimateObjectsCount() { HeapIterator it(heap_, HeapIterator::kFilterUnreachable); int objects_count = 0; - while (it.next()) ++objects_count; + while (!it.next().is_null()) ++objects_count; return objects_count; } class IndexedReferencesExtractor : public ObjectVisitor { public: - IndexedReferencesExtractor(V8HeapExplorer* generator, HeapObject* parent_obj, + IndexedReferencesExtractor(V8HeapExplorer* generator, HeapObject parent_obj, HeapEntry* parent) : generator_(generator), parent_obj_(parent_obj), - parent_start_(HeapObject::RawField(parent_obj_, 0)), - parent_end_(HeapObject::RawField(parent_obj_, parent_obj_->Size())), - parent_(parent) {} - void VisitPointers(HeapObject* host, Object** start, Object** end) override { - VisitPointers(host, reinterpret_cast<MaybeObject**>(start), - reinterpret_cast<MaybeObject**>(end)); - } - void VisitPointers(HeapObject* host, MaybeObject** start, - MaybeObject** end) override { - int next_index = 0; - for (MaybeObject** p = start; p < end; p++) { - int index = static_cast<int>(reinterpret_cast<Object**>(p) - - HeapObject::RawField(parent_obj_, 0)); - ++next_index; - // |p| could be outside of the object, e.g., while visiting RelocInfo of - // code objects. - if (reinterpret_cast<Object**>(p) >= parent_start_ && - reinterpret_cast<Object**>(p) < parent_end_ && - generator_->visited_fields_[index]) { - generator_->visited_fields_[index] = false; + parent_start_(HeapObject::RawMaybeWeakField(parent_obj_, 0)), + parent_end_( + HeapObject::RawMaybeWeakField(parent_obj_, parent_obj_->Size())), + parent_(parent), + next_index_(0) {} + void VisitPointers(HeapObject host, ObjectSlot start, + ObjectSlot end) override { + VisitPointers(host, MaybeObjectSlot(start), MaybeObjectSlot(end)); + } + void VisitPointers(HeapObject host, MaybeObjectSlot start, + MaybeObjectSlot end) override { + // [start,end) must be a sub-region of [parent_start_, parent_end), i.e. + // all the slots must point inside the object. + CHECK_LE(parent_start_, start); + CHECK_LE(end, parent_end_); + for (MaybeObjectSlot p = start; p < end; ++p) { + int field_index = static_cast<int>(p - parent_start_); + if (generator_->visited_fields_[field_index]) { + generator_->visited_fields_[field_index] = false; continue; } - HeapObject* heap_object; - if ((*p)->GetHeapObjectIfWeak(&heap_object) || - (*p)->GetHeapObjectIfStrong(&heap_object)) { - generator_->SetHiddenReference(parent_obj_, parent_, next_index, - heap_object, index * kPointerSize); + HeapObject heap_object; + if ((*p)->GetHeapObject(&heap_object)) { + VisitHeapObjectImpl(heap_object, field_index); } } } + void VisitCodeTarget(Code host, RelocInfo* rinfo) override { + Code target = Code::GetCodeFromTargetAddress(rinfo->target_address()); + VisitHeapObjectImpl(target, -1); + } + + void VisitEmbeddedPointer(Code host, RelocInfo* rinfo) override { + VisitHeapObjectImpl(rinfo->target_object(), -1); + } + private: + V8_INLINE void VisitHeapObjectImpl(HeapObject heap_object, int field_index) { + DCHECK_LE(-1, field_index); + // The last parameter {field_offset} is only used to check some well-known + // skipped references, so passing -1 * kTaggedSize for objects embedded + // into code is fine. + generator_->SetHiddenReference(parent_obj_, parent_, next_index_++, + heap_object, field_index * kTaggedSize); + } + V8HeapExplorer* generator_; - HeapObject* parent_obj_; - Object** parent_start_; - Object** parent_end_; + HeapObject parent_obj_; + MaybeObjectSlot parent_start_; + MaybeObjectSlot parent_end_; HeapEntry* parent_; + int next_index_; }; -void V8HeapExplorer::ExtractReferences(HeapEntry* entry, HeapObject* obj) { +void V8HeapExplorer::ExtractReferences(HeapEntry* entry, HeapObject obj) { if (obj->IsJSGlobalProxy()) { ExtractJSGlobalProxyReferences(entry, JSGlobalProxy::cast(obj)); } else if (obj->IsJSArrayBuffer()) { @@ -753,6 +773,8 @@ void V8HeapExplorer::ExtractReferences(HeapEntry* entry, HeapObject* obj) { entry, ArrayBoilerplateDescription::cast(obj)); } else if (obj->IsFeedbackVector()) { ExtractFeedbackVectorReferences(entry, FeedbackVector::cast(obj)); + } else if (obj->IsDescriptorArray()) { + ExtractDescriptorArrayReferences(entry, DescriptorArray::cast(obj)); } else if (obj->IsWeakFixedArray()) { ExtractWeakArrayReferences(WeakFixedArray::kHeaderSize, entry, WeakFixedArray::cast(obj)); @@ -769,14 +791,14 @@ void V8HeapExplorer::ExtractReferences(HeapEntry* entry, HeapObject* obj) { } void V8HeapExplorer::ExtractJSGlobalProxyReferences(HeapEntry* entry, - JSGlobalProxy* proxy) { + JSGlobalProxy proxy) { SetInternalReference(entry, "native_context", proxy->native_context(), JSGlobalProxy::kNativeContextOffset); } void V8HeapExplorer::ExtractJSObjectReferences(HeapEntry* entry, - JSObject* js_obj) { - HeapObject* obj = js_obj; + JSObject js_obj) { + HeapObject obj = js_obj; ExtractPropertyReferences(js_obj, entry); ExtractElementReferences(js_obj, entry); ExtractInternalReferences(js_obj, entry); @@ -784,7 +806,7 @@ void V8HeapExplorer::ExtractJSObjectReferences(HeapEntry* entry, ReadOnlyRoots roots(heap_); SetPropertyReference(entry, roots.proto_string(), iter.GetCurrent()); if (obj->IsJSBoundFunction()) { - JSBoundFunction* js_fun = JSBoundFunction::cast(obj); + JSBoundFunction js_fun = JSBoundFunction::cast(obj); TagObject(js_fun->bound_arguments(), "(bound arguments)"); SetInternalReference(entry, "bindings", js_fun->bound_arguments(), JSBoundFunction::kBoundArgumentsOffset); @@ -793,15 +815,15 @@ void V8HeapExplorer::ExtractJSObjectReferences(HeapEntry* entry, SetInternalReference(entry, "bound_function", js_fun->bound_target_function(), JSBoundFunction::kBoundTargetFunctionOffset); - FixedArray* bindings = js_fun->bound_arguments(); + FixedArray bindings = js_fun->bound_arguments(); for (int i = 0; i < bindings->length(); i++) { const char* reference_name = names_->GetFormatted("bound_argument_%d", i); SetNativeBindReference(entry, reference_name, bindings->get(i)); } } else if (obj->IsJSFunction()) { - JSFunction* js_fun = JSFunction::cast(js_obj); + JSFunction js_fun = JSFunction::cast(js_obj); if (js_fun->has_prototype_slot()) { - Object* proto_or_map = js_fun->prototype_or_initial_map(); + Object proto_or_map = js_fun->prototype_or_initial_map(); if (!proto_or_map->IsTheHole(heap_->isolate())) { if (!proto_or_map->IsMap()) { SetPropertyReference(entry, roots.prototype_string(), proto_or_map, @@ -815,9 +837,9 @@ void V8HeapExplorer::ExtractJSObjectReferences(HeapEntry* entry, } } } - SharedFunctionInfo* shared_info = js_fun->shared(); - TagObject(js_fun->feedback_cell(), "(function feedback cell)"); - SetInternalReference(entry, "feedback_cell", js_fun->feedback_cell(), + SharedFunctionInfo shared_info = js_fun->shared(); + TagObject(js_fun->raw_feedback_cell(), "(function feedback cell)"); + SetInternalReference(entry, "feedback_cell", js_fun->raw_feedback_cell(), JSFunction::kFeedbackCellOffset); TagObject(shared_info, "(shared function info)"); SetInternalReference(entry, "shared", shared_info, @@ -825,19 +847,18 @@ void V8HeapExplorer::ExtractJSObjectReferences(HeapEntry* entry, TagObject(js_fun->context(), "(context)"); SetInternalReference(entry, "context", js_fun->context(), JSFunction::kContextOffset); - TagCodeObject(js_fun->code()); SetInternalReference(entry, "code", js_fun->code(), JSFunction::kCodeOffset); } else if (obj->IsJSGlobalObject()) { - JSGlobalObject* global_obj = JSGlobalObject::cast(obj); + JSGlobalObject global_obj = JSGlobalObject::cast(obj); SetInternalReference(entry, "native_context", global_obj->native_context(), JSGlobalObject::kNativeContextOffset); SetInternalReference(entry, "global_proxy", global_obj->global_proxy(), JSGlobalObject::kGlobalProxyOffset); STATIC_ASSERT(JSGlobalObject::kSize - JSObject::kHeaderSize == - 2 * kPointerSize); + 2 * kTaggedSize); } else if (obj->IsJSArrayBufferView()) { - JSArrayBufferView* view = JSArrayBufferView::cast(obj); + JSArrayBufferView view = JSArrayBufferView::cast(obj); SetInternalReference(entry, "buffer", view->buffer(), JSArrayBufferView::kBufferOffset); } @@ -851,47 +872,47 @@ void V8HeapExplorer::ExtractJSObjectReferences(HeapEntry* entry, JSObject::kElementsOffset); } -void V8HeapExplorer::ExtractStringReferences(HeapEntry* entry, String* string) { +void V8HeapExplorer::ExtractStringReferences(HeapEntry* entry, String string) { if (string->IsConsString()) { - ConsString* cs = ConsString::cast(string); + ConsString cs = ConsString::cast(string); SetInternalReference(entry, "first", cs->first(), ConsString::kFirstOffset); SetInternalReference(entry, "second", cs->second(), ConsString::kSecondOffset); } else if (string->IsSlicedString()) { - SlicedString* ss = SlicedString::cast(string); + SlicedString ss = SlicedString::cast(string); SetInternalReference(entry, "parent", ss->parent(), SlicedString::kParentOffset); } else if (string->IsThinString()) { - ThinString* ts = ThinString::cast(string); + ThinString ts = ThinString::cast(string); SetInternalReference(entry, "actual", ts->actual(), ThinString::kActualOffset); } } -void V8HeapExplorer::ExtractSymbolReferences(HeapEntry* entry, Symbol* symbol) { +void V8HeapExplorer::ExtractSymbolReferences(HeapEntry* entry, Symbol symbol) { SetInternalReference(entry, "name", symbol->name(), Symbol::kNameOffset); } void V8HeapExplorer::ExtractJSCollectionReferences(HeapEntry* entry, - JSCollection* collection) { + JSCollection collection) { SetInternalReference(entry, "table", collection->table(), JSCollection::kTableOffset); } void V8HeapExplorer::ExtractJSWeakCollectionReferences(HeapEntry* entry, - JSWeakCollection* obj) { + JSWeakCollection obj) { SetInternalReference(entry, "table", obj->table(), JSWeakCollection::kTableOffset); } void V8HeapExplorer::ExtractEphemeronHashTableReferences( - HeapEntry* entry, EphemeronHashTable* table) { + HeapEntry* entry, EphemeronHashTable table) { for (int i = 0, capacity = table->Capacity(); i < capacity; ++i) { int key_index = EphemeronHashTable::EntryToIndex(i) + EphemeronHashTable::kEntryKeyIndex; int value_index = EphemeronHashTable::EntryToValueIndex(i); - Object* key = table->get(key_index); - Object* value = table->get(value_index); + Object key = table->get(key_index); + Object value = table->get(value_index); SetWeakReference(entry, key_index, key, table->OffsetOfElementAt(key_index)); SetWeakReference(entry, value_index, value, @@ -916,23 +937,23 @@ static const struct { } native_context_names[] = { #define CONTEXT_FIELD_INDEX_NAME(index, _, name) {Context::index, #name}, NATIVE_CONTEXT_FIELDS(CONTEXT_FIELD_INDEX_NAME) -#undef CONTEXT_FIELD_INDEX +#undef CONTEXT_FIELD_INDEX_NAME }; void V8HeapExplorer::ExtractContextReferences(HeapEntry* entry, - Context* context) { + Context context) { if (!context->IsNativeContext() && context->is_declaration_context()) { - ScopeInfo* scope_info = context->scope_info(); + ScopeInfo scope_info = context->scope_info(); // Add context allocated locals. int context_locals = scope_info->ContextLocalCount(); for (int i = 0; i < context_locals; ++i) { - String* local_name = scope_info->ContextLocalName(i); + String local_name = scope_info->ContextLocalName(i); int idx = Context::MIN_CONTEXT_SLOTS + i; SetContextReference(entry, local_name, context->get(idx), Context::OffsetOfElementAt(idx)); } if (scope_info->HasFunctionName()) { - String* name = String::cast(scope_info->FunctionName()); + String name = String::cast(scope_info->FunctionName()); int idx = scope_info->FunctionContextSlotIndex(name); if (idx >= 0) { SetContextReference(entry, name, context->get(idx), @@ -979,9 +1000,9 @@ void V8HeapExplorer::ExtractContextReferences(HeapEntry* entry, } } -void V8HeapExplorer::ExtractMapReferences(HeapEntry* entry, Map* map) { - MaybeObject* maybe_raw_transitions_or_prototype_info = map->raw_transitions(); - HeapObject* raw_transitions_or_prototype_info; +void V8HeapExplorer::ExtractMapReferences(HeapEntry* entry, Map map) { + MaybeObject maybe_raw_transitions_or_prototype_info = map->raw_transitions(); + HeapObject raw_transitions_or_prototype_info; if (maybe_raw_transitions_or_prototype_info->GetHeapObjectIfWeak( &raw_transitions_or_prototype_info)) { DCHECK(raw_transitions_or_prototype_info->IsMap()); @@ -990,7 +1011,7 @@ void V8HeapExplorer::ExtractMapReferences(HeapEntry* entry, Map* map) { } else if (maybe_raw_transitions_or_prototype_info->GetHeapObjectIfStrong( &raw_transitions_or_prototype_info)) { if (raw_transitions_or_prototype_info->IsTransitionArray()) { - TransitionArray* transitions = + TransitionArray transitions = TransitionArray::cast(raw_transitions_or_prototype_info); if (map->CanTransition() && transitions->HasPrototypeTransitions()) { TagObject(transitions->GetPrototypeTransitions(), @@ -1012,7 +1033,7 @@ void V8HeapExplorer::ExtractMapReferences(HeapEntry* entry, Map* map) { Map::kTransitionsOrPrototypeInfoOffset); } } - DescriptorArray* descriptors = map->instance_descriptors(); + DescriptorArray descriptors = map->instance_descriptors(); TagObject(descriptors, "(map descriptors)"); SetInternalReference(entry, "descriptors", descriptors, Map::kDescriptorsOffset); @@ -1022,7 +1043,7 @@ void V8HeapExplorer::ExtractMapReferences(HeapEntry* entry, Map* map) { SetInternalReference(entry, "layout_descriptor", map->layout_descriptor(), Map::kLayoutDescriptorOffset); } - Object* constructor_or_backpointer = map->constructor_or_backpointer(); + Object constructor_or_backpointer = map->constructor_or_backpointer(); if (constructor_or_backpointer->IsMap()) { TagObject(constructor_or_backpointer, "(back pointer)"); SetInternalReference(entry, "back_pointer", constructor_or_backpointer, @@ -1042,8 +1063,8 @@ void V8HeapExplorer::ExtractMapReferences(HeapEntry* entry, Map* map) { } void V8HeapExplorer::ExtractSharedFunctionInfoReferences( - HeapEntry* entry, SharedFunctionInfo* shared) { - String* shared_name = shared->DebugName(); + HeapEntry* entry, SharedFunctionInfo shared) { + String shared_name = shared->DebugName(); const char* name = nullptr; if (shared_name != ReadOnlyRoots(heap_).empty_string()) { name = names_->GetName(shared_name); @@ -1071,7 +1092,7 @@ void V8HeapExplorer::ExtractSharedFunctionInfoReferences( SharedFunctionInfo::kOuterScopeInfoOrFeedbackMetadataOffset); } -void V8HeapExplorer::ExtractScriptReferences(HeapEntry* entry, Script* script) { +void V8HeapExplorer::ExtractScriptReferences(HeapEntry* entry, Script script) { SetInternalReference(entry, "source", script->source(), Script::kSourceOffset); SetInternalReference(entry, "name", script->name(), Script::kNameOffset); @@ -1082,8 +1103,8 @@ void V8HeapExplorer::ExtractScriptReferences(HeapEntry* entry, Script* script) { Script::kLineEndsOffset); } -void V8HeapExplorer::ExtractAccessorInfoReferences( - HeapEntry* entry, AccessorInfo* accessor_info) { +void V8HeapExplorer::ExtractAccessorInfoReferences(HeapEntry* entry, + AccessorInfo accessor_info) { SetInternalReference(entry, "name", accessor_info->name(), AccessorInfo::kNameOffset); SetInternalReference(entry, "expected_receiver_type", @@ -1098,27 +1119,18 @@ void V8HeapExplorer::ExtractAccessorInfoReferences( } void V8HeapExplorer::ExtractAccessorPairReferences(HeapEntry* entry, - AccessorPair* accessors) { + AccessorPair accessors) { SetInternalReference(entry, "getter", accessors->getter(), AccessorPair::kGetterOffset); SetInternalReference(entry, "setter", accessors->setter(), AccessorPair::kSetterOffset); } -void V8HeapExplorer::TagBuiltinCodeObject(Code* code, const char* name) { +void V8HeapExplorer::TagBuiltinCodeObject(Code code, const char* name) { TagObject(code, names_->GetFormatted("(%s builtin)", name)); } -void V8HeapExplorer::TagCodeObject(Code* code) { - if (code->kind() == Code::STUB) { - TagObject(code, names_->GetFormatted( - "(%s code)", - CodeStub::MajorName(CodeStub::GetMajorKey(code)))); - } -} - -void V8HeapExplorer::ExtractCodeReferences(HeapEntry* entry, Code* code) { - TagCodeObject(code); +void V8HeapExplorer::ExtractCodeReferences(HeapEntry* entry, Code code) { TagObject(code->relocation_info(), "(code relocation info)"); SetInternalReference(entry, "relocation_info", code->relocation_info(), Code::kRelocationInfoOffset); @@ -1132,19 +1144,19 @@ void V8HeapExplorer::ExtractCodeReferences(HeapEntry* entry, Code* code) { Code::kSourcePositionTableOffset); } -void V8HeapExplorer::ExtractCellReferences(HeapEntry* entry, Cell* cell) { +void V8HeapExplorer::ExtractCellReferences(HeapEntry* entry, Cell cell) { SetInternalReference(entry, "value", cell->value(), Cell::kValueOffset); } -void V8HeapExplorer::ExtractFeedbackCellReferences( - HeapEntry* entry, FeedbackCell* feedback_cell) { +void V8HeapExplorer::ExtractFeedbackCellReferences(HeapEntry* entry, + FeedbackCell feedback_cell) { TagObject(feedback_cell, "(feedback cell)"); SetInternalReference(entry, "value", feedback_cell->value(), FeedbackCell::kValueOffset); } void V8HeapExplorer::ExtractPropertyCellReferences(HeapEntry* entry, - PropertyCell* cell) { + PropertyCell cell) { SetInternalReference(entry, "value", cell->value(), PropertyCell::kValueOffset); TagObject(cell->dependent_code(), "(dependent code)"); @@ -1153,7 +1165,7 @@ void V8HeapExplorer::ExtractPropertyCellReferences(HeapEntry* entry, } void V8HeapExplorer::ExtractAllocationSiteReferences(HeapEntry* entry, - AllocationSite* site) { + AllocationSite site) { SetInternalReference(entry, "transition_info", site->transition_info_or_boilerplate(), AllocationSite::kTransitionInfoOrBoilerplateOffset); @@ -1165,7 +1177,7 @@ void V8HeapExplorer::ExtractAllocationSiteReferences(HeapEntry* entry, } void V8HeapExplorer::ExtractArrayBoilerplateDescriptionReferences( - HeapEntry* entry, ArrayBoilerplateDescription* value) { + HeapEntry* entry, ArrayBoilerplateDescription value) { SetInternalReference(entry, "constant_elements", value->constant_elements(), ArrayBoilerplateDescription::kConstantElementsOffset); } @@ -1187,10 +1199,9 @@ class JSArrayBufferDataEntryAllocator : public HeapEntriesAllocator { }; void V8HeapExplorer::ExtractJSArrayBufferReferences(HeapEntry* entry, - JSArrayBuffer* buffer) { + JSArrayBuffer buffer) { // Setup a reference to a native memory backing_store object. - if (!buffer->backing_store()) - return; + if (!buffer->backing_store()) return; size_t data_size = buffer->byte_length(); JSArrayBufferDataEntryAllocator allocator(data_size, this); HeapEntry* data_entry = @@ -1200,14 +1211,14 @@ void V8HeapExplorer::ExtractJSArrayBufferReferences(HeapEntry* entry, } void V8HeapExplorer::ExtractJSPromiseReferences(HeapEntry* entry, - JSPromise* promise) { + JSPromise promise) { SetInternalReference(entry, "reactions_or_result", promise->reactions_or_result(), JSPromise::kReactionsOrResultOffset); } void V8HeapExplorer::ExtractJSGeneratorObjectReferences( - HeapEntry* entry, JSGeneratorObject* generator) { + HeapEntry* entry, JSGeneratorObject generator) { SetInternalReference(entry, "function", generator->function(), JSGeneratorObject::kFunctionOffset); SetInternalReference(entry, "context", generator->context(), @@ -1220,7 +1231,7 @@ void V8HeapExplorer::ExtractJSGeneratorObjectReferences( } void V8HeapExplorer::ExtractFixedArrayReferences(HeapEntry* entry, - FixedArray* array) { + FixedArray array) { for (int i = 0, l = array->length(); i < l; ++i) { DCHECK(!HasWeakHeapObjectTag(array->get(i))); SetInternalReference(entry, i, array->get(i), array->OffsetOfElementAt(i)); @@ -1228,35 +1239,55 @@ void V8HeapExplorer::ExtractFixedArrayReferences(HeapEntry* entry, } void V8HeapExplorer::ExtractFeedbackVectorReferences( - HeapEntry* entry, FeedbackVector* feedback_vector) { - MaybeObject* code = feedback_vector->optimized_code_weak_or_smi(); - HeapObject* code_heap_object; + HeapEntry* entry, FeedbackVector feedback_vector) { + MaybeObject code = feedback_vector->optimized_code_weak_or_smi(); + HeapObject code_heap_object; if (code->GetHeapObjectIfWeak(&code_heap_object)) { SetWeakReference(entry, "optimized code", code_heap_object, FeedbackVector::kOptimizedCodeOffset); } } +void V8HeapExplorer::ExtractDescriptorArrayReferences(HeapEntry* entry, + DescriptorArray array) { + SetInternalReference(entry, "enum_cache", array->enum_cache(), + DescriptorArray::kEnumCacheOffset); + MaybeObjectSlot start = MaybeObjectSlot(array->GetDescriptorSlot(0)); + MaybeObjectSlot end = MaybeObjectSlot( + array->GetDescriptorSlot(array->number_of_all_descriptors())); + for (int i = 0; start + i < end; ++i) { + MaybeObjectSlot slot = start + i; + int offset = static_cast<int>(slot.address() - array->address()); + MaybeObject object = *slot; + HeapObject heap_object; + if (object->GetHeapObjectIfWeak(&heap_object)) { + SetWeakReference(entry, i, heap_object, offset); + } else if (object->GetHeapObjectIfStrong(&heap_object)) { + SetInternalReference(entry, i, heap_object, offset); + } + } +} + template <typename T> void V8HeapExplorer::ExtractWeakArrayReferences(int header_size, - HeapEntry* entry, T* array) { + HeapEntry* entry, T array) { for (int i = 0; i < array->length(); ++i) { - MaybeObject* object = array->Get(i); - HeapObject* heap_object; + MaybeObject object = array->Get(i); + HeapObject heap_object; if (object->GetHeapObjectIfWeak(&heap_object)) { - SetWeakReference(entry, i, heap_object, header_size + i * kPointerSize); + SetWeakReference(entry, i, heap_object, header_size + i * kTaggedSize); } else if (object->GetHeapObjectIfStrong(&heap_object)) { SetInternalReference(entry, i, heap_object, - header_size + i * kPointerSize); + header_size + i * kTaggedSize); } } } -void V8HeapExplorer::ExtractPropertyReferences(JSObject* js_obj, +void V8HeapExplorer::ExtractPropertyReferences(JSObject js_obj, HeapEntry* entry) { Isolate* isolate = js_obj->GetIsolate(); if (js_obj->HasFastProperties()) { - DescriptorArray* descs = js_obj->map()->instance_descriptors(); + DescriptorArray descs = js_obj->map()->instance_descriptors(); int real_size = js_obj->map()->NumberOfOwnDescriptors(); for (int i = 0; i < real_size; i++) { PropertyDetails details = descs->GetDetails(i); @@ -1265,9 +1296,9 @@ void V8HeapExplorer::ExtractPropertyReferences(JSObject* js_obj, Representation r = details.representation(); if (r.IsSmi() || r.IsDouble()) break; - Name* k = descs->GetKey(i); + Name k = descs->GetKey(i); FieldIndex field_index = FieldIndex::ForDescriptor(js_obj->map(), i); - Object* value = js_obj->RawFastPropertyAt(field_index); + Object value = js_obj->RawFastPropertyAt(field_index); int field_offset = field_index.is_inobject() ? field_index.offset() : -1; @@ -1284,26 +1315,26 @@ void V8HeapExplorer::ExtractPropertyReferences(JSObject* js_obj, } } else if (js_obj->IsJSGlobalObject()) { // We assume that global objects can only have slow properties. - GlobalDictionary* dictionary = + GlobalDictionary dictionary = JSGlobalObject::cast(js_obj)->global_dictionary(); int length = dictionary->Capacity(); ReadOnlyRoots roots(isolate); for (int i = 0; i < length; ++i) { if (!dictionary->IsKey(roots, dictionary->KeyAt(i))) continue; - PropertyCell* cell = dictionary->CellAt(i); - Name* name = cell->name(); - Object* value = cell->value(); + PropertyCell cell = dictionary->CellAt(i); + Name name = cell->name(); + Object value = cell->value(); PropertyDetails details = cell->property_details(); SetDataOrAccessorPropertyReference(details.kind(), entry, name, value); } } else { - NameDictionary* dictionary = js_obj->property_dictionary(); + NameDictionary dictionary = js_obj->property_dictionary(); int length = dictionary->Capacity(); ReadOnlyRoots roots(isolate); for (int i = 0; i < length; ++i) { - Object* k = dictionary->KeyAt(i); + Object k = dictionary->KeyAt(i); if (!dictionary->IsKey(roots, k)) continue; - Object* value = dictionary->ValueAt(i); + Object value = dictionary->ValueAt(i); PropertyDetails details = dictionary->DetailsAt(i); SetDataOrAccessorPropertyReference(details.kind(), entry, Name::cast(k), value); @@ -1311,27 +1342,27 @@ void V8HeapExplorer::ExtractPropertyReferences(JSObject* js_obj, } } -void V8HeapExplorer::ExtractAccessorPairProperty(HeapEntry* entry, Name* key, - Object* callback_obj, +void V8HeapExplorer::ExtractAccessorPairProperty(HeapEntry* entry, Name key, + Object callback_obj, int field_offset) { if (!callback_obj->IsAccessorPair()) return; - AccessorPair* accessors = AccessorPair::cast(callback_obj); + AccessorPair accessors = AccessorPair::cast(callback_obj); SetPropertyReference(entry, key, accessors, nullptr, field_offset); - Object* getter = accessors->getter(); + Object getter = accessors->getter(); if (!getter->IsOddball()) { SetPropertyReference(entry, key, getter, "get %s"); } - Object* setter = accessors->setter(); + Object setter = accessors->setter(); if (!setter->IsOddball()) { SetPropertyReference(entry, key, setter, "set %s"); } } -void V8HeapExplorer::ExtractElementReferences(JSObject* js_obj, +void V8HeapExplorer::ExtractElementReferences(JSObject js_obj, HeapEntry* entry) { ReadOnlyRoots roots = js_obj->GetReadOnlyRoots(); if (js_obj->HasObjectElements()) { - FixedArray* elements = FixedArray::cast(js_obj->elements()); + FixedArray elements = FixedArray::cast(js_obj->elements()); int length = js_obj->IsJSArray() ? Smi::ToInt(JSArray::cast(js_obj)->length()) : elements->length(); @@ -1341,10 +1372,10 @@ void V8HeapExplorer::ExtractElementReferences(JSObject* js_obj, } } } else if (js_obj->HasDictionaryElements()) { - NumberDictionary* dictionary = js_obj->element_dictionary(); + NumberDictionary dictionary = js_obj->element_dictionary(); int length = dictionary->Capacity(); for (int i = 0; i < length; ++i) { - Object* k = dictionary->KeyAt(i); + Object k = dictionary->KeyAt(i); if (!dictionary->IsKey(roots, k)) continue; DCHECK(k->IsNumber()); uint32_t index = static_cast<uint32_t>(k->Number()); @@ -1353,28 +1384,28 @@ void V8HeapExplorer::ExtractElementReferences(JSObject* js_obj, } } -void V8HeapExplorer::ExtractInternalReferences(JSObject* js_obj, +void V8HeapExplorer::ExtractInternalReferences(JSObject js_obj, HeapEntry* entry) { int length = js_obj->GetEmbedderFieldCount(); for (int i = 0; i < length; ++i) { - Object* o = js_obj->GetEmbedderField(i); + Object o = js_obj->GetEmbedderField(i); SetInternalReference(entry, i, o, js_obj->GetEmbedderFieldOffset(i)); } } -JSFunction* V8HeapExplorer::GetConstructor(JSReceiver* receiver) { +JSFunction V8HeapExplorer::GetConstructor(JSReceiver receiver) { Isolate* isolate = receiver->GetIsolate(); DisallowHeapAllocation no_gc; HandleScope scope(isolate); MaybeHandle<JSFunction> maybe_constructor = JSReceiver::GetConstructor(handle(receiver, isolate)); - if (maybe_constructor.is_null()) return nullptr; + if (maybe_constructor.is_null()) return JSFunction(); return *maybe_constructor.ToHandleChecked(); } -String* V8HeapExplorer::GetConstructorName(JSObject* object) { +String V8HeapExplorer::GetConstructorName(JSObject object) { Isolate* isolate = object->GetIsolate(); if (object->IsJSFunction()) return ReadOnlyRoots(isolate).closure_string(); DisallowHeapAllocation no_gc; @@ -1382,8 +1413,10 @@ String* V8HeapExplorer::GetConstructorName(JSObject* object) { return *JSReceiver::GetConstructorName(handle(object, isolate)); } -HeapEntry* V8HeapExplorer::GetEntry(Object* obj) { - return obj->IsHeapObject() ? generator_->FindOrAddEntry(obj, this) : nullptr; +HeapEntry* V8HeapExplorer::GetEntry(Object obj) { + return obj->IsHeapObject() ? generator_->FindOrAddEntry( + reinterpret_cast<void*>(obj.ptr()), this) + : nullptr; } class RootsReferencesExtractor : public RootVisitor { @@ -1394,7 +1427,7 @@ class RootsReferencesExtractor : public RootVisitor { void SetVisitingWeakRoots() { visiting_weak_roots_ = true; } void VisitRootPointer(Root root, const char* description, - Object** object) override { + FullObjectSlot object) override { if (root == Root::kBuiltins) { explorer_->TagBuiltinCodeObject(Code::cast(*object), description); } @@ -1402,10 +1435,11 @@ class RootsReferencesExtractor : public RootVisitor { *object); } - void VisitRootPointers(Root root, const char* description, Object** start, - Object** end) override { - for (Object** p = start; p < end; p++) + void VisitRootPointers(Root root, const char* description, + FullObjectSlot start, FullObjectSlot end) override { + for (FullObjectSlot p = start; p < end; ++p) { VisitRootPointer(root, description, p); + } } private: @@ -1427,7 +1461,8 @@ bool V8HeapExplorer::IterateAndExtractReferences( // first. Otherwise a particular JSFunction object could set // its custom name to a generic builtin. RootsReferencesExtractor extractor(this); - heap_->IterateRoots(&extractor, VISIT_ONLY_STRONG_FOR_SERIALIZATION); + ReadOnlyRoots(heap_).Iterate(&extractor); + heap_->IterateRoots(&extractor, VISIT_ONLY_STRONG); extractor.SetVisitingWeakRoots(); heap_->IterateWeakGlobalHandles(&extractor); @@ -1435,11 +1470,11 @@ bool V8HeapExplorer::IterateAndExtractReferences( HeapIterator iterator(heap_, HeapIterator::kFilterUnreachable); // Heap iteration with filtering must be finished in any case. - for (HeapObject *obj = iterator.next(); obj != nullptr; + for (HeapObject obj = iterator.next(); !obj.is_null(); obj = iterator.next(), progress_->ProgressStep()) { if (interrupted) continue; - size_t max_pointer = obj->Size() / kPointerSize; + size_t max_pointer = obj->Size() / kTaggedSize; if (max_pointer > visited_fields_.size()) { // Clear the current bits. std::vector<bool>().swap(visited_fields_); @@ -1470,8 +1505,7 @@ bool V8HeapExplorer::IterateAndExtractReferences( return interrupted ? false : progress_->ProgressReport(true); } - -bool V8HeapExplorer::IsEssentialObject(Object* object) { +bool V8HeapExplorer::IsEssentialObject(Object object) { ReadOnlyRoots roots(heap_); return object->IsHeapObject() && !object->IsOddball() && object != roots.empty_byte_array() && @@ -1486,7 +1520,7 @@ bool V8HeapExplorer::IsEssentialObject(Object* object) { object != roots.two_pointer_filler_map(); } -bool V8HeapExplorer::IsEssentialHiddenReference(Object* parent, +bool V8HeapExplorer::IsEssentialHiddenReference(Object parent, int field_offset) { if (parent->IsAllocationSite() && field_offset == AllocationSite::kWeakNextOffset) @@ -1501,8 +1535,8 @@ bool V8HeapExplorer::IsEssentialHiddenReference(Object* parent, } void V8HeapExplorer::SetContextReference(HeapEntry* parent_entry, - String* reference_name, - Object* child_obj, int field_offset) { + String reference_name, + Object child_obj, int field_offset) { HeapEntry* child_entry = GetEntry(child_obj); if (child_entry == nullptr) return; parent_entry->SetNamedReference(HeapGraphEdge::kContextVariable, @@ -1512,14 +1546,14 @@ void V8HeapExplorer::SetContextReference(HeapEntry* parent_entry, void V8HeapExplorer::MarkVisitedField(int offset) { if (offset < 0) return; - int index = offset / kPointerSize; + int index = offset / kTaggedSize; DCHECK(!visited_fields_[index]); visited_fields_[index] = true; } void V8HeapExplorer::SetNativeBindReference(HeapEntry* parent_entry, const char* reference_name, - Object* child_obj) { + Object child_obj) { HeapEntry* child_entry = GetEntry(child_obj); if (child_entry == nullptr) return; parent_entry->SetNamedReference(HeapGraphEdge::kShortcut, reference_name, @@ -1527,7 +1561,7 @@ void V8HeapExplorer::SetNativeBindReference(HeapEntry* parent_entry, } void V8HeapExplorer::SetElementReference(HeapEntry* parent_entry, int index, - Object* child_obj) { + Object child_obj) { HeapEntry* child_entry = GetEntry(child_obj); if (child_entry == nullptr) return; parent_entry->SetIndexedReference(HeapGraphEdge::kElement, index, @@ -1536,7 +1570,7 @@ void V8HeapExplorer::SetElementReference(HeapEntry* parent_entry, int index, void V8HeapExplorer::SetInternalReference(HeapEntry* parent_entry, const char* reference_name, - Object* child_obj, int field_offset) { + Object child_obj, int field_offset) { HeapEntry* child_entry = GetEntry(child_obj); if (child_entry == nullptr) return; if (IsEssentialObject(child_obj)) { @@ -1547,7 +1581,7 @@ void V8HeapExplorer::SetInternalReference(HeapEntry* parent_entry, } void V8HeapExplorer::SetInternalReference(HeapEntry* parent_entry, int index, - Object* child_obj, int field_offset) { + Object child_obj, int field_offset) { HeapEntry* child_entry = GetEntry(child_obj); if (child_entry == nullptr) return; if (IsEssentialObject(child_obj)) { @@ -1557,9 +1591,9 @@ void V8HeapExplorer::SetInternalReference(HeapEntry* parent_entry, int index, MarkVisitedField(field_offset); } -void V8HeapExplorer::SetHiddenReference(HeapObject* parent_obj, +void V8HeapExplorer::SetHiddenReference(HeapObject parent_obj, HeapEntry* parent_entry, int index, - Object* child_obj, int field_offset) { + Object child_obj, int field_offset) { DCHECK_EQ(parent_entry, GetEntry(parent_obj)); HeapEntry* child_entry = GetEntry(child_obj); if (child_entry != nullptr && IsEssentialObject(child_obj) && @@ -1571,7 +1605,7 @@ void V8HeapExplorer::SetHiddenReference(HeapObject* parent_obj, void V8HeapExplorer::SetWeakReference(HeapEntry* parent_entry, const char* reference_name, - Object* child_obj, int field_offset) { + Object child_obj, int field_offset) { HeapEntry* child_entry = GetEntry(child_obj); if (child_entry == nullptr) return; if (IsEssentialObject(child_obj)) { @@ -1582,7 +1616,7 @@ void V8HeapExplorer::SetWeakReference(HeapEntry* parent_entry, } void V8HeapExplorer::SetWeakReference(HeapEntry* parent_entry, int index, - Object* child_obj, int field_offset) { + Object child_obj, int field_offset) { HeapEntry* child_entry = GetEntry(child_obj); if (child_entry == nullptr) return; if (IsEssentialObject(child_obj)) { @@ -1593,8 +1627,8 @@ void V8HeapExplorer::SetWeakReference(HeapEntry* parent_entry, int index, } void V8HeapExplorer::SetDataOrAccessorPropertyReference( - PropertyKind kind, HeapEntry* parent_entry, Name* reference_name, - Object* child_obj, const char* name_format_string, int field_offset) { + PropertyKind kind, HeapEntry* parent_entry, Name reference_name, + Object child_obj, const char* name_format_string, int field_offset) { if (kind == kAccessor) { ExtractAccessorPairProperty(parent_entry, reference_name, child_obj, field_offset); @@ -1605,8 +1639,7 @@ void V8HeapExplorer::SetDataOrAccessorPropertyReference( } void V8HeapExplorer::SetPropertyReference(HeapEntry* parent_entry, - Name* reference_name, - Object* child_obj, + Name reference_name, Object child_obj, const char* name_format_string, int field_offset) { HeapEntry* child_entry = GetEntry(child_obj); @@ -1633,7 +1666,7 @@ void V8HeapExplorer::SetRootGcRootsReference() { snapshot_->gc_roots()); } -void V8HeapExplorer::SetUserGlobalReference(Object* child_obj) { +void V8HeapExplorer::SetUserGlobalReference(Object child_obj) { HeapEntry* child_entry = GetEntry(child_obj); DCHECK_NOT_NULL(child_entry); snapshot_->root()->SetNamedAutoIndexReference(HeapGraphEdge::kShortcut, @@ -1646,7 +1679,7 @@ void V8HeapExplorer::SetGcRootsReference(Root root) { } void V8HeapExplorer::SetGcSubrootReference(Root root, const char* description, - bool is_weak, Object* child_obj) { + bool is_weak, Object child_obj) { HeapEntry* child_entry = GetEntry(child_obj); if (child_entry == nullptr) return; const char* name = GetStrongGcSubrootName(child_obj); @@ -1665,7 +1698,7 @@ void V8HeapExplorer::SetGcSubrootReference(Root root, const char* description, // also used as starting points in distance calculations. if (is_weak || !child_obj->IsNativeContext()) return; - JSGlobalObject* global = Context::cast(child_obj)->global_object(); + JSGlobalObject global = Context::cast(child_obj)->global_object(); if (!global->IsJSGlobalObject()) return; if (!user_roots_.insert(global).second) return; @@ -1673,24 +1706,13 @@ void V8HeapExplorer::SetGcSubrootReference(Root root, const char* description, SetUserGlobalReference(global); } -// This static array is used to prevent excessive code-size in -// GetStrongGcSubrootName below, which would happen if we called emplace() for -// every root in a macro. -static const char* root_names[] = { -#define ROOT_NAME(type, name, CamelName) #name, - READ_ONLY_ROOT_LIST(ROOT_NAME) MUTABLE_ROOT_LIST(ROOT_NAME) -#undef ROOT_NAME -}; -STATIC_ASSERT(static_cast<uint16_t>(RootIndex::kRootListLength) == - arraysize(root_names)); - -const char* V8HeapExplorer::GetStrongGcSubrootName(Object* object) { +const char* V8HeapExplorer::GetStrongGcSubrootName(Object object) { if (strong_gc_subroot_names_.empty()) { - for (uint16_t i = 0; i < static_cast<uint16_t>(RootIndex::kRootListLength); - i++) { - const char* name = root_names[i]; - RootIndex index = static_cast<RootIndex>(i); - strong_gc_subroot_names_.emplace(heap_->root(index), name); + Isolate* isolate = heap_->isolate(); + for (RootIndex root_index = RootIndex::kFirstStrongOrReadOnlyRoot; + root_index <= RootIndex::kLastStrongOrReadOnlyRoot; ++root_index) { + const char* name = RootsTable::name(root_index); + strong_gc_subroot_names_.emplace(isolate->root(root_index), name); } CHECK(!strong_gc_subroot_names_.empty()); } @@ -1698,7 +1720,7 @@ const char* V8HeapExplorer::GetStrongGcSubrootName(Object* object) { return it != strong_gc_subroot_names_.end() ? it->second : nullptr; } -void V8HeapExplorer::TagObject(Object* obj, const char* tag) { +void V8HeapExplorer::TagObject(Object obj, const char* tag) { if (IsEssentialObject(obj)) { HeapEntry* entry = GetEntry(obj); if (entry->name()[0] == '\0') { @@ -1709,13 +1731,13 @@ void V8HeapExplorer::TagObject(Object* obj, const char* tag) { class GlobalObjectsEnumerator : public RootVisitor { public: - void VisitRootPointers(Root root, const char* description, Object** start, - Object** end) override { - for (Object** p = start; p < end; p++) { + void VisitRootPointers(Root root, const char* description, + FullObjectSlot start, FullObjectSlot end) override { + for (FullObjectSlot p = start; p < end; ++p) { if (!(*p)->IsNativeContext()) continue; - JSObject* proxy = Context::cast(*p)->global_proxy(); + JSObject proxy = Context::cast(*p)->global_proxy(); if (!proxy->IsJSGlobalProxy()) continue; - Object* global = proxy->map()->prototype(); + Object global = proxy->map()->prototype(); if (!global->IsJSGlobalObject()) continue; objects_.push_back(Handle<JSGlobalObject>(JSGlobalObject::cast(global), proxy->GetIsolate())); @@ -1759,8 +1781,8 @@ class EmbedderGraphImpl : public EmbedderGraph { class V8NodeImpl : public Node { public: - explicit V8NodeImpl(Object* object) : object_(object) {} - Object* GetObject() { return object_; } + explicit V8NodeImpl(Object object) : object_(object) {} + Object GetObject() { return object_; } // Node overrides. bool IsEmbedderNode() override { return false; } @@ -1776,7 +1798,7 @@ class EmbedderGraphImpl : public EmbedderGraph { } private: - Object* object_; + Object object_; }; Node* V8Node(const v8::Local<v8::Value>& value) final { @@ -1811,7 +1833,7 @@ class GlobalHandlesExtractor : public PersistentHandleVisitor { void VisitPersistentHandle(Persistent<Value>* value, uint16_t class_id) override { Handle<Object> object = Utils::OpenPersistent(value); - explorer_->VisitSubtreeWrapper(object.location(), class_id); + explorer_->VisitSubtreeWrapper(object, class_id); } private: @@ -1948,7 +1970,7 @@ NativeObjectsExplorer::~NativeObjectsExplorer() { for (auto map_entry : objects_by_info_) { v8::RetainedObjectInfo* info = map_entry.first; info->Dispose(); - std::vector<HeapObject*>* objects = map_entry.second; + std::vector<HeapObject>* objects = map_entry.second; delete objects; } for (auto map_entry : native_groups_) { @@ -1970,14 +1992,14 @@ void NativeObjectsExplorer::FillRetainedObjects() { v8::HeapProfiler::RetainerInfos infos = snapshot_->profiler()->GetRetainerInfos(isolate_); for (auto& pair : infos.groups) { - std::vector<HeapObject*>* info = GetVectorMaybeDisposeInfo(pair.first); + std::vector<HeapObject>* info = GetVectorMaybeDisposeInfo(pair.first); for (auto& persistent : pair.second) { if (persistent->IsEmpty()) continue; Handle<Object> object = v8::Utils::OpenHandle( *persistent->Get(reinterpret_cast<v8::Isolate*>(isolate_))); DCHECK(!object.is_null()); - HeapObject* heap_object = HeapObject::cast(*object); + HeapObject heap_object = HeapObject::cast(*object); info->push_back(heap_object); in_groups_.insert(heap_object); } @@ -1999,27 +2021,27 @@ void NativeObjectsExplorer::FillEdges() { Handle<Object> parent_object = v8::Utils::OpenHandle( *pair.first->Get(reinterpret_cast<v8::Isolate*>(isolate_))); - HeapObject* parent = HeapObject::cast(*parent_object); - HeapEntry* parent_entry = - generator_->FindOrAddEntry(parent, native_entries_allocator_.get()); + HeapObject parent = HeapObject::cast(*parent_object); + HeapEntry* parent_entry = generator_->FindOrAddEntry( + reinterpret_cast<void*>(parent.ptr()), native_entries_allocator_.get()); DCHECK_NOT_NULL(parent_entry); Handle<Object> child_object = v8::Utils::OpenHandle( *pair.second->Get(reinterpret_cast<v8::Isolate*>(isolate_))); - HeapObject* child = HeapObject::cast(*child_object); - HeapEntry* child_entry = - generator_->FindOrAddEntry(child, native_entries_allocator_.get()); + HeapObject child = HeapObject::cast(*child_object); + HeapEntry* child_entry = generator_->FindOrAddEntry( + reinterpret_cast<void*>(child.ptr()), native_entries_allocator_.get()); parent_entry->SetNamedReference(HeapGraphEdge::kInternal, "native", child_entry); } edges_.clear(); } -std::vector<HeapObject*>* NativeObjectsExplorer::GetVectorMaybeDisposeInfo( +std::vector<HeapObject>* NativeObjectsExplorer::GetVectorMaybeDisposeInfo( v8::RetainedObjectInfo* info) { if (objects_by_info_.count(info)) { info->Dispose(); } else { - objects_by_info_[info] = new std::vector<HeapObject*>(); + objects_by_info_[info] = new std::vector<HeapObject>(); } return objects_by_info_[info]; } @@ -2036,9 +2058,10 @@ HeapEntry* NativeObjectsExplorer::EntryForEmbedderGraphNode( } else { EmbedderGraphImpl::V8NodeImpl* v8_node = static_cast<EmbedderGraphImpl::V8NodeImpl*>(node); - Object* object = v8_node->GetObject(); + Object object = v8_node->GetObject(); if (object->IsSmi()) return nullptr; - return generator_->FindEntry(HeapObject::cast(object)); + return generator_->FindEntry( + reinterpret_cast<void*>(Object::cast(object).ptr())); } } @@ -2088,8 +2111,8 @@ bool NativeObjectsExplorer::IterateAndExtractReferences( for (auto map_entry : objects_by_info_) { v8::RetainedObjectInfo* info = map_entry.first; SetNativeRootReference(info); - std::vector<HeapObject*>* objects = map_entry.second; - for (HeapObject* object : *objects) { + std::vector<HeapObject>* objects = map_entry.second; + for (HeapObject object : *objects) { SetWrapperNativeReferences(object, info); } } @@ -2123,8 +2146,9 @@ void NativeObjectsExplorer::SetNativeRootReference( } void NativeObjectsExplorer::SetWrapperNativeReferences( - HeapObject* wrapper, v8::RetainedObjectInfo* info) { - HeapEntry* wrapper_entry = generator_->FindEntry(wrapper); + HeapObject wrapper, v8::RetainedObjectInfo* info) { + HeapEntry* wrapper_entry = + generator_->FindEntry(reinterpret_cast<void*>(wrapper.ptr())); DCHECK_NOT_NULL(wrapper_entry); HeapEntry* info_entry = generator_->FindOrAddEntry(info, native_entries_allocator_.get()); @@ -2146,7 +2170,8 @@ void NativeObjectsExplorer::SetRootNativeRootsReference() { } } -void NativeObjectsExplorer::VisitSubtreeWrapper(Object** p, uint16_t class_id) { +void NativeObjectsExplorer::VisitSubtreeWrapper(Handle<Object> p, + uint16_t class_id) { if (in_groups_.count(*p)) return; v8::RetainedObjectInfo* info = isolate_->heap_profiler()->ExecuteWrapperClassCallback(class_id, p); @@ -2171,13 +2196,13 @@ class NullContextScope { public: explicit NullContextScope(Isolate* isolate) : isolate_(isolate), prev_(isolate->context()) { - isolate_->set_context(nullptr); + isolate_->set_context(Context()); } ~NullContextScope() { isolate_->set_context(prev_); } private: Isolate* isolate_; - Context* prev_; + Context prev_; }; } // namespace diff --git a/deps/v8/src/profiler/heap-snapshot-generator.h b/deps/v8/src/profiler/heap-snapshot-generator.h index 1f8f364912..14cce75f90 100644 --- a/deps/v8/src/profiler/heap-snapshot-generator.h +++ b/deps/v8/src/profiler/heap-snapshot-generator.h @@ -15,6 +15,8 @@ #include "src/objects.h" #include "src/objects/fixed-array.h" #include "src/objects/hash-table.h" +#include "src/objects/heap-object.h" +#include "src/objects/js-objects.h" #include "src/objects/literal-objects.h" #include "src/profiler/strings-storage.h" #include "src/string-hasher.h" @@ -322,106 +324,105 @@ class V8HeapExplorer : public HeapEntriesAllocator { int EstimateObjectsCount(); bool IterateAndExtractReferences(HeapSnapshotGenerator* generator); void TagGlobalObjects(); - void TagCodeObject(Code* code); - void TagBuiltinCodeObject(Code* code, const char* name); + void TagBuiltinCodeObject(Code code, const char* name); HeapEntry* AddEntry(Address address, HeapEntry::Type type, const char* name, size_t size); - static JSFunction* GetConstructor(JSReceiver* receiver); - static String* GetConstructorName(JSObject* object); + static JSFunction GetConstructor(JSReceiver receiver); + static String GetConstructorName(JSObject object); private: void MarkVisitedField(int offset); - HeapEntry* AddEntry(HeapObject* object); - HeapEntry* AddEntry(HeapObject* object, - HeapEntry::Type type, + HeapEntry* AddEntry(HeapObject object); + HeapEntry* AddEntry(HeapObject object, HeapEntry::Type type, const char* name); - const char* GetSystemEntryName(HeapObject* object); - - void ExtractLocation(HeapEntry* entry, HeapObject* object); - void ExtractLocationForJSFunction(HeapEntry* entry, JSFunction* func); - void ExtractReferences(HeapEntry* entry, HeapObject* obj); - void ExtractJSGlobalProxyReferences(HeapEntry* entry, JSGlobalProxy* proxy); - void ExtractJSObjectReferences(HeapEntry* entry, JSObject* js_obj); - void ExtractStringReferences(HeapEntry* entry, String* obj); - void ExtractSymbolReferences(HeapEntry* entry, Symbol* symbol); - void ExtractJSCollectionReferences(HeapEntry* entry, - JSCollection* collection); + const char* GetSystemEntryName(HeapObject object); + + void ExtractLocation(HeapEntry* entry, HeapObject object); + void ExtractLocationForJSFunction(HeapEntry* entry, JSFunction func); + void ExtractReferences(HeapEntry* entry, HeapObject obj); + void ExtractJSGlobalProxyReferences(HeapEntry* entry, JSGlobalProxy proxy); + void ExtractJSObjectReferences(HeapEntry* entry, JSObject js_obj); + void ExtractStringReferences(HeapEntry* entry, String obj); + void ExtractSymbolReferences(HeapEntry* entry, Symbol symbol); + void ExtractJSCollectionReferences(HeapEntry* entry, JSCollection collection); void ExtractJSWeakCollectionReferences(HeapEntry* entry, - JSWeakCollection* collection); + JSWeakCollection collection); void ExtractEphemeronHashTableReferences(HeapEntry* entry, - EphemeronHashTable* table); - void ExtractContextReferences(HeapEntry* entry, Context* context); - void ExtractMapReferences(HeapEntry* entry, Map* map); + EphemeronHashTable table); + void ExtractContextReferences(HeapEntry* entry, Context context); + void ExtractMapReferences(HeapEntry* entry, Map map); void ExtractSharedFunctionInfoReferences(HeapEntry* entry, - SharedFunctionInfo* shared); - void ExtractScriptReferences(HeapEntry* entry, Script* script); + SharedFunctionInfo shared); + void ExtractScriptReferences(HeapEntry* entry, Script script); void ExtractAccessorInfoReferences(HeapEntry* entry, - AccessorInfo* accessor_info); - void ExtractAccessorPairReferences(HeapEntry* entry, AccessorPair* accessors); - void ExtractCodeReferences(HeapEntry* entry, Code* code); - void ExtractCellReferences(HeapEntry* entry, Cell* cell); + AccessorInfo accessor_info); + void ExtractAccessorPairReferences(HeapEntry* entry, AccessorPair accessors); + void ExtractCodeReferences(HeapEntry* entry, Code code); + void ExtractCellReferences(HeapEntry* entry, Cell cell); void ExtractFeedbackCellReferences(HeapEntry* entry, - FeedbackCell* feedback_cell); - void ExtractPropertyCellReferences(HeapEntry* entry, PropertyCell* cell); - void ExtractAllocationSiteReferences(HeapEntry* entry, AllocationSite* site); + FeedbackCell feedback_cell); + void ExtractPropertyCellReferences(HeapEntry* entry, PropertyCell cell); + void ExtractAllocationSiteReferences(HeapEntry* entry, AllocationSite site); void ExtractArrayBoilerplateDescriptionReferences( - HeapEntry* entry, ArrayBoilerplateDescription* value); - void ExtractJSArrayBufferReferences(HeapEntry* entry, JSArrayBuffer* buffer); - void ExtractJSPromiseReferences(HeapEntry* entry, JSPromise* promise); + HeapEntry* entry, ArrayBoilerplateDescription value); + void ExtractJSArrayBufferReferences(HeapEntry* entry, JSArrayBuffer buffer); + void ExtractJSPromiseReferences(HeapEntry* entry, JSPromise promise); void ExtractJSGeneratorObjectReferences(HeapEntry* entry, - JSGeneratorObject* generator); - void ExtractFixedArrayReferences(HeapEntry* entry, FixedArray* array); + JSGeneratorObject generator); + void ExtractFixedArrayReferences(HeapEntry* entry, FixedArray array); void ExtractFeedbackVectorReferences(HeapEntry* entry, - FeedbackVector* feedback_vector); + FeedbackVector feedback_vector); + void ExtractDescriptorArrayReferences(HeapEntry* entry, + DescriptorArray array); template <typename T> - void ExtractWeakArrayReferences(int header_size, HeapEntry* entry, T* array); - void ExtractPropertyReferences(JSObject* js_obj, HeapEntry* entry); - void ExtractAccessorPairProperty(HeapEntry* entry, Name* key, - Object* callback_obj, int field_offset = -1); - void ExtractElementReferences(JSObject* js_obj, HeapEntry* entry); - void ExtractInternalReferences(JSObject* js_obj, HeapEntry* entry); - - bool IsEssentialObject(Object* object); - bool IsEssentialHiddenReference(Object* parent, int field_offset); - - void SetContextReference(HeapEntry* parent_entry, String* reference_name, - Object* child, int field_offset); + void ExtractWeakArrayReferences(int header_size, HeapEntry* entry, T array); + void ExtractPropertyReferences(JSObject js_obj, HeapEntry* entry); + void ExtractAccessorPairProperty(HeapEntry* entry, Name key, + Object callback_obj, int field_offset = -1); + void ExtractElementReferences(JSObject js_obj, HeapEntry* entry); + void ExtractInternalReferences(JSObject js_obj, HeapEntry* entry); + + bool IsEssentialObject(Object object); + bool IsEssentialHiddenReference(Object parent, int field_offset); + + void SetContextReference(HeapEntry* parent_entry, String reference_name, + Object child, int field_offset); void SetNativeBindReference(HeapEntry* parent_entry, - const char* reference_name, Object* child); - void SetElementReference(HeapEntry* parent_entry, int index, Object* child); + const char* reference_name, Object child); + void SetElementReference(HeapEntry* parent_entry, int index, Object child); void SetInternalReference(HeapEntry* parent_entry, const char* reference_name, - Object* child, int field_offset = -1); - void SetInternalReference(HeapEntry* parent_entry, int index, Object* child, + Object child, int field_offset = -1); + void SetInternalReference(HeapEntry* parent_entry, int index, Object child, int field_offset = -1); - void SetHiddenReference(HeapObject* parent_obj, HeapEntry* parent_entry, - int index, Object* child, int field_offset); + void SetHiddenReference(HeapObject parent_obj, HeapEntry* parent_entry, + int index, Object child, int field_offset); void SetWeakReference(HeapEntry* parent_entry, const char* reference_name, - Object* child_obj, int field_offset); - void SetWeakReference(HeapEntry* parent_entry, int index, Object* child_obj, + Object child_obj, int field_offset); + void SetWeakReference(HeapEntry* parent_entry, int index, Object child_obj, int field_offset); - void SetPropertyReference(HeapEntry* parent_entry, Name* reference_name, - Object* child, + void SetPropertyReference(HeapEntry* parent_entry, Name reference_name, + Object child, const char* name_format_string = nullptr, int field_offset = -1); void SetDataOrAccessorPropertyReference( - PropertyKind kind, HeapEntry* parent_entry, Name* reference_name, - Object* child, const char* name_format_string = nullptr, + PropertyKind kind, HeapEntry* parent_entry, Name reference_name, + Object child, const char* name_format_string = nullptr, int field_offset = -1); - void SetUserGlobalReference(Object* user_global); + void SetUserGlobalReference(Object user_global); void SetRootGcRootsReference(); void SetGcRootsReference(Root root); void SetGcSubrootReference(Root root, const char* description, bool is_weak, - Object* child); - const char* GetStrongGcSubrootName(Object* object); - void TagObject(Object* obj, const char* tag); + Object child); + const char* GetStrongGcSubrootName(Object object); + void TagObject(Object obj, const char* tag); - HeapEntry* GetEntry(Object* obj); + HeapEntry* GetEntry(Object obj); Heap* heap_; HeapSnapshot* snapshot_; @@ -429,9 +430,10 @@ class V8HeapExplorer : public HeapEntriesAllocator { HeapObjectsMap* heap_object_map_; SnapshottingProgressReportingInterface* progress_; HeapSnapshotGenerator* generator_ = nullptr; - std::unordered_map<JSGlobalObject*, const char*> objects_tags_; - std::unordered_map<Object*, const char*> strong_gc_subroot_names_; - std::unordered_set<JSGlobalObject*> user_roots_; + std::unordered_map<JSGlobalObject, const char*, Object::Hasher> objects_tags_; + std::unordered_map<Object, const char*, Object::Hasher> + strong_gc_subroot_names_; + std::unordered_set<JSGlobalObject, Object::Hasher> user_roots_; v8::HeapProfiler::ObjectNameResolver* global_object_name_resolver_; std::vector<bool> visited_fields_; @@ -458,13 +460,13 @@ class NativeObjectsExplorer { private: void FillRetainedObjects(); void FillEdges(); - std::vector<HeapObject*>* GetVectorMaybeDisposeInfo( + std::vector<HeapObject>* GetVectorMaybeDisposeInfo( v8::RetainedObjectInfo* info); void SetNativeRootReference(v8::RetainedObjectInfo* info); void SetRootNativeRootsReference(); - void SetWrapperNativeReferences(HeapObject* wrapper, - v8::RetainedObjectInfo* info); - void VisitSubtreeWrapper(Object** p, uint16_t class_id); + void SetWrapperNativeReferences(HeapObject wrapper, + v8::RetainedObjectInfo* info); + void VisitSubtreeWrapper(Handle<Object> p, uint16_t class_id); struct RetainedInfoHasher { std::size_t operator()(v8::RetainedObjectInfo* info) const { @@ -486,8 +488,8 @@ class NativeObjectsExplorer { HeapSnapshot* snapshot_; StringsStorage* names_; bool embedder_queried_; - std::unordered_set<Object*> in_groups_; - std::unordered_map<v8::RetainedObjectInfo*, std::vector<HeapObject*>*, + std::unordered_set<Object, Object::Hasher> in_groups_; + std::unordered_map<v8::RetainedObjectInfo*, std::vector<HeapObject>*, RetainedInfoHasher, RetainedInfoEquals> objects_by_info_; std::unordered_map<const char*, NativeGroupRetainedObjectInfo*, diff --git a/deps/v8/src/profiler/profile-generator.cc b/deps/v8/src/profiler/profile-generator.cc index d60da5a44d..8ce9fb392e 100644 --- a/deps/v8/src/profiler/profile-generator.cc +++ b/deps/v8/src/profiler/profile-generator.cc @@ -18,7 +18,8 @@ namespace v8 { namespace internal { -void SourcePositionTable::SetPosition(int pc_offset, int line) { +void SourcePositionTable::SetPosition(int pc_offset, int line, + int inlining_id) { 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 @@ -26,8 +27,9 @@ void SourcePositionTable::SetPosition(int pc_offset, int line) { 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}); + pc_offsets_to_lines_.back().line_number != line || + pc_offsets_to_lines_.back().inlining_id != inlining_id) { + pc_offsets_to_lines_.push_back({pc_offset, line, inlining_id}); } } @@ -35,13 +37,33 @@ int SourcePositionTable::GetSourceLineNumber(int pc_offset) const { if (pc_offsets_to_lines_.empty()) { return v8::CpuProfileNode::kNoLineNumberInfo; } - auto it = - std::upper_bound(pc_offsets_to_lines_.begin(), pc_offsets_to_lines_.end(), - PCOffsetAndLineNumber{pc_offset, 0}); + auto it = std::lower_bound( + pc_offsets_to_lines_.begin(), pc_offsets_to_lines_.end(), + SourcePositionTuple{pc_offset, 0, SourcePosition::kNotInlined}); if (it != pc_offsets_to_lines_.begin()) --it; return it->line_number; } +int SourcePositionTable::GetInliningId(int pc_offset) const { + if (pc_offsets_to_lines_.empty()) { + return SourcePosition::kNotInlined; + } + auto it = std::lower_bound( + pc_offsets_to_lines_.begin(), pc_offsets_to_lines_.end(), + SourcePositionTuple{pc_offset, 0, SourcePosition::kNotInlined}); + if (it != pc_offsets_to_lines_.begin()) --it; + return it->inlining_id; +} + +void SourcePositionTable::print() const { + base::OS::Print(" - source position table at %p\n", this); + for (const SourcePositionTuple& pos_info : pc_offsets_to_lines_) { + base::OS::Print(" %d --> line_number: %d inlining_id: %d\n", + pos_info.pc_offset, pos_info.line_number, + pos_info.inlining_id); + } +} + const char* const CodeEntry::kWasmResourceNamePrefix = "wasm "; const char* const CodeEntry::kEmptyResourceName = ""; const char* const CodeEntry::kEmptyBailoutReason = ""; @@ -66,20 +88,22 @@ base::LazyDynamicInstance<CodeEntry, CodeEntry::kUnresolvedEntry = LAZY_DYNAMIC_INSTANCE_INITIALIZER; CodeEntry* CodeEntry::ProgramEntryCreateTrait::Create() { - return new CodeEntry(Logger::FUNCTION_TAG, CodeEntry::kProgramEntryName); + return new CodeEntry(CodeEventListener::FUNCTION_TAG, + CodeEntry::kProgramEntryName); } CodeEntry* CodeEntry::IdleEntryCreateTrait::Create() { - return new CodeEntry(Logger::FUNCTION_TAG, CodeEntry::kIdleEntryName); + return new CodeEntry(CodeEventListener::FUNCTION_TAG, + CodeEntry::kIdleEntryName); } CodeEntry* CodeEntry::GCEntryCreateTrait::Create() { - return new CodeEntry(Logger::BUILTIN_TAG, + return new CodeEntry(CodeEventListener::BUILTIN_TAG, CodeEntry::kGarbageCollectorEntryName); } CodeEntry* CodeEntry::UnresolvedEntryCreateTrait::Create() { - return new CodeEntry(Logger::FUNCTION_TAG, + return new CodeEntry(CodeEventListener::FUNCTION_TAG, CodeEntry::kUnresolvedFunctionName); } @@ -119,17 +143,25 @@ int CodeEntry::GetSourceLine(int pc_offset) const { return v8::CpuProfileNode::kNoLineNumberInfo; } -void CodeEntry::AddInlineStack( - int pc_offset, std::vector<std::unique_ptr<CodeEntry>> inline_stack) { - EnsureRareData()->inline_locations_.insert( - std::make_pair(pc_offset, std::move(inline_stack))); +void CodeEntry::SetInlineStacks( + std::unordered_set<std::unique_ptr<CodeEntry>, Hasher, Equals> + inline_entries, + std::unordered_map<int, std::vector<CodeEntryAndLineNumber>> + inline_stacks) { + EnsureRareData()->inline_entries_ = std::move(inline_entries); + rare_data_->inline_stacks_ = std::move(inline_stacks); } -const std::vector<std::unique_ptr<CodeEntry>>* CodeEntry::GetInlineStack( +const std::vector<CodeEntryAndLineNumber>* 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; + if (!line_info_) return nullptr; + + int inlining_id = line_info_->GetInliningId(pc_offset); + if (inlining_id == SourcePosition::kNotInlined) return nullptr; + DCHECK(rare_data_); + + auto it = rare_data_->inline_stacks_.find(inlining_id); + return it != rare_data_->inline_stacks_.end() ? &it->second : nullptr; } void CodeEntry::set_deopt_info( @@ -142,9 +174,9 @@ void CodeEntry::set_deopt_info( rare_data->deopt_inlined_frames_ = std::move(inlined_frames); } -void CodeEntry::FillFunctionInfo(SharedFunctionInfo* shared) { +void CodeEntry::FillFunctionInfo(SharedFunctionInfo shared) { if (!shared->script()->IsScript()) return; - Script* script = Script::cast(shared->script()); + Script script = Script::cast(shared->script()); set_script_id(script->id()); set_position(shared->StartPosition()); if (shared->optimization_disabled()) { @@ -174,6 +206,55 @@ CodeEntry::RareData* CodeEntry::EnsureRareData() { return rare_data_.get(); } +void CodeEntry::print() const { + base::OS::Print("CodeEntry: at %p\n", this); + + base::OS::Print(" - name: %s\n", name_); + base::OS::Print(" - resource_name: %s\n", resource_name_); + base::OS::Print(" - line_number: %d\n", line_number_); + base::OS::Print(" - column_number: %d\n", column_number_); + base::OS::Print(" - script_id: %d\n", script_id_); + base::OS::Print(" - position: %d\n", position_); + base::OS::Print(" - instruction_start: %p\n", + reinterpret_cast<void*>(instruction_start_)); + + if (line_info_) { + line_info_->print(); + } + + if (rare_data_) { + base::OS::Print(" - deopt_reason: %s\n", rare_data_->deopt_reason_); + base::OS::Print(" - bailout_reason: %s\n", rare_data_->bailout_reason_); + base::OS::Print(" - deopt_id: %d\n", rare_data_->deopt_id_); + + if (!rare_data_->inline_stacks_.empty()) { + base::OS::Print(" - inline stacks:\n"); + for (auto it = rare_data_->inline_stacks_.begin(); + it != rare_data_->inline_stacks_.end(); it++) { + base::OS::Print(" inlining_id: [%d]\n", it->first); + for (const auto& e : it->second) { + base::OS::Print(" %s --> %d\n", e.code_entry->name(), + e.line_number); + } + } + } else { + base::OS::Print(" - inline stacks: (empty)\n"); + } + + if (!rare_data_->deopt_inlined_frames_.empty()) { + base::OS::Print(" - deopt inlined frames:\n"); + for (const CpuProfileDeoptFrame& frame : + rare_data_->deopt_inlined_frames_) { + base::OS::Print("script_id: %d position: %zu\n", frame.script_id, + frame.position); + } + } else { + base::OS::Print(" - deopt inlined frames: (empty)\n"); + } + } + base::OS::Print("\n"); +} + void ProfileNode::CollectDeoptInfo(CodeEntry* entry) { deopt_infos_.push_back(entry->GetDeoptInfo()); entry->clear_deopt_info(); @@ -759,15 +840,22 @@ void ProfileGenerator::RecordTickSample(const TickSample& sample) { int pc_offset = static_cast<int>(stack_pos - entry->instruction_start()); // TODO(petermarshall): pc_offset can still be negative in some cases. - const std::vector<std::unique_ptr<CodeEntry>>* inline_stack = + const std::vector<CodeEntryAndLineNumber>* inline_stack = entry->GetInlineStack(pc_offset); if (inline_stack) { - std::transform( - inline_stack->rbegin(), inline_stack->rend(), - std::back_inserter(stack_trace), - [=](const std::unique_ptr<CodeEntry>& ptr) { - return CodeEntryAndLineNumber{ptr.get(), no_line_info}; - }); + int most_inlined_frame_line_number = entry->GetSourceLine(pc_offset); + stack_trace.insert(stack_trace.end(), inline_stack->begin(), + inline_stack->end()); + // This is a bit of a messy hack. The line number for the most-inlined + // frame (the function at the end of the chain of function calls) has + // the wrong line number in inline_stack. The actual line number in + // this function is stored in the SourcePositionTable in entry. We fix + // up the line number for the most-inlined frame here. + // TODO(petermarshall): Remove this and use a tree with a node per + // inlining_id. + DCHECK(!inline_stack->empty()); + size_t index = stack_trace.size() - inline_stack->size(); + stack_trace[index].line_number = most_inlined_frame_line_number; } // Skip unresolved frames (e.g. internal frame) and get source line of // the first JS caller. @@ -779,6 +867,12 @@ void ProfileGenerator::RecordTickSample(const TickSample& sample) { src_line_not_found = false; } line_number = entry->GetSourceLine(pc_offset); + + // The inline stack contains the top-level function i.e. the same + // function as entry. We don't want to add it twice. The one from the + // inline stack has the correct line number for this particular inlining + // so we use it instead of pushing entry to stack_trace. + if (inline_stack) continue; } stack_trace.push_back({entry, line_number}); } diff --git a/deps/v8/src/profiler/profile-generator.h b/deps/v8/src/profiler/profile-generator.h index ac9506ab21..ebb4f0ea2c 100644 --- a/deps/v8/src/profiler/profile-generator.h +++ b/deps/v8/src/profiler/profile-generator.h @@ -16,7 +16,8 @@ #include "include/v8-profiler.h" #include "src/allocation.h" -#include "src/log.h" +#include "src/builtins/builtins.h" +#include "src/code-events.h" #include "src/profiler/strings-storage.h" #include "src/source-position.h" @@ -26,29 +27,35 @@ namespace internal { struct TickSample; // Provides a mapping from the offsets within generated code or a bytecode array -// to the source line. +// to the source line and inlining id. class SourcePositionTable : public Malloced { public: SourcePositionTable() = default; - void SetPosition(int pc_offset, int line); + void SetPosition(int pc_offset, int line, int inlining_id); int GetSourceLineNumber(int pc_offset) const; + int GetInliningId(int pc_offset) const; + + void print() const; private: - struct PCOffsetAndLineNumber { - bool operator<(const PCOffsetAndLineNumber& other) const { + struct SourcePositionTuple { + bool operator<(const SourcePositionTuple& other) const { return pc_offset < other.pc_offset; } int pc_offset; int line_number; + int inlining_id; }; - // This is logically a map, but we store it as a vector of pairs, sorted by + // This is logically a map, but we store it as a vector of tuples, sorted by // the pc offset, so that we can save space and look up items using binary // search. - std::vector<PCOffsetAndLineNumber> pc_offsets_to_lines_; + std::vector<SourcePositionTuple> pc_offsets_to_lines_; DISALLOW_COPY_AND_ASSIGN(SourcePositionTable); }; +struct CodeEntryAndLineNumber; + class CodeEntry { public: // CodeEntry doesn't own name strings, just references them. @@ -91,7 +98,7 @@ class CodeEntry { void mark_used() { bit_field_ = UsedField::update(bit_field_, true); } bool used() const { return UsedField::decode(bit_field_); } - void FillFunctionInfo(SharedFunctionInfo* shared); + void FillFunctionInfo(SharedFunctionInfo shared); void SetBuiltinId(Builtins::Name id); Builtins::Name builtin_id() const { @@ -103,9 +110,24 @@ class CodeEntry { int GetSourceLine(int pc_offset) const; - void AddInlineStack(int pc_offset, - std::vector<std::unique_ptr<CodeEntry>> inline_stack); - const std::vector<std::unique_ptr<CodeEntry>>* GetInlineStack( + struct Equals { + bool operator()(const std::unique_ptr<CodeEntry>& lhs, + const std::unique_ptr<CodeEntry>& rhs) const { + return lhs.get()->IsSameFunctionAs(rhs.get()); + } + }; + struct Hasher { + std::size_t operator()(const std::unique_ptr<CodeEntry>& e) const { + return e->GetHash(); + } + }; + + void SetInlineStacks( + std::unordered_set<std::unique_ptr<CodeEntry>, Hasher, Equals> + inline_entries, + std::unordered_map<int, std::vector<CodeEntryAndLineNumber>> + inline_stacks); + const std::vector<CodeEntryAndLineNumber>* GetInlineStack( int pc_offset) const; void set_instruction_start(Address start) { instruction_start_ = start; } @@ -136,13 +158,16 @@ class CodeEntry { return kUnresolvedEntry.Pointer(); } + void print() const; + private: struct RareData { const char* deopt_reason_ = kNoDeoptReason; const char* bailout_reason_ = kEmptyBailoutReason; int deopt_id_ = kNoDeoptimizationId; - std::unordered_map<int, std::vector<std::unique_ptr<CodeEntry>>> - inline_locations_; + std::unordered_map<int, std::vector<CodeEntryAndLineNumber>> inline_stacks_; + std::unordered_set<std::unique_ptr<CodeEntry>, Hasher, Equals> + inline_entries_; std::vector<CpuProfileDeoptFrame> deopt_inlined_frames_; }; @@ -170,7 +195,7 @@ class CodeEntry { static base::LazyDynamicInstance<CodeEntry, UnresolvedEntryCreateTrait>::type kUnresolvedEntry; - using TagField = BitField<Logger::LogEventsAndTags, 0, 8>; + using TagField = BitField<CodeEventListener::LogEventsAndTags, 0, 8>; using BuiltinIdField = BitField<Builtins::Name, 8, 23>; using UsedField = BitField<bool, 31, 1>; @@ -313,6 +338,7 @@ class ProfileTree { DISALLOW_COPY_AND_ASSIGN(ProfileTree); }; +class CpuProfiler; class CpuProfile { public: @@ -412,7 +438,7 @@ class CpuProfilesCollection { std::vector<std::unique_ptr<CpuProfile>>* profiles() { return &finished_profiles_; } - const char* GetName(Name* name) { return resource_names_.GetName(name); } + const char* GetName(Name name) { return resource_names_.GetName(name); } bool IsLastProfile(const char* title); void RemoveProfile(CpuProfile* profile); diff --git a/deps/v8/src/profiler/profiler-listener.cc b/deps/v8/src/profiler/profiler-listener.cc index f90a2e11d3..2aac98f61f 100644 --- a/deps/v8/src/profiler/profiler-listener.cc +++ b/deps/v8/src/profiler/profiler-listener.cc @@ -5,10 +5,11 @@ #include "src/profiler/profiler-listener.h" #include "src/deoptimizer.h" -#include "src/instruction-stream.h" #include "src/objects-inl.h" #include "src/profiler/cpu-profiler.h" #include "src/profiler/profile-generator-inl.h" +#include "src/reloc-info.h" +#include "src/snapshot/embedded-data.h" #include "src/source-position-table.h" #include "src/wasm/wasm-code-manager.h" @@ -21,7 +22,7 @@ ProfilerListener::ProfilerListener(Isolate* isolate, ProfilerListener::~ProfilerListener() = default; -void ProfilerListener::CallbackEvent(Name* name, Address entry_point) { +void ProfilerListener::CallbackEvent(Name name, Address entry_point) { CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION); CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_; rec->instruction_start = entry_point; @@ -31,7 +32,7 @@ void ProfilerListener::CallbackEvent(Name* name, Address entry_point) { } void ProfilerListener::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag, - AbstractCode* code, const char* name) { + AbstractCode code, const char* name) { CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION); CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_; rec->instruction_start = code->InstructionStart(); @@ -39,13 +40,12 @@ void ProfilerListener::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag, CpuProfileNode::kNoLineNumberInfo, CpuProfileNode::kNoColumnNumberInfo, nullptr, code->InstructionStart()); - RecordInliningInfo(rec->entry, code); rec->instruction_size = code->InstructionSize(); DispatchCodeEvent(evt_rec); } void ProfilerListener::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag, - AbstractCode* code, Name* name) { + AbstractCode code, Name name) { CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION); CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_; rec->instruction_start = code->InstructionStart(); @@ -53,15 +53,14 @@ void ProfilerListener::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag, CpuProfileNode::kNoLineNumberInfo, CpuProfileNode::kNoColumnNumberInfo, nullptr, code->InstructionStart()); - RecordInliningInfo(rec->entry, code); rec->instruction_size = code->InstructionSize(); DispatchCodeEvent(evt_rec); } void ProfilerListener::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag, - AbstractCode* code, - SharedFunctionInfo* shared, - Name* script_name) { + AbstractCode code, + SharedFunctionInfo shared, + Name script_name) { CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION); CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_; rec->instruction_start = code->InstructionStart(); @@ -70,40 +69,113 @@ void ProfilerListener::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag, CpuProfileNode::kNoLineNumberInfo, CpuProfileNode::kNoColumnNumberInfo, nullptr, code->InstructionStart()); - RecordInliningInfo(rec->entry, code); + DCHECK(!code->IsCode()); rec->entry->FillFunctionInfo(shared); rec->instruction_size = code->InstructionSize(); DispatchCodeEvent(evt_rec); } +namespace { + +CodeEntry* GetOrInsertCachedEntry( + std::unordered_set<std::unique_ptr<CodeEntry>, CodeEntry::Hasher, + CodeEntry::Equals>* entries, + std::unique_ptr<CodeEntry> search_value) { + auto it = entries->find(search_value); + if (it != entries->end()) return it->get(); + CodeEntry* ret = search_value.get(); + entries->insert(std::move(search_value)); + return ret; +} + +} // namespace + void ProfilerListener::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag, - AbstractCode* abstract_code, - SharedFunctionInfo* shared, - Name* script_name, int line, - int column) { + AbstractCode abstract_code, + SharedFunctionInfo shared, + Name script_name, int line, int column) { CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION); CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_; rec->instruction_start = abstract_code->InstructionStart(); std::unique_ptr<SourcePositionTable> line_table; + std::unordered_map<int, std::vector<CodeEntryAndLineNumber>> inline_stacks; + std::unordered_set<std::unique_ptr<CodeEntry>, CodeEntry::Hasher, + CodeEntry::Equals> + cached_inline_entries; if (shared->script()->IsScript()) { - Script* script = Script::cast(shared->script()); + Script script = Script::cast(shared->script()); line_table.reset(new SourcePositionTable()); + HandleScope scope(isolate_); + + // Add each position to the source position table and store inlining stacks + // for inline positions. We store almost the same information in the + // profiler as is stored on the code object, except that we transform source + // positions to line numbers here, because we only care about attributing + // ticks to a given line. for (SourcePositionTableIterator it(abstract_code->source_position_table()); !it.done(); it.Advance()) { - // TODO(alph,tebbi) Skipping inlined positions for now, because they might - // refer to a different script. - if (it.source_position().InliningId() != SourcePosition::kNotInlined) - continue; int position = it.source_position().ScriptOffset(); int line_number = script->GetLineNumber(position) + 1; - line_table->SetPosition(it.code_offset(), line_number); + int inlining_id = it.source_position().InliningId(); + line_table->SetPosition(it.code_offset(), line_number, inlining_id); + + if (inlining_id != SourcePosition::kNotInlined) { + DCHECK(abstract_code->IsCode()); + Code code = abstract_code->GetCode(); + std::vector<SourcePositionInfo> stack = + it.source_position().InliningStack(handle(code, isolate_)); + DCHECK(!stack.empty()); + + std::vector<CodeEntryAndLineNumber> inline_stack; + for (SourcePositionInfo& pos_info : stack) { + if (pos_info.position.ScriptOffset() == kNoSourcePosition) continue; + if (pos_info.script.is_null()) continue; + + int line_number = + pos_info.script->GetLineNumber(pos_info.position.ScriptOffset()) + + 1; + + const char* resource_name = + (pos_info.script->name()->IsName()) + ? GetName(Name::cast(pos_info.script->name())) + : CodeEntry::kEmptyResourceName; + + // We need the start line number and column number of the function for + // kLeafNodeLineNumbers mode. Creating a SourcePositionInfo is a handy + // way of getting both easily. + SourcePositionInfo start_pos_info( + SourcePosition(pos_info.shared->StartPosition()), + pos_info.shared); + + std::unique_ptr<CodeEntry> inline_entry = + base::make_unique<CodeEntry>( + tag, GetName(pos_info.shared->DebugName()), resource_name, + start_pos_info.line + 1, start_pos_info.column + 1, nullptr, + code->InstructionStart()); + inline_entry->FillFunctionInfo(*pos_info.shared); + + // Create a canonical CodeEntry for each inlined frame and then re-use + // them for subsequent inline stacks to avoid a lot of duplication. + CodeEntry* cached_entry = GetOrInsertCachedEntry( + &cached_inline_entries, std::move(inline_entry)); + + inline_stack.push_back( + CodeEntryAndLineNumber{cached_entry, line_number}); + } + DCHECK(!inline_stack.empty()); + inline_stacks.emplace(inlining_id, std::move(inline_stack)); + } } } rec->entry = NewCodeEntry(tag, GetName(shared->DebugName()), GetName(InferScriptName(script_name, shared)), line, column, std::move(line_table), abstract_code->InstructionStart()); - RecordInliningInfo(rec->entry, abstract_code); + if (!inline_stacks.empty()) { + rec->entry->SetInlineStacks(std::move(cached_inline_entries), + std::move(inline_stacks)); + } + rec->entry->FillFunctionInfo(shared); rec->instruction_size = abstract_code->InstructionSize(); DispatchCodeEvent(evt_rec); @@ -123,7 +195,7 @@ void ProfilerListener::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag, DispatchCodeEvent(evt_rec); } -void ProfilerListener::CodeMoveEvent(AbstractCode* from, AbstractCode* to) { +void ProfilerListener::CodeMoveEvent(AbstractCode from, AbstractCode to) { CodeEventsContainer evt_rec(CodeEventRecord::CODE_MOVE); CodeMoveEventRecord* rec = &evt_rec.CodeMoveEventRecord_; rec->from_instruction_start = from->InstructionStart(); @@ -131,8 +203,8 @@ void ProfilerListener::CodeMoveEvent(AbstractCode* from, AbstractCode* to) { DispatchCodeEvent(evt_rec); } -void ProfilerListener::CodeDisableOptEvent(AbstractCode* code, - SharedFunctionInfo* shared) { +void ProfilerListener::CodeDisableOptEvent(AbstractCode code, + SharedFunctionInfo shared) { CodeEventsContainer evt_rec(CodeEventRecord::CODE_DISABLE_OPT); CodeDisableOptEventRecord* rec = &evt_rec.CodeDisableOptEventRecord_; rec->instruction_start = code->InstructionStart(); @@ -140,7 +212,7 @@ void ProfilerListener::CodeDisableOptEvent(AbstractCode* code, DispatchCodeEvent(evt_rec); } -void ProfilerListener::CodeDeoptEvent(Code* code, DeoptimizeKind kind, +void ProfilerListener::CodeDeoptEvent(Code code, DeoptimizeKind kind, Address pc, int fp_to_sp_delta) { CodeEventsContainer evt_rec(CodeEventRecord::CODE_DEOPT); CodeDeoptEventRecord* rec = &evt_rec.CodeDeoptEventRecord_; @@ -157,7 +229,7 @@ void ProfilerListener::CodeDeoptEvent(Code* code, DeoptimizeKind kind, DispatchCodeEvent(evt_rec); } -void ProfilerListener::GetterCallbackEvent(Name* name, Address entry_point) { +void ProfilerListener::GetterCallbackEvent(Name name, Address entry_point) { CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION); CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_; rec->instruction_start = entry_point; @@ -167,8 +239,7 @@ void ProfilerListener::GetterCallbackEvent(Name* name, Address entry_point) { DispatchCodeEvent(evt_rec); } -void ProfilerListener::RegExpCodeCreateEvent(AbstractCode* code, - String* source) { +void ProfilerListener::RegExpCodeCreateEvent(AbstractCode code, String source) { CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION); CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_; rec->instruction_start = code->InstructionStart(); @@ -180,7 +251,7 @@ void ProfilerListener::RegExpCodeCreateEvent(AbstractCode* code, DispatchCodeEvent(evt_rec); } -void ProfilerListener::SetterCallbackEvent(Name* name, Address entry_point) { +void ProfilerListener::SetterCallbackEvent(Name name, Address entry_point) { CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION); CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_; rec->instruction_start = entry_point; @@ -190,67 +261,14 @@ void ProfilerListener::SetterCallbackEvent(Name* name, Address entry_point) { DispatchCodeEvent(evt_rec); } -Name* ProfilerListener::InferScriptName(Name* name, SharedFunctionInfo* info) { +Name ProfilerListener::InferScriptName(Name name, SharedFunctionInfo info) { if (name->IsString() && String::cast(name)->length()) return name; if (!info->script()->IsScript()) return name; - Object* source_url = Script::cast(info->script())->source_url(); + Object source_url = Script::cast(info->script())->source_url(); return source_url->IsName() ? Name::cast(source_url) : name; } -void ProfilerListener::RecordInliningInfo(CodeEntry* entry, - AbstractCode* abstract_code) { - if (!abstract_code->IsCode()) return; - Code* code = abstract_code->GetCode(); - if (code->kind() != Code::OPTIMIZED_FUNCTION) return; - DeoptimizationData* deopt_input_data = - DeoptimizationData::cast(code->deoptimization_data()); - int deopt_count = deopt_input_data->DeoptCount(); - for (int i = 0; i < deopt_count; i++) { - int pc_offset = deopt_input_data->Pc(i)->value(); - if (pc_offset == -1) continue; - int translation_index = deopt_input_data->TranslationIndex(i)->value(); - TranslationIterator it(deopt_input_data->TranslationByteArray(), - translation_index); - Translation::Opcode opcode = static_cast<Translation::Opcode>(it.Next()); - DCHECK_EQ(Translation::BEGIN, opcode); - it.Skip(Translation::NumberOfOperandsFor(opcode)); - int depth = 0; - std::vector<std::unique_ptr<CodeEntry>> inline_stack; - while (it.HasNext() && - Translation::BEGIN != - (opcode = static_cast<Translation::Opcode>(it.Next()))) { - if (opcode != Translation::INTERPRETED_FRAME) { - it.Skip(Translation::NumberOfOperandsFor(opcode)); - continue; - } - it.Next(); // Skip ast_id - int shared_info_id = it.Next(); - it.Next(); // Skip height - SharedFunctionInfo* shared_info = SharedFunctionInfo::cast( - deopt_input_data->LiteralArray()->get(shared_info_id)); - if (!depth++) continue; // Skip the current function itself. - - const char* resource_name = - (shared_info->script()->IsScript() && - Script::cast(shared_info->script())->name()->IsName()) - ? GetName(Name::cast(Script::cast(shared_info->script())->name())) - : CodeEntry::kEmptyResourceName; - - CodeEntry* inline_entry = - new CodeEntry(entry->tag(), GetName(shared_info->DebugName()), - resource_name, CpuProfileNode::kNoLineNumberInfo, - CpuProfileNode::kNoColumnNumberInfo, nullptr, - code->InstructionStart()); - inline_entry->FillFunctionInfo(shared_info); - inline_stack.emplace_back(inline_entry); - } - if (!inline_stack.empty()) { - entry->AddInlineStack(pc_offset, std::move(inline_stack)); - } - } -} - -void ProfilerListener::AttachDeoptInlinedFrames(Code* code, +void ProfilerListener::AttachDeoptInlinedFrames(Code code, CodeDeoptEventRecord* rec) { int deopt_id = rec->deopt_id; SourcePosition last_position = SourcePosition::Unknown(); diff --git a/deps/v8/src/profiler/profiler-listener.h b/deps/v8/src/profiler/profiler-listener.h index 51fba18a60..6bd794df70 100644 --- a/deps/v8/src/profiler/profiler-listener.h +++ b/deps/v8/src/profiler/profiler-listener.h @@ -28,30 +28,30 @@ class ProfilerListener : public CodeEventListener { ProfilerListener(Isolate*, CodeEventObserver*); ~ProfilerListener() override; - void CallbackEvent(Name* name, Address entry_point) override; + void CallbackEvent(Name name, Address entry_point) override; void CodeCreateEvent(CodeEventListener::LogEventsAndTags tag, - AbstractCode* code, const char* comment) override; + AbstractCode code, const char* comment) override; void CodeCreateEvent(CodeEventListener::LogEventsAndTags tag, - AbstractCode* code, Name* name) override; + AbstractCode code, Name name) override; void CodeCreateEvent(CodeEventListener::LogEventsAndTags tag, - AbstractCode* code, SharedFunctionInfo* shared, - Name* script_name) override; + AbstractCode code, SharedFunctionInfo shared, + Name script_name) override; void CodeCreateEvent(CodeEventListener::LogEventsAndTags tag, - AbstractCode* code, SharedFunctionInfo* shared, - Name* script_name, int line, int column) override; + AbstractCode code, SharedFunctionInfo shared, + Name script_name, int line, int column) override; void CodeCreateEvent(CodeEventListener::LogEventsAndTags tag, const wasm::WasmCode* code, wasm::WasmName name) override; void CodeMovingGCEvent() override {} - void CodeMoveEvent(AbstractCode* from, AbstractCode* to) override; - void CodeDisableOptEvent(AbstractCode* code, - SharedFunctionInfo* shared) override; - void CodeDeoptEvent(Code* code, DeoptimizeKind kind, Address pc, + void CodeMoveEvent(AbstractCode from, AbstractCode to) override; + void CodeDisableOptEvent(AbstractCode code, + SharedFunctionInfo shared) override; + void CodeDeoptEvent(Code code, DeoptimizeKind kind, Address pc, int fp_to_sp_delta) override; - void GetterCallbackEvent(Name* name, Address entry_point) override; - void RegExpCodeCreateEvent(AbstractCode* code, String* source) override; - void SetterCallbackEvent(Name* name, Address entry_point) override; + void GetterCallbackEvent(Name name, Address entry_point) override; + void RegExpCodeCreateEvent(AbstractCode code, String source) override; + void SetterCallbackEvent(Name name, Address entry_point) override; void SharedFunctionInfoMoveEvent(Address from, Address to) override {} CodeEntry* NewCodeEntry( @@ -62,7 +62,7 @@ class ProfilerListener : public CodeEventListener { std::unique_ptr<SourcePositionTable> line_info = nullptr, Address instruction_start = kNullAddress); - const char* GetName(Name* name) { + const char* GetName(Name name) { return function_and_resource_names_.GetName(name); } const char* GetName(int args_count) { @@ -71,14 +71,13 @@ class ProfilerListener : public CodeEventListener { const char* GetName(const char* name) { return function_and_resource_names_.GetCopy(name); } - const char* GetConsName(const char* prefix, Name* name) { + const char* GetConsName(const char* prefix, Name name) { return function_and_resource_names_.GetConsName(prefix, name); } private: - void RecordInliningInfo(CodeEntry* entry, AbstractCode* abstract_code); - void AttachDeoptInlinedFrames(Code* code, CodeDeoptEventRecord* rec); - Name* InferScriptName(Name* name, SharedFunctionInfo* info); + void AttachDeoptInlinedFrames(Code code, CodeDeoptEventRecord* rec); + Name InferScriptName(Name name, SharedFunctionInfo info); V8_INLINE void DispatchCodeEvent(const CodeEventsContainer& evt_rec) { observer_->CodeEventHandler(evt_rec); } diff --git a/deps/v8/src/profiler/sampling-heap-profiler.cc b/deps/v8/src/profiler/sampling-heap-profiler.cc index 2e07135d85..3e158544fd 100644 --- a/deps/v8/src/profiler/sampling-heap-profiler.cc +++ b/deps/v8/src/profiler/sampling-heap-profiler.cc @@ -31,8 +31,8 @@ intptr_t SamplingAllocationObserver::GetNextSampleInterval(uint64_t rate) { } double u = random_->NextDouble(); double next = (-base::ieee754::log(u)) * rate; - return next < kPointerSize - ? kPointerSize + return next < kTaggedSize + ? kTaggedSize : (next > INT_MAX ? INT_MAX : static_cast<intptr_t>(next)); } @@ -44,7 +44,7 @@ intptr_t SamplingAllocationObserver::GetNextSampleInterval(uint64_t rate) { // approximate the true number of allocations with size *size* given that // *count* samples were observed. v8::AllocationProfile::Allocation SamplingHeapProfiler::ScaleSample( - size_t size, unsigned int count) { + size_t size, unsigned int count) const { double scale = 1.0 / (1.0 - std::exp(-static_cast<double>(size) / rate_)); // Round count instead of truncating. return {size, static_cast<unsigned int>(count * scale + 0.5)}; @@ -62,40 +62,39 @@ SamplingHeapProfiler::SamplingHeapProfiler( heap_, static_cast<intptr_t>(rate), rate, this, heap->isolate()->random_number_generator())), names_(names), - profile_root_(nullptr, "(root)", v8::UnboundScript::kNoScriptId, 0), + profile_root_(nullptr, "(root)", v8::UnboundScript::kNoScriptId, 0, + next_node_id()), stack_depth_(stack_depth), rate_(rate), flags_(flags) { CHECK_GT(rate_, 0u); - heap_->AddAllocationObserversToAllSpaces(other_spaces_observer_.get(), new_space_observer_.get()); } - SamplingHeapProfiler::~SamplingHeapProfiler() { heap_->RemoveAllocationObserversFromAllSpaces(other_spaces_observer_.get(), new_space_observer_.get()); } - void SamplingHeapProfiler::SampleObject(Address soon_object, size_t size) { DisallowHeapAllocation no_allocation; HandleScope scope(isolate_); - HeapObject* heap_object = HeapObject::FromAddress(soon_object); + HeapObject heap_object = HeapObject::FromAddress(soon_object); Handle<Object> obj(heap_object, isolate_); // Mark the new block as FreeSpace to make sure the heap is iterable while we // are taking the sample. - heap()->CreateFillerObjectAt(soon_object, static_cast<int>(size), - ClearRecordedSlots::kNo); + heap_->CreateFillerObjectAt(soon_object, static_cast<int>(size), + ClearRecordedSlots::kNo); Local<v8::Value> loc = v8::Utils::ToLocal(obj); AllocationNode* node = AddStack(); node->allocations_[size]++; - auto sample = base::make_unique<Sample>(size, node, loc, this); + auto sample = + base::make_unique<Sample>(size, node, loc, this, next_sample_id()); sample->global.SetWeak(sample.get(), OnWeakCallback, WeakCallbackType::kParameter); #if __clang__ @@ -132,25 +131,25 @@ void SamplingHeapProfiler::OnWeakCallback( // sample is deleted because its unique ptr was erased from samples_. } -SamplingHeapProfiler::AllocationNode* -SamplingHeapProfiler::AllocationNode::FindOrAddChildNode(const char* name, - int script_id, - int start_position) { - FunctionId id = function_id(script_id, start_position, name); - auto it = children_.find(id); - if (it != children_.end()) { - DCHECK_EQ(strcmp(it->second->name_, name), 0); - return it->second.get(); +SamplingHeapProfiler::AllocationNode* SamplingHeapProfiler::FindOrAddChildNode( + AllocationNode* parent, const char* name, int script_id, + int start_position) { + AllocationNode::FunctionId id = + AllocationNode::function_id(script_id, start_position, name); + AllocationNode* child = parent->FindChildNode(id); + if (child) { + DCHECK_EQ(strcmp(child->name_, name), 0); + return child; } - auto child = - base::make_unique<AllocationNode>(this, name, script_id, start_position); - return children_.emplace(id, std::move(child)).first->second.get(); + auto new_child = base::make_unique<AllocationNode>( + parent, name, script_id, start_position, next_node_id()); + return parent->AddChildNode(id, std::move(new_child)); } SamplingHeapProfiler::AllocationNode* SamplingHeapProfiler::AddStack() { AllocationNode* node = &profile_root_; - std::vector<SharedFunctionInfo*> stack; + std::vector<SharedFunctionInfo> stack; JavaScriptFrameIterator it(isolate_); int frames_captured = 0; bool found_arguments_marker_frames = false; @@ -162,7 +161,7 @@ SamplingHeapProfiler::AllocationNode* SamplingHeapProfiler::AddStack() { // in the top frames of the stack). The allocations made in this // sensitive moment belong to the formerly optimized frame anyway. if (frame->unchecked_function()->IsJSFunction()) { - SharedFunctionInfo* shared = frame->function()->shared(); + SharedFunctionInfo shared = frame->function()->shared(); stack.push_back(shared); frames_captured++; } else { @@ -199,25 +198,25 @@ SamplingHeapProfiler::AllocationNode* SamplingHeapProfiler::AddStack() { name = "(JS)"; break; } - return node->FindOrAddChildNode(name, v8::UnboundScript::kNoScriptId, 0); + return FindOrAddChildNode(node, name, v8::UnboundScript::kNoScriptId, 0); } // We need to process the stack in reverse order as the top of the stack is // the first element in the list. for (auto it = stack.rbegin(); it != stack.rend(); ++it) { - SharedFunctionInfo* shared = *it; + SharedFunctionInfo shared = *it; const char* name = this->names()->GetName(shared->DebugName()); int script_id = v8::UnboundScript::kNoScriptId; if (shared->script()->IsScript()) { - Script* script = Script::cast(shared->script()); + Script script = Script::cast(shared->script()); script_id = script->id(); } - node = node->FindOrAddChildNode(name, script_id, shared->StartPosition()); + node = FindOrAddChildNode(node, name, script_id, shared->StartPosition()); } if (found_arguments_marker_frames) { node = - node->FindOrAddChildNode("(deopt)", v8::UnboundScript::kNoScriptId, 0); + FindOrAddChildNode(node, "(deopt)", v8::UnboundScript::kNoScriptId, 0); } return node; @@ -243,7 +242,7 @@ v8::AllocationProfile::Node* SamplingHeapProfiler::TranslateAllocationNode( Handle<Script> script = non_const_scripts[node->script_id_]; if (!script.is_null()) { if (script->name()->IsName()) { - Name* name = Name::cast(script->name()); + Name name = Name::cast(script->name()); script_name = ToApiHandle<v8::String>( isolate_->factory()->InternalizeUtf8String(names_->GetName(name))); } @@ -255,12 +254,12 @@ v8::AllocationProfile::Node* SamplingHeapProfiler::TranslateAllocationNode( allocations.push_back(ScaleSample(alloc.first, alloc.second)); } - profile->nodes().push_back(v8::AllocationProfile::Node{ + profile->nodes_.push_back(v8::AllocationProfile::Node{ ToApiHandle<v8::String>( isolate_->factory()->InternalizeUtf8String(node->name_)), script_name, node->script_id_, node->script_position_, line, column, - std::vector<v8::AllocationProfile::Node*>(), allocations}); - v8::AllocationProfile::Node* current = &profile->nodes().back(); + node->id_, std::vector<v8::AllocationProfile::Node*>(), allocations}); + v8::AllocationProfile::Node* current = &profile->nodes_.back(); // The |children_| map may have nodes inserted into it during translation // because the translation may allocate strings on the JS heap that have // the potential to be sampled. That's ok since map iterators are not @@ -283,14 +282,30 @@ v8::AllocationProfile* SamplingHeapProfiler::GetAllocationProfile() { std::map<int, Handle<Script>> scripts; { Script::Iterator iterator(isolate_); - while (Script* script = iterator.Next()) { + for (Script script = iterator.Next(); !script.is_null(); + script = iterator.Next()) { scripts[script->id()] = handle(script, isolate_); } } auto profile = new v8::internal::AllocationProfile(); TranslateAllocationNode(profile, &profile_root_, scripts); + profile->samples_ = SamplingHeapProfiler::BuildSamples(); + return profile; } +const std::vector<v8::AllocationProfile::Sample> +SamplingHeapProfiler::BuildSamples() const { + std::vector<v8::AllocationProfile::Sample> samples; + samples.reserve(samples_.size()); + for (const auto& it : samples_) { + const Sample* sample = it.second.get(); + samples.emplace_back(v8::AllocationProfile::Sample{ + sample->owner->id_, sample->size, ScaleSample(sample->size, 1).count, + sample->sample_id}); + } + return samples; +} + } // namespace internal } // namespace v8 diff --git a/deps/v8/src/profiler/sampling-heap-profiler.h b/deps/v8/src/profiler/sampling-heap-profiler.h index 072c5eb677..818c33581d 100644 --- a/deps/v8/src/profiler/sampling-heap-profiler.h +++ b/deps/v8/src/profiler/sampling-heap-profiler.h @@ -25,62 +25,48 @@ class SamplingAllocationObserver; class AllocationProfile : public v8::AllocationProfile { public: - AllocationProfile() : nodes_() {} + AllocationProfile() = default; v8::AllocationProfile::Node* GetRootNode() override { return nodes_.size() == 0 ? nullptr : &nodes_.front(); } - std::deque<v8::AllocationProfile::Node>& nodes() { return nodes_; } + const std::vector<v8::AllocationProfile::Sample>& GetSamples() override { + return samples_; + } private: std::deque<v8::AllocationProfile::Node> nodes_; + std::vector<v8::AllocationProfile::Sample> samples_; + + friend class SamplingHeapProfiler; DISALLOW_COPY_AND_ASSIGN(AllocationProfile); }; class SamplingHeapProfiler { public: - SamplingHeapProfiler(Heap* heap, StringsStorage* names, uint64_t rate, - int stack_depth, v8::HeapProfiler::SamplingFlags flags); - ~SamplingHeapProfiler(); - - v8::AllocationProfile* GetAllocationProfile(); - - StringsStorage* names() const { return names_; } - - class AllocationNode; - - struct Sample { - public: - Sample(size_t size_, AllocationNode* owner_, Local<Value> local_, - SamplingHeapProfiler* profiler_) - : size(size_), - owner(owner_), - global(Global<Value>( - reinterpret_cast<v8::Isolate*>(profiler_->isolate_), local_)), - profiler(profiler_) {} - ~Sample() { global.Reset(); } - const size_t size; - AllocationNode* const owner; - Global<Value> global; - SamplingHeapProfiler* const profiler; - - private: - DISALLOW_COPY_AND_ASSIGN(Sample); - }; - class AllocationNode { public: + typedef uint64_t FunctionId; AllocationNode(AllocationNode* parent, const char* name, int script_id, - int start_position) + int start_position, uint32_t id) : parent_(parent), script_id_(script_id), script_position_(start_position), - name_(name) {} + name_(name), + id_(id) {} + + AllocationNode* FindChildNode(FunctionId id) { + auto it = children_.find(id); + return it != children_.end() ? it->second.get() : nullptr; + } + + AllocationNode* AddChildNode(FunctionId id, + std::unique_ptr<AllocationNode> node) { + return children_.emplace(id, std::move(node)).first->second.get(); + } - private: - typedef uint64_t FunctionId; static FunctionId function_id(int script_id, int start_position, const char* name) { // script_id == kNoScriptId case: @@ -96,8 +82,8 @@ class SamplingHeapProfiler { DCHECK(static_cast<unsigned>(start_position) < (1u << 31)); return (static_cast<uint64_t>(script_id) << 32) + (start_position << 1); } - AllocationNode* FindOrAddChildNode(const char* name, int script_id, - int start_position); + + private: // TODO(alph): make use of unordered_map's here. Pay attention to // iterator invalidation during TranslateAllocationNode. std::map<size_t, unsigned int> allocations_; @@ -106,6 +92,7 @@ class SamplingHeapProfiler { const int script_id_; const int script_position_; const char* const name_; + uint32_t id_; bool pinned_ = false; friend class SamplingHeapProfiler; @@ -113,13 +100,45 @@ class SamplingHeapProfiler { DISALLOW_COPY_AND_ASSIGN(AllocationNode); }; - private: - Heap* heap() const { return heap_; } + struct Sample { + Sample(size_t size_, AllocationNode* owner_, Local<Value> local_, + SamplingHeapProfiler* profiler_, uint64_t sample_id) + : size(size_), + owner(owner_), + global(Global<Value>( + reinterpret_cast<v8::Isolate*>(profiler_->isolate_), local_)), + profiler(profiler_), + sample_id(sample_id) {} + ~Sample() { global.Reset(); } + const size_t size; + AllocationNode* const owner; + Global<Value> global; + SamplingHeapProfiler* const profiler; + const uint64_t sample_id; + + private: + DISALLOW_COPY_AND_ASSIGN(Sample); + }; + SamplingHeapProfiler(Heap* heap, StringsStorage* names, uint64_t rate, + int stack_depth, v8::HeapProfiler::SamplingFlags flags); + ~SamplingHeapProfiler(); + + v8::AllocationProfile* GetAllocationProfile(); + StringsStorage* names() const { return names_; } + + private: void SampleObject(Address soon_object, size_t size); + const std::vector<v8::AllocationProfile::Sample> BuildSamples() const; + + AllocationNode* FindOrAddChildNode(AllocationNode* parent, const char* name, + int script_id, int start_position); static void OnWeakCallback(const WeakCallbackInfo<Sample>& data); + uint32_t next_node_id() { return ++last_node_id_; } + uint64_t next_sample_id() { return ++last_sample_id_; } + // Methods that construct v8::AllocationProfile. // Translates the provided AllocationNode *node* returning an equivalent @@ -131,11 +150,13 @@ class SamplingHeapProfiler { AllocationProfile* profile, SamplingHeapProfiler::AllocationNode* node, const std::map<int, Handle<Script>>& scripts); v8::AllocationProfile::Allocation ScaleSample(size_t size, - unsigned int count); + unsigned int count) const; AllocationNode* AddStack(); Isolate* const isolate_; Heap* const heap_; + uint64_t last_sample_id_ = 0; + uint32_t last_node_id_ = 0; std::unique_ptr<SamplingAllocationObserver> new_space_observer_; std::unique_ptr<SamplingAllocationObserver> other_spaces_observer_; StringsStorage* const names_; diff --git a/deps/v8/src/profiler/strings-storage.cc b/deps/v8/src/profiler/strings-storage.cc index 9a5a006ff4..04a2379707 100644 --- a/deps/v8/src/profiler/strings-storage.cc +++ b/deps/v8/src/profiler/strings-storage.cc @@ -69,9 +69,9 @@ const char* StringsStorage::GetVFormatted(const char* format, va_list args) { return AddOrDisposeString(str.start(), len); } -const char* StringsStorage::GetName(Name* name) { +const char* StringsStorage::GetName(Name name) { if (name->IsString()) { - String* str = String::cast(name); + String str = String::cast(name); int length = Min(FLAG_heap_snapshot_string_limit, str->length()); int actual_length = 0; std::unique_ptr<char[]> data = str->ToCString( @@ -87,9 +87,9 @@ const char* StringsStorage::GetName(int index) { return GetFormatted("%d", index); } -const char* StringsStorage::GetConsName(const char* prefix, Name* name) { +const char* StringsStorage::GetConsName(const char* prefix, Name name) { if (name->IsString()) { - String* str = String::cast(name); + String str = String::cast(name); int length = Min(FLAG_heap_snapshot_string_limit, str->length()); int actual_length = 0; std::unique_ptr<char[]> data = str->ToCString( diff --git a/deps/v8/src/profiler/strings-storage.h b/deps/v8/src/profiler/strings-storage.h index 5c0f8afd93..9b56a6e412 100644 --- a/deps/v8/src/profiler/strings-storage.h +++ b/deps/v8/src/profiler/strings-storage.h @@ -29,12 +29,12 @@ class V8_EXPORT_PRIVATE StringsStorage { // Returns a formatted string, de-duplicated via the storage. PRINTF_FORMAT(2, 3) const char* GetFormatted(const char* format, ...); // Returns a stored string resulting from name, or "<symbol>" for a symbol. - const char* GetName(Name* name); + const char* GetName(Name name); // Returns the string representation of the int from the store. const char* GetName(int index); // Appends string resulting from name to prefix, then returns the stored // result. - const char* GetConsName(const char* prefix, Name* name); + const char* GetConsName(const char* prefix, Name name); private: static bool StringsMatch(void* key1, void* key2); diff --git a/deps/v8/src/profiler/tick-sample.cc b/deps/v8/src/profiler/tick-sample.cc index 69a6bbf778..501dbd63a8 100644 --- a/deps/v8/src/profiler/tick-sample.cc +++ b/deps/v8/src/profiler/tick-sample.cc @@ -255,17 +255,16 @@ bool TickSample::GetStackSample(Isolate* v8_isolate, RegisterState* regs, // bytecode_array might be garbage, so don't actually dereference it. We // avoid the frame->GetXXX functions since they call BytecodeArray::cast, // which has a heap access in its DCHECK. - i::Object* bytecode_array = i::Memory<i::Object*>( + i::Address bytecode_array = i::Memory<i::Address>( frame->fp() + i::InterpreterFrameConstants::kBytecodeArrayFromFp); - i::Object* bytecode_offset = i::Memory<i::Object*>( + i::Address bytecode_offset = i::Memory<i::Address>( frame->fp() + i::InterpreterFrameConstants::kBytecodeOffsetFromFp); // If the bytecode array is a heap object and the bytecode offset is a // Smi, use those, otherwise fall back to using the frame's pc. if (HAS_HEAP_OBJECT_TAG(bytecode_array) && HAS_SMI_TAG(bytecode_offset)) { frames[i++] = reinterpret_cast<void*>( - reinterpret_cast<i::Address>(bytecode_array) + - i::Internals::SmiValue(bytecode_offset)); + bytecode_array + i::Internals::SmiValue(bytecode_offset)); continue; } } @@ -287,5 +286,20 @@ void TickSample::Init(Isolate* isolate, const v8::RegisterState& state, timestamp = base::TimeTicks::HighResolutionNow(); } +void TickSample::print() const { + PrintF("TickSample: at %p\n", this); + PrintF(" - state: %s\n", StateToString(state)); + PrintF(" - pc: %p\n", pc); + PrintF(" - stack: (%u frames)\n", frames_count); + for (unsigned i = 0; i < frames_count; i++) { + PrintF(" %p\n", stack[i]); + } + PrintF(" - has_external_callback: %d\n", has_external_callback); + PrintF(" - %s: %p\n", + has_external_callback ? "external_callback_entry" : "tos", tos); + PrintF(" - update_stats: %d\n", update_stats); + PrintF("\n"); +} + } // namespace internal } // namespace v8 diff --git a/deps/v8/src/profiler/tick-sample.h b/deps/v8/src/profiler/tick-sample.h index 819b862388..ea66010632 100644 --- a/deps/v8/src/profiler/tick-sample.h +++ b/deps/v8/src/profiler/tick-sample.h @@ -19,6 +19,8 @@ struct TickSample : public v8::TickSample { RecordCEntryFrame record_c_entry_frame, bool update_stats, bool use_simulator_reg_state = true); base::TimeTicks timestamp; + + void print() const; }; } // namespace internal diff --git a/deps/v8/src/profiler/tracing-cpu-profiler.cc b/deps/v8/src/profiler/tracing-cpu-profiler.cc index 875478139d..0cb502bdf1 100644 --- a/deps/v8/src/profiler/tracing-cpu-profiler.cc +++ b/deps/v8/src/profiler/tracing-cpu-profiler.cc @@ -13,10 +13,6 @@ namespace internal { TracingCpuProfilerImpl::TracingCpuProfilerImpl(Isolate* isolate) : isolate_(isolate), profiling_enabled_(false) { - // Make sure tracing system notices profiler categories. - TRACE_EVENT_WARMUP_CATEGORY(TRACE_DISABLED_BY_DEFAULT("v8.cpu_profiler")); - TRACE_EVENT_WARMUP_CATEGORY( - TRACE_DISABLED_BY_DEFAULT("v8.cpu_profiler.hires")); V8::GetCurrentPlatform()->GetTracingController()->AddTraceStateObserver(this); } @@ -40,7 +36,7 @@ void TracingCpuProfilerImpl::OnTraceEnabled() { } void TracingCpuProfilerImpl::OnTraceDisabled() { - base::LockGuard<base::Mutex> lock(&mutex_); + base::MutexGuard lock(&mutex_); if (!profiling_enabled_) return; profiling_enabled_ = false; isolate_->RequestInterrupt( @@ -51,7 +47,7 @@ void TracingCpuProfilerImpl::OnTraceDisabled() { } void TracingCpuProfilerImpl::StartProfiling() { - base::LockGuard<base::Mutex> lock(&mutex_); + base::MutexGuard lock(&mutex_); if (!profiling_enabled_ || profiler_) return; bool enabled; TRACE_EVENT_CATEGORY_GROUP_ENABLED( @@ -64,7 +60,7 @@ void TracingCpuProfilerImpl::StartProfiling() { } void TracingCpuProfilerImpl::StopProfiling() { - base::LockGuard<base::Mutex> lock(&mutex_); + base::MutexGuard lock(&mutex_); if (!profiler_) return; profiler_->StopProfiling(""); profiler_.reset(); |