8224584: Shenandoah: Eliminate forwarding pointer word

Reviewed-by: shade, roland
This commit is contained in:
Roman Kennke 2019-05-29 12:01:21 +02:00
parent 114ba5a57c
commit fb4bb0a6cb
21 changed files with 285 additions and 425 deletions

@ -211,18 +211,46 @@ void ShenandoahBarrierSetAssembler::satb_write_barrier_pre(MacroAssembler* masm,
__ bind(done);
}
void ShenandoahBarrierSetAssembler::resolve_forward_pointer(MacroAssembler* masm, Register dst) {
void ShenandoahBarrierSetAssembler::resolve_forward_pointer(MacroAssembler* masm, Register dst, Register tmp) {
assert(ShenandoahLoadRefBarrier || ShenandoahCASBarrier, "Should be enabled");
Label is_null;
__ cbz(dst, is_null);
resolve_forward_pointer_not_null(masm, dst);
resolve_forward_pointer_not_null(masm, dst, tmp);
__ bind(is_null);
}
// IMPORTANT: This must preserve all registers, even rscratch1 and rscratch2.
void ShenandoahBarrierSetAssembler::resolve_forward_pointer_not_null(MacroAssembler* masm, Register dst) {
// IMPORTANT: This must preserve all registers, even rscratch1 and rscratch2, except those explicitely
// passed in.
void ShenandoahBarrierSetAssembler::resolve_forward_pointer_not_null(MacroAssembler* masm, Register dst, Register tmp) {
assert(ShenandoahLoadRefBarrier || ShenandoahCASBarrier, "Should be enabled");
__ ldr(dst, Address(dst, ShenandoahForwarding::byte_offset()));
// The below loads the mark word, checks if the lowest two bits are
// set, and if so, clear the lowest two bits and copy the result
// to dst. Otherwise it leaves dst alone.
// Implementing this is surprisingly awkward. I do it here by:
// - Inverting the mark word
// - Test lowest two bits == 0
// - If so, set the lowest two bits
// - Invert the result back, and copy to dst
bool borrow_reg = (tmp == noreg);
if (borrow_reg) {
// No free registers available. Make one useful.
tmp = rscratch1;
__ push(RegSet::of(tmp), sp);
}
Label done;
__ ldr(tmp, Address(dst, oopDesc::mark_offset_in_bytes()));
__ eon(tmp, tmp, zr);
__ ands(zr, tmp, markOopDesc::lock_mask_in_place);
__ br(Assembler::NE, done);
__ orr(tmp, tmp, markOopDesc::marked_value);
__ eon(dst, tmp, zr);
__ bind(done);
if (borrow_reg) {
__ pop(RegSet::of(tmp), sp);
}
}
void ShenandoahBarrierSetAssembler::load_reference_barrier_not_null(MacroAssembler* masm, Register dst, Register tmp) {
@ -343,40 +371,6 @@ void ShenandoahBarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet
}
void ShenandoahBarrierSetAssembler::tlab_allocate(MacroAssembler* masm, Register obj,
Register var_size_in_bytes,
int con_size_in_bytes,
Register t1,
Register t2,
Label& slow_case) {
assert_different_registers(obj, t2);
assert_different_registers(obj, var_size_in_bytes);
Register end = t2;
__ ldr(obj, Address(rthread, JavaThread::tlab_top_offset()));
if (var_size_in_bytes == noreg) {
__ lea(end, Address(obj, (int) (con_size_in_bytes + ShenandoahForwarding::byte_size())));
} else {
__ add(var_size_in_bytes, var_size_in_bytes, ShenandoahForwarding::byte_size());
__ lea(end, Address(obj, var_size_in_bytes));
}
__ ldr(rscratch1, Address(rthread, JavaThread::tlab_end_offset()));
__ cmp(end, rscratch1);
__ br(Assembler::HI, slow_case);
// update the tlab top pointer
__ str(end, Address(rthread, JavaThread::tlab_top_offset()));
__ add(obj, obj, ShenandoahForwarding::byte_size());
__ str(obj, Address(obj, ShenandoahForwarding::byte_offset()));
// recover var_size_in_bytes if necessary
if (var_size_in_bytes == end) {
__ sub(var_size_in_bytes, var_size_in_bytes, obj);
}
}
void ShenandoahBarrierSetAssembler::cmpxchg_oop(MacroAssembler* masm, Register addr, Register expected, Register new_val,
bool acquire, bool release, bool weak, bool is_cae,
Register result) {
@ -570,7 +564,7 @@ address ShenandoahBarrierSetAssembler::generate_shenandoah_lrb(StubCodeGenerator
__ bind(work);
__ mov(rscratch2, r0);
resolve_forward_pointer_not_null(cgen->assembler(), r0);
resolve_forward_pointer_not_null(cgen->assembler(), r0, rscratch1);
__ cmp(rscratch2, r0);
__ br(Assembler::NE, done);

@ -54,8 +54,8 @@ private:
bool tosca_live,
bool expand_call);
void resolve_forward_pointer(MacroAssembler* masm, Register dst);
void resolve_forward_pointer_not_null(MacroAssembler* masm, Register dst);
void resolve_forward_pointer(MacroAssembler* masm, Register dst, Register tmp = noreg);
void resolve_forward_pointer_not_null(MacroAssembler* masm, Register dst, Register tmp = noreg);
void load_reference_barrier(MacroAssembler* masm, Register dst, Register tmp);
void load_reference_barrier_not_null(MacroAssembler* masm, Register dst, Register tmp);
@ -80,13 +80,6 @@ public:
Register dst, Address src, Register tmp1, Register tmp_thread);
virtual void store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
Address dst, Register val, Register tmp1, Register tmp2);
virtual void tlab_allocate(MacroAssembler* masm, Register obj,
Register var_size_in_bytes,
int con_size_in_bytes,
Register t1,
Register t2,
Label& slow_case);
void cmpxchg_oop(MacroAssembler* masm, Register addr, Register expected, Register new_val,
bool acquire, bool release, bool weak, bool is_cae, Register result);

@ -317,18 +317,46 @@ void ShenandoahBarrierSetAssembler::satb_write_barrier_pre(MacroAssembler* masm,
__ bind(done);
}
void ShenandoahBarrierSetAssembler::resolve_forward_pointer(MacroAssembler* masm, Register dst) {
void ShenandoahBarrierSetAssembler::resolve_forward_pointer(MacroAssembler* masm, Register dst, Register tmp) {
assert(ShenandoahCASBarrier, "should be enabled");
Label is_null;
__ testptr(dst, dst);
__ jcc(Assembler::zero, is_null);
resolve_forward_pointer_not_null(masm, dst);
resolve_forward_pointer_not_null(masm, dst, tmp);
__ bind(is_null);
}
void ShenandoahBarrierSetAssembler::resolve_forward_pointer_not_null(MacroAssembler* masm, Register dst) {
void ShenandoahBarrierSetAssembler::resolve_forward_pointer_not_null(MacroAssembler* masm, Register dst, Register tmp) {
assert(ShenandoahCASBarrier || ShenandoahLoadRefBarrier, "should be enabled");
__ movptr(dst, Address(dst, ShenandoahForwarding::byte_offset()));
// The below loads the mark word, checks if the lowest two bits are
// set, and if so, clear the lowest two bits and copy the result
// to dst. Otherwise it leaves dst alone.
// Implementing this is surprisingly awkward. I do it here by:
// - Inverting the mark word
// - Test lowest two bits == 0
// - If so, set the lowest two bits
// - Invert the result back, and copy to dst
bool borrow_reg = (tmp == noreg);
if (borrow_reg) {
// No free registers available. Make one useful.
tmp = rscratch1;
__ push(tmp);
}
Label done;
__ movptr(tmp, Address(dst, oopDesc::mark_offset_in_bytes()));
__ notptr(tmp);
__ testb(tmp, markOopDesc::marked_value);
__ jccb(Assembler::notZero, done);
__ orptr(tmp, markOopDesc::marked_value);
__ notptr(tmp);
__ mov(dst, tmp);
__ bind(done);
if (borrow_reg) {
__ pop(tmp);
}
}
@ -338,13 +366,7 @@ void ShenandoahBarrierSetAssembler::load_reference_barrier_not_null(MacroAssembl
Label done;
Address gc_state(r15_thread, in_bytes(ShenandoahThreadLocalData::gc_state_offset()));
__ testb(gc_state, ShenandoahHeap::HAS_FORWARDED | ShenandoahHeap::EVACUATION | ShenandoahHeap::TRAVERSAL);
__ jccb(Assembler::zero, done);
// Heap is unstable, need to perform the resolve even if LRB is inactive
resolve_forward_pointer_not_null(masm, dst);
__ testb(gc_state, ShenandoahHeap::EVACUATION | ShenandoahHeap::TRAVERSAL);
__ testb(gc_state, ShenandoahHeap::HAS_FORWARDED);
__ jccb(Assembler::zero, done);
if (dst != rax) {
@ -479,55 +501,6 @@ void ShenandoahBarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet
}
}
void ShenandoahBarrierSetAssembler::tlab_allocate(MacroAssembler* masm,
Register thread, Register obj,
Register var_size_in_bytes,
int con_size_in_bytes,
Register t1, Register t2,
Label& slow_case) {
assert_different_registers(obj, t1, t2);
assert_different_registers(obj, var_size_in_bytes, t1);
Register end = t2;
if (!thread->is_valid()) {
#ifdef _LP64
thread = r15_thread;
#else
assert(t1->is_valid(), "need temp reg");
thread = t1;
__ get_thread(thread);
#endif
}
__ verify_tlab();
__ movptr(obj, Address(thread, JavaThread::tlab_top_offset()));
if (var_size_in_bytes == noreg) {
__ lea(end, Address(obj, con_size_in_bytes + ShenandoahForwarding::byte_size()));
} else {
__ addptr(var_size_in_bytes, ShenandoahForwarding::byte_size());
__ lea(end, Address(obj, var_size_in_bytes, Address::times_1));
}
__ cmpptr(end, Address(thread, JavaThread::tlab_end_offset()));
__ jcc(Assembler::above, slow_case);
// update the tlab top pointer
__ movptr(Address(thread, JavaThread::tlab_top_offset()), end);
// Initialize brooks pointer
#ifdef _LP64
__ incrementq(obj, ShenandoahForwarding::byte_size());
#else
__ incrementl(obj, ShenandoahForwarding::byte_size());
#endif
__ movptr(Address(obj, ShenandoahForwarding::byte_offset()), obj);
// recover var_size_in_bytes if necessary
if (var_size_in_bytes == end) {
__ subptr(var_size_in_bytes, obj);
}
__ verify_tlab();
}
// Special Shenandoah CAS implementation that handles false negatives
// due to concurrent evacuation.
#ifndef _LP64
@ -856,7 +829,7 @@ address ShenandoahBarrierSetAssembler::generate_shenandoah_lrb(StubCodeGenerator
address start = __ pc();
#ifdef _LP64
Label not_done;
Label resolve_oop, slow_path;
// We use RDI, which also serves as argument register for slow call.
// RAX always holds the src object ptr, except after the slow call and
@ -878,13 +851,31 @@ address ShenandoahBarrierSetAssembler::generate_shenandoah_lrb(StubCodeGenerator
// unlive: rdi
__ testbool(r8);
// unlive: r8
__ jccb(Assembler::notZero, not_done);
__ jccb(Assembler::notZero, resolve_oop);
__ pop(r8);
__ pop(rdi);
__ ret(0);
__ bind(not_done);
__ bind(resolve_oop);
__ movptr(r8, Address(rax, oopDesc::mark_offset_in_bytes()));
// Test if both lowest bits are set. We trick it by negating the bits
// then test for both bits clear.
__ notptr(r8);
__ testb(r8, markOopDesc::marked_value);
__ jccb(Assembler::notZero, slow_path);
// Clear both lower bits. It's still inverted, so set them, and then invert back.
__ orptr(r8, markOopDesc::marked_value);
__ notptr(r8);
// At this point, r8 contains the decoded forwarding pointer.
__ mov(rax, r8);
__ pop(r8);
__ pop(rdi);
__ ret(0);
__ bind(slow_path);
__ push(rcx);
__ push(rdx);

@ -55,8 +55,8 @@ private:
bool tosca_live,
bool expand_call);
void resolve_forward_pointer(MacroAssembler* masm, Register dst);
void resolve_forward_pointer_not_null(MacroAssembler* masm, Register dst);
void resolve_forward_pointer(MacroAssembler* masm, Register dst, Register tmp = noreg);
void resolve_forward_pointer_not_null(MacroAssembler* masm, Register dst, Register tmp = noreg);
void load_reference_barrier_not_null(MacroAssembler* masm, Register dst);
@ -91,13 +91,6 @@ public:
virtual void store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
Address dst, Register val, Register tmp1, Register tmp2);
virtual void tlab_allocate(MacroAssembler* masm,
Register thread, Register obj,
Register var_size_in_bytes,
int con_size_in_bytes,
Register t1, Register t2,
Label& slow_case);
virtual void barrier_stubs_init();
};

@ -710,30 +710,6 @@ void ShenandoahBarrierSetC2::clone(GraphKit* kit, Node* src, Node* dst, Node* si
BarrierSetC2::clone(kit, src, dst, size, is_array);
}
Node* ShenandoahBarrierSetC2::obj_allocate(PhaseMacroExpand* macro, Node* ctrl, Node* mem, Node* toobig_false, Node* size_in_bytes,
Node*& i_o, Node*& needgc_ctrl,
Node*& fast_oop_ctrl, Node*& fast_oop_rawmem,
intx prefetch_lines) const {
PhaseIterGVN& igvn = macro->igvn();
// Allocate several words more for the Shenandoah brooks pointer.
size_in_bytes = new AddXNode(size_in_bytes, igvn.MakeConX(ShenandoahForwarding::byte_size()));
macro->transform_later(size_in_bytes);
Node* fast_oop = BarrierSetC2::obj_allocate(macro, ctrl, mem, toobig_false, size_in_bytes,
i_o, needgc_ctrl, fast_oop_ctrl, fast_oop_rawmem,
prefetch_lines);
// Bump up object for Shenandoah brooks pointer.
fast_oop = new AddPNode(macro->top(), fast_oop, igvn.MakeConX(ShenandoahForwarding::byte_size()));
macro->transform_later(fast_oop);
// Initialize Shenandoah brooks pointer to point to the object itself.
fast_oop_rawmem = macro->make_store(fast_oop_ctrl, fast_oop_rawmem, fast_oop, ShenandoahForwarding::byte_offset(), fast_oop, T_OBJECT);
return fast_oop;
}
// Support for GC barriers emitted during parsing
bool ShenandoahBarrierSetC2::is_gc_barrier_node(Node* node) const {
if (node->Opcode() == Op_ShenandoahLoadReferenceBarrier) return true;

@ -108,11 +108,6 @@ public:
// This is the entry-point for the backend to perform accesses through the Access API.
virtual void clone(GraphKit* kit, Node* src, Node* dst, Node* size, bool is_array) const;
virtual Node* obj_allocate(PhaseMacroExpand* macro, Node* ctrl, Node* mem, Node* toobig_false, Node* size_in_bytes,
Node*& i_o, Node*& needgc_ctrl,
Node*& fast_oop_ctrl, Node*& fast_oop_rawmem,
intx prefetch_lines) const;
// These are general helper methods used by C2
virtual bool array_copy_requires_gc_barriers(bool tightly_coupled_alloc, BasicType type, bool is_clone, ArrayCopyPhase phase) const;
virtual void clone_barrier_at_expansion(ArrayCopyNode* ac, Node* call, PhaseIterGVN& igvn) const;

@ -1455,7 +1455,7 @@ void ShenandoahBarrierC2Support::pin_and_expand(PhaseIdealLoop* phase) {
assert(val->bottom_type()->make_oopptr(), "need oop");
assert(val->bottom_type()->make_oopptr()->const_oop() == NULL, "expect non-constant");
enum { _heap_stable = 1, _not_cset, _not_equal, _evac_path, _null_path, PATH_LIMIT };
enum { _heap_stable = 1, _not_cset, _fwded, _evac_path, _null_path, PATH_LIMIT };
Node* region = new RegionNode(PATH_LIMIT);
Node* val_phi = new PhiNode(region, uncasted_val->bottom_type()->is_oopptr());
Node* raw_mem_phi = PhiNode::make(region, raw_mem, Type::MEMORY, TypeRawPtr::BOTTOM);
@ -1505,36 +1505,48 @@ void ShenandoahBarrierC2Support::pin_and_expand(PhaseIdealLoop* phase) {
IfNode* iff = unc_ctrl->in(0)->as_If();
phase->igvn().replace_input_of(iff, 1, phase->igvn().intcon(1));
}
Node* addr = new AddPNode(new_val, uncasted_val, phase->igvn().MakeConX(ShenandoahForwarding::byte_offset()));
Node* addr = new AddPNode(new_val, uncasted_val, phase->igvn().MakeConX(oopDesc::mark_offset_in_bytes()));
phase->register_new_node(addr, ctrl);
assert(val->bottom_type()->isa_oopptr(), "what else?");
const TypePtr* obj_type = val->bottom_type()->is_oopptr();
const TypePtr* adr_type = TypeRawPtr::BOTTOM;
Node* fwd = new LoadPNode(ctrl, raw_mem, addr, adr_type, obj_type, MemNode::unordered);
phase->register_new_node(fwd, ctrl);
assert(new_val->bottom_type()->isa_oopptr(), "what else?");
Node* markword = new LoadXNode(ctrl, raw_mem, addr, TypeRawPtr::BOTTOM, TypeX_X, MemNode::unordered);
phase->register_new_node(markword, ctrl);
// Test if object is forwarded. This is the case if lowest two bits are set.
Node* masked = new AndXNode(markword, phase->igvn().MakeConX(markOopDesc::lock_mask_in_place));
phase->register_new_node(masked, ctrl);
Node* cmp = new CmpXNode(masked, phase->igvn().MakeConX(markOopDesc::marked_value));
phase->register_new_node(cmp, ctrl);
// Only branch to LRB stub if object is not forwarded; otherwise reply with fwd ptr
Node* cmp = new CmpPNode(fwd, new_val);
phase->register_new_node(cmp, ctrl);
Node* bol = new BoolNode(cmp, BoolTest::eq);
Node* bol = new BoolNode(cmp, BoolTest::eq); // Equals 3 means it's forwarded
phase->register_new_node(bol, ctrl);
IfNode* iff = new IfNode(ctrl, bol, PROB_UNLIKELY(0.999), COUNT_UNKNOWN);
if (reg2_ctrl == NULL) reg2_ctrl = iff;
IfNode* iff = new IfNode(ctrl, bol, PROB_LIKELY(0.999), COUNT_UNKNOWN);
phase->register_control(iff, loop, ctrl);
Node* if_not_eq = new IfFalseNode(iff);
phase->register_control(if_not_eq, loop, iff);
Node* if_eq = new IfTrueNode(iff);
phase->register_control(if_eq, loop, iff);
Node* if_fwd = new IfTrueNode(iff);
phase->register_control(if_fwd, loop, iff);
Node* if_not_fwd = new IfFalseNode(iff);
phase->register_control(if_not_fwd, loop, iff);
// Decode forward pointer: since we already have the lowest bits, we can just subtract them
// from the mark word without the need for large immediate mask.
Node* masked2 = new SubXNode(markword, masked);
phase->register_new_node(masked2, if_fwd);
Node* fwdraw = new CastX2PNode(masked2);
fwdraw->init_req(0, if_fwd);
phase->register_new_node(fwdraw, if_fwd);
Node* fwd = new CheckCastPPNode(NULL, fwdraw, val->bottom_type());
phase->register_new_node(fwd, if_fwd);
// Wire up not-equal-path in slots 3.
region->init_req(_not_equal, if_not_eq);
val_phi->init_req(_not_equal, fwd);
raw_mem_phi->init_req(_not_equal, raw_mem);
region->init_req(_fwded, if_fwd);
val_phi->init_req(_fwded, fwd);
raw_mem_phi->init_req(_fwded, raw_mem);
// Call lrb-stub and wire up that path in slots 4
Node* result_mem = NULL;
ctrl = if_eq;
ctrl = if_not_fwd;
fwd = new_val;
call_lrb_stub(ctrl, fwd, result_mem, raw_mem, phase);
region->init_req(_evac_path, ctrl);
val_phi->init_req(_evac_path, fwd);

@ -60,6 +60,9 @@ void ShenandoahAsserts::print_obj(ShenandoahMessageBuffer& msg, oop obj) {
stringStream ss;
r->print_on(&ss);
stringStream mw_ss;
obj->mark()->print_on(&mw_ss);
ShenandoahMarkingContext* const ctx = heap->marking_context();
msg.append(" " PTR_FORMAT " - klass " PTR_FORMAT " %s\n", p2i(obj), p2i(obj->klass()), obj->klass()->external_name());
@ -69,6 +72,7 @@ void ShenandoahAsserts::print_obj(ShenandoahMessageBuffer& msg, oop obj) {
if (heap->traversal_gc() != NULL) {
msg.append(" %3s in traversal set\n", heap->traversal_gc()->traversal_set()->is_in((HeapWord*) obj) ? "" : "not");
}
msg.append(" mark:%s\n", mw_ss.as_string());
msg.append(" region: %s", ss.as_string());
}
@ -250,7 +254,7 @@ void ShenandoahAsserts::assert_in_correct_region(void* interior_loc, oop obj, co
file, line);
}
size_t alloc_size = obj->size() + ShenandoahForwarding::word_size();
size_t alloc_size = obj->size();
if (alloc_size > ShenandoahHeapRegion::humongous_threshold_words()) {
size_t idx = r->region_number();
size_t num_regions = ShenandoahHeapRegion::required_regions(alloc_size * HeapWordSize);

@ -26,7 +26,6 @@
#include "gc/shenandoah/shenandoahBarrierSet.hpp"
#include "gc/shenandoah/shenandoahBarrierSetAssembler.hpp"
#include "gc/shenandoah/shenandoahCollectorPolicy.hpp"
#include "gc/shenandoah/shenandoahForwarding.hpp"
#include "gc/shenandoah/shenandoahHeap.inline.hpp"
#include "gc/shenandoah/shenandoahHeuristics.hpp"
#include "gc/shenandoah/shenandoahTraversalGC.hpp"
@ -262,7 +261,7 @@ oop ShenandoahBarrierSet::load_reference_barrier_mutator(oop obj) {
ShenandoahHeapRegion* r = _heap->heap_region_containing(obj);
assert(r->is_cset(), "sanity");
HeapWord* cur = (HeapWord*)obj + obj->size() + ShenandoahForwarding::word_size();
HeapWord* cur = (HeapWord*)obj + obj->size();
size_t count = 0;
while ((cur < r->top()) && ctx->is_marked(oop(cur)) && (count++ < max)) {
@ -270,7 +269,7 @@ oop ShenandoahBarrierSet::load_reference_barrier_mutator(oop obj) {
if (oopDesc::equals_raw(cur_oop, resolve_forwarded_not_null(cur_oop))) {
_heap->evacuate_object(cur_oop, thread);
}
cur = cur + cur_oop->size() + ShenandoahForwarding::word_size();
cur = cur + cur_oop->size();
}
}

@ -25,7 +25,6 @@
#define SHARE_GC_SHENANDOAH_SHENANDOAHCONCURRENTMARK_INLINE_HPP
#include "gc/shenandoah/shenandoahAsserts.hpp"
#include "gc/shenandoah/shenandoahForwarding.hpp"
#include "gc/shenandoah/shenandoahBarrierSet.inline.hpp"
#include "gc/shenandoah/shenandoahConcurrentMark.hpp"
#include "gc/shenandoah/shenandoahMarkingContext.inline.hpp"
@ -70,7 +69,7 @@ void ShenandoahConcurrentMark::do_task(ShenandoahObjToScanQueue* q, T* cl, jusho
inline void ShenandoahConcurrentMark::count_liveness(jushort* live_data, oop obj) {
size_t region_idx = _heap->heap_region_index_containing(obj);
ShenandoahHeapRegion* region = _heap->get_region(region_idx);
size_t size = obj->size() + ShenandoahForwarding::word_size();
size_t size = obj->size();
if (!region->is_humongous_start()) {
assert(!region->is_humongous(), "Cannot have continuations here");

@ -28,68 +28,11 @@
#include "utilities/globalDefinitions.hpp"
class ShenandoahForwarding {
/*
* Notes:
*
* a. It is important to have byte_offset and word_offset return constant
* expressions, because that will allow to constant-fold forwarding ptr
* accesses. This is not a problem in JIT compilers that would generate
* the code once, but it is problematic in GC hotpath code.
*
* b. With filler object mechanics, we may need to allocate more space for
* the forwarding ptr to meet alignment requirements for objects. This
* means *_offset and *_size calls are NOT interchangeable. The accesses
* to forwarding ptrs should always be via *_offset. Storage size
* calculations should always be via *_size.
*/
public:
/* Offset from the object start, in HeapWords. */
static inline int word_offset() {
return -1; // exactly one HeapWord
}
/* Offset from the object start, in bytes. */
static inline int byte_offset() {
return -HeapWordSize; // exactly one HeapWord
}
/* Allocated size, in HeapWords. */
static inline uint word_size() {
return (uint) MinObjAlignment;
}
/* Allocated size, in bytes */
static inline uint byte_size() {
return (uint) MinObjAlignmentInBytes;
}
/* Assert basic stuff once at startup. */
static void initial_checks() {
guarantee (MinObjAlignment > 0, "sanity, word_size is correct");
guarantee (MinObjAlignmentInBytes > 0, "sanity, byte_size is correct");
}
/* Initializes forwarding pointer (to self).
*/
static inline void initialize(oop obj);
/* Gets forwardee from the given object.
*/
static inline oop get_forwardee(oop obj);
/* Tries to atomically update forwardee in $holder object to $update.
* Assumes $holder points at itself.
* Asserts $holder is in from-space.
* Asserts $update is in to-space.
*/
static inline oop try_update_forwardee(oop obj, oop update);
/* Sets raw value for forwardee slot.
* THIS IS DANGEROUS: USERS HAVE TO INITIALIZE/SET FORWARDEE BACK AFTER THEY ARE DONE.
*/
static inline void set_forwardee_raw(oop obj, HeapWord* update);
/* Returns the raw value from forwardee slot.
*/
static inline HeapWord* get_forwardee_raw(oop obj);
@ -99,8 +42,21 @@ public:
*/
static inline HeapWord* get_forwardee_raw_unchecked(oop obj);
private:
static inline HeapWord** forward_ptr_addr(oop obj);
/**
* Returns true if the object is forwarded, false otherwise.
*/
static inline bool is_forwarded(oop obj);
/* Tries to atomically update forwardee in $holder object to $update.
* Assumes $holder points at itself.
* Asserts $holder is in from-space.
* Asserts $update is in to-space.
*
* Returns the new object 'update' upon success, or
* the new forwardee that a competing thread installed.
*/
static inline oop try_update_forwardee(oop obj, oop update);
};
#endif // SHARE_GC_SHENANDOAH_SHENANDOAHFORWARDING_HPP

@ -26,40 +26,45 @@
#include "gc/shenandoah/shenandoahAsserts.hpp"
#include "gc/shenandoah/shenandoahForwarding.hpp"
#include "oops/markOop.inline.hpp"
#include "runtime/atomic.hpp"
inline HeapWord** ShenandoahForwarding::forward_ptr_addr(oop obj) {
return (HeapWord**)((HeapWord*) obj + word_offset());
}
inline void ShenandoahForwarding::initialize(oop obj) {
shenandoah_assert_in_heap(NULL, obj);
*forward_ptr_addr(obj) = (HeapWord*) obj;
}
inline void ShenandoahForwarding::set_forwardee_raw(oop obj, HeapWord* update) {
shenandoah_assert_in_heap(NULL, obj);
*forward_ptr_addr(obj) = update;
}
inline HeapWord* ShenandoahForwarding::get_forwardee_raw(oop obj) {
shenandoah_assert_in_heap(NULL, obj);
return *forward_ptr_addr(obj);
return get_forwardee_raw_unchecked(obj);
}
inline HeapWord* ShenandoahForwarding::get_forwardee_raw_unchecked(oop obj) {
return *forward_ptr_addr(obj);
markOop mark = obj->mark_raw();
if (mark->is_marked()) {
return (HeapWord*) mark->clear_lock_bits();
} else {
return (HeapWord*) obj;
}
}
inline oop ShenandoahForwarding::get_forwardee(oop obj) {
shenandoah_assert_correct(NULL, obj);
return oop(*forward_ptr_addr(obj));
return oop(get_forwardee_raw_unchecked(obj));
}
inline bool ShenandoahForwarding::is_forwarded(oop obj) {
return obj->mark_raw()->is_marked();
}
inline oop ShenandoahForwarding::try_update_forwardee(oop obj, oop update) {
oop result = (oop) Atomic::cmpxchg(update, (oop*)forward_ptr_addr(obj), obj);
shenandoah_assert_correct_except(NULL, obj, !oopDesc::equals_raw(result, obj));
return result;
markOop old_mark = obj->mark_raw();
if (old_mark->is_marked()) {
return (oop) old_mark->clear_lock_bits();
}
markOop new_mark = markOopDesc::encode_pointer_as_mark(update);
markOop prev_mark = obj->cas_set_mark_raw(new_mark, old_mark);
if (prev_mark == old_mark) {
return update;
} else {
return (oop) prev_mark->clear_lock_bits();
}
}
#endif // SHARE_GC_SHENANDOAH_SHENANDOAHFORWARDING_INLINE_HPP

@ -34,7 +34,6 @@
#include "gc/shenandoah/shenandoahAllocTracker.hpp"
#include "gc/shenandoah/shenandoahBarrierSet.hpp"
#include "gc/shenandoah/shenandoahForwarding.hpp"
#include "gc/shenandoah/shenandoahClosures.inline.hpp"
#include "gc/shenandoah/shenandoahCollectionSet.hpp"
#include "gc/shenandoah/shenandoahCollectorPolicy.hpp"
@ -139,8 +138,6 @@ public:
};
jint ShenandoahHeap::initialize() {
ShenandoahForwarding::initial_checks();
initialize_heuristics();
//
@ -876,49 +873,6 @@ HeapWord* ShenandoahHeap::allocate_memory_under_lock(ShenandoahAllocRequest& req
return _free_set->allocate(req, in_new_region);
}
class ShenandoahMemAllocator : public MemAllocator {
private:
MemAllocator& _initializer;
public:
ShenandoahMemAllocator(MemAllocator& initializer, Klass* klass, size_t word_size, Thread* thread) :
MemAllocator(klass, word_size + ShenandoahForwarding::word_size(), thread),
_initializer(initializer) {}
protected:
virtual HeapWord* mem_allocate(Allocation& allocation) const {
HeapWord* result = MemAllocator::mem_allocate(allocation);
// Initialize brooks-pointer
if (result != NULL) {
result += ShenandoahForwarding::word_size();
ShenandoahForwarding::initialize(oop(result));
assert(! ShenandoahHeap::heap()->in_collection_set(result), "never allocate in targetted region");
}
return result;
}
virtual oop initialize(HeapWord* mem) const {
return _initializer.initialize(mem);
}
};
oop ShenandoahHeap::obj_allocate(Klass* klass, int size, TRAPS) {
ObjAllocator initializer(klass, size, THREAD);
ShenandoahMemAllocator allocator(initializer, klass, size, THREAD);
return allocator.allocate();
}
oop ShenandoahHeap::array_allocate(Klass* klass, int size, int length, bool do_zero, TRAPS) {
ObjArrayAllocator initializer(klass, size, length, do_zero, THREAD);
ShenandoahMemAllocator allocator(initializer, klass, size, THREAD);
return allocator.allocate();
}
oop ShenandoahHeap::class_allocate(Klass* klass, int size, TRAPS) {
ClassAllocator initializer(klass, size, THREAD);
ShenandoahMemAllocator allocator(initializer, klass, size, THREAD);
return allocator.allocate();
}
HeapWord* ShenandoahHeap::mem_allocate(size_t size,
bool* gc_overhead_limit_was_exceeded) {
ShenandoahAllocRequest req = ShenandoahAllocRequest::for_shared(size);
@ -961,15 +915,6 @@ MetaWord* ShenandoahHeap::satisfy_failed_metadata_allocation(ClassLoaderData* lo
return NULL;
}
void ShenandoahHeap::fill_with_dummy_object(HeapWord* start, HeapWord* end, bool zap) {
HeapWord* obj = tlab_post_allocation_setup(start);
CollectedHeap::fill_with_object(obj, end);
}
size_t ShenandoahHeap::min_dummy_object_size() const {
return CollectedHeap::min_dummy_object_size() + ShenandoahForwarding::word_size();
}
class ShenandoahConcurrentEvacuateRegionObjectClosure : public ObjectClosure {
private:
ShenandoahHeap* const _heap;
@ -980,7 +925,7 @@ public:
void do_object(oop p) {
shenandoah_assert_marked(NULL, p);
if (oopDesc::equals_raw(p, ShenandoahBarrierSet::resolve_forwarded_not_null(p))) {
if (!p->is_forwarded()) {
_heap->evacuate_object(p, _thread);
}
}
@ -1060,8 +1005,8 @@ void ShenandoahHeap::print_heap_regions_on(outputStream* st) const {
void ShenandoahHeap::trash_humongous_region_at(ShenandoahHeapRegion* start) {
assert(start->is_humongous_start(), "reclaim regions starting with the first one");
oop humongous_obj = oop(start->bottom() + ShenandoahForwarding::word_size());
size_t size = humongous_obj->size() + ShenandoahForwarding::word_size();
oop humongous_obj = oop(start->bottom());
size_t size = humongous_obj->size();
size_t required_regions = ShenandoahHeapRegion::required_regions(size * HeapWordSize);
size_t index = start->region_number() + required_regions - 1;
@ -1874,13 +1819,6 @@ void ShenandoahHeap::set_evacuation_in_progress(bool in_progress) {
set_gc_state_mask(EVACUATION, in_progress);
}
HeapWord* ShenandoahHeap::tlab_post_allocation_setup(HeapWord* obj) {
// Initialize Brooks pointer for the next object
HeapWord* result = obj + ShenandoahForwarding::word_size();
ShenandoahForwarding::initialize(oop(result));
return result;
}
void ShenandoahHeap::ref_processing_init() {
assert(_max_workers > 0, "Sanity");
@ -2853,11 +2791,3 @@ void ShenandoahHeap::flush_liveness_cache(uint worker_id) {
}
}
}
size_t ShenandoahHeap::obj_size(oop obj) const {
return CollectedHeap::obj_size(obj) + ShenandoahForwarding::word_size();
}
ptrdiff_t ShenandoahHeap::cell_header_size() const {
return ShenandoahForwarding::byte_size();
}

@ -520,9 +520,6 @@ public:
bool is_in(const void* p) const;
size_t obj_size(oop obj) const;
virtual ptrdiff_t cell_header_size() const;
void collect(GCCause::Cause cause);
void do_full_collection(bool clear_all_soft_refs);
@ -576,10 +573,6 @@ public:
size_t size,
Metaspace::MetadataType mdtype);
oop obj_allocate(Klass* klass, int size, TRAPS);
oop array_allocate(Klass* klass, int size, int length, bool do_zero, TRAPS);
oop class_allocate(Klass* klass, int size, TRAPS);
void notify_mutator_alloc_words(size_t words, bool waste);
// Shenandoah supports TLAB allocation
@ -591,10 +584,6 @@ public:
size_t max_tlab_size() const;
size_t tlab_used(Thread* ignored) const;
HeapWord* tlab_post_allocation_setup(HeapWord* obj);
void fill_with_dummy_object(HeapWord* start, HeapWord* end, bool zap);
size_t min_dummy_object_size() const;
void resize_tlabs();
void ensure_parsability(bool retire_tlabs);

@ -235,51 +235,46 @@ inline oop ShenandoahHeap::evacuate_object(oop p, Thread* thread) {
assert(ShenandoahThreadLocalData::is_evac_allowed(thread), "must be enclosed in oom-evac scope");
size_t size_no_fwdptr = (size_t) p->size();
size_t size_with_fwdptr = size_no_fwdptr + ShenandoahForwarding::word_size();
size_t size = p->size();
assert(!heap_region_containing(p)->is_humongous(), "never evacuate humongous objects");
bool alloc_from_gclab = true;
HeapWord* filler = NULL;
HeapWord* copy = NULL;
#ifdef ASSERT
if (ShenandoahOOMDuringEvacALot &&
(os::random() & 1) == 0) { // Simulate OOM every ~2nd slow-path call
filler = NULL;
copy = NULL;
} else {
#endif
if (UseTLAB) {
filler = allocate_from_gclab(thread, size_with_fwdptr);
copy = allocate_from_gclab(thread, size);
}
if (filler == NULL) {
ShenandoahAllocRequest req = ShenandoahAllocRequest::for_shared_gc(size_with_fwdptr);
filler = allocate_memory(req);
if (copy == NULL) {
ShenandoahAllocRequest req = ShenandoahAllocRequest::for_shared_gc(size);
copy = allocate_memory(req);
alloc_from_gclab = false;
}
#ifdef ASSERT
}
#endif
if (filler == NULL) {
control_thread()->handle_alloc_failure_evac(size_with_fwdptr);
if (copy == NULL) {
control_thread()->handle_alloc_failure_evac(size);
_oom_evac_handler.handle_out_of_memory_during_evacuation();
return ShenandoahBarrierSet::resolve_forwarded(p);
}
// Copy the object and initialize its forwarding ptr:
HeapWord* copy = filler + ShenandoahForwarding::word_size();
oop copy_val = oop(copy);
Copy::aligned_disjoint_words((HeapWord*) p, copy, size_no_fwdptr);
ShenandoahForwarding::initialize(oop(copy));
// Copy the object:
Copy::aligned_disjoint_words((HeapWord*) p, copy, size);
// Try to install the new forwarding pointer.
oop copy_val = oop(copy);
oop result = ShenandoahForwarding::try_update_forwardee(p, copy_val);
if (oopDesc::equals_raw(result, p)) {
if (oopDesc::equals_raw(result, copy_val)) {
// Successfully evacuated. Our copy is now the public one!
shenandoah_assert_correct(NULL, copy_val);
return copy_val;
@ -296,11 +291,11 @@ inline oop ShenandoahHeap::evacuate_object(oop p, Thread* thread) {
// 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(filler, size_with_fwdptr);
ShenandoahThreadLocalData::gclab(thread)->undo_allocation(copy, size);
} else {
fill_with_object(copy, size_no_fwdptr);
fill_with_object(copy, size);
shenandoah_assert_correct(NULL, copy_val);
}
shenandoah_assert_correct(NULL, copy_val);
shenandoah_assert_correct(NULL, result);
return result;
}
@ -371,7 +366,6 @@ inline void ShenandoahHeap::marked_object_iterate(ShenandoahHeapRegion* region,
template<class T>
inline void ShenandoahHeap::marked_object_iterate(ShenandoahHeapRegion* region, T* cl, HeapWord* limit) {
assert(ShenandoahForwarding::word_offset() < 0, "skip_delta calculation below assumes the forwarding ptr is before obj");
assert(! region->is_humongous_continuation(), "no humongous continuation regions here");
ShenandoahMarkingContext* const ctx = complete_marking_context();
@ -380,10 +374,9 @@ inline void ShenandoahHeap::marked_object_iterate(ShenandoahHeapRegion* region,
MarkBitMap* mark_bit_map = ctx->mark_bit_map();
HeapWord* tams = ctx->top_at_mark_start(region);
size_t skip_bitmap_delta = ShenandoahForwarding::word_size() + 1;
size_t skip_objsize_delta = ShenandoahForwarding::word_size() /* + actual obj.size() below */;
HeapWord* start = region->bottom() + ShenandoahForwarding::word_size();
HeapWord* end = MIN2(tams + ShenandoahForwarding::word_size(), region->end());
size_t skip_bitmap_delta = 1;
HeapWord* start = region->bottom();
HeapWord* end = MIN2(tams, region->end());
// Step 1. Scan below the TAMS based on bitmap data.
HeapWord* limit_bitmap = MIN2(limit, tams);
@ -413,7 +406,7 @@ inline void ShenandoahHeap::marked_object_iterate(ShenandoahHeapRegion* region,
do {
avail = 0;
for (int c = 0; (c < dist) && (cb < limit_bitmap); c++) {
Prefetch::read(cb, ShenandoahForwarding::byte_offset());
Prefetch::read(cb, oopDesc::mark_offset_in_bytes());
slots[avail++] = cb;
cb += skip_bitmap_delta;
if (cb < limit_bitmap) {
@ -448,16 +441,16 @@ inline void ShenandoahHeap::marked_object_iterate(ShenandoahHeapRegion* region,
// Step 2. Accurate size-based traversal, happens past the TAMS.
// This restarts the scan at TAMS, which makes sure we traverse all objects,
// regardless of what happened at Step 1.
HeapWord* cs = tams + ShenandoahForwarding::word_size();
HeapWord* cs = tams;
while (cs < limit) {
assert (cs > tams, "only objects past TAMS here: " PTR_FORMAT " (" PTR_FORMAT ")", p2i(cs), p2i(tams));
assert (cs >= tams, "only objects past TAMS here: " PTR_FORMAT " (" PTR_FORMAT ")", p2i(cs), p2i(tams));
assert (cs < limit, "only objects below limit here: " PTR_FORMAT " (" PTR_FORMAT ")", p2i(cs), p2i(limit));
oop obj = oop(cs);
assert(oopDesc::is_oop(obj), "sanity");
assert(ctx->is_marked(obj), "object expected to be marked");
int size = obj->size();
cl->do_object(obj);
cs += size + skip_objsize_delta;
cs += size;
}
}

@ -23,7 +23,6 @@
#include "precompiled.hpp"
#include "memory/allocation.hpp"
#include "gc/shenandoah/shenandoahForwarding.hpp"
#include "gc/shenandoah/shenandoahHeapRegionSet.inline.hpp"
#include "gc/shenandoah/shenandoahHeap.inline.hpp"
#include "gc/shenandoah/shenandoahHeapRegion.hpp"
@ -453,12 +452,12 @@ void ShenandoahHeapRegion::oop_iterate(OopIterateClosure* blk) {
void ShenandoahHeapRegion::oop_iterate_objects(OopIterateClosure* blk) {
assert(! is_humongous(), "no humongous region here");
HeapWord* obj_addr = bottom() + ShenandoahForwarding::word_size();
HeapWord* obj_addr = bottom();
HeapWord* t = top();
// Could call objects iterate, but this is easier.
while (obj_addr < t) {
oop obj = oop(obj_addr);
obj_addr += obj->oop_iterate_size(blk) + ShenandoahForwarding::word_size();
obj_addr += obj->oop_iterate_size(blk);
}
}
@ -467,7 +466,7 @@ void ShenandoahHeapRegion::oop_iterate_humongous(OopIterateClosure* blk) {
// Find head.
ShenandoahHeapRegion* r = humongous_start_region();
assert(r->is_humongous_start(), "need humongous head here");
oop obj = oop(r->bottom() + ShenandoahForwarding::word_size());
oop obj = oop(r->bottom());
obj->oop_iterate(blk, MemRegion(bottom(), top()));
}
@ -506,11 +505,11 @@ HeapWord* ShenandoahHeapRegion::block_start_const(const void* p) const {
if (p >= top()) {
return top();
} else {
HeapWord* last = bottom() + ShenandoahForwarding::word_size();
HeapWord* last = bottom();
HeapWord* cur = last;
while (cur <= p) {
last = cur;
cur += oop(cur)->size() + ShenandoahForwarding::word_size();
cur += oop(cur)->size();
}
shenandoah_assert_correct(NULL, oop(last));
return last;

@ -24,7 +24,6 @@
#include "precompiled.hpp"
#include "gc/shared/gcCause.hpp"
#include "gc/shenandoah/shenandoahForwarding.hpp"
#include "gc/shenandoah/shenandoahCollectionSet.inline.hpp"
#include "gc/shenandoah/shenandoahCollectorPolicy.hpp"
#include "gc/shenandoah/shenandoahHeap.inline.hpp"
@ -164,7 +163,7 @@ void ShenandoahHeuristics::choose_collection_set(ShenandoahCollectionSet* collec
// Reclaim humongous regions here, and count them as the immediate garbage
#ifdef ASSERT
bool reg_live = region->has_live();
bool bm_live = ctx->is_marked(oop(region->bottom() + ShenandoahForwarding::word_size()));
bool bm_live = ctx->is_marked(oop(region->bottom()));
assert(reg_live == bm_live,
"Humongous liveness and marks should agree. Region live: %s; Bitmap live: %s; Region Live Words: " SIZE_FORMAT,
BOOL_TO_STR(reg_live), BOOL_TO_STR(bm_live), region->get_live_data_words());

@ -25,6 +25,7 @@
#include "code/codeCache.hpp"
#include "gc/shared/gcTraceTime.inline.hpp"
#include "gc/shared/preservedMarks.inline.hpp"
#include "gc/shenandoah/shenandoahForwarding.inline.hpp"
#include "gc/shenandoah/shenandoahConcurrentMark.inline.hpp"
#include "gc/shenandoah/shenandoahCollectionSet.hpp"
@ -46,11 +47,16 @@
#include "memory/universe.hpp"
#include "oops/compressedOops.inline.hpp"
#include "oops/oop.inline.hpp"
#include "runtime/biasedLocking.hpp"
#include "runtime/thread.hpp"
#include "utilities/copy.hpp"
#include "utilities/growableArray.hpp"
#include "gc/shared/workgroup.hpp"
ShenandoahMarkCompact::ShenandoahMarkCompact() :
_gc_timer(NULL),
_preserved_marks(new PreservedMarksSet(true)) {}
void ShenandoahMarkCompact::initialize(GCTimer* gc_timer) {
_gc_timer = gc_timer;
}
@ -121,6 +127,10 @@ void ShenandoahMarkCompact::do_it(GCCause::Cause gc_cause) {
// e. Set back forwarded objects bit back, in case some steps above dropped it.
heap->set_has_forwarded_objects(has_forwarded_objects);
// The rest of prologue:
BiasedLocking::preserve_marks();
_preserved_marks->init(heap->workers()->active_workers());
}
heap->make_parsable(true);
@ -159,6 +169,16 @@ void ShenandoahMarkCompact::do_it(GCCause::Cause gc_cause) {
phase4_compact_objects(worker_slices);
}
{
// Epilogue
SharedRestorePreservedMarksTaskExecutor exec(heap->workers());
_preserved_marks->restore(&exec);
BiasedLocking::restore_marks();
_preserved_marks->reclaim();
JvmtiExport::gc_epilogue();
}
// Resize metaspace
MetaspaceGC::compute_new_size();
@ -168,8 +188,6 @@ void ShenandoahMarkCompact::do_it(GCCause::Cause gc_cause) {
}
FREE_C_HEAP_ARRAY(ShenandoahHeapRegionSet*, worker_slices);
JvmtiExport::gc_epilogue();
heap->set_full_gc_move_in_progress(false);
heap->set_full_gc_in_progress(false);
@ -230,6 +248,7 @@ void ShenandoahMarkCompact::phase1_mark_heap() {
class ShenandoahPrepareForCompactionObjectClosure : public ObjectClosure {
private:
PreservedMarks* const _preserved_marks;
ShenandoahHeap* const _heap;
GrowableArray<ShenandoahHeapRegion*>& _empty_regions;
int _empty_regions_pos;
@ -238,7 +257,10 @@ private:
HeapWord* _compact_point;
public:
ShenandoahPrepareForCompactionObjectClosure(GrowableArray<ShenandoahHeapRegion*>& empty_regions, ShenandoahHeapRegion* to_region) :
ShenandoahPrepareForCompactionObjectClosure(PreservedMarks* preserved_marks,
GrowableArray<ShenandoahHeapRegion*>& empty_regions,
ShenandoahHeapRegion* to_region) :
_preserved_marks(preserved_marks),
_heap(ShenandoahHeap::heap()),
_empty_regions(empty_regions),
_empty_regions_pos(0),
@ -268,7 +290,7 @@ public:
assert(_heap->complete_marking_context()->is_marked(p), "must be marked");
assert(!_heap->complete_marking_context()->allocated_after_mark_start((HeapWord*) p), "must be truly marked");
size_t obj_size = p->size() + ShenandoahForwarding::word_size();
size_t obj_size = p->size();
if (_compact_point + obj_size > _to_region->end()) {
finish_region();
@ -291,13 +313,15 @@ public:
// Object fits into current region, record new location:
assert(_compact_point + obj_size <= _to_region->end(), "must fit");
shenandoah_assert_not_forwarded(NULL, p);
ShenandoahForwarding::set_forwardee_raw(p, _compact_point + ShenandoahForwarding::word_size());
_preserved_marks->push_if_necessary(p, p->mark_raw());
p->forward_to(oop(_compact_point));
_compact_point += obj_size;
}
};
class ShenandoahPrepareForCompactionTask : public AbstractGangTask {
private:
PreservedMarksSet* const _preserved_marks;
ShenandoahHeap* const _heap;
ShenandoahHeapRegionSet** const _worker_slices;
ShenandoahRegionIterator _heap_regions;
@ -320,8 +344,9 @@ private:
}
public:
ShenandoahPrepareForCompactionTask(ShenandoahHeapRegionSet** worker_slices) :
ShenandoahPrepareForCompactionTask(PreservedMarksSet* preserved_marks, ShenandoahHeapRegionSet** worker_slices) :
AbstractGangTask("Shenandoah Prepare For Compaction Task"),
_preserved_marks(preserved_marks),
_heap(ShenandoahHeap::heap()), _worker_slices(worker_slices) {
}
@ -337,7 +362,7 @@ public:
// Remember empty regions and reuse them as needed.
ResourceMark rm;
GrowableArray<ShenandoahHeapRegion*> empty_regions((int)_heap->num_regions());
ShenandoahPrepareForCompactionObjectClosure cl(empty_regions, from_region);
ShenandoahPrepareForCompactionObjectClosure cl(_preserved_marks->get(worker_id), empty_regions, from_region);
while (from_region != NULL) {
cl.set_from_region(from_region);
if (from_region->has_live()) {
@ -377,8 +402,8 @@ void ShenandoahMarkCompact::calculate_target_humongous_objects() {
size_t to_begin = heap->num_regions();
size_t to_end = heap->num_regions();
for (size_t c = heap->num_regions() - 1; c > 0; c--) {
ShenandoahHeapRegion *r = heap->get_region(c);
for (size_t c = heap->num_regions(); c > 0; c--) {
ShenandoahHeapRegion *r = heap->get_region(c - 1);
if (r->is_humongous_continuation() || (r->new_top() == r->bottom())) {
// To-region candidate: record this, and continue scan
to_begin = r->region_number();
@ -387,15 +412,16 @@ void ShenandoahMarkCompact::calculate_target_humongous_objects() {
if (r->is_humongous_start() && r->is_move_allowed()) {
// From-region candidate: movable humongous region
oop old_obj = oop(r->bottom() + ShenandoahForwarding::word_size());
size_t words_size = old_obj->size() + ShenandoahForwarding::word_size();
oop old_obj = oop(r->bottom());
size_t words_size = old_obj->size();
size_t num_regions = ShenandoahHeapRegion::required_regions(words_size * HeapWordSize);
size_t start = to_end - num_regions;
if (start >= to_begin && start != r->region_number()) {
// Fits into current window, and the move is non-trivial. Record the move then, and continue scan.
ShenandoahForwarding::set_forwardee_raw(old_obj, heap->get_region(start)->bottom() + ShenandoahForwarding::word_size());
_preserved_marks->get(0)->push_if_necessary(old_obj, old_obj->mark_raw());
old_obj->forward_to(oop(heap->get_region(start)->bottom()));
to_end = start;
continue;
}
@ -443,7 +469,7 @@ public:
void heap_region_do(ShenandoahHeapRegion* r) {
if (r->is_humongous_start()) {
oop humongous_obj = oop(r->bottom() + ShenandoahForwarding::word_size());
oop humongous_obj = oop(r->bottom());
if (!_ctx->is_marked(humongous_obj)) {
assert(!r->has_live(),
"Region " SIZE_FORMAT " is not marked, should not have live", r->region_number());
@ -484,7 +510,7 @@ void ShenandoahMarkCompact::phase2_calculate_target_addresses(ShenandoahHeapRegi
// Compute the new addresses for regular objects
{
ShenandoahGCPhase phase(ShenandoahPhaseTimings::full_gc_calculate_addresses_regular);
ShenandoahPrepareForCompactionTask prepare_task(worker_slices);
ShenandoahPrepareForCompactionTask prepare_task(_preserved_marks, worker_slices);
heap->workers()->run_task(&prepare_task);
}
@ -506,8 +532,10 @@ private:
if (!CompressedOops::is_null(o)) {
oop obj = CompressedOops::decode_not_null(o);
assert(_ctx->is_marked(obj), "must be marked");
oop forw = oop(ShenandoahForwarding::get_forwardee_raw(obj));
RawAccess<IS_NOT_NULL>::oop_store(p, forw);
if (obj->is_forwarded()) {
oop forw = obj->forwardee();
RawAccess<IS_NOT_NULL>::oop_store(p, forw);
}
}
}
@ -531,7 +559,6 @@ public:
}
void do_object(oop p) {
assert(_heap->complete_marking_context()->is_marked(p), "must be marked");
HeapWord* forw = ShenandoahForwarding::get_forwardee_raw(p);
p->oop_iterate(&_cl);
}
};
@ -562,15 +589,17 @@ public:
class ShenandoahAdjustRootPointersTask : public AbstractGangTask {
private:
ShenandoahRootAdjuster* _rp;
PreservedMarksSet* _preserved_marks;
public:
ShenandoahAdjustRootPointersTask(ShenandoahRootAdjuster* rp) :
ShenandoahAdjustRootPointersTask(ShenandoahRootAdjuster* rp, PreservedMarksSet* preserved_marks) :
AbstractGangTask("Shenandoah Adjust Root Pointers Task"),
_rp(rp) {}
_rp(rp),
_preserved_marks(preserved_marks) {}
void work(uint worker_id) {
ShenandoahAdjustPointersClosure cl;
_rp->roots_do(worker_id, &cl);
_preserved_marks->get(worker_id)->adjust_during_full_gc();
}
};
@ -587,7 +616,7 @@ void ShenandoahMarkCompact::phase3_update_references() {
DerivedPointerTable::clear();
#endif
ShenandoahRootAdjuster rp(nworkers, ShenandoahPhaseTimings::full_gc_roots);
ShenandoahAdjustRootPointersTask task(&rp);
ShenandoahAdjustRootPointersTask task(&rp, _preserved_marks);
workers->run_task(&task);
#if COMPILER2_OR_JVMCI
DerivedPointerTable::update_pointers();
@ -610,13 +639,13 @@ public:
void do_object(oop p) {
assert(_heap->complete_marking_context()->is_marked(p), "must be marked");
size_t size = (size_t)p->size();
HeapWord* compact_to = ShenandoahForwarding::get_forwardee_raw(p);
HeapWord* compact_from = (HeapWord*) p;
if (compact_from != compact_to) {
if (p->is_forwarded()) {
HeapWord* compact_from = (HeapWord*) p;
HeapWord* compact_to = (HeapWord*) p->forwardee();
Copy::aligned_conjoint_words(compact_from, compact_to, size);
oop new_obj = oop(compact_to);
new_obj->init_mark_raw();
}
oop new_obj = oop(compact_to);
ShenandoahForwarding::initialize(new_obj);
}
};
@ -707,31 +736,30 @@ void ShenandoahMarkCompact::compact_humongous_objects() {
ShenandoahHeap* heap = ShenandoahHeap::heap();
for (size_t c = heap->num_regions() - 1; c > 0; c--) {
ShenandoahHeapRegion* r = heap->get_region(c);
for (size_t c = heap->num_regions(); c > 0; c--) {
ShenandoahHeapRegion* r = heap->get_region(c - 1);
if (r->is_humongous_start()) {
oop old_obj = oop(r->bottom() + ShenandoahForwarding::word_size());
size_t words_size = old_obj->size() + ShenandoahForwarding::word_size();
oop old_obj = oop(r->bottom());
if (!old_obj->is_forwarded()) {
// No need to move the object, it stays at the same slot
continue;
}
size_t words_size = old_obj->size();
size_t num_regions = ShenandoahHeapRegion::required_regions(words_size * HeapWordSize);
size_t old_start = r->region_number();
size_t old_end = old_start + num_regions - 1;
size_t new_start = heap->heap_region_index_containing(ShenandoahForwarding::get_forwardee_raw(old_obj));
size_t new_start = heap->heap_region_index_containing(old_obj->forwardee());
size_t new_end = new_start + num_regions - 1;
if (old_start == new_start) {
// No need to move the object, it stays at the same slot
continue;
}
assert(old_start != new_start, "must be real move");
assert (r->is_move_allowed(), "should be movable");
Copy::aligned_conjoint_words(heap->get_region(old_start)->bottom(),
heap->get_region(new_start)->bottom(),
ShenandoahHeapRegion::region_size_words()*num_regions);
oop new_obj = oop(heap->get_region(new_start)->bottom() + ShenandoahForwarding::word_size());
ShenandoahForwarding::initialize(new_obj);
oop new_obj = oop(heap->get_region(new_start)->bottom());
new_obj->init_mark_raw();
{
for (size_t c = old_start; c <= old_end; c++) {

@ -49,12 +49,19 @@
* where it does sliding compaction, without interfering with other threads.
*/
class PreservedMarksSet;
class ShenandoahMarkCompact : public CHeapObj<mtGC> {
friend class ShenandoahPrepareForCompactionObjectClosure;
private:
GCTimer* _gc_timer;
PreservedMarksSet* _preserved_marks;
public:
ShenandoahMarkCompact();
void initialize(GCTimer* gc_timer);
void do_it(GCCause::Cause gc_cause);
private:
@ -65,7 +72,6 @@ private:
void calculate_target_humongous_objects();
void compact_humongous_objects();
};
#endif // SHARE_GC_SHENANDOAH_SHENANDOAHMARKCOMPACT_HPP

@ -35,7 +35,6 @@
#include "gc/shenandoah/shenandoahCollectionSet.hpp"
#include "gc/shenandoah/shenandoahCollectorPolicy.hpp"
#include "gc/shenandoah/shenandoahFreeSet.hpp"
#include "gc/shenandoah/shenandoahForwarding.hpp"
#include "gc/shenandoah/shenandoahPhaseTimings.hpp"
#include "gc/shenandoah/shenandoahHeap.inline.hpp"
#include "gc/shenandoah/shenandoahHeapRegionSet.inline.hpp"
@ -633,7 +632,7 @@ void ShenandoahTraversalGC::final_traversal_collection() {
bool candidate = traversal_regions->is_in(r) && !r->has_live() && not_allocated;
if (r->is_humongous_start() && candidate) {
// Trash humongous.
HeapWord* humongous_obj = r->bottom() + ShenandoahForwarding::word_size();
HeapWord* humongous_obj = r->bottom();
assert(!ctx->is_marked(oop(humongous_obj)), "must not be marked");
r->make_trash_immediate();
while (i + 1 < num_regions && _heap->get_region(i + 1)->is_humongous_continuation()) {

@ -138,7 +138,7 @@ private:
// skip
break;
case ShenandoahVerifier::_verify_liveness_complete:
Atomic::add(obj->size() + ShenandoahForwarding::word_size(), &_ld[obj_reg->region_number()]);
Atomic::add((uint) obj->size(), &_ld[obj_reg->region_number()]);
// fallthrough for fast failure for un-live regions:
case ShenandoahVerifier::_verify_liveness_conservative:
check(ShenandoahAsserts::_safe_oop, obj, obj_reg->has_live(),
@ -533,7 +533,7 @@ public:
virtual void work_humongous(ShenandoahHeapRegion *r, ShenandoahVerifierStack& stack, ShenandoahVerifyOopClosure& cl) {
size_t processed = 0;
HeapWord* obj = r->bottom() + ShenandoahForwarding::word_size();
HeapWord* obj = r->bottom();
if (_heap->complete_marking_context()->is_marked((oop)obj)) {
verify_and_follow(obj, stack, cl, &processed);
}
@ -547,12 +547,12 @@ public:
// Bitmaps, before TAMS
if (tams > r->bottom()) {
HeapWord* start = r->bottom() + ShenandoahForwarding::word_size();
HeapWord* start = r->bottom();
HeapWord* addr = mark_bit_map->get_next_marked_addr(start, tams);
while (addr < tams) {
verify_and_follow(addr, stack, cl, &processed);
addr += ShenandoahForwarding::word_size();
addr += 1;
if (addr < tams) {
addr = mark_bit_map->get_next_marked_addr(addr, tams);
}
@ -562,11 +562,11 @@ public:
// Size-based, after TAMS
{
HeapWord* limit = r->top();
HeapWord* addr = tams + ShenandoahForwarding::word_size();
HeapWord* addr = tams;
while (addr < limit) {
verify_and_follow(addr, stack, cl, &processed);
addr += oop(addr)->size() + ShenandoahForwarding::word_size();
addr += oop(addr)->size();
}
}