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