8231086: Shenandoah: Stronger invariant for object-arraycopy
Reviewed-by: shade
This commit is contained in:
parent
5eb643144b
commit
9510e7fe5d
@ -47,7 +47,7 @@ void ShenandoahBarrierSetAssembler::arraycopy_prologue(MacroAssembler* masm, Dec
|
||||
Register src, Register dst, Register count, RegSet saved_regs) {
|
||||
if (is_oop) {
|
||||
bool dest_uninitialized = (decorators & IS_DEST_UNINITIALIZED) != 0;
|
||||
if (ShenandoahSATBBarrier && !dest_uninitialized) {
|
||||
if ((ShenandoahSATBBarrier && !dest_uninitialized) || ShenandoahLoadRefBarrier) {
|
||||
|
||||
Label done;
|
||||
|
||||
@ -57,27 +57,27 @@ void ShenandoahBarrierSetAssembler::arraycopy_prologue(MacroAssembler* masm, Dec
|
||||
// Is marking active?
|
||||
Address gc_state(rthread, in_bytes(ShenandoahThreadLocalData::gc_state_offset()));
|
||||
__ ldrb(rscratch1, gc_state);
|
||||
__ tbz(rscratch1, ShenandoahHeap::MARKING_BITPOS, done);
|
||||
if (dest_uninitialized) {
|
||||
__ tbz(rscratch2, ShenandoahHeap::HAS_FORWARDED_BITPOS, done);
|
||||
} else {
|
||||
__ mov(rscratch2, ShenandoahHeap::HAS_FORWARDED | ShenandoahHeap::MARKING);
|
||||
__ tst(rscratch1, rscratch2);
|
||||
__ br(Assembler::EQ, done);
|
||||
}
|
||||
|
||||
__ push(saved_regs, sp);
|
||||
if (count == c_rarg0) {
|
||||
if (dst == c_rarg1) {
|
||||
// exactly backwards!!
|
||||
__ mov(rscratch1, c_rarg0);
|
||||
__ mov(c_rarg0, c_rarg1);
|
||||
__ mov(c_rarg1, rscratch1);
|
||||
if (UseCompressedOops) {
|
||||
if (dest_uninitialized) {
|
||||
__ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_array_pre_duinit_narrow_oop_entry), src, dst, count);
|
||||
} else {
|
||||
__ mov(c_rarg1, count);
|
||||
__ mov(c_rarg0, dst);
|
||||
__ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_array_pre_narrow_oop_entry), src, dst, count);
|
||||
}
|
||||
} else {
|
||||
__ mov(c_rarg0, dst);
|
||||
__ mov(c_rarg1, count);
|
||||
}
|
||||
if (UseCompressedOops) {
|
||||
__ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_array_pre_narrow_oop_entry), 2);
|
||||
} else {
|
||||
__ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_array_pre_oop_entry), 2);
|
||||
if (dest_uninitialized) {
|
||||
__ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_array_pre_duinit_oop_entry), src, dst, count);
|
||||
} else {
|
||||
__ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_array_pre_oop_entry), src, dst, count);
|
||||
}
|
||||
}
|
||||
__ pop(saved_regs, sp);
|
||||
__ bind(done);
|
||||
@ -85,31 +85,6 @@ void ShenandoahBarrierSetAssembler::arraycopy_prologue(MacroAssembler* masm, Dec
|
||||
}
|
||||
}
|
||||
|
||||
void ShenandoahBarrierSetAssembler::arraycopy_epilogue(MacroAssembler* masm, DecoratorSet decorators, bool is_oop,
|
||||
Register start, Register count, Register scratch, RegSet saved_regs) {
|
||||
if (is_oop) {
|
||||
Label done;
|
||||
|
||||
// Avoid calling runtime if count == 0
|
||||
__ cbz(count, done);
|
||||
|
||||
// Is updating references?
|
||||
Address gc_state(rthread, in_bytes(ShenandoahThreadLocalData::gc_state_offset()));
|
||||
__ ldrb(rscratch1, gc_state);
|
||||
__ tbz(rscratch1, ShenandoahHeap::UPDATEREFS_BITPOS, done);
|
||||
|
||||
__ push(saved_regs, sp);
|
||||
assert_different_registers(start, count, scratch);
|
||||
assert_different_registers(c_rarg0, count);
|
||||
__ mov(c_rarg0, start);
|
||||
__ mov(c_rarg1, count);
|
||||
__ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_array_post_entry), 2);
|
||||
__ pop(saved_regs, sp);
|
||||
|
||||
__ bind(done);
|
||||
}
|
||||
}
|
||||
|
||||
void ShenandoahBarrierSetAssembler::shenandoah_write_barrier_pre(MacroAssembler* masm,
|
||||
Register obj,
|
||||
Register pre_val,
|
||||
|
@ -76,8 +76,6 @@ public:
|
||||
|
||||
virtual void arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, bool is_oop,
|
||||
Register src, Register dst, Register count, RegSet saved_regs);
|
||||
virtual void arraycopy_epilogue(MacroAssembler* masm, DecoratorSet decorators, bool is_oop,
|
||||
Register start, Register count, Register tmp, RegSet saved_regs);
|
||||
virtual void load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
|
||||
Register dst, Address src, Register tmp1, Register tmp_thread);
|
||||
virtual void store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
|
||||
|
@ -47,35 +47,28 @@ address ShenandoahBarrierSetAssembler::_shenandoah_lrb = NULL;
|
||||
void ShenandoahBarrierSetAssembler::arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
|
||||
Register src, Register dst, Register count) {
|
||||
|
||||
bool checkcast = (decorators & ARRAYCOPY_CHECKCAST) != 0;
|
||||
bool disjoint = (decorators & ARRAYCOPY_DISJOINT) != 0;
|
||||
bool obj_int = type == T_OBJECT LP64_ONLY(&& UseCompressedOops);
|
||||
bool dest_uninitialized = (decorators & IS_DEST_UNINITIALIZED) != 0;
|
||||
|
||||
if (type == T_OBJECT || type == T_ARRAY) {
|
||||
#ifdef _LP64
|
||||
if (!checkcast) {
|
||||
if (!obj_int) {
|
||||
// Save count for barrier
|
||||
__ movptr(r11, count);
|
||||
} else if (disjoint) {
|
||||
// Save dst in r11 in the disjoint case
|
||||
__ movq(r11, dst);
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (disjoint) {
|
||||
__ mov(rdx, dst); // save 'to'
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ShenandoahSATBBarrier && !dest_uninitialized) {
|
||||
Register thread = NOT_LP64(rax) LP64_ONLY(r15_thread);
|
||||
assert_different_registers(dst, count, thread); // we don't care about src here?
|
||||
#ifndef _LP64
|
||||
if ((ShenandoahSATBBarrier && !dest_uninitialized) || ShenandoahLoadRefBarrier) {
|
||||
#ifdef _LP64
|
||||
Register thread = r15_thread;
|
||||
#else
|
||||
Register thread = rax;
|
||||
if (thread == src || thread == dst || thread == count) {
|
||||
thread = rbx;
|
||||
}
|
||||
if (thread == src || thread == dst || thread == count) {
|
||||
thread = rcx;
|
||||
}
|
||||
if (thread == src || thread == dst || thread == count) {
|
||||
thread = rdx;
|
||||
}
|
||||
__ push(thread);
|
||||
__ get_thread(thread);
|
||||
#endif
|
||||
assert_different_registers(src, dst, count, thread);
|
||||
|
||||
Label done;
|
||||
// Short-circuit if count == 0.
|
||||
@ -84,32 +77,33 @@ void ShenandoahBarrierSetAssembler::arraycopy_prologue(MacroAssembler* masm, Dec
|
||||
|
||||
// Avoid runtime call when not marking.
|
||||
Address gc_state(thread, in_bytes(ShenandoahThreadLocalData::gc_state_offset()));
|
||||
__ testb(gc_state, ShenandoahHeap::MARKING);
|
||||
int flags = ShenandoahHeap::HAS_FORWARDED;
|
||||
if (!dest_uninitialized) {
|
||||
flags |= ShenandoahHeap::MARKING;
|
||||
}
|
||||
__ testb(gc_state, flags);
|
||||
__ jcc(Assembler::zero, done);
|
||||
|
||||
__ pusha(); // push registers
|
||||
#ifdef _LP64
|
||||
if (count == c_rarg0) {
|
||||
if (dst == c_rarg1) {
|
||||
// exactly backwards!!
|
||||
__ xchgptr(c_rarg1, c_rarg0);
|
||||
} else {
|
||||
__ movptr(c_rarg1, count);
|
||||
__ movptr(c_rarg0, dst);
|
||||
}
|
||||
} else {
|
||||
__ movptr(c_rarg0, dst);
|
||||
__ movptr(c_rarg1, count);
|
||||
}
|
||||
assert(src == rdi, "expected");
|
||||
assert(dst == rsi, "expected");
|
||||
assert(count == rdx, "expected");
|
||||
if (UseCompressedOops) {
|
||||
__ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_array_pre_narrow_oop_entry), 2);
|
||||
} else {
|
||||
__ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_array_pre_oop_entry), 2);
|
||||
}
|
||||
#else
|
||||
__ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_array_pre_oop_entry),
|
||||
dst, count);
|
||||
if (dest_uninitialized) {
|
||||
__ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_array_pre_duinit_narrow_oop_entry), src, dst, count);
|
||||
} else {
|
||||
__ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_array_pre_narrow_oop_entry), src, dst, count);
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
if (dest_uninitialized) {
|
||||
__ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_array_pre_duinit_oop_entry), src, dst, count);
|
||||
} else {
|
||||
__ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_array_pre_oop_entry), src, dst, count);
|
||||
}
|
||||
}
|
||||
__ popa();
|
||||
__ bind(done);
|
||||
NOT_LP64(__ pop(thread);)
|
||||
@ -118,73 +112,6 @@ void ShenandoahBarrierSetAssembler::arraycopy_prologue(MacroAssembler* masm, Dec
|
||||
|
||||
}
|
||||
|
||||
void ShenandoahBarrierSetAssembler::arraycopy_epilogue(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
|
||||
Register src, Register dst, Register count) {
|
||||
bool checkcast = (decorators & ARRAYCOPY_CHECKCAST) != 0;
|
||||
bool disjoint = (decorators & ARRAYCOPY_DISJOINT) != 0;
|
||||
bool obj_int = type == T_OBJECT LP64_ONLY(&& UseCompressedOops);
|
||||
Register tmp = rax;
|
||||
|
||||
if (type == T_OBJECT || type == T_ARRAY) {
|
||||
#ifdef _LP64
|
||||
if (!checkcast) {
|
||||
if (!obj_int) {
|
||||
// Save count for barrier
|
||||
count = r11;
|
||||
} else if (disjoint && obj_int) {
|
||||
// Use the saved dst in the disjoint case
|
||||
dst = r11;
|
||||
}
|
||||
} else {
|
||||
tmp = rscratch1;
|
||||
}
|
||||
#else
|
||||
if (disjoint) {
|
||||
__ mov(dst, rdx); // restore 'to'
|
||||
}
|
||||
#endif
|
||||
|
||||
Register thread = NOT_LP64(rax) LP64_ONLY(r15_thread);
|
||||
assert_different_registers(dst, thread); // do we care about src at all here?
|
||||
|
||||
#ifndef _LP64
|
||||
__ push(thread);
|
||||
__ get_thread(thread);
|
||||
#endif
|
||||
|
||||
// Short-circuit if count == 0.
|
||||
Label done;
|
||||
__ testptr(count, count);
|
||||
__ jcc(Assembler::zero, done);
|
||||
|
||||
// Skip runtime call if no forwarded objects.
|
||||
Address gc_state(thread, in_bytes(ShenandoahThreadLocalData::gc_state_offset()));
|
||||
__ testb(gc_state, ShenandoahHeap::UPDATEREFS);
|
||||
__ jcc(Assembler::zero, done);
|
||||
|
||||
__ pusha(); // push registers (overkill)
|
||||
#ifdef _LP64
|
||||
if (c_rarg0 == count) { // On win64 c_rarg0 == rcx
|
||||
assert_different_registers(c_rarg1, dst);
|
||||
__ mov(c_rarg1, count);
|
||||
__ mov(c_rarg0, dst);
|
||||
} else {
|
||||
assert_different_registers(c_rarg0, count);
|
||||
__ mov(c_rarg0, dst);
|
||||
__ mov(c_rarg1, count);
|
||||
}
|
||||
__ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_array_post_entry), 2);
|
||||
#else
|
||||
__ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_array_post_entry),
|
||||
dst, count);
|
||||
#endif
|
||||
__ popa();
|
||||
|
||||
__ bind(done);
|
||||
NOT_LP64(__ pop(thread);)
|
||||
}
|
||||
}
|
||||
|
||||
void ShenandoahBarrierSetAssembler::shenandoah_write_barrier_pre(MacroAssembler* masm,
|
||||
Register obj,
|
||||
Register pre_val,
|
||||
|
@ -83,8 +83,6 @@ public:
|
||||
bool exchange, Register tmp1, Register tmp2);
|
||||
virtual void arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
|
||||
Register src, Register dst, Register count);
|
||||
virtual void arraycopy_epilogue(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
|
||||
Register src, Register dst, Register count);
|
||||
virtual void load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
|
||||
Register dst, Address src, Register tmp1, Register tmp_thread);
|
||||
virtual void store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
|
||||
|
@ -461,9 +461,11 @@ const TypeFunc* ShenandoahBarrierSetC2::write_ref_field_pre_entry_Type() {
|
||||
}
|
||||
|
||||
const TypeFunc* ShenandoahBarrierSetC2::shenandoah_clone_barrier_Type() {
|
||||
const Type **fields = TypeTuple::fields(1);
|
||||
fields[TypeFunc::Parms+0] = TypeInstPtr::NOTNULL; // original field value
|
||||
const TypeTuple *domain = TypeTuple::make(TypeFunc::Parms+1, fields);
|
||||
const Type **fields = TypeTuple::fields(3);
|
||||
fields[TypeFunc::Parms+0] = TypeInstPtr::NOTNULL; // src
|
||||
fields[TypeFunc::Parms+1] = TypeInstPtr::NOTNULL; // dst
|
||||
fields[TypeFunc::Parms+2] = TypeInt::INT; // length
|
||||
const TypeTuple *domain = TypeTuple::make(TypeFunc::Parms+3, fields);
|
||||
|
||||
// create result type (range)
|
||||
fields = TypeTuple::fields(0);
|
||||
@ -705,11 +707,6 @@ Node* ShenandoahBarrierSetC2::atomic_xchg_at_resolved(C2AtomicParseAccess& acces
|
||||
return result;
|
||||
}
|
||||
|
||||
void ShenandoahBarrierSetC2::clone(GraphKit* kit, Node* src, Node* dst, Node* size, bool is_array) const {
|
||||
assert(!src->is_AddP(), "unexpected input");
|
||||
BarrierSetC2::clone(kit, src, dst, size, is_array);
|
||||
}
|
||||
|
||||
// Support for GC barriers emitted during parsing
|
||||
bool ShenandoahBarrierSetC2::is_gc_barrier_node(Node* node) const {
|
||||
if (node->Opcode() == Op_ShenandoahLoadReferenceBarrier) return true;
|
||||
@ -771,9 +768,8 @@ bool ShenandoahBarrierSetC2::array_copy_requires_gc_barriers(bool tightly_couple
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ShenandoahBarrierSetC2::clone_needs_postbarrier(ArrayCopyNode *ac, PhaseIterGVN& igvn) {
|
||||
Node* src = ac->in(ArrayCopyNode::Src);
|
||||
const TypeOopPtr* src_type = igvn.type(src)->is_oopptr();
|
||||
bool ShenandoahBarrierSetC2::clone_needs_barrier(Node* src, PhaseGVN& gvn) {
|
||||
const TypeOopPtr* src_type = gvn.type(src)->is_oopptr();
|
||||
if (src_type->isa_instptr() != NULL) {
|
||||
ciInstanceKlass* ik = src_type->klass()->as_instance_klass();
|
||||
if ((src_type->klass_is_exact() || (!ik->is_interface() && !ik->has_subklass())) && !ik->has_injected_fields()) {
|
||||
@ -781,7 +777,7 @@ bool ShenandoahBarrierSetC2::clone_needs_postbarrier(ArrayCopyNode *ac, PhaseIte
|
||||
return true;
|
||||
} else {
|
||||
if (!src_type->klass_is_exact()) {
|
||||
igvn.C->dependencies()->assert_leaf_type(ik);
|
||||
Compile::current()->dependencies()->assert_leaf_type(ik);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -798,42 +794,29 @@ bool ShenandoahBarrierSetC2::clone_needs_postbarrier(ArrayCopyNode *ac, PhaseIte
|
||||
return false;
|
||||
}
|
||||
|
||||
void ShenandoahBarrierSetC2::clone_barrier_at_expansion(ArrayCopyNode* ac, Node* call, PhaseIterGVN& igvn) const {
|
||||
assert(ac->is_clonebasic(), "no other kind of arraycopy here");
|
||||
|
||||
if (!clone_needs_postbarrier(ac, igvn)) {
|
||||
BarrierSetC2::clone_barrier_at_expansion(ac, call, igvn);
|
||||
return;
|
||||
}
|
||||
|
||||
const TypePtr* raw_adr_type = TypeRawPtr::BOTTOM;
|
||||
Node* c = new ProjNode(call,TypeFunc::Control);
|
||||
c = igvn.transform(c);
|
||||
Node* m = new ProjNode(call, TypeFunc::Memory);
|
||||
m = igvn.transform(m);
|
||||
#define XTOP LP64_ONLY(COMMA phase->top())
|
||||
|
||||
void ShenandoahBarrierSetC2::clone_at_expansion(PhaseMacroExpand* phase, ArrayCopyNode* ac) const {
|
||||
Node* ctrl = ac->in(TypeFunc::Control);
|
||||
Node* mem = ac->in(TypeFunc::Memory);
|
||||
Node* src = ac->in(ArrayCopyNode::Src);
|
||||
Node* src_offset = ac->in(ArrayCopyNode::SrcPos);
|
||||
Node* dest = ac->in(ArrayCopyNode::Dest);
|
||||
assert(dest->is_AddP(), "bad input");
|
||||
Node* barrier_call = new CallLeafNode(ShenandoahBarrierSetC2::shenandoah_clone_barrier_Type(),
|
||||
CAST_FROM_FN_PTR(address, ShenandoahRuntime::shenandoah_clone_barrier),
|
||||
"shenandoah_clone_barrier", raw_adr_type);
|
||||
barrier_call->init_req(TypeFunc::Control, c);
|
||||
barrier_call->init_req(TypeFunc::I_O , igvn.C->top());
|
||||
barrier_call->init_req(TypeFunc::Memory , m);
|
||||
barrier_call->init_req(TypeFunc::ReturnAdr, igvn.C->top());
|
||||
barrier_call->init_req(TypeFunc::FramePtr, igvn.C->top());
|
||||
barrier_call->init_req(TypeFunc::Parms+0, dest->in(AddPNode::Base));
|
||||
|
||||
barrier_call = igvn.transform(barrier_call);
|
||||
c = new ProjNode(barrier_call,TypeFunc::Control);
|
||||
c = igvn.transform(c);
|
||||
m = new ProjNode(barrier_call, TypeFunc::Memory);
|
||||
m = igvn.transform(m);
|
||||
|
||||
Node* out_c = ac->proj_out(TypeFunc::Control);
|
||||
Node* out_m = ac->proj_out(TypeFunc::Memory);
|
||||
igvn.replace_node(out_c, c);
|
||||
igvn.replace_node(out_m, m);
|
||||
Node* dest_offset = ac->in(ArrayCopyNode::DestPos);
|
||||
Node* length = ac->in(ArrayCopyNode::Length);
|
||||
assert (src_offset == NULL && dest_offset == NULL, "for clone offsets should be null");
|
||||
if (ShenandoahCloneBarrier && clone_needs_barrier(src, phase->igvn())) {
|
||||
Node* call = phase->make_leaf_call(ctrl, mem,
|
||||
ShenandoahBarrierSetC2::shenandoah_clone_barrier_Type(),
|
||||
CAST_FROM_FN_PTR(address, ShenandoahRuntime::shenandoah_clone_barrier),
|
||||
"shenandoah_clone",
|
||||
TypeRawPtr::BOTTOM,
|
||||
src, dest, length);
|
||||
call = phase->transform_later(call);
|
||||
phase->igvn().replace_node(ac, call);
|
||||
} else {
|
||||
BarrierSetC2::clone_at_expansion(phase, ac);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -78,7 +78,7 @@ private:
|
||||
void insert_pre_barrier(GraphKit* kit, Node* base_oop, Node* offset,
|
||||
Node* pre_val, bool need_mem_bar) const;
|
||||
|
||||
static bool clone_needs_postbarrier(ArrayCopyNode *ac, PhaseIterGVN& igvn);
|
||||
static bool clone_needs_barrier(Node* src, PhaseGVN& gvn);
|
||||
|
||||
protected:
|
||||
virtual Node* load_at_resolved(C2Access& access, const Type* val_type) const;
|
||||
@ -106,11 +106,10 @@ public:
|
||||
virtual bool has_load_barriers() const { return true; }
|
||||
|
||||
// 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 void clone_at_expansion(PhaseMacroExpand* phase, ArrayCopyNode* ac) 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;
|
||||
|
||||
// Support for GC barriers emitted during parsing
|
||||
virtual bool is_gc_barrier_node(Node* node) const;
|
||||
|
@ -41,33 +41,6 @@
|
||||
class ShenandoahBarrierSetC1;
|
||||
class ShenandoahBarrierSetC2;
|
||||
|
||||
template <bool STOREVAL_EVAC_BARRIER>
|
||||
class ShenandoahUpdateRefsForOopClosure: public BasicOopIterateClosure {
|
||||
private:
|
||||
ShenandoahHeap* _heap;
|
||||
ShenandoahBarrierSet* _bs;
|
||||
|
||||
template <class T>
|
||||
inline void do_oop_work(T* p) {
|
||||
oop o;
|
||||
if (STOREVAL_EVAC_BARRIER) {
|
||||
o = _heap->evac_update_with_forwarded(p);
|
||||
if (!CompressedOops::is_null(o)) {
|
||||
_bs->enqueue(o);
|
||||
}
|
||||
} else {
|
||||
_heap->maybe_update_with_forwarded(p);
|
||||
}
|
||||
}
|
||||
public:
|
||||
ShenandoahUpdateRefsForOopClosure() : _heap(ShenandoahHeap::heap()), _bs(ShenandoahBarrierSet::barrier_set()) {
|
||||
assert(UseShenandoahGC && ShenandoahCloneBarrier, "should be enabled");
|
||||
}
|
||||
|
||||
virtual void do_oop(oop* p) { do_oop_work(p); }
|
||||
virtual void do_oop(narrowOop* p) { do_oop_work(p); }
|
||||
};
|
||||
|
||||
ShenandoahBarrierSet::ShenandoahBarrierSet(ShenandoahHeap* heap) :
|
||||
BarrierSet(make_barrier_set_assembler<ShenandoahBarrierSetAssembler>(),
|
||||
make_barrier_set_c1<ShenandoahBarrierSetC1>(),
|
||||
@ -97,73 +70,6 @@ bool ShenandoahBarrierSet::is_aligned(HeapWord* hw) {
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class T, bool STOREVAL_EVAC_BARRIER>
|
||||
void ShenandoahBarrierSet::write_ref_array_loop(HeapWord* start, size_t count) {
|
||||
assert(UseShenandoahGC && ShenandoahCloneBarrier, "should be enabled");
|
||||
ShenandoahUpdateRefsForOopClosure<STOREVAL_EVAC_BARRIER> cl;
|
||||
T* dst = (T*) start;
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
cl.do_oop(dst++);
|
||||
}
|
||||
}
|
||||
|
||||
void ShenandoahBarrierSet::write_ref_array(HeapWord* start, size_t count) {
|
||||
assert(_heap->is_update_refs_in_progress(), "should not be here otherwise");
|
||||
assert(count > 0, "Should have been filtered before");
|
||||
|
||||
if (_heap->is_concurrent_traversal_in_progress()) {
|
||||
ShenandoahEvacOOMScope oom_evac_scope;
|
||||
if (UseCompressedOops) {
|
||||
write_ref_array_loop<narrowOop, /* evac = */ true>(start, count);
|
||||
} else {
|
||||
write_ref_array_loop<oop, /* evac = */ true>(start, count);
|
||||
}
|
||||
} else {
|
||||
if (UseCompressedOops) {
|
||||
write_ref_array_loop<narrowOop, /* evac = */ false>(start, count);
|
||||
} else {
|
||||
write_ref_array_loop<oop, /* evac = */ false>(start, count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void ShenandoahBarrierSet::write_ref_array_pre_work(T* dst, size_t count) {
|
||||
shenandoah_assert_not_in_cset_loc_except(dst, _heap->cancelled_gc());
|
||||
assert(ShenandoahThreadLocalData::satb_mark_queue(Thread::current()).is_active(), "Shouldn't be here otherwise");
|
||||
assert(ShenandoahSATBBarrier, "Shouldn't be here otherwise");
|
||||
assert(count > 0, "Should have been filtered before");
|
||||
|
||||
Thread* thread = Thread::current();
|
||||
ShenandoahMarkingContext* ctx = _heap->marking_context();
|
||||
bool has_forwarded = _heap->has_forwarded_objects();
|
||||
T* elem_ptr = dst;
|
||||
for (size_t i = 0; i < count; i++, elem_ptr++) {
|
||||
T heap_oop = RawAccess<>::oop_load(elem_ptr);
|
||||
if (!CompressedOops::is_null(heap_oop)) {
|
||||
oop obj = CompressedOops::decode_not_null(heap_oop);
|
||||
if (has_forwarded) {
|
||||
obj = resolve_forwarded_not_null(obj);
|
||||
}
|
||||
if (!ctx->is_marked(obj)) {
|
||||
ShenandoahThreadLocalData::satb_mark_queue(thread).enqueue_known_active(obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ShenandoahBarrierSet::write_ref_array_pre(oop* dst, size_t count, bool dest_uninitialized) {
|
||||
if (! dest_uninitialized) {
|
||||
write_ref_array_pre_work(dst, count);
|
||||
}
|
||||
}
|
||||
|
||||
void ShenandoahBarrierSet::write_ref_array_pre(narrowOop* dst, size_t count, bool dest_uninitialized) {
|
||||
if (! dest_uninitialized) {
|
||||
write_ref_array_pre_work(dst, count);
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline void ShenandoahBarrierSet::inline_write_ref_field_pre(T* field, oop new_val) {
|
||||
shenandoah_assert_not_in_cset_loc_except(field, _heap->cancelled_gc());
|
||||
@ -194,27 +100,6 @@ void ShenandoahBarrierSet::write_ref_field_work(void* v, oop o, bool release) {
|
||||
shenandoah_assert_not_in_cset_except (v, o, o == NULL || _heap->cancelled_gc() || !_heap->is_concurrent_mark_in_progress());
|
||||
}
|
||||
|
||||
void ShenandoahBarrierSet::write_region(MemRegion mr) {
|
||||
if (!ShenandoahCloneBarrier) return;
|
||||
if (!_heap->is_update_refs_in_progress()) return;
|
||||
|
||||
// This is called for cloning an object (see jvm.cpp) after the clone
|
||||
// has been made. We are not interested in any 'previous value' because
|
||||
// it would be NULL in any case. But we *are* interested in any oop*
|
||||
// that potentially need to be updated.
|
||||
|
||||
oop obj = oop(mr.start());
|
||||
shenandoah_assert_correct(NULL, obj);
|
||||
if (_heap->is_concurrent_traversal_in_progress()) {
|
||||
ShenandoahEvacOOMScope oom_evac_scope;
|
||||
ShenandoahUpdateRefsForOopClosure</* evac = */ true> cl;
|
||||
obj->oop_iterate(&cl);
|
||||
} else {
|
||||
ShenandoahUpdateRefsForOopClosure</* evac = */ false> cl;
|
||||
obj->oop_iterate(&cl);
|
||||
}
|
||||
}
|
||||
|
||||
oop ShenandoahBarrierSet::load_reference_barrier_not_null(oop obj) {
|
||||
if (ShenandoahLoadRefBarrier && _heap->has_forwarded_objects()) {
|
||||
return load_reference_barrier_impl(obj);
|
||||
|
@ -63,14 +63,14 @@ public:
|
||||
|
||||
bool is_aligned(HeapWord* hw);
|
||||
|
||||
void write_ref_array(HeapWord* start, size_t count);
|
||||
|
||||
template <class T> void
|
||||
write_ref_array_pre_work(T* dst, size_t count);
|
||||
write_ref_array_pre_work(T* src, T* dst, size_t count, bool dest_uninitialized);
|
||||
|
||||
void write_ref_array_pre(oop* dst, size_t count, bool dest_uninitialized);
|
||||
|
||||
void write_ref_array_pre(narrowOop* dst, size_t count, bool dest_uninitialized);
|
||||
inline void arraycopy_pre(oop* src, oop* dst, size_t count);
|
||||
inline void arraycopy_pre(narrowOop* src, narrowOop* dst, size_t count);
|
||||
inline void arraycopy_update(oop* src, size_t count);
|
||||
inline void arraycopy_update(narrowOop* src, size_t count);
|
||||
inline void clone_barrier(oop src);
|
||||
|
||||
// We export this to make it available in cases where the static
|
||||
// type of the barrier set is known. Note that it is non-virtual.
|
||||
@ -82,7 +82,6 @@ public:
|
||||
void write_ref_field_pre_work(void* field, oop new_val);
|
||||
|
||||
void write_ref_field_work(void* v, oop o, bool release = false);
|
||||
void write_region(MemRegion mr);
|
||||
|
||||
oop oop_load_from_native_barrier(oop obj);
|
||||
|
||||
@ -104,8 +103,12 @@ public:
|
||||
void enqueue(oop obj);
|
||||
|
||||
private:
|
||||
template <class T, bool STOREVAL_WRITE_BARRIER>
|
||||
void write_ref_array_loop(HeapWord* start, size_t count);
|
||||
template <class T>
|
||||
inline void arraycopy_pre_work(T* src, T* dst, size_t count);
|
||||
template <class T, bool HAS_FWD, bool EVAC, bool ENQUEUE>
|
||||
inline void arraycopy_work(T* src, size_t count);
|
||||
template <class T>
|
||||
inline void arraycopy_update_impl(T* src, size_t count);
|
||||
|
||||
oop load_reference_barrier_impl(oop obj);
|
||||
|
||||
@ -118,24 +121,6 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool arraycopy_loop_1(T* src, T* dst, size_t length, Klass* bound,
|
||||
bool checkcast, bool satb, bool disjoint, ShenandoahBarrierSet::ArrayCopyStoreValMode storeval_mode);
|
||||
|
||||
template <typename T, bool CHECKCAST>
|
||||
bool arraycopy_loop_2(T* src, T* dst, size_t length, Klass* bound,
|
||||
bool satb, bool disjoint, ShenandoahBarrierSet::ArrayCopyStoreValMode storeval_mode);
|
||||
|
||||
template <typename T, bool CHECKCAST, bool SATB>
|
||||
bool arraycopy_loop_3(T* src, T* dst, size_t length, Klass* bound,
|
||||
bool disjoint, ShenandoahBarrierSet::ArrayCopyStoreValMode storeval_mode);
|
||||
|
||||
template <typename T, bool CHECKCAST, bool SATB, ShenandoahBarrierSet::ArrayCopyStoreValMode STOREVAL_MODE>
|
||||
bool arraycopy_loop(T* src, T* dst, size_t length, Klass* bound, bool disjoint);
|
||||
|
||||
template <typename T, bool CHECKCAST, bool SATB, ShenandoahBarrierSet::ArrayCopyStoreValMode STOREVAL_MODE>
|
||||
bool arraycopy_element(T* cur_src, T* cur_dst, Klass* bound, Thread* const thread, ShenandoahMarkingContext* const ctx);
|
||||
|
||||
public:
|
||||
// Callbacks for runtime accesses.
|
||||
template <DecoratorSet decorators, typename BarrierSetT = ShenandoahBarrierSet>
|
||||
|
@ -27,11 +27,14 @@
|
||||
#include "gc/shared/barrierSet.hpp"
|
||||
#include "gc/shenandoah/shenandoahAsserts.hpp"
|
||||
#include "gc/shenandoah/shenandoahBarrierSet.hpp"
|
||||
#include "gc/shenandoah/shenandoahCollectionSet.inline.hpp"
|
||||
#include "gc/shenandoah/shenandoahForwarding.inline.hpp"
|
||||
#include "gc/shenandoah/shenandoahHeap.inline.hpp"
|
||||
#include "gc/shenandoah/shenandoahHeapRegion.hpp"
|
||||
#include "gc/shenandoah/shenandoahMarkingContext.inline.hpp"
|
||||
#include "gc/shenandoah/shenandoahThreadLocalData.hpp"
|
||||
#include "memory/iterator.inline.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
|
||||
inline oop ShenandoahBarrierSet::resolve_forwarded_not_null(oop p) {
|
||||
return ShenandoahForwarding::get_forwardee(p);
|
||||
@ -179,158 +182,13 @@ inline oop ShenandoahBarrierSet::AccessBarrier<decorators, BarrierSetT>::oop_ato
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool ShenandoahBarrierSet::arraycopy_loop_1(T* src, T* dst, size_t length, Klass* bound,
|
||||
bool checkcast, bool satb, bool disjoint,
|
||||
ShenandoahBarrierSet::ArrayCopyStoreValMode storeval_mode) {
|
||||
if (checkcast) {
|
||||
return arraycopy_loop_2<T, true>(src, dst, length, bound, satb, disjoint, storeval_mode);
|
||||
} else {
|
||||
return arraycopy_loop_2<T, false>(src, dst, length, bound, satb, disjoint, storeval_mode);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, bool CHECKCAST>
|
||||
bool ShenandoahBarrierSet::arraycopy_loop_2(T* src, T* dst, size_t length, Klass* bound,
|
||||
bool satb, bool disjoint,
|
||||
ShenandoahBarrierSet::ArrayCopyStoreValMode storeval_mode) {
|
||||
if (satb) {
|
||||
return arraycopy_loop_3<T, CHECKCAST, true>(src, dst, length, bound, disjoint, storeval_mode);
|
||||
} else {
|
||||
return arraycopy_loop_3<T, CHECKCAST, false>(src, dst, length, bound, disjoint, storeval_mode);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, bool CHECKCAST, bool SATB>
|
||||
bool ShenandoahBarrierSet::arraycopy_loop_3(T* src, T* dst, size_t length, Klass* bound, bool disjoint,
|
||||
ShenandoahBarrierSet::ArrayCopyStoreValMode storeval_mode) {
|
||||
switch (storeval_mode) {
|
||||
case NONE:
|
||||
return arraycopy_loop<T, CHECKCAST, SATB, NONE>(src, dst, length, bound, disjoint);
|
||||
case RESOLVE_BARRIER:
|
||||
return arraycopy_loop<T, CHECKCAST, SATB, RESOLVE_BARRIER>(src, dst, length, bound, disjoint);
|
||||
case EVAC_BARRIER:
|
||||
return arraycopy_loop<T, CHECKCAST, SATB, EVAC_BARRIER>(src, dst, length, bound, disjoint);
|
||||
default:
|
||||
ShouldNotReachHere();
|
||||
return true; // happy compiler
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, bool CHECKCAST, bool SATB, ShenandoahBarrierSet::ArrayCopyStoreValMode STOREVAL_MODE>
|
||||
bool ShenandoahBarrierSet::arraycopy_loop(T* src, T* dst, size_t length, Klass* bound, bool disjoint) {
|
||||
Thread* thread = Thread::current();
|
||||
ShenandoahMarkingContext* ctx = _heap->marking_context();
|
||||
ShenandoahEvacOOMScope oom_evac_scope;
|
||||
|
||||
// We need to handle four cases:
|
||||
//
|
||||
// a) src < dst, conjoint, can only copy backward only
|
||||
// [...src...]
|
||||
// [...dst...]
|
||||
//
|
||||
// b) src < dst, disjoint, can only copy forward, because types may mismatch
|
||||
// [...src...]
|
||||
// [...dst...]
|
||||
//
|
||||
// c) src > dst, conjoint, can copy forward only
|
||||
// [...src...]
|
||||
// [...dst...]
|
||||
//
|
||||
// d) src > dst, disjoint, can only copy forward, because types may mismatch
|
||||
// [...src...]
|
||||
// [...dst...]
|
||||
//
|
||||
if (src > dst || disjoint) {
|
||||
// copy forward:
|
||||
T* cur_src = src;
|
||||
T* cur_dst = dst;
|
||||
T* src_end = src + length;
|
||||
for (; cur_src < src_end; cur_src++, cur_dst++) {
|
||||
if (!arraycopy_element<T, CHECKCAST, SATB, STOREVAL_MODE>(cur_src, cur_dst, bound, thread, ctx)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// copy backward:
|
||||
T* cur_src = src + length - 1;
|
||||
T* cur_dst = dst + length - 1;
|
||||
for (; cur_src >= src; cur_src--, cur_dst--) {
|
||||
if (!arraycopy_element<T, CHECKCAST, SATB, STOREVAL_MODE>(cur_src, cur_dst, bound, thread, ctx)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T, bool CHECKCAST, bool SATB, ShenandoahBarrierSet::ArrayCopyStoreValMode STOREVAL_MODE>
|
||||
bool ShenandoahBarrierSet::arraycopy_element(T* cur_src, T* cur_dst, Klass* bound, Thread* const thread, ShenandoahMarkingContext* const ctx) {
|
||||
T o = RawAccess<>::oop_load(cur_src);
|
||||
|
||||
if (SATB) {
|
||||
assert(ShenandoahThreadLocalData::satb_mark_queue(thread).is_active(), "Shouldn't be here otherwise");
|
||||
T prev = RawAccess<>::oop_load(cur_dst);
|
||||
if (!CompressedOops::is_null(prev)) {
|
||||
oop prev_obj = CompressedOops::decode_not_null(prev);
|
||||
switch (STOREVAL_MODE) {
|
||||
case NONE:
|
||||
break;
|
||||
case RESOLVE_BARRIER:
|
||||
case EVAC_BARRIER:
|
||||
// The evac-barrier case cannot really happen. It's traversal-only and traversal
|
||||
// doesn't currently use SATB. And even if it did, it would not be fatal to just do the normal resolve here.
|
||||
prev_obj = ShenandoahBarrierSet::resolve_forwarded_not_null(prev_obj);
|
||||
}
|
||||
if (!ctx->is_marked(prev_obj)) {
|
||||
ShenandoahThreadLocalData::satb_mark_queue(thread).enqueue_known_active(prev_obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!CompressedOops::is_null(o)) {
|
||||
oop obj = CompressedOops::decode_not_null(o);
|
||||
|
||||
if (CHECKCAST) {
|
||||
assert(bound != NULL, "need element klass for checkcast");
|
||||
if (!oopDesc::is_instanceof_or_null(obj, bound)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
switch (STOREVAL_MODE) {
|
||||
case NONE:
|
||||
break;
|
||||
case RESOLVE_BARRIER:
|
||||
obj = ShenandoahBarrierSet::resolve_forwarded_not_null(obj);
|
||||
break;
|
||||
case EVAC_BARRIER:
|
||||
if (_heap->in_collection_set(obj)) {
|
||||
oop forw = ShenandoahBarrierSet::resolve_forwarded_not_null(obj);
|
||||
if (forw == obj) {
|
||||
forw = _heap->evacuate_object(forw, thread);
|
||||
}
|
||||
obj = forw;
|
||||
}
|
||||
enqueue(obj);
|
||||
break;
|
||||
default:
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
|
||||
RawAccess<IS_NOT_NULL>::oop_store(cur_dst, obj);
|
||||
} else {
|
||||
// Store null.
|
||||
RawAccess<>::oop_store(cur_dst, o);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Clone barrier support
|
||||
template <DecoratorSet decorators, typename BarrierSetT>
|
||||
void ShenandoahBarrierSet::AccessBarrier<decorators, BarrierSetT>::clone_in_heap(oop src, oop dst, size_t size) {
|
||||
if (ShenandoahCloneBarrier) {
|
||||
ShenandoahBarrierSet::barrier_set()->clone_barrier(src);
|
||||
}
|
||||
Raw::clone(src, dst, size);
|
||||
ShenandoahBarrierSet::barrier_set()->write_region(MemRegion((HeapWord*) dst, size));
|
||||
}
|
||||
|
||||
template <DecoratorSet decorators, typename BarrierSetT>
|
||||
@ -338,36 +196,144 @@ template <typename T>
|
||||
bool ShenandoahBarrierSet::AccessBarrier<decorators, BarrierSetT>::oop_arraycopy_in_heap(arrayOop src_obj, size_t src_offset_in_bytes, T* src_raw,
|
||||
arrayOop dst_obj, size_t dst_offset_in_bytes, T* dst_raw,
|
||||
size_t length) {
|
||||
ShenandoahHeap* heap = ShenandoahHeap::heap();
|
||||
bool satb = ShenandoahSATBBarrier && heap->is_concurrent_mark_in_progress();
|
||||
bool checkcast = HasDecorator<decorators, ARRAYCOPY_CHECKCAST>::value;
|
||||
bool disjoint = HasDecorator<decorators, ARRAYCOPY_DISJOINT>::value;
|
||||
ArrayCopyStoreValMode storeval_mode;
|
||||
if (heap->has_forwarded_objects()) {
|
||||
if (heap->is_concurrent_traversal_in_progress()) {
|
||||
storeval_mode = EVAC_BARRIER;
|
||||
} else if (heap->is_update_refs_in_progress()) {
|
||||
storeval_mode = RESOLVE_BARRIER;
|
||||
} else {
|
||||
assert(heap->is_idle() || heap->is_evacuation_in_progress(), "must not have anything in progress");
|
||||
storeval_mode = NONE; // E.g. during evac or outside cycle
|
||||
}
|
||||
} else {
|
||||
assert(heap->is_stable() || heap->is_concurrent_mark_in_progress(), "must not have anything in progress");
|
||||
storeval_mode = NONE;
|
||||
}
|
||||
|
||||
if (!satb && !checkcast && storeval_mode == NONE) {
|
||||
// Short-circuit to bulk copy.
|
||||
return Raw::oop_arraycopy(src_obj, src_offset_in_bytes, src_raw, dst_obj, dst_offset_in_bytes, dst_raw, length);
|
||||
}
|
||||
|
||||
src_raw = arrayOopDesc::obj_offset_to_raw(src_obj, src_offset_in_bytes, src_raw);
|
||||
dst_raw = arrayOopDesc::obj_offset_to_raw(dst_obj, dst_offset_in_bytes, dst_raw);
|
||||
|
||||
Klass* bound = objArrayOop(dst_obj)->element_klass();
|
||||
ShenandoahBarrierSet* bs = ShenandoahBarrierSet::barrier_set();
|
||||
return bs->arraycopy_loop_1(src_raw, dst_raw, length, bound, checkcast, satb, disjoint, storeval_mode);
|
||||
bs->arraycopy_pre(arrayOopDesc::obj_offset_to_raw(src_obj, src_offset_in_bytes, src_raw),
|
||||
arrayOopDesc::obj_offset_to_raw(dst_obj, dst_offset_in_bytes, dst_raw),
|
||||
length);
|
||||
return Raw::oop_arraycopy_in_heap(src_obj, src_offset_in_bytes, src_raw, dst_obj, dst_offset_in_bytes, dst_raw, length);
|
||||
}
|
||||
|
||||
template <class T, bool HAS_FWD, bool EVAC, bool ENQUEUE>
|
||||
void ShenandoahBarrierSet::arraycopy_work(T* src, size_t count) {
|
||||
Thread* thread = Thread::current();
|
||||
SATBMarkQueue& queue = ShenandoahThreadLocalData::satb_mark_queue(thread);
|
||||
ShenandoahMarkingContext* ctx = _heap->marking_context();
|
||||
const ShenandoahCollectionSet* const cset = _heap->collection_set();
|
||||
T* end = src + count;
|
||||
for (T* elem_ptr = src; elem_ptr < end; elem_ptr++) {
|
||||
T o = RawAccess<>::oop_load(elem_ptr);
|
||||
if (!CompressedOops::is_null(o)) {
|
||||
oop obj = CompressedOops::decode_not_null(o);
|
||||
if (HAS_FWD && cset->is_in((HeapWord *) obj)) {
|
||||
assert(_heap->has_forwarded_objects(), "only get here with forwarded objects");
|
||||
oop fwd = resolve_forwarded_not_null(obj);
|
||||
if (EVAC && obj == fwd) {
|
||||
fwd = _heap->evacuate_object(obj, thread);
|
||||
}
|
||||
assert(obj != fwd || _heap->cancelled_gc(), "must be forwarded");
|
||||
oop witness = ShenandoahHeap::cas_oop(fwd, elem_ptr, o);
|
||||
obj = fwd;
|
||||
}
|
||||
if (ENQUEUE && !ctx->is_marked(obj)) {
|
||||
queue.enqueue_known_active(obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void ShenandoahBarrierSet::arraycopy_pre_work(T* src, T* dst, size_t count) {
|
||||
if (_heap->is_concurrent_mark_in_progress()) {
|
||||
if (_heap->has_forwarded_objects()) {
|
||||
arraycopy_work<T, true, false, true>(dst, count);
|
||||
} else {
|
||||
arraycopy_work<T, false, false, true>(dst, count);
|
||||
}
|
||||
}
|
||||
|
||||
arraycopy_update_impl(src, count);
|
||||
}
|
||||
|
||||
void ShenandoahBarrierSet::arraycopy_pre(oop* src, oop* dst, size_t count) {
|
||||
arraycopy_pre_work(src, dst, count);
|
||||
}
|
||||
|
||||
void ShenandoahBarrierSet::arraycopy_pre(narrowOop* src, narrowOop* dst, size_t count) {
|
||||
arraycopy_pre_work(src, dst, count);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void ShenandoahBarrierSet::arraycopy_update_impl(T* src, size_t count) {
|
||||
if (_heap->is_evacuation_in_progress()) {
|
||||
ShenandoahEvacOOMScope oom_evac;
|
||||
arraycopy_work<T, true, true, false>(src, count);
|
||||
} else if (_heap->is_concurrent_traversal_in_progress()){
|
||||
ShenandoahEvacOOMScope oom_evac;
|
||||
arraycopy_work<T, true, true, true>(src, count);
|
||||
} else if (_heap->has_forwarded_objects()) {
|
||||
arraycopy_work<T, true, false, false>(src, count);
|
||||
}
|
||||
}
|
||||
|
||||
void ShenandoahBarrierSet::arraycopy_update(oop* src, size_t count) {
|
||||
arraycopy_update_impl(src, count);
|
||||
}
|
||||
|
||||
void ShenandoahBarrierSet::arraycopy_update(narrowOop* src, size_t count) {
|
||||
arraycopy_update_impl(src, count);
|
||||
}
|
||||
|
||||
template <bool EVAC, bool ENQUEUE>
|
||||
class ShenandoahUpdateRefsForOopClosure: public BasicOopIterateClosure {
|
||||
private:
|
||||
ShenandoahHeap* const _heap;
|
||||
ShenandoahBarrierSet* const _bs;
|
||||
const ShenandoahCollectionSet* const _cset;
|
||||
Thread* const _thread;
|
||||
|
||||
template <class T>
|
||||
inline void do_oop_work(T* p) {
|
||||
T o = RawAccess<>::oop_load(p);
|
||||
if (!CompressedOops::is_null(o)) {
|
||||
oop obj = CompressedOops::decode_not_null(o);
|
||||
if (_cset->is_in((HeapWord *)obj)) {
|
||||
oop fwd = _bs->resolve_forwarded_not_null(obj);
|
||||
if (EVAC && obj == fwd) {
|
||||
fwd = _heap->evacuate_object(obj, _thread);
|
||||
}
|
||||
if (ENQUEUE) {
|
||||
_bs->enqueue(fwd);
|
||||
}
|
||||
assert(obj != fwd || _heap->cancelled_gc(), "must be forwarded");
|
||||
ShenandoahHeap::cas_oop(fwd, p, o);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
public:
|
||||
ShenandoahUpdateRefsForOopClosure() :
|
||||
_heap(ShenandoahHeap::heap()),
|
||||
_bs(ShenandoahBarrierSet::barrier_set()),
|
||||
_cset(_heap->collection_set()),
|
||||
_thread(Thread::current()) {
|
||||
}
|
||||
|
||||
virtual void do_oop(oop* p) { do_oop_work(p); }
|
||||
virtual void do_oop(narrowOop* p) { do_oop_work(p); }
|
||||
};
|
||||
|
||||
void ShenandoahBarrierSet::clone_barrier(oop obj) {
|
||||
assert(ShenandoahCloneBarrier, "only get here with clone barriers enabled");
|
||||
if (!_heap->has_forwarded_objects()) return;
|
||||
|
||||
// This is called for cloning an object (see jvm.cpp) after the clone
|
||||
// has been made. We are not interested in any 'previous value' because
|
||||
// it would be NULL in any case. But we *are* interested in any oop*
|
||||
// that potentially need to be updated.
|
||||
|
||||
shenandoah_assert_correct(NULL, obj);
|
||||
if (_heap->is_evacuation_in_progress()) {
|
||||
ShenandoahEvacOOMScope evac_scope;
|
||||
ShenandoahUpdateRefsForOopClosure</* evac = */ true, /* enqueue */ false> cl;
|
||||
obj->oop_iterate(&cl);
|
||||
} else if (_heap->is_concurrent_traversal_in_progress()) {
|
||||
ShenandoahEvacOOMScope evac_scope;
|
||||
ShenandoahUpdateRefsForOopClosure</* evac = */ true, /* enqueue */ true> cl;
|
||||
obj->oop_iterate(&cl);
|
||||
} else {
|
||||
ShenandoahUpdateRefsForOopClosure</* evac = */ false, /* enqueue */ false> cl;
|
||||
obj->oop_iterate(&cl);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // SHARE_GC_SHENANDOAH_SHENANDOAHBARRIERSET_INLINE_HPP
|
||||
|
@ -707,6 +707,7 @@ public:
|
||||
|
||||
static inline oop cas_oop(oop n, narrowOop* addr, oop c);
|
||||
static inline oop cas_oop(oop n, oop* addr, oop c);
|
||||
static inline oop cas_oop(oop n, narrowOop* addr, narrowOop c);
|
||||
|
||||
void trash_humongous_region_at(ShenandoahHeapRegion *r);
|
||||
|
||||
|
@ -133,6 +133,11 @@ inline oop ShenandoahHeap::cas_oop(oop n, oop* addr, oop c) {
|
||||
return (oop) Atomic::cmpxchg(n, addr, c);
|
||||
}
|
||||
|
||||
inline oop ShenandoahHeap::cas_oop(oop n, narrowOop* addr, narrowOop c) {
|
||||
narrowOop val = CompressedOops::encode(n);
|
||||
return CompressedOops::decode((narrowOop) Atomic::cmpxchg(val, addr, c));
|
||||
}
|
||||
|
||||
inline oop ShenandoahHeap::cas_oop(oop n, narrowOop* addr, oop c) {
|
||||
narrowOop cmp = CompressedOops::encode(c);
|
||||
narrowOop val = CompressedOops::encode(n);
|
||||
|
@ -22,25 +22,30 @@
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "gc/shenandoah/shenandoahBarrierSet.hpp"
|
||||
#include "gc/shenandoah/shenandoahBarrierSet.inline.hpp"
|
||||
#include "gc/shenandoah/shenandoahRuntime.hpp"
|
||||
#include "gc/shenandoah/shenandoahThreadLocalData.hpp"
|
||||
#include "runtime/interfaceSupport.inline.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
|
||||
void ShenandoahRuntime::write_ref_array_pre_oop_entry(oop* dst, size_t length) {
|
||||
void ShenandoahRuntime::write_ref_array_pre_oop_entry(oop* src, oop* dst, size_t length) {
|
||||
ShenandoahBarrierSet *bs = ShenandoahBarrierSet::barrier_set();
|
||||
bs->write_ref_array_pre(dst, length, false);
|
||||
bs->arraycopy_pre(src, dst, length);
|
||||
}
|
||||
|
||||
void ShenandoahRuntime::write_ref_array_pre_narrow_oop_entry(narrowOop* dst, size_t length) {
|
||||
void ShenandoahRuntime::write_ref_array_pre_narrow_oop_entry(narrowOop* src, narrowOop* dst, size_t length) {
|
||||
ShenandoahBarrierSet *bs = ShenandoahBarrierSet::barrier_set();
|
||||
bs->write_ref_array_pre(dst, length, false);
|
||||
bs->arraycopy_pre(src, dst, length);
|
||||
}
|
||||
|
||||
void ShenandoahRuntime::write_ref_array_post_entry(HeapWord* dst, size_t length) {
|
||||
void ShenandoahRuntime::write_ref_array_pre_duinit_oop_entry(oop* src, oop* dst, size_t length) {
|
||||
ShenandoahBarrierSet *bs = ShenandoahBarrierSet::barrier_set();
|
||||
bs->ShenandoahBarrierSet::write_ref_array(dst, length);
|
||||
bs->arraycopy_update(src, length);
|
||||
}
|
||||
|
||||
void ShenandoahRuntime::write_ref_array_pre_duinit_narrow_oop_entry(narrowOop* src, narrowOop* dst, size_t length) {
|
||||
ShenandoahBarrierSet *bs = ShenandoahBarrierSet::barrier_set();
|
||||
bs->arraycopy_update(src, length);
|
||||
}
|
||||
|
||||
// Shenandoah pre write barrier slowpath
|
||||
@ -62,8 +67,13 @@ JRT_END
|
||||
|
||||
// Shenandoah clone barrier: makes sure that references point to to-space
|
||||
// in cloned objects.
|
||||
JRT_LEAF(void, ShenandoahRuntime::shenandoah_clone_barrier(oopDesc* obj))
|
||||
ShenandoahBarrierSet::barrier_set()->write_region(MemRegion((HeapWord*) obj, obj->size()));
|
||||
JRT_LEAF(void, ShenandoahRuntime::shenandoah_clone_barrier(oopDesc* s, oopDesc* d, size_t length))
|
||||
oop src = oop(s);
|
||||
oop dst = oop(d);
|
||||
shenandoah_assert_correct(NULL, src);
|
||||
shenandoah_assert_correct(NULL, dst);
|
||||
ShenandoahBarrierSet::barrier_set()->clone_barrier(src);
|
||||
RawAccessBarrier<IS_NOT_NULL>::clone(src, dst, length);
|
||||
JRT_END
|
||||
|
||||
JRT_LEAF(oopDesc*, ShenandoahRuntime::load_reference_barrier_native(oopDesc * src))
|
||||
|
@ -32,15 +32,16 @@ class oopDesc;
|
||||
|
||||
class ShenandoahRuntime : public AllStatic {
|
||||
public:
|
||||
static void write_ref_array_pre_oop_entry(oop* dst, size_t length);
|
||||
static void write_ref_array_pre_narrow_oop_entry(narrowOop* dst, size_t length);
|
||||
static void write_ref_array_post_entry(HeapWord* dst, size_t length);
|
||||
static void write_ref_array_pre_oop_entry(oop* src, oop* dst, size_t length);
|
||||
static void write_ref_array_pre_narrow_oop_entry(narrowOop* src, narrowOop* dst, size_t length);
|
||||
static void write_ref_array_pre_duinit_oop_entry(oop* src, oop* dst, size_t length);
|
||||
static void write_ref_array_pre_duinit_narrow_oop_entry(narrowOop* src, narrowOop* dst, size_t length);
|
||||
static void write_ref_field_pre_entry(oopDesc* orig, JavaThread* thread);
|
||||
|
||||
static oopDesc* load_reference_barrier(oopDesc *src);
|
||||
static oopDesc* load_reference_barrier_native(oopDesc *src);
|
||||
|
||||
static void shenandoah_clone_barrier(oopDesc* obj);
|
||||
static void shenandoah_clone_barrier(oopDesc* s, oopDesc* d, size_t length);
|
||||
};
|
||||
|
||||
#endif // SHARE_GC_SHENANDOAH_SHENANDOAHRUNTIME_HPP
|
||||
|
Loading…
Reference in New Issue
Block a user