Chromium Code Reviews| 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(); |