8353216: Improve VerifyMethodHandles for method handle linkers

Reviewed-by: dlong
This commit is contained in:
Vladimir Ivanov 2025-04-24 01:09:17 +00:00
parent bbec3c0730
commit 428334b616
5 changed files with 109 additions and 14 deletions

View File

@ -2041,7 +2041,7 @@ void MacroAssembler::clinit_barrier(Register klass, Register scratch, Label* L_f
// Fast path check: class is fully initialized
lea(scratch, Address(klass, InstanceKlass::init_state_offset()));
ldarb(scratch, scratch);
subs(zr, scratch, InstanceKlass::fully_initialized);
cmp(scratch, InstanceKlass::fully_initialized);
br(Assembler::EQ, *L_fast_path);
// Fast path check: current thread is initializer thread

View File

@ -93,14 +93,60 @@ void MethodHandles::verify_klass(MacroAssembler* _masm,
void MethodHandles::verify_ref_kind(MacroAssembler* _masm, int ref_kind, Register member_reg, Register temp) { }
void MethodHandles::verify_method(MacroAssembler* _masm, Register method, vmIntrinsics::ID iid) {
BLOCK_COMMENT("verify_method {");
__ verify_method_ptr(method);
if (VerifyMethodHandles) {
Label L_ok;
assert_different_registers(method, rscratch1, rscratch2);
const Register method_holder = rscratch1;
__ load_method_holder(method_holder, method);
switch (iid) {
case vmIntrinsicID::_invokeBasic:
// Require compiled LambdaForm class to be fully initialized.
__ lea(rscratch2, Address(method_holder, InstanceKlass::init_state_offset()));
__ ldarb(rscratch2, rscratch2);
__ cmp(rscratch2, InstanceKlass::fully_initialized);
__ br(Assembler::EQ, L_ok);
break;
case vmIntrinsicID::_linkToStatic:
__ clinit_barrier(method_holder, rscratch2, &L_ok);
break;
case vmIntrinsicID::_linkToVirtual:
case vmIntrinsicID::_linkToSpecial:
case vmIntrinsicID::_linkToInterface:
// Class initialization check is too strong here. Just ensure that class initialization has been initiated.
__ lea(rscratch2, Address(method_holder, InstanceKlass::init_state_offset()));
__ ldarb(rscratch2, rscratch2);
__ cmp(rscratch2, InstanceKlass::being_initialized);
__ br(Assembler::GE, L_ok);
// init_state check failed, but it may be an abstract interface method
__ ldrh(rscratch2, Address(method, Method::access_flags_offset()));
__ tbnz(rscratch2, exact_log2(JVM_ACC_ABSTRACT), L_ok);
break;
default:
fatal("unexpected intrinsic %d: %s", vmIntrinsics::as_int(iid), vmIntrinsics::name_at(iid));
}
// Method holder init state check failed for a concrete method.
__ stop("Method holder klass is not initialized");
__ bind(L_ok);
}
BLOCK_COMMENT("} verify_method");
}
#endif //ASSERT
void MethodHandles::jump_from_method_handle(MacroAssembler* _masm, Register method, Register temp,
bool for_compiler_entry) {
bool for_compiler_entry, vmIntrinsics::ID iid) {
assert(method == rmethod, "interpreter calling convention");
Label L_no_such_method;
__ cbz(rmethod, L_no_such_method);
__ verify_method_ptr(method);
verify_method(_masm, method, iid);
if (!for_compiler_entry && JvmtiExport::can_post_interpreter_events()) {
Label run_compiled_code;
@ -160,7 +206,7 @@ void MethodHandles::jump_to_lambda_form(MacroAssembler* _masm,
__ BIND(L);
}
jump_from_method_handle(_masm, method_temp, temp2, for_compiler_entry);
jump_from_method_handle(_masm, method_temp, temp2, for_compiler_entry, vmIntrinsics::_invokeBasic);
BLOCK_COMMENT("} jump_to_lambda_form");
}
@ -447,8 +493,7 @@ void MethodHandles::generate_method_handle_dispatch(MacroAssembler* _masm,
// After figuring out which concrete method to call, jump into it.
// Note that this works in the interpreter with no data motion.
// But the compiled version will require that r2_recv be shifted out.
__ verify_method_ptr(rmethod);
jump_from_method_handle(_masm, rmethod, temp1, for_compiler_entry);
jump_from_method_handle(_masm, rmethod, temp1, for_compiler_entry, iid);
if (iid == vmIntrinsics::_linkToInterface) {
__ bind(L_incompatible_class_change_error);
__ far_jump(RuntimeAddress(SharedRuntime::throw_IncompatibleClassChangeError_entry()));

View File

@ -39,6 +39,8 @@ public:
Register obj, vmClassID klass_id,
const char* error_message = "wrong klass") NOT_DEBUG_RETURN;
static void verify_method(MacroAssembler* _masm, Register method, vmIntrinsics::ID iid) NOT_DEBUG_RETURN;
static void verify_method_handle(MacroAssembler* _masm, Register mh_reg) {
verify_klass(_masm, mh_reg, VM_CLASS_ID(java_lang_invoke_MethodHandle),
"reference is a MH");
@ -49,7 +51,7 @@ public:
// Similar to InterpreterMacroAssembler::jump_from_interpreted.
// Takes care of special dispatch from single stepping too.
static void jump_from_method_handle(MacroAssembler* _masm, Register method, Register temp,
bool for_compiler_entry);
bool for_compiler_entry, vmIntrinsics::ID iid);
static void jump_to_lambda_form(MacroAssembler* _masm,
Register recv, Register method_temp,

View File

@ -122,17 +122,64 @@ void MethodHandles::verify_ref_kind(MacroAssembler* _masm, int ref_kind, Registe
__ bind(L);
}
#endif //ASSERT
void MethodHandles::verify_method(MacroAssembler* _masm, Register method, Register temp, vmIntrinsics::ID iid) {
BLOCK_COMMENT("verify_method {");
__ verify_method_ptr(method);
if (VerifyMethodHandles) {
Label L_ok;
assert_different_registers(method, temp);
const Register method_holder = temp;
__ load_method_holder(method_holder, method);
__ push(method_holder); // keep holder around for diagnostic purposes
switch (iid) {
case vmIntrinsicID::_invokeBasic:
// Require compiled LambdaForm class to be fully initialized.
__ cmpb(Address(method_holder, InstanceKlass::init_state_offset()), InstanceKlass::fully_initialized);
__ jccb(Assembler::equal, L_ok);
break;
case vmIntrinsicID::_linkToStatic:
__ clinit_barrier(method_holder, &L_ok);
break;
case vmIntrinsicID::_linkToVirtual:
case vmIntrinsicID::_linkToSpecial:
case vmIntrinsicID::_linkToInterface:
// Class initialization check is too strong here. Just ensure that initialization has been initiated.
__ cmpb(Address(method_holder, InstanceKlass::init_state_offset()), InstanceKlass::being_initialized);
__ jcc(Assembler::greaterEqual, L_ok);
// init_state check failed, but it may be an abstract interface method
__ load_unsigned_short(temp, Address(method, Method::access_flags_offset()));
__ testl(temp, JVM_ACC_ABSTRACT);
__ jccb(Assembler::notZero, L_ok);
break;
default:
fatal("unexpected intrinsic %d: %s", vmIntrinsics::as_int(iid), vmIntrinsics::name_at(iid));
}
// clinit check failed for a concrete method
__ STOP("Method holder klass is not initialized");
__ BIND(L_ok);
__ pop(method_holder); // restore stack layout
}
BLOCK_COMMENT("} verify_method");
}
#endif // ASSERT
void MethodHandles::jump_from_method_handle(MacroAssembler* _masm, Register method, Register temp,
bool for_compiler_entry) {
bool for_compiler_entry, vmIntrinsics::ID iid) {
assert(method == rbx, "interpreter calling convention");
Label L_no_such_method;
__ testptr(rbx, rbx);
__ jcc(Assembler::zero, L_no_such_method);
__ verify_method_ptr(method);
verify_method(_masm, method, temp, iid);
if (!for_compiler_entry && JvmtiExport::can_post_interpreter_events()) {
Label run_compiled_code;
@ -193,7 +240,7 @@ void MethodHandles::jump_to_lambda_form(MacroAssembler* _masm,
__ BIND(L);
}
jump_from_method_handle(_masm, method_temp, temp2, for_compiler_entry);
jump_from_method_handle(_masm, method_temp, temp2, for_compiler_entry, vmIntrinsics::_invokeBasic);
BLOCK_COMMENT("} jump_to_lambda_form");
}
@ -485,8 +532,7 @@ void MethodHandles::generate_method_handle_dispatch(MacroAssembler* _masm,
// After figuring out which concrete method to call, jump into it.
// Note that this works in the interpreter with no data motion.
// But the compiled version will require that rcx_recv be shifted out.
__ verify_method_ptr(rbx_method);
jump_from_method_handle(_masm, rbx_method, temp1, for_compiler_entry);
jump_from_method_handle(_masm, rbx_method, temp1, for_compiler_entry, iid);
if (iid == vmIntrinsics::_linkToInterface) {
__ bind(L_incompatible_class_change_error);

View File

@ -38,6 +38,8 @@ public:
Register obj, vmClassID klass_id,
const char* error_message = "wrong klass") NOT_DEBUG_RETURN;
static void verify_method(MacroAssembler* _masm, Register method, Register temp, vmIntrinsics::ID iid) NOT_DEBUG_RETURN;
static void verify_method_handle(MacroAssembler* _masm, Register mh_reg) {
verify_klass(_masm, mh_reg, VM_CLASS_ID(MethodHandle_klass),
"reference is a MH");
@ -48,7 +50,7 @@ public:
// Similar to InterpreterMacroAssembler::jump_from_interpreted.
// Takes care of special dispatch from single stepping too.
static void jump_from_method_handle(MacroAssembler* _masm, Register method, Register temp,
bool for_compiler_entry);
bool for_compiler_entry, vmIntrinsics::ID iid);
static void jump_to_lambda_form(MacroAssembler* _masm,
Register recv, Register method_temp,