Index: src/profile-generator.cc |
diff --git a/src/profile-generator.cc b/src/profile-generator.cc |
index 261b3d6ff019c64f50a321dd841c9fef023ed1c6..8fa35cc2e4a18fc84684a44df389cf9f9b427462 100644 |
--- a/src/profile-generator.cc |
+++ b/src/profile-generator.cc |
@@ -1177,12 +1177,6 @@ void HeapGraphPath::Print() { |
} |
-HeapObject *const HeapSnapshot::kInternalRootObject = |
- reinterpret_cast<HeapObject*>(1); |
-HeapObject *const HeapSnapshot::kGcRootsObject = |
- reinterpret_cast<HeapObject*>(2); |
- |
- |
// It is very important to keep objects that form a heap snapshot |
// as small as possible. |
namespace { // Avoid littering the global namespace. |
@@ -1253,96 +1247,6 @@ void HeapSnapshot::AllocateEntries(int entries_count, |
} |
-HeapEntry* HeapSnapshot::AddEntry(HeapObject* object, |
- int children_count, |
- int retainers_count) { |
- if (object == kInternalRootObject) { |
- ASSERT(root_entry_ == NULL); |
- ASSERT(retainers_count == 0); |
- return (root_entry_ = AddEntry(HeapEntry::kObject, |
- "", |
- HeapObjectsMap::kInternalRootObjectId, |
- 0, |
- children_count, |
- retainers_count)); |
- } else if (object == kGcRootsObject) { |
- ASSERT(gc_roots_entry_ == NULL); |
- return (gc_roots_entry_ = AddEntry(HeapEntry::kObject, |
- "(GC roots)", |
- HeapObjectsMap::kGcRootsObjectId, |
- 0, |
- children_count, |
- retainers_count)); |
- } else if (object->IsJSFunction()) { |
- JSFunction* func = JSFunction::cast(object); |
- SharedFunctionInfo* shared = func->shared(); |
- return AddEntry(object, |
- HeapEntry::kClosure, |
- collection_->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()), |
- children_count, |
- retainers_count); |
- } else if (object->IsJSObject()) { |
- return AddEntry(object, |
- HeapEntry::kObject, |
- collection_->GetName(GetConstructorNameForHeapProfile( |
- JSObject::cast(object))), |
- children_count, |
- retainers_count); |
- } else if (object->IsString()) { |
- return AddEntry(object, |
- HeapEntry::kString, |
- collection_->GetName(String::cast(object)), |
- children_count, |
- retainers_count); |
- } else if (object->IsCode()) { |
- return AddEntry(object, |
- HeapEntry::kCode, |
- "", |
- children_count, |
- retainers_count); |
- } else if (object->IsSharedFunctionInfo()) { |
- SharedFunctionInfo* shared = SharedFunctionInfo::cast(object); |
- return AddEntry(object, |
- HeapEntry::kCode, |
- collection_->GetName(String::cast(shared->name())), |
- children_count, |
- retainers_count); |
- } else if (object->IsScript()) { |
- Script* script = Script::cast(object); |
- return AddEntry(object, |
- HeapEntry::kCode, |
- script->name()->IsString() ? |
- collection_->GetName(String::cast(script->name())) : "", |
- children_count, |
- retainers_count); |
- } else if (object->IsFixedArray()) { |
- return AddEntry(object, |
- HeapEntry::kArray, |
- "", |
- children_count, |
- retainers_count); |
- } else if (object->IsHeapNumber()) { |
- return AddEntry(object, |
- HeapEntry::kHeapNumber, |
- "number", |
- children_count, |
- retainers_count); |
- } |
- return AddEntry(object, |
- HeapEntry::kHidden, |
- "system", |
- children_count, |
- retainers_count); |
-} |
- |
- |
static void HeapEntryClearPaint(HeapEntry** entry_ptr) { |
(*entry_ptr)->clear_paint(); |
} |
@@ -1352,17 +1256,26 @@ void HeapSnapshot::ClearPaint() { |
} |
-HeapEntry* HeapSnapshot::AddEntry(HeapObject* object, |
- HeapEntry::Type type, |
- const char* name, |
- int children_count, |
- int retainers_count) { |
- return AddEntry(type, |
- name, |
- collection_->GetObjectId(object->address()), |
- object->Size(), |
- children_count, |
- retainers_count); |
+HeapEntry* HeapSnapshot::AddRootEntry(int children_count) { |
+ ASSERT(root_entry_ == NULL); |
+ return (root_entry_ = AddEntry(HeapEntry::kObject, |
+ "", |
+ HeapObjectsMap::kInternalRootObjectId, |
+ 0, |
+ children_count, |
+ 0)); |
+} |
+ |
+ |
+HeapEntry* HeapSnapshot::AddGcRootsEntry(int children_count, |
+ int retainers_count) { |
+ ASSERT(gc_roots_entry_ == NULL); |
+ return (gc_roots_entry_ = AddEntry(HeapEntry::kObject, |
+ "(GC roots)", |
+ HeapObjectsMap::kGcRootsObjectId, |
+ 0, |
+ children_count, |
+ retainers_count)); |
} |
@@ -1615,7 +1528,7 @@ HeapEntry *const HeapEntriesMap::kHeapEntryPlaceholder = |
reinterpret_cast<HeapEntry*>(1); |
HeapEntriesMap::HeapEntriesMap() |
- : entries_(HeapObjectsMatch), |
+ : entries_(HeapThingsMatch), |
entries_count_(0), |
total_children_count_(0), |
total_retainers_count_(0) { |
@@ -1629,8 +1542,8 @@ HeapEntriesMap::~HeapEntriesMap() { |
} |
-HeapEntry* HeapEntriesMap::Map(HeapObject* object) { |
- HashMap::Entry* cache_entry = entries_.Lookup(object, Hash(object), false); |
+HeapEntry* HeapEntriesMap::Map(HeapThing thing) { |
+ HashMap::Entry* cache_entry = entries_.Lookup(thing, Hash(thing), false); |
if (cache_entry != NULL) { |
EntryInfo* entry_info = reinterpret_cast<EntryInfo*>(cache_entry->value); |
return entry_info->entry; |
@@ -1640,15 +1553,16 @@ HeapEntry* HeapEntriesMap::Map(HeapObject* object) { |
} |
-void HeapEntriesMap::Pair(HeapObject* object, HeapEntry* entry) { |
- HashMap::Entry* cache_entry = entries_.Lookup(object, Hash(object), true); |
+void HeapEntriesMap::Pair( |
+ HeapThing thing, HeapEntriesAllocator* allocator, HeapEntry* entry) { |
+ HashMap::Entry* cache_entry = entries_.Lookup(thing, Hash(thing), true); |
ASSERT(cache_entry->value == NULL); |
- cache_entry->value = new EntryInfo(entry); |
+ cache_entry->value = new EntryInfo(entry, allocator); |
++entries_count_; |
} |
-void HeapEntriesMap::CountReference(HeapObject* from, HeapObject* to, |
+void HeapEntriesMap::CountReference(HeapThing from, HeapThing to, |
int* prev_children_count, |
int* prev_retainers_count) { |
HashMap::Entry* from_cache_entry = entries_.Lookup(from, Hash(from), false); |
@@ -1670,8 +1584,23 @@ void HeapEntriesMap::CountReference(HeapObject* from, HeapObject* to, |
} |
+void HeapEntriesMap::UpdateEntries() { |
+ for (HashMap::Entry* p = entries_.Start(); |
+ p != NULL; |
+ p = entries_.Next(p)) { |
+ EntryInfo* entry_info = reinterpret_cast<EntryInfo*>(p->value); |
+ entry_info->entry = entry_info->allocator->AllocateEntry( |
+ p->key, |
+ entry_info->children_count, |
+ entry_info->retainers_count); |
+ entry_info->children_count = 0; |
+ entry_info->retainers_count = 0; |
+ } |
+} |
+ |
+ |
HeapObjectsSet::HeapObjectsSet() |
- : entries_(HeapEntriesMap::HeapObjectsMatch) { |
+ : entries_(HeapEntriesMap::HeapThingsMatch) { |
} |
@@ -1700,206 +1629,144 @@ void HeapObjectsSet::Insert(Object* obj) { |
} |
-HeapSnapshotGenerator::HeapSnapshotGenerator(HeapSnapshot* snapshot, |
- v8::ActivityControl* control) |
+HeapObject *const V8HeapExplorer::kInternalRootObject = |
+ reinterpret_cast<HeapObject*>(1); |
+HeapObject *const V8HeapExplorer::kGcRootsObject = |
+ reinterpret_cast<HeapObject*>(2); |
+ |
+ |
+V8HeapExplorer::V8HeapExplorer( |
+ HeapSnapshot* snapshot, |
+ SnapshottingProgressReportingInterface* progress) |
: snapshot_(snapshot), |
- control_(control), |
- collection_(snapshot->collection()), |
+ collection_(snapshot_->collection()), |
+ progress_(progress), |
filler_(NULL) { |
} |
-class SnapshotCounter : public HeapSnapshotGenerator::SnapshotFillerInterface { |
- public: |
- explicit SnapshotCounter(HeapEntriesMap* entries) |
- : entries_(entries) { } |
- HeapEntry* AddEntry(HeapObject* obj) { |
- entries_->Pair(obj, HeapEntriesMap::kHeapEntryPlaceholder); |
- return HeapEntriesMap::kHeapEntryPlaceholder; |
- } |
- void SetIndexedReference(HeapGraphEdge::Type, |
- HeapObject* parent_obj, |
- HeapEntry*, |
- int, |
- Object* child_obj, |
- HeapEntry*) { |
- entries_->CountReference(parent_obj, HeapObject::cast(child_obj)); |
- } |
- void SetNamedReference(HeapGraphEdge::Type, |
- HeapObject* parent_obj, |
- HeapEntry*, |
- const char*, |
- Object* child_obj, |
- HeapEntry*) { |
- entries_->CountReference(parent_obj, HeapObject::cast(child_obj)); |
- } |
- void SetRootShortcutReference(Object* child_obj, HeapEntry*) { |
- entries_->CountReference( |
- HeapSnapshot::kInternalRootObject, HeapObject::cast(child_obj)); |
- } |
- void SetRootGcRootsReference() { |
- entries_->CountReference( |
- HeapSnapshot::kInternalRootObject, HeapSnapshot::kGcRootsObject); |
- } |
- void SetStrongRootReference(Object* child_obj, HeapEntry*) { |
- entries_->CountReference( |
- HeapSnapshot::kGcRootsObject, HeapObject::cast(child_obj)); |
- } |
- private: |
- HeapEntriesMap* entries_; |
-}; |
- |
- |
-class SnapshotFiller : public HeapSnapshotGenerator::SnapshotFillerInterface { |
- public: |
- explicit SnapshotFiller(HeapSnapshot* snapshot, HeapEntriesMap* entries) |
- : snapshot_(snapshot), |
- collection_(snapshot->collection()), |
- entries_(entries) { } |
- HeapEntry* AddEntry(HeapObject* obj) { |
- UNREACHABLE(); |
- return NULL; |
- } |
- void SetIndexedReference(HeapGraphEdge::Type type, |
- HeapObject* parent_obj, |
- HeapEntry* parent_entry, |
- int index, |
- Object* child_obj, |
- HeapEntry* child_entry) { |
- int child_index, retainer_index; |
- entries_->CountReference(parent_obj, |
- HeapObject::cast(child_obj), |
- &child_index, |
- &retainer_index); |
- parent_entry->SetIndexedReference( |
- type, child_index, index, child_entry, retainer_index); |
- } |
- void SetNamedReference(HeapGraphEdge::Type type, |
- HeapObject* parent_obj, |
- HeapEntry* parent_entry, |
- const char* reference_name, |
- Object* child_obj, |
- HeapEntry* child_entry) { |
- int child_index, retainer_index; |
- entries_->CountReference(parent_obj, HeapObject::cast(child_obj), |
- &child_index, &retainer_index); |
- parent_entry->SetNamedReference(type, |
- child_index, |
- reference_name, |
- child_entry, |
- retainer_index); |
- } |
- void SetRootGcRootsReference() { |
- int child_index, retainer_index; |
- entries_->CountReference(HeapSnapshot::kInternalRootObject, |
- HeapSnapshot::kGcRootsObject, |
- &child_index, |
- &retainer_index); |
- snapshot_->root()->SetIndexedReference(HeapGraphEdge::kElement, |
- child_index, |
- child_index + 1, |
- snapshot_->gc_roots(), |
- retainer_index); |
- } |
- void SetRootShortcutReference(Object* child_obj, |
- HeapEntry* child_entry) { |
- int child_index, retainer_index; |
- entries_->CountReference(HeapSnapshot::kInternalRootObject, |
- HeapObject::cast(child_obj), |
- &child_index, |
- &retainer_index); |
- snapshot_->root()->SetNamedReference(HeapGraphEdge::kShortcut, |
- child_index, |
- collection_->GetName(child_index + 1), |
- child_entry, |
- retainer_index); |
- } |
- void SetStrongRootReference(Object* child_obj, |
- HeapEntry* child_entry) { |
- int child_index, retainer_index; |
- entries_->CountReference(HeapSnapshot::kGcRootsObject, |
- HeapObject::cast(child_obj), |
- &child_index, |
- &retainer_index); |
- snapshot_->gc_roots()->SetIndexedReference(HeapGraphEdge::kElement, |
- child_index, |
- child_index + 1, |
- child_entry, |
- retainer_index); |
- } |
- private: |
- HeapSnapshot* snapshot_; |
- HeapSnapshotsCollection* collection_; |
- HeapEntriesMap* entries_; |
-}; |
-class SnapshotAllocator { |
- public: |
- explicit SnapshotAllocator(HeapSnapshot* snapshot) |
- : snapshot_(snapshot) { } |
- HeapEntry* GetEntry( |
- HeapObject* obj, int children_count, int retainers_count) { |
- HeapEntry* entry = |
- snapshot_->AddEntry(obj, children_count, retainers_count); |
- ASSERT(entry != NULL); |
- return entry; |
- } |
- private: |
- HeapSnapshot* snapshot_; |
-}; |
- |
-class RootsReferencesExtractor : public ObjectVisitor { |
- public: |
- explicit RootsReferencesExtractor(HeapSnapshotGenerator* generator) |
- : generator_(generator) { |
- } |
- void VisitPointers(Object** start, Object** end) { |
- for (Object** p = start; p < end; p++) generator_->SetGcRootsReference(*p); |
- } |
- private: |
- HeapSnapshotGenerator* generator_; |
-}; |
+V8HeapExplorer::~V8HeapExplorer() { |
+} |
-bool HeapSnapshotGenerator::GenerateSnapshot() { |
- AssertNoAllocation no_alloc; |
+HeapEntry* V8HeapExplorer::AllocateEntry( |
+ HeapThing ptr, int children_count, int retainers_count) { |
+ return AddEntry( |
+ reinterpret_cast<HeapObject*>(ptr), children_count, retainers_count); |
+} |
- SetProgressTotal(4); // 2 passes + dominators + sizes. |
- // Pass 1. Iterate heap contents to count entries and references. |
- if (!CountEntriesAndReferences()) return false; |
+HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object, |
+ int children_count, |
+ int retainers_count) { |
+ if (object == kInternalRootObject) { |
+ ASSERT(retainers_count == 0); |
+ return snapshot_->AddRootEntry(children_count); |
+ } else if (object == kGcRootsObject) { |
+ return snapshot_->AddGcRootsEntry(children_count, retainers_count); |
+ } else if (object->IsJSFunction()) { |
+ JSFunction* func = JSFunction::cast(object); |
+ SharedFunctionInfo* shared = func->shared(); |
+ return AddEntry(object, |
+ HeapEntry::kClosure, |
+ collection_->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()), |
+ children_count, |
+ retainers_count); |
+ } else if (object->IsJSObject()) { |
+ return AddEntry(object, |
+ HeapEntry::kObject, |
+ collection_->GetName(GetConstructorNameForHeapProfile( |
+ JSObject::cast(object))), |
+ children_count, |
+ retainers_count); |
+ } else if (object->IsString()) { |
+ return AddEntry(object, |
+ HeapEntry::kString, |
+ collection_->GetName(String::cast(object)), |
+ children_count, |
+ retainers_count); |
+ } else if (object->IsCode()) { |
+ return AddEntry(object, |
+ HeapEntry::kCode, |
+ "", |
+ children_count, |
+ retainers_count); |
+ } else if (object->IsSharedFunctionInfo()) { |
+ SharedFunctionInfo* shared = SharedFunctionInfo::cast(object); |
+ return AddEntry(object, |
+ HeapEntry::kCode, |
+ collection_->GetName(String::cast(shared->name())), |
+ children_count, |
+ retainers_count); |
+ } else if (object->IsScript()) { |
+ Script* script = Script::cast(object); |
+ return AddEntry(object, |
+ HeapEntry::kCode, |
+ script->name()->IsString() ? |
+ collection_->GetName(String::cast(script->name())) : "", |
+ children_count, |
+ retainers_count); |
+ } else if (object->IsFixedArray()) { |
+ return AddEntry(object, |
+ HeapEntry::kArray, |
+ "", |
+ children_count, |
+ retainers_count); |
+ } else if (object->IsHeapNumber()) { |
+ return AddEntry(object, |
+ HeapEntry::kHeapNumber, |
+ "number", |
+ children_count, |
+ retainers_count); |
+ } |
+ return AddEntry(object, |
+ HeapEntry::kHidden, |
+ "system", |
+ children_count, |
+ retainers_count); |
+} |
- // Allocate and fill entries in the snapshot, allocate references. |
- snapshot_->AllocateEntries(entries_.entries_count(), |
- entries_.total_children_count(), |
- entries_.total_retainers_count()); |
- SnapshotAllocator allocator(snapshot_); |
- entries_.UpdateEntries(&allocator); |
- // Pass 2. Fill references. |
- if (!FillReferences()) return false; |
+HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object, |
+ HeapEntry::Type type, |
+ const char* name, |
+ int children_count, |
+ int retainers_count) { |
+ return snapshot_->AddEntry(type, |
+ name, |
+ collection_->GetObjectId(object->address()), |
+ object->Size(), |
+ children_count, |
+ retainers_count); |
+} |
- if (!SetEntriesDominators()) return false; |
- if (!ApproximateRetainedSizes()) return false; |
- progress_counter_ = progress_total_; |
- if (!ReportProgress(true)) return false; |
- return true; |
+void V8HeapExplorer::AddRootEntries(SnapshotFillerInterface* filler) { |
+ filler->AddEntry(kInternalRootObject); |
+ filler->AddEntry(kGcRootsObject); |
} |
-HeapEntry* HeapSnapshotGenerator::GetEntry(Object* obj) { |
- if (!obj->IsHeapObject()) return NULL; |
- HeapObject* object = HeapObject::cast(obj); |
- HeapEntry* entry = entries_.Map(object); |
- // A new entry. |
- if (entry == NULL) entry = filler_->AddEntry(object); |
- return entry; |
+int V8HeapExplorer::EstimateObjectsCount() { |
+ HeapIterator iterator(HeapIterator::kFilterUnreachable); |
+ int objects_count = 0; |
+ for (HeapObject* obj = iterator.next(); |
+ obj != NULL; |
+ obj = iterator.next(), ++objects_count) {} |
+ return objects_count; |
} |
class IndexedReferencesExtractor : public ObjectVisitor { |
public: |
- IndexedReferencesExtractor(HeapSnapshotGenerator* generator, |
+ IndexedReferencesExtractor(V8HeapExplorer* generator, |
HeapObject* parent_obj, |
HeapEntry* parent_entry, |
HeapObjectsSet* known_references = NULL) |
@@ -1917,7 +1784,7 @@ class IndexedReferencesExtractor : public ObjectVisitor { |
} |
} |
private: |
- HeapSnapshotGenerator* generator_; |
+ V8HeapExplorer* generator_; |
HeapObject* parent_obj_; |
HeapEntry* parent_; |
HeapObjectsSet* known_references_; |
@@ -1925,7 +1792,7 @@ class IndexedReferencesExtractor : public ObjectVisitor { |
}; |
-void HeapSnapshotGenerator::ExtractReferences(HeapObject* obj) { |
+void V8HeapExplorer::ExtractReferences(HeapObject* obj) { |
HeapEntry* entry = GetEntry(obj); |
if (entry == NULL) return; // No interest in this object. |
@@ -1969,8 +1836,8 @@ void HeapSnapshotGenerator::ExtractReferences(HeapObject* obj) { |
} |
-void HeapSnapshotGenerator::ExtractClosureReferences(JSObject* js_obj, |
- HeapEntry* entry) { |
+void V8HeapExplorer::ExtractClosureReferences(JSObject* js_obj, |
+ HeapEntry* entry) { |
if (js_obj->IsJSFunction()) { |
HandleScope hs; |
JSFunction* func = JSFunction::cast(js_obj); |
@@ -1992,8 +1859,8 @@ void HeapSnapshotGenerator::ExtractClosureReferences(JSObject* js_obj, |
} |
-void HeapSnapshotGenerator::ExtractPropertyReferences(JSObject* js_obj, |
- HeapEntry* entry) { |
+void V8HeapExplorer::ExtractPropertyReferences(JSObject* js_obj, |
+ HeapEntry* entry) { |
if (js_obj->HasFastProperties()) { |
DescriptorArray* descs = js_obj->map()->instance_descriptors(); |
for (int i = 0; i < descs->number_of_descriptors(); i++) { |
@@ -2034,8 +1901,8 @@ void HeapSnapshotGenerator::ExtractPropertyReferences(JSObject* js_obj, |
} |
-void HeapSnapshotGenerator::ExtractElementReferences(JSObject* js_obj, |
- HeapEntry* entry) { |
+void V8HeapExplorer::ExtractElementReferences(JSObject* js_obj, |
+ HeapEntry* entry) { |
if (js_obj->HasFastElements()) { |
FixedArray* elements = FixedArray::cast(js_obj->elements()); |
int length = js_obj->IsJSArray() ? |
@@ -2061,8 +1928,8 @@ void HeapSnapshotGenerator::ExtractElementReferences(JSObject* js_obj, |
} |
-void HeapSnapshotGenerator::ExtractInternalReferences(JSObject* js_obj, |
- HeapEntry* entry) { |
+void V8HeapExplorer::ExtractInternalReferences(JSObject* js_obj, |
+ HeapEntry* entry) { |
int length = js_obj->GetInternalFieldCount(); |
for (int i = 0; i < length; ++i) { |
Object* o = js_obj->GetInternalField(i); |
@@ -2071,10 +1938,55 @@ void HeapSnapshotGenerator::ExtractInternalReferences(JSObject* js_obj, |
} |
-void HeapSnapshotGenerator::SetClosureReference(HeapObject* parent_obj, |
- HeapEntry* parent_entry, |
- String* reference_name, |
- Object* child_obj) { |
+HeapEntry* V8HeapExplorer::GetEntry(Object* obj) { |
+ if (!obj->IsHeapObject()) return NULL; |
+ return filler_->FindOrAddEntry(obj); |
+} |
+ |
+ |
+class RootsReferencesExtractor : public ObjectVisitor { |
+ public: |
+ explicit RootsReferencesExtractor(V8HeapExplorer* explorer) |
+ : explorer_(explorer) { |
+ } |
+ void VisitPointers(Object** start, Object** end) { |
+ for (Object** p = start; p < end; p++) explorer_->SetGcRootsReference(*p); |
+ } |
+ private: |
+ V8HeapExplorer* explorer_; |
+}; |
+ |
+ |
+bool V8HeapExplorer::IterateAndExtractReferences( |
+ SnapshotFillerInterface* filler) { |
+ filler_ = filler; |
+ HeapIterator iterator(HeapIterator::kFilterUnreachable); |
+ bool interrupted = false; |
+ // Heap iteration with filtering must be finished in any case. |
+ for (HeapObject* obj = iterator.next(); |
+ obj != NULL; |
+ obj = iterator.next(), progress_->ProgressStep()) { |
+ if (!interrupted) { |
+ ExtractReferences(obj); |
+ if (!progress_->ProgressReport(false)) interrupted = true; |
+ } |
+ } |
+ if (interrupted) { |
+ filler_ = NULL; |
+ return false; |
+ } |
+ SetRootGcRootsReference(); |
+ RootsReferencesExtractor extractor(this); |
+ Heap::IterateRoots(&extractor, VISIT_ALL); |
+ filler_ = NULL; |
+ return progress_->ProgressReport(false); |
+} |
+ |
+ |
+void V8HeapExplorer::SetClosureReference(HeapObject* parent_obj, |
+ HeapEntry* parent_entry, |
+ String* reference_name, |
+ Object* child_obj) { |
HeapEntry* child_entry = GetEntry(child_obj); |
if (child_entry != NULL) { |
filler_->SetNamedReference(HeapGraphEdge::kContextVariable, |
@@ -2088,10 +2000,10 @@ void HeapSnapshotGenerator::SetClosureReference(HeapObject* parent_obj, |
} |
-void HeapSnapshotGenerator::SetElementReference(HeapObject* parent_obj, |
- HeapEntry* parent_entry, |
- int index, |
- Object* child_obj) { |
+void V8HeapExplorer::SetElementReference(HeapObject* parent_obj, |
+ HeapEntry* parent_entry, |
+ int index, |
+ Object* child_obj) { |
HeapEntry* child_entry = GetEntry(child_obj); |
if (child_entry != NULL) { |
filler_->SetIndexedReference(HeapGraphEdge::kElement, |
@@ -2105,10 +2017,10 @@ void HeapSnapshotGenerator::SetElementReference(HeapObject* parent_obj, |
} |
-void HeapSnapshotGenerator::SetInternalReference(HeapObject* parent_obj, |
- HeapEntry* parent_entry, |
- const char* reference_name, |
- Object* child_obj) { |
+void V8HeapExplorer::SetInternalReference(HeapObject* parent_obj, |
+ HeapEntry* parent_entry, |
+ const char* reference_name, |
+ Object* child_obj) { |
HeapEntry* child_entry = GetEntry(child_obj); |
if (child_entry != NULL) { |
filler_->SetNamedReference(HeapGraphEdge::kInternal, |
@@ -2122,10 +2034,10 @@ void HeapSnapshotGenerator::SetInternalReference(HeapObject* parent_obj, |
} |
-void HeapSnapshotGenerator::SetInternalReference(HeapObject* parent_obj, |
- HeapEntry* parent_entry, |
- int index, |
- Object* child_obj) { |
+void V8HeapExplorer::SetInternalReference(HeapObject* parent_obj, |
+ HeapEntry* parent_entry, |
+ int index, |
+ Object* child_obj) { |
HeapEntry* child_entry = GetEntry(child_obj); |
if (child_entry != NULL) { |
filler_->SetNamedReference(HeapGraphEdge::kInternal, |
@@ -2139,10 +2051,10 @@ void HeapSnapshotGenerator::SetInternalReference(HeapObject* parent_obj, |
} |
-void HeapSnapshotGenerator::SetHiddenReference(HeapObject* parent_obj, |
- HeapEntry* parent_entry, |
- int index, |
- Object* child_obj) { |
+void V8HeapExplorer::SetHiddenReference(HeapObject* parent_obj, |
+ HeapEntry* parent_entry, |
+ int index, |
+ Object* child_obj) { |
HeapEntry* child_entry = GetEntry(child_obj); |
if (child_entry != NULL) { |
filler_->SetIndexedReference(HeapGraphEdge::kHidden, |
@@ -2155,10 +2067,10 @@ void HeapSnapshotGenerator::SetHiddenReference(HeapObject* parent_obj, |
} |
-void HeapSnapshotGenerator::SetPropertyReference(HeapObject* parent_obj, |
- HeapEntry* parent_entry, |
- String* reference_name, |
- Object* child_obj) { |
+void V8HeapExplorer::SetPropertyReference(HeapObject* parent_obj, |
+ HeapEntry* parent_entry, |
+ String* reference_name, |
+ Object* child_obj) { |
HeapEntry* child_entry = GetEntry(child_obj); |
if (child_entry != NULL) { |
HeapGraphEdge::Type type = reference_name->length() > 0 ? |
@@ -2174,7 +2086,7 @@ void HeapSnapshotGenerator::SetPropertyReference(HeapObject* parent_obj, |
} |
-void HeapSnapshotGenerator::SetPropertyShortcutReference( |
+void V8HeapExplorer::SetPropertyShortcutReference( |
HeapObject* parent_obj, |
HeapEntry* parent_entry, |
String* reference_name, |
@@ -2191,52 +2103,221 @@ void HeapSnapshotGenerator::SetPropertyShortcutReference( |
} |
-void HeapSnapshotGenerator::SetRootGcRootsReference() { |
- filler_->SetRootGcRootsReference(); |
+void V8HeapExplorer::SetRootGcRootsReference() { |
+ filler_->SetIndexedAutoIndexReference( |
+ HeapGraphEdge::kElement, |
+ kInternalRootObject, snapshot_->root(), |
+ kGcRootsObject, snapshot_->gc_roots()); |
} |
-void HeapSnapshotGenerator::SetRootShortcutReference(Object* child_obj) { |
+void V8HeapExplorer::SetRootShortcutReference(Object* child_obj) { |
HeapEntry* child_entry = GetEntry(child_obj); |
ASSERT(child_entry != NULL); |
- filler_->SetRootShortcutReference(child_obj, child_entry); |
+ filler_->SetNamedAutoIndexReference( |
+ HeapGraphEdge::kShortcut, |
+ kInternalRootObject, snapshot_->root(), |
+ child_obj, child_entry); |
} |
-void HeapSnapshotGenerator::SetGcRootsReference(Object* child_obj) { |
+void V8HeapExplorer::SetGcRootsReference(Object* child_obj) { |
HeapEntry* child_entry = GetEntry(child_obj); |
if (child_entry != NULL) { |
- filler_->SetStrongRootReference(child_obj, child_entry); |
+ filler_->SetIndexedAutoIndexReference( |
+ HeapGraphEdge::kElement, |
+ kGcRootsObject, snapshot_->gc_roots(), |
+ child_obj, child_entry); |
} |
} |
+HeapSnapshotGenerator::HeapSnapshotGenerator(HeapSnapshot* snapshot, |
+ v8::ActivityControl* control) |
+ : snapshot_(snapshot), |
+ control_(control), |
+ v8_heap_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); |
+ return HeapEntriesMap::kHeapEntryPlaceholder; |
+ } |
+ HeapEntry* FindOrAddEntry(HeapThing ptr) { |
+ HeapEntry* entry = entries_->Map(ptr); |
+ return entry != NULL ? entry : AddEntry(ptr); |
+ } |
+ void SetIndexedReference(HeapGraphEdge::Type, |
+ HeapThing parent_ptr, |
+ HeapEntry*, |
+ int, |
+ HeapThing child_ptr, |
+ HeapEntry*) { |
+ entries_->CountReference(parent_ptr, child_ptr); |
+ } |
+ void SetIndexedAutoIndexReference(HeapGraphEdge::Type, |
+ HeapThing parent_ptr, |
+ HeapEntry*, |
+ HeapThing child_ptr, |
+ HeapEntry*) { |
+ entries_->CountReference(parent_ptr, child_ptr); |
+ } |
+ void SetNamedReference(HeapGraphEdge::Type, |
+ HeapThing parent_ptr, |
+ HeapEntry*, |
+ const char*, |
+ HeapThing child_ptr, |
+ HeapEntry*) { |
+ entries_->CountReference(parent_ptr, child_ptr); |
+ } |
+ void SetNamedAutoIndexReference(HeapGraphEdge::Type, |
+ HeapThing parent_ptr, |
+ HeapEntry*, |
+ HeapThing child_ptr, |
+ HeapEntry*) { |
+ entries_->CountReference(parent_ptr, child_ptr); |
+ } |
+ private: |
+ HeapEntriesAllocator* allocator_; |
+ HeapEntriesMap* entries_; |
+}; |
+ |
+ |
+class SnapshotFiller : public SnapshotFillerInterface { |
+ public: |
+ explicit SnapshotFiller(HeapSnapshot* snapshot, HeapEntriesMap* entries) |
+ : snapshot_(snapshot), |
+ collection_(snapshot->collection()), |
+ entries_(entries) { } |
+ HeapEntry* AddEntry(HeapThing ptr) { |
+ UNREACHABLE(); |
+ return NULL; |
+ } |
+ HeapEntry* FindOrAddEntry(HeapThing ptr) { |
+ HeapEntry* entry = entries_->Map(ptr); |
+ return entry != NULL ? entry : AddEntry(ptr); |
+ } |
+ void SetIndexedReference(HeapGraphEdge::Type type, |
+ HeapThing parent_ptr, |
+ HeapEntry* parent_entry, |
+ int index, |
+ HeapThing child_ptr, |
+ HeapEntry* child_entry) { |
+ int child_index, retainer_index; |
+ entries_->CountReference( |
+ parent_ptr, child_ptr, &child_index, &retainer_index); |
+ parent_entry->SetIndexedReference( |
+ type, child_index, index, child_entry, retainer_index); |
+ } |
+ void SetIndexedAutoIndexReference(HeapGraphEdge::Type type, |
+ HeapThing parent_ptr, |
+ HeapEntry* parent_entry, |
+ HeapThing child_ptr, |
+ HeapEntry* child_entry) { |
+ int child_index, retainer_index; |
+ entries_->CountReference( |
+ parent_ptr, child_ptr, &child_index, &retainer_index); |
+ parent_entry->SetIndexedReference( |
+ type, child_index, child_index + 1, child_entry, retainer_index); |
+ } |
+ void SetNamedReference(HeapGraphEdge::Type type, |
+ HeapThing parent_ptr, |
+ HeapEntry* parent_entry, |
+ const char* reference_name, |
+ HeapThing child_ptr, |
+ HeapEntry* child_entry) { |
+ int child_index, retainer_index; |
+ entries_->CountReference( |
+ parent_ptr, child_ptr, &child_index, &retainer_index); |
+ parent_entry->SetNamedReference( |
+ type, child_index, reference_name, child_entry, retainer_index); |
+ } |
+ void SetNamedAutoIndexReference(HeapGraphEdge::Type type, |
+ HeapThing parent_ptr, |
+ HeapEntry* parent_entry, |
+ HeapThing child_ptr, |
+ HeapEntry* child_entry) { |
+ int child_index, retainer_index; |
+ entries_->CountReference( |
+ parent_ptr, child_ptr, &child_index, &retainer_index); |
+ parent_entry->SetNamedReference(type, |
+ child_index, |
+ collection_->GetName(child_index + 1), |
+ child_entry, |
+ retainer_index); |
+ } |
+ private: |
+ HeapSnapshot* snapshot_; |
+ HeapSnapshotsCollection* collection_; |
+ HeapEntriesMap* entries_; |
+}; |
+ |
+ |
+bool HeapSnapshotGenerator::GenerateSnapshot() { |
+ AssertNoAllocation no_alloc; |
+ |
+ SetProgressTotal(4); // 2 passes + dominators + sizes. |
+ |
+ // Pass 1. Iterate heap contents to count entries and references. |
+ if (!CountEntriesAndReferences()) return false; |
+ |
+ // Allocate and fill entries in the snapshot, allocate references. |
+ snapshot_->AllocateEntries(entries_.entries_count(), |
+ entries_.total_children_count(), |
+ entries_.total_retainers_count()); |
+ entries_.UpdateEntries(); |
+ |
+ // Pass 2. Fill references. |
+ if (!FillReferences()) return false; |
+ |
+ if (!SetEntriesDominators()) return false; |
+ if (!ApproximateRetainedSizes()) return false; |
+ |
+ progress_counter_ = progress_total_; |
+ if (!ProgressReport(true)) return false; |
+ return true; |
+} |
+ |
+ |
+void HeapSnapshotGenerator::ProgressStep() { |
+ ++progress_counter_; |
+} |
+ |
+ |
+bool HeapSnapshotGenerator::ProgressReport(bool force) { |
+ const int kProgressReportGranularity = 10000; |
+ if (control_ != NULL |
+ && (force || progress_counter_ % kProgressReportGranularity == 0)) { |
+ return |
+ control_->ReportProgressValue(progress_counter_, progress_total_) == |
+ v8::ActivityControl::kContinue; |
+ } |
+ return true; |
+} |
+ |
+ |
void HeapSnapshotGenerator::SetProgressTotal(int iterations_count) { |
if (control_ == NULL) return; |
- |
- HeapIterator iterator(HeapIterator::kFilterUnreachable); |
- int objects_count = 0; |
- for (HeapObject* obj = iterator.next(); |
- obj != NULL; |
- obj = iterator.next(), ++objects_count) {} |
- progress_total_ = objects_count * iterations_count; |
+ progress_total_ = v8_heap_explorer_.EstimateObjectsCount() * iterations_count; |
progress_counter_ = 0; |
} |
bool HeapSnapshotGenerator::CountEntriesAndReferences() { |
- SnapshotCounter counter(&entries_); |
- filler_ = &counter; |
- filler_->AddEntry(HeapSnapshot::kInternalRootObject); |
- filler_->AddEntry(HeapSnapshot::kGcRootsObject); |
- return IterateAndExtractReferences(); |
+ SnapshotCounter counter(&v8_heap_explorer_, &entries_); |
+ v8_heap_explorer_.AddRootEntries(&counter); |
+ return v8_heap_explorer_.IterateAndExtractReferences(&counter); |
} |
bool HeapSnapshotGenerator::FillReferences() { |
SnapshotFiller filler(snapshot_, &entries_); |
- filler_ = &filler; |
- return IterateAndExtractReferences(); |
+ return v8_heap_explorer_.IterateAndExtractReferences(&filler); |
} |
@@ -2322,7 +2403,7 @@ bool HeapSnapshotGenerator::BuildDominatorTree( |
int remaining = entries_length - changed; |
if (remaining < 0) remaining = 0; |
progress_counter_ = base_progress_counter + remaining; |
- if (!ReportProgress(true)) return false; |
+ if (!ProgressReport(true)) return false; |
} |
return true; |
} |
@@ -2352,7 +2433,7 @@ bool HeapSnapshotGenerator::ApproximateRetainedSizes() { |
} |
for (int i = 0; |
i < snapshot_->entries()->length(); |
- ++i, IncProgressCounter()) { |
+ ++i, ProgressStep()) { |
HeapEntry* entry = snapshot_->entries()->at(i); |
int entry_size = entry->self_size(); |
for (HeapEntry* dominator = entry->dominator(); |
@@ -2360,32 +2441,12 @@ bool HeapSnapshotGenerator::ApproximateRetainedSizes() { |
entry = dominator, dominator = entry->dominator()) { |
dominator->add_retained_size(entry_size); |
} |
- if (!ReportProgress()) return false; |
+ if (!ProgressReport()) return false; |
} |
return true; |
} |
-bool HeapSnapshotGenerator::IterateAndExtractReferences() { |
- HeapIterator iterator(HeapIterator::kFilterUnreachable); |
- bool interrupted = false; |
- // Heap iteration with filtering must be finished in any case. |
- for (HeapObject* obj = iterator.next(); |
- obj != NULL; |
- obj = iterator.next(), IncProgressCounter()) { |
- if (!interrupted) { |
- ExtractReferences(obj); |
- if (!ReportProgress()) interrupted = true; |
- } |
- } |
- if (interrupted) return false; |
- SetRootGcRootsReference(); |
- RootsReferencesExtractor extractor(this); |
- Heap::IterateRoots(&extractor, VISIT_ALL); |
- return ReportProgress(); |
-} |
- |
- |
void HeapSnapshotsDiff::CreateRoots(int additions_count, int deletions_count) { |
raw_additions_root_ = |
NewArray<char>(HeapEntry::EntriesSize(1, additions_count, 0)); |