Chromium Code Reviews| Index: src/profile-generator.cc |
| diff --git a/src/profile-generator.cc b/src/profile-generator.cc |
| index 29f9ab4d3536c4714639ce92caa65dcdb635bd0a..55ae56662796b92b28d16e0276fd22e8a6ab626d 100644 |
| --- a/src/profile-generator.cc |
| +++ b/src/profile-generator.cc |
| @@ -829,7 +829,10 @@ void ProfileGenerator::RecordTickSample(const TickSample& sample) { |
| void HeapGraphEdge::Init( |
| int child_index, Type type, const char* name, HeapEntry* to) { |
| - ASSERT(type == kContextVariable || type == kProperty || type == kInternal); |
| + ASSERT(type == kContextVariable |
| + || type == kProperty |
| + || type == kInternal |
| + || type == kShortcut); |
| child_index_ = child_index; |
| type_ = type; |
| name_ = name; |
| @@ -837,14 +840,20 @@ void HeapGraphEdge::Init( |
| } |
| -void HeapGraphEdge::Init(int child_index, int index, HeapEntry* to) { |
| +void HeapGraphEdge::Init(int child_index, Type type, int index, HeapEntry* to) { |
| + ASSERT(type == kElement || type == kHidden); |
| child_index_ = child_index; |
| - type_ = kElement; |
| + type_ = type; |
| index_ = index; |
| to_ = to; |
| } |
| +void HeapGraphEdge::Init(int child_index, int index, HeapEntry* to) { |
| + Init(child_index, kElement, index, to); |
| +} |
| + |
| + |
| HeapEntry* HeapGraphEdge::From() { |
| return reinterpret_cast<HeapEntry*>(this - child_index_) - 1; |
| } |
| @@ -879,9 +888,12 @@ void HeapEntry::SetNamedReference(HeapGraphEdge::Type type, |
| } |
| -void HeapEntry::SetElementReference( |
| - int child_index, int index, HeapEntry* entry, int retainer_index) { |
| - children_arr()[child_index].Init(child_index, index, entry); |
| +void HeapEntry::SetIndexedReference(HeapGraphEdge::Type type, |
| + int child_index, |
| + int index, |
| + HeapEntry* entry, |
| + int retainer_index) { |
| + children_arr()[child_index].Init(child_index, type, index, entry); |
| entry->retainers_arr()[retainer_index] = children_arr() + child_index; |
| } |
| @@ -929,6 +941,7 @@ void HeapEntry::ApplyAndPaintAllReachable(Visitor* visitor) { |
| HeapEntry* entry = list.RemoveLast(); |
| Vector<HeapGraphEdge> children = entry->children(); |
| for (int i = 0; i < children.length(); ++i) { |
| + if (children[i].type() == HeapGraphEdge::kShortcut) continue; |
| HeapEntry* child = children[i].to(); |
| if (!child->painted_reachable()) { |
| list.Add(child); |
| @@ -985,6 +998,12 @@ void HeapEntry::Print(int max_depth, int indent) { |
| case HeapGraphEdge::kProperty: |
| OS::Print(" %*c %s: ", indent, ' ', edge.name()); |
| break; |
| + case HeapGraphEdge::kHidden: |
| + OS::Print(" %*c $%d: ", indent, ' ', edge.index()); |
| + break; |
| + case HeapGraphEdge::kShortcut: |
| + OS::Print(" %*c ^%s: ", indent, ' ', edge.name()); |
| + break; |
| default: |
| OS::Print("!!! unknown edge type: %d ", edge.type()); |
| } |
| @@ -995,7 +1014,7 @@ void HeapEntry::Print(int max_depth, int indent) { |
| const char* HeapEntry::TypeAsString() { |
| switch (type()) { |
| - case kInternal: return "/internal/"; |
| + case kHidden: return "/hidden/"; |
| case kObject: return "/object/"; |
| case kClosure: return "/closure/"; |
| case kString: return "/string/"; |
| @@ -1094,6 +1113,7 @@ void HeapEntryCalculatedData::CalculateSizes(HeapEntry* entry) { |
| HeapEntry* curr = list.RemoveLast(); |
| Vector<HeapGraphEdge> children = curr->children(); |
| for (int i = 0; i < children.length(); ++i) { |
| + if (children[i].type() == HeapGraphEdge::kShortcut) continue; |
| HeapEntry* child = children[i].to(); |
| if (child != entry && child->not_painted_reachable_from_others()) { |
| list.Add(child); |
| @@ -1192,6 +1212,7 @@ void HeapGraphPath::Print() { |
| OS::Print("[#%s] ", edge->name()); |
| break; |
| case HeapGraphEdge::kElement: |
| + case HeapGraphEdge::kHidden: |
| OS::Print("[%d] ", edge->index()); |
| break; |
| case HeapGraphEdge::kInternal: |
| @@ -1200,6 +1221,9 @@ void HeapGraphPath::Print() { |
| case HeapGraphEdge::kProperty: |
| OS::Print("[%s] ", edge->name()); |
| break; |
| + case HeapGraphEdge::kShortcut: |
| + OS::Print("[^%s] ", edge->name()); |
| + break; |
| default: |
| OS::Print("!!! unknown edge type: %d ", edge->type()); |
| } |
| @@ -1211,6 +1235,8 @@ 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 |
| @@ -1240,6 +1266,7 @@ HeapSnapshot::HeapSnapshot(HeapSnapshotsCollection* collection, |
| title_(title), |
| uid_(uid), |
| root_entry_(NULL), |
| + gc_roots_entry_(NULL), |
| raw_entries_(NULL), |
| entries_sorted_(false) { |
| STATIC_ASSERT( |
| @@ -1280,9 +1307,20 @@ HeapEntry* HeapSnapshot::AddEntry(HeapObject* object, |
| if (object == kInternalRootObject) { |
| ASSERT(root_entry_ == NULL); |
| ASSERT(retainers_count == 0); |
| - root_entry_ = AddEntry( |
| - HeapEntry::kInternal, "", 0, 0, children_count, retainers_count); |
| - return root_entry_; |
| + 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(); |
| @@ -1345,22 +1383,11 @@ HeapEntry* HeapSnapshot::AddEntry(HeapObject* object, |
| children_count, |
| retainers_count); |
| } |
| - // No interest in this object. |
| - return NULL; |
| -} |
| - |
| - |
| -bool HeapSnapshot::WillAddEntry(HeapObject* object) { |
| - return object == kInternalRootObject |
| - || object->IsJSFunction() |
| - || object->IsJSRegExp() |
| - || object->IsJSObject() |
| - || object->IsString() |
| - || object->IsCode() |
| - || object->IsSharedFunctionInfo() |
| - || object->IsScript() |
| - || object->IsFixedArray() |
| - || object->IsHeapNumber(); |
| + return AddEntry(object, |
| + HeapEntry::kHidden, |
| + "system", |
| + children_count, |
| + retainers_count); |
| } |
| @@ -1387,7 +1414,7 @@ HeapEntry* HeapSnapshot::AddEntry(HeapObject* object, |
| return AddEntry(type, |
| name, |
| collection_->GetObjectId(object->address()), |
| - GetObjectSize(object), |
| + object->Size(), |
| children_count, |
| retainers_count); |
| } |
| @@ -1419,36 +1446,6 @@ HeapEntry* HeapSnapshot::GetNextEntryToInit() { |
| } |
| -int HeapSnapshot::GetObjectSize(HeapObject* obj) { |
| - return obj->IsJSObject() ? |
| - CalculateNetworkSize(JSObject::cast(obj)) : obj->Size(); |
| -} |
| - |
| - |
| -int HeapSnapshot::CalculateNetworkSize(JSObject* obj) { |
| - int size = obj->Size(); |
| - // If 'properties' and 'elements' are non-empty (thus, non-shared), |
| - // take their size into account. |
| - if (obj->properties() != Heap::empty_fixed_array()) { |
| - size += obj->properties()->Size(); |
| - } |
| - if (obj->elements() != Heap::empty_fixed_array()) { |
| - size += obj->elements()->Size(); |
| - } |
| - // For functions, also account non-empty context and literals sizes. |
| - if (obj->IsJSFunction()) { |
| - JSFunction* f = JSFunction::cast(obj); |
| - if (f->unchecked_context()->IsContext()) { |
| - size += f->context()->Size(); |
| - } |
| - if (f->literals()->length() != 0) { |
| - size += f->literals()->Size(); |
| - } |
| - } |
| - return size; |
| -} |
| - |
| - |
| HeapSnapshotsDiff* HeapSnapshot::CompareWith(HeapSnapshot* snapshot) { |
| return collection_->CompareSnapshots(this, snapshot); |
| } |
| @@ -1475,9 +1472,12 @@ void HeapSnapshot::Print(int max_depth) { |
| } |
| +const uint64_t HeapObjectsMap::kInternalRootObjectId = 0; |
| +const uint64_t HeapObjectsMap::kGcRootsObjectId = 1; |
|
Søren Thygesen Gjesse
2010/11/18 08:14:54
Please add kNumReservedObjectsIds = 2 (maybe you c
mnaganov (inactive)
2010/11/18 10:32:51
OK, I've introduced kFirstAvailableObjectId.
|
| + |
| HeapObjectsMap::HeapObjectsMap() |
| : initial_fill_mode_(true), |
| - next_id_(1), |
| + next_id_(2), // Reserve 0..1 for internal root objects. |
| entries_map_(AddressesMatch), |
| entries_(new List<EntryInfo>()) { } |
| @@ -1628,17 +1628,7 @@ HeapEntriesMap::HeapEntriesMap() |
| HeapEntriesMap::~HeapEntriesMap() { |
| for (HashMap::Entry* p = entries_.Start(); p != NULL; p = entries_.Next(p)) { |
| - if (!IsAlias(p->value)) delete reinterpret_cast<EntryInfo*>(p->value); |
| - } |
| -} |
| - |
| - |
| -void HeapEntriesMap::Alias(HeapObject* from, HeapObject* to) { |
| - HashMap::Entry* from_cache_entry = entries_.Lookup(from, Hash(from), true); |
| - HashMap::Entry* to_cache_entry = entries_.Lookup(to, Hash(to), false); |
| - if (from_cache_entry->value == NULL) { |
| - ASSERT(to_cache_entry != NULL); |
| - from_cache_entry->value = MakeAlias(to_cache_entry->value); |
| + delete reinterpret_cast<EntryInfo*>(p->value); |
| } |
| } |
| @@ -1646,8 +1636,7 @@ void HeapEntriesMap::Alias(HeapObject* from, HeapObject* to) { |
| HeapEntry* HeapEntriesMap::Map(HeapObject* object) { |
| HashMap::Entry* cache_entry = entries_.Lookup(object, Hash(object), false); |
| if (cache_entry != NULL) { |
| - EntryInfo* entry_info = |
| - reinterpret_cast<EntryInfo*>(Unalias(cache_entry->value)); |
| + EntryInfo* entry_info = reinterpret_cast<EntryInfo*>(cache_entry->value); |
| return entry_info->entry; |
| } else { |
| return NULL; |
| @@ -1671,9 +1660,9 @@ void HeapEntriesMap::CountReference(HeapObject* from, HeapObject* to, |
| ASSERT(from_cache_entry != NULL); |
| ASSERT(to_cache_entry != NULL); |
| EntryInfo* from_entry_info = |
| - reinterpret_cast<EntryInfo*>(Unalias(from_cache_entry->value)); |
| + reinterpret_cast<EntryInfo*>(from_cache_entry->value); |
| EntryInfo* to_entry_info = |
| - reinterpret_cast<EntryInfo*>(Unalias(to_cache_entry->value)); |
| + reinterpret_cast<EntryInfo*>(to_cache_entry->value); |
| if (prev_children_count) |
| *prev_children_count = from_entry_info->children_count; |
| if (prev_retainers_count) |
| @@ -1685,6 +1674,36 @@ void HeapEntriesMap::CountReference(HeapObject* from, HeapObject* to, |
| } |
| +HeapObjectsSet::HeapObjectsSet() |
| + : entries_(HeapEntriesMap::HeapObjectsMatch) { |
| +} |
| + |
| + |
| +void HeapObjectsSet::Clear() { |
| + entries_.Clear(); |
| +} |
| + |
| + |
| +bool HeapObjectsSet::Contains(Object* obj) { |
| + if (!obj->IsHeapObject()) return false; |
| + HeapObject* object = HeapObject::cast(obj); |
| + HashMap::Entry* cache_entry = |
| + entries_.Lookup(object, HeapEntriesMap::Hash(object), false); |
| + return cache_entry != NULL; |
| +} |
| + |
| + |
| +void HeapObjectsSet::Insert(Object* obj) { |
| + if (!obj->IsHeapObject()) return; |
| + HeapObject* object = HeapObject::cast(obj); |
| + HashMap::Entry* cache_entry = |
| + entries_.Lookup(object, HeapEntriesMap::Hash(object), true); |
| + if (cache_entry->value == NULL) { |
| + cache_entry->value = HeapEntriesMap::kHeapEntryPlaceholder; |
| + } |
| +} |
| + |
| + |
| HeapSnapshotGenerator::HeapSnapshotGenerator(HeapSnapshot* snapshot) |
| : snapshot_(snapshot), |
| collection_(snapshot->collection()), |
| @@ -1699,7 +1718,8 @@ class SnapshotCounter : public HeapSnapshotGenerator::SnapshotFillerInterface { |
| entries_->Pair(obj, HeapEntriesMap::kHeapEntryPlaceholder); |
| return HeapEntriesMap::kHeapEntryPlaceholder; |
| } |
| - void SetElementReference(HeapObject* parent_obj, |
| + void SetIndexedReference(HeapGraphEdge::Type, |
| + HeapObject* parent_obj, |
| HeapEntry*, |
| int, |
| Object* child_obj, |
| @@ -1714,10 +1734,18 @@ class SnapshotCounter : public HeapSnapshotGenerator::SnapshotFillerInterface { |
| HeapEntry*) { |
| entries_->CountReference(parent_obj, HeapObject::cast(child_obj)); |
| } |
| - void SetRootReference(Object* child_obj, HeapEntry*) { |
| + 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_; |
| }; |
| @@ -1733,16 +1761,19 @@ class SnapshotFiller : public HeapSnapshotGenerator::SnapshotFillerInterface { |
| UNREACHABLE(); |
| return NULL; |
| } |
| - void SetElementReference(HeapObject* parent_obj, |
| + 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->SetElementReference( |
| - child_index, index, child_entry, 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, |
| @@ -1759,13 +1790,43 @@ class SnapshotFiller : public HeapSnapshotGenerator::SnapshotFillerInterface { |
| child_entry, |
| retainer_index); |
| } |
| - void SetRootReference(Object* child_obj, HeapEntry* child_entry) { |
| + void SetRootGcRootsReference() { |
| int child_index, retainer_index; |
| - entries_->CountReference( |
| - HeapSnapshot::kInternalRootObject, HeapObject::cast(child_obj), |
| - &child_index, &retainer_index); |
| - snapshot_->root()->SetElementReference( |
| - child_index, child_index + 1, child_entry, 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_; |
| @@ -1788,6 +1849,18 @@ class SnapshotAllocator { |
| 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_; |
| +}; |
| + |
|
Søren Thygesen Gjesse
2010/11/18 08:14:54
Add empty line.
mnaganov (inactive)
2010/11/18 10:32:51
Done.
|
| void HeapSnapshotGenerator::GenerateSnapshot() { |
| AssertNoAllocation no_alloc; |
| @@ -1795,12 +1868,14 @@ void HeapSnapshotGenerator::GenerateSnapshot() { |
| SnapshotCounter counter(&entries_); |
| filler_ = &counter; |
| filler_->AddEntry(HeapSnapshot::kInternalRootObject); |
| - HeapIterator iterator1; |
| - for (HeapObject* obj = iterator1.next(); |
| - obj != NULL; |
| - obj = iterator1.next()) { |
| + filler_->AddEntry(HeapSnapshot::kGcRootsObject); |
| + HeapIterator iterator(HeapIterator::kPreciseFiltering); |
| + for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) { |
| ExtractReferences(obj); |
| } |
| + SetRootGcRootsReference(); |
| + RootsReferencesExtractor extractor(this); |
| + Heap::IterateRoots(&extractor, VISIT_ONLY_STRONG); |
| // Allocate and fill entries in the snapshot, allocate references. |
| snapshot_->AllocateEntries(entries_.entries_count(), |
| @@ -1812,12 +1887,12 @@ void HeapSnapshotGenerator::GenerateSnapshot() { |
| // Pass 2. Fill references. |
| SnapshotFiller filler(snapshot_, &entries_); |
| filler_ = &filler; |
| - HeapIterator iterator2; |
| - for (HeapObject* obj = iterator2.next(); |
| - obj != NULL; |
| - obj = iterator2.next()) { |
| + iterator.reset(); |
| + for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) { |
| ExtractReferences(obj); |
| } |
| + SetRootGcRootsReference(); |
| + Heap::IterateRoots(&extractor, VISIT_ONLY_STRONG); |
| } |
| @@ -1825,25 +1900,8 @@ 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) { |
| - if (obj->IsJSGlobalPropertyCell()) { |
| - Object* cell_target = JSGlobalPropertyCell::cast(obj)->value(); |
| - entry = GetEntry(cell_target); |
| - // If GPC references an object that we have interest in (see |
| - // HeapSnapshot::AddEntry, WillAddEntry), add the object. We |
| - // don't store HeapEntries for GPCs. Instead, we make our hash |
| - // map to point to object's HeapEntry by GPCs address. |
| - if (entry != NULL) { |
| - entries_.Alias(object, HeapObject::cast(cell_target)); |
| - } |
| - return entry; |
| - } |
| - |
| - if (snapshot_->WillAddEntry(object)) entry = filler_->AddEntry(object); |
| - } |
| - |
| + if (entry == NULL) entry = filler_->AddEntry(object); |
| return entry; |
| } |
| @@ -1852,43 +1910,44 @@ class IndexedReferencesExtractor : public ObjectVisitor { |
| public: |
| IndexedReferencesExtractor(HeapSnapshotGenerator* generator, |
| HeapObject* parent_obj, |
| - HeapEntry* parent_entry) |
| + HeapEntry* parent_entry, |
| + HeapObjectsSet* knownReferences = NULL) |
|
Søren Thygesen Gjesse
2010/11/18 08:14:54
knownReferences -> known_references
mnaganov (inactive)
2010/11/18 10:32:51
Done.
|
| : generator_(generator), |
| parent_obj_(parent_obj), |
| parent_(parent_entry), |
| + known_references_(knownReferences), |
| next_index_(1) { |
| } |
| - |
| - void VisitPointer(Object** o) { |
| - generator_->SetElementReference(parent_obj_, parent_, next_index_++, *o); |
| - } |
| - |
| void VisitPointers(Object** start, Object** end) { |
| - for (Object** p = start; p < end; p++) VisitPointer(p); |
| + for (Object** p = start; p < end; p++) { |
| + if (!known_references_ || !known_references_->Contains(*p)) { |
| + generator_->SetHiddenReference(parent_obj_, parent_, next_index_++, *p); |
| + } |
| + } |
| } |
| - |
| private: |
| HeapSnapshotGenerator* generator_; |
| HeapObject* parent_obj_; |
| HeapEntry* parent_; |
| + HeapObjectsSet* known_references_; |
| int next_index_; |
| }; |
| void HeapSnapshotGenerator::ExtractReferences(HeapObject* obj) { |
| - // We need to reference JS global objects from snapshot's root. |
| - // We use JSGlobalProxy because this is what embedder (e.g. browser) |
| - // uses for the global object. |
| - if (obj->IsJSGlobalProxy()) { |
| - JSGlobalProxy* proxy = JSGlobalProxy::cast(obj); |
| - SetRootReference(proxy->map()->prototype()); |
| - return; |
| - } |
| - |
| HeapEntry* entry = GetEntry(obj); |
| if (entry == NULL) return; // No interest in this object. |
| - if (obj->IsJSObject()) { |
| + known_references_.Clear(); |
| + if (obj->IsJSGlobalProxy()) { |
| + // We need to reference JS global objects from snapshot's root. |
| + // We use JSGlobalProxy because this is what embedder (e.g. browser) |
| + // uses for the global object. |
| + JSGlobalProxy* proxy = JSGlobalProxy::cast(obj); |
| + SetRootShortcutReference(proxy->map()->prototype()); |
| + IndexedReferencesExtractor refs_extractor(this, obj, entry); |
| + obj->Iterate(&refs_extractor); |
| + } else if (obj->IsJSObject()) { |
| JSObject* js_obj = JSObject::cast(obj); |
| ExtractClosureReferences(js_obj, entry); |
| ExtractPropertyReferences(js_obj, entry); |
| @@ -1903,16 +1962,16 @@ void HeapSnapshotGenerator::ExtractReferences(HeapObject* obj) { |
| obj, entry, Heap::prototype_symbol(), js_fun->prototype()); |
| } |
| } |
| + IndexedReferencesExtractor refs_extractor( |
| + this, obj, entry, &known_references_); |
| + obj->Iterate(&refs_extractor); |
| } else if (obj->IsString()) { |
| if (obj->IsConsString()) { |
| ConsString* cs = ConsString::cast(obj); |
| - SetInternalReference(obj, entry, "1", cs->first()); |
| - SetInternalReference(obj, entry, "2", cs->second()); |
| + SetInternalReference(obj, entry, 1, cs->first()); |
| + SetInternalReference(obj, entry, 2, cs->second()); |
| } |
| - } else if (obj->IsCode() || obj->IsSharedFunctionInfo() || obj->IsScript()) { |
| - IndexedReferencesExtractor refs_extractor(this, obj, entry); |
| - obj->Iterate(&refs_extractor); |
| - } else if (obj->IsFixedArray()) { |
| + } else { |
| IndexedReferencesExtractor refs_extractor(this, obj, entry); |
| obj->Iterate(&refs_extractor); |
| } |
| @@ -1967,8 +2026,17 @@ void HeapSnapshotGenerator::ExtractPropertyReferences(JSObject* js_obj, |
| for (int i = 0; i < length; ++i) { |
| Object* k = dictionary->KeyAt(i); |
| if (dictionary->IsKey(k)) { |
| + Object* target = dictionary->ValueAt(i); |
| SetPropertyReference( |
| - js_obj, entry, String::cast(k), dictionary->ValueAt(i)); |
| + js_obj, entry, String::cast(k), target); |
| + // We assume that global objects can only have slow properties. |
| + if (target->IsJSGlobalPropertyCell()) { |
| + SetPropertyShortcutReference(js_obj, |
| + entry, |
| + String::cast(k), |
| + JSGlobalPropertyCell::cast( |
| + target)->value()); |
| + } |
| } |
| } |
| } |
| @@ -2024,6 +2092,7 @@ void HeapSnapshotGenerator::SetClosureReference(HeapObject* parent_obj, |
| collection_->GetName(reference_name), |
| child_obj, |
| child_entry); |
| + known_references_.Insert(child_obj); |
| } |
| } |
| @@ -2034,8 +2103,13 @@ void HeapSnapshotGenerator::SetElementReference(HeapObject* parent_obj, |
| Object* child_obj) { |
| HeapEntry* child_entry = GetEntry(child_obj); |
| if (child_entry != NULL) { |
| - filler_->SetElementReference( |
| - parent_obj, parent_entry, index, child_obj, child_entry); |
| + filler_->SetIndexedReference(HeapGraphEdge::kElement, |
| + parent_obj, |
| + parent_entry, |
| + index, |
| + child_obj, |
| + child_entry); |
| + known_references_.Insert(child_obj); |
| } |
| } |
| @@ -2052,6 +2126,7 @@ void HeapSnapshotGenerator::SetInternalReference(HeapObject* parent_obj, |
| reference_name, |
| child_obj, |
| child_entry); |
| + known_references_.Insert(child_obj); |
| } |
| } |
| @@ -2068,6 +2143,23 @@ void HeapSnapshotGenerator::SetInternalReference(HeapObject* parent_obj, |
| collection_->GetName(index), |
| child_obj, |
| child_entry); |
| + known_references_.Insert(child_obj); |
| + } |
| +} |
| + |
| + |
| +void HeapSnapshotGenerator::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, |
| + parent_obj, |
| + parent_entry, |
| + index, |
| + child_obj, |
| + child_entry); |
| } |
| } |
| @@ -2086,14 +2178,45 @@ void HeapSnapshotGenerator::SetPropertyReference(HeapObject* parent_obj, |
| collection_->GetName(reference_name), |
| child_obj, |
| child_entry); |
| + known_references_.Insert(child_obj); |
| } |
| } |
| -void HeapSnapshotGenerator::SetRootReference(Object* child_obj) { |
| +void HeapSnapshotGenerator::SetPropertyShortcutReference( |
| + 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::kShortcut, |
| + parent_obj, |
| + parent_entry, |
| + collection_->GetName(reference_name), |
| + child_obj, |
| + child_entry); |
| + } |
| +} |
| + |
| + |
| +void HeapSnapshotGenerator::SetRootGcRootsReference() { |
| + filler_->SetRootGcRootsReference(); |
| +} |
| + |
| + |
| +void HeapSnapshotGenerator::SetRootShortcutReference(Object* child_obj) { |
| HeapEntry* child_entry = GetEntry(child_obj); |
| ASSERT(child_entry != NULL); |
| - filler_->SetRootReference(child_obj, child_entry); |
| + filler_->SetRootShortcutReference(child_obj, child_entry); |
| +} |
| + |
| + |
| +void HeapSnapshotGenerator::SetGcRootsReference(Object* child_obj) { |
| + HeapEntry* child_entry = GetEntry(child_obj); |
| + if (child_entry != NULL) { |
| + filler_->SetStrongRootReference(child_obj, child_entry); |
| + } |
| } |
| @@ -2101,11 +2224,11 @@ void HeapSnapshotsDiff::CreateRoots(int additions_count, int deletions_count) { |
| raw_additions_root_ = |
| NewArray<char>(HeapEntry::EntriesSize(1, additions_count, 0)); |
| additions_root()->Init( |
| - snapshot2_, HeapEntry::kInternal, "", 0, 0, additions_count, 0); |
| + snapshot2_, HeapEntry::kHidden, "", 0, 0, additions_count, 0); |
| raw_deletions_root_ = |
| NewArray<char>(HeapEntry::EntriesSize(1, deletions_count, 0)); |
| deletions_root()->Init( |
| - snapshot1_, HeapEntry::kInternal, "", 0, 0, deletions_count, 0); |
| + snapshot1_, HeapEntry::kHidden, "", 0, 0, deletions_count, 0); |
| } |
| @@ -2324,7 +2447,8 @@ void HeapSnapshotJSONSerializer::SerializeEdge(HeapGraphEdge* edge) { |
| writer_->AddCharacter(','); |
| writer_->AddNumber(edge->type()); |
| writer_->AddCharacter(','); |
| - if (edge->type() == HeapGraphEdge::kElement) { |
| + if (edge->type() == HeapGraphEdge::kElement |
| + || edge->type() == HeapGraphEdge::kHidden) { |
| writer_->AddNumber(edge->index()); |
| } else { |
| writer_->AddNumber(GetStringId(edge->name())); |
| @@ -2355,13 +2479,13 @@ void HeapSnapshotJSONSerializer::SerializeNode(HeapEntry* entry) { |
| void HeapSnapshotJSONSerializer::SerializeNodes() { |
| - // The first (zero) item of nodes array is a JSON-ified object |
| - // describing node serialization layout. |
| - // We use a set of macros to improve readability. |
| + // The first (zero) item of nodes array is an object describing node |
| + // serialization layout. We use a set of macros to improve |
| + // readability. |
| #define JSON_A(s) "["s"]" |
| #define JSON_O(s) "{"s"}" |
| -#define JSON_S(s) "\\\""s"\\\"" |
| - writer_->AddString("\"" JSON_O( |
| +#define JSON_S(s) "\""s"\"" |
| + writer_->AddString(JSON_O( |
| JSON_S("fields") ":" JSON_A( |
| JSON_S("type") |
| "," JSON_S("name") |
| @@ -2371,7 +2495,7 @@ void HeapSnapshotJSONSerializer::SerializeNodes() { |
| "," JSON_S("children")) |
| "," JSON_S("types") ":" JSON_A( |
| JSON_A( |
| - JSON_S("internal") |
| + JSON_S("hidden") |
| "," JSON_S("array") |
| "," JSON_S("string") |
| "," JSON_S("object") |
| @@ -2393,9 +2517,11 @@ void HeapSnapshotJSONSerializer::SerializeNodes() { |
| JSON_S("context") |
| "," JSON_S("element") |
| "," JSON_S("property") |
| - "," JSON_S("internal")) |
| + "," JSON_S("internal") |
| + "," JSON_S("hidden") |
| + "," JSON_S("shortcut")) |
| "," JSON_S("string_or_number") |
| - "," JSON_S("node"))))) "\""); |
| + "," JSON_S("node")))))); |
| #undef JSON_S |
| #undef JSON_O |
| #undef JSON_A |