Adds a scavenge GC pass to collect unmodified references
Adds a scavenge GC pass that collects unmodified references instead of processing object groups. This mode can be controlled by setting FLAG_scavenge_reclaim_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/1410593005 Cr-Commit-Position: refs/heads/master@{#31599}
This commit is contained in:
parent
37f5e23b5c
commit
959e050c1d
24
include/v8.h
24
include/v8.h
@ -603,6 +603,13 @@ template <class T> class PersistentBase {
|
|||||||
*/
|
*/
|
||||||
V8_INLINE void MarkPartiallyDependent();
|
V8_INLINE void MarkPartiallyDependent();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marks the reference to this object as active. The scavenge garbage
|
||||||
|
* collection should not reclaim the objects marked as active.
|
||||||
|
* This bit is cleared after the each garbage collection pass.
|
||||||
|
*/
|
||||||
|
V8_INLINE void MarkActive();
|
||||||
|
|
||||||
V8_INLINE bool IsIndependent() const;
|
V8_INLINE bool IsIndependent() const;
|
||||||
|
|
||||||
/** Checks if the handle holds the only reference to an object. */
|
/** Checks if the handle holds the only reference to an object. */
|
||||||
@ -5960,6 +5967,13 @@ class V8_EXPORT Isolate {
|
|||||||
*/
|
*/
|
||||||
void VisitHandlesForPartialDependence(PersistentHandleVisitor* visitor);
|
void VisitHandlesForPartialDependence(PersistentHandleVisitor* visitor);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Iterates through all the persistent handles in the current isolate's heap
|
||||||
|
* that have class_ids and are weak to be marked as inactive if there is no
|
||||||
|
* pending activity for the handle.
|
||||||
|
*/
|
||||||
|
void VisitWeakHandles(PersistentHandleVisitor* visitor);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template <class K, class V, class Traits>
|
template <class K, class V, class Traits>
|
||||||
friend class PersistentValueMapBase;
|
friend class PersistentValueMapBase;
|
||||||
@ -7042,6 +7056,7 @@ class Internals {
|
|||||||
static const int kNodeStateIsNearDeathValue = 4;
|
static const int kNodeStateIsNearDeathValue = 4;
|
||||||
static const int kNodeIsIndependentShift = 3;
|
static const int kNodeIsIndependentShift = 3;
|
||||||
static const int kNodeIsPartiallyDependentShift = 4;
|
static const int kNodeIsPartiallyDependentShift = 4;
|
||||||
|
static const int kNodeIsActiveShift = 4;
|
||||||
|
|
||||||
static const int kJSObjectType = 0xb7;
|
static const int kJSObjectType = 0xb7;
|
||||||
static const int kFirstNonstringType = 0x80;
|
static const int kFirstNonstringType = 0x80;
|
||||||
@ -7368,6 +7383,15 @@ void PersistentBase<T>::MarkPartiallyDependent() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void PersistentBase<T>::MarkActive() {
|
||||||
|
typedef internal::Internals I;
|
||||||
|
if (this->IsEmpty()) return;
|
||||||
|
I::UpdateNodeFlag(reinterpret_cast<internal::Object**>(this->val_), true,
|
||||||
|
I::kNodeIsActiveShift);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
void PersistentBase<T>::SetWrapperClassId(uint16_t class_id) {
|
void PersistentBase<T>::SetWrapperClassId(uint16_t class_id) {
|
||||||
typedef internal::Internals I;
|
typedef internal::Internals I;
|
||||||
|
@ -7593,6 +7593,15 @@ void Isolate::VisitHandlesForPartialDependence(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Isolate::VisitWeakHandles(PersistentHandleVisitor* visitor) {
|
||||||
|
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
|
||||||
|
i::DisallowHeapAllocation no_allocation;
|
||||||
|
VisitorAdapter visitor_adapter(visitor);
|
||||||
|
isolate->global_handles()->IterateWeakRootsInNewSpaceWithClassIds(
|
||||||
|
&visitor_adapter);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
String::Utf8Value::Utf8Value(v8::Local<v8::Value> obj)
|
String::Utf8Value::Utf8Value(v8::Local<v8::Value> obj)
|
||||||
: str_(NULL), length_(0) {
|
: str_(NULL), length_(0) {
|
||||||
if (obj.IsEmpty()) return;
|
if (obj.IsEmpty()) return;
|
||||||
|
@ -683,6 +683,8 @@ DEFINE_BOOL(verify_heap, false, "verify heap pointers before and after GC")
|
|||||||
#endif
|
#endif
|
||||||
DEFINE_BOOL(move_object_start, false, "enable moving of object starts")
|
DEFINE_BOOL(move_object_start, false, "enable moving of object starts")
|
||||||
DEFINE_BOOL(memory_reducer, true, "use memory reducer")
|
DEFINE_BOOL(memory_reducer, true, "use memory reducer")
|
||||||
|
DEFINE_BOOL(scavenge_reclaim_unmodified_objects, false,
|
||||||
|
"remove unmodified and unreferenced objects")
|
||||||
|
|
||||||
// counters.cc
|
// counters.cc
|
||||||
DEFINE_INT(histogram_interval, 600000,
|
DEFINE_INT(histogram_interval, 600000,
|
||||||
|
@ -54,6 +54,8 @@ class GlobalHandles::Node {
|
|||||||
Internals::kNodeIsIndependentShift);
|
Internals::kNodeIsIndependentShift);
|
||||||
STATIC_ASSERT(static_cast<int>(IsPartiallyDependent::kShift) ==
|
STATIC_ASSERT(static_cast<int>(IsPartiallyDependent::kShift) ==
|
||||||
Internals::kNodeIsPartiallyDependentShift);
|
Internals::kNodeIsPartiallyDependentShift);
|
||||||
|
STATIC_ASSERT(static_cast<int>(IsActive::kShift) ==
|
||||||
|
Internals::kNodeIsActiveShift);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ENABLE_HANDLE_ZAPPING
|
#ifdef ENABLE_HANDLE_ZAPPING
|
||||||
@ -64,7 +66,11 @@ class GlobalHandles::Node {
|
|||||||
class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId;
|
class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId;
|
||||||
index_ = 0;
|
index_ = 0;
|
||||||
set_independent(false);
|
set_independent(false);
|
||||||
set_partially_dependent(false);
|
if (FLAG_scavenge_reclaim_unmodified_objects) {
|
||||||
|
set_active(false);
|
||||||
|
} else {
|
||||||
|
set_partially_dependent(false);
|
||||||
|
}
|
||||||
set_in_new_space_list(false);
|
set_in_new_space_list(false);
|
||||||
parameter_or_next_free_.next_free = NULL;
|
parameter_or_next_free_.next_free = NULL;
|
||||||
weak_callback_ = NULL;
|
weak_callback_ = NULL;
|
||||||
@ -86,7 +92,11 @@ class GlobalHandles::Node {
|
|||||||
object_ = object;
|
object_ = object;
|
||||||
class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId;
|
class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId;
|
||||||
set_independent(false);
|
set_independent(false);
|
||||||
set_partially_dependent(false);
|
if (FLAG_scavenge_reclaim_unmodified_objects) {
|
||||||
|
set_active(false);
|
||||||
|
} else {
|
||||||
|
set_partially_dependent(false);
|
||||||
|
}
|
||||||
set_state(NORMAL);
|
set_state(NORMAL);
|
||||||
parameter_or_next_free_.parameter = NULL;
|
parameter_or_next_free_.parameter = NULL;
|
||||||
weak_callback_ = NULL;
|
weak_callback_ = NULL;
|
||||||
@ -106,7 +116,11 @@ class GlobalHandles::Node {
|
|||||||
object_ = reinterpret_cast<Object*>(kGlobalHandleZapValue);
|
object_ = reinterpret_cast<Object*>(kGlobalHandleZapValue);
|
||||||
class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId;
|
class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId;
|
||||||
set_independent(false);
|
set_independent(false);
|
||||||
set_partially_dependent(false);
|
if (FLAG_scavenge_reclaim_unmodified_objects) {
|
||||||
|
set_active(false);
|
||||||
|
} else {
|
||||||
|
set_partially_dependent(false);
|
||||||
|
}
|
||||||
weak_callback_ = NULL;
|
weak_callback_ = NULL;
|
||||||
DecreaseBlockUses();
|
DecreaseBlockUses();
|
||||||
}
|
}
|
||||||
@ -140,12 +154,23 @@ class GlobalHandles::Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool is_partially_dependent() {
|
bool is_partially_dependent() {
|
||||||
|
CHECK(!FLAG_scavenge_reclaim_unmodified_objects);
|
||||||
return IsPartiallyDependent::decode(flags_);
|
return IsPartiallyDependent::decode(flags_);
|
||||||
}
|
}
|
||||||
void set_partially_dependent(bool v) {
|
void set_partially_dependent(bool v) {
|
||||||
|
CHECK(!FLAG_scavenge_reclaim_unmodified_objects);
|
||||||
flags_ = IsPartiallyDependent::update(flags_, v);
|
flags_ = IsPartiallyDependent::update(flags_, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool is_active() {
|
||||||
|
CHECK(FLAG_scavenge_reclaim_unmodified_objects);
|
||||||
|
return IsActive::decode(flags_);
|
||||||
|
}
|
||||||
|
void set_active(bool v) {
|
||||||
|
CHECK(FLAG_scavenge_reclaim_unmodified_objects);
|
||||||
|
flags_ = IsActive::update(flags_, v);
|
||||||
|
}
|
||||||
|
|
||||||
bool is_in_new_space_list() {
|
bool is_in_new_space_list() {
|
||||||
return IsInNewSpaceList::decode(flags_);
|
return IsInNewSpaceList::decode(flags_);
|
||||||
}
|
}
|
||||||
@ -349,6 +374,8 @@ class GlobalHandles::Node {
|
|||||||
// in_new_space_list) and a State.
|
// in_new_space_list) and a State.
|
||||||
class NodeState : public BitField<State, 0, 3> {};
|
class NodeState : public BitField<State, 0, 3> {};
|
||||||
class IsIndependent : public BitField<bool, 3, 1> {};
|
class IsIndependent : public BitField<bool, 3, 1> {};
|
||||||
|
// The following two fields are mutually exclusive
|
||||||
|
class IsActive : public BitField<bool, 4, 1> {};
|
||||||
class IsPartiallyDependent : public BitField<bool, 4, 1> {};
|
class IsPartiallyDependent : public BitField<bool, 4, 1> {};
|
||||||
class IsInNewSpaceList : public BitField<bool, 5, 1> {};
|
class IsInNewSpaceList : public BitField<bool, 5, 1> {};
|
||||||
class NodeWeaknessType : public BitField<WeaknessType, 6, 2> {};
|
class NodeWeaknessType : public BitField<WeaknessType, 6, 2> {};
|
||||||
@ -646,10 +673,18 @@ void GlobalHandles::IdentifyWeakHandles(WeakSlotCallback f) {
|
|||||||
void GlobalHandles::IterateNewSpaceStrongAndDependentRoots(ObjectVisitor* v) {
|
void GlobalHandles::IterateNewSpaceStrongAndDependentRoots(ObjectVisitor* v) {
|
||||||
for (int i = 0; i < new_space_nodes_.length(); ++i) {
|
for (int i = 0; i < new_space_nodes_.length(); ++i) {
|
||||||
Node* node = new_space_nodes_[i];
|
Node* node = new_space_nodes_[i];
|
||||||
if (node->IsStrongRetainer() ||
|
if (FLAG_scavenge_reclaim_unmodified_objects) {
|
||||||
(node->IsWeakRetainer() && !node->is_independent() &&
|
if (node->IsStrongRetainer() ||
|
||||||
!node->is_partially_dependent())) {
|
(node->IsWeakRetainer() && !node->is_independent() &&
|
||||||
|
node->is_active())) {
|
||||||
v->VisitPointer(node->location());
|
v->VisitPointer(node->location());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (node->IsStrongRetainer() ||
|
||||||
|
(node->IsWeakRetainer() && !node->is_independent() &&
|
||||||
|
!node->is_partially_dependent())) {
|
||||||
|
v->VisitPointer(node->location());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -687,6 +722,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_active(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_active()) && 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_active()) &&
|
||||||
|
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,
|
bool GlobalHandles::IterateObjectGroups(ObjectVisitor* v,
|
||||||
WeakSlotCallbackWithHeap can_skip) {
|
WeakSlotCallbackWithHeap can_skip) {
|
||||||
ComputeObjectGroupsAndImplicitReferences();
|
ComputeObjectGroupsAndImplicitReferences();
|
||||||
@ -757,13 +835,23 @@ int GlobalHandles::PostScavengeProcessing(
|
|||||||
// the freed_nodes.
|
// the freed_nodes.
|
||||||
continue;
|
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
|
// called between two global garbage collection callbacks which
|
||||||
// are not called for minor collections.
|
// are not called for minor collections.
|
||||||
if (!node->is_independent() && !node->is_partially_dependent()) {
|
if (FLAG_scavenge_reclaim_unmodified_objects) {
|
||||||
continue;
|
if (!node->is_independent() && (node->is_active())) {
|
||||||
|
node->set_active(false);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
node->set_active(false);
|
||||||
|
} else {
|
||||||
|
if (!node->is_independent() && !node->is_partially_dependent()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
node->clear_partially_dependent();
|
||||||
}
|
}
|
||||||
node->clear_partially_dependent();
|
|
||||||
if (node->PostGarbageCollectionProcessing(isolate_)) {
|
if (node->PostGarbageCollectionProcessing(isolate_)) {
|
||||||
if (initial_post_gc_processing_count != post_gc_processing_count_) {
|
if (initial_post_gc_processing_count != post_gc_processing_count_) {
|
||||||
// Weak callback triggered another GC and another round of
|
// Weak callback triggered another GC and another round of
|
||||||
@ -790,7 +878,11 @@ int GlobalHandles::PostMarkSweepProcessing(
|
|||||||
// the freed_nodes.
|
// the freed_nodes.
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
it.node()->clear_partially_dependent();
|
if (FLAG_scavenge_reclaim_unmodified_objects) {
|
||||||
|
it.node()->set_active(false);
|
||||||
|
} else {
|
||||||
|
it.node()->clear_partially_dependent();
|
||||||
|
}
|
||||||
if (it.node()->PostGarbageCollectionProcessing(isolate_)) {
|
if (it.node()->PostGarbageCollectionProcessing(isolate_)) {
|
||||||
if (initial_post_gc_processing_count != post_gc_processing_count_) {
|
if (initial_post_gc_processing_count != post_gc_processing_count_) {
|
||||||
// See the comment above.
|
// See the comment above.
|
||||||
@ -955,6 +1047,16 @@ void GlobalHandles::IterateAllRootsInNewSpaceWithClassIds(ObjectVisitor* v) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void GlobalHandles::IterateWeakRootsInNewSpaceWithClassIds(ObjectVisitor* v) {
|
||||||
|
for (int i = 0; i < new_space_nodes_.length(); ++i) {
|
||||||
|
Node* node = new_space_nodes_[i];
|
||||||
|
if (node->has_wrapper_class_id() && node->IsWeak()) {
|
||||||
|
v->VisitEmbedderReference(node->location(), node->wrapper_class_id());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int GlobalHandles::NumberOfWeakHandles() {
|
int GlobalHandles::NumberOfWeakHandles() {
|
||||||
int count = 0;
|
int count = 0;
|
||||||
for (NodeIterator it(this); !it.done(); it.Advance()) {
|
for (NodeIterator it(this); !it.done(); it.Advance()) {
|
||||||
|
@ -197,6 +197,10 @@ class GlobalHandles {
|
|||||||
// class ID.
|
// class ID.
|
||||||
void IterateAllRootsInNewSpaceWithClassIds(ObjectVisitor* v);
|
void IterateAllRootsInNewSpaceWithClassIds(ObjectVisitor* v);
|
||||||
|
|
||||||
|
// Iterate over all handles in the new space that are weak, unmodified
|
||||||
|
// and have class IDs
|
||||||
|
void IterateWeakRootsInNewSpaceWithClassIds(ObjectVisitor* v);
|
||||||
|
|
||||||
// Iterates over all weak roots in heap.
|
// Iterates over all weak roots in heap.
|
||||||
void IterateWeakRoots(ObjectVisitor* v);
|
void IterateWeakRoots(ObjectVisitor* v);
|
||||||
|
|
||||||
@ -204,7 +208,7 @@ class GlobalHandles {
|
|||||||
// them as pending.
|
// them as pending.
|
||||||
void IdentifyWeakHandles(WeakSlotCallback f);
|
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
|
// scavenge collections and iterate over sets of handles that are
|
||||||
// guaranteed to contain all handles holding new space objects (but
|
// guaranteed to contain all handles holding new space objects (but
|
||||||
// may also include old space objects).
|
// may also include old space objects).
|
||||||
@ -220,6 +224,19 @@ class GlobalHandles {
|
|||||||
// See the note above.
|
// See the note above.
|
||||||
void IterateNewSpaceWeakIndependentRoots(ObjectVisitor* v);
|
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
|
// Iterate over objects in object groups that have at least one object
|
||||||
// which requires visiting. The callback has to return true if objects
|
// which requires visiting. The callback has to return true if objects
|
||||||
// can be skipped and false otherwise.
|
// can be skipped and false otherwise.
|
||||||
|
@ -1501,6 +1501,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,
|
void Heap::ScavengeStoreBufferCallback(Heap* heap, MemoryChunk* page,
|
||||||
StoreBufferEvent event) {
|
StoreBufferEvent event) {
|
||||||
heap->store_buffer_rebuilder_.Callback(page, event);
|
heap->store_buffer_rebuilder_.Callback(page, event);
|
||||||
@ -1619,6 +1635,12 @@ void Heap::Scavenge() {
|
|||||||
promotion_queue_.Initialize();
|
promotion_queue_.Initialize();
|
||||||
|
|
||||||
ScavengeVisitor scavenge_visitor(this);
|
ScavengeVisitor scavenge_visitor(this);
|
||||||
|
|
||||||
|
if (FLAG_scavenge_reclaim_unmodified_objects) {
|
||||||
|
isolate()->global_handles()->IdentifyWeakUnmodifiedObjects(
|
||||||
|
&IsUnmodifiedHeapObject);
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
// Copy roots.
|
// Copy roots.
|
||||||
GCTracer::Scope gc_scope(tracer(), GCTracer::Scope::SCAVENGER_ROOTS);
|
GCTracer::Scope gc_scope(tracer(), GCTracer::Scope::SCAVENGER_ROOTS);
|
||||||
@ -1657,7 +1679,14 @@ void Heap::Scavenge() {
|
|||||||
new_space_front = DoScavenge(&scavenge_visitor, new_space_front);
|
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 gc_scope(tracer(),
|
||||||
GCTracer::Scope::SCAVENGER_OBJECT_GROUPS);
|
GCTracer::Scope::SCAVENGER_OBJECT_GROUPS);
|
||||||
while (isolate()->global_handles()->IterateObjectGroups(
|
while (isolate()->global_handles()->IterateObjectGroups(
|
||||||
@ -1666,15 +1695,15 @@ void Heap::Scavenge() {
|
|||||||
}
|
}
|
||||||
isolate()->global_handles()->RemoveObjectGroups();
|
isolate()->global_handles()->RemoveObjectGroups();
|
||||||
isolate()->global_handles()->RemoveImplicitRefGroups();
|
isolate()->global_handles()->RemoveImplicitRefGroups();
|
||||||
|
|
||||||
|
isolate()->global_handles()->IdentifyNewSpaceWeakIndependentHandles(
|
||||||
|
&IsUnscavengedHeapObject);
|
||||||
|
|
||||||
|
isolate()->global_handles()->IterateNewSpaceWeakIndependentRoots(
|
||||||
|
&scavenge_visitor);
|
||||||
|
new_space_front = DoScavenge(&scavenge_visitor, new_space_front);
|
||||||
}
|
}
|
||||||
|
|
||||||
isolate()->global_handles()->IdentifyNewSpaceWeakIndependentHandles(
|
|
||||||
&IsUnscavengedHeapObject);
|
|
||||||
|
|
||||||
isolate()->global_handles()->IterateNewSpaceWeakIndependentRoots(
|
|
||||||
&scavenge_visitor);
|
|
||||||
new_space_front = DoScavenge(&scavenge_visitor, new_space_front);
|
|
||||||
|
|
||||||
UpdateNewSpaceReferencesInExternalStringTable(
|
UpdateNewSpaceReferencesInExternalStringTable(
|
||||||
&UpdateNewSpaceReferenceInExternalStringTableEntry);
|
&UpdateNewSpaceReferenceInExternalStringTableEntry);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user