Skip to content

Commit 428334b

Browse files
author
Vladimir Ivanov
committed
8353216: Improve VerifyMethodHandles for method handle linkers
Reviewed-by: dlong
1 parent bbec3c0 commit 428334b

File tree

5 files changed

+109
-14
lines changed

5 files changed

+109
-14
lines changed

src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2041,7 +2041,7 @@ void MacroAssembler::clinit_barrier(Register klass, Register scratch, Label* L_f
20412041
// Fast path check: class is fully initialized
20422042
lea(scratch, Address(klass, InstanceKlass::init_state_offset()));
20432043
ldarb(scratch, scratch);
2044-
subs(zr, scratch, InstanceKlass::fully_initialized);
2044+
cmp(scratch, InstanceKlass::fully_initialized);
20452045
br(Assembler::EQ, *L_fast_path);
20462046

20472047
// Fast path check: current thread is initializer thread

src/hotspot/cpu/aarch64/methodHandles_aarch64.cpp

Lines changed: 50 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -93,14 +93,60 @@ void MethodHandles::verify_klass(MacroAssembler* _masm,
9393

9494
void MethodHandles::verify_ref_kind(MacroAssembler* _masm, int ref_kind, Register member_reg, Register temp) { }
9595

96+
void MethodHandles::verify_method(MacroAssembler* _masm, Register method, vmIntrinsics::ID iid) {
97+
BLOCK_COMMENT("verify_method {");
98+
__ verify_method_ptr(method);
99+
if (VerifyMethodHandles) {
100+
Label L_ok;
101+
assert_different_registers(method, rscratch1, rscratch2);
102+
const Register method_holder = rscratch1;
103+
__ load_method_holder(method_holder, method);
104+
105+
switch (iid) {
106+
case vmIntrinsicID::_invokeBasic:
107+
// Require compiled LambdaForm class to be fully initialized.
108+
__ lea(rscratch2, Address(method_holder, InstanceKlass::init_state_offset()));
109+
__ ldarb(rscratch2, rscratch2);
110+
__ cmp(rscratch2, InstanceKlass::fully_initialized);
111+
__ br(Assembler::EQ, L_ok);
112+
break;
113+
114+
case vmIntrinsicID::_linkToStatic:
115+
__ clinit_barrier(method_holder, rscratch2, &L_ok);
116+
break;
117+
118+
case vmIntrinsicID::_linkToVirtual:
119+
case vmIntrinsicID::_linkToSpecial:
120+
case vmIntrinsicID::_linkToInterface:
121+
// Class initialization check is too strong here. Just ensure that class initialization has been initiated.
122+
__ lea(rscratch2, Address(method_holder, InstanceKlass::init_state_offset()));
123+
__ ldarb(rscratch2, rscratch2);
124+
__ cmp(rscratch2, InstanceKlass::being_initialized);
125+
__ br(Assembler::GE, L_ok);
126+
127+
// init_state check failed, but it may be an abstract interface method
128+
__ ldrh(rscratch2, Address(method, Method::access_flags_offset()));
129+
__ tbnz(rscratch2, exact_log2(JVM_ACC_ABSTRACT), L_ok);
130+
break;
131+
132+
default:
133+
fatal("unexpected intrinsic %d: %s", vmIntrinsics::as_int(iid), vmIntrinsics::name_at(iid));
134+
}
135+
136+
// Method holder init state check failed for a concrete method.
137+
__ stop("Method holder klass is not initialized");
138+
__ bind(L_ok);
139+
}
140+
BLOCK_COMMENT("} verify_method");
141+
}
96142
#endif //ASSERT
97143

98144
void MethodHandles::jump_from_method_handle(MacroAssembler* _masm, Register method, Register temp,
99-
bool for_compiler_entry) {
145+
bool for_compiler_entry, vmIntrinsics::ID iid) {
100146
assert(method == rmethod, "interpreter calling convention");
101147
Label L_no_such_method;
102148
__ cbz(rmethod, L_no_such_method);
103-
__ verify_method_ptr(method);
149+
verify_method(_masm, method, iid);
104150

105151
if (!for_compiler_entry && JvmtiExport::can_post_interpreter_events()) {
106152
Label run_compiled_code;
@@ -160,7 +206,7 @@ void MethodHandles::jump_to_lambda_form(MacroAssembler* _masm,
160206
__ BIND(L);
161207
}
162208

163-
jump_from_method_handle(_masm, method_temp, temp2, for_compiler_entry);
209+
jump_from_method_handle(_masm, method_temp, temp2, for_compiler_entry, vmIntrinsics::_invokeBasic);
164210
BLOCK_COMMENT("} jump_to_lambda_form");
165211
}
166212

@@ -447,8 +493,7 @@ void MethodHandles::generate_method_handle_dispatch(MacroAssembler* _masm,
447493
// After figuring out which concrete method to call, jump into it.
448494
// Note that this works in the interpreter with no data motion.
449495
// But the compiled version will require that r2_recv be shifted out.
450-
__ verify_method_ptr(rmethod);
451-
jump_from_method_handle(_masm, rmethod, temp1, for_compiler_entry);
496+
jump_from_method_handle(_masm, rmethod, temp1, for_compiler_entry, iid);
452497
if (iid == vmIntrinsics::_linkToInterface) {
453498
__ bind(L_incompatible_class_change_error);
454499
__ far_jump(RuntimeAddress(SharedRuntime::throw_IncompatibleClassChangeError_entry()));

src/hotspot/cpu/aarch64/methodHandles_aarch64.hpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ enum /* platform_dependent_constants */ {
3939
Register obj, vmClassID klass_id,
4040
const char* error_message = "wrong klass") NOT_DEBUG_RETURN;
4141

42+
static void verify_method(MacroAssembler* _masm, Register method, vmIntrinsics::ID iid) NOT_DEBUG_RETURN;
43+
4244
static void verify_method_handle(MacroAssembler* _masm, Register mh_reg) {
4345
verify_klass(_masm, mh_reg, VM_CLASS_ID(java_lang_invoke_MethodHandle),
4446
"reference is a MH");
@@ -49,7 +51,7 @@ enum /* platform_dependent_constants */ {
4951
// Similar to InterpreterMacroAssembler::jump_from_interpreted.
5052
// Takes care of special dispatch from single stepping too.
5153
static void jump_from_method_handle(MacroAssembler* _masm, Register method, Register temp,
52-
bool for_compiler_entry);
54+
bool for_compiler_entry, vmIntrinsics::ID iid);
5355

5456
static void jump_to_lambda_form(MacroAssembler* _masm,
5557
Register recv, Register method_temp,

src/hotspot/cpu/x86/methodHandles_x86.cpp

Lines changed: 52 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -122,17 +122,64 @@ void MethodHandles::verify_ref_kind(MacroAssembler* _masm, int ref_kind, Registe
122122
__ bind(L);
123123
}
124124

125-
#endif //ASSERT
125+
void MethodHandles::verify_method(MacroAssembler* _masm, Register method, Register temp, vmIntrinsics::ID iid) {
126+
BLOCK_COMMENT("verify_method {");
127+
__ verify_method_ptr(method);
128+
if (VerifyMethodHandles) {
129+
Label L_ok;
130+
assert_different_registers(method, temp);
131+
132+
const Register method_holder = temp;
133+
__ load_method_holder(method_holder, method);
134+
__ push(method_holder); // keep holder around for diagnostic purposes
135+
136+
switch (iid) {
137+
case vmIntrinsicID::_invokeBasic:
138+
// Require compiled LambdaForm class to be fully initialized.
139+
__ cmpb(Address(method_holder, InstanceKlass::init_state_offset()), InstanceKlass::fully_initialized);
140+
__ jccb(Assembler::equal, L_ok);
141+
break;
142+
143+
case vmIntrinsicID::_linkToStatic:
144+
__ clinit_barrier(method_holder, &L_ok);
145+
break;
146+
147+
case vmIntrinsicID::_linkToVirtual:
148+
case vmIntrinsicID::_linkToSpecial:
149+
case vmIntrinsicID::_linkToInterface:
150+
// Class initialization check is too strong here. Just ensure that initialization has been initiated.
151+
__ cmpb(Address(method_holder, InstanceKlass::init_state_offset()), InstanceKlass::being_initialized);
152+
__ jcc(Assembler::greaterEqual, L_ok);
153+
154+
// init_state check failed, but it may be an abstract interface method
155+
__ load_unsigned_short(temp, Address(method, Method::access_flags_offset()));
156+
__ testl(temp, JVM_ACC_ABSTRACT);
157+
__ jccb(Assembler::notZero, L_ok);
158+
break;
159+
160+
default:
161+
fatal("unexpected intrinsic %d: %s", vmIntrinsics::as_int(iid), vmIntrinsics::name_at(iid));
162+
}
163+
164+
// clinit check failed for a concrete method
165+
__ STOP("Method holder klass is not initialized");
166+
167+
__ BIND(L_ok);
168+
__ pop(method_holder); // restore stack layout
169+
}
170+
BLOCK_COMMENT("} verify_method");
171+
}
172+
#endif // ASSERT
126173

127174
void MethodHandles::jump_from_method_handle(MacroAssembler* _masm, Register method, Register temp,
128-
bool for_compiler_entry) {
175+
bool for_compiler_entry, vmIntrinsics::ID iid) {
129176
assert(method == rbx, "interpreter calling convention");
130177

131178
Label L_no_such_method;
132179
__ testptr(rbx, rbx);
133180
__ jcc(Assembler::zero, L_no_such_method);
134181

135-
__ verify_method_ptr(method);
182+
verify_method(_masm, method, temp, iid);
136183

137184
if (!for_compiler_entry && JvmtiExport::can_post_interpreter_events()) {
138185
Label run_compiled_code;
@@ -193,7 +240,7 @@ void MethodHandles::jump_to_lambda_form(MacroAssembler* _masm,
193240
__ BIND(L);
194241
}
195242

196-
jump_from_method_handle(_masm, method_temp, temp2, for_compiler_entry);
243+
jump_from_method_handle(_masm, method_temp, temp2, for_compiler_entry, vmIntrinsics::_invokeBasic);
197244
BLOCK_COMMENT("} jump_to_lambda_form");
198245
}
199246

@@ -485,8 +532,7 @@ void MethodHandles::generate_method_handle_dispatch(MacroAssembler* _masm,
485532
// After figuring out which concrete method to call, jump into it.
486533
// Note that this works in the interpreter with no data motion.
487534
// But the compiled version will require that rcx_recv be shifted out.
488-
__ verify_method_ptr(rbx_method);
489-
jump_from_method_handle(_masm, rbx_method, temp1, for_compiler_entry);
535+
jump_from_method_handle(_masm, rbx_method, temp1, for_compiler_entry, iid);
490536

491537
if (iid == vmIntrinsics::_linkToInterface) {
492538
__ bind(L_incompatible_class_change_error);

src/hotspot/cpu/x86/methodHandles_x86.hpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ enum /* platform_dependent_constants */ {
3838
Register obj, vmClassID klass_id,
3939
const char* error_message = "wrong klass") NOT_DEBUG_RETURN;
4040

41+
static void verify_method(MacroAssembler* _masm, Register method, Register temp, vmIntrinsics::ID iid) NOT_DEBUG_RETURN;
42+
4143
static void verify_method_handle(MacroAssembler* _masm, Register mh_reg) {
4244
verify_klass(_masm, mh_reg, VM_CLASS_ID(MethodHandle_klass),
4345
"reference is a MH");
@@ -48,7 +50,7 @@ enum /* platform_dependent_constants */ {
4850
// Similar to InterpreterMacroAssembler::jump_from_interpreted.
4951
// Takes care of special dispatch from single stepping too.
5052
static void jump_from_method_handle(MacroAssembler* _masm, Register method, Register temp,
51-
bool for_compiler_entry);
53+
bool for_compiler_entry, vmIntrinsics::ID iid);
5254

5355
static void jump_to_lambda_form(MacroAssembler* _masm,
5456
Register recv, Register method_temp,

0 commit comments

Comments
 (0)