Revision: 12874
Author:   [email protected]
Date:     Tue Nov  6 09:32:15 2012
Log:      Allow collection of DOM objects in minor GC cycles.

A design document: https://docs.google.com/a/google.com/document/d/16DeHrzkm3cO9XCPT1aK3Y5qgUxXB3RFmueqQWYmN2rI/edit

Performance & memory results: https://docs.google.com/a/google.com/document/d/1h0-EsHu7T0sSMuZm5eE0r1e8sCAzY3weLvsDUpOSngE/edit

The WebKit side patch: https://bugs.webkit.org/show_bug.cgi?id=98725

At present no one is using the V8 APIs this patch is going to add. After this patch is landed, the WebKit side patch will use it.

BUG=

Review URL: https://codereview.chromium.org/11085015
Patch from Kentaro Hara <[email protected]>.
http://code.google.com/p/v8/source/detail?r=12874

Modified:
 /branches/bleeding_edge/include/v8.h
 /branches/bleeding_edge/src/api.cc
 /branches/bleeding_edge/src/global-handles.cc
 /branches/bleeding_edge/src/global-handles.h
 /branches/bleeding_edge/src/heap.cc
 /branches/bleeding_edge/src/heap.h

=======================================
--- /branches/bleeding_edge/include/v8.h        Tue Nov  6 08:47:15 2012
+++ /branches/bleeding_edge/include/v8.h        Tue Nov  6 09:32:15 2012
@@ -414,6 +414,16 @@
    */
   inline void MarkIndependent();

+  /**
+   * Marks the reference to this object partially dependent. Partially
+   * dependent handles only depend on other partially dependent handles and
+ * these dependencies are provided through object groups. It provides a way
+   * to build smaller object groups for young objects that represent only a
+ * subset of all external dependencies. This mark is automatically cleared
+   * after each garbage collection.
+   */
+  inline void MarkPartiallyDependent();
+
   /** Returns true if this handle was previously marked as independent. */
   inline bool IsIndependent() const;
   inline bool IsIndependent(Isolate* isolate) const;
@@ -3279,7 +3289,10 @@
    * After each garbage collection, object groups are removed. It is
    * intended to be used in the before-garbage-collection callback
    * function, for instance to simulate DOM tree connections among JS
-   * wrapper objects.
+   * wrapper objects. Object groups for all dependent handles need to
+   * be provided for kGCTypeMarkSweepCompact collections, for all other
+   * garbage collection types it is sufficient to provide object groups
+   * for partially dependent handles only.
    * See v8-profiler.h for RetainedObjectInfo interface description.
    */
   static void AddObjectGroup(Persistent<Value>* objects,
@@ -3520,6 +3533,7 @@
                        WeakReferenceCallback);
   static void ClearWeak(internal::Object** global_handle);
   static void MarkIndependent(internal::Object** global_handle);
+  static void MarkPartiallyDependent(internal::Object** global_handle);
   static bool IsGlobalIndependent(internal::Object** global_handle);
   static bool IsGlobalIndependent(internal::Isolate* isolate,
                                   internal::Object** global_handle);
@@ -4320,6 +4334,11 @@
 void Persistent<T>::MarkIndependent() {
   V8::MarkIndependent(reinterpret_cast<internal::Object**>(**this));
 }
+
+template <class T>
+void Persistent<T>::MarkPartiallyDependent() {
+  V8::MarkPartiallyDependent(reinterpret_cast<internal::Object**>(**this));
+}

 template <class T>
 void Persistent<T>::SetWrapperClassId(uint16_t class_id) {
=======================================
--- /branches/bleeding_edge/src/api.cc  Mon Nov  5 05:20:45 2012
+++ /branches/bleeding_edge/src/api.cc  Tue Nov  6 09:32:15 2012
@@ -649,6 +649,13 @@
   LOG_API(isolate, "MarkIndependent");
   isolate->global_handles()->MarkIndependent(object);
 }
+
+
+void V8::MarkPartiallyDependent(i::Object** object) {
+  i::Isolate* isolate = i::Isolate::Current();
+  LOG_API(isolate, "MarkPartiallyDependent");
+  isolate->global_handles()->MarkPartiallyDependent(object);
+}


 bool V8::IsGlobalIndependent(i::Object** obj) {
=======================================
--- /branches/bleeding_edge/src/global-handles.cc       Wed Oct 17 23:52:37 2012
+++ /branches/bleeding_edge/src/global-handles.cc       Tue Nov  6 09:32:15 2012
@@ -69,6 +69,7 @@
     class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId;
     index_ = 0;
     independent_ = false;
+    partially_dependent_ = false;
     in_new_space_list_ = false;
     parameter_or_next_free_.next_free = NULL;
     callback_ = NULL;
@@ -89,6 +90,7 @@
     object_ = object;
     class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId;
     independent_ = false;
+    partially_dependent_ = false;
     state_  = NORMAL;
     parameter_or_next_free_.parameter = NULL;
     callback_ = NULL;
@@ -153,6 +155,15 @@
     independent_ = true;
   }
   bool is_independent() const { return independent_; }
+
+  void MarkPartiallyDependent(GlobalHandles* global_handles) {
+    ASSERT(state_ != FREE);
+    if (global_handles->isolate()->heap()->InNewSpace(object_)) {
+      partially_dependent_ = true;
+    }
+  }
+  bool is_partially_dependent() const { return partially_dependent_; }
+  void clear_partially_dependent() { partially_dependent_ = false; }

   // In-new-space-list flag accessors.
   void set_in_new_space_list(bool v) { in_new_space_list_ = v; }
@@ -260,6 +271,7 @@
   State state_ : 4;

   bool independent_ : 1;
+  bool partially_dependent_ : 1;
   bool in_new_space_list_ : 1;

   // Handle specific callback.
@@ -446,6 +458,11 @@
 void GlobalHandles::MarkIndependent(Object** location) {
   Node::FromLocation(location)->MarkIndependent();
 }
+
+
+void GlobalHandles::MarkPartiallyDependent(Object** location) {
+  Node::FromLocation(location)->MarkPartiallyDependent(this);
+}


 bool GlobalHandles::IsIndependent(Object** location) {
@@ -501,8 +518,9 @@
   for (int i = 0; i < new_space_nodes_.length(); ++i) {
     Node* node = new_space_nodes_[i];
     if (node->IsStrongRetainer() ||
-        (node->IsWeakRetainer() && !node->is_independent())) {
-      v->VisitPointer(node->location());
+        (node->IsWeakRetainer() && !node->is_independent() &&
+         !node->is_partially_dependent())) {
+        v->VisitPointer(node->location());
     }
   }
 }
@@ -513,8 +531,8 @@
   for (int i = 0; i < new_space_nodes_.length(); ++i) {
     Node* node = new_space_nodes_[i];
     ASSERT(node->is_in_new_space_list());
-    if (node->is_independent() && node->IsWeak() &&
-        f(isolate_->heap(), node->location())) {
+    if ((node->is_independent() || node->is_partially_dependent()) &&
+        node->IsWeak() && f(isolate_->heap(), node->location())) {
       node->MarkPending();
     }
   }
@@ -525,7 +543,8 @@
   for (int i = 0; i < new_space_nodes_.length(); ++i) {
     Node* node = new_space_nodes_[i];
     ASSERT(node->is_in_new_space_list());
-    if (node->is_independent() && node->IsWeakRetainer()) {
+    if ((node->is_independent() || node->is_partially_dependent()) &&
+        node->IsWeakRetainer()) {
       v->VisitPointer(node->location());
     }
   }
@@ -547,7 +566,10 @@
       // Skip dependent handles. Their weak callbacks might expect to be
       // called between two global garbage collection callbacks which
       // are not called for minor collections.
-      if (!node->is_independent()) continue;
+      if (!node->is_independent() && !node->is_partially_dependent()) {
+        continue;
+      }
+      node->clear_partially_dependent();
       if (node->PostGarbageCollectionProcessing(isolate_, this)) {
if (initial_post_gc_processing_count != post_gc_processing_count_) {
           // Weak callback triggered another GC and another round of
@@ -563,6 +585,7 @@
     }
   } else {
     for (NodeIterator it(this); !it.done(); it.Advance()) {
+      it.node()->clear_partially_dependent();
       if (it.node()->PostGarbageCollectionProcessing(isolate_, this)) {
if (initial_post_gc_processing_count != post_gc_processing_count_) {
           // See the comment above.
=======================================
--- /branches/bleeding_edge/src/global-handles.h        Wed Oct 17 23:52:37 2012
+++ /branches/bleeding_edge/src/global-handles.h        Tue Nov  6 09:32:15 2012
@@ -155,6 +155,9 @@
   // Clear the weakness of a global handle.
   void MarkIndependent(Object** location);

+  // Mark the reference to this object externaly unreachable.
+  void MarkPartiallyDependent(Object** location);
+
   static bool IsIndependent(Object** location);

   // Tells whether global handle is near death.
@@ -195,16 +198,17 @@
   // Iterates over strong and dependent handles. See the node above.
   void IterateNewSpaceStrongAndDependentRoots(ObjectVisitor* v);

-  // Finds weak independent handles satisfying the callback predicate
-  // and marks them as pending. See the note above.
+  // Finds weak independent or partially independent handles satisfying
+  // the callback predicate and marks them as pending. See the note above.
   void IdentifyNewSpaceWeakIndependentHandles(WeakSlotCallbackWithHeap f);

-  // Iterates over weak independent handles. See the note above.
+  // Iterates over weak independent or partially independent handles.
+  // See the note above.
   void IterateNewSpaceWeakIndependentRoots(ObjectVisitor* v);

   // Add an object group.
   // Should be only used in GC callback function before a collection.
-  // All groups are destroyed after a mark-compact collection.
+  // All groups are destroyed after a garbage collection.
   void AddObjectGroup(Object*** handles,
                       size_t length,
                       v8::RetainedObjectInfo* info);
=======================================
--- /branches/bleeding_edge/src/heap.cc Tue Nov  6 08:47:15 2012
+++ /branches/bleeding_edge/src/heap.cc Tue Nov  6 09:32:15 2012
@@ -1333,6 +1333,12 @@
   scavenge_visitor.VisitPointer(BitCast<Object**>(&native_contexts_list_));

   new_space_front = DoScavenge(&scavenge_visitor, new_space_front);
+
+  while (IterateObjectGroups(&scavenge_visitor)) {
+    new_space_front = DoScavenge(&scavenge_visitor, new_space_front);
+  }
+  isolate()->global_handles()->RemoveObjectGroups();
+
   isolate_->global_handles()->IdentifyNewSpaceWeakIndependentHandles(
       &IsUnscavengedHeapObject);
   isolate_->global_handles()->IterateNewSpaceWeakIndependentRoots(
@@ -1371,6 +1377,51 @@

   scavenges_since_last_idle_round_++;
 }
+
+
+// TODO(mstarzinger): Unify this method with
+// MarkCompactCollector::MarkObjectGroups().
+bool Heap::IterateObjectGroups(ObjectVisitor* scavenge_visitor) {
+  List<ObjectGroup*>* object_groups =
+    isolate()->global_handles()->object_groups();
+
+  int last = 0;
+  bool changed = false;
+  for (int i = 0; i < object_groups->length(); i++) {
+    ObjectGroup* entry = object_groups->at(i);
+    ASSERT(entry != NULL);
+
+    Object*** objects = entry->objects_;
+    bool group_marked = false;
+    for (size_t j = 0; j < entry->length_; j++) {
+      Object* object = *objects[j];
+      if (object->IsHeapObject()) {
+        if (!IsUnscavengedHeapObject(this, &object)) {
+          group_marked = true;
+          break;
+        }
+      }
+    }
+
+    if (!group_marked) {
+      (*object_groups)[last++] = entry;
+      continue;
+    }
+
+    for (size_t j = 0; j < entry->length_; ++j) {
+      Object* object = *objects[j];
+      if (object->IsHeapObject()) {
+        scavenge_visitor->VisitPointer(&object);
+        changed = true;
+      }
+    }
+
+    entry->Dispose();
+    object_groups->at(i) = NULL;
+  }
+  object_groups->Rewind(last);
+  return changed;
+}


 String* Heap::UpdateNewSpaceReferenceInExternalStringTableEntry(Heap* heap,
=======================================
--- /branches/bleeding_edge/src/heap.h  Tue Nov  6 08:47:15 2012
+++ /branches/bleeding_edge/src/heap.h  Tue Nov  6 09:32:15 2012
@@ -1907,6 +1907,7 @@
   bool PerformGarbageCollection(GarbageCollector collector,
                                 GCTracer* tracer);

+  bool IterateObjectGroups(ObjectVisitor* scavenge_visitor);

   inline void UpdateOldSpaceLimits();

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

Reply via email to