Index: src/profile-generator.cc |
diff --git a/src/profile-generator.cc b/src/profile-generator.cc |
index 7612eab993ca123ab3bbe4a32022087f03050205..4997690836af1e92dd9c729a2e453199c8f7016f 100644 |
--- a/src/profile-generator.cc |
+++ b/src/profile-generator.cc |
@@ -29,6 +29,7 @@ |
#include "v8.h" |
#include "global-handles.h" |
+#include "heap-profiler.h" |
#include "scopeinfo.h" |
#include "top.h" |
#include "unicode.h" |
@@ -94,51 +95,70 @@ StringsStorage::StringsStorage() |
} |
-static void DeleteIndexName(char** name_ptr) { |
- DeleteArray(*name_ptr); |
-} |
- |
- |
StringsStorage::~StringsStorage() { |
for (HashMap::Entry* p = names_.Start(); |
p != NULL; |
p = names_.Next(p)) { |
DeleteArray(reinterpret_cast<const char*>(p->value)); |
} |
- index_names_.Iterate(DeleteIndexName); |
+} |
+ |
+ |
+const char* StringsStorage::GetCopy(const char* src) { |
+ int len = strlen(src); |
+ Vector<char> dst = Vector<char>::New(len + 1); |
+ OS::StrNCpy(dst, src, len); |
+ dst[len] = '\0'; |
+ uint32_t hash = HashSequentialString(dst.start(), len); |
+ return AddOrDisposeString(dst.start(), hash); |
+} |
+ |
+ |
+const char* StringsStorage::GetFormatted(const char* format, ...) { |
+ va_list args; |
+ va_start(args, format); |
+ const char* result = GetVFormatted(format, args); |
+ va_end(args); |
+ return result; |
+} |
+ |
+ |
+const char* StringsStorage::AddOrDisposeString(char* str, uint32_t hash) { |
+ HashMap::Entry* cache_entry = names_.Lookup(str, hash, true); |
+ if (cache_entry->value == NULL) { |
+ // New entry added. |
+ cache_entry->value = str; |
+ } else { |
+ DeleteArray(str); |
+ } |
+ return reinterpret_cast<const char*>(cache_entry->value); |
+} |
+ |
+ |
+const char* StringsStorage::GetVFormatted(const char* format, va_list args) { |
+ Vector<char> str = Vector<char>::New(1024); |
+ int len = OS::VSNPrintF(str, format, args); |
+ if (len == -1) { |
+ DeleteArray(str.start()); |
+ return format; |
+ } |
+ uint32_t hash = HashSequentialString(str.start(), len); |
+ return AddOrDisposeString(str.start(), hash); |
} |
const char* StringsStorage::GetName(String* name) { |
if (name->IsString()) { |
- char* c_name = |
- name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL).Detach(); |
- HashMap::Entry* cache_entry = names_.Lookup(c_name, name->Hash(), true); |
- if (cache_entry->value == NULL) { |
- // New entry added. |
- cache_entry->value = c_name; |
- } else { |
- DeleteArray(c_name); |
- } |
- return reinterpret_cast<const char*>(cache_entry->value); |
+ return AddOrDisposeString( |
+ name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL).Detach(), |
+ name->Hash()); |
} |
return ""; |
} |
const char* StringsStorage::GetName(int index) { |
- ASSERT(index >= 0); |
- if (index_names_.length() <= index) { |
- index_names_.AddBlock( |
- NULL, index - index_names_.length() + 1); |
- } |
- if (index_names_[index] == NULL) { |
- const int kMaximumNameLength = 32; |
- char* name = NewArray<char>(kMaximumNameLength); |
- OS::SNPrintF(Vector<char>(name, kMaximumNameLength), "%d", index); |
- index_names_[index] = name; |
- } |
- return index_names_[index]; |
+ return GetFormatted("%d", index); |
} |
@@ -1009,6 +1029,7 @@ const char* HeapEntry::TypeAsString() { |
case kArray: return "/array/"; |
case kRegExp: return "/regexp/"; |
case kHeapNumber: return "/number/"; |
+ case kNative: return "/native/"; |
default: return "???"; |
} |
} |
@@ -1205,6 +1226,7 @@ HeapSnapshot::HeapSnapshot(HeapSnapshotsCollection* collection, |
uid_(uid), |
root_entry_(NULL), |
gc_roots_entry_(NULL), |
+ dom_subtrees_root_entry_(NULL), |
raw_entries_(NULL), |
entries_sorted_(false), |
retaining_paths_(HeapEntry::Match) { |
@@ -1279,6 +1301,19 @@ HeapEntry* HeapSnapshot::AddGcRootsEntry(int children_count, |
} |
+HeapEntry* HeapSnapshot::AddNativesRootEntry(int children_count, |
+ int retainers_count) { |
+ ASSERT(dom_subtrees_root_entry_ == NULL); |
+ return (dom_subtrees_root_entry_ = AddEntry( |
+ HeapEntry::kObject, |
+ "(Native objects)", |
+ HeapObjectsMap::kNativesRootObjectId, |
+ 0, |
+ children_count, |
+ retainers_count)); |
+} |
+ |
+ |
HeapEntry* HeapSnapshot::AddEntry(HeapEntry::Type type, |
const char* name, |
uint64_t id, |
@@ -1372,10 +1407,13 @@ void HeapSnapshot::Print(int max_depth) { |
} |
-const uint64_t HeapObjectsMap::kInternalRootObjectId = 0; |
-const uint64_t HeapObjectsMap::kGcRootsObjectId = 1; |
+// We split IDs on evens for embedder objects (see |
+// HeapObjectsMap::GenerateId) and odds for native objects. |
+const uint64_t HeapObjectsMap::kInternalRootObjectId = 1; |
+const uint64_t HeapObjectsMap::kGcRootsObjectId = 3; |
+const uint64_t HeapObjectsMap::kNativesRootObjectId = 5; |
// Increase kFirstAvailableObjectId if new 'special' objects appear. |
-const uint64_t HeapObjectsMap::kFirstAvailableObjectId = 2; |
+const uint64_t HeapObjectsMap::kFirstAvailableObjectId = 7; |
HeapObjectsMap::HeapObjectsMap() |
: initial_fill_mode_(true), |
@@ -1400,7 +1438,8 @@ uint64_t HeapObjectsMap::FindObject(Address addr) { |
uint64_t existing = FindEntry(addr); |
if (existing != 0) return existing; |
} |
- uint64_t id = next_id_++; |
+ uint64_t id = next_id_; |
+ next_id_ += 2; |
AddEntry(addr, id); |
return id; |
} |
@@ -1468,6 +1507,17 @@ void HeapObjectsMap::RemoveDeadEntries() { |
} |
+uint64_t HeapObjectsMap::GenerateId(v8::RetainedObjectInfo* info) { |
+ uint64_t id = static_cast<uint64_t>(info->GetHash()); |
+ const char* label = info->GetLabel(); |
+ id ^= HashSequentialString(label, strlen(label)); |
+ intptr_t element_count = info->GetElementCount(); |
+ if (element_count != -1) |
+ id ^= ComputeIntegerHash(static_cast<uint32_t>(element_count)); |
+ return id << 1; |
+} |
+ |
+ |
HeapSnapshotsCollection::HeapSnapshotsCollection() |
: is_tracking_objects_(false), |
snapshots_uids_(HeapSnapshotsMatch), |
@@ -1551,6 +1601,8 @@ void HeapEntriesMap::AllocateEntries() { |
p->key, |
entry_info->children_count, |
entry_info->retainers_count); |
+ ASSERT(entry_info->entry != NULL); |
+ ASSERT(entry_info->entry != kHeapEntryPlaceholder); |
entry_info->children_count = 0; |
entry_info->retainers_count = 0; |
} |
@@ -1630,9 +1682,11 @@ void HeapObjectsSet::Insert(Object* obj) { |
HeapObject *const V8HeapExplorer::kInternalRootObject = |
- reinterpret_cast<HeapObject*>(1); |
+ reinterpret_cast<HeapObject*>( |
+ static_cast<intptr_t>(HeapObjectsMap::kInternalRootObjectId)); |
HeapObject *const V8HeapExplorer::kGcRootsObject = |
- reinterpret_cast<HeapObject*>(2); |
+ reinterpret_cast<HeapObject*>( |
+ static_cast<intptr_t>(HeapObjectsMap::kGcRootsObjectId)); |
V8HeapExplorer::V8HeapExplorer( |
@@ -1669,27 +1723,28 @@ HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object, |
SharedFunctionInfo* shared = func->shared(); |
return AddEntry(object, |
HeapEntry::kClosure, |
- collection_->GetName(String::cast(shared->name())), |
+ collection_->names()->GetName(String::cast(shared->name())), |
children_count, |
retainers_count); |
} else if (object->IsJSRegExp()) { |
JSRegExp* re = JSRegExp::cast(object); |
return AddEntry(object, |
HeapEntry::kRegExp, |
- collection_->GetName(re->Pattern()), |
+ collection_->names()->GetName(re->Pattern()), |
children_count, |
retainers_count); |
} else if (object->IsJSObject()) { |
return AddEntry(object, |
HeapEntry::kObject, |
- collection_->GetName(GetConstructorNameForHeapProfile( |
- JSObject::cast(object))), |
+ collection_->names()->GetName( |
+ GetConstructorNameForHeapProfile( |
+ JSObject::cast(object))), |
children_count, |
retainers_count); |
} else if (object->IsString()) { |
return AddEntry(object, |
HeapEntry::kString, |
- collection_->GetName(String::cast(object)), |
+ collection_->names()->GetName(String::cast(object)), |
children_count, |
retainers_count); |
} else if (object->IsCode()) { |
@@ -1702,7 +1757,7 @@ HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object, |
SharedFunctionInfo* shared = SharedFunctionInfo::cast(object); |
return AddEntry(object, |
HeapEntry::kCode, |
- collection_->GetName(String::cast(shared->name())), |
+ collection_->names()->GetName(String::cast(shared->name())), |
children_count, |
retainers_count); |
} else if (object->IsScript()) { |
@@ -1710,7 +1765,9 @@ HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object, |
return AddEntry(object, |
HeapEntry::kCode, |
script->name()->IsString() ? |
- collection_->GetName(String::cast(script->name())) : "", |
+ collection_->names()->GetName( |
+ String::cast(script->name())) |
+ : "", |
children_count, |
retainers_count); |
} else if (object->IsFixedArray()) { |
@@ -1749,8 +1806,8 @@ HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object, |
void V8HeapExplorer::AddRootEntries(SnapshotFillerInterface* filler) { |
- filler->AddEntry(kInternalRootObject); |
- filler->AddEntry(kGcRootsObject); |
+ filler->AddEntry(kInternalRootObject, this); |
+ filler->AddEntry(kGcRootsObject, this); |
} |
@@ -1940,7 +1997,7 @@ void V8HeapExplorer::ExtractInternalReferences(JSObject* js_obj, |
HeapEntry* V8HeapExplorer::GetEntry(Object* obj) { |
if (!obj->IsHeapObject()) return NULL; |
- return filler_->FindOrAddEntry(obj); |
+ return filler_->FindOrAddEntry(obj, this); |
} |
@@ -1992,7 +2049,7 @@ void V8HeapExplorer::SetClosureReference(HeapObject* parent_obj, |
filler_->SetNamedReference(HeapGraphEdge::kContextVariable, |
parent_obj, |
parent_entry, |
- collection_->GetName(reference_name), |
+ collection_->names()->GetName(reference_name), |
child_obj, |
child_entry); |
known_references_.Insert(child_obj); |
@@ -2043,7 +2100,7 @@ void V8HeapExplorer::SetInternalReference(HeapObject* parent_obj, |
filler_->SetNamedReference(HeapGraphEdge::kInternal, |
parent_obj, |
parent_entry, |
- collection_->GetName(index), |
+ collection_->names()->GetName(index), |
child_obj, |
child_entry); |
known_references_.Insert(child_obj); |
@@ -2078,7 +2135,7 @@ void V8HeapExplorer::SetPropertyReference(HeapObject* parent_obj, |
filler_->SetNamedReference(type, |
parent_obj, |
parent_entry, |
- collection_->GetName(reference_name), |
+ collection_->names()->GetName(reference_name), |
child_obj, |
child_entry); |
known_references_.Insert(child_obj); |
@@ -2096,7 +2153,7 @@ void V8HeapExplorer::SetPropertyShortcutReference( |
filler_->SetNamedReference(HeapGraphEdge::kShortcut, |
parent_obj, |
parent_entry, |
- collection_->GetName(reference_name), |
+ collection_->names()->GetName(reference_name), |
child_obj, |
child_entry); |
} |
@@ -2132,25 +2189,215 @@ void V8HeapExplorer::SetGcRootsReference(Object* child_obj) { |
} |
+class GlobalHandlesExtractor : public ObjectVisitor { |
+ public: |
+ explicit GlobalHandlesExtractor(NativeObjectsExplorer* explorer) |
+ : explorer_(explorer) {} |
+ virtual ~GlobalHandlesExtractor() {} |
+ virtual void VisitPointers(Object** start, Object** end) { |
+ UNREACHABLE(); |
+ } |
+ virtual void VisitEmbedderReference(Object** p, uint16_t class_id) { |
+ explorer_->VisitSubtreeWrapper(p, class_id); |
+ } |
+ private: |
+ NativeObjectsExplorer* explorer_; |
+}; |
+ |
+HeapThing const NativeObjectsExplorer::kNativesRootObject = |
+ reinterpret_cast<HeapThing>( |
+ static_cast<intptr_t>(HeapObjectsMap::kNativesRootObjectId)); |
+ |
+ |
+NativeObjectsExplorer::NativeObjectsExplorer( |
+ HeapSnapshot* snapshot, SnapshottingProgressReportingInterface* progress) |
+ : snapshot_(snapshot), |
+ collection_(snapshot_->collection()), |
+ progress_(progress), |
+ embedder_queried_(false), |
+ objects_by_info_(RetainedInfosMatch), |
+ filler_(NULL) { |
+} |
+ |
+ |
+NativeObjectsExplorer::~NativeObjectsExplorer() { |
+ for (HashMap::Entry* p = objects_by_info_.Start(); |
+ p != NULL; |
+ p = objects_by_info_.Next(p)) { |
+ v8::RetainedObjectInfo* info = |
+ reinterpret_cast<v8::RetainedObjectInfo*>(p->key); |
+ info->Dispose(); |
+ List<HeapObject*>* objects = |
+ reinterpret_cast<List<HeapObject*>* >(p->value); |
+ delete objects; |
+ } |
+} |
+ |
+ |
+HeapEntry* NativeObjectsExplorer::AllocateEntry( |
+ HeapThing ptr, int children_count, int retainers_count) { |
+ if (ptr == kNativesRootObject) { |
+ return snapshot_->AddNativesRootEntry(children_count, retainers_count); |
+ } else { |
+ v8::RetainedObjectInfo* info = |
+ reinterpret_cast<v8::RetainedObjectInfo*>(ptr); |
+ intptr_t elements = info->GetElementCount(); |
+ intptr_t size = info->GetSizeInBytes(); |
+ return snapshot_->AddEntry( |
+ HeapEntry::kNative, |
+ elements != -1 ? |
+ collection_->names()->GetFormatted( |
+ "%s / %" V8_PTR_PREFIX "d entries", |
+ info->GetLabel(), |
+ info->GetElementCount()) : |
+ collection_->names()->GetCopy(info->GetLabel()), |
+ HeapObjectsMap::GenerateId(info), |
+ size != -1 ? static_cast<int>(size) : 0, |
+ children_count, |
+ retainers_count); |
+ } |
+} |
+ |
+ |
+void NativeObjectsExplorer::AddRootEntries(SnapshotFillerInterface* filler) { |
+ if (EstimateObjectsCount() <= 0) return; |
+ filler->AddEntry(kNativesRootObject, this); |
+} |
+ |
+ |
+int NativeObjectsExplorer::EstimateObjectsCount() { |
+ FillRetainedObjects(); |
+ return objects_by_info_.occupancy(); |
+} |
+ |
+ |
+void NativeObjectsExplorer::FillRetainedObjects() { |
+ if (embedder_queried_) return; |
+ // Record objects that are joined into ObjectGroups. |
+ Heap::CallGlobalGCPrologueCallback(); |
+ List<ObjectGroup*>* groups = GlobalHandles::ObjectGroups(); |
+ for (int i = 0; i < groups->length(); ++i) { |
+ ObjectGroup* group = groups->at(i); |
+ if (group->info_ == NULL) continue; |
+ List<HeapObject*>* list = GetListMaybeDisposeInfo(group->info_); |
+ for (int j = 0; j < group->objects_.length(); ++j) { |
+ HeapObject* obj = HeapObject::cast(*group->objects_[j]); |
+ list->Add(obj); |
+ in_groups_.Insert(obj); |
+ } |
+ group->info_ = NULL; // Acquire info object ownership. |
+ } |
+ GlobalHandles::RemoveObjectGroups(); |
+ Heap::CallGlobalGCEpilogueCallback(); |
+ // Record objects that are not in ObjectGroups, but have class ID. |
+ GlobalHandlesExtractor extractor(this); |
+ GlobalHandles::IterateAllRootsWithClassIds(&extractor); |
+ embedder_queried_ = true; |
+} |
+ |
+ |
+List<HeapObject*>* NativeObjectsExplorer::GetListMaybeDisposeInfo( |
+ v8::RetainedObjectInfo* info) { |
+ HashMap::Entry* entry = |
+ objects_by_info_.Lookup(info, InfoHash(info), true); |
+ if (entry->value != NULL) { |
+ info->Dispose(); |
+ } else { |
+ entry->value = new List<HeapObject*>(4); |
+ } |
+ return reinterpret_cast<List<HeapObject*>* >(entry->value); |
+} |
+ |
+ |
+bool NativeObjectsExplorer::IterateAndExtractReferences( |
+ SnapshotFillerInterface* filler) { |
+ if (EstimateObjectsCount() <= 0) return true; |
+ filler_ = filler; |
+ FillRetainedObjects(); |
+ for (HashMap::Entry* p = objects_by_info_.Start(); |
+ p != NULL; |
+ p = objects_by_info_.Next(p)) { |
+ v8::RetainedObjectInfo* info = |
+ reinterpret_cast<v8::RetainedObjectInfo*>(p->key); |
+ SetNativeRootReference(info); |
+ List<HeapObject*>* objects = |
+ reinterpret_cast<List<HeapObject*>* >(p->value); |
+ for (int i = 0; i < objects->length(); ++i) { |
+ SetWrapperNativeReferences(objects->at(i), info); |
+ } |
+ } |
+ SetRootNativesRootReference(); |
+ filler_ = NULL; |
+ return true; |
+} |
+ |
+ |
+void NativeObjectsExplorer::SetNativeRootReference( |
+ v8::RetainedObjectInfo* info) { |
+ HeapEntry* child_entry = filler_->FindOrAddEntry(info, this); |
+ ASSERT(child_entry != NULL); |
+ filler_->SetIndexedAutoIndexReference( |
+ HeapGraphEdge::kElement, |
+ kNativesRootObject, snapshot_->dom_subtrees_root(), |
+ info, child_entry); |
+} |
+ |
+ |
+void NativeObjectsExplorer::SetWrapperNativeReferences( |
+ HeapObject* wrapper, v8::RetainedObjectInfo* info) { |
+ HeapEntry* wrapper_entry = filler_->FindEntry(wrapper); |
+ ASSERT(wrapper_entry != NULL); |
+ HeapEntry* info_entry = filler_->FindOrAddEntry(info, this); |
+ ASSERT(info_entry != NULL); |
+ filler_->SetNamedReference(HeapGraphEdge::kInternal, |
+ wrapper, wrapper_entry, |
+ "Native", |
+ info, info_entry); |
+ filler_->SetIndexedAutoIndexReference(HeapGraphEdge::kElement, |
+ info, info_entry, |
+ wrapper, wrapper_entry); |
+} |
+ |
+ |
+void NativeObjectsExplorer::SetRootNativesRootReference() { |
+ filler_->SetIndexedAutoIndexReference( |
+ HeapGraphEdge::kElement, |
+ V8HeapExplorer::kInternalRootObject, snapshot_->root(), |
+ kNativesRootObject, snapshot_->dom_subtrees_root()); |
+} |
+ |
+ |
+void NativeObjectsExplorer::VisitSubtreeWrapper(Object** p, uint16_t class_id) { |
+ if (in_groups_.Contains(*p)) return; |
+ v8::RetainedObjectInfo* info = |
+ HeapProfiler::ExecuteWrapperClassCallback(class_id, p); |
+ if (info == NULL) return; |
+ GetListMaybeDisposeInfo(info)->Add(HeapObject::cast(*p)); |
+} |
+ |
+ |
HeapSnapshotGenerator::HeapSnapshotGenerator(HeapSnapshot* snapshot, |
v8::ActivityControl* control) |
: snapshot_(snapshot), |
control_(control), |
- v8_heap_explorer_(snapshot_, this) { |
+ v8_heap_explorer_(snapshot_, this), |
+ dom_explorer_(snapshot_, this) { |
} |
class SnapshotCounter : public SnapshotFillerInterface { |
public: |
- SnapshotCounter(HeapEntriesAllocator* allocator, HeapEntriesMap* entries) |
- : allocator_(allocator), entries_(entries) { } |
- HeapEntry* AddEntry(HeapThing ptr) { |
- entries_->Pair(ptr, allocator_, HeapEntriesMap::kHeapEntryPlaceholder); |
+ explicit SnapshotCounter(HeapEntriesMap* entries) : entries_(entries) { } |
+ HeapEntry* AddEntry(HeapThing ptr, HeapEntriesAllocator* allocator) { |
+ entries_->Pair(ptr, allocator, HeapEntriesMap::kHeapEntryPlaceholder); |
return HeapEntriesMap::kHeapEntryPlaceholder; |
} |
- HeapEntry* FindOrAddEntry(HeapThing ptr) { |
- HeapEntry* entry = entries_->Map(ptr); |
- return entry != NULL ? entry : AddEntry(ptr); |
+ HeapEntry* FindEntry(HeapThing ptr) { |
+ return entries_->Map(ptr); |
+ } |
+ HeapEntry* FindOrAddEntry(HeapThing ptr, HeapEntriesAllocator* allocator) { |
+ HeapEntry* entry = FindEntry(ptr); |
+ return entry != NULL ? entry : AddEntry(ptr, allocator); |
} |
void SetIndexedReference(HeapGraphEdge::Type, |
HeapThing parent_ptr, |
@@ -2183,7 +2430,6 @@ class SnapshotCounter : public SnapshotFillerInterface { |
entries_->CountReference(parent_ptr, child_ptr); |
} |
private: |
- HeapEntriesAllocator* allocator_; |
HeapEntriesMap* entries_; |
}; |
@@ -2194,13 +2440,16 @@ class SnapshotFiller : public SnapshotFillerInterface { |
: snapshot_(snapshot), |
collection_(snapshot->collection()), |
entries_(entries) { } |
- HeapEntry* AddEntry(HeapThing ptr) { |
+ HeapEntry* AddEntry(HeapThing ptr, HeapEntriesAllocator* allocator) { |
UNREACHABLE(); |
return NULL; |
} |
- HeapEntry* FindOrAddEntry(HeapThing ptr) { |
- HeapEntry* entry = entries_->Map(ptr); |
- return entry != NULL ? entry : AddEntry(ptr); |
+ HeapEntry* FindEntry(HeapThing ptr) { |
+ return entries_->Map(ptr); |
+ } |
+ HeapEntry* FindOrAddEntry(HeapThing ptr, HeapEntriesAllocator* allocator) { |
+ HeapEntry* entry = FindEntry(ptr); |
+ return entry != NULL ? entry : AddEntry(ptr, allocator); |
} |
void SetIndexedReference(HeapGraphEdge::Type type, |
HeapThing parent_ptr, |
@@ -2247,7 +2496,7 @@ class SnapshotFiller : public SnapshotFillerInterface { |
parent_ptr, child_ptr, &child_index, &retainer_index); |
parent_entry->SetNamedReference(type, |
child_index, |
- collection_->GetName(child_index + 1), |
+ collection_->names()->GetName(child_index + 1), |
child_entry, |
retainer_index); |
} |
@@ -2303,21 +2552,28 @@ bool HeapSnapshotGenerator::ProgressReport(bool force) { |
void HeapSnapshotGenerator::SetProgressTotal(int iterations_count) { |
if (control_ == NULL) return; |
- progress_total_ = v8_heap_explorer_.EstimateObjectsCount() * iterations_count; |
+ progress_total_ = ( |
+ v8_heap_explorer_.EstimateObjectsCount() + |
+ dom_explorer_.EstimateObjectsCount()) * iterations_count; |
progress_counter_ = 0; |
} |
bool HeapSnapshotGenerator::CountEntriesAndReferences() { |
- SnapshotCounter counter(&v8_heap_explorer_, &entries_); |
+ SnapshotCounter counter(&entries_); |
v8_heap_explorer_.AddRootEntries(&counter); |
- return v8_heap_explorer_.IterateAndExtractReferences(&counter); |
+ dom_explorer_.AddRootEntries(&counter); |
+ return |
+ v8_heap_explorer_.IterateAndExtractReferences(&counter) && |
+ dom_explorer_.IterateAndExtractReferences(&counter); |
} |
bool HeapSnapshotGenerator::FillReferences() { |
SnapshotFiller filler(snapshot_, &entries_); |
- return v8_heap_explorer_.IterateAndExtractReferences(&filler); |
+ return |
+ v8_heap_explorer_.IterateAndExtractReferences(&filler) && |
+ dom_explorer_.IterateAndExtractReferences(&filler); |
} |
@@ -2735,7 +2991,8 @@ void HeapSnapshotJSONSerializer::SerializeNodes() { |
"," JSON_S("code") |
"," JSON_S("closure") |
"," JSON_S("regexp") |
- "," JSON_S("number")) |
+ "," JSON_S("number") |
+ "," JSON_S("native")) |
"," JSON_S("string") |
"," JSON_S("number") |
"," JSON_S("number") |