Heap profiler improvements.
authormikhail.naganov@gmail.com <mikhail.naganov@gmail.com@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 26 Oct 2009 10:51:30 +0000 (10:51 +0000)
committermikhail.naganov@gmail.com <mikhail.naganov@gmail.com@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 26 Oct 2009 10:51:30 +0000 (10:51 +0000)
- account code objects in retainers profile;
- differentiate between function boilerplates and closures;
- simplify code;

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

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

src/heap-profiler.cc
src/heap-profiler.h
src/heap.h
src/objects.cc

index bfd378d..4f9456e 100644 (file)
@@ -78,6 +78,10 @@ JSObjectsCluster Clusterizer::Clusterize(HeapObject* obj, bool fine_grain) {
     }
   } else if (obj->IsString()) {
     return JSObjectsCluster(Heap::String_symbol());
+  } else if (obj->IsJSGlobalPropertyCell()) {
+    return JSObjectsCluster(JSObjectsCluster::GLOBAL_PROPERTY);
+  } else if (obj->IsCode() || obj->IsSharedFunctionInfo() || obj->IsScript()) {
+    return JSObjectsCluster(JSObjectsCluster::CODE);
   }
   return JSObjectsCluster();
 }
@@ -112,6 +116,16 @@ int Clusterizer::CalculateNetworkSize(JSObject* obj) {
   if (FixedArray::cast(obj->elements())->length() != 0) {
     size += obj->elements()->Size();
   }
+  // For functions, also account non-empty context and literals sizes.
+  if (obj->IsJSFunction()) {
+    JSFunction* f = JSFunction::cast(obj);
+    if (f->unchecked_context()->IsContext()) {
+      size += f->context()->Size();
+    }
+    if (f->literals()->length() != 0) {
+      size += f->literals()->Size();
+    }
+  }
   return size;
 }
 
@@ -127,15 +141,15 @@ class ReferencesExtractor : public ObjectVisitor {
   }
 
   void VisitPointer(Object** o) {
-    if ((*o)->IsJSObject() || (*o)->IsString()) {
-      profile_->StoreReference(cluster_, HeapObject::cast(*o));
-    } else if ((*o)->IsFixedArray() && !inside_array_) {
+    if ((*o)->IsFixedArray() && !inside_array_) {
       // Traverse one level deep for data members that are fixed arrays.
       // This covers the case of 'elements' and 'properties' of JSObject,
       // and function contexts.
       inside_array_ = true;
       FixedArray::cast(*o)->Iterate(this);
       inside_array_ = false;
+    } else {
+      profile_->StoreReference(cluster_, HeapObject::cast(*o));
     }
   }
 
@@ -340,6 +354,8 @@ void JSObjectsCluster::Print(StringStream* accumulator) const {
     accumulator->Add("(roots)");
   } else if (constructor_ == FromSpecialCase(GLOBAL_PROPERTY)) {
     accumulator->Add("(global property)");
+  } else if (constructor_ == FromSpecialCase(CODE)) {
+    accumulator->Add("(code)");
   } else if (constructor_ == FromSpecialCase(SELF)) {
     accumulator->Add("(self)");
   } else {
@@ -527,6 +543,7 @@ RetainerHeapProfile::RetainerHeapProfile()
 void RetainerHeapProfile::StoreReference(const JSObjectsCluster& cluster,
                                          HeapObject* ref) {
   JSObjectsCluster ref_cluster = Clusterizer::Clusterize(ref);
+  if (ref_cluster.is_null()) return;
   JSObjectsRetainerTree::Locator ref_loc;
   if (retainers_tree_.Insert(ref_cluster, &ref_loc)) {
     ref_loc.set_value(new JSObjectsClusterTree());
@@ -537,15 +554,10 @@ void RetainerHeapProfile::StoreReference(const JSObjectsCluster& cluster,
 
 
 void RetainerHeapProfile::CollectStats(HeapObject* obj) {
-  if (obj->IsJSObject()) {
-    const JSObjectsCluster cluster = Clusterizer::Clusterize(obj);
-    ReferencesExtractor extractor(cluster, this);
-    obj->Iterate(&extractor);
-  } else if (obj->IsJSGlobalPropertyCell()) {
-    JSObjectsCluster global_prop(JSObjectsCluster::GLOBAL_PROPERTY);
-    ReferencesExtractor extractor(global_prop, this);
-    obj->Iterate(&extractor);
-  }
+  const JSObjectsCluster cluster = Clusterizer::Clusterize(obj);
+  if (cluster.is_null()) return;
+  ReferencesExtractor extractor(cluster, this);
+  obj->Iterate(&extractor);
 }
 
 
index bd875df..f8cb04d 100644 (file)
@@ -54,7 +54,8 @@ class JSObjectsCluster BASE_EMBEDDED {
   enum SpecialCase {
     ROOTS = 1,
     GLOBAL_PROPERTY = 2,
-    SELF = 3  // This case is used in ClustersCoarser only.
+    CODE = 3,
+    SELF = 100  // This case is used in ClustersCoarser only.
   };
 
   JSObjectsCluster() : constructor_(NULL), instance_(NULL) {}
@@ -97,6 +98,7 @@ class JSObjectsCluster BASE_EMBEDDED {
     switch (special) {
       case ROOTS: return Heap::result_symbol();
       case GLOBAL_PROPERTY: return Heap::code_symbol();
+      case CODE: return Heap::arguments_shadow_symbol();
       case SELF: return Heap::catch_var_symbol();
       default:
         UNREACHABLE();
index cd49a8d..05be0c4 100644 (file)
@@ -221,7 +221,8 @@ namespace internal {
   V(exec_symbol, "exec")                                                 \
   V(zero_symbol, "0")                                                    \
   V(global_eval_symbol, "GlobalEval")                                    \
-  V(identity_hash_symbol, "v8::IdentityHash")
+  V(identity_hash_symbol, "v8::IdentityHash")                            \
+  V(closure_symbol, "(closure)")
 
 
 // Forward declaration of the GCTracer class.
index af1a0e5..28be636 100644 (file)
@@ -1251,7 +1251,8 @@ String* JSObject::class_name() {
 
 String* JSObject::constructor_name() {
   if (IsJSFunction()) {
-    return Heap::function_class_symbol();
+    return JSFunction::cast(this)->IsBoilerplate() ?
+      Heap::function_class_symbol() : Heap::closure_symbol();
   }
   if (map()->constructor()->IsJSFunction()) {
     JSFunction* constructor = JSFunction::cast(map()->constructor());