Reviewers: Mikhail Naganov (Chromium), Description: Heap profiler should report implicit references.
Implicit references reported to V8 with V8::AddImplicitReferences calls are now
reported by heap profiler as 'native' references with type kInternal. Original WebKit bug report: https://bugs.webkit.org/show_bug.cgi?id=77414 Please review this at https://chromiumcodereview.appspot.com/9316092/ SVN Base: http://v8.googlecode.com/svn/branches/bleeding_edge/ Affected files: M src/profile-generator.h M src/profile-generator.cc M test/cctest/test-heap-profiler.cc Index: src/profile-generator.cc =================================================================== --- src/profile-generator.cc (revision 10596) +++ src/profile-generator.cc (working copy) @@ -2782,6 +2782,28 @@ embedder_queried_ = true; } +void NativeObjectsExplorer::FillImplicitReferences() +{ + Isolate* isolate = Isolate::Current(); + List<ImplicitRefGroup*>* groups = + isolate->global_handles()->implicit_ref_groups(); + for (int i = 0; i < groups->length(); ++i) { + ImplicitRefGroup* group = groups->at(i); + HeapObject* parent = *group->parent_; + HeapEntry* parent_entry = filler_->FindOrAddEntry(parent, this); + ASSERT(parent_entry != NULL); + Object*** children = group->children_; + for (size_t j = 0; j < group->length_; ++j) { + Object* child = *children[j]; + HeapEntry* child_entry = filler_->FindOrAddEntry(child, this); + filler_->SetNamedReference( + HeapGraphEdge::kInternal, + parent, parent_entry, + "native", + child, child_entry); + } + } +} List<HeapObject*>* NativeObjectsExplorer::GetListMaybeDisposeInfo( v8::RetainedObjectInfo* info) { @@ -2798,9 +2820,13 @@ bool NativeObjectsExplorer::IterateAndExtractReferences( SnapshotFillerInterface* filler) { - if (EstimateObjectsCount() <= 0) return true; filler_ = filler; FillRetainedObjects(); + FillImplicitReferences(); + if (EstimateObjectsCount() <= 0) { + filler_ = NULL; + return true; + } for (HashMap::Entry* p = objects_by_info_.Start(); p != NULL; p = objects_by_info_.Next(p)) { Index: src/profile-generator.h =================================================================== --- src/profile-generator.h (revision 10596) +++ src/profile-generator.h (working copy) @@ -1042,6 +1042,7 @@ private: void FillRetainedObjects(); + void FillImplicitReferences(); List<HeapObject*>* GetListMaybeDisposeInfo(v8::RetainedObjectInfo* info); void SetNativeRootReference(v8::RetainedObjectInfo* info); void SetRootNativeRootsReference(); Index: test/cctest/test-heap-profiler.cc =================================================================== --- test/cctest/test-heap-profiler.cc (revision 10596) +++ test/cctest/test-heap-profiler.cc (working copy) @@ -805,6 +805,72 @@ } +class GraphWithImplicitRefs { + public: + GraphWithImplicitRefs(LocalContext& env) { + CHECK_EQ(NULL, instance_); + instance_ = this; + for (int i = 0; i < 4; i++) + objects_[i] = v8::Persistent<v8::Object>::New(v8::Object::New()); + env->Global()->Set(v8_str("root_object"), objects_[0]); + } + ~GraphWithImplicitRefs() { + instance_ = NULL; + } + + static void gcPrologue() { + instance_->AddImplicitReferences(); + } + private: + void AddImplicitReferences() { + // 0 -> 1 + v8::V8::AddImplicitReferences( + v8::Persistent<v8::Object>::Cast(objects_[0]), &objects_[1], 1); + // 1 -> 2, 1 -> 3 + v8::V8::AddImplicitReferences( + v8::Persistent<v8::Object>::Cast(objects_[1]), &objects_[2], 2); + } + + v8::Persistent<v8::Value> objects_[4]; + static GraphWithImplicitRefs* instance_; +}; + +GraphWithImplicitRefs* GraphWithImplicitRefs::instance_ = NULL; + + +TEST(HeapSnapshotImplicitReferences) { + v8::HandleScope scope; + LocalContext env; + + GraphWithImplicitRefs graph(env); + v8::V8::SetGlobalGCPrologueCallback(&GraphWithImplicitRefs::gcPrologue); + + const v8::HeapSnapshot* snapshot = + v8::HeapProfiler::TakeSnapshot(v8_str("implicit_refs")); + + const v8::HeapGraphNode* global_object = GetGlobalObject(snapshot); + // Use kShortcut type to skip intermediate JSGlobalPropertyCell + const v8::HeapGraphNode* o0 = GetProperty( + global_object, v8::HeapGraphEdge::kShortcut, "root_object"); + CHECK(o0); + CHECK_EQ(v8::HeapGraphNode::kObject, o0->GetType()); + const v8::HeapGraphNode* o1 = GetProperty( + o0, v8::HeapGraphEdge::kInternal, "native"); + CHECK(o1); + int implicit_targets_count = 0; + for (int i = 0, count = o1->GetChildrenCount(); i < count; ++i) { + const v8::HeapGraphEdge* prop = o1->GetChild(i); + v8::String::AsciiValue prop_name(prop->GetName()); + if (prop->GetType() == v8::HeapGraphEdge::kInternal && + strcmp("native", *prop_name) == 0) { + ++implicit_targets_count; + } + } + CHECK_EQ(2, implicit_targets_count); + v8::V8::SetGlobalGCPrologueCallback(NULL); +} + + TEST(DeleteAllHeapSnapshots) { v8::HandleScope scope; LocalContext env; -- v8-dev mailing list [email protected] http://groups.google.com/group/v8-dev
