diff options
Diffstat (limited to 'chromium/v8/src/profiler/heap-snapshot-generator.cc')
-rw-r--r-- | chromium/v8/src/profiler/heap-snapshot-generator.cc | 148 |
1 files changed, 115 insertions, 33 deletions
diff --git a/chromium/v8/src/profiler/heap-snapshot-generator.cc b/chromium/v8/src/profiler/heap-snapshot-generator.cc index 9cc26fa3e20..da4e57fad9a 100644 --- a/chromium/v8/src/profiler/heap-snapshot-generator.cc +++ b/chromium/v8/src/profiler/heap-snapshot-generator.cc @@ -183,9 +183,11 @@ const char* HeapEntry::TypeAsString() const { } } -HeapSnapshot::HeapSnapshot(HeapProfiler* profiler, bool global_objects_as_roots) +HeapSnapshot::HeapSnapshot(HeapProfiler* profiler, bool global_objects_as_roots, + bool capture_numeric_value) : profiler_(profiler), - treat_global_objects_as_roots_(global_objects_as_roots) { + treat_global_objects_as_roots_(global_objects_as_roots), + capture_numeric_value_(capture_numeric_value) { // It is very important to keep objects that form a heap snapshot // as small as possible. Check assumptions about data structure sizes. STATIC_ASSERT(kSystemPointerSize != 4 || sizeof(HeapGraphEdge) == 12); @@ -387,8 +389,7 @@ SnapshotObjectId HeapObjectsMap::FindOrAddEntry(Address addr, return entry_info.id; } entry->value = reinterpret_cast<void*>(entries_.size()); - SnapshotObjectId id = next_id_; - next_id_ += kObjectIdStep; + SnapshotObjectId id = get_next_id(); entries_.push_back(EntryInfo(id, addr, size, accessed)); DCHECK(static_cast<uint32_t>(entries_.size()) > entries_map_.occupancy()); return id; @@ -553,6 +554,16 @@ HeapEntry* V8HeapExplorer::AllocateEntry(HeapThing ptr) { return AddEntry(HeapObject::cast(Object(reinterpret_cast<Address>(ptr)))); } +HeapEntry* V8HeapExplorer::AllocateEntry(Smi smi) { + SnapshotObjectId id = heap_object_map_->get_next_id(); + HeapEntry* entry = + snapshot_->AddEntry(HeapEntry::kHeapNumber, "smi number", id, 0, 0); + // XXX: Smis do not appear in CombinedHeapObjectIterator, so we need to + // extract the references here + ExtractNumberReference(entry, smi); + return entry; +} + void V8HeapExplorer::ExtractLocation(HeapEntry* entry, HeapObject object) { if (object.IsJSFunction()) { JSFunction func = JSFunction::cast(object); @@ -638,7 +649,7 @@ HeapEntry* V8HeapExplorer::AddEntry(HeapObject object) { object.IsByteArray()) { return AddEntry(object, HeapEntry::kArray, ""); } else if (object.IsHeapNumber()) { - return AddEntry(object, HeapEntry::kHeapNumber, "number"); + return AddEntry(object, HeapEntry::kHeapNumber, "heap number"); } return AddEntry(object, HeapEntry::kHidden, GetSystemEntryName(object)); } @@ -721,6 +732,13 @@ class IndexedReferencesExtractor : public ObjectVisitor { ObjectSlot end) override { VisitPointers(host, MaybeObjectSlot(start), MaybeObjectSlot(end)); } + void VisitMapPointer(HeapObject object) override { + if (generator_->visited_fields_[0]) { + generator_->visited_fields_[0] = false; + } else { + VisitHeapObjectImpl(object.map(), 0); + } + } void VisitPointers(HeapObject host, MaybeObjectSlot start, MaybeObjectSlot end) override { // [start,end) must be a sub-region of [parent_start_, parent_end), i.e. @@ -830,6 +848,10 @@ void V8HeapExplorer::ExtractReferences(HeapEntry* entry, HeapObject obj) { ExtractEphemeronHashTableReferences(entry, EphemeronHashTable::cast(obj)); } else if (obj.IsFixedArray()) { ExtractFixedArrayReferences(entry, FixedArray::cast(obj)); + } else if (obj.IsHeapNumber()) { + if (snapshot_->capture_numeric_value()) { + ExtractNumberReference(entry, obj); + } } } @@ -867,7 +889,7 @@ void V8HeapExplorer::ExtractJSObjectReferences(HeapEntry* entry, } else if (obj.IsJSFunction()) { 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(kAcquireLoad); if (!proto_or_map.IsTheHole(isolate)) { if (!proto_or_map.IsMap()) { SetPropertyReference(entry, roots.prototype_string(), proto_or_map, @@ -1246,6 +1268,11 @@ class JSArrayBufferDataEntryAllocator : public HeapEntriesAllocator { HeapEntry::kNative, "system / JSArrayBufferData", size_); } + HeapEntry* AllocateEntry(Smi smi) override { + DCHECK(false); + return nullptr; + } + private: size_t size_; V8HeapExplorer* explorer_; @@ -1291,6 +1318,30 @@ void V8HeapExplorer::ExtractFixedArrayReferences(HeapEntry* entry, } } +void V8HeapExplorer::ExtractNumberReference(HeapEntry* entry, Object number) { + DCHECK(number.IsNumber()); + + // Must be large enough to fit any double, int, or size_t. + char arr[32]; + Vector<char> buffer(arr, arraysize(arr)); + + const char* string; + if (number.IsSmi()) { + int int_value = Smi::ToInt(number); + string = IntToCString(int_value, buffer); + } else { + double double_value = HeapNumber::cast(number).value(); + string = DoubleToCString(double_value, buffer); + } + + const char* name = names_->GetCopy(string); + + SnapshotObjectId id = heap_object_map_->get_next_id(); + HeapEntry* child_entry = + snapshot_->AddEntry(HeapEntry::kString, name, id, 0, 0); + entry->SetNamedReference(HeapGraphEdge::kInternal, "value", child_entry); +} + void V8HeapExplorer::ExtractFeedbackVectorReferences( HeapEntry* entry, FeedbackVector feedback_vector) { MaybeObject code = feedback_vector.maybe_optimized_code(); @@ -1345,8 +1396,10 @@ void V8HeapExplorer::ExtractPropertyReferences(JSObject js_obj, PropertyDetails details = descs.GetDetails(i); switch (details.location()) { case kField: { - Representation r = details.representation(); - if (r.IsSmi() || r.IsDouble()) break; + if (!snapshot_->capture_numeric_value()) { + Representation r = details.representation(); + if (r.IsSmi() || r.IsDouble()) break; + } Name k = descs.GetKey(i); FieldIndex field_index = FieldIndex::ForDescriptor(js_obj.map(), i); @@ -1476,9 +1529,15 @@ String V8HeapExplorer::GetConstructorName(JSObject object) { } HeapEntry* V8HeapExplorer::GetEntry(Object obj) { - return obj.IsHeapObject() ? generator_->FindOrAddEntry( - reinterpret_cast<void*>(obj.ptr()), this) - : nullptr; + if (obj.IsHeapObject()) { + return generator_->FindOrAddEntry(reinterpret_cast<void*>(obj.ptr()), this); + } + + DCHECK(obj.IsSmi()); + if (!snapshot_->capture_numeric_value()) { + return nullptr; + } + return generator_->FindOrAddEntry(Smi::cast(obj), this); } class RootsReferencesExtractor : public RootVisitor { @@ -1500,6 +1559,7 @@ class RootsReferencesExtractor : public RootVisitor { void VisitRootPointers(Root root, const char* description, FullObjectSlot start, FullObjectSlot end) override { for (FullObjectSlot p = start; p < end; ++p) { + DCHECK(!MapWord::IsPacked(p.Relaxed_Load().ptr())); VisitRootPointer(root, description, p); } } @@ -1649,23 +1709,25 @@ void V8HeapExplorer::SetElementReference(HeapEntry* parent_entry, int index, void V8HeapExplorer::SetInternalReference(HeapEntry* parent_entry, const char* reference_name, Object child_obj, int field_offset) { - HeapEntry* child_entry = GetEntry(child_obj); - if (child_entry == nullptr) return; - if (IsEssentialObject(child_obj)) { - parent_entry->SetNamedReference(HeapGraphEdge::kInternal, reference_name, - child_entry); + if (!IsEssentialObject(child_obj)) { + return; } + HeapEntry* child_entry = GetEntry(child_obj); + DCHECK_NOT_NULL(child_entry); + parent_entry->SetNamedReference(HeapGraphEdge::kInternal, reference_name, + child_entry); MarkVisitedField(field_offset); } void V8HeapExplorer::SetInternalReference(HeapEntry* parent_entry, int index, Object child_obj, int field_offset) { - HeapEntry* child_entry = GetEntry(child_obj); - if (child_entry == nullptr) return; - if (IsEssentialObject(child_obj)) { - parent_entry->SetNamedReference(HeapGraphEdge::kInternal, - names_->GetName(index), child_entry); + if (!IsEssentialObject(child_obj)) { + return; } + HeapEntry* child_entry = GetEntry(child_obj); + DCHECK_NOT_NULL(child_entry); + parent_entry->SetNamedReference(HeapGraphEdge::kInternal, + names_->GetName(index), child_entry); MarkVisitedField(field_offset); } @@ -1673,9 +1735,13 @@ void V8HeapExplorer::SetHiddenReference(HeapObject parent_obj, HeapEntry* parent_entry, int index, Object child_obj, int field_offset) { DCHECK_EQ(parent_entry, GetEntry(parent_obj)); + DCHECK(!MapWord::IsPacked(child_obj.ptr())); + if (!IsEssentialObject(child_obj)) { + return; + } HeapEntry* child_entry = GetEntry(child_obj); - if (child_entry != nullptr && IsEssentialObject(child_obj) && - IsEssentialHiddenReference(parent_obj, field_offset)) { + DCHECK_NOT_NULL(child_entry); + if (IsEssentialHiddenReference(parent_obj, field_offset)) { parent_entry->SetIndexedReference(HeapGraphEdge::kHidden, index, child_entry); } @@ -1684,23 +1750,25 @@ void V8HeapExplorer::SetHiddenReference(HeapObject parent_obj, void V8HeapExplorer::SetWeakReference(HeapEntry* parent_entry, const char* reference_name, Object child_obj, int field_offset) { - HeapEntry* child_entry = GetEntry(child_obj); - if (child_entry == nullptr) return; - if (IsEssentialObject(child_obj)) { - parent_entry->SetNamedReference(HeapGraphEdge::kWeak, reference_name, - child_entry); + if (!IsEssentialObject(child_obj)) { + return; } + HeapEntry* child_entry = GetEntry(child_obj); + DCHECK_NOT_NULL(child_entry); + parent_entry->SetNamedReference(HeapGraphEdge::kWeak, reference_name, + child_entry); MarkVisitedField(field_offset); } void V8HeapExplorer::SetWeakReference(HeapEntry* parent_entry, int index, Object child_obj, int field_offset) { - HeapEntry* child_entry = GetEntry(child_obj); - if (child_entry == nullptr) return; - if (IsEssentialObject(child_obj)) { - parent_entry->SetNamedReference( - HeapGraphEdge::kWeak, names_->GetFormatted("%d", index), child_entry); + if (!IsEssentialObject(child_obj)) { + return; } + HeapEntry* child_entry = GetEntry(child_obj); + DCHECK_NOT_NULL(child_entry); + parent_entry->SetNamedReference( + HeapGraphEdge::kWeak, names_->GetFormatted("%d", index), child_entry); MarkVisitedField(field_offset); } @@ -1758,6 +1826,13 @@ void V8HeapExplorer::SetGcRootsReference(Root root) { void V8HeapExplorer::SetGcSubrootReference(Root root, const char* description, bool is_weak, Object child_obj) { + if (child_obj.IsSmi()) { + // TODO(arenevier): if we handle smis here, the snapshot gets 2 to 3 times + // slower on large heaps. According to perf, The bulk of the extra works + // happens in TemplateHashMapImpl::Probe method, when tyring to get + // names->GetFormatted("%d / %s", index, description) + return; + } HeapEntry* child_entry = GetEntry(child_obj); if (child_entry == nullptr) return; const char* name = GetStrongGcSubrootName(child_obj); @@ -1834,6 +1909,7 @@ class GlobalObjectsEnumerator : public RootVisitor { void VisitRootPointersImpl(Root root, const char* description, TSlot start, TSlot end) { for (TSlot p = start; p < end; ++p) { + DCHECK(!MapWord::IsPacked(p.Relaxed_Load(isolate_).ptr())); Object o = p.load(isolate_); if (!o.IsNativeContext(isolate_)) continue; JSObject proxy = Context::cast(o).global_proxy(); @@ -1934,6 +2010,7 @@ class EmbedderGraphEntriesAllocator : public HeapEntriesAllocator { names_(snapshot_->profiler()->names()), heap_object_map_(snapshot_->profiler()->heap_object_map()) {} HeapEntry* AllocateEntry(HeapThing ptr) override; + HeapEntry* AllocateEntry(Smi smi) override; private: HeapSnapshot* snapshot_; @@ -1984,6 +2061,11 @@ HeapEntry* EmbedderGraphEntriesAllocator::AllocateEntry(HeapThing ptr) { return heap_entry; } +HeapEntry* EmbedderGraphEntriesAllocator::AllocateEntry(Smi smi) { + DCHECK(false); + return nullptr; +} + NativeObjectsExplorer::NativeObjectsExplorer( HeapSnapshot* snapshot, SnapshottingProgressReportingInterface* progress) : isolate_( |