Chromium Code Reviews| 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. |