Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

8332257: Shenandoah: Move evacuation methods to implementation file #19240

Closed
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 77 additions & 0 deletions src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp
Original file line number Diff line number Diff line change
@@ -1119,6 +1119,83 @@ void ShenandoahHeap::evacuate_collection_set(bool concurrent) {
workers()->run_task(&task);
}

oop ShenandoahHeap::evacuate_object(oop p, Thread* thread) {
if (ShenandoahThreadLocalData::is_oom_during_evac(Thread::current())) {
// This thread went through the OOM during evac protocol and it is safe to return
// the forward pointer. It must not attempt to evacuate any more.
return ShenandoahBarrierSet::resolve_forwarded(p);
}

assert(ShenandoahThreadLocalData::is_evac_allowed(thread), "must be enclosed in oom-evac scope");

size_t size = p->size();

assert(!heap_region_containing(p)->is_humongous(), "never evacuate humongous objects");

bool alloc_from_gclab = true;
HeapWord* copy = nullptr;

#ifdef ASSERT
if (ShenandoahOOMDuringEvacALot &&
(os::random() & 1) == 0) { // Simulate OOM every ~2nd slow-path call
copy = nullptr;
} else {
#endif
if (UseTLAB) {
copy = allocate_from_gclab(thread, size);
}
if (copy == nullptr) {
ShenandoahAllocRequest req = ShenandoahAllocRequest::for_shared_gc(size);
copy = allocate_memory(req);
alloc_from_gclab = false;
}
#ifdef ASSERT
}
#endif

if (copy == nullptr) {
control_thread()->handle_alloc_failure_evac(size);

_oom_evac_handler.handle_out_of_memory_during_evacuation();

return ShenandoahBarrierSet::resolve_forwarded(p);
}

// Copy the object:
Copy::aligned_disjoint_words(cast_from_oop<HeapWord*>(p), copy, size);

// Try to install the new forwarding pointer.
oop copy_val = cast_to_oop(copy);
ContinuationGCSupport::relativize_stack_chunk(copy_val);

oop result = ShenandoahForwarding::try_update_forwardee(p, copy_val);
if (result == copy_val) {
// Successfully evacuated. Our copy is now the public one!
shenandoah_assert_correct(nullptr, copy_val);
return copy_val;
} else {
// Failed to evacuate. We need to deal with the object that is left behind. Since this
// new allocation is certainly after TAMS, it will be considered live in the next cycle.
// But if it happens to contain references to evacuated regions, those references would
// not get updated for this stale copy during this cycle, and we will crash while scanning
// it the next cycle.
//
// For GCLAB allocations, it is enough to rollback the allocation ptr. Either the next
// object will overwrite this stale copy, or the filler object on LAB retirement will
// do this. For non-GCLAB allocations, we have no way to retract the allocation, and
// have to explicitly overwrite the copy with the filler object. With that overwrite,
// we have to keep the fwdptr initialized and pointing to our (stale) copy.
if (alloc_from_gclab) {
ShenandoahThreadLocalData::gclab(thread)->undo_allocation(copy, size);
} else {
fill_with_object(copy, size);
shenandoah_assert_correct(nullptr, copy_val);
}
shenandoah_assert_correct(nullptr, result);
return result;
}
}

void ShenandoahHeap::trash_cset_regions() {
ShenandoahHeapLocker locker(lock());

2 changes: 1 addition & 1 deletion src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp
Original file line number Diff line number Diff line change
@@ -639,7 +639,7 @@ class ShenandoahHeap : public CollectedHeap, public ShenandoahSpaceInfo {

// Evacuates object src. Returns the evacuated object, either evacuated
// by this thread, or by some other thread.
inline oop evacuate_object(oop src, Thread* thread);
oop evacuate_object(oop src, Thread* thread);

// Call before/after evacuation.
inline void enter_evacuation(Thread* t);
77 changes: 0 additions & 77 deletions src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp
Original file line number Diff line number Diff line change
@@ -287,83 +287,6 @@ inline HeapWord* ShenandoahHeap::allocate_from_gclab(Thread* thread, size_t size
return allocate_from_gclab_slow(thread, size);
}

inline oop ShenandoahHeap::evacuate_object(oop p, Thread* thread) {
if (ShenandoahThreadLocalData::is_oom_during_evac(Thread::current())) {
// This thread went through the OOM during evac protocol and it is safe to return
// the forward pointer. It must not attempt to evacuate any more.
return ShenandoahBarrierSet::resolve_forwarded(p);
}

assert(ShenandoahThreadLocalData::is_evac_allowed(thread), "must be enclosed in oom-evac scope");

size_t size = p->size();

assert(!heap_region_containing(p)->is_humongous(), "never evacuate humongous objects");

bool alloc_from_gclab = true;
HeapWord* copy = nullptr;

#ifdef ASSERT
if (ShenandoahOOMDuringEvacALot &&
(os::random() & 1) == 0) { // Simulate OOM every ~2nd slow-path call
copy = nullptr;
} else {
#endif
if (UseTLAB) {
copy = allocate_from_gclab(thread, size);
}
if (copy == nullptr) {
ShenandoahAllocRequest req = ShenandoahAllocRequest::for_shared_gc(size);
copy = allocate_memory(req);
alloc_from_gclab = false;
}
#ifdef ASSERT
}
#endif

if (copy == nullptr) {
control_thread()->handle_alloc_failure_evac(size);

_oom_evac_handler.handle_out_of_memory_during_evacuation();

return ShenandoahBarrierSet::resolve_forwarded(p);
}

// Copy the object:
Copy::aligned_disjoint_words(cast_from_oop<HeapWord*>(p), copy, size);

// Try to install the new forwarding pointer.
oop copy_val = cast_to_oop(copy);
ContinuationGCSupport::relativize_stack_chunk(copy_val);

oop result = ShenandoahForwarding::try_update_forwardee(p, copy_val);
if (result == copy_val) {
// Successfully evacuated. Our copy is now the public one!
shenandoah_assert_correct(nullptr, copy_val);
return copy_val;
} else {
// Failed to evacuate. We need to deal with the object that is left behind. Since this
// new allocation is certainly after TAMS, it will be considered live in the next cycle.
// But if it happens to contain references to evacuated regions, those references would
// not get updated for this stale copy during this cycle, and we will crash while scanning
// it the next cycle.
//
// For GCLAB allocations, it is enough to rollback the allocation ptr. Either the next
// object will overwrite this stale copy, or the filler object on LAB retirement will
// do this. For non-GCLAB allocations, we have no way to retract the allocation, and
// have to explicitly overwrite the copy with the filler object. With that overwrite,
// we have to keep the fwdptr initialized and pointing to our (stale) copy.
if (alloc_from_gclab) {
ShenandoahThreadLocalData::gclab(thread)->undo_allocation(copy, size);
} else {
fill_with_object(copy, size);
shenandoah_assert_correct(nullptr, copy_val);
}
shenandoah_assert_correct(nullptr, result);
return result;
}
}

inline bool ShenandoahHeap::requires_marking(const void* entry) const {
oop obj = cast_to_oop(entry);
return !_marking_context->is_marked_strong(obj);