Index: src/heap-snapshot-generator.cc |
diff --git a/src/heap-snapshot-generator.cc b/src/heap-snapshot-generator.cc |
index 332d0dbf6ff3705318f28a666d7134667e12295c..b23b60f3f537a699735720cfb56b96762b51a58b 100644 |
--- a/src/heap-snapshot-generator.cc |
+++ b/src/heap-snapshot-generator.cc |
@@ -1101,10 +1101,8 @@ class IndexedReferencesExtractor : public ObjectVisitor { |
}; |
-void V8HeapExplorer::ExtractReferences(HeapObject* obj) { |
- HeapEntry* heap_entry = GetEntry(obj); |
- if (heap_entry == NULL) return; // No interest in this object. |
- int entry = heap_entry->index(); |
+bool V8HeapExplorer::ExtractReferencesPass1(int entry, HeapObject* obj) { |
+ if (obj->IsFixedArray()) return false; // FixedArrays are processed on pass 2 |
if (obj->IsJSGlobalProxy()) { |
ExtractJSGlobalProxyReferences(entry, JSGlobalProxy::cast(obj)); |
@@ -1114,8 +1112,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()) { |
@@ -1137,12 +1133,19 @@ void V8HeapExplorer::ExtractReferences(HeapObject* obj) { |
} else if (obj->IsAllocationSite()) { |
ExtractAllocationSiteReferences(entry, AllocationSite::cast(obj)); |
} |
- SetInternalReference(obj, entry, "map", obj->map(), HeapObject::kMapOffset); |
+ return true; |
+} |
+ |
- // Extract unvisited fields as hidden references and restore tags |
- // of visited fields. |
- IndexedReferencesExtractor refs_extractor(this, obj, entry); |
- obj->Iterate(&refs_extractor); |
+bool V8HeapExplorer::ExtractReferencesPass2(int entry, HeapObject* obj) { |
+ if (!obj->IsFixedArray()) return false; |
+ |
+ if (obj->IsContext()) { |
+ ExtractContextReferences(entry, Context::cast(obj)); |
+ } else { |
+ ExtractFixedArrayReferences(entry, FixedArray::cast(obj)); |
+ } |
+ return true; |
} |
@@ -1320,6 +1323,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 +1340,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 +1350,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 +1512,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 +1524,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 +1570,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 +1855,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 +1881,22 @@ 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) continue; |
+ |
+ HeapEntry* heap_entry = GetEntry(obj); |
+ int entry = heap_entry->index(); |
+ if ((this->*extractor)(entry, 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); |
} |
- } |
- if (interrupted) { |
- filler_ = NULL; |
- return false; |
- } |
- filler_ = NULL; |
- return progress_->ProgressReport(true); |
+ if (!progress_->ProgressReport(false)) interrupted = true; |
+ } |
+ return interrupted; |
} |
@@ -1987,6 +2032,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 +2177,13 @@ void V8HeapExplorer::TagObject(Object* obj, const char* tag) { |
} |
+void V8HeapExplorer::MarkAsWeakContainer(Object* object) { |
+ if (IsEssentialObject(object) && object->IsFixedArray()) { |
+ weak_containers_.Insert(object); |
+ } |
+} |
+ |
+ |
class GlobalObjectsEnumerator : public ObjectVisitor { |
public: |
virtual void VisitPointers(Object** start, Object** end) { |
@@ -2504,7 +2574,7 @@ bool HeapSnapshotGenerator::GenerateSnapshot() { |
debug_heap->Verify(); |
#endif |
- SetProgressTotal(1); // 1 pass. |
+ SetProgressTotal(2); // 2 passes. |
#ifdef VERIFY_HEAP |
debug_heap->Verify(); |