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

Reply via email to