summaryrefslogtreecommitdiff
path: root/deps/v8/src/profiler
diff options
context:
space:
mode:
authorMichaël Zasso <targos@protonmail.com>2019-03-12 09:01:49 +0100
committerMichaël Zasso <targos@protonmail.com>2019-03-14 18:49:21 +0100
commit7b48713334469818661fe276cf571de9c7899f2d (patch)
tree4dbda49ac88db76ce09dc330a0cb587e68e139ba /deps/v8/src/profiler
parent8549ac09b256666cf5275224ec58fab9939ff32e (diff)
downloadandroid-node-v8-7b48713334469818661fe276cf571de9c7899f2d.tar.gz
android-node-v8-7b48713334469818661fe276cf571de9c7899f2d.tar.bz2
android-node-v8-7b48713334469818661fe276cf571de9c7899f2d.zip
deps: update V8 to 7.3.492.25
PR-URL: https://github.com/nodejs/node/pull/25852 Reviewed-By: Ujjwal Sharma <usharma1998@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Ali Ijaz Sheikh <ofrobots@google.com>
Diffstat (limited to 'deps/v8/src/profiler')
-rw-r--r--deps/v8/src/profiler/allocation-tracker.cc28
-rw-r--r--deps/v8/src/profiler/allocation-tracker.h4
-rw-r--r--deps/v8/src/profiler/circular-queue.h6
-rw-r--r--deps/v8/src/profiler/cpu-profiler-inl.h6
-rw-r--r--deps/v8/src/profiler/cpu-profiler.cc147
-rw-r--r--deps/v8/src/profiler/cpu-profiler.h89
-rw-r--r--deps/v8/src/profiler/heap-profiler.cc20
-rw-r--r--deps/v8/src/profiler/heap-profiler.h2
-rw-r--r--deps/v8/src/profiler/heap-snapshot-generator.cc485
-rw-r--r--deps/v8/src/profiler/heap-snapshot-generator.h152
-rw-r--r--deps/v8/src/profiler/profile-generator.cc148
-rw-r--r--deps/v8/src/profiler/profile-generator.h56
-rw-r--r--deps/v8/src/profiler/profiler-listener.cc188
-rw-r--r--deps/v8/src/profiler/profiler-listener.h37
-rw-r--r--deps/v8/src/profiler/sampling-heap-profiler.cc85
-rw-r--r--deps/v8/src/profiler/sampling-heap-profiler.h101
-rw-r--r--deps/v8/src/profiler/strings-storage.cc8
-rw-r--r--deps/v8/src/profiler/strings-storage.h4
-rw-r--r--deps/v8/src/profiler/tick-sample.cc22
-rw-r--r--deps/v8/src/profiler/tick-sample.h2
-rw-r--r--deps/v8/src/profiler/tracing-cpu-profiler.cc10
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();