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 <haraken@chromium.org>.

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@12874 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent c54fc70f
......@@ -414,6 +414,16 @@ template <class T> class Persistent : public Handle<T> {
*/
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 @@ class V8EXPORT V8 {
* 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 @@ class V8EXPORT V8 {
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);
......@@ -4321,6 +4335,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) {
V8::SetWrapperClassId(reinterpret_cast<internal::Object**>(**this), class_id);
......
......@@ -651,6 +651,13 @@ void V8::MarkIndependent(i::Object** 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) {
i::Isolate* isolate = i::Isolate::Current();
LOG_API(isolate, "IsGlobalIndependent");
......
......@@ -69,6 +69,7 @@ class GlobalHandles::Node {
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 @@ class GlobalHandles::Node {
object_ = object;
class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId;
independent_ = false;
partially_dependent_ = false;
state_ = NORMAL;
parameter_or_next_free_.parameter = NULL;
callback_ = NULL;
......@@ -154,6 +156,15 @@ class GlobalHandles::Node {
}
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; }
bool is_in_new_space_list() const { return in_new_space_list_; }
......@@ -260,6 +271,7 @@ class GlobalHandles::Node {
State state_ : 4;
bool independent_ : 1;
bool partially_dependent_ : 1;
bool in_new_space_list_ : 1;
// Handle specific callback.
......@@ -448,6 +460,11 @@ void GlobalHandles::MarkIndependent(Object** location) {
}
void GlobalHandles::MarkPartiallyDependent(Object** location) {
Node::FromLocation(location)->MarkPartiallyDependent(this);
}
bool GlobalHandles::IsIndependent(Object** location) {
return Node::FromLocation(location)->is_independent();
}
......@@ -501,8 +518,9 @@ void GlobalHandles::IterateNewSpaceStrongAndDependentRoots(ObjectVisitor* v) {
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 @@ void GlobalHandles::IdentifyNewSpaceWeakIndependentHandles(
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 @@ void GlobalHandles::IterateNewSpaceWeakIndependentRoots(ObjectVisitor* v) {
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 @@ bool GlobalHandles::PostGarbageCollectionProcessing(
// 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 @@ bool GlobalHandles::PostGarbageCollectionProcessing(
}
} 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.
......
......@@ -155,6 +155,9 @@ class GlobalHandles {
// 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 @@ class GlobalHandles {
// 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);
......
......@@ -1333,6 +1333,12 @@ void Heap::Scavenge() {
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(
......@@ -1373,6 +1379,51 @@ void Heap::Scavenge() {
}
// 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,
Object** p) {
MapWord first_word = HeapObject::cast(*p)->map_word();
......
......@@ -1907,6 +1907,7 @@ class Heap {
bool PerformGarbageCollection(GarbageCollector collector,
GCTracer* tracer);
bool IterateObjectGroups(ObjectVisitor* scavenge_visitor);
inline void UpdateOldSpaceLimits();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment