Revision: 20429
Author:   [email protected]
Date:     Wed Apr  2 11:19:53 2014 UTC
Log:      Show references from weak containers as weak in heap snapshots.

BUG=356590
LOG=Y
[email protected], [email protected]

Review URL: https://codereview.chromium.org/213673006
http://code.google.com/p/v8/source/detail?r=20429

Modified:
 /branches/bleeding_edge/src/heap-snapshot-generator.cc
 /branches/bleeding_edge/src/heap-snapshot-generator.h
 /branches/bleeding_edge/test/cctest/test-heap-profiler.cc

=======================================
--- /branches/bleeding_edge/src/heap-snapshot-generator.cc Thu Mar 27 14:19:51 2014 UTC +++ /branches/bleeding_edge/src/heap-snapshot-generator.cc Wed Apr 2 11:19:53 2014 UTC
@@ -1101,10 +1101,8 @@
 };


-void V8HeapExplorer::ExtractReferences(HeapObject* obj) {
-  HeapEntry* heap_entry = GetEntry(obj);
-  if (heap_entry == NULL) return;  // No interest in this object.
-  int entry = heap_entry->index();
+bool V8HeapExplorer::ExtractReferencesPass1(int entry, HeapObject* obj) {
+ if (obj->IsFixedArray()) return false; // FixedArrays are processed on pass 2

   if (obj->IsJSGlobalProxy()) {
     ExtractJSGlobalProxyReferences(entry, JSGlobalProxy::cast(obj));
@@ -1114,8 +1112,6 @@
     ExtractJSObjectReferences(entry, JSObject::cast(obj));
   } else if (obj->IsString()) {
     ExtractStringReferences(entry, String::cast(obj));
-  } else if (obj->IsContext()) {
-    ExtractContextReferences(entry, Context::cast(obj));
   } else if (obj->IsMap()) {
     ExtractMapReferences(entry, Map::cast(obj));
   } else if (obj->IsSharedFunctionInfo()) {
@@ -1137,12 +1133,19 @@
   } else if (obj->IsAllocationSite()) {
     ExtractAllocationSiteReferences(entry, AllocationSite::cast(obj));
   }
- SetInternalReference(obj, entry, "map", obj->map(), HeapObject::kMapOffset);
+  return true;
+}

-  // Extract unvisited fields as hidden references and restore tags
-  // of visited fields.
-  IndexedReferencesExtractor refs_extractor(this, obj, entry);
-  obj->Iterate(&refs_extractor);
+
+bool V8HeapExplorer::ExtractReferencesPass2(int entry, HeapObject* obj) {
+  if (!obj->IsFixedArray()) return false;
+
+  if (obj->IsContext()) {
+    ExtractContextReferences(entry, Context::cast(obj));
+  } else {
+    ExtractFixedArrayReferences(entry, FixedArray::cast(obj));
+  }
+  return true;
 }


@@ -1320,6 +1323,7 @@
     SetInternalReference(transitions, transitions_entry,
                          "back_pointer", back_pointer);
     TagObject(transitions, "(transition array)");
+    MarkAsWeakContainer(transitions);
     SetInternalReference(map, entry,
                          "transitions", transitions,
                          Map::kTransitionsOrBackPointerOffset);
@@ -1336,6 +1340,7 @@
                        "descriptors", descriptors,
                        Map::kDescriptorsOffset);

+  MarkAsWeakContainer(map->code_cache());
   SetInternalReference(map, entry,
                        "code_cache", map->code_cache(),
                        Map::kCodeCacheOffset);
@@ -1345,6 +1350,7 @@
                        "constructor", map->constructor(),
                        Map::kConstructorOffset);
   TagObject(map->dependent_code(), "(dependent code)");
+  MarkAsWeakContainer(map->dependent_code());
   SetInternalReference(map, entry,
                        "dependent_code", map->dependent_code(),
                        Map::kDependentCodeOffset);
@@ -1506,6 +1512,7 @@
   ExtractCellReferences(entry, cell);
   SetInternalReference(cell, entry, "type", cell->type(),
                        PropertyCell::kTypeOffset);
+  MarkAsWeakContainer(cell->dependent_code());
SetInternalReference(cell, entry, "dependent_code", cell->dependent_code(),
                        PropertyCell::kDependentCodeOffset);
 }
@@ -1517,6 +1524,7 @@
                        AllocationSite::kTransitionInfoOffset);
   SetInternalReference(site, entry, "nested_site", site->nested_site(),
                        AllocationSite::kNestedSiteOffset);
+  MarkAsWeakContainer(site->dependent_code());
SetInternalReference(site, entry, "dependent_code", site->dependent_code(),
                        AllocationSite::kDependentCodeOffset);
   // Do not visit weak_next as it is not visited by the StaticVisitor,
@@ -1560,6 +1568,20 @@
   filler_->SetNamedReference(HeapGraphEdge::kInternal,
                              entry, "backing_store", data_entry);
 }
+
+
+void V8HeapExplorer::ExtractFixedArrayReferences(int entry, FixedArray* array) {
+  bool is_weak = weak_containers_.Contains(array);
+  for (int i = 0, l = array->length(); i < l; ++i) {
+    if (is_weak) {
+      SetWeakReference(array, entry,
+                       i, array->get(i), array->OffsetOfElementAt(i));
+    } else {
+      SetInternalReference(array, entry,
+                           i, array->get(i), array->OffsetOfElementAt(i));
+    }
+  }
+}


void V8HeapExplorer::ExtractClosureReferences(JSObject* js_obj, int entry) {
@@ -1833,6 +1855,25 @@
   heap_->IterateRoots(&extractor, VISIT_ALL);
   extractor.FillReferences(this);

+  // We have to do two passes as sometimes FixedArrays are used
+  // to weakly hold their items, and it's impossible to distinguish
+  // between these cases without processing the array owner first.
+  bool interrupted =
+ IterateAndExtractSinglePass<&V8HeapExplorer::ExtractReferencesPass1>() || + IterateAndExtractSinglePass<&V8HeapExplorer::ExtractReferencesPass2>();
+
+  if (interrupted) {
+    filler_ = NULL;
+    return false;
+  }
+
+  filler_ = NULL;
+  return progress_->ProgressReport(true);
+}
+
+
+template<V8HeapExplorer::ExtractReferencesMethod extractor>
+bool V8HeapExplorer::IterateAndExtractSinglePass() {
   // Now iterate the whole heap.
   bool interrupted = false;
   HeapIterator iterator(heap_, HeapIterator::kFilterUnreachable);
@@ -1840,18 +1881,22 @@
   for (HeapObject* obj = iterator.next();
        obj != NULL;
        obj = iterator.next(), progress_->ProgressStep()) {
-    if (!interrupted) {
-      ExtractReferences(obj);
-      if (!progress_->ProgressReport(false)) interrupted = true;
+    if (interrupted) continue;
+
+    HeapEntry* heap_entry = GetEntry(obj);
+    int entry = heap_entry->index();
+    if ((this->*extractor)(entry, obj)) {
+      SetInternalReference(obj, entry,
+                           "map", obj->map(), HeapObject::kMapOffset);
+      // Extract unvisited fields as hidden references and restore tags
+      // of visited fields.
+      IndexedReferencesExtractor refs_extractor(this, obj, entry);
+      obj->Iterate(&refs_extractor);
     }
-  }
-  if (interrupted) {
-    filler_ = NULL;
-    return false;
-  }

-  filler_ = NULL;
-  return progress_->ProgressReport(true);
+    if (!progress_->ProgressReport(false)) interrupted = true;
+  }
+  return interrupted;
 }


@@ -1985,6 +2030,24 @@
   }
   IndexedReferencesExtractor::MarkVisitedField(parent_obj, field_offset);
 }
+
+
+void V8HeapExplorer::SetWeakReference(HeapObject* parent_obj,
+                                      int parent_entry,
+                                      int index,
+                                      Object* child_obj,
+                                      int field_offset) {
+  ASSERT(parent_entry == GetEntry(parent_obj)->index());
+  HeapEntry* child_entry = GetEntry(child_obj);
+  if (child_entry == NULL) return;
+  if (IsEssentialObject(child_obj)) {
+    filler_->SetNamedReference(HeapGraphEdge::kWeak,
+                               parent_entry,
+                               names_->GetFormatted("%d", index),
+                               child_entry);
+  }
+  IndexedReferencesExtractor::MarkVisitedField(parent_obj, field_offset);
+}


 void V8HeapExplorer::SetPropertyReference(HeapObject* parent_obj,
@@ -2112,6 +2175,13 @@
     }
   }
 }
+
+
+void V8HeapExplorer::MarkAsWeakContainer(Object* object) {
+  if (IsEssentialObject(object) && object->IsFixedArray()) {
+    weak_containers_.Insert(object);
+  }
+}


 class GlobalObjectsEnumerator : public ObjectVisitor {
@@ -2504,7 +2574,7 @@
   debug_heap->Verify();
 #endif

-  SetProgressTotal(1);  // 1 pass.
+  SetProgressTotal(2);  // 2 passes.

 #ifdef VERIFY_HEAP
   debug_heap->Verify();
=======================================
--- /branches/bleeding_edge/src/heap-snapshot-generator.h Thu Mar 13 07:48:42 2014 UTC +++ /branches/bleeding_edge/src/heap-snapshot-generator.h Wed Apr 2 11:19:53 2014 UTC
@@ -376,6 +376,9 @@
   static HeapObject* const kInternalRootObject;

  private:
+  typedef bool (V8HeapExplorer::*ExtractReferencesMethod)(int entry,
+ HeapObject* object);
+
   HeapEntry* AddEntry(HeapObject* object);
   HeapEntry* AddEntry(HeapObject* object,
                       HeapEntry::Type type,
@@ -383,7 +386,11 @@

   const char* GetSystemEntryName(HeapObject* object);

-  void ExtractReferences(HeapObject* obj);
+  template<V8HeapExplorer::ExtractReferencesMethod extractor>
+  bool IterateAndExtractSinglePass();
+
+  bool ExtractReferencesPass1(int entry, HeapObject* obj);
+  bool ExtractReferencesPass2(int entry, HeapObject* obj);
   void ExtractJSGlobalProxyReferences(int entry, JSGlobalProxy* proxy);
   void ExtractJSObjectReferences(int entry, JSObject* js_obj);
   void ExtractStringReferences(int entry, String* obj);
@@ -400,12 +407,14 @@
   void ExtractPropertyCellReferences(int entry, PropertyCell* cell);
   void ExtractAllocationSiteReferences(int entry, AllocationSite* site);
   void ExtractJSArrayBufferReferences(int entry, JSArrayBuffer* buffer);
+  void ExtractFixedArrayReferences(int entry, FixedArray* array);
   void ExtractClosureReferences(JSObject* js_obj, int entry);
   void ExtractPropertyReferences(JSObject* js_obj, int entry);
   bool ExtractAccessorPairProperty(JSObject* js_obj, int entry,
                                    Object* key, Object* callback_obj);
   void ExtractElementReferences(JSObject* js_obj, int entry);
   void ExtractInternalReferences(JSObject* js_obj, int entry);
+
   bool IsEssentialObject(Object* object);
   void SetContextReference(HeapObject* parent_obj,
                            int parent,
@@ -437,6 +446,11 @@
   void SetWeakReference(HeapObject* parent_obj,
                         int parent,
                         const char* reference_name,
+                        Object* child_obj,
+                        int field_offset);
+  void SetWeakReference(HeapObject* parent_obj,
+                        int parent,
+                        int index,
                         Object* child_obj,
                         int field_offset);
   void SetPropertyReference(HeapObject* parent_obj,
@@ -452,6 +466,7 @@
       VisitorSynchronization::SyncTag tag, bool is_weak, Object* child);
   const char* GetStrongGcSubrootName(Object* object);
   void TagObject(Object* obj, const char* tag);
+  void MarkAsWeakContainer(Object* object);

   HeapEntry* GetEntry(Object* obj);

@@ -467,6 +482,7 @@
   HeapObjectsSet objects_tags_;
   HeapObjectsSet strong_gc_subroot_names_;
   HeapObjectsSet user_roots_;
+  HeapObjectsSet weak_containers_;
   v8::HeapProfiler::ObjectNameResolver* global_object_name_resolver_;

   static HeapObject* const kGcRootsObject;
=======================================
--- /branches/bleeding_edge/test/cctest/test-heap-profiler.cc Fri Mar 7 17:20:03 2014 UTC +++ /branches/bleeding_edge/test/cctest/test-heap-profiler.cc Wed Apr 2 11:19:53 2014 UTC
@@ -2506,6 +2506,41 @@
       GetProperty(box_node, v8::HeapGraphEdge::kInternal, "value");
   CHECK_NE(NULL, box_value);
 }
+
+
+TEST(WeakContainers) {
+  i::FLAG_allow_natives_syntax = true;
+  LocalContext env;
+  v8::HandleScope scope(env->GetIsolate());
+  if (!CcTest::i_isolate()->use_crankshaft()) return;
+  v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
+  CompileRun(
+      "function foo(a) { return a.x; }\n"
+      "obj = {x : 123};\n"
+      "foo(obj);\n"
+      "foo(obj);\n"
+      "%OptimizeFunctionOnNextCall(foo);\n"
+      "foo(obj);\n");
+  const v8::HeapSnapshot* snapshot =
+      heap_profiler->TakeHeapSnapshot(v8_str("snapshot"));
+  CHECK(ValidateSnapshot(snapshot));
+  const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
+  const v8::HeapGraphNode* obj =
+      GetProperty(global, v8::HeapGraphEdge::kProperty, "obj");
+  CHECK_NE(NULL, obj);
+  const v8::HeapGraphNode* map =
+      GetProperty(obj, v8::HeapGraphEdge::kInternal, "map");
+  CHECK_NE(NULL, map);
+  const v8::HeapGraphNode* dependent_code =
+      GetProperty(map, v8::HeapGraphEdge::kInternal, "dependent_code");
+  if (!dependent_code) return;
+  int count = dependent_code->GetChildrenCount();
+  CHECK_NE(0, count);
+  for (int i = 0; i < count; ++i) {
+    const v8::HeapGraphEdge* prop = dependent_code->GetChild(i);
+    CHECK_EQ(v8::HeapGraphEdge::kWeak, prop->GetType());
+  }
+}


 static inline i::Address ToAddress(int n) {

--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
--- You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to