| 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();
|
|
|