Index: src/profile-generator.cc |
diff --git a/src/profile-generator.cc b/src/profile-generator.cc |
index c954c4fbc63189d046638e61a4070ce1ff3378f5..1ad3fa91714422accde71b622e3614cbc87f3ebd 100644 |
--- a/src/profile-generator.cc |
+++ b/src/profile-generator.cc |
@@ -1602,6 +1602,28 @@ void HeapObjectsSet::Insert(Object* obj) { |
} |
+const char* HeapObjectsSet::GetTag(Object* obj) { |
+ HeapObject* object = HeapObject::cast(obj); |
+ HashMap::Entry* cache_entry = |
+ entries_.Lookup(object, HeapEntriesMap::Hash(object), false); |
+ if (cache_entry != NULL |
+ && cache_entry->value != HeapEntriesMap::kHeapEntryPlaceholder) { |
+ return reinterpret_cast<const char*>(cache_entry->value); |
+ } else { |
+ return NULL; |
+ } |
+} |
+ |
+ |
+void HeapObjectsSet::SetTag(Object* obj, const char* tag) { |
+ if (!obj->IsHeapObject()) return; |
+ HeapObject* object = HeapObject::cast(obj); |
+ HashMap::Entry* cache_entry = |
+ entries_.Lookup(object, HeapEntriesMap::Hash(object), true); |
+ cache_entry->value = const_cast<char*>(tag); |
+} |
+ |
+ |
HeapObject *const V8HeapExplorer::kInternalRootObject = |
reinterpret_cast<HeapObject*>( |
static_cast<intptr_t>(HeapObjectsMap::kInternalRootObjectId)); |
@@ -1639,6 +1661,19 @@ HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object, |
return snapshot_->AddRootEntry(children_count); |
} else if (object == kGcRootsObject) { |
return snapshot_->AddGcRootsEntry(children_count, retainers_count); |
+ } else if (object->IsJSGlobalObject()) { |
+ const char* tag = objects_tags_.GetTag(object); |
+ const char* name = collection_->names()->GetName( |
+ GetConstructorNameForHeapProfile( |
+ JSObject::cast(object))); |
Vitaly Repeshko
2011/05/29 23:01:34
nit: Fits on the previous line?
mnaganov (inactive)
2011/05/30 14:20:42
Done.
|
+ if (tag != NULL) { |
+ name = collection_->names()->GetFormatted("%s / %s", name, tag); |
+ } |
+ return AddEntry(object, |
+ HeapEntry::kObject, |
+ name, |
+ children_count, |
+ retainers_count); |
} else if (object->IsJSFunction()) { |
JSFunction* func = JSFunction::cast(object); |
SharedFunctionInfo* shared = func->shared(); |
@@ -1780,6 +1815,7 @@ class IndexedReferencesExtractor : public ObjectVisitor { |
ASSERT(Memory::Object_at(field)->IsHeapObject()); |
*field |= kFailureTag; |
} |
+ |
private: |
bool CheckVisitedAndUnmark(Object** field) { |
if ((*field)->IsFailure()) { |
@@ -2206,6 +2242,89 @@ void V8HeapExplorer::SetGcRootsReference(Object* child_obj) { |
} |
+class GlobalObjectsCounter : public ObjectVisitor { |
+ public: |
+ GlobalObjectsCounter() : count_(0) {} |
+ void VisitPointers(Object** start, Object** end) { |
Vitaly Repeshko
2011/05/29 23:01:34
nit: virtual
mnaganov (inactive)
2011/05/30 14:20:42
Done.
|
+ for (Object** p = start; p < end; p++) { |
+ if ((*p)->IsGlobalContext()) |
+ ++count_; |
+ } |
+ } |
+ int count() { return count_; } |
+ |
+ private: |
+ int count_; |
+}; |
+ |
+ |
+class GlobalObjectsEnumerator : public ObjectVisitor { |
+ public: |
+ explicit GlobalObjectsEnumerator(int length) |
+ : length_(length), |
+ count_(0), |
+ objects_(NewArray<Handle<JSGlobalObject> >(length)) {} |
+ ~GlobalObjectsEnumerator() { |
+ DeleteArray(objects_); |
+ } |
+ void VisitPointers(Object** start, Object** end) { |
Vitaly Repeshko
2011/05/29 23:01:34
nit: virtual
mnaganov (inactive)
2011/05/30 14:20:42
Done.
|
+ for (Object** p = start; count_ < length_ && p < end; p++) { |
+ if ((*p)->IsGlobalContext()) { |
+ Context* context = Context::cast(*p); |
+ JSObject* proxy = context->global_proxy(); |
+ if (proxy->IsJSGlobalProxy()) { |
Vitaly Repeshko
2011/05/29 23:01:34
Given that this loop has more conditions than its
mnaganov (inactive)
2011/05/30 14:20:42
Fixed by eliminating the counter class.
|
+ Object* global = proxy->map()->prototype(); |
+ if (global->IsJSGlobalObject()) |
Vitaly Repeshko
2011/05/29 23:01:34
nit: {}
mnaganov (inactive)
2011/05/30 14:20:42
Done.
|
+ objects_[count_++] = |
+ Handle<JSGlobalObject>(JSGlobalObject::cast(global)); |
+ } |
+ } |
+ } |
+ } |
+ int count() { return count_; } |
+ Handle<JSGlobalObject>* objects() { return objects_; } |
+ |
+ private: |
+ const int length_; |
+ int count_; |
+ Handle<JSGlobalObject>* objects_; |
Vitaly Repeshko
2011/05/29 23:01:34
Can we use a growable collection of handles (e.g.
mnaganov (inactive)
2011/05/30 14:20:42
Sure. Sorry, I forgot about their existence.
|
+}; |
+ |
+ |
+// Modifies heap. Must not be run during heap traversal. |
+void V8HeapExplorer::TagGlobalObjects() { |
Vitaly Repeshko
2011/05/29 23:01:34
Random idea. I don't know how flexible we want to
mnaganov (inactive)
2011/05/30 14:20:42
Let's discuss it later.
|
+ Isolate* isolate = Isolate::Current(); |
+ GlobalObjectsCounter counter; |
+ isolate->global_handles()->IterateAllRoots(&counter); |
+ GlobalObjectsEnumerator enumerator(counter.count()); |
+ isolate->global_handles()->IterateAllRoots(&enumerator); |
+ Handle<String> document_string = |
+ isolate->factory()->NewStringFromAscii(CStrVector("document")); |
+ Handle<String> url_string = |
+ isolate->factory()->NewStringFromAscii(CStrVector("URL")); |
+ const char** urls = NewArray<const char*>(counter.count()); |
+ for (int i = 0; i < counter.count(); ++i) { |
+ urls[i] = NULL; |
+ Handle<JSGlobalObject>& go = enumerator.objects()[i]; |
Vitaly Repeshko
2011/05/29 23:01:34
Reference is not needed here. "go" is too short.
mnaganov (inactive)
2011/05/30 14:20:42
Removed ref. s/go/global_obj/
|
+ Object* obj_document = go->GetPropertyNoExceptionThrown(*document_string); |
Vitaly Repeshko
2011/05/29 23:01:34
This is not safe, because it asserts on failure/ex
mnaganov (inactive)
2011/05/30 14:20:42
Done.
|
+ if (obj_document->IsJSObject()) { |
+ JSObject* document = JSObject::cast(obj_document); |
+ Object* obj_url = document->GetProperty(*url_string)->ToObjectUnchecked(); |
Vitaly Repeshko
2011/05/29 23:01:34
Also asserts on failure/exception.
mnaganov (inactive)
2011/05/30 14:20:42
Done.
|
+ if (obj_url->IsString()) { |
+ urls[i] = collection_->names()->GetName(String::cast(obj_url)); |
+ } |
+ } |
+ } |
+ |
+ AssertNoAllocation no_allocation; |
+ for (int i = 0; i < counter.count(); ++i) { |
+ objects_tags_.SetTag(*enumerator.objects()[i], urls[i]); |
+ } |
+ |
+ DeleteArray(urls); |
+} |
+ |
+ |
class GlobalHandlesExtractor : public ObjectVisitor { |
public: |
explicit GlobalHandlesExtractor(NativeObjectsExplorer* explorer) |
@@ -2448,6 +2567,7 @@ class SnapshotCounter : public SnapshotFillerInterface { |
HeapEntry*) { |
entries_->CountReference(parent_ptr, child_ptr); |
} |
+ |
private: |
HeapEntriesMap* entries_; |
}; |
@@ -2519,6 +2639,7 @@ class SnapshotFiller : public SnapshotFillerInterface { |
child_entry, |
retainer_index); |
} |
+ |
private: |
HeapSnapshot* snapshot_; |
HeapSnapshotsCollection* collection_; |
@@ -2527,6 +2648,8 @@ class SnapshotFiller : public SnapshotFillerInterface { |
bool HeapSnapshotGenerator::GenerateSnapshot() { |
+ v8_heap_explorer_.TagGlobalObjects(); |
+ |
AssertNoAllocation no_alloc; |
SetProgressTotal(4); // 2 passes + dominators + sizes. |