Index: src/heap-snapshot-generator.cc |
diff --git a/src/heap-snapshot-generator.cc b/src/heap-snapshot-generator.cc |
index 332d0dbf6ff3705318f28a666d7134667e12295c..bab6b7160531257732c1e3849731cddc63512524 100644 |
--- a/src/heap-snapshot-generator.cc |
+++ b/src/heap-snapshot-generator.cc |
@@ -1101,7 +1101,9 @@ class IndexedReferencesExtractor : public ObjectVisitor { |
}; |
-void V8HeapExplorer::ExtractReferences(HeapObject* obj) { |
+void V8HeapExplorer::ExtractReferencesPass1(HeapObject* obj) { |
+ if (obj->IsFixedArray()) return; // FixedArrays are processed on pass 2. |
+ |
HeapEntry* heap_entry = GetEntry(obj); |
if (heap_entry == NULL) return; // No interest in this object. |
int entry = heap_entry->index(); |
@@ -1114,8 +1116,6 @@ void V8HeapExplorer::ExtractReferences(HeapObject* obj) { |
ExtractJSObjectReferences(entry, JSObject::cast(obj)); |
} else if (obj->IsString()) { |
ExtractStringReferences(entry, String::cast(obj)); |
- } else if (obj->IsContext()) { |
- ExtractContextReferences(entry, Context::cast(obj)); |
} else if (obj->IsMap()) { |
ExtractMapReferences(entry, Map::cast(obj)); |
} else if (obj->IsSharedFunctionInfo()) { |
@@ -1146,6 +1146,28 @@ void V8HeapExplorer::ExtractReferences(HeapObject* obj) { |
} |
+void V8HeapExplorer::ExtractReferencesPass2(HeapObject* obj) { |
+ if (!obj->IsFixedArray()) return; |
+ |
+ HeapEntry* heap_entry = GetEntry(obj); |
yurys
2014/04/01 15:51:55
Consider extracting common prologue and epilogue o
alph
2014/04/01 16:30:03
Done.
|
+ if (heap_entry == NULL) return; // No interest in this object. |
+ int entry = heap_entry->index(); |
+ |
+ if (obj->IsContext()) { |
+ ExtractContextReferences(entry, Context::cast(obj)); |
+ } else { |
+ ExtractFixedArrayReferences(entry, FixedArray::cast(obj)); |
+ } |
+ |
+ SetInternalReference(obj, entry, "map", obj->map(), HeapObject::kMapOffset); |
+ |
+ // Extract unvisited fields as hidden references and restore tags |
+ // of visited fields. |
+ IndexedReferencesExtractor refs_extractor(this, obj, entry); |
+ obj->Iterate(&refs_extractor); |
+} |
+ |
+ |
void V8HeapExplorer::ExtractJSGlobalProxyReferences( |
int entry, JSGlobalProxy* proxy) { |
SetInternalReference(proxy, entry, |
@@ -1320,6 +1342,7 @@ void V8HeapExplorer::ExtractMapReferences(int entry, Map* map) { |
SetInternalReference(transitions, transitions_entry, |
"back_pointer", back_pointer); |
TagObject(transitions, "(transition array)"); |
+ MarkAsWeakContainer(transitions); |
SetInternalReference(map, entry, |
"transitions", transitions, |
Map::kTransitionsOrBackPointerOffset); |
@@ -1336,6 +1359,7 @@ void V8HeapExplorer::ExtractMapReferences(int entry, Map* map) { |
"descriptors", descriptors, |
Map::kDescriptorsOffset); |
+ MarkAsWeakContainer(map->code_cache()); |
SetInternalReference(map, entry, |
"code_cache", map->code_cache(), |
Map::kCodeCacheOffset); |
@@ -1345,6 +1369,7 @@ void V8HeapExplorer::ExtractMapReferences(int entry, Map* map) { |
"constructor", map->constructor(), |
Map::kConstructorOffset); |
TagObject(map->dependent_code(), "(dependent code)"); |
+ MarkAsWeakContainer(map->dependent_code()); |
SetInternalReference(map, entry, |
"dependent_code", map->dependent_code(), |
Map::kDependentCodeOffset); |
@@ -1506,6 +1531,7 @@ void V8HeapExplorer::ExtractPropertyCellReferences(int entry, |
ExtractCellReferences(entry, cell); |
SetInternalReference(cell, entry, "type", cell->type(), |
PropertyCell::kTypeOffset); |
+ MarkAsWeakContainer(cell->dependent_code()); |
SetInternalReference(cell, entry, "dependent_code", cell->dependent_code(), |
PropertyCell::kDependentCodeOffset); |
} |
@@ -1517,6 +1543,7 @@ void V8HeapExplorer::ExtractAllocationSiteReferences(int entry, |
AllocationSite::kTransitionInfoOffset); |
SetInternalReference(site, entry, "nested_site", site->nested_site(), |
AllocationSite::kNestedSiteOffset); |
+ MarkAsWeakContainer(site->dependent_code()); |
SetInternalReference(site, entry, "dependent_code", site->dependent_code(), |
AllocationSite::kDependentCodeOffset); |
// Do not visit weak_next as it is not visited by the StaticVisitor, |
@@ -1562,6 +1589,20 @@ void V8HeapExplorer::ExtractJSArrayBufferReferences( |
} |
+void V8HeapExplorer::ExtractFixedArrayReferences(int entry, FixedArray* array) { |
+ bool is_weak = weak_containers_.Contains(array); |
+ for (int i = 0, l = array->length(); i < l; ++i) { |
+ if (is_weak) { |
+ SetWeakReference(array, entry, |
+ i, array->get(i), array->OffsetOfElementAt(i)); |
+ } else { |
+ SetInternalReference(array, entry, |
+ i, array->get(i), array->OffsetOfElementAt(i)); |
+ } |
+ } |
+} |
+ |
+ |
void V8HeapExplorer::ExtractClosureReferences(JSObject* js_obj, int entry) { |
if (!js_obj->IsJSFunction()) return; |
@@ -1833,6 +1874,25 @@ bool V8HeapExplorer::IterateAndExtractReferences( |
heap_->IterateRoots(&extractor, VISIT_ALL); |
extractor.FillReferences(this); |
+ // We have to do two passes as sometimes FixedArrays are used |
+ // to weakly hold their items, and it's impossible to distinguish |
+ // between these cases without processing the array owner first. |
+ bool interrupted = |
+ IterateAndExtractSinglePass<&V8HeapExplorer::ExtractReferencesPass1>() || |
+ IterateAndExtractSinglePass<&V8HeapExplorer::ExtractReferencesPass2>(); |
+ |
+ if (interrupted) { |
+ filler_ = NULL; |
+ return false; |
+ } |
+ |
+ filler_ = NULL; |
+ return progress_->ProgressReport(true); |
+} |
+ |
+ |
+template<V8HeapExplorer::ExtractReferencesMethod extractor> |
+bool V8HeapExplorer::IterateAndExtractSinglePass() { |
// Now iterate the whole heap. |
bool interrupted = false; |
HeapIterator iterator(heap_, HeapIterator::kFilterUnreachable); |
@@ -1840,18 +1900,11 @@ bool V8HeapExplorer::IterateAndExtractReferences( |
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; |
+ if (interrupted) continue; |
+ (this->*extractor)(obj); |
+ if (!progress_->ProgressReport(false)) interrupted = true; |
} |
- |
- filler_ = NULL; |
- return progress_->ProgressReport(true); |
+ return interrupted; |
} |
@@ -1987,6 +2040,24 @@ void V8HeapExplorer::SetWeakReference(HeapObject* parent_obj, |
} |
+void V8HeapExplorer::SetWeakReference(HeapObject* parent_obj, |
+ int parent_entry, |
+ int index, |
+ Object* child_obj, |
+ int field_offset) { |
+ ASSERT(parent_entry == GetEntry(parent_obj)->index()); |
+ HeapEntry* child_entry = GetEntry(child_obj); |
+ if (child_entry == NULL) return; |
+ if (IsEssentialObject(child_obj)) { |
+ filler_->SetNamedReference(HeapGraphEdge::kWeak, |
+ parent_entry, |
+ names_->GetFormatted("%d", index), |
+ child_entry); |
+ } |
+ IndexedReferencesExtractor::MarkVisitedField(parent_obj, field_offset); |
+} |
+ |
+ |
void V8HeapExplorer::SetPropertyReference(HeapObject* parent_obj, |
int parent_entry, |
Name* reference_name, |
@@ -2114,6 +2185,13 @@ void V8HeapExplorer::TagObject(Object* obj, const char* tag) { |
} |
+void V8HeapExplorer::MarkAsWeakContainer(Object* object) { |
+ if (IsEssentialObject(object)) { |
yurys
2014/04/01 15:51:55
Can you add an assert that the object passed in is
alph
2014/04/01 16:30:03
Done.
|
+ weak_containers_.Insert(object); |
+ } |
+} |
+ |
+ |
class GlobalObjectsEnumerator : public ObjectVisitor { |
public: |
virtual void VisitPointers(Object** start, Object** end) { |
@@ -2504,7 +2582,7 @@ bool HeapSnapshotGenerator::GenerateSnapshot() { |
debug_heap->Verify(); |
#endif |
- SetProgressTotal(1); // 1 pass. |
+ SetProgressTotal(2); // 2 passes. |
#ifdef VERIFY_HEAP |
debug_heap->Verify(); |