8261837: SIGSEGV in ciVirtualCallTypeData::translate_from

Co-authored-by: Fei Yang <fyang@openjdk.org>
Reviewed-by: iveresov, vlivanov, kvn
This commit is contained in:
Dean Long 2023-11-27 22:01:37 +00:00
parent 5f7f2c4ea0
commit 1bb250c9e6
7 changed files with 115 additions and 39 deletions

View File

@ -2699,7 +2699,10 @@ void LIR_Assembler::emit_profile_type(LIR_OpProfileType* op) {
__ verify_oop(obj); __ verify_oop(obj);
if (tmp != obj) { if (tmp != obj) {
assert_different_registers(obj, tmp, rscratch1, rscratch2, mdo_addr.base(), mdo_addr.index());
__ mov(tmp, obj); __ mov(tmp, obj);
} else {
assert_different_registers(obj, rscratch1, rscratch2, mdo_addr.base(), mdo_addr.index());
} }
if (do_null) { if (do_null) {
__ cbnz(tmp, update); __ cbnz(tmp, update);
@ -2756,10 +2759,11 @@ void LIR_Assembler::emit_profile_type(LIR_OpProfileType* op) {
__ cbz(rscratch2, none); __ cbz(rscratch2, none);
__ cmp(rscratch2, (u1)TypeEntries::null_seen); __ cmp(rscratch2, (u1)TypeEntries::null_seen);
__ br(Assembler::EQ, none); __ br(Assembler::EQ, none);
// There is a chance that the checks above (re-reading profiling // There is a chance that the checks above
// data from memory) fail if another thread has just set the // fail if another thread has just set the
// profiling to this obj's klass // profiling to this obj's klass
__ dmb(Assembler::ISHLD); __ dmb(Assembler::ISHLD);
__ eor(tmp, tmp, rscratch2); // get back original value before XOR
__ ldr(rscratch2, mdo_addr); __ ldr(rscratch2, mdo_addr);
__ eor(tmp, tmp, rscratch2); __ eor(tmp, tmp, rscratch2);
__ andr(rscratch1, tmp, TypeEntries::type_klass_mask); __ andr(rscratch1, tmp, TypeEntries::type_klass_mask);
@ -2784,6 +2788,10 @@ void LIR_Assembler::emit_profile_type(LIR_OpProfileType* op) {
__ bind(none); __ bind(none);
// first time here. Set profile type. // first time here. Set profile type.
__ str(tmp, mdo_addr); __ str(tmp, mdo_addr);
#ifdef ASSERT
__ andr(tmp, tmp, TypeEntries::type_mask);
__ verify_klass_ptr(tmp);
#endif
} }
} else { } else {
// There's a single possible klass at this profile point // There's a single possible klass at this profile point
@ -2815,6 +2823,10 @@ void LIR_Assembler::emit_profile_type(LIR_OpProfileType* op) {
#endif #endif
// first time here. Set profile type. // first time here. Set profile type.
__ str(tmp, mdo_addr); __ str(tmp, mdo_addr);
#ifdef ASSERT
__ andr(tmp, tmp, TypeEntries::type_mask);
__ verify_klass_ptr(tmp);
#endif
} else { } else {
assert(ciTypeEntries::valid_ciklass(current_klass) != nullptr && assert(ciTypeEntries::valid_ciklass(current_klass) != nullptr &&
ciTypeEntries::valid_ciklass(current_klass) != exact_klass, "inconsistent"); ciTypeEntries::valid_ciklass(current_klass) != exact_klass, "inconsistent");

View File

@ -1562,7 +1562,7 @@ void InterpreterMacroAssembler::call_VM_base(Register oop_result,
} }
void InterpreterMacroAssembler::profile_obj_type(Register obj, const Address& mdo_addr) { void InterpreterMacroAssembler::profile_obj_type(Register obj, const Address& mdo_addr) {
assert_different_registers(obj, rscratch1); assert_different_registers(obj, rscratch1, mdo_addr.base(), mdo_addr.index());
Label update, next, none; Label update, next, none;
verify_oop(obj); verify_oop(obj);
@ -1584,13 +1584,13 @@ void InterpreterMacroAssembler::profile_obj_type(Register obj, const Address& md
tbnz(obj, exact_log2(TypeEntries::type_unknown), next); tbnz(obj, exact_log2(TypeEntries::type_unknown), next);
// already unknown. Nothing to do anymore. // already unknown. Nothing to do anymore.
ldr(rscratch1, mdo_addr);
cbz(rscratch1, none); cbz(rscratch1, none);
cmp(rscratch1, (u1)TypeEntries::null_seen); cmp(rscratch1, (u1)TypeEntries::null_seen);
br(Assembler::EQ, none); br(Assembler::EQ, none);
// There is a chance that the checks above (re-reading profiling // There is a chance that the checks above
// data from memory) fail if another thread has just set the // fail if another thread has just set the
// profiling to this obj's klass // profiling to this obj's klass
eor(obj, obj, rscratch1); // get back original value before XOR
ldr(rscratch1, mdo_addr); ldr(rscratch1, mdo_addr);
eor(obj, obj, rscratch1); eor(obj, obj, rscratch1);
tst(obj, TypeEntries::type_klass_mask); tst(obj, TypeEntries::type_klass_mask);
@ -1603,6 +1603,10 @@ void InterpreterMacroAssembler::profile_obj_type(Register obj, const Address& md
bind(none); bind(none);
// first time here. Set profile type. // first time here. Set profile type.
str(obj, mdo_addr); str(obj, mdo_addr);
#ifdef ASSERT
andr(obj, obj, TypeEntries::type_mask);
verify_klass_ptr(obj);
#endif
bind(next); bind(next);
} }

View File

@ -1653,10 +1653,11 @@ void LIR_Assembler::check_conflict(ciKlass* exact_klass, intptr_t current_klass,
__ beqz(t1, none); __ beqz(t1, none);
__ mv(t0, (u1)TypeEntries::null_seen); __ mv(t0, (u1)TypeEntries::null_seen);
__ beq(t0, t1, none); __ beq(t0, t1, none);
// There is a chance that the checks above (re-reading profiling // There is a chance that the checks above
// data from memory) fail if another thread has just set the // fail if another thread has just set the
// profiling to this obj's klass // profiling to this obj's klass
__ membar(MacroAssembler::LoadLoad); __ membar(MacroAssembler::LoadLoad);
__ xorr(tmp, tmp, t1); // get back original value before XOR
__ ld(t1, mdo_addr); __ ld(t1, mdo_addr);
__ xorr(tmp, tmp, t1); __ xorr(tmp, tmp, t1);
__ andi(t0, tmp, TypeEntries::type_klass_mask); __ andi(t0, tmp, TypeEntries::type_klass_mask);
@ -1683,6 +1684,10 @@ void LIR_Assembler::check_conflict(ciKlass* exact_klass, intptr_t current_klass,
__ bind(none); __ bind(none);
// first time here. Set profile type. // first time here. Set profile type.
__ sd(tmp, mdo_addr); __ sd(tmp, mdo_addr);
#ifdef ASSERT
__ andi(tmp, tmp, TypeEntries::type_mask);
__ verify_klass_ptr(tmp);
#endif
} }
} }
@ -1717,6 +1722,10 @@ void LIR_Assembler::check_no_conflict(ciKlass* exact_klass, intptr_t current_kla
#endif #endif
// first time here. Set profile type. // first time here. Set profile type.
__ sd(tmp, mdo_addr); __ sd(tmp, mdo_addr);
#ifdef ASSERT
__ andi(tmp, tmp, TypeEntries::type_mask);
__ verify_klass_ptr(tmp);
#endif
} else { } else {
assert(ciTypeEntries::valid_ciklass(current_klass) != nullptr && assert(ciTypeEntries::valid_ciklass(current_klass) != nullptr &&
ciTypeEntries::valid_ciklass(current_klass) != exact_klass, "inconsistent"); ciTypeEntries::valid_ciklass(current_klass) != exact_klass, "inconsistent");

View File

@ -1627,8 +1627,8 @@ void InterpreterMacroAssembler::profile_obj_type(Register obj, const Address& md
bind(update); bind(update);
load_klass(obj, obj); load_klass(obj, obj);
ld(t0, mdo_addr); ld(tmp, mdo_addr);
xorr(obj, obj, t0); xorr(obj, obj, tmp);
andi(t0, obj, TypeEntries::type_klass_mask); andi(t0, obj, TypeEntries::type_klass_mask);
beqz(t0, next); // klass seen before, nothing to beqz(t0, next); // klass seen before, nothing to
// do. The unknown bit may have been // do. The unknown bit may have been
@ -1638,15 +1638,15 @@ void InterpreterMacroAssembler::profile_obj_type(Register obj, const Address& md
bnez(t0, next); bnez(t0, next);
// already unknown. Nothing to do anymore. // already unknown. Nothing to do anymore.
ld(t0, mdo_addr); beqz(tmp, none);
beqz(t0, none); mv(t0, (u1)TypeEntries::null_seen);
mv(tmp, (u1)TypeEntries::null_seen); beq(tmp, t0, none);
beq(t0, tmp, none); // There is a chance that the checks above
// There is a chance that the checks above (re-reading profiling // fail if another thread has just set the
// data from memory) fail if another thread has just set the
// profiling to this obj's klass // profiling to this obj's klass
ld(t0, mdo_addr); xorr(obj, obj, tmp); // get back original value before XOR
xorr(obj, obj, t0); ld(tmp, mdo_addr);
xorr(obj, obj, tmp);
andi(t0, obj, TypeEntries::type_klass_mask); andi(t0, obj, TypeEntries::type_klass_mask);
beqz(t0, next); beqz(t0, next);
@ -1657,6 +1657,10 @@ void InterpreterMacroAssembler::profile_obj_type(Register obj, const Address& md
bind(none); bind(none);
// first time here. Set profile type. // first time here. Set profile type.
sd(obj, mdo_addr); sd(obj, mdo_addr);
#ifdef ASSERT
andi(obj, obj, TypeEntries::type_mask);
verify_klass_ptr(obj);
#endif
bind(next); bind(next);
} }

View File

@ -3629,13 +3629,33 @@ void LIR_Assembler::emit_profile_type(LIR_OpProfileType* op) {
__ verify_oop(obj); __ verify_oop(obj);
if (tmp != obj) { #ifdef ASSERT
__ mov(tmp, obj); if (obj == tmp) {
#ifdef _LP64
assert_different_registers(obj, rscratch1, mdo_addr.base(), mdo_addr.index());
#else
assert_different_registers(obj, mdo_addr.base(), mdo_addr.index());
#endif
} else {
#ifdef _LP64
assert_different_registers(obj, tmp, rscratch1, mdo_addr.base(), mdo_addr.index());
#else
assert_different_registers(obj, tmp, mdo_addr.base(), mdo_addr.index());
#endif
} }
#endif
if (do_null) { if (do_null) {
__ testptr(tmp, tmp); __ testptr(obj, obj);
__ jccb(Assembler::notZero, update); __ jccb(Assembler::notZero, update);
if (!TypeEntries::was_null_seen(current_klass)) { if (!TypeEntries::was_null_seen(current_klass)) {
__ testptr(mdo_addr, TypeEntries::null_seen);
#ifndef ASSERT
__ jccb(Assembler::notZero, next); // already set
#else
__ jcc(Assembler::notZero, next); // already set
#endif
// atomic update to prevent overwriting Klass* with 0
__ lock();
__ orptr(mdo_addr, TypeEntries::null_seen); __ orptr(mdo_addr, TypeEntries::null_seen);
} }
if (do_update) { if (do_update) {
@ -3646,7 +3666,7 @@ void LIR_Assembler::emit_profile_type(LIR_OpProfileType* op) {
__ jmp(next); __ jmp(next);
} }
} else { } else {
__ testptr(tmp, tmp); __ testptr(obj, obj);
__ jcc(Assembler::notZero, update); __ jcc(Assembler::notZero, update);
__ stop("unexpected null obj"); __ stop("unexpected null obj");
#endif #endif
@ -3658,7 +3678,7 @@ void LIR_Assembler::emit_profile_type(LIR_OpProfileType* op) {
#ifdef ASSERT #ifdef ASSERT
if (exact_klass != nullptr) { if (exact_klass != nullptr) {
Label ok; Label ok;
__ load_klass(tmp, tmp, tmp_load_klass); __ load_klass(tmp, obj, tmp_load_klass);
__ push(tmp); __ push(tmp);
__ mov_metadata(tmp, exact_klass->constant_encoding()); __ mov_metadata(tmp, exact_klass->constant_encoding());
__ cmpptr(tmp, Address(rsp, 0)); __ cmpptr(tmp, Address(rsp, 0));
@ -3673,9 +3693,11 @@ void LIR_Assembler::emit_profile_type(LIR_OpProfileType* op) {
if (exact_klass != nullptr) { if (exact_klass != nullptr) {
__ mov_metadata(tmp, exact_klass->constant_encoding()); __ mov_metadata(tmp, exact_klass->constant_encoding());
} else { } else {
__ load_klass(tmp, tmp, tmp_load_klass); __ load_klass(tmp, obj, tmp_load_klass);
} }
#ifdef _LP64
__ mov(rscratch1, tmp); // save original value before XOR
#endif
__ xorptr(tmp, mdo_addr); __ xorptr(tmp, mdo_addr);
__ testptr(tmp, TypeEntries::type_klass_mask); __ testptr(tmp, TypeEntries::type_klass_mask);
// klass seen before, nothing to do. The unknown bit may have been // klass seen before, nothing to do. The unknown bit may have been
@ -3686,23 +3708,23 @@ void LIR_Assembler::emit_profile_type(LIR_OpProfileType* op) {
__ jccb(Assembler::notZero, next); // already unknown. Nothing to do anymore. __ jccb(Assembler::notZero, next); // already unknown. Nothing to do anymore.
if (TypeEntries::is_type_none(current_klass)) { if (TypeEntries::is_type_none(current_klass)) {
__ cmpptr(mdo_addr, 0); __ testptr(mdo_addr, TypeEntries::type_mask);
__ jccb(Assembler::equal, none); __ jccb(Assembler::zero, none);
__ cmpptr(mdo_addr, TypeEntries::null_seen); #ifdef _LP64
__ jccb(Assembler::equal, none);
// There is a chance that the checks above (re-reading profiling // There is a chance that the checks above (re-reading profiling
// data from memory) fail if another thread has just set the // data from memory) fail if another thread has just set the
// profiling to this obj's klass // profiling to this obj's klass
__ mov(tmp, rscratch1); // get back original value before XOR
__ xorptr(tmp, mdo_addr); __ xorptr(tmp, mdo_addr);
__ testptr(tmp, TypeEntries::type_klass_mask); __ testptr(tmp, TypeEntries::type_klass_mask);
__ jccb(Assembler::zero, next); __ jccb(Assembler::zero, next);
#endif
} }
} else { } else {
assert(ciTypeEntries::valid_ciklass(current_klass) != nullptr && assert(ciTypeEntries::valid_ciklass(current_klass) != nullptr &&
ciTypeEntries::valid_ciklass(current_klass) != exact_klass, "conflict only"); ciTypeEntries::valid_ciklass(current_klass) != exact_klass, "conflict only");
__ movptr(tmp, mdo_addr); __ testptr(mdo_addr, TypeEntries::type_unknown);
__ testptr(tmp, TypeEntries::type_unknown);
__ jccb(Assembler::notZero, next); // already unknown. Nothing to do anymore. __ jccb(Assembler::notZero, next); // already unknown. Nothing to do anymore.
} }
@ -3715,6 +3737,10 @@ void LIR_Assembler::emit_profile_type(LIR_OpProfileType* op) {
__ bind(none); __ bind(none);
// first time here. Set profile type. // first time here. Set profile type.
__ movptr(mdo_addr, tmp); __ movptr(mdo_addr, tmp);
#ifdef ASSERT
__ andptr(tmp, TypeEntries::type_klass_mask);
__ verify_klass_ptr(tmp);
#endif
} }
} else { } else {
// There's a single possible klass at this profile point // There's a single possible klass at this profile point
@ -3729,10 +3755,8 @@ void LIR_Assembler::emit_profile_type(LIR_OpProfileType* op) {
{ {
Label ok; Label ok;
__ push(tmp); __ push(tmp);
__ cmpptr(mdo_addr, 0); __ testptr(mdo_addr, TypeEntries::type_mask);
__ jcc(Assembler::equal, ok); __ jcc(Assembler::zero, ok);
__ cmpptr(mdo_addr, TypeEntries::null_seen);
__ jcc(Assembler::equal, ok);
// may have been set by another thread // may have been set by another thread
__ mov_metadata(tmp, exact_klass->constant_encoding()); __ mov_metadata(tmp, exact_klass->constant_encoding());
__ xorptr(tmp, mdo_addr); __ xorptr(tmp, mdo_addr);
@ -3748,20 +3772,22 @@ void LIR_Assembler::emit_profile_type(LIR_OpProfileType* op) {
#endif #endif
// first time here. Set profile type. // first time here. Set profile type.
__ movptr(mdo_addr, tmp); __ movptr(mdo_addr, tmp);
#ifdef ASSERT
__ andptr(tmp, TypeEntries::type_klass_mask);
__ verify_klass_ptr(tmp);
#endif
} else { } else {
assert(ciTypeEntries::valid_ciklass(current_klass) != nullptr && assert(ciTypeEntries::valid_ciklass(current_klass) != nullptr &&
ciTypeEntries::valid_ciklass(current_klass) != exact_klass, "inconsistent"); ciTypeEntries::valid_ciklass(current_klass) != exact_klass, "inconsistent");
__ movptr(tmp, mdo_addr); __ testptr(mdo_addr, TypeEntries::type_unknown);
__ testptr(tmp, TypeEntries::type_unknown);
__ jccb(Assembler::notZero, next); // already unknown. Nothing to do anymore. __ jccb(Assembler::notZero, next); // already unknown. Nothing to do anymore.
__ orptr(mdo_addr, TypeEntries::type_unknown); __ orptr(mdo_addr, TypeEntries::type_unknown);
} }
} }
__ bind(next);
} }
__ bind(next);
} }
void LIR_Assembler::emit_delay(LIR_OpDelay*) { void LIR_Assembler::emit_delay(LIR_OpDelay*) {

View File

@ -54,15 +54,28 @@ void InterpreterMacroAssembler::jump_to_entry(address entry) {
void InterpreterMacroAssembler::profile_obj_type(Register obj, const Address& mdo_addr) { void InterpreterMacroAssembler::profile_obj_type(Register obj, const Address& mdo_addr) {
Label update, next, none; Label update, next, none;
#ifdef _LP64
assert_different_registers(obj, rscratch1, mdo_addr.base(), mdo_addr.index());
#else
assert_different_registers(obj, mdo_addr.base(), mdo_addr.index());
#endif
interp_verify_oop(obj, atos); interp_verify_oop(obj, atos);
testptr(obj, obj); testptr(obj, obj);
jccb(Assembler::notZero, update); jccb(Assembler::notZero, update);
testptr(mdo_addr, TypeEntries::null_seen);
jccb(Assembler::notZero, next); // null already seen. Nothing to do anymore.
// atomic update to prevent overwriting Klass* with 0
lock();
orptr(mdo_addr, TypeEntries::null_seen); orptr(mdo_addr, TypeEntries::null_seen);
jmpb(next); jmpb(next);
bind(update); bind(update);
load_klass(obj, obj, rscratch1); load_klass(obj, obj, rscratch1);
#ifdef _LP64
mov(rscratch1, obj);
#endif
xorptr(obj, mdo_addr); xorptr(obj, mdo_addr);
testptr(obj, TypeEntries::type_klass_mask); testptr(obj, TypeEntries::type_klass_mask);
@ -77,12 +90,15 @@ void InterpreterMacroAssembler::profile_obj_type(Register obj, const Address& md
jccb(Assembler::equal, none); jccb(Assembler::equal, none);
cmpptr(mdo_addr, TypeEntries::null_seen); cmpptr(mdo_addr, TypeEntries::null_seen);
jccb(Assembler::equal, none); jccb(Assembler::equal, none);
#ifdef _LP64
// There is a chance that the checks above (re-reading profiling // There is a chance that the checks above (re-reading profiling
// data from memory) fail if another thread has just set the // data from memory) fail if another thread has just set the
// profiling to this obj's klass // profiling to this obj's klass
mov(obj, rscratch1);
xorptr(obj, mdo_addr); xorptr(obj, mdo_addr);
testptr(obj, TypeEntries::type_klass_mask); testptr(obj, TypeEntries::type_klass_mask);
jccb(Assembler::zero, next); jccb(Assembler::zero, next);
#endif
// different than before. Cannot keep accurate profile. // different than before. Cannot keep accurate profile.
orptr(mdo_addr, TypeEntries::type_unknown); orptr(mdo_addr, TypeEntries::type_unknown);
@ -91,6 +107,10 @@ void InterpreterMacroAssembler::profile_obj_type(Register obj, const Address& md
bind(none); bind(none);
// first time here. Set profile type. // first time here. Set profile type.
movptr(mdo_addr, obj); movptr(mdo_addr, obj);
#ifdef ASSERT
andptr(obj, TypeEntries::type_klass_mask);
verify_klass_ptr(obj);
#endif
bind(next); bind(next);
} }

View File

@ -894,6 +894,7 @@ public:
void testptr(Register src, int32_t imm32) { LP64_ONLY(testq(src, imm32)) NOT_LP64(testl(src, imm32)); } void testptr(Register src, int32_t imm32) { LP64_ONLY(testq(src, imm32)) NOT_LP64(testl(src, imm32)); }
void testptr(Register src1, Address src2) { LP64_ONLY(testq(src1, src2)) NOT_LP64(testl(src1, src2)); } void testptr(Register src1, Address src2) { LP64_ONLY(testq(src1, src2)) NOT_LP64(testl(src1, src2)); }
void testptr(Address src, int32_t imm32) { LP64_ONLY(testq(src, imm32)) NOT_LP64(testl(src, imm32)); }
void testptr(Register src1, Register src2); void testptr(Register src1, Register src2);
void xorptr(Register dst, Register src) { LP64_ONLY(xorq(dst, src)) NOT_LP64(xorl(dst, src)); } void xorptr(Register dst, Register src) { LP64_ONLY(xorq(dst, src)) NOT_LP64(xorl(dst, src)); }