Revision: 4891
Author: [email protected]
Date: Thu Jun 17 05:56:55 2010
Log: Heap profiler: add a missing link between a function closure and shared function info.

Review URL: http://codereview.chromium.org/2846012
http://code.google.com/p/v8/source/detail?r=4891

Modified:
 /branches/bleeding_edge/include/v8-profiler.h
 /branches/bleeding_edge/src/api.cc
 /branches/bleeding_edge/src/checks.h
 /branches/bleeding_edge/src/profile-generator.cc
 /branches/bleeding_edge/src/profile-generator.h
 /branches/bleeding_edge/test/cctest/test-heap-profiler.cc

=======================================
--- /branches/bleeding_edge/include/v8-profiler.h       Tue Jun 15 04:44:07 2010
+++ /branches/bleeding_edge/include/v8-profiler.h       Thu Jun 17 05:56:55 2010
@@ -196,7 +196,9 @@
   enum Type {
     CONTEXT_VARIABLE = 0,  // A variable from a function context.
     ELEMENT = 1,           // An element of an array.
-    PROPERTY = 2           // A named object property.
+    PROPERTY = 2,          // A named object property.
+    INTERNAL = 3           // A link that can't be accessed from JS,
+                           // thus, its name isn't a real property name.
   };

   /** Returns edge type (see HeapGraphEdge::Type). */
=======================================
--- /branches/bleeding_edge/src/api.cc  Tue Jun 15 10:01:02 2010
+++ /branches/bleeding_edge/src/api.cc  Thu Jun 17 05:56:55 2010
@@ -4460,6 +4460,7 @@
       reinterpret_cast<const i::HeapGraphEdge*>(this);
   switch (edge->type()) {
     case i::HeapGraphEdge::CONTEXT_VARIABLE:
+    case i::HeapGraphEdge::INTERNAL:
     case i::HeapGraphEdge::PROPERTY:
       return Handle<String>(ToApi<String>(i::Factory::LookupAsciiSymbol(
           edge->name())));
=======================================
--- /branches/bleeding_edge/src/checks.h        Tue Jun  8 05:04:49 2010
+++ /branches/bleeding_edge/src/checks.h        Thu Jun 17 05:56:55 2010
@@ -155,9 +155,9 @@
 static inline void CheckEqualsHelper(const char* file,
                                      int line,
                                      const char* expected_source,
-                                     void* expected,
+                                     const void* expected,
                                      const char* value_source,
-                                     void* value) {
+                                     const void* value) {
   if (expected != value) {
     V8_Fatal(file, line,
              "CHECK_EQ(%s, %s) failed\n#   Expected: %p\n#   Found: %p",
@@ -170,9 +170,9 @@
 static inline void CheckNonEqualsHelper(const char* file,
                                         int line,
                                         const char* expected_source,
-                                        void* expected,
+                                        const void* expected,
                                         const char* value_source,
-                                        void* value) {
+                                        const void* value) {
   if (expected == value) {
     V8_Fatal(file, line, "CHECK_NE(%s, %s) failed\n#   Value: %p",
              expected_source, value_source, value);
=======================================
--- /branches/bleeding_edge/src/profile-generator.cc Tue Jun 15 04:44:07 2010 +++ /branches/bleeding_edge/src/profile-generator.cc Thu Jun 17 05:56:55 2010
@@ -818,7 +818,7 @@
                              HeapEntry* from,
                              HeapEntry* to)
     : type_(type), name_(name), from_(from), to_(to) {
-  ASSERT(type_ == CONTEXT_VARIABLE || type_ == PROPERTY);
+ ASSERT(type_ == CONTEXT_VARIABLE || type_ == PROPERTY || type_ == INTERNAL);
 }


@@ -845,26 +845,30 @@
 }


-void HeapEntry::SetClosureReference(const char* name, HeapEntry* entry) {
-  HeapGraphEdge* edge =
- new HeapGraphEdge(HeapGraphEdge::CONTEXT_VARIABLE, name, this, entry);
+void HeapEntry::AddEdge(HeapGraphEdge* edge) {
   children_.Add(edge);
-  entry->retainers_.Add(edge);
+  edge->to()->retainers_.Add(edge);
+}
+
+
+void HeapEntry::SetClosureReference(const char* name, HeapEntry* entry) {
+  AddEdge(
+ new HeapGraphEdge(HeapGraphEdge::CONTEXT_VARIABLE, name, this, entry));
 }


 void HeapEntry::SetElementReference(int index, HeapEntry* entry) {
-  HeapGraphEdge* edge = new HeapGraphEdge(index, this, entry);
-  children_.Add(edge);
-  entry->retainers_.Add(edge);
+  AddEdge(new HeapGraphEdge(index, this, entry));
+}
+
+
+void HeapEntry::SetInternalReference(const char* name, HeapEntry* entry) {
+  AddEdge(new HeapGraphEdge(HeapGraphEdge::INTERNAL, name, this, entry));
 }


 void HeapEntry::SetPropertyReference(const char* name, HeapEntry* entry) {
-  HeapGraphEdge* edge =
-      new HeapGraphEdge(HeapGraphEdge::PROPERTY, name, this, entry);
-  children_.Add(edge);
-  entry->retainers_.Add(edge);
+  AddEdge(new HeapGraphEdge(HeapGraphEdge::PROPERTY, name, this, entry));
 }


@@ -1074,7 +1078,7 @@


 void HeapEntry::Print(int max_depth, int indent) {
-  OS::Print("%6d %6d %6d", self_size_, TotalSize(), NonSharedTotalSize());
+  OS::Print("%6d %6d %6d ", self_size_, TotalSize(), NonSharedTotalSize());
   if (type_ != STRING) {
     OS::Print("%s %.40s\n", TypeAsString(), name_);
   } else {
@@ -1100,6 +1104,9 @@
       case HeapGraphEdge::ELEMENT:
         OS::Print("  %*c %d: ", indent, ' ', edge->index());
         break;
+      case HeapGraphEdge::INTERNAL:
+        OS::Print("  %*c $%s: ", indent, ' ', edge->name());
+        break;
       case HeapGraphEdge::PROPERTY:
         OS::Print("  %*c %s: ", indent, ' ', edge->name());
         break;
@@ -1145,6 +1152,9 @@
       case HeapGraphEdge::ELEMENT:
         OS::Print("[%d] ", edge->index());
         break;
+      case HeapGraphEdge::INTERNAL:
+        OS::Print("[$%s] ", edge->name());
+        break;
       case HeapGraphEdge::PROPERTY:
         OS::Print("[%s] ", edge->name());
         break;
@@ -1316,6 +1326,16 @@
     parent->SetElementReference(index, child_entry);
   }
 }
+
+
+void HeapSnapshot::SetInternalReference(HeapEntry* parent,
+                                        const char* reference_name,
+                                        Object* child) {
+  HeapEntry* child_entry = GetEntry(child);
+  if (child_entry != NULL) {
+    parent->SetInternalReference(reference_name, child_entry);
+  }
+}


 void HeapSnapshot::SetPropertyReference(HeapEntry* parent,
@@ -1546,6 +1566,7 @@
snapshot_->SetClosureReference(entry, local_name, context->get(idx));
       }
     }
+    snapshot_->SetInternalReference(entry, "code", func->shared());
   }
 }

=======================================
--- /branches/bleeding_edge/src/profile-generator.h     Tue Jun 15 04:44:07 2010
+++ /branches/bleeding_edge/src/profile-generator.h     Thu Jun 17 05:56:55 2010
@@ -431,7 +431,8 @@
   enum Type {
     CONTEXT_VARIABLE = v8::HeapGraphEdge::CONTEXT_VARIABLE,
     ELEMENT = v8::HeapGraphEdge::ELEMENT,
-    PROPERTY = v8::HeapGraphEdge::PROPERTY
+    PROPERTY = v8::HeapGraphEdge::PROPERTY,
+    INTERNAL = v8::HeapGraphEdge::INTERNAL
   };

HeapGraphEdge(Type type, const char* name, HeapEntry* from, HeapEntry* to);
@@ -443,7 +444,7 @@
     return index_;
   }
   const char* name() const {
-    ASSERT(type_ == CONTEXT_VARIABLE || type_ == PROPERTY);
+ ASSERT(type_ == CONTEXT_VARIABLE || type_ == PROPERTY || type_ == INTERNAL);
     return name_;
   }
   HeapEntry* from() const { return from_; }
@@ -533,6 +534,7 @@
   void PaintReachableFromOthers() { painted_ = kPaintReachableFromOthers; }
   void SetClosureReference(const char* name, HeapEntry* entry);
   void SetElementReference(int index, HeapEntry* entry);
+  void SetInternalReference(const char* name, HeapEntry* entry);
   void SetPropertyReference(const char* name, HeapEntry* entry);
   void SetAutoIndexReference(HeapEntry* entry);

@@ -542,6 +544,7 @@
   void Print(int max_depth, int indent);

  private:
+  void AddEdge(HeapGraphEdge* edge);
   int CalculateTotalSize();
   int CalculateNonSharedTotalSize();
   void FindRetainingPaths(HeapEntry* node, CachedHeapGraphPath* prev_path);
@@ -641,6 +644,8 @@
   void SetClosureReference(
       HeapEntry* parent, String* reference_name, Object* child);
   void SetElementReference(HeapEntry* parent, int index, Object* child);
+  void SetInternalReference(
+      HeapEntry* parent, const char* reference_name, Object* child);
   void SetPropertyReference(
       HeapEntry* parent, String* reference_name, Object* child);

=======================================
--- /branches/bleeding_edge/test/cctest/test-heap-profiler.cc Tue Jun 15 05:28:25 2010 +++ /branches/bleeding_edge/test/cctest/test-heap-profiler.cc Thu Jun 17 05:56:55 2010
@@ -428,6 +428,53 @@

 }  // namespace

+
+static const v8::HeapGraphNode* GetGlobalObject(
+    const v8::HeapSnapshot* snapshot) {
+  if (i::Snapshot::IsEnabled()) {
+    // In case if snapshots are enabled, there will present a
+    // vanilla deserealized global object, without properties
+    // added by the test code.
+    CHECK_EQ(2, snapshot->GetHead()->GetChildrenCount());
+    // Choose the global object of a bigger size.
+    const v8::HeapGraphNode* node0 =
+        snapshot->GetHead()->GetChild(0)->GetToNode();
+    const v8::HeapGraphNode* node1 =
+        snapshot->GetHead()->GetChild(1)->GetToNode();
+    return node0->GetTotalSize() > node1->GetTotalSize() ? node0 : node1;
+  } else {
+    CHECK_EQ(1, snapshot->GetHead()->GetChildrenCount());
+    return snapshot->GetHead()->GetChild(0)->GetToNode();
+  }
+}
+
+
+static const v8::HeapGraphNode* GetProperty(const v8::HeapGraphNode* node,
+                                            v8::HeapGraphEdge::Type type,
+                                            const char* name) {
+  for (int i = 0, count = node->GetChildrenCount(); i < count; ++i) {
+    const v8::HeapGraphEdge* prop = node->GetChild(i);
+    v8::String::AsciiValue prop_name(prop->GetName());
+    if (prop->GetType() == type && strcmp(name, *prop_name) == 0)
+      return prop->GetToNode();
+  }
+  return NULL;
+}
+
+
+static bool HasString(const v8::HeapGraphNode* node, const char* contents) {
+  for (int i = 0, count = node->GetChildrenCount(); i < count; ++i) {
+    const v8::HeapGraphEdge* prop = node->GetChild(i);
+    const v8::HeapGraphNode* node = prop->GetToNode();
+    if (node->GetType() == v8::HeapGraphNode::STRING) {
+      v8::String::AsciiValue node_name(node->GetName());
+      if (strcmp(contents, *node_name) == 0) return true;
+    }
+  }
+  return false;
+}
+
+
 TEST(HeapSnapshot) {
   v8::HandleScope scope;

@@ -458,53 +505,20 @@
       "var c2 = new C2(a2);");
   const v8::HeapSnapshot* snapshot_env2 =
       v8::HeapProfiler::TakeSnapshot(v8::String::New("env2"));
-  const v8::HeapGraphNode* global_env2;
-  if (i::Snapshot::IsEnabled()) {
-    // In case if snapshots are enabled, there will present a
-    // vanilla deserealized global object, without properties
-    // added by the test code.
-    CHECK_EQ(2, snapshot_env2->GetHead()->GetChildrenCount());
-    // Choose the global object of a bigger size.
-    const v8::HeapGraphNode* node0 =
-        snapshot_env2->GetHead()->GetChild(0)->GetToNode();
-    const v8::HeapGraphNode* node1 =
-        snapshot_env2->GetHead()->GetChild(1)->GetToNode();
-    global_env2 = node0->GetTotalSize() > node1->GetTotalSize() ?
-        node0 : node1;
-  } else {
-    CHECK_EQ(1, snapshot_env2->GetHead()->GetChildrenCount());
-    global_env2 = snapshot_env2->GetHead()->GetChild(0)->GetToNode();
-  }
+  const v8::HeapGraphNode* global_env2 = GetGlobalObject(snapshot_env2);

   // Verify, that JS global object of env2 doesn't have '..1'
   // properties, but has '..2' properties.
-  bool has_a1 = false, has_b1_1 = false, has_b1_2 = false, has_c1 = false;
-  bool has_a2 = false, has_b2_1 = false, has_b2_2 = false, has_c2 = false;
-  // This will be needed further.
-  const v8::HeapGraphNode* a2_node = NULL;
- for (int i = 0, count = global_env2->GetChildrenCount(); i < count; ++i) {
-    const v8::HeapGraphEdge* prop = global_env2->GetChild(i);
-    v8::String::AsciiValue prop_name(prop->GetName());
-    if (strcmp("a1", *prop_name) == 0) has_a1 = true;
-    if (strcmp("b1_1", *prop_name) == 0) has_b1_1 = true;
-    if (strcmp("b1_2", *prop_name) == 0) has_b1_2 = true;
-    if (strcmp("c1", *prop_name) == 0) has_c1 = true;
-    if (strcmp("a2", *prop_name) == 0) {
-      has_a2 = true;
-      a2_node = prop->GetToNode();
-    }
-    if (strcmp("b2_1", *prop_name) == 0) has_b2_1 = true;
-    if (strcmp("b2_2", *prop_name) == 0) has_b2_2 = true;
-    if (strcmp("c2", *prop_name) == 0) has_c2 = true;
-  }
-  CHECK(!has_a1);
-  CHECK(!has_b1_1);
-  CHECK(!has_b1_2);
-  CHECK(!has_c1);
-  CHECK(has_a2);
-  CHECK(has_b2_1);
-  CHECK(has_b2_2);
-  CHECK(has_c2);
+ CHECK_EQ(NULL, GetProperty(global_env2, v8::HeapGraphEdge::PROPERTY, "a1")); + CHECK_EQ(NULL, GetProperty(global_env2, v8::HeapGraphEdge::PROPERTY, "b1_1")); + CHECK_EQ(NULL, GetProperty(global_env2, v8::HeapGraphEdge::PROPERTY, "b1_2")); + CHECK_EQ(NULL, GetProperty(global_env2, v8::HeapGraphEdge::PROPERTY, "c1"));
+  const v8::HeapGraphNode* a2_node =
+      GetProperty(global_env2, v8::HeapGraphEdge::PROPERTY, "a2");
+  CHECK_NE(NULL, a2_node);
+ CHECK_NE(NULL, GetProperty(global_env2, v8::HeapGraphEdge::PROPERTY, "b2_1")); + CHECK_NE(NULL, GetProperty(global_env2, v8::HeapGraphEdge::PROPERTY, "b2_2")); + CHECK_NE(NULL, GetProperty(global_env2, v8::HeapGraphEdge::PROPERTY, "c2"));

   // Verify that anything related to '[ABC]1' is not reachable.
   NamedEntriesDetector det;
@@ -564,5 +578,63 @@
   CHECK(has_b2_1_x_ref);
   CHECK(has_b2_2_x_ref);
 }
+
+
+TEST(HeapSnapshotCodeObjects) {
+  v8::HandleScope scope;
+  v8::Handle<v8::Context> env = v8::Context::New();
+  env->Enter();
+
+  CompileAndRunScript(
+      "function lazy(x) { return x - 1; }\n"
+      "function compiled(x) { return x + 1; }\n"
+      "compiled(1)");
+  const v8::HeapSnapshot* snapshot =
+      v8::HeapProfiler::TakeSnapshot(v8::String::New("code"));
+
+  const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
+  const v8::HeapGraphNode* compiled =
+      GetProperty(global, v8::HeapGraphEdge::PROPERTY, "compiled");
+  CHECK_NE(NULL, compiled);
+  CHECK_EQ(v8::HeapGraphNode::CLOSURE, compiled->GetType());
+  const v8::HeapGraphNode* lazy =
+      GetProperty(global, v8::HeapGraphEdge::PROPERTY, "lazy");
+  CHECK_NE(NULL, lazy);
+  CHECK_EQ(v8::HeapGraphNode::CLOSURE, lazy->GetType());
+
+  // Find references to code.
+  const v8::HeapGraphNode* compiled_code =
+      GetProperty(compiled, v8::HeapGraphEdge::INTERNAL, "code");
+  CHECK_NE(NULL, compiled_code);
+  const v8::HeapGraphNode* lazy_code =
+      GetProperty(lazy, v8::HeapGraphEdge::INTERNAL, "code");
+  CHECK_NE(NULL, lazy_code);
+
+  // Verify that non-compiled code doesn't contain references to "x"
+  // literal, while compiled code does.
+  bool compiled_references_x = false, lazy_references_x = false;
+ for (int i = 0, count = compiled_code->GetChildrenCount(); i < count; ++i) {
+    const v8::HeapGraphEdge* prop = compiled_code->GetChild(i);
+    const v8::HeapGraphNode* node = prop->GetToNode();
+    if (node->GetType() == v8::HeapGraphNode::CODE) {
+      if (HasString(node, "x")) {
+        compiled_references_x = true;
+        break;
+      }
+    }
+  }
+  for (int i = 0, count = lazy_code->GetChildrenCount(); i < count; ++i) {
+    const v8::HeapGraphEdge* prop = lazy_code->GetChild(i);
+    const v8::HeapGraphNode* node = prop->GetToNode();
+    if (node->GetType() == v8::HeapGraphNode::CODE) {
+      if (HasString(node, "x")) {
+        lazy_references_x = true;
+        break;
+      }
+    }
+  }
+  CHECK(compiled_references_x);
+  CHECK(!lazy_references_x);
+}

 #endif  // ENABLE_LOGGING_AND_PROFILING

--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev

Reply via email to