Heap profiler: for objects of class "Object", try to lookup name
authormikhail.naganov@gmail.com <mikhail.naganov@gmail.com@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 23 Aug 2011 12:24:54 +0000 (12:24 +0000)
committermikhail.naganov@gmail.com <mikhail.naganov@gmail.com@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 23 Aug 2011 12:24:54 +0000 (12:24 +0000)
from the constructor function. This works well for binding objects,
and this matches DevTools' algorithm for name assignment.

R=sgjesse@chromium.org
BUG=none
TEST=test-heap-profiler/GetConstructorName

Review URL: http://codereview.chromium.org/7709026

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

src/profile-generator.cc
src/profile-generator.h
test/cctest/test-heap-profiler.cc

index 07426f293992dab657bcdd02101b1fe265142d73..db9f8928de7f6c508f7cdb690f0b8df04d62effa 100644 (file)
@@ -1663,7 +1663,7 @@ HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object,
   } else if (object->IsJSGlobalObject()) {
     const char* tag = objects_tags_.GetTag(object);
     const char* name = collection_->names()->GetName(
-        GetConstructorNameForHeapProfile(JSObject::cast(object)));
+        GetConstructorName(JSObject::cast(object)));
     if (tag != NULL) {
       name = collection_->names()->GetFormatted("%s / %s", name, tag);
     }
@@ -1691,8 +1691,7 @@ HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object,
     return AddEntry(object,
                     HeapEntry::kObject,
                     collection_->names()->GetName(
-                        GetConstructorNameForHeapProfile(
-                            JSObject::cast(object))),
+                        GetConstructorName(JSObject::cast(object))),
                     children_count,
                     retainers_count);
   } else if (object->IsString()) {
@@ -2101,6 +2100,31 @@ void V8HeapExplorer::ExtractInternalReferences(JSObject* js_obj,
 }
 
 
+String* V8HeapExplorer::GetConstructorName(JSObject* object) {
+  if (object->IsJSFunction()) return HEAP->closure_symbol();
+  String* constructor_name = object->constructor_name();
+  if (constructor_name == HEAP->Object_symbol()) {
+    // Look up an immediate "constructor" property, if it is a function,
+    // return its name. This is for instances of binding objects, which
+    // have prototype constructor type "Object".
+    Object* constructor_prop = NULL;
+    LookupResult result;
+    object->LocalLookupRealNamedProperty(HEAP->constructor_symbol(), &result);
+    if (result.IsProperty()) {
+      constructor_prop = result.GetLazyValue();
+    }
+    if (constructor_prop->IsJSFunction()) {
+      Object* maybe_name = JSFunction::cast(constructor_prop)->shared()->name();
+      if (maybe_name->IsString()) {
+        String* name = String::cast(maybe_name);
+        if (name->length() > 0) return name;
+      }
+    }
+  }
+  return object->constructor_name();
+}
+
+
 HeapEntry* V8HeapExplorer::GetEntry(Object* obj) {
   if (!obj->IsHeapObject()) return NULL;
   return filler_->FindOrAddEntry(obj, this);
@@ -3250,10 +3274,4 @@ void HeapSnapshotJSONSerializer::SortHashMap(
   sorted_entries->Sort(SortUsingEntryValue);
 }
 
-
-String* GetConstructorNameForHeapProfile(JSObject* object) {
-  if (object->IsJSFunction()) return HEAP->closure_symbol();
-  return object->constructor_name();
-}
-
 } }  // namespace v8::internal
index d1c2b3804af6b65e584b5d72e5fe4e3f056375d0..9ab44a1e210061ac7965f398cb7309dbc84fb288 100644 (file)
@@ -921,6 +921,8 @@ class V8HeapExplorer : public HeapEntriesAllocator {
   bool IterateAndExtractReferences(SnapshotFillerInterface* filler);
   void TagGlobalObjects();
 
+  static String* GetConstructorName(JSObject* object);
+
   static HeapObject* const kInternalRootObject;
 
  private:
@@ -1119,9 +1121,6 @@ class HeapSnapshotJSONSerializer {
   DISALLOW_COPY_AND_ASSIGN(HeapSnapshotJSONSerializer);
 };
 
-
-String* GetConstructorNameForHeapProfile(JSObject* object);
-
 } }  // namespace v8::internal
 
 #endif  // V8_PROFILE_GENERATOR_H_
index 169e6dcbdb601209c2c4ec562c00ad9cc7c74005..24d96193a2e0d85178828792b756dd8998059840 100644 (file)
@@ -889,3 +889,59 @@ TEST(NodesIteration) {
   }
   CHECK_EQ(1, count);
 }
+
+
+static int StringCmp(const char* ref, i::String* act) {
+  i::SmartPointer<char> s_act = act->ToCString();
+  int result = strcmp(ref, *s_act);
+  if (result != 0)
+    fprintf(stderr, "Expected: \"%s\", Actual: \"%s\"\n", ref, *s_act);
+  return result;
+}
+
+
+TEST(GetConstructorName) {
+  v8::HandleScope scope;
+  LocalContext env;
+
+  CompileRun(
+      "function Constructor1() {};\n"
+      "var obj1 = new Constructor1();\n"
+      "var Constructor2 = function() {};\n"
+      "var obj2 = new Constructor2();\n"
+      "var obj3 = {};\n"
+      "obj3.constructor = function Constructor3() {};\n"
+      "var obj4 = {};\n"
+      "// Slow properties\n"
+      "for (var i=0; i<2000; ++i) obj4[\"p\" + i] = i;\n"
+      "obj4.constructor = function Constructor4() {};\n"
+      "var obj5 = {};\n"
+      "var obj6 = {};\n"
+      "obj6.constructor = 6;");
+  v8::Local<v8::Object> js_global =
+      env->Global()->GetPrototype().As<v8::Object>();
+  v8::Local<v8::Object> obj1 = js_global->Get(v8_str("obj1")).As<v8::Object>();
+  i::Handle<i::JSObject> js_obj1 = v8::Utils::OpenHandle(*obj1);
+  CHECK_EQ(0, StringCmp(
+      "Constructor1", i::V8HeapExplorer::GetConstructorName(*js_obj1)));
+  v8::Local<v8::Object> obj2 = js_global->Get(v8_str("obj2")).As<v8::Object>();
+  i::Handle<i::JSObject> js_obj2 = v8::Utils::OpenHandle(*obj2);
+  CHECK_EQ(0, StringCmp(
+      "Constructor2", i::V8HeapExplorer::GetConstructorName(*js_obj2)));
+  v8::Local<v8::Object> obj3 = js_global->Get(v8_str("obj3")).As<v8::Object>();
+  i::Handle<i::JSObject> js_obj3 = v8::Utils::OpenHandle(*obj3);
+  CHECK_EQ(0, StringCmp(
+      "Constructor3", i::V8HeapExplorer::GetConstructorName(*js_obj3)));
+  v8::Local<v8::Object> obj4 = js_global->Get(v8_str("obj4")).As<v8::Object>();
+  i::Handle<i::JSObject> js_obj4 = v8::Utils::OpenHandle(*obj4);
+  CHECK_EQ(0, StringCmp(
+      "Constructor4", i::V8HeapExplorer::GetConstructorName(*js_obj4)));
+  v8::Local<v8::Object> obj5 = js_global->Get(v8_str("obj5")).As<v8::Object>();
+  i::Handle<i::JSObject> js_obj5 = v8::Utils::OpenHandle(*obj5);
+  CHECK_EQ(0, StringCmp(
+      "Object", i::V8HeapExplorer::GetConstructorName(*js_obj5)));
+  v8::Local<v8::Object> obj6 = js_global->Get(v8_str("obj6")).As<v8::Object>();
+  i::Handle<i::JSObject> js_obj6 = v8::Utils::OpenHandle(*obj6);
+  CHECK_EQ(0, StringCmp(
+      "Object", i::V8HeapExplorer::GetConstructorName(*js_obj6)));
+}