| Index: src/profile-generator.cc
|
| ===================================================================
|
| --- src/profile-generator.cc (revision 7006)
|
| +++ src/profile-generator.cc (working copy)
|
| @@ -158,13 +158,18 @@
|
|
|
| uint32_t CodeEntry::GetCallUid() const {
|
| uint32_t hash = ComputeIntegerHash(tag_);
|
| - hash ^= ComputeIntegerHash(
|
| - static_cast<uint32_t>(reinterpret_cast<uintptr_t>(name_prefix_)));
|
| - hash ^= ComputeIntegerHash(
|
| - static_cast<uint32_t>(reinterpret_cast<uintptr_t>(name_)));
|
| - hash ^= ComputeIntegerHash(
|
| - static_cast<uint32_t>(reinterpret_cast<uintptr_t>(resource_name_)));
|
| - hash ^= ComputeIntegerHash(line_number_);
|
| + if (shared_id_ != 0) {
|
| + hash ^= ComputeIntegerHash(
|
| + static_cast<uint32_t>(shared_id_));
|
| + } else {
|
| + hash ^= ComputeIntegerHash(
|
| + static_cast<uint32_t>(reinterpret_cast<uintptr_t>(name_prefix_)));
|
| + hash ^= ComputeIntegerHash(
|
| + static_cast<uint32_t>(reinterpret_cast<uintptr_t>(name_)));
|
| + hash ^= ComputeIntegerHash(
|
| + static_cast<uint32_t>(reinterpret_cast<uintptr_t>(resource_name_)));
|
| + hash ^= ComputeIntegerHash(line_number_);
|
| + }
|
| return hash;
|
| }
|
|
|
| @@ -172,10 +177,12 @@
|
| bool CodeEntry::IsSameAs(CodeEntry* entry) const {
|
| return this == entry
|
| || (tag_ == entry->tag_
|
| - && name_prefix_ == entry->name_prefix_
|
| - && name_ == entry->name_
|
| - && resource_name_ == entry->resource_name_
|
| - && line_number_ == entry->line_number_);
|
| + && shared_id_ == entry->shared_id_
|
| + && (shared_id_ != 0
|
| + || (name_prefix_ == entry->name_prefix_
|
| + && name_ == entry->name_
|
| + && resource_name_ == entry->resource_name_
|
| + && line_number_ == entry->line_number_)));
|
| }
|
|
|
|
|
| @@ -460,23 +467,12 @@
|
| }
|
|
|
|
|
| +CodeEntry* const CodeMap::kSfiCodeEntry = NULL;
|
| const CodeMap::CodeTreeConfig::Key CodeMap::CodeTreeConfig::kNoKey = NULL;
|
| const CodeMap::CodeTreeConfig::Value CodeMap::CodeTreeConfig::kNoValue =
|
| CodeMap::CodeEntryInfo(NULL, 0);
|
|
|
|
|
| -void CodeMap::AddAlias(Address start, CodeEntry* entry, Address code_start) {
|
| - CodeTree::Locator locator;
|
| - if (tree_.Find(code_start, &locator)) {
|
| - const CodeEntryInfo& code_info = locator.value();
|
| - if (tree_.Insert(start, &locator)) {
|
| - entry->CopyData(*code_info.entry);
|
| - locator.set_value(CodeEntryInfo(entry, code_info.size));
|
| - }
|
| - }
|
| -}
|
| -
|
| -
|
| CodeEntry* CodeMap::FindEntry(Address addr) {
|
| CodeTree::Locator locator;
|
| if (tree_.FindGreatestLessThan(addr, &locator)) {
|
| @@ -489,6 +485,22 @@
|
| }
|
|
|
|
|
| +int CodeMap::GetSFITag(Address addr) {
|
| + CodeTree::Locator locator;
|
| + // For SFI entries, 'size' field is used to store their IDs.
|
| + if (tree_.Find(addr, &locator)) {
|
| + const CodeEntryInfo& entry = locator.value();
|
| + ASSERT(entry.entry == kSfiCodeEntry);
|
| + return entry.size;
|
| + } else {
|
| + tree_.Insert(addr, &locator);
|
| + int tag = next_sfi_tag_++;
|
| + locator.set_value(CodeEntryInfo(kSfiCodeEntry, tag));
|
| + return tag;
|
| + }
|
| +}
|
| +
|
| +
|
| void CodeMap::CodeTreePrinter::Call(
|
| const Address& key, const CodeMap::CodeEntryInfo& value) {
|
| OS::Print("%p %5d %s\n", key, value.size, value.entry->name());
|
| @@ -717,13 +729,6 @@
|
| }
|
|
|
|
|
| -CodeEntry* CpuProfilesCollection::NewCodeEntry(int security_token_id) {
|
| - CodeEntry* entry = new CodeEntry(security_token_id);
|
| - code_entries_.Add(entry);
|
| - return entry;
|
| -}
|
| -
|
| -
|
| void CpuProfilesCollection::AddPathToCurrentProfiles(
|
| const Vector<CodeEntry*>& path) {
|
| // As starting / stopping profiles is rare relatively to this
|
| @@ -788,19 +793,10 @@
|
| if (sample.pc != NULL) {
|
| *entry++ = code_map_.FindEntry(sample.pc);
|
|
|
| - if (sample.function != NULL) {
|
| - *entry = code_map_.FindEntry(sample.function);
|
| + if (sample.tos != NULL) {
|
| + *entry = code_map_.FindEntry(sample.tos);
|
| if (*entry != NULL && !(*entry)->is_js_function()) {
|
| *entry = NULL;
|
| - } else {
|
| - CodeEntry* pc_entry = *entries.start();
|
| - if (pc_entry == NULL) {
|
| - *entry = NULL;
|
| - } else if (pc_entry->is_js_function()) {
|
| - // Use function entry in favor of pc entry, as function
|
| - // entry has security token.
|
| - *entries.start() = NULL;
|
| - }
|
| }
|
| entry++;
|
| }
|
| @@ -1185,12 +1181,6 @@
|
| }
|
|
|
|
|
| -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
|
| // as small as possible.
|
| namespace { // Avoid littering the global namespace.
|
| @@ -1261,96 +1251,6 @@
|
| }
|
|
|
|
|
| -HeapEntry* HeapSnapshot::AddEntry(HeapObject* object,
|
| - int children_count,
|
| - int retainers_count) {
|
| - if (object == kInternalRootObject) {
|
| - ASSERT(root_entry_ == NULL);
|
| - ASSERT(retainers_count == 0);
|
| - 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();
|
| - return AddEntry(object,
|
| - HeapEntry::kClosure,
|
| - collection_->GetName(String::cast(shared->name())),
|
| - children_count,
|
| - retainers_count);
|
| - } else if (object->IsJSRegExp()) {
|
| - JSRegExp* re = JSRegExp::cast(object);
|
| - return AddEntry(object,
|
| - HeapEntry::kRegExp,
|
| - collection_->GetName(re->Pattern()),
|
| - children_count,
|
| - retainers_count);
|
| - } else if (object->IsJSObject()) {
|
| - return AddEntry(object,
|
| - HeapEntry::kObject,
|
| - collection_->GetName(GetConstructorNameForHeapProfile(
|
| - JSObject::cast(object))),
|
| - children_count,
|
| - retainers_count);
|
| - } else if (object->IsString()) {
|
| - return AddEntry(object,
|
| - HeapEntry::kString,
|
| - collection_->GetName(String::cast(object)),
|
| - children_count,
|
| - retainers_count);
|
| - } else if (object->IsCode()) {
|
| - return AddEntry(object,
|
| - HeapEntry::kCode,
|
| - "",
|
| - children_count,
|
| - retainers_count);
|
| - } else if (object->IsSharedFunctionInfo()) {
|
| - SharedFunctionInfo* shared = SharedFunctionInfo::cast(object);
|
| - return AddEntry(object,
|
| - HeapEntry::kCode,
|
| - collection_->GetName(String::cast(shared->name())),
|
| - children_count,
|
| - retainers_count);
|
| - } else if (object->IsScript()) {
|
| - Script* script = Script::cast(object);
|
| - return AddEntry(object,
|
| - HeapEntry::kCode,
|
| - script->name()->IsString() ?
|
| - collection_->GetName(String::cast(script->name())) : "",
|
| - children_count,
|
| - retainers_count);
|
| - } else if (object->IsFixedArray()) {
|
| - return AddEntry(object,
|
| - HeapEntry::kArray,
|
| - "",
|
| - children_count,
|
| - retainers_count);
|
| - } else if (object->IsHeapNumber()) {
|
| - return AddEntry(object,
|
| - HeapEntry::kHeapNumber,
|
| - "number",
|
| - children_count,
|
| - retainers_count);
|
| - }
|
| - return AddEntry(object,
|
| - HeapEntry::kHidden,
|
| - "system",
|
| - children_count,
|
| - retainers_count);
|
| -}
|
| -
|
| -
|
| static void HeapEntryClearPaint(HeapEntry** entry_ptr) {
|
| (*entry_ptr)->clear_paint();
|
| }
|
| @@ -1360,20 +1260,29 @@
|
| }
|
|
|
|
|
| -HeapEntry* HeapSnapshot::AddEntry(HeapObject* object,
|
| - HeapEntry::Type type,
|
| - const char* name,
|
| - int children_count,
|
| - int retainers_count) {
|
| - return AddEntry(type,
|
| - name,
|
| - collection_->GetObjectId(object->address()),
|
| - object->Size(),
|
| - children_count,
|
| - retainers_count);
|
| +HeapEntry* HeapSnapshot::AddRootEntry(int children_count) {
|
| + ASSERT(root_entry_ == NULL);
|
| + return (root_entry_ = AddEntry(HeapEntry::kObject,
|
| + "",
|
| + HeapObjectsMap::kInternalRootObjectId,
|
| + 0,
|
| + children_count,
|
| + 0));
|
| }
|
|
|
|
|
| +HeapEntry* HeapSnapshot::AddGcRootsEntry(int children_count,
|
| + int retainers_count) {
|
| + ASSERT(gc_roots_entry_ == NULL);
|
| + return (gc_roots_entry_ = AddEntry(HeapEntry::kObject,
|
| + "(GC roots)",
|
| + HeapObjectsMap::kGcRootsObjectId,
|
| + 0,
|
| + children_count,
|
| + retainers_count));
|
| +}
|
| +
|
| +
|
| HeapEntry* HeapSnapshot::AddEntry(HeapEntry::Type type,
|
| const char* name,
|
| uint64_t id,
|
| @@ -1623,7 +1532,7 @@
|
| reinterpret_cast<HeapEntry*>(1);
|
|
|
| HeapEntriesMap::HeapEntriesMap()
|
| - : entries_(HeapObjectsMatch),
|
| + : entries_(HeapThingsMatch),
|
| entries_count_(0),
|
| total_children_count_(0),
|
| total_retainers_count_(0) {
|
| @@ -1637,8 +1546,23 @@
|
| }
|
|
|
|
|
| -HeapEntry* HeapEntriesMap::Map(HeapObject* object) {
|
| - HashMap::Entry* cache_entry = entries_.Lookup(object, Hash(object), false);
|
| +void HeapEntriesMap::AllocateEntries() {
|
| + for (HashMap::Entry* p = entries_.Start();
|
| + p != NULL;
|
| + p = entries_.Next(p)) {
|
| + EntryInfo* entry_info = reinterpret_cast<EntryInfo*>(p->value);
|
| + entry_info->entry = entry_info->allocator->AllocateEntry(
|
| + p->key,
|
| + entry_info->children_count,
|
| + entry_info->retainers_count);
|
| + entry_info->children_count = 0;
|
| + entry_info->retainers_count = 0;
|
| + }
|
| +}
|
| +
|
| +
|
| +HeapEntry* HeapEntriesMap::Map(HeapThing thing) {
|
| + HashMap::Entry* cache_entry = entries_.Lookup(thing, Hash(thing), false);
|
| if (cache_entry != NULL) {
|
| EntryInfo* entry_info = reinterpret_cast<EntryInfo*>(cache_entry->value);
|
| return entry_info->entry;
|
| @@ -1648,15 +1572,16 @@
|
| }
|
|
|
|
|
| -void HeapEntriesMap::Pair(HeapObject* object, HeapEntry* entry) {
|
| - HashMap::Entry* cache_entry = entries_.Lookup(object, Hash(object), true);
|
| +void HeapEntriesMap::Pair(
|
| + HeapThing thing, HeapEntriesAllocator* allocator, HeapEntry* entry) {
|
| + HashMap::Entry* cache_entry = entries_.Lookup(thing, Hash(thing), true);
|
| ASSERT(cache_entry->value == NULL);
|
| - cache_entry->value = new EntryInfo(entry);
|
| + cache_entry->value = new EntryInfo(entry, allocator);
|
| ++entries_count_;
|
| }
|
|
|
|
|
| -void HeapEntriesMap::CountReference(HeapObject* from, HeapObject* to,
|
| +void HeapEntriesMap::CountReference(HeapThing from, HeapThing to,
|
| int* prev_children_count,
|
| int* prev_retainers_count) {
|
| HashMap::Entry* from_cache_entry = entries_.Lookup(from, Hash(from), false);
|
| @@ -1679,7 +1604,7 @@
|
|
|
|
|
| HeapObjectsSet::HeapObjectsSet()
|
| - : entries_(HeapEntriesMap::HeapObjectsMatch) {
|
| + : entries_(HeapEntriesMap::HeapThingsMatch) {
|
| }
|
|
|
|
|
| @@ -1708,206 +1633,144 @@
|
| }
|
|
|
|
|
| -HeapSnapshotGenerator::HeapSnapshotGenerator(HeapSnapshot* snapshot,
|
| - v8::ActivityControl* control)
|
| +HeapObject *const V8HeapExplorer::kInternalRootObject =
|
| + reinterpret_cast<HeapObject*>(1);
|
| +HeapObject *const V8HeapExplorer::kGcRootsObject =
|
| + reinterpret_cast<HeapObject*>(2);
|
| +
|
| +
|
| +V8HeapExplorer::V8HeapExplorer(
|
| + HeapSnapshot* snapshot,
|
| + SnapshottingProgressReportingInterface* progress)
|
| : snapshot_(snapshot),
|
| - control_(control),
|
| - collection_(snapshot->collection()),
|
| + collection_(snapshot_->collection()),
|
| + progress_(progress),
|
| filler_(NULL) {
|
| }
|
|
|
| -class SnapshotCounter : public HeapSnapshotGenerator::SnapshotFillerInterface {
|
| - public:
|
| - explicit SnapshotCounter(HeapEntriesMap* entries)
|
| - : entries_(entries) { }
|
| - HeapEntry* AddEntry(HeapObject* obj) {
|
| - entries_->Pair(obj, HeapEntriesMap::kHeapEntryPlaceholder);
|
| - return HeapEntriesMap::kHeapEntryPlaceholder;
|
| - }
|
| - void SetIndexedReference(HeapGraphEdge::Type,
|
| - HeapObject* parent_obj,
|
| - HeapEntry*,
|
| - int,
|
| - Object* child_obj,
|
| - HeapEntry*) {
|
| - entries_->CountReference(parent_obj, HeapObject::cast(child_obj));
|
| - }
|
| - void SetNamedReference(HeapGraphEdge::Type,
|
| - HeapObject* parent_obj,
|
| - HeapEntry*,
|
| - const char*,
|
| - Object* child_obj,
|
| - HeapEntry*) {
|
| - entries_->CountReference(parent_obj, HeapObject::cast(child_obj));
|
| - }
|
| - 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_;
|
| -};
|
|
|
| +V8HeapExplorer::~V8HeapExplorer() {
|
| +}
|
|
|
| -class SnapshotFiller : public HeapSnapshotGenerator::SnapshotFillerInterface {
|
| - public:
|
| - explicit SnapshotFiller(HeapSnapshot* snapshot, HeapEntriesMap* entries)
|
| - : snapshot_(snapshot),
|
| - collection_(snapshot->collection()),
|
| - entries_(entries) { }
|
| - HeapEntry* AddEntry(HeapObject* obj) {
|
| - UNREACHABLE();
|
| - return NULL;
|
| - }
|
| - 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->SetIndexedReference(
|
| - type, child_index, index, child_entry, retainer_index);
|
| - }
|
| - void SetNamedReference(HeapGraphEdge::Type type,
|
| - HeapObject* parent_obj,
|
| - HeapEntry* parent_entry,
|
| - const char* reference_name,
|
| - 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->SetNamedReference(type,
|
| - child_index,
|
| - reference_name,
|
| - child_entry,
|
| - retainer_index);
|
| - }
|
| - void SetRootGcRootsReference() {
|
| - int child_index, 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_;
|
| - HeapSnapshotsCollection* collection_;
|
| - HeapEntriesMap* entries_;
|
| -};
|
|
|
| -class SnapshotAllocator {
|
| - public:
|
| - explicit SnapshotAllocator(HeapSnapshot* snapshot)
|
| - : snapshot_(snapshot) { }
|
| - HeapEntry* GetEntry(
|
| - HeapObject* obj, int children_count, int retainers_count) {
|
| - HeapEntry* entry =
|
| - snapshot_->AddEntry(obj, children_count, retainers_count);
|
| - ASSERT(entry != NULL);
|
| - return entry;
|
| - }
|
| - private:
|
| - HeapSnapshot* snapshot_;
|
| -};
|
| +HeapEntry* V8HeapExplorer::AllocateEntry(
|
| + HeapThing ptr, int children_count, int retainers_count) {
|
| + return AddEntry(
|
| + reinterpret_cast<HeapObject*>(ptr), children_count, retainers_count);
|
| +}
|
|
|
| -class RootsReferencesExtractor : public ObjectVisitor {
|
| - public:
|
| - explicit RootsReferencesExtractor(HeapSnapshotGenerator* generator)
|
| - : generator_(generator) {
|
| +
|
| +HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object,
|
| + int children_count,
|
| + int retainers_count) {
|
| + if (object == kInternalRootObject) {
|
| + ASSERT(retainers_count == 0);
|
| + return snapshot_->AddRootEntry(children_count);
|
| + } else if (object == kGcRootsObject) {
|
| + return snapshot_->AddGcRootsEntry(children_count, retainers_count);
|
| + } else if (object->IsJSFunction()) {
|
| + JSFunction* func = JSFunction::cast(object);
|
| + SharedFunctionInfo* shared = func->shared();
|
| + return AddEntry(object,
|
| + HeapEntry::kClosure,
|
| + collection_->GetName(String::cast(shared->name())),
|
| + children_count,
|
| + retainers_count);
|
| + } else if (object->IsJSRegExp()) {
|
| + JSRegExp* re = JSRegExp::cast(object);
|
| + return AddEntry(object,
|
| + HeapEntry::kRegExp,
|
| + collection_->GetName(re->Pattern()),
|
| + children_count,
|
| + retainers_count);
|
| + } else if (object->IsJSObject()) {
|
| + return AddEntry(object,
|
| + HeapEntry::kObject,
|
| + collection_->GetName(GetConstructorNameForHeapProfile(
|
| + JSObject::cast(object))),
|
| + children_count,
|
| + retainers_count);
|
| + } else if (object->IsString()) {
|
| + return AddEntry(object,
|
| + HeapEntry::kString,
|
| + collection_->GetName(String::cast(object)),
|
| + children_count,
|
| + retainers_count);
|
| + } else if (object->IsCode()) {
|
| + return AddEntry(object,
|
| + HeapEntry::kCode,
|
| + "",
|
| + children_count,
|
| + retainers_count);
|
| + } else if (object->IsSharedFunctionInfo()) {
|
| + SharedFunctionInfo* shared = SharedFunctionInfo::cast(object);
|
| + return AddEntry(object,
|
| + HeapEntry::kCode,
|
| + collection_->GetName(String::cast(shared->name())),
|
| + children_count,
|
| + retainers_count);
|
| + } else if (object->IsScript()) {
|
| + Script* script = Script::cast(object);
|
| + return AddEntry(object,
|
| + HeapEntry::kCode,
|
| + script->name()->IsString() ?
|
| + collection_->GetName(String::cast(script->name())) : "",
|
| + children_count,
|
| + retainers_count);
|
| + } else if (object->IsFixedArray()) {
|
| + return AddEntry(object,
|
| + HeapEntry::kArray,
|
| + "",
|
| + children_count,
|
| + retainers_count);
|
| + } else if (object->IsHeapNumber()) {
|
| + return AddEntry(object,
|
| + HeapEntry::kHeapNumber,
|
| + "number",
|
| + children_count,
|
| + retainers_count);
|
| }
|
| - void VisitPointers(Object** start, Object** end) {
|
| - for (Object** p = start; p < end; p++) generator_->SetGcRootsReference(*p);
|
| - }
|
| - private:
|
| - HeapSnapshotGenerator* generator_;
|
| -};
|
| + return AddEntry(object,
|
| + HeapEntry::kHidden,
|
| + "system",
|
| + children_count,
|
| + retainers_count);
|
| +}
|
|
|
|
|
| -bool HeapSnapshotGenerator::GenerateSnapshot() {
|
| - AssertNoAllocation no_alloc;
|
| +HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object,
|
| + HeapEntry::Type type,
|
| + const char* name,
|
| + int children_count,
|
| + int retainers_count) {
|
| + return snapshot_->AddEntry(type,
|
| + name,
|
| + collection_->GetObjectId(object->address()),
|
| + object->Size(),
|
| + children_count,
|
| + retainers_count);
|
| +}
|
|
|
| - SetProgressTotal(4); // 2 passes + dominators + sizes.
|
|
|
| - // Pass 1. Iterate heap contents to count entries and references.
|
| - if (!CountEntriesAndReferences()) return false;
|
| -
|
| - // Allocate and fill entries in the snapshot, allocate references.
|
| - snapshot_->AllocateEntries(entries_.entries_count(),
|
| - entries_.total_children_count(),
|
| - entries_.total_retainers_count());
|
| - SnapshotAllocator allocator(snapshot_);
|
| - entries_.UpdateEntries(&allocator);
|
| -
|
| - // Pass 2. Fill references.
|
| - if (!FillReferences()) return false;
|
| -
|
| - if (!SetEntriesDominators()) return false;
|
| - if (!ApproximateRetainedSizes()) return false;
|
| -
|
| - progress_counter_ = progress_total_;
|
| - if (!ReportProgress(true)) return false;
|
| - return true;
|
| +void V8HeapExplorer::AddRootEntries(SnapshotFillerInterface* filler) {
|
| + filler->AddEntry(kInternalRootObject);
|
| + filler->AddEntry(kGcRootsObject);
|
| }
|
|
|
|
|
| -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) entry = filler_->AddEntry(object);
|
| - return entry;
|
| +int V8HeapExplorer::EstimateObjectsCount() {
|
| + HeapIterator iterator(HeapIterator::kFilterUnreachable);
|
| + int objects_count = 0;
|
| + for (HeapObject* obj = iterator.next();
|
| + obj != NULL;
|
| + obj = iterator.next(), ++objects_count) {}
|
| + return objects_count;
|
| }
|
|
|
|
|
| class IndexedReferencesExtractor : public ObjectVisitor {
|
| public:
|
| - IndexedReferencesExtractor(HeapSnapshotGenerator* generator,
|
| + IndexedReferencesExtractor(V8HeapExplorer* generator,
|
| HeapObject* parent_obj,
|
| HeapEntry* parent_entry,
|
| HeapObjectsSet* known_references = NULL)
|
| @@ -1925,7 +1788,7 @@
|
| }
|
| }
|
| private:
|
| - HeapSnapshotGenerator* generator_;
|
| + V8HeapExplorer* generator_;
|
| HeapObject* parent_obj_;
|
| HeapEntry* parent_;
|
| HeapObjectsSet* known_references_;
|
| @@ -1933,7 +1796,7 @@
|
| };
|
|
|
|
|
| -void HeapSnapshotGenerator::ExtractReferences(HeapObject* obj) {
|
| +void V8HeapExplorer::ExtractReferences(HeapObject* obj) {
|
| HeapEntry* entry = GetEntry(obj);
|
| if (entry == NULL) return; // No interest in this object.
|
|
|
| @@ -1977,8 +1840,8 @@
|
| }
|
|
|
|
|
| -void HeapSnapshotGenerator::ExtractClosureReferences(JSObject* js_obj,
|
| - HeapEntry* entry) {
|
| +void V8HeapExplorer::ExtractClosureReferences(JSObject* js_obj,
|
| + HeapEntry* entry) {
|
| if (js_obj->IsJSFunction()) {
|
| HandleScope hs;
|
| JSFunction* func = JSFunction::cast(js_obj);
|
| @@ -2000,8 +1863,8 @@
|
| }
|
|
|
|
|
| -void HeapSnapshotGenerator::ExtractPropertyReferences(JSObject* js_obj,
|
| - HeapEntry* entry) {
|
| +void V8HeapExplorer::ExtractPropertyReferences(JSObject* js_obj,
|
| + HeapEntry* entry) {
|
| if (js_obj->HasFastProperties()) {
|
| DescriptorArray* descs = js_obj->map()->instance_descriptors();
|
| for (int i = 0; i < descs->number_of_descriptors(); i++) {
|
| @@ -2042,8 +1905,8 @@
|
| }
|
|
|
|
|
| -void HeapSnapshotGenerator::ExtractElementReferences(JSObject* js_obj,
|
| - HeapEntry* entry) {
|
| +void V8HeapExplorer::ExtractElementReferences(JSObject* js_obj,
|
| + HeapEntry* entry) {
|
| if (js_obj->HasFastElements()) {
|
| FixedArray* elements = FixedArray::cast(js_obj->elements());
|
| int length = js_obj->IsJSArray() ?
|
| @@ -2069,8 +1932,8 @@
|
| }
|
|
|
|
|
| -void HeapSnapshotGenerator::ExtractInternalReferences(JSObject* js_obj,
|
| - HeapEntry* entry) {
|
| +void V8HeapExplorer::ExtractInternalReferences(JSObject* js_obj,
|
| + HeapEntry* entry) {
|
| int length = js_obj->GetInternalFieldCount();
|
| for (int i = 0; i < length; ++i) {
|
| Object* o = js_obj->GetInternalField(i);
|
| @@ -2079,10 +1942,55 @@
|
| }
|
|
|
|
|
| -void HeapSnapshotGenerator::SetClosureReference(HeapObject* parent_obj,
|
| - HeapEntry* parent_entry,
|
| - String* reference_name,
|
| - Object* child_obj) {
|
| +HeapEntry* V8HeapExplorer::GetEntry(Object* obj) {
|
| + if (!obj->IsHeapObject()) return NULL;
|
| + return filler_->FindOrAddEntry(obj);
|
| +}
|
| +
|
| +
|
| +class RootsReferencesExtractor : public ObjectVisitor {
|
| + public:
|
| + explicit RootsReferencesExtractor(V8HeapExplorer* explorer)
|
| + : explorer_(explorer) {
|
| + }
|
| + void VisitPointers(Object** start, Object** end) {
|
| + for (Object** p = start; p < end; p++) explorer_->SetGcRootsReference(*p);
|
| + }
|
| + private:
|
| + V8HeapExplorer* explorer_;
|
| +};
|
| +
|
| +
|
| +bool V8HeapExplorer::IterateAndExtractReferences(
|
| + SnapshotFillerInterface* filler) {
|
| + filler_ = filler;
|
| + HeapIterator iterator(HeapIterator::kFilterUnreachable);
|
| + bool interrupted = false;
|
| + // Heap iteration with filtering must be finished in any case.
|
| + 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;
|
| + }
|
| + SetRootGcRootsReference();
|
| + RootsReferencesExtractor extractor(this);
|
| + HEAP->IterateRoots(&extractor, VISIT_ALL);
|
| + filler_ = NULL;
|
| + return progress_->ProgressReport(false);
|
| +}
|
| +
|
| +
|
| +void V8HeapExplorer::SetClosureReference(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::kContextVariable,
|
| @@ -2096,10 +2004,10 @@
|
| }
|
|
|
|
|
| -void HeapSnapshotGenerator::SetElementReference(HeapObject* parent_obj,
|
| - HeapEntry* parent_entry,
|
| - int index,
|
| - Object* child_obj) {
|
| +void V8HeapExplorer::SetElementReference(HeapObject* parent_obj,
|
| + HeapEntry* parent_entry,
|
| + int index,
|
| + Object* child_obj) {
|
| HeapEntry* child_entry = GetEntry(child_obj);
|
| if (child_entry != NULL) {
|
| filler_->SetIndexedReference(HeapGraphEdge::kElement,
|
| @@ -2113,10 +2021,10 @@
|
| }
|
|
|
|
|
| -void HeapSnapshotGenerator::SetInternalReference(HeapObject* parent_obj,
|
| - HeapEntry* parent_entry,
|
| - const char* reference_name,
|
| - Object* child_obj) {
|
| +void V8HeapExplorer::SetInternalReference(HeapObject* parent_obj,
|
| + HeapEntry* parent_entry,
|
| + const char* reference_name,
|
| + Object* child_obj) {
|
| HeapEntry* child_entry = GetEntry(child_obj);
|
| if (child_entry != NULL) {
|
| filler_->SetNamedReference(HeapGraphEdge::kInternal,
|
| @@ -2130,10 +2038,10 @@
|
| }
|
|
|
|
|
| -void HeapSnapshotGenerator::SetInternalReference(HeapObject* parent_obj,
|
| - HeapEntry* parent_entry,
|
| - int index,
|
| - Object* child_obj) {
|
| +void V8HeapExplorer::SetInternalReference(HeapObject* parent_obj,
|
| + HeapEntry* parent_entry,
|
| + int index,
|
| + Object* child_obj) {
|
| HeapEntry* child_entry = GetEntry(child_obj);
|
| if (child_entry != NULL) {
|
| filler_->SetNamedReference(HeapGraphEdge::kInternal,
|
| @@ -2147,10 +2055,10 @@
|
| }
|
|
|
|
|
| -void HeapSnapshotGenerator::SetHiddenReference(HeapObject* parent_obj,
|
| - HeapEntry* parent_entry,
|
| - int index,
|
| - Object* child_obj) {
|
| +void V8HeapExplorer::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,
|
| @@ -2163,10 +2071,10 @@
|
| }
|
|
|
|
|
| -void HeapSnapshotGenerator::SetPropertyReference(HeapObject* parent_obj,
|
| - HeapEntry* parent_entry,
|
| - String* reference_name,
|
| - Object* child_obj) {
|
| +void V8HeapExplorer::SetPropertyReference(HeapObject* parent_obj,
|
| + HeapEntry* parent_entry,
|
| + String* reference_name,
|
| + Object* child_obj) {
|
| HeapEntry* child_entry = GetEntry(child_obj);
|
| if (child_entry != NULL) {
|
| HeapGraphEdge::Type type = reference_name->length() > 0 ?
|
| @@ -2182,7 +2090,7 @@
|
| }
|
|
|
|
|
| -void HeapSnapshotGenerator::SetPropertyShortcutReference(
|
| +void V8HeapExplorer::SetPropertyShortcutReference(
|
| HeapObject* parent_obj,
|
| HeapEntry* parent_entry,
|
| String* reference_name,
|
| @@ -2199,52 +2107,221 @@
|
| }
|
|
|
|
|
| -void HeapSnapshotGenerator::SetRootGcRootsReference() {
|
| - filler_->SetRootGcRootsReference();
|
| +void V8HeapExplorer::SetRootGcRootsReference() {
|
| + filler_->SetIndexedAutoIndexReference(
|
| + HeapGraphEdge::kElement,
|
| + kInternalRootObject, snapshot_->root(),
|
| + kGcRootsObject, snapshot_->gc_roots());
|
| }
|
|
|
|
|
| -void HeapSnapshotGenerator::SetRootShortcutReference(Object* child_obj) {
|
| +void V8HeapExplorer::SetRootShortcutReference(Object* child_obj) {
|
| HeapEntry* child_entry = GetEntry(child_obj);
|
| ASSERT(child_entry != NULL);
|
| - filler_->SetRootShortcutReference(child_obj, child_entry);
|
| + filler_->SetNamedAutoIndexReference(
|
| + HeapGraphEdge::kShortcut,
|
| + kInternalRootObject, snapshot_->root(),
|
| + child_obj, child_entry);
|
| }
|
|
|
|
|
| -void HeapSnapshotGenerator::SetGcRootsReference(Object* child_obj) {
|
| +void V8HeapExplorer::SetGcRootsReference(Object* child_obj) {
|
| HeapEntry* child_entry = GetEntry(child_obj);
|
| if (child_entry != NULL) {
|
| - filler_->SetStrongRootReference(child_obj, child_entry);
|
| + filler_->SetIndexedAutoIndexReference(
|
| + HeapGraphEdge::kElement,
|
| + kGcRootsObject, snapshot_->gc_roots(),
|
| + child_obj, child_entry);
|
| }
|
| }
|
|
|
|
|
| +HeapSnapshotGenerator::HeapSnapshotGenerator(HeapSnapshot* snapshot,
|
| + v8::ActivityControl* control)
|
| + : snapshot_(snapshot),
|
| + control_(control),
|
| + v8_heap_explorer_(snapshot_, this) {
|
| +}
|
| +
|
| +
|
| +class SnapshotCounter : public SnapshotFillerInterface {
|
| + public:
|
| + SnapshotCounter(HeapEntriesAllocator* allocator, HeapEntriesMap* entries)
|
| + : allocator_(allocator), entries_(entries) { }
|
| + HeapEntry* AddEntry(HeapThing ptr) {
|
| + entries_->Pair(ptr, allocator_, HeapEntriesMap::kHeapEntryPlaceholder);
|
| + return HeapEntriesMap::kHeapEntryPlaceholder;
|
| + }
|
| + HeapEntry* FindOrAddEntry(HeapThing ptr) {
|
| + HeapEntry* entry = entries_->Map(ptr);
|
| + return entry != NULL ? entry : AddEntry(ptr);
|
| + }
|
| + void SetIndexedReference(HeapGraphEdge::Type,
|
| + HeapThing parent_ptr,
|
| + HeapEntry*,
|
| + int,
|
| + HeapThing child_ptr,
|
| + HeapEntry*) {
|
| + entries_->CountReference(parent_ptr, child_ptr);
|
| + }
|
| + void SetIndexedAutoIndexReference(HeapGraphEdge::Type,
|
| + HeapThing parent_ptr,
|
| + HeapEntry*,
|
| + HeapThing child_ptr,
|
| + HeapEntry*) {
|
| + entries_->CountReference(parent_ptr, child_ptr);
|
| + }
|
| + void SetNamedReference(HeapGraphEdge::Type,
|
| + HeapThing parent_ptr,
|
| + HeapEntry*,
|
| + const char*,
|
| + HeapThing child_ptr,
|
| + HeapEntry*) {
|
| + entries_->CountReference(parent_ptr, child_ptr);
|
| + }
|
| + void SetNamedAutoIndexReference(HeapGraphEdge::Type,
|
| + HeapThing parent_ptr,
|
| + HeapEntry*,
|
| + HeapThing child_ptr,
|
| + HeapEntry*) {
|
| + entries_->CountReference(parent_ptr, child_ptr);
|
| + }
|
| + private:
|
| + HeapEntriesAllocator* allocator_;
|
| + HeapEntriesMap* entries_;
|
| +};
|
| +
|
| +
|
| +class SnapshotFiller : public SnapshotFillerInterface {
|
| + public:
|
| + explicit SnapshotFiller(HeapSnapshot* snapshot, HeapEntriesMap* entries)
|
| + : snapshot_(snapshot),
|
| + collection_(snapshot->collection()),
|
| + entries_(entries) { }
|
| + HeapEntry* AddEntry(HeapThing ptr) {
|
| + UNREACHABLE();
|
| + return NULL;
|
| + }
|
| + HeapEntry* FindOrAddEntry(HeapThing ptr) {
|
| + HeapEntry* entry = entries_->Map(ptr);
|
| + return entry != NULL ? entry : AddEntry(ptr);
|
| + }
|
| + void SetIndexedReference(HeapGraphEdge::Type type,
|
| + HeapThing parent_ptr,
|
| + HeapEntry* parent_entry,
|
| + int index,
|
| + HeapThing child_ptr,
|
| + HeapEntry* child_entry) {
|
| + int child_index, retainer_index;
|
| + entries_->CountReference(
|
| + parent_ptr, child_ptr, &child_index, &retainer_index);
|
| + parent_entry->SetIndexedReference(
|
| + type, child_index, index, child_entry, retainer_index);
|
| + }
|
| + void SetIndexedAutoIndexReference(HeapGraphEdge::Type type,
|
| + HeapThing parent_ptr,
|
| + HeapEntry* parent_entry,
|
| + HeapThing child_ptr,
|
| + HeapEntry* child_entry) {
|
| + int child_index, retainer_index;
|
| + entries_->CountReference(
|
| + parent_ptr, child_ptr, &child_index, &retainer_index);
|
| + parent_entry->SetIndexedReference(
|
| + type, child_index, child_index + 1, child_entry, retainer_index);
|
| + }
|
| + void SetNamedReference(HeapGraphEdge::Type type,
|
| + HeapThing parent_ptr,
|
| + HeapEntry* parent_entry,
|
| + const char* reference_name,
|
| + HeapThing child_ptr,
|
| + HeapEntry* child_entry) {
|
| + int child_index, retainer_index;
|
| + entries_->CountReference(
|
| + parent_ptr, child_ptr, &child_index, &retainer_index);
|
| + parent_entry->SetNamedReference(
|
| + type, child_index, reference_name, child_entry, retainer_index);
|
| + }
|
| + void SetNamedAutoIndexReference(HeapGraphEdge::Type type,
|
| + HeapThing parent_ptr,
|
| + HeapEntry* parent_entry,
|
| + HeapThing child_ptr,
|
| + HeapEntry* child_entry) {
|
| + int child_index, retainer_index;
|
| + entries_->CountReference(
|
| + parent_ptr, child_ptr, &child_index, &retainer_index);
|
| + parent_entry->SetNamedReference(type,
|
| + child_index,
|
| + collection_->GetName(child_index + 1),
|
| + child_entry,
|
| + retainer_index);
|
| + }
|
| + private:
|
| + HeapSnapshot* snapshot_;
|
| + HeapSnapshotsCollection* collection_;
|
| + HeapEntriesMap* entries_;
|
| +};
|
| +
|
| +
|
| +bool HeapSnapshotGenerator::GenerateSnapshot() {
|
| + AssertNoAllocation no_alloc;
|
| +
|
| + SetProgressTotal(4); // 2 passes + dominators + sizes.
|
| +
|
| + // Pass 1. Iterate heap contents to count entries and references.
|
| + if (!CountEntriesAndReferences()) return false;
|
| +
|
| + // Allocate and fill entries in the snapshot, allocate references.
|
| + snapshot_->AllocateEntries(entries_.entries_count(),
|
| + entries_.total_children_count(),
|
| + entries_.total_retainers_count());
|
| + entries_.AllocateEntries();
|
| +
|
| + // Pass 2. Fill references.
|
| + if (!FillReferences()) return false;
|
| +
|
| + if (!SetEntriesDominators()) return false;
|
| + if (!ApproximateRetainedSizes()) return false;
|
| +
|
| + progress_counter_ = progress_total_;
|
| + if (!ProgressReport(true)) return false;
|
| + return true;
|
| +}
|
| +
|
| +
|
| +void HeapSnapshotGenerator::ProgressStep() {
|
| + ++progress_counter_;
|
| +}
|
| +
|
| +
|
| +bool HeapSnapshotGenerator::ProgressReport(bool force) {
|
| + const int kProgressReportGranularity = 10000;
|
| + if (control_ != NULL
|
| + && (force || progress_counter_ % kProgressReportGranularity == 0)) {
|
| + return
|
| + control_->ReportProgressValue(progress_counter_, progress_total_) ==
|
| + v8::ActivityControl::kContinue;
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +
|
| void HeapSnapshotGenerator::SetProgressTotal(int iterations_count) {
|
| if (control_ == NULL) return;
|
| -
|
| - HeapIterator iterator(HeapIterator::kFilterUnreachable);
|
| - int objects_count = 0;
|
| - for (HeapObject* obj = iterator.next();
|
| - obj != NULL;
|
| - obj = iterator.next(), ++objects_count) {}
|
| - progress_total_ = objects_count * iterations_count;
|
| + progress_total_ = v8_heap_explorer_.EstimateObjectsCount() * iterations_count;
|
| progress_counter_ = 0;
|
| }
|
|
|
|
|
| bool HeapSnapshotGenerator::CountEntriesAndReferences() {
|
| - SnapshotCounter counter(&entries_);
|
| - filler_ = &counter;
|
| - filler_->AddEntry(HeapSnapshot::kInternalRootObject);
|
| - filler_->AddEntry(HeapSnapshot::kGcRootsObject);
|
| - return IterateAndExtractReferences();
|
| + SnapshotCounter counter(&v8_heap_explorer_, &entries_);
|
| + v8_heap_explorer_.AddRootEntries(&counter);
|
| + return v8_heap_explorer_.IterateAndExtractReferences(&counter);
|
| }
|
|
|
|
|
| bool HeapSnapshotGenerator::FillReferences() {
|
| SnapshotFiller filler(snapshot_, &entries_);
|
| - filler_ = &filler;
|
| - return IterateAndExtractReferences();
|
| + return v8_heap_explorer_.IterateAndExtractReferences(&filler);
|
| }
|
|
|
|
|
| @@ -2289,7 +2366,7 @@
|
|
|
| // The algorithm is based on the article:
|
| // K. Cooper, T. Harvey and K. Kennedy "A Simple, Fast Dominance Algorithm"
|
| -// Softw. Pract. Exper. 4 (2001), pp. 1–10.
|
| +// Softw. Pract. Exper. 4 (2001), pp. 1-10.
|
| bool HeapSnapshotGenerator::BuildDominatorTree(
|
| const Vector<HeapEntry*>& entries,
|
| Vector<HeapEntry*>* dominators) {
|
| @@ -2330,7 +2407,7 @@
|
| int remaining = entries_length - changed;
|
| if (remaining < 0) remaining = 0;
|
| progress_counter_ = base_progress_counter + remaining;
|
| - if (!ReportProgress(true)) return false;
|
| + if (!ProgressReport(true)) return false;
|
| }
|
| return true;
|
| }
|
| @@ -2360,7 +2437,7 @@
|
| }
|
| for (int i = 0;
|
| i < snapshot_->entries()->length();
|
| - ++i, IncProgressCounter()) {
|
| + ++i, ProgressStep()) {
|
| HeapEntry* entry = snapshot_->entries()->at(i);
|
| int entry_size = entry->self_size();
|
| for (HeapEntry* dominator = entry->dominator();
|
| @@ -2368,32 +2445,12 @@
|
| entry = dominator, dominator = entry->dominator()) {
|
| dominator->add_retained_size(entry_size);
|
| }
|
| - if (!ReportProgress()) return false;
|
| + if (!ProgressReport()) return false;
|
| }
|
| return true;
|
| }
|
|
|
|
|
| -bool HeapSnapshotGenerator::IterateAndExtractReferences() {
|
| - HeapIterator iterator(HeapIterator::kFilterUnreachable);
|
| - bool interrupted = false;
|
| - // Heap iteration with filtering must be finished in any case.
|
| - for (HeapObject* obj = iterator.next();
|
| - obj != NULL;
|
| - obj = iterator.next(), IncProgressCounter()) {
|
| - if (!interrupted) {
|
| - ExtractReferences(obj);
|
| - if (!ReportProgress()) interrupted = true;
|
| - }
|
| - }
|
| - if (interrupted) return false;
|
| - SetRootGcRootsReference();
|
| - RootsReferencesExtractor extractor(this);
|
| - HEAP->IterateRoots(&extractor, VISIT_ALL);
|
| - return ReportProgress();
|
| -}
|
| -
|
| -
|
| void HeapSnapshotsDiff::CreateRoots(int additions_count, int deletions_count) {
|
| raw_additions_root_ =
|
| NewArray<char>(HeapEntry::EntriesSize(1, additions_count, 0));
|
|
|