Revision: 7259
Author:   [email protected]
Date:     Fri Mar 18 05:49:27 2011
Log:      Dramatically speed up detailed heap snapshot generation.

I've replaced calls to HashMap::Clear with instance re-creation.
This has sped up taking a heap snapshot of GMail from 33s -> 3s!

[email protected]
BUG=none
TEST=none

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

Modified:
 /branches/bleeding_edge/src/objects-inl.h
 /branches/bleeding_edge/src/objects.h
 /branches/bleeding_edge/src/profile-generator.cc
 /branches/bleeding_edge/src/profile-generator.h

=======================================
--- /branches/bleeding_edge/src/objects-inl.h   Thu Mar 10 04:05:31 2011
+++ /branches/bleeding_edge/src/objects-inl.h   Fri Mar 18 05:49:27 2011
@@ -1311,6 +1311,12 @@
   return ((Size() - GetHeaderSize()) >> kPointerSizeLog2) -
          map()->inobject_properties();
 }
+
+
+int JSObject::GetInternalFieldOffset(int index) {
+  ASSERT(index < GetInternalFieldCount() && index >= 0);
+  return GetHeaderSize() + (kPointerSize * index);
+}


 Object* JSObject::GetInternalField(int index) {
@@ -1362,6 +1368,14 @@
   }
   return value;
 }
+
+
+int JSObject::GetInObjectPropertyOffset(int index) {
+  // Adjust for the number of properties stored in the object.
+  index -= map()->inobject_properties();
+  ASSERT(index < 0);
+  return map()->instance_size() + (index * kPointerSize);
+}


 Object* JSObject::InObjectPropertyAt(int index) {
=======================================
--- /branches/bleeding_edge/src/objects.h       Thu Mar 10 04:05:31 2011
+++ /branches/bleeding_edge/src/objects.h       Fri Mar 18 05:49:27 2011
@@ -1587,6 +1587,7 @@
   inline int GetHeaderSize();

   inline int GetInternalFieldCount();
+  inline int GetInternalFieldOffset(int index);
   inline Object* GetInternalField(int index);
   inline void SetInternalField(int index, Object* value);

@@ -1704,6 +1705,7 @@
   inline Object* FastPropertyAtPut(int index, Object* value);

   // Access to in object properties.
+  inline int GetInObjectPropertyOffset(int index);
   inline Object* InObjectPropertyAt(int index);
   inline Object* InObjectPropertyAtPut(int index,
                                        Object* value,
=======================================
--- /branches/bleeding_edge/src/profile-generator.cc Thu Mar 10 04:58:57 2011 +++ /branches/bleeding_edge/src/profile-generator.cc Fri Mar 18 05:49:27 2011
@@ -1826,25 +1826,40 @@
   IndexedReferencesExtractor(V8HeapExplorer* generator,
                              HeapObject* parent_obj,
                              HeapEntry* parent_entry,
-                             HeapObjectsSet* known_references = NULL)
+                             bool process_field_marks = false)
       : generator_(generator),
         parent_obj_(parent_obj),
         parent_(parent_entry),
-        known_references_(known_references),
+        process_field_marks_(process_field_marks),
         next_index_(1) {
   }
   void VisitPointers(Object** start, Object** end) {
     for (Object** p = start; p < end; p++) {
-      if (!known_references_ || !known_references_->Contains(*p)) {
- generator_->SetHiddenReference(parent_obj_, parent_, next_index_++, *p);
-      }
+      if (CheckVisitedAndUnmark(p)) continue;
+ generator_->SetHiddenReference(parent_obj_, parent_, next_index_++, *p);
     }
   }
+  static void MarkVisitedField(HeapObject* obj, int offset) {
+    if (offset < 0) return;
+    Address field = obj->address() + offset;
+    ASSERT(!Memory::Object_at(field)->IsFailure());
+    ASSERT(Memory::Object_at(field)->IsHeapObject());
+    *field |= kFailureTag;
+  }
  private:
+  bool CheckVisitedAndUnmark(Object** field) {
+    if (process_field_marks_ && (*field)->IsFailure()) {
+ intptr_t untagged = reinterpret_cast<intptr_t>(*field) & ~kFailureTagMask;
+      *field = reinterpret_cast<Object*>(untagged | kHeapObjectTag);
+      ASSERT((*field)->IsHeapObject());
+      return true;
+    }
+    return false;
+  }
   V8HeapExplorer* generator_;
   HeapObject* parent_obj_;
   HeapEntry* parent_;
-  HeapObjectsSet* known_references_;
+  bool process_field_marks_;
   int next_index_;
 };

@@ -1853,7 +1868,6 @@
   HeapEntry* entry = GetEntry(obj);
   if (entry == NULL) return;  // No interest in this object.

-  known_references_.Clear();
   if (obj->IsJSGlobalProxy()) {
     // We need to reference JS global objects from snapshot's root.
     // We use JSGlobalProxy because this is what embedder (e.g. browser)
@@ -1868,17 +1882,29 @@
     ExtractPropertyReferences(js_obj, entry);
     ExtractElementReferences(js_obj, entry);
     ExtractInternalReferences(js_obj, entry);
-    SetPropertyReference(
-        obj, entry, Heap::Proto_symbol(), js_obj->GetPrototype());
+    SetPropertyReference(obj, entry,
+                         Heap::Proto_symbol(), js_obj->GetPrototype());
     if (obj->IsJSFunction()) {
-      JSFunction* js_fun = JSFunction::cast(obj);
-      if (js_fun->has_prototype()) {
-        SetPropertyReference(
-            obj, entry, Heap::prototype_symbol(), js_fun->prototype());
+      JSFunction* js_fun = JSFunction::cast(js_obj);
+      SetInternalReference(
+          js_fun, entry,
+          "code", js_fun->shared(),
+          JSFunction::kSharedFunctionInfoOffset);
+      Object* proto_or_map = js_fun->prototype_or_initial_map();
+      if (!proto_or_map->IsTheHole()) {
+        if (!proto_or_map->IsMap()) {
+          SetPropertyReference(
+              obj, entry,
+              Heap::prototype_symbol(), proto_or_map,
+              JSFunction::kPrototypeOrInitialMapOffset);
+        } else {
+          SetPropertyReference(
+              obj, entry,
+              Heap::prototype_symbol(), js_fun->prototype());
+        }
       }
     }
-    IndexedReferencesExtractor refs_extractor(
-        this, obj, entry, &known_references_);
+    IndexedReferencesExtractor refs_extractor(this, obj, entry, true);
     obj->Iterate(&refs_extractor);
   } else if (obj->IsString()) {
     if (obj->IsConsString()) {
@@ -1911,7 +1937,6 @@
         SetClosureReference(js_obj, entry, local_name, context->get(idx));
       }
     }
-    SetInternalReference(js_obj, entry, "code", func->shared());
   }
 }

@@ -1924,13 +1949,22 @@
       switch (descs->GetType(i)) {
         case FIELD: {
           int index = descs->GetFieldIndex(i);
-          SetPropertyReference(
- js_obj, entry, descs->GetKey(i), js_obj->FastPropertyAt(index));
+          if (index < js_obj->map()->inobject_properties()) {
+            SetPropertyReference(
+                js_obj, entry,
+                descs->GetKey(i), js_obj->InObjectPropertyAt(index),
+                js_obj->GetInObjectPropertyOffset(index));
+          } else {
+            SetPropertyReference(
+                js_obj, entry,
+                descs->GetKey(i), js_obj->FastPropertyAt(index));
+          }
           break;
         }
         case CONSTANT_FUNCTION:
           SetPropertyReference(
- js_obj, entry, descs->GetKey(i), descs->GetConstantFunction(i));
+              js_obj, entry,
+              descs->GetKey(i), descs->GetConstantFunction(i));
           break;
         default: ;
       }
@@ -1990,7 +2024,8 @@
   int length = js_obj->GetInternalFieldCount();
   for (int i = 0; i < length; ++i) {
     Object* o = js_obj->GetInternalField(i);
-    SetInternalReference(js_obj, entry, i, o);
+    SetInternalReference(
+        js_obj, entry, i, o, js_obj->GetInternalFieldOffset(i));
   }
 }

@@ -2052,7 +2087,6 @@
collection_->names()->GetName(reference_name),
                                child_obj,
                                child_entry);
-    known_references_.Insert(child_obj);
   }
 }

@@ -2069,7 +2103,6 @@
                                  index,
                                  child_obj,
                                  child_entry);
-    known_references_.Insert(child_obj);
   }
 }

@@ -2077,7 +2110,8 @@
 void V8HeapExplorer::SetInternalReference(HeapObject* parent_obj,
                                           HeapEntry* parent_entry,
                                           const char* reference_name,
-                                          Object* child_obj) {
+                                          Object* child_obj,
+                                          int field_offset) {
   HeapEntry* child_entry = GetEntry(child_obj);
   if (child_entry != NULL) {
     filler_->SetNamedReference(HeapGraphEdge::kInternal,
@@ -2086,7 +2120,7 @@
                                reference_name,
                                child_obj,
                                child_entry);
-    known_references_.Insert(child_obj);
+    IndexedReferencesExtractor::MarkVisitedField(parent_obj, field_offset);
   }
 }

@@ -2094,7 +2128,8 @@
 void V8HeapExplorer::SetInternalReference(HeapObject* parent_obj,
                                           HeapEntry* parent_entry,
                                           int index,
-                                          Object* child_obj) {
+                                          Object* child_obj,
+                                          int field_offset) {
   HeapEntry* child_entry = GetEntry(child_obj);
   if (child_entry != NULL) {
     filler_->SetNamedReference(HeapGraphEdge::kInternal,
@@ -2103,7 +2138,7 @@
                                collection_->names()->GetName(index),
                                child_obj,
                                child_entry);
-    known_references_.Insert(child_obj);
+    IndexedReferencesExtractor::MarkVisitedField(parent_obj, field_offset);
   }
 }

@@ -2127,7 +2162,8 @@
 void V8HeapExplorer::SetPropertyReference(HeapObject* parent_obj,
                                           HeapEntry* parent_entry,
                                           String* reference_name,
-                                          Object* child_obj) {
+                                          Object* child_obj,
+                                          int field_offset) {
   HeapEntry* child_entry = GetEntry(child_obj);
   if (child_entry != NULL) {
     HeapGraphEdge::Type type = reference_name->length() > 0 ?
@@ -2138,16 +2174,15 @@
collection_->names()->GetName(reference_name),
                                child_obj,
                                child_entry);
-    known_references_.Insert(child_obj);
+    IndexedReferencesExtractor::MarkVisitedField(parent_obj, field_offset);
   }
 }


-void V8HeapExplorer::SetPropertyShortcutReference(
-    HeapObject* parent_obj,
-    HeapEntry* parent_entry,
-    String* reference_name,
-    Object* child_obj) {
+void V8HeapExplorer::SetPropertyShortcutReference(HeapObject* parent_obj,
+                                                  HeapEntry* parent_entry,
+                                                  String* reference_name,
+                                                  Object* child_obj) {
   HeapEntry* child_entry = GetEntry(child_obj);
   if (child_entry != NULL) {
     filler_->SetNamedReference(HeapGraphEdge::kShortcut,
=======================================
--- /branches/bleeding_edge/src/profile-generator.h     Thu Mar 10 04:22:59 2011
+++ /branches/bleeding_edge/src/profile-generator.h     Fri Mar 18 05:49:27 2011
@@ -1030,11 +1030,13 @@
   void SetInternalReference(HeapObject* parent_obj,
                             HeapEntry* parent,
                             const char* reference_name,
-                            Object* child);
+                            Object* child,
+                            int field_offset = -1);
   void SetInternalReference(HeapObject* parent_obj,
                             HeapEntry* parent,
                             int index,
-                            Object* child);
+                            Object* child,
+                            int field_offset = -1);
   void SetHiddenReference(HeapObject* parent_obj,
                           HeapEntry* parent,
                           int index,
@@ -1042,7 +1044,8 @@
   void SetPropertyReference(HeapObject* parent_obj,
                             HeapEntry* parent,
                             String* reference_name,
-                            Object* child);
+                            Object* child,
+                            int field_offset = -1);
   void SetPropertyShortcutReference(HeapObject* parent_obj,
                                     HeapEntry* parent,
                                     String* reference_name,
@@ -1056,9 +1059,6 @@
   HeapSnapshot* snapshot_;
   HeapSnapshotsCollection* collection_;
   SnapshottingProgressReportingInterface* progress_;
-  // Used during references extraction to mark heap objects that
-  // are references via non-hidden properties.
-  HeapObjectsSet known_references_;
   SnapshotFillerInterface* filler_;

   static HeapObject* const kGcRootsObject;

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

Reply via email to