Commit 62540192 authored by mythria's avatar mythria Committed by Commit bot

Changed scavenge GC to collect unmodified references

Added a scavenge GC pass that collects unmodified references instead of
processing object groups.  This mode can be controlled by setting
FLAG_scavenge_remove_unmodified_objects. By default this is turned off.
Also, modified a test case to suit the handle the new GC pass.

BUG=v8:4421
LOG=N

Review URL: https://codereview.chromium.org/1358703003

Cr-Commit-Position: refs/heads/master@{#31102}
parent 17ab6c28
......@@ -677,6 +677,8 @@ DEFINE_BOOL(verify_heap, false, "verify heap pointers before and after GC")
#endif
DEFINE_BOOL(move_object_start, false, "enable moving of object starts")
DEFINE_BOOL(memory_reducer, true, "use memory reducer")
DEFINE_BOOL(scavenge_reclaim_unmodified_objects, true,
"remove unmodified and unreferenced objects")
// counters.cc
DEFINE_INT(histogram_interval, 600000,
......
......@@ -64,7 +64,11 @@ class GlobalHandles::Node {
class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId;
index_ = 0;
set_independent(false);
set_partially_dependent(false);
if (FLAG_scavenge_reclaim_unmodified_objects) {
set_unmodified(false);
} else {
set_partially_dependent(false);
}
set_in_new_space_list(false);
parameter_or_next_free_.next_free = NULL;
weak_callback_ = NULL;
......@@ -77,6 +81,9 @@ class GlobalHandles::Node {
set_state(FREE);
set_weakness_type(NORMAL_WEAK);
set_in_new_space_list(false);
if (FLAG_scavenge_reclaim_unmodified_objects) {
set_unmodified(false);
}
parameter_or_next_free_.next_free = *first_free;
*first_free = this;
}
......@@ -86,7 +93,11 @@ class GlobalHandles::Node {
object_ = object;
class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId;
set_independent(false);
set_partially_dependent(false);
if (FLAG_scavenge_reclaim_unmodified_objects) {
set_unmodified(false);
} else {
set_partially_dependent(false);
}
set_state(NORMAL);
parameter_or_next_free_.parameter = NULL;
weak_callback_ = NULL;
......@@ -106,7 +117,11 @@ class GlobalHandles::Node {
object_ = reinterpret_cast<Object*>(kGlobalHandleZapValue);
class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId;
set_independent(false);
set_partially_dependent(false);
if (FLAG_scavenge_reclaim_unmodified_objects) {
set_unmodified(false);
} else {
set_partially_dependent(false);
}
weak_callback_ = NULL;
DecreaseBlockUses();
}
......@@ -140,12 +155,23 @@ class GlobalHandles::Node {
}
bool is_partially_dependent() {
CHECK(!FLAG_scavenge_reclaim_unmodified_objects);
return IsPartiallyDependent::decode(flags_);
}
void set_partially_dependent(bool v) {
CHECK(!FLAG_scavenge_reclaim_unmodified_objects);
flags_ = IsPartiallyDependent::update(flags_, v);
}
bool is_unmodified() {
CHECK(FLAG_scavenge_reclaim_unmodified_objects);
return IsUnmodified::decode(flags_);
}
void set_unmodified(bool v) {
CHECK(FLAG_scavenge_reclaim_unmodified_objects);
flags_ = IsUnmodified::update(flags_, v);
}
bool is_in_new_space_list() {
return IsInNewSpaceList::decode(flags_);
}
......@@ -349,6 +375,8 @@ class GlobalHandles::Node {
// in_new_space_list) and a State.
class NodeState : public BitField<State, 0, 3> {};
class IsIndependent : public BitField<bool, 3, 1> {};
// The following two fields are mutually exclusive
class IsUnmodified : public BitField<bool, 4, 1> {};
class IsPartiallyDependent : public BitField<bool, 4, 1> {};
class IsInNewSpaceList : public BitField<bool, 5, 1> {};
class NodeWeaknessType : public BitField<WeaknessType, 6, 2> {};
......@@ -646,10 +674,18 @@ void GlobalHandles::IdentifyWeakHandles(WeakSlotCallback f) {
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() &&
!node->is_partially_dependent())) {
if (FLAG_scavenge_reclaim_unmodified_objects) {
if (node->IsStrongRetainer() ||
(node->IsWeakRetainer() && !node->is_independent() &&
!node->is_unmodified())) {
v->VisitPointer(node->location());
}
} else {
if (node->IsStrongRetainer() ||
(node->IsWeakRetainer() && !node->is_independent() &&
!node->is_partially_dependent())) {
v->VisitPointer(node->location());
}
}
}
}
......@@ -687,6 +723,49 @@ void GlobalHandles::IterateNewSpaceWeakIndependentRoots(ObjectVisitor* v) {
}
void GlobalHandles::IdentifyWeakUnmodifiedObjects(
WeakSlotCallback is_unmodified) {
for (int i = 0; i < new_space_nodes_.length(); ++i) {
Node* node = new_space_nodes_[i];
if (node->IsWeak() && is_unmodified(node->location())) {
node->set_unmodified(true);
}
}
}
void GlobalHandles::MarkNewSpaceWeakUnmodifiedObjectsPending(
WeakSlotCallbackWithHeap is_unscavenged) {
for (int i = 0; i < new_space_nodes_.length(); ++i) {
Node* node = new_space_nodes_[i];
DCHECK(node->is_in_new_space_list());
if ((node->is_independent() || node->is_unmodified()) && node->IsWeak() &&
is_unscavenged(isolate_->heap(), node->location())) {
node->MarkPending();
}
}
}
void GlobalHandles::IterateNewSpaceWeakUnmodifiedRoots(ObjectVisitor* v) {
for (int i = 0; i < new_space_nodes_.length(); ++i) {
Node* node = new_space_nodes_[i];
DCHECK(node->is_in_new_space_list());
if ((node->is_independent() || node->is_unmodified()) &&
node->IsWeakRetainer()) {
// Pending weak phantom handles die immediately. Everything else survives.
if (node->state() == Node::PENDING &&
node->weakness_type() != NORMAL_WEAK) {
node->CollectPhantomCallbackData(isolate(),
&pending_phantom_callbacks_);
} else {
v->VisitPointer(node->location());
}
}
}
}
bool GlobalHandles::IterateObjectGroups(ObjectVisitor* v,
WeakSlotCallbackWithHeap can_skip) {
ComputeObjectGroupsAndImplicitReferences();
......@@ -757,13 +836,22 @@ int GlobalHandles::PostScavengeProcessing(
// the freed_nodes.
continue;
}
// Skip dependent handles. Their weak callbacks might expect to be
// Skip dependent or unmodified 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() && !node->is_partially_dependent()) {
continue;
if (FLAG_scavenge_reclaim_unmodified_objects) {
if (!node->is_independent() && !node->is_unmodified()) {
continue;
}
node->set_unmodified(false);
} else {
if (!node->is_independent() && !node->is_partially_dependent()) {
continue;
}
node->clear_partially_dependent();
}
node->clear_partially_dependent();
if (node->PostGarbageCollectionProcessing(isolate_)) {
if (initial_post_gc_processing_count != post_gc_processing_count_) {
// Weak callback triggered another GC and another round of
......@@ -790,7 +878,11 @@ int GlobalHandles::PostMarkSweepProcessing(
// the freed_nodes.
continue;
}
it.node()->clear_partially_dependent();
if (FLAG_scavenge_reclaim_unmodified_objects) {
it.node()->set_unmodified(false);
} else {
it.node()->clear_partially_dependent();
}
if (it.node()->PostGarbageCollectionProcessing(isolate_)) {
if (initial_post_gc_processing_count != post_gc_processing_count_) {
// See the comment above.
......
......@@ -204,7 +204,7 @@ class GlobalHandles {
// them as pending.
void IdentifyWeakHandles(WeakSlotCallback f);
// NOTE: Three ...NewSpace... functions below are used during
// NOTE: Five ...NewSpace... functions below are used during
// scavenge collections and iterate over sets of handles that are
// guaranteed to contain all handles holding new space objects (but
// may also include old space objects).
......@@ -220,6 +220,19 @@ class GlobalHandles {
// See the note above.
void IterateNewSpaceWeakIndependentRoots(ObjectVisitor* v);
// Finds weak independent or unmodified handles satisfying
// the callback predicate and marks them as pending. See the note above.
void MarkNewSpaceWeakUnmodifiedObjectsPending(
WeakSlotCallbackWithHeap is_unscavenged);
// Iterates over weak independent or unmodified handles.
// See the note above.
void IterateNewSpaceWeakUnmodifiedRoots(ObjectVisitor* v);
// Identify unmodified objects that are in weak state and marks them
// unmodified
void IdentifyWeakUnmodifiedObjects(WeakSlotCallback is_unmodified);
// Iterate over objects in object groups that have at least one object
// which requires visiting. The callback has to return true if objects
// can be skipped and false otherwise.
......
......@@ -1239,7 +1239,10 @@ bool Heap::PerformGarbageCollection(
GCTracer::Scope scope(tracer(), GCTracer::Scope::EXTERNAL);
VMState<EXTERNAL> state(isolate_);
HandleScope handle_scope(isolate_);
CallGCPrologueCallbacks(gc_type, kNoGCCallbackFlags);
if (!(FLAG_scavenge_reclaim_unmodified_objects &&
(gc_type == kGCTypeScavenge))) {
CallGCPrologueCallbacks(gc_type, kNoGCCallbackFlags);
}
}
}
......@@ -1324,7 +1327,10 @@ bool Heap::PerformGarbageCollection(
GCTracer::Scope scope(tracer(), GCTracer::Scope::EXTERNAL);
VMState<EXTERNAL> state(isolate_);
HandleScope handle_scope(isolate_);
CallGCEpilogueCallbacks(gc_type, gc_callback_flags);
if (!(FLAG_scavenge_reclaim_unmodified_objects &&
(gc_type == kGCTypeScavenge))) {
CallGCEpilogueCallbacks(gc_type, gc_callback_flags);
}
}
}
......@@ -1484,6 +1490,22 @@ static bool IsUnscavengedHeapObject(Heap* heap, Object** p) {
}
static bool IsUnmodifiedHeapObject(Object** p) {
Object* object = *p;
DCHECK(object->IsHeapObject());
HeapObject* heap_object = HeapObject::cast(object);
if (!object->IsJSObject()) return false;
Object* obj_constructor = (JSObject::cast(object))->map()->GetConstructor();
if (!obj_constructor->IsJSFunction()) return false;
JSFunction* constructor = JSFunction::cast(obj_constructor);
if (constructor != nullptr &&
constructor->initial_map() == heap_object->map()) {
return true;
}
return false;
}
void Heap::ScavengeStoreBufferCallback(Heap* heap, MemoryChunk* page,
StoreBufferEvent event) {
heap->store_buffer_rebuilder_.Callback(page, event);
......@@ -1602,6 +1624,12 @@ void Heap::Scavenge() {
promotion_queue_.Initialize();
ScavengeVisitor scavenge_visitor(this);
if (FLAG_scavenge_reclaim_unmodified_objects) {
isolate()->global_handles()->IdentifyWeakUnmodifiedObjects(
&IsUnmodifiedHeapObject);
}
{
// Copy roots.
GCTracer::Scope gc_scope(tracer(), GCTracer::Scope::SCAVENGER_ROOTS);
......@@ -1640,7 +1668,14 @@ void Heap::Scavenge() {
new_space_front = DoScavenge(&scavenge_visitor, new_space_front);
}
{
if (FLAG_scavenge_reclaim_unmodified_objects) {
isolate()->global_handles()->MarkNewSpaceWeakUnmodifiedObjectsPending(
&IsUnscavengedHeapObject);
isolate()->global_handles()->IterateNewSpaceWeakUnmodifiedRoots(
&scavenge_visitor);
new_space_front = DoScavenge(&scavenge_visitor, new_space_front);
} else {
GCTracer::Scope gc_scope(tracer(),
GCTracer::Scope::SCAVENGER_OBJECT_GROUPS);
while (isolate()->global_handles()->IterateObjectGroups(
......@@ -1649,14 +1684,14 @@ void Heap::Scavenge() {
}
isolate()->global_handles()->RemoveObjectGroups();
isolate()->global_handles()->RemoveImplicitRefGroups();
}
isolate()->global_handles()->IdentifyNewSpaceWeakIndependentHandles(
&IsUnscavengedHeapObject);
isolate()->global_handles()->IdentifyNewSpaceWeakIndependentHandles(
&IsUnscavengedHeapObject);
isolate()->global_handles()->IterateNewSpaceWeakIndependentRoots(
&scavenge_visitor);
new_space_front = DoScavenge(&scavenge_visitor, new_space_front);
isolate()->global_handles()->IterateNewSpaceWeakIndependentRoots(
&scavenge_visitor);
new_space_front = DoScavenge(&scavenge_visitor, new_space_front);
}
UpdateNewSpaceReferencesInExternalStringTable(
&UpdateNewSpaceReferenceInExternalStringTableEntry);
......
......@@ -6536,7 +6536,8 @@ static void IndependentWeakHandle(bool global_gc, bool interlinked) {
Local<Object> b(v8::Object::New(iso));
object_a.handle.Reset(iso, a);
object_b.handle.Reset(iso, b);
if (interlinked) {
if (interlinked &&
!v8::internal::FLAG_scavenge_reclaim_unmodified_objects) {
a->Set(v8_str("x"), b);
b->Set(v8_str("x"), a);
}
......@@ -6548,7 +6549,8 @@ static void IndependentWeakHandle(bool global_gc, bool interlinked) {
// We are relying on this creating a big flag array and reserving the space
// up front.
v8::Handle<Value> big_array = CompileRun("new Array(50000)");
a->Set(v8_str("y"), big_array);
if (!v8::internal::FLAG_scavenge_reclaim_unmodified_objects)
a->Set(v8_str("y"), big_array);
big_heap_size = CcTest::heap()->SizeOfObjects();
}
......
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