}
-HeapEntry* HeapSnapshot::AddNativesRootEntry(int children_count,
- int retainers_count) {
- ASSERT(natives_root_entry_ == NULL);
- return (natives_root_entry_ = AddEntry(
- HeapEntry::kObject,
- "(Native objects)",
- HeapObjectsMap::kNativesRootObjectId,
- 0,
- children_count,
- retainers_count));
-}
-
-
HeapEntry* HeapSnapshot::AddEntry(HeapEntry::Type type,
const char* name,
uint64_t id,
const uint64_t HeapObjectsMap::kInternalRootObjectId = 1;
const uint64_t HeapObjectsMap::kGcRootsObjectId =
HeapObjectsMap::kInternalRootObjectId + HeapObjectsMap::kObjectIdStep;
-const uint64_t HeapObjectsMap::kNativesRootObjectId =
- HeapObjectsMap::kGcRootsObjectId + HeapObjectsMap::kObjectIdStep;
const uint64_t HeapObjectsMap::kGcRootsFirstSubrootId =
- HeapObjectsMap::kNativesRootObjectId + HeapObjectsMap::kObjectIdStep;
+ HeapObjectsMap::kGcRootsObjectId + HeapObjectsMap::kObjectIdStep;
const uint64_t HeapObjectsMap::kFirstAvailableObjectId =
HeapObjectsMap::kGcRootsFirstSubrootId +
VisitorSynchronization::kNumberOfSyncTags * HeapObjectsMap::kObjectIdStep;
NativeObjectsExplorer* explorer_;
};
-HeapThing const NativeObjectsExplorer::kNativesRootObject =
- reinterpret_cast<HeapThing>(
- static_cast<intptr_t>(HeapObjectsMap::kNativesRootObjectId));
-
-
NativeObjectsExplorer::NativeObjectsExplorer(
HeapSnapshot* snapshot, SnapshottingProgressReportingInterface* progress)
: snapshot_(snapshot),
progress_(progress),
embedder_queried_(false),
objects_by_info_(RetainedInfosMatch),
+ native_groups_(StringsMatch),
filler_(NULL) {
}
HeapEntry* NativeObjectsExplorer::AllocateEntry(
HeapThing ptr, int children_count, int retainers_count) {
- if (ptr == kNativesRootObject) {
- return snapshot_->AddNativesRootEntry(children_count, retainers_count);
- } else {
- v8::RetainedObjectInfo* info =
- reinterpret_cast<v8::RetainedObjectInfo*>(ptr);
- intptr_t elements = info->GetElementCount();
- intptr_t size = info->GetSizeInBytes();
- return snapshot_->AddEntry(
- HeapEntry::kNative,
- elements != -1 ?
- collection_->names()->GetFormatted(
- "%s / %" V8_PTR_PREFIX "d entries",
- info->GetLabel(),
- info->GetElementCount()) :
- collection_->names()->GetCopy(info->GetLabel()),
- HeapObjectsMap::GenerateId(info),
- size != -1 ? static_cast<int>(size) : 0,
- children_count,
- retainers_count);
- }
-}
-
-
-void NativeObjectsExplorer::AddRootEntries(SnapshotFillerInterface* filler) {
- if (EstimateObjectsCount() <= 0) return;
- filler->AddEntry(kNativesRootObject, this);
+ v8::RetainedObjectInfo* info =
+ reinterpret_cast<v8::RetainedObjectInfo*>(ptr);
+ intptr_t elements = info->GetElementCount();
+ intptr_t size = info->GetSizeInBytes();
+ return snapshot_->AddEntry(
+ HeapEntry::kNative,
+ elements != -1 ?
+ collection_->names()->GetFormatted(
+ "%s / %" V8_PTR_PREFIX "d entries",
+ info->GetLabel(),
+ info->GetElementCount()) :
+ collection_->names()->GetCopy(info->GetLabel()),
+ HeapObjectsMap::GenerateId(info),
+ size != -1 ? static_cast<int>(size) : 0,
+ children_count,
+ retainers_count);
}
SetWrapperNativeReferences(objects->at(i), info);
}
}
- SetRootNativesRootReference();
+ SetRootNativeRootsReference();
filler_ = NULL;
return true;
}
+class NativeGroupRetainedObjectInfo : public v8::RetainedObjectInfo {
+ public:
+ explicit NativeGroupRetainedObjectInfo(const char* label)
+ : disposed_(false),
+ hash_(reinterpret_cast<intptr_t>(label)),
+ label_(label) {
+ }
+
+ virtual ~NativeGroupRetainedObjectInfo() {}
+ virtual void Dispose() {
+ CHECK(!disposed_);
+ disposed_ = true;
+ }
+ virtual bool IsEquivalent(RetainedObjectInfo* other) {
+ return hash_ == other->GetHash() && !strcmp(label_, other->GetLabel());
+ }
+ virtual intptr_t GetHash() { return hash_; }
+ virtual const char* GetLabel() { return label_; }
+
+ private:
+ bool disposed_;
+ int hash_;
+ const char* label_;
+};
+
+
+NativeGroupRetainedObjectInfo* NativeObjectsExplorer::FindOrAddGroupInfo(
+ const char* label) {
+ const char* label_copy = collection_->names()->GetCopy(label);
+ intptr_t hash = HashSequentialString(label_copy, strlen(label_copy),
+ HEAP->HashSeed());
+ HashMap::Entry* entry = native_groups_.Lookup(const_cast<char*>(label_copy),
+ hash, true);
+ if (entry->value == NULL)
+ entry->value = new NativeGroupRetainedObjectInfo(label);
+ return static_cast<NativeGroupRetainedObjectInfo*>(entry->value);
+}
+
+
void NativeObjectsExplorer::SetNativeRootReference(
v8::RetainedObjectInfo* info) {
HeapEntry* child_entry = filler_->FindOrAddEntry(info, this);
ASSERT(child_entry != NULL);
- filler_->SetIndexedAutoIndexReference(
- HeapGraphEdge::kElement,
- kNativesRootObject, snapshot_->natives_root(),
+ NativeGroupRetainedObjectInfo* group_info =
+ FindOrAddGroupInfo(info->GetGroupLabel());
+ HeapEntry* group_entry = filler_->FindOrAddEntry(group_info, this);
+ filler_->SetNamedAutoIndexReference(
+ HeapGraphEdge::kInternal,
+ group_info, group_entry,
info, child_entry);
}
}
-void NativeObjectsExplorer::SetRootNativesRootReference() {
- filler_->SetIndexedAutoIndexReference(
- HeapGraphEdge::kElement,
- V8HeapExplorer::kInternalRootObject, snapshot_->root(),
- kNativesRootObject, snapshot_->natives_root());
+void NativeObjectsExplorer::SetRootNativeRootsReference() {
+ for (HashMap::Entry* entry = native_groups_.Start();
+ entry;
+ entry = native_groups_.Next(entry)) {
+ NativeGroupRetainedObjectInfo* group_info =
+ static_cast<NativeGroupRetainedObjectInfo*>(entry->value);
+ HeapEntry* group_entry = filler_->FindOrAddEntry(group_info, this);
+ ASSERT(group_entry != NULL);
+ filler_->SetIndexedAutoIndexReference(
+ HeapGraphEdge::kElement,
+ V8HeapExplorer::kInternalRootObject, snapshot_->root(),
+ group_info, group_entry);
+ }
}
bool HeapSnapshotGenerator::CountEntriesAndReferences() {
SnapshotCounter counter(&entries_);
v8_heap_explorer_.AddRootEntries(&counter);
- dom_explorer_.AddRootEntries(&counter);
return
v8_heap_explorer_.IterateAndExtractReferences(&counter) &&
dom_explorer_.IterateAndExtractReferences(&counter);
DISALLOW_COPY_AND_ASSIGN(V8HeapExplorer);
};
+class NativeGroupRetainedObjectInfo;
// An implementation of retained native objects extractor.
class NativeObjectsExplorer : public HeapEntriesAllocator {
void FillRetainedObjects();
List<HeapObject*>* GetListMaybeDisposeInfo(v8::RetainedObjectInfo* info);
void SetNativeRootReference(v8::RetainedObjectInfo* info);
- void SetRootNativesRootReference();
+ void SetRootNativeRootsReference();
void SetWrapperNativeReferences(HeapObject* wrapper,
v8::RetainedObjectInfo* info);
void VisitSubtreeWrapper(Object** p, uint16_t class_id);
(reinterpret_cast<v8::RetainedObjectInfo*>(key1))->IsEquivalent(
reinterpret_cast<v8::RetainedObjectInfo*>(key2));
}
+ INLINE(static bool StringsMatch(void* key1, void* key2)) {
+ return strcmp(reinterpret_cast<char*>(key1),
+ reinterpret_cast<char*>(key2)) == 0;
+ }
+
+ NativeGroupRetainedObjectInfo* FindOrAddGroupInfo(const char* label);
HeapSnapshot* snapshot_;
HeapSnapshotsCollection* collection_;
HeapObjectsSet in_groups_;
// RetainedObjectInfo* -> List<HeapObject*>*
HashMap objects_by_info_;
+ HashMap native_groups_;
// Used during references extraction.
SnapshotFillerInterface* filler_;
class TestRetainedObjectInfo : public v8::RetainedObjectInfo {
public:
TestRetainedObjectInfo(int hash,
+ const char* group_label,
const char* label,
intptr_t element_count = -1,
intptr_t size = -1)
: disposed_(false),
hash_(hash),
+ group_label_(group_label),
label_(label),
element_count_(element_count),
size_(size) {
return GetHash() == other->GetHash();
}
virtual intptr_t GetHash() { return hash_; }
+ virtual const char* GetGroupLabel() { return group_label_; }
virtual const char* GetLabel() { return label_; }
virtual intptr_t GetElementCount() { return element_count_; }
virtual intptr_t GetSizeInBytes() { return size_; }
if (wrapper->IsString()) {
v8::String::AsciiValue ascii(wrapper);
if (strcmp(*ascii, "AAA") == 0)
- return new TestRetainedObjectInfo(1, "aaa", 100);
+ return new TestRetainedObjectInfo(1, "aaa-group", "aaa", 100);
else if (strcmp(*ascii, "BBB") == 0)
- return new TestRetainedObjectInfo(1, "aaa", 100);
+ return new TestRetainedObjectInfo(1, "aaa-group", "aaa", 100);
}
} else if (class_id == 2) {
if (wrapper->IsString()) {
v8::String::AsciiValue ascii(wrapper);
if (strcmp(*ascii, "CCC") == 0)
- return new TestRetainedObjectInfo(2, "ccc");
+ return new TestRetainedObjectInfo(2, "ccc-group", "ccc");
}
}
CHECK(false);
bool disposed_;
int category_;
int hash_;
+ const char* group_label_;
const char* label_;
intptr_t element_count_;
intptr_t size_;
delete TestRetainedObjectInfo::instances[i];
}
- const v8::HeapGraphNode* natives = GetNode(
- snapshot->GetRoot(), v8::HeapGraphNode::kObject, "(Native objects)");
- CHECK_NE(NULL, natives);
- CHECK_EQ(2, natives->GetChildrenCount());
+ const v8::HeapGraphNode* native_group_aaa = GetNode(
+ snapshot->GetRoot(), v8::HeapGraphNode::kNative, "aaa-group");
+ CHECK_NE(NULL, native_group_aaa);
+ CHECK_EQ(1, native_group_aaa->GetChildrenCount());
const v8::HeapGraphNode* aaa = GetNode(
- natives, v8::HeapGraphNode::kNative, "aaa / 100 entries");
+ native_group_aaa, v8::HeapGraphNode::kNative, "aaa / 100 entries");
CHECK_NE(NULL, aaa);
+ CHECK_EQ(2, aaa->GetChildrenCount());
+
+ const v8::HeapGraphNode* native_group_ccc = GetNode(
+ snapshot->GetRoot(), v8::HeapGraphNode::kNative, "ccc-group");
const v8::HeapGraphNode* ccc = GetNode(
- natives, v8::HeapGraphNode::kNative, "ccc");
+ native_group_ccc, v8::HeapGraphNode::kNative, "ccc");
CHECK_NE(NULL, ccc);
- CHECK_EQ(2, aaa->GetChildrenCount());
const v8::HeapGraphNode* n_AAA = GetNode(
aaa, v8::HeapGraphNode::kString, "AAA");
CHECK_NE(NULL, n_AAA);