8388139: Shenandoah: -XX:+VerifyOops fails on forwarded objects with COH

Reviewed-by: wkemper, xpeng
This commit is contained in:
Aleksey Shipilev 2026-07-14 17:58:31 +00:00
parent 5d24cecccd
commit 0efadf5f54
8 changed files with 103 additions and 0 deletions

View File

@ -420,6 +420,32 @@ void ShenandoahBarrierSetAssembler::try_peek_weak_handle_in_nmethod(MacroAssembl
__ bind(done);
}
void ShenandoahBarrierSetAssembler::check_oop(MacroAssembler* masm, Register obj, Register tmp1, Register tmp2, Label& L_error) {
// Check if the oop is in the right area of memory
__ mov(tmp2, (intptr_t) Universe::verify_oop_mask());
__ andr(tmp1, obj, tmp2);
__ mov(tmp2, (intptr_t) Universe::verify_oop_bits());
// Compare tmp1 and tmp2. We don't use a compare
// instruction here because the flags register is live.
__ eor(tmp1, tmp1, tmp2);
__ cbnz(tmp1, L_error);
// This routine is sometimes called before applying GC barriers.
// With +COH, loading the klass may end up loading forwarding pointer instead.
Label L_skip;
if (UseCompactObjectHeaders) {
Address gc_state(rthread, in_bytes(ShenandoahThreadLocalData::gc_state_offset()));
__ ldrb(tmp1, gc_state);
__ tbnz(tmp1, ShenandoahHeap::HAS_FORWARDED_BITPOS, L_skip);
}
// Make sure klass is 'reasonable', which is not zero.
__ load_narrow_klass(tmp1, obj);
__ cbz(tmp1, L_error);
__ bind(L_skip);
}
void ShenandoahBarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators,
Register start, Register count, Register scratch) {
assert(ShenandoahCardBarrier, "Should have been checked by caller");

View File

@ -74,6 +74,7 @@ public:
Register obj, Register tmp, Label& slowpath);
virtual void try_peek_weak_handle_in_nmethod(MacroAssembler* masm, Register weak_handle, Register obj,
Register tmp, Label& slow_path);
virtual void check_oop(MacroAssembler* masm, Register obj, Register tmp1, Register tmp2, Label& L_error);
#ifdef COMPILER1
void keepalive_barrier_c1_stub(LIR_Assembler* ce, ShenandoahKeepaliveBarrierStub* stub);

View File

@ -659,6 +659,26 @@ void ShenandoahBarrierSetAssembler::try_peek_weak_handle_in_nmethod(MacroAssembl
__ block_comment("} try_peek_weak_handle_in_nmethod (shenandoahgc)");
}
void ShenandoahBarrierSetAssembler::check_oop(MacroAssembler *masm, Register obj, const char* msg) {
if (!VerifyOops) {
return;
}
__ mr(R0, obj);
// This routine is sometimes called before applying GC barriers.
// With +COH, verification can touch the klass that may end up loading forwarding pointer instead.
Label L_skip;
if (UseCompactObjectHeaders) {
__ lbz(R0, in_bytes(ShenandoahThreadLocalData::gc_state_offset()), R16_thread);
__ andi_(R0, R0, ShenandoahHeap::HAS_FORWARDED);
__ bne(CR0, L_skip);
}
__ verify_oop(R0, msg);
__ bind(L_skip);
}
void ShenandoahBarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators,
Register addr, Register count, Register preserve) {
assert(ShenandoahCardBarrier, "Should have been checked by caller");

View File

@ -125,6 +125,8 @@ public:
virtual void try_peek_weak_handle_in_nmethod(MacroAssembler* masm, Register weak_handle, Register obj,
Register tmp, Label& slow_path);
virtual void check_oop(MacroAssembler *masm, Register obj, const char* msg);
#ifdef COMPILER2
// Entry points from Matcher
void load_c2(const MachNode* node, MacroAssembler* masm, Register dst, Register addr, int disp, Register tmp1, Register tmp2, bool narrow, bool acquire);

View File

@ -433,6 +433,32 @@ void ShenandoahBarrierSetAssembler::try_peek_weak_handle_in_nmethod(MacroAssembl
__ bind(done);
}
void ShenandoahBarrierSetAssembler::check_oop(MacroAssembler* masm, Register obj, Register tmp1, Register tmp2, Label& L_error) {
// Check if the oop is in the right area of memory
__ mv(tmp2, (intptr_t) Universe::verify_oop_mask());
__ andr(tmp1, obj, tmp2);
__ mv(tmp2, (intptr_t) Universe::verify_oop_bits());
// Compare tmp1 and tmp2.
__ bne(tmp1, tmp2, L_error);
// This routine is sometimes called before applying GC barriers.
// With +COH, loading the klass may end up loading forwarding pointer instead.
Label L_skip;
if (UseCompactObjectHeaders) {
Address gc_state(xthread, ShenandoahThreadLocalData::gc_state_offset());
__ lbu(tmp1, gc_state);
__ test_bit(tmp1, tmp1, ShenandoahHeap::HAS_FORWARDED_BITPOS);
__ bnez(tmp1, L_skip);
}
// Make sure klass is 'reasonable', which is not zero.
__ load_narrow_klass(tmp1, obj);
__ beqz(tmp1, L_error);
__ bind(L_skip);
}
void ShenandoahBarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators,
Register start, Register count, Register tmp) {
assert(ShenandoahCardBarrier, "Did you mean to enable ShenandoahCardBarrier?");

View File

@ -79,6 +79,7 @@ public:
Register obj, Register tmp, Label& slowpath);
virtual void try_peek_weak_handle_in_nmethod(MacroAssembler* masm, Register weak_handle, Register obj,
Register tmp, Label& slow_path);
virtual void check_oop(MacroAssembler* masm, Register obj, Register tmp1, Register tmp2, Label& L_error);
#ifdef COMPILER1
void keepalive_barrier_c1_stub(LIR_Assembler* ce, ShenandoahKeepaliveBarrierStub* stub);

View File

@ -507,6 +507,32 @@ void ShenandoahBarrierSetAssembler::try_peek_weak_handle_in_nmethod(MacroAssembl
__ bind(done);
}
void ShenandoahBarrierSetAssembler::check_oop(MacroAssembler* masm, Register obj, Register tmp1, Register tmp2, Label& L_error) {
// Check if the oop is in the right area of memory
__ movptr(tmp1, obj);
__ movptr(tmp2, (intptr_t) Universe::verify_oop_mask());
__ andptr(tmp1, tmp2);
__ movptr(tmp2, (intptr_t) Universe::verify_oop_bits());
__ cmpptr(tmp1, tmp2);
__ jcc(Assembler::notZero, L_error);
// This routine is sometimes called before applying GC barriers.
// With +COH, loading the klass may end up loading forwarding pointer instead.
Label L_skip;
if (UseCompactObjectHeaders) {
Address gc_state(r15_thread, ShenandoahThreadLocalData::gc_state_offset());
__ testb(gc_state, ShenandoahHeap::HAS_FORWARDED);
__ jcc(Assembler::notZero, L_skip);
}
// Make sure klass is 'reasonable', which is not zero.
__ load_narrow_klass(tmp1, obj);
__ testl(tmp1, tmp1);
__ jcc(Assembler::zero, L_error);
__ bind(L_skip);
}
#ifdef PRODUCT
#define BLOCK_COMMENT(str) /* nothing */
#else

View File

@ -71,6 +71,7 @@ public:
virtual void try_resolve_jobject_in_native(MacroAssembler* masm, Register jni_env,
Register obj, Register tmp, Label& slowpath);
virtual void try_peek_weak_handle_in_nmethod(MacroAssembler* masm, Register weak_handle, Register obj, Label& slowpath);
virtual void check_oop(MacroAssembler* masm, Register obj, Register tmp1, Register tmp2, Label& L_error);
#ifdef COMPILER1
void keepalive_barrier_c1_stub(LIR_Assembler* ce, ShenandoahKeepaliveBarrierStub* stub);