Commit dc78e0d4 authored by hlopko's avatar hlopko Committed by Commit bot

Immediately promote marked objects during scavenge

It happens that a scavenger runs during incremental marking. Currently scavenger does not care about MarkCompact's mark bits. When an object is alive and marked, and at least one scavenge happens during incremental marking, the object will be copied once to the other semispace in the new_space, and then once to the old_space. For surviving objects this is useless extra work.

In our current attempts (https://codereview.chromium.org/1988623002) to ensure marked objects are scavenged, all marked objects will survive therefore there will be many objects which will be uselessly copied.

This cl modifies our promotion logic so when incremental marking is in progress, and the object is marked, we promote it unconditionally.

BUG=
LOG=no

Review-Url: https://codereview.chromium.org/2005173003
Cr-Commit-Position: refs/heads/master@{#36643}
parent d87fb10f
...@@ -393,14 +393,30 @@ bool Heap::OldGenerationAllocationLimitReached() { ...@@ -393,14 +393,30 @@ bool Heap::OldGenerationAllocationLimitReached() {
return OldGenerationSpaceAvailable() < 0; return OldGenerationSpaceAvailable() < 0;
} }
template <PromotionMode promotion_mode>
bool Heap::ShouldBePromoted(Address old_address, int object_size) { bool Heap::ShouldBePromoted(Address old_address, int object_size) {
Page* page = Page::FromAddress(old_address); Page* page = Page::FromAddress(old_address);
Address age_mark = new_space_.age_mark(); Address age_mark = new_space_.age_mark();
if (promotion_mode == PROMOTE_MARKED) {
MarkBit mark_bit = Marking::MarkBitFrom(old_address);
if (!Marking::IsWhite(mark_bit)) {
return true;
}
}
return page->IsFlagSet(MemoryChunk::NEW_SPACE_BELOW_AGE_MARK) && return page->IsFlagSet(MemoryChunk::NEW_SPACE_BELOW_AGE_MARK) &&
(!page->ContainsLimit(age_mark) || old_address < age_mark); (!page->ContainsLimit(age_mark) || old_address < age_mark);
} }
PromotionMode Heap::CurrentPromotionMode() {
if (incremental_marking()->IsMarking()) {
return PROMOTE_MARKED;
} else {
return DEFAULT_PROMOTION;
}
}
void Heap::RecordWrite(Object* object, int offset, Object* o) { void Heap::RecordWrite(Object* object, int offset, Object* o) {
if (!InNewSpace(o) || !object->IsHeapObject() || InNewSpace(object)) { if (!InNewSpace(o) || !object->IsHeapObject() || InNewSpace(object)) {
return; return;
......
...@@ -1653,6 +1653,7 @@ void Heap::Scavenge() { ...@@ -1653,6 +1653,7 @@ void Heap::Scavenge() {
Address new_space_front = new_space_.ToSpaceStart(); Address new_space_front = new_space_.ToSpaceStart();
promotion_queue_.Initialize(); promotion_queue_.Initialize();
PromotionMode promotion_mode = CurrentPromotionMode();
ScavengeVisitor scavenge_visitor(this); ScavengeVisitor scavenge_visitor(this);
if (FLAG_scavenge_reclaim_unmodified_objects) { if (FLAG_scavenge_reclaim_unmodified_objects) {
...@@ -1670,7 +1671,7 @@ void Heap::Scavenge() { ...@@ -1670,7 +1671,7 @@ void Heap::Scavenge() {
// Copy objects reachable from the old generation. // Copy objects reachable from the old generation.
TRACE_GC(tracer(), GCTracer::Scope::SCAVENGER_OLD_TO_NEW_POINTERS); TRACE_GC(tracer(), GCTracer::Scope::SCAVENGER_OLD_TO_NEW_POINTERS);
RememberedSet<OLD_TO_NEW>::Iterate(this, [this](Address addr) { RememberedSet<OLD_TO_NEW>::Iterate(this, [this](Address addr) {
return Scavenger::CheckAndScavengeObject(this, addr, DEFAULT_PROMOTION); return Scavenger::CheckAndScavengeObject(this, addr);
}); });
RememberedSet<OLD_TO_NEW>::IterateTyped( RememberedSet<OLD_TO_NEW>::IterateTyped(
...@@ -1681,7 +1682,7 @@ void Heap::Scavenge() { ...@@ -1681,7 +1682,7 @@ void Heap::Scavenge() {
// If we do not force promotion, then we need to clear // If we do not force promotion, then we need to clear
// old_to_new slots in dead code objects after mark-compact. // old_to_new slots in dead code objects after mark-compact.
return Scavenger::CheckAndScavengeObject( return Scavenger::CheckAndScavengeObject(
this, reinterpret_cast<Address>(addr), FORCE_PROMOTION); this, reinterpret_cast<Address>(addr));
}); });
}); });
} }
...@@ -1705,7 +1706,8 @@ void Heap::Scavenge() { ...@@ -1705,7 +1706,8 @@ void Heap::Scavenge() {
{ {
TRACE_GC(tracer(), GCTracer::Scope::SCAVENGER_SEMISPACE); TRACE_GC(tracer(), GCTracer::Scope::SCAVENGER_SEMISPACE);
new_space_front = DoScavenge(&scavenge_visitor, new_space_front); new_space_front =
DoScavenge(&scavenge_visitor, new_space_front, promotion_mode);
} }
if (FLAG_scavenge_reclaim_unmodified_objects) { if (FLAG_scavenge_reclaim_unmodified_objects) {
...@@ -1714,12 +1716,14 @@ void Heap::Scavenge() { ...@@ -1714,12 +1716,14 @@ void Heap::Scavenge() {
isolate()->global_handles()->IterateNewSpaceWeakUnmodifiedRoots( isolate()->global_handles()->IterateNewSpaceWeakUnmodifiedRoots(
&scavenge_visitor); &scavenge_visitor);
new_space_front = DoScavenge(&scavenge_visitor, new_space_front); new_space_front =
DoScavenge(&scavenge_visitor, new_space_front, promotion_mode);
} else { } else {
TRACE_GC(tracer(), GCTracer::Scope::SCAVENGER_OBJECT_GROUPS); TRACE_GC(tracer(), GCTracer::Scope::SCAVENGER_OBJECT_GROUPS);
while (isolate()->global_handles()->IterateObjectGroups( while (isolate()->global_handles()->IterateObjectGroups(
&scavenge_visitor, &IsUnscavengedHeapObject)) { &scavenge_visitor, &IsUnscavengedHeapObject)) {
new_space_front = DoScavenge(&scavenge_visitor, new_space_front); new_space_front =
DoScavenge(&scavenge_visitor, new_space_front, promotion_mode);
} }
isolate()->global_handles()->RemoveObjectGroups(); isolate()->global_handles()->RemoveObjectGroups();
isolate()->global_handles()->RemoveImplicitRefGroups(); isolate()->global_handles()->RemoveImplicitRefGroups();
...@@ -1729,7 +1733,8 @@ void Heap::Scavenge() { ...@@ -1729,7 +1733,8 @@ void Heap::Scavenge() {
isolate()->global_handles()->IterateNewSpaceWeakIndependentRoots( isolate()->global_handles()->IterateNewSpaceWeakIndependentRoots(
&scavenge_visitor); &scavenge_visitor);
new_space_front = DoScavenge(&scavenge_visitor, new_space_front); new_space_front =
DoScavenge(&scavenge_visitor, new_space_front, promotion_mode);
} }
UpdateNewSpaceReferencesInExternalStringTable( UpdateNewSpaceReferencesInExternalStringTable(
...@@ -1911,9 +1916,9 @@ void Heap::VisitExternalResources(v8::ExternalResourceVisitor* visitor) { ...@@ -1911,9 +1916,9 @@ void Heap::VisitExternalResources(v8::ExternalResourceVisitor* visitor) {
external_string_table_.Iterate(&external_string_table_visitor); external_string_table_.Iterate(&external_string_table_visitor);
} }
Address Heap::DoScavenge(ObjectVisitor* scavenge_visitor, Address Heap::DoScavenge(ObjectVisitor* scavenge_visitor,
Address new_space_front) { Address new_space_front,
PromotionMode promotion_mode) {
do { do {
SemiSpace::AssertValidRange(new_space_front, new_space_.top()); SemiSpace::AssertValidRange(new_space_front, new_space_.top());
// The addresses new_space_front and new_space_.top() define a // The addresses new_space_front and new_space_.top() define a
...@@ -1922,8 +1927,14 @@ Address Heap::DoScavenge(ObjectVisitor* scavenge_visitor, ...@@ -1922,8 +1927,14 @@ Address Heap::DoScavenge(ObjectVisitor* scavenge_visitor,
while (new_space_front != new_space_.top()) { while (new_space_front != new_space_.top()) {
if (!Page::IsAlignedToPageSize(new_space_front)) { if (!Page::IsAlignedToPageSize(new_space_front)) {
HeapObject* object = HeapObject::FromAddress(new_space_front); HeapObject* object = HeapObject::FromAddress(new_space_front);
if (promotion_mode == PROMOTE_MARKED) {
new_space_front += StaticScavengeVisitor<PROMOTE_MARKED>::IterateBody(
object->map(), object);
} else {
new_space_front += new_space_front +=
StaticScavengeVisitor::IterateBody(object->map(), object); StaticScavengeVisitor<DEFAULT_PROMOTION>::IterateBody(
object->map(), object);
}
} else { } else {
new_space_front = Page::FromAllocationAreaAddress(new_space_front) new_space_front = Page::FromAllocationAreaAddress(new_space_front)
->next_page() ->next_page()
...@@ -4689,8 +4700,8 @@ void Heap::IteratePromotedObjectPointers(HeapObject* object, Address start, ...@@ -4689,8 +4700,8 @@ void Heap::IteratePromotedObjectPointers(HeapObject* object, Address start,
Object* target = *slot; Object* target = *slot;
if (target->IsHeapObject()) { if (target->IsHeapObject()) {
if (Heap::InFromSpace(target)) { if (Heap::InFromSpace(target)) {
callback(reinterpret_cast<HeapObject**>(slot), HeapObject::cast(target), callback(reinterpret_cast<HeapObject**>(slot),
DEFAULT_PROMOTION); HeapObject::cast(target));
Object* new_target = *slot; Object* new_target = *slot;
if (InNewSpace(new_target)) { if (InNewSpace(new_target)) {
SLOW_DCHECK(Heap::InToSpace(new_target)); SLOW_DCHECK(Heap::InToSpace(new_target));
...@@ -5232,7 +5243,8 @@ V8_DECLARE_ONCE(initialize_gc_once); ...@@ -5232,7 +5243,8 @@ V8_DECLARE_ONCE(initialize_gc_once);
static void InitializeGCOnce() { static void InitializeGCOnce() {
Scavenger::Initialize(); Scavenger::Initialize();
StaticScavengeVisitor::Initialize(); StaticScavengeVisitor<DEFAULT_PROMOTION>::Initialize();
StaticScavengeVisitor<PROMOTE_MARKED>::Initialize();
MarkCompactCollector::Initialize(); MarkCompactCollector::Initialize();
} }
......
...@@ -303,10 +303,9 @@ class Scavenger; ...@@ -303,10 +303,9 @@ class Scavenger;
class ScavengeJob; class ScavengeJob;
class WeakObjectRetainer; class WeakObjectRetainer;
enum PromotionMode { FORCE_PROMOTION, DEFAULT_PROMOTION }; enum PromotionMode { PROMOTE_MARKED, DEFAULT_PROMOTION };
typedef void (*ObjectSlotCallback)(HeapObject** from, HeapObject* to, typedef void (*ObjectSlotCallback)(HeapObject** from, HeapObject* to);
PromotionMode mode);
// A queue of objects promoted during scavenge. Each object is accompanied // A queue of objects promoted during scavenge. Each object is accompanied
// by it's size to avoid dereferencing a map pointer for scanning. // by it's size to avoid dereferencing a map pointer for scanning.
...@@ -779,8 +778,11 @@ class Heap { ...@@ -779,8 +778,11 @@ class Heap {
// An object should be promoted if the object has survived a // An object should be promoted if the object has survived a
// scavenge operation. // scavenge operation.
template <PromotionMode promotion_mode>
inline bool ShouldBePromoted(Address old_address, int object_size); inline bool ShouldBePromoted(Address old_address, int object_size);
inline PromotionMode CurrentPromotionMode();
void ClearNormalizedMapCaches(); void ClearNormalizedMapCaches();
void IncrementDeferredCount(v8::Isolate::UseCounterFeature feature); void IncrementDeferredCount(v8::Isolate::UseCounterFeature feature);
...@@ -1698,7 +1700,8 @@ class Heap { ...@@ -1698,7 +1700,8 @@ class Heap {
// Performs a minor collection in new generation. // Performs a minor collection in new generation.
void Scavenge(); void Scavenge();
Address DoScavenge(ObjectVisitor* scavenge_visitor, Address new_space_front); Address DoScavenge(ObjectVisitor* scavenge_visitor, Address new_space_front,
PromotionMode promotion_mode);
void UpdateNewSpaceReferencesInExternalStringTable( void UpdateNewSpaceReferencesInExternalStringTable(
ExternalStringTableUpdaterCallback updater_func); ExternalStringTableUpdaterCallback updater_func);
......
...@@ -1747,7 +1747,7 @@ class MarkCompactCollector::EvacuateNewSpaceVisitor final ...@@ -1747,7 +1747,7 @@ class MarkCompactCollector::EvacuateNewSpaceVisitor final
local_pretenuring_feedback_); local_pretenuring_feedback_);
int size = object->Size(); int size = object->Size();
HeapObject* target_object = nullptr; HeapObject* target_object = nullptr;
if (heap_->ShouldBePromoted(object->address(), size) && if (heap_->ShouldBePromoted<DEFAULT_PROMOTION>(object->address(), size) &&
TryEvacuateObject(compaction_spaces_->Get(OLD_SPACE), object, TryEvacuateObject(compaction_spaces_->Get(OLD_SPACE), object,
&target_object)) { &target_object)) {
// If we end up needing more special cases, we should factor this out. // If we end up needing more special cases, we should factor this out.
......
...@@ -10,8 +10,7 @@ ...@@ -10,8 +10,7 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
void Scavenger::ScavengeObject(HeapObject** p, HeapObject* object, void Scavenger::ScavengeObject(HeapObject** p, HeapObject* object) {
PromotionMode promotion_mode) {
DCHECK(object->GetIsolate()->heap()->InFromSpace(object)); DCHECK(object->GetIsolate()->heap()->InFromSpace(object));
// We use the first word (where the map pointer usually is) of a heap // We use the first word (where the map pointer usually is) of a heap
...@@ -35,19 +34,18 @@ void Scavenger::ScavengeObject(HeapObject** p, HeapObject* object, ...@@ -35,19 +34,18 @@ void Scavenger::ScavengeObject(HeapObject** p, HeapObject* object,
// AllocationMementos are unrooted and shouldn't survive a scavenge // AllocationMementos are unrooted and shouldn't survive a scavenge
DCHECK(object->map() != object->GetHeap()->allocation_memento_map()); DCHECK(object->map() != object->GetHeap()->allocation_memento_map());
// Call the slow part of scavenge object. // Call the slow part of scavenge object.
return ScavengeObjectSlow(p, object, promotion_mode); return ScavengeObjectSlow(p, object);
} }
SlotCallbackResult Scavenger::CheckAndScavengeObject( SlotCallbackResult Scavenger::CheckAndScavengeObject(Heap* heap,
Heap* heap, Address slot_address, PromotionMode promotion_mode) { Address slot_address) {
Object** slot = reinterpret_cast<Object**>(slot_address); Object** slot = reinterpret_cast<Object**>(slot_address);
Object* object = *slot; Object* object = *slot;
if (heap->InFromSpace(object)) { if (heap->InFromSpace(object)) {
HeapObject* heap_object = reinterpret_cast<HeapObject*>(object); HeapObject* heap_object = reinterpret_cast<HeapObject*>(object);
DCHECK(heap_object->IsHeapObject()); DCHECK(heap_object->IsHeapObject());
ScavengeObject(reinterpret_cast<HeapObject**>(slot), heap_object, ScavengeObject(reinterpret_cast<HeapObject**>(slot), heap_object);
promotion_mode);
object = *slot; object = *slot;
// If the object was in from space before and is after executing the // If the object was in from space before and is after executing the
...@@ -64,13 +62,14 @@ SlotCallbackResult Scavenger::CheckAndScavengeObject( ...@@ -64,13 +62,14 @@ SlotCallbackResult Scavenger::CheckAndScavengeObject(
} }
// static // static
void StaticScavengeVisitor::VisitPointer(Heap* heap, HeapObject* obj, template <PromotionMode promotion_mode>
void StaticScavengeVisitor<promotion_mode>::VisitPointer(Heap* heap,
HeapObject* obj,
Object** p) { Object** p) {
Object* object = *p; Object* object = *p;
if (!heap->InNewSpace(object)) return; if (!heap->InNewSpace(object)) return;
Scavenger::ScavengeObject(reinterpret_cast<HeapObject**>(p), Scavenger::ScavengeObject(reinterpret_cast<HeapObject**>(p),
reinterpret_cast<HeapObject*>(object), reinterpret_cast<HeapObject*>(object));
DEFAULT_PROMOTION);
} }
} // namespace internal } // namespace internal
......
This diff is collapsed.
...@@ -12,8 +12,7 @@ namespace v8 { ...@@ -12,8 +12,7 @@ namespace v8 {
namespace internal { namespace internal {
typedef void (*ScavengingCallback)(Map* map, HeapObject** slot, typedef void (*ScavengingCallback)(Map* map, HeapObject** slot,
HeapObject* object, HeapObject* object);
PromotionMode promotion_mode);
class Scavenger { class Scavenger {
public: public:
...@@ -26,15 +25,12 @@ class Scavenger { ...@@ -26,15 +25,12 @@ class Scavenger {
// necessary, the object might be promoted to an old space. The caller must // necessary, the object might be promoted to an old space. The caller must
// ensure the precondition that the object is (a) a heap object and (b) in // ensure the precondition that the object is (a) a heap object and (b) in
// the heap's from space. // the heap's from space.
static inline void ScavengeObject( static inline void ScavengeObject(HeapObject** p, HeapObject* object);
HeapObject** p, HeapObject* object, static inline SlotCallbackResult CheckAndScavengeObject(Heap* heap,
PromotionMode promotion_mode = DEFAULT_PROMOTION); Address slot_address);
static inline SlotCallbackResult CheckAndScavengeObject(
Heap* heap, Address slot_address, PromotionMode promotion_mode);
// Slow part of {ScavengeObject} above. // Slow part of {ScavengeObject} above.
static void ScavengeObjectSlow(HeapObject** p, HeapObject* object, static void ScavengeObjectSlow(HeapObject** p, HeapObject* object);
PromotionMode promotion_mode);
// Chooses an appropriate static visitor table depending on the current state // Chooses an appropriate static visitor table depending on the current state
// of the heap (i.e. incremental marking, logging and profiling). // of the heap (i.e. incremental marking, logging and profiling).
...@@ -67,8 +63,9 @@ class ScavengeVisitor : public ObjectVisitor { ...@@ -67,8 +63,9 @@ class ScavengeVisitor : public ObjectVisitor {
// Helper class for turning the scavenger into an object visitor that is also // Helper class for turning the scavenger into an object visitor that is also
// filtering out non-HeapObjects and objects which do not reside in new space. // filtering out non-HeapObjects and objects which do not reside in new space.
template <PromotionMode promotion_mode>
class StaticScavengeVisitor class StaticScavengeVisitor
: public StaticNewSpaceVisitor<StaticScavengeVisitor> { : public StaticNewSpaceVisitor<StaticScavengeVisitor<promotion_mode>> {
public: public:
static inline void VisitPointer(Heap* heap, HeapObject* object, Object** p); static inline void VisitPointer(Heap* heap, HeapObject* object, Object** p);
}; };
......
...@@ -711,6 +711,44 @@ TEST(DeleteWeakGlobalHandle) { ...@@ -711,6 +711,44 @@ TEST(DeleteWeakGlobalHandle) {
CHECK(WeakPointerCleared); CHECK(WeakPointerCleared);
} }
TEST(DoNotPromoteWhiteObjectsOnScavenge) {
CcTest::InitializeVM();
Isolate* isolate = CcTest::i_isolate();
Heap* heap = isolate->heap();
Factory* factory = isolate->factory();
HandleScope scope(isolate);
Handle<Object> white = factory->NewStringFromStaticChars("white");
CHECK(Marking::IsWhite(Marking::MarkBitFrom(HeapObject::cast(*white))));
heap->CollectGarbage(NEW_SPACE);
CHECK(heap->InNewSpace(*white));
}
TEST(PromoteGreyOrBlackObjectsOnScavenge) {
CcTest::InitializeVM();
Isolate* isolate = CcTest::i_isolate();
Heap* heap = isolate->heap();
Factory* factory = isolate->factory();
HandleScope scope(isolate);
Handle<Object> marked = factory->NewStringFromStaticChars("marked");
IncrementalMarking* marking = heap->incremental_marking();
marking->Stop();
heap->StartIncrementalMarking();
while (Marking::IsWhite(Marking::MarkBitFrom(HeapObject::cast(*marked)))) {
marking->Step(MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD,
IncrementalMarking::FORCE_MARKING,
IncrementalMarking::DO_NOT_FORCE_COMPLETION);
}
heap->CollectGarbage(NEW_SPACE);
CHECK(!heap->InNewSpace(*marked));
}
TEST(BytecodeArray) { TEST(BytecodeArray) {
static const uint8_t kRawBytes[] = {0xc3, 0x7e, 0xa5, 0x5a}; static const uint8_t kRawBytes[] = {0xc3, 0x7e, 0xa5, 0x5a};
......
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