HeapProfiler: provide human readable names for code objects.
authorloislo@chromium.org <loislo@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 5 Nov 2013 13:23:03 +0000 (13:23 +0000)
committerloislo@chromium.org <loislo@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 5 Nov 2013 13:23:03 +0000 (13:23 +0000)
It is very hard to understand the structure of the heap even for about:blank page
because code objects in the heap have no names. This patch propagates the names
for Code::STUB and Code::BUILTIN code objects.
Also it assign function names from SharedFunctionInfo to the code objects.

BUG=
R=alph@chromium.org, svenpanne@chromium.org, yurys@chromium.org

Review URL: https://codereview.chromium.org/52643002

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@17486 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/builtins.h
src/heap-snapshot-generator.cc
src/heap-snapshot-generator.h
test/cctest/test-heap-profiler.cc

index 9b589d8..7e081ee 100644 (file)
@@ -364,6 +364,11 @@ class Builtins {
   }
 
   static const char* GetName(JavaScript id) { return javascript_names_[id]; }
+  const char* name(int index) {
+    ASSERT(index >= 0);
+    ASSERT(index < builtin_count);
+    return names_[index];
+  }
   static int GetArgumentsCount(JavaScript id) { return javascript_argc_[id]; }
   Handle<Code> GetCode(JavaScript id, bool* resolved);
   static int NumberOfJavaScriptBuiltins() { return id_count; }
index 10d113c..b7b7f22 100644 (file)
@@ -30,6 +30,7 @@
 #include "heap-snapshot-generator-inl.h"
 
 #include "allocation-tracker.h"
+#include "code-stubs.h"
 #include "heap-profiler.h"
 #include "debug.h"
 #include "types.h"
@@ -1110,7 +1111,7 @@ class IndexedReferencesExtractor : public ObjectVisitor {
   void VisitCodeEntry(Address entry_address) {
      Code* code = Code::cast(Code::GetObjectFromEntryAddress(entry_address));
      generator_->SetInternalReference(parent_obj_, parent_, "code", code);
-     generator_->TagObject(code, "(code)");
+     generator_->TagCodeObject(code);
   }
   void VisitPointers(Object** start, Object** end) {
     for (Object** p = start; p < end; p++) {
@@ -1370,10 +1371,20 @@ void V8HeapExplorer::ExtractMapReferences(int entry, Map* map) {
 void V8HeapExplorer::ExtractSharedFunctionInfoReferences(
     int entry, SharedFunctionInfo* shared) {
   HeapObject* obj = shared;
+  StringsStorage* names = collection_->names();
+  String* shared_name = shared->DebugName();
+  const char* name = NULL;
+  if (shared_name != *heap_->isolate()->factory()->empty_string()) {
+    name = names->GetName(shared_name);
+    TagObject(shared->code(), names->GetFormatted("(code for %s)", name));
+  } else {
+    TagObject(shared->code(), names->GetFormatted("(%s code)",
+        Code::Kind2String(shared->code()->kind())));
+  }
+
   SetInternalReference(obj, entry,
                        "name", shared->name(),
                        SharedFunctionInfo::kNameOffset);
-  TagObject(shared->code(), "(code)");
   SetInternalReference(obj, entry,
                        "code", shared->code(),
                        SharedFunctionInfo::kCodeOffset);
@@ -1387,7 +1398,10 @@ void V8HeapExplorer::ExtractSharedFunctionInfoReferences(
   SetInternalReference(obj, entry,
                        "script", shared->script(),
                        SharedFunctionInfo::kScriptOffset);
-  TagObject(shared->construct_stub(), "(code)");
+  const char* construct_stub_name = name ?
+      names->GetFormatted("(construct stub code for %s)", name) :
+      "(construct stub code)";
+  TagObject(shared->construct_stub(), construct_stub_name);
   SetInternalReference(obj, entry,
                        "construct_stub", shared->construct_stub(),
                        SharedFunctionInfo::kConstructStubOffset);
@@ -1400,6 +1414,9 @@ void V8HeapExplorer::ExtractSharedFunctionInfoReferences(
   SetInternalReference(obj, entry,
                        "inferred_name", shared->inferred_name(),
                        SharedFunctionInfo::kInferredNameOffset);
+  SetInternalReference(obj, entry,
+                       "optimized_code_map", shared->optimized_code_map(),
+                       SharedFunctionInfo::kOptimizedCodeMapOffset);
   SetWeakReference(obj, entry,
                    1, shared->initial_map(),
                    SharedFunctionInfo::kInitialMapOffset);
@@ -1449,7 +1466,23 @@ void V8HeapExplorer::ExtractCodeCacheReferences(
 }
 
 
+void V8HeapExplorer::TagCodeObject(Code* code, const char* external_name) {
+  TagObject(code, collection_->names()->GetFormatted("(%s code)",
+      external_name));
+}
+
+
+void V8HeapExplorer::TagCodeObject(Code* code) {
+  if (code->kind() == Code::STUB) {
+    TagObject(code, collection_->names()->GetFormatted(
+        "(%s code)", CodeStub::MajorName(
+            static_cast<CodeStub::Major>(code->major_key()), true)));
+  }
+}
+
+
 void V8HeapExplorer::ExtractCodeReferences(int entry, Code* code) {
+  TagCodeObject(code);
   TagObject(code->relocation_info(), "(code relocation info)");
   SetInternalReference(code, entry,
                        "relocation_info", code->relocation_info(),
@@ -1695,9 +1728,10 @@ class RootsReferencesExtractor : public ObjectVisitor {
   };
 
  public:
-  RootsReferencesExtractor()
+  explicit RootsReferencesExtractor(Heap* heap)
       : collecting_all_references_(false),
-        previous_reference_count_(0) {
+        previous_reference_count_(0),
+        heap_(heap) {
   }
 
   void VisitPointers(Object** start, Object** end) {
@@ -1712,22 +1746,30 @@ class RootsReferencesExtractor : public ObjectVisitor {
 
   void FillReferences(V8HeapExplorer* explorer) {
     ASSERT(strong_references_.length() <= all_references_.length());
+    Builtins* builtins = heap_->isolate()->builtins();
     for (int i = 0; i < reference_tags_.length(); ++i) {
       explorer->SetGcRootsReference(reference_tags_[i].tag);
     }
-    int strong_index = 0, all_index = 0, tags_index = 0;
+    int strong_index = 0, all_index = 0, tags_index = 0, builtin_index = 0;
     while (all_index < all_references_.length()) {
       if (strong_index < strong_references_.length() &&
           strong_references_[strong_index] == all_references_[all_index]) {
         explorer->SetGcSubrootReference(reference_tags_[tags_index].tag,
                                         false,
-                                        all_references_[all_index++]);
+                                        all_references_[all_index]);
         ++strong_index;
       } else {
         explorer->SetGcSubrootReference(reference_tags_[tags_index].tag,
                                         true,
-                                        all_references_[all_index++]);
+                                        all_references_[all_index]);
+      }
+      if (reference_tags_[tags_index].tag ==
+          VisitorSynchronization::kBuiltins) {
+        ASSERT(all_references_[all_index]->IsCode());
+        explorer->TagCodeObject(Code::cast(all_references_[all_index]),
+            builtins->name(builtin_index++));
       }
+      ++all_index;
       if (reference_tags_[tags_index].index == all_index) ++tags_index;
     }
   }
@@ -1746,6 +1788,7 @@ class RootsReferencesExtractor : public ObjectVisitor {
   List<Object*> all_references_;
   int previous_reference_count_;
   List<IndexTag> reference_tags_;
+  Heap* heap_;
 };
 
 
@@ -1771,7 +1814,7 @@ bool V8HeapExplorer::IterateAndExtractReferences(
   }
 
   SetRootGcRootsReference();
-  RootsReferencesExtractor extractor;
+  RootsReferencesExtractor extractor(heap_);
   heap_->IterateRoots(&extractor, VISIT_ONLY_STRONG);
   extractor.SetCollectingAllReferences();
   heap_->IterateRoots(&extractor, VISIT_ALL);
index e4038b1..b8199ba 100644 (file)
@@ -447,6 +447,8 @@ class V8HeapExplorer : public HeapEntriesAllocator {
   int EstimateObjectsCount(HeapIterator* iterator);
   bool IterateAndExtractReferences(SnapshotFillerInterface* filler);
   void TagGlobalObjects();
+  void TagCodeObject(Code* code);
+  void TagCodeObject(Code* code, const char* external_name);
 
   static String* GetConstructorName(JSObject* object);
 
index db2243a..4544a9f 100644 (file)
@@ -2177,3 +2177,56 @@ TEST(TrackHeapAllocations) {
   CHECK_GE(node->allocation_size(), 4 * node->allocation_count());
   heap_profiler->StopRecordingHeapAllocations();
 }
+
+
+static const v8::HeapGraphNode* GetNodeByPath(const v8::HeapSnapshot* snapshot,
+                                              const char* path[],
+                                              int depth) {
+  const v8::HeapGraphNode* node = snapshot->GetRoot();
+  for (int current_depth = 0; current_depth < depth; ++current_depth) {
+    int i, count = node->GetChildrenCount();
+    for (i = 0; i < count; ++i) {
+      const v8::HeapGraphEdge* edge = node->GetChild(i);
+      const v8::HeapGraphNode* to_node = edge->GetToNode();
+      v8::String::Utf8Value edge_name(edge->GetName());
+      v8::String::Utf8Value node_name(to_node->GetName());
+      i::EmbeddedVector<char, 100> name;
+      i::OS::SNPrintF(name, "%s::%s", *edge_name, *node_name);
+      if (strstr(name.start(), path[current_depth])) {
+        node = to_node;
+        break;
+      }
+    }
+    if (i == count) return NULL;
+  }
+  return node;
+}
+
+
+TEST(CheckCodeNames) {
+  LocalContext env;
+  v8::HandleScope scope(env->GetIsolate());
+  v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
+  CompileRun("var a = 1.1;");
+  const v8::HeapSnapshot* snapshot =
+      heap_profiler->TakeHeapSnapshot(v8_str("CheckCodeNames"));
+  CHECK(ValidateSnapshot(snapshot));
+
+  const char* stub_path[] = {
+    "::(GC roots)",
+    "::(Strong roots)",
+    "code_stubs::",
+    "::(ArraySingleArgumentConstructorStub code)"
+  };
+  const v8::HeapGraphNode* node = GetNodeByPath(snapshot,
+      stub_path, ARRAY_SIZE(stub_path));
+  CHECK_NE(NULL, node);
+
+  const char* builtin_path[] = {
+    "::(GC roots)",
+    "::(Builtins)",
+    "::(KeyedLoadIC_Generic code)"
+  };
+  node = GetNodeByPath(snapshot, builtin_path, ARRAY_SIZE(builtin_path));
+  CHECK_NE(NULL, node);
+}