8305387: JDK-8301995 breaks arm 32-bit

Reviewed-by: shade, matsaave
This commit is contained in:
Aleksei Voitylov 2023-04-28 09:41:55 +00:00 committed by Aleksey Shipilev
parent 3d9d84b742
commit 60a29a668c
4 changed files with 103 additions and 13 deletions

View file

@ -290,6 +290,27 @@ void InterpreterMacroAssembler::load_resolved_klass_at_offset(
ldr(Rklass, Address(Rklass, Array<Klass*>::base_offset_in_bytes()));
}
void InterpreterMacroAssembler::load_resolved_indy_entry(Register cache, Register index) {
// Get index out of bytecode pointer, get_cache_entry_pointer_at_bcp
assert_different_registers(cache, index, Rtemp);
get_index_at_bcp(index, 1, Rtemp, sizeof(u4));
// load constant pool cache pointer
ldr(cache, Address(FP, frame::interpreter_frame_cache_offset * wordSize));
// Get address of invokedynamic array
ldr(cache, Address(cache, in_bytes(ConstantPoolCache::invokedynamic_entries_offset())));
// Scale the index to be the entry index * sizeof(ResolvedInvokeDynamicInfo)
// On ARM32 sizeof(ResolvedIndyEntry) is 12, use mul instead of lsl
mov(Rtemp, sizeof(ResolvedIndyEntry));
mul(index, index, Rtemp);
add(cache, cache, Array<ResolvedIndyEntry>::base_offset_in_bytes());
add(cache, cache, index);
}
// Generate a subtype check: branch to not_subtype if sub_klass is
// not a subtype of super_klass.
// Profiling code for the subtype check failure (profile_typecheck_failed)

View file

@ -69,7 +69,6 @@ class InterpreterMacroAssembler: public MacroAssembler {
inline void check_extended_sp(Register tmp) {}
inline void check_no_cached_stack_top(Register tmp) {}
void save_bcp() { str(Rbcp, Address(FP, frame::interpreter_frame_bcp_offset * wordSize)); }
void restore_bcp() { ldr(Rbcp, Address(FP, frame::interpreter_frame_bcp_offset * wordSize)); }
void restore_locals() {
@ -103,6 +102,8 @@ class InterpreterMacroAssembler: public MacroAssembler {
// load cpool->resolved_klass_at(index); Rtemp is corrupted upon return
void load_resolved_klass_at_offset(Register Rcpool, Register Rindex, Register Rklass);
void load_resolved_indy_entry(Register cache, Register index);
void pop_ptr(Register r);
void pop_i(Register r = R0_tos);
void pop_l(Register lo = R0_tos_lo, Register hi = R1_tos_hi);

View file

@ -364,24 +364,32 @@ address TemplateInterpreterGenerator::generate_return_entry_for(TosState state,
const Register Rcache = R2_tmp;
const Register Rindex = R3_tmp;
__ get_cache_and_index_at_bcp(Rcache, Rindex, 1, index_size);
__ add(Rtemp, Rcache, AsmOperand(Rindex, lsl, LogBytesPerWord));
__ ldrb(Rtemp, Address(Rtemp, ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::flags_offset()));
__ check_stack_top();
__ add(Rstack_top, Rstack_top, AsmOperand(Rtemp, lsl, Interpreter::logStackElementSize));
if (index_size == sizeof(u4)) {
__ load_resolved_indy_entry(Rcache, Rindex);
__ ldrh(Rcache, Address(Rcache, in_bytes(ResolvedIndyEntry::num_parameters_offset())));
__ check_stack_top();
__ add(Rstack_top, Rstack_top, AsmOperand(Rcache, lsl, Interpreter::logStackElementSize));
} else {
// Pop N words from the stack
__ get_cache_and_index_at_bcp(Rcache, Rindex, 1, index_size);
__ add(Rtemp, Rcache, AsmOperand(Rindex, lsl, LogBytesPerWord));
__ ldrb(Rtemp, Address(Rtemp, ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::flags_offset()));
__ check_stack_top();
__ add(Rstack_top, Rstack_top, AsmOperand(Rtemp, lsl, Interpreter::logStackElementSize));
}
__ convert_retval_to_tos(state);
__ check_and_handle_popframe();
__ check_and_handle_earlyret();
__ check_and_handle_popframe();
__ check_and_handle_earlyret();
__ dispatch_next(state, step);
return entry;
}
address TemplateInterpreterGenerator::generate_deopt_entry_for(TosState state, int step, address continuation) {
address entry = __ pc();

View file

@ -2608,6 +2608,66 @@ void TemplateTable::load_field_cp_cache_entry(Register Rcache,
}
}
// The rmethod register is input and overwritten to be the adapter method for the
// indy call. Link Register (lr) is set to the return address for the adapter and
// an appendix may be pushed to the stack. Registers R1-R3, Rtemp (R12) are clobbered
void TemplateTable::load_invokedynamic_entry(Register method) {
// setup registers
const Register appendix = R1;
const Register cache = R2_tmp;
const Register index = R3_tmp;
assert_different_registers(method, appendix, cache, index);
__ save_bcp();
Label resolved;
__ load_resolved_indy_entry(cache, index);
// Load-acquire the adapter method to match store-release in ResolvedIndyEntry::fill_in()
__ ldr(method, Address(cache, in_bytes(ResolvedIndyEntry::method_offset())));
TemplateTable::volatile_barrier(MacroAssembler::Membar_mask_bits(MacroAssembler::LoadLoad | MacroAssembler::LoadStore), noreg, true);
// Compare the method to zero
__ cbnz(method, resolved);
Bytecodes::Code code = bytecode();
// Call to the interpreter runtime to resolve invokedynamic
address entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_from_cache);
__ mov(R1, code); // this is essentially Bytecodes::_invokedynamic, call_VM requires R1
__ call_VM(noreg, entry, R1);
// Update registers with resolved info
__ load_resolved_indy_entry(cache, index);
// Load-acquire the adapter method to match store-release in ResolvedIndyEntry::fill_in()
__ ldr(method, Address(cache, in_bytes(ResolvedIndyEntry::method_offset())));
TemplateTable::volatile_barrier(MacroAssembler::Membar_mask_bits(MacroAssembler::LoadLoad | MacroAssembler::LoadStore), noreg, true);
#ifdef ASSERT
__ cbnz(method, resolved);
__ stop("Should be resolved by now");
#endif // ASSERT
__ bind(resolved);
Label L_no_push;
// Check if there is an appendix
__ ldrb(index, Address(cache, in_bytes(ResolvedIndyEntry::flags_offset())));
__ tbz(index, ResolvedIndyEntry::has_appendix_shift, L_no_push);
// Get appendix
__ ldrh(index, Address(cache, in_bytes(ResolvedIndyEntry::resolved_references_index_offset())));
// Push the appendix as a trailing parameter
// since the parameter_size includes it.
__ load_resolved_reference_at_index(appendix, index);
__ verify_oop(appendix);
__ push(appendix); // push appendix (MethodType, CallSite, etc.)
__ bind(L_no_push);
// compute return type
__ ldrb(index, Address(cache, in_bytes(ResolvedIndyEntry::result_type_offset())));
// load return address
{
const address table_addr = (address) Interpreter::invoke_return_entry_table_for(code);
__ mov_address(Rtemp, table_addr);
__ ldr(LR, Address(Rtemp, index, lsl, Interpreter::logStackElementSize));
}
}
// Blows all volatile registers: R0-R3, Rtemp, LR.
void TemplateTable::load_invoke_cp_cache_entry(int byte_no,
@ -2616,7 +2676,7 @@ void TemplateTable::load_invoke_cp_cache_entry(int byte_no,
Register flags,
bool is_invokevirtual,
bool is_invokevfinal/*unused*/,
bool is_invokedynamic) {
bool is_invokedynamic /*unused*/) {
// setup registers
const Register cache = R2_tmp;
const Register index = R3_tmp;
@ -2639,7 +2699,7 @@ void TemplateTable::load_invoke_cp_cache_entry(int byte_no,
const int index_offset = in_bytes(ConstantPoolCache::base_offset() +
ConstantPoolCacheEntry::f2_offset());
size_t index_size = (is_invokedynamic ? sizeof(u4) : sizeof(u2));
size_t index_size = sizeof(u2);
resolve_cache_and_index(byte_no, cache, index, index_size);
__ add(temp_reg, cache, AsmOperand(index, lsl, LogBytesPerWord));
__ ldr(method, Address(temp_reg, method_offset));
@ -3565,7 +3625,7 @@ void TemplateTable::prepare_invoke(int byte_no,
load_invoke_cp_cache_entry(byte_no, method, index, flags, is_invokevirtual, false, is_invokedynamic);
// maybe push extra argument
if (is_invokedynamic || is_invokehandle) {
if (is_invokehandle) {
Label L_no_push;
__ tbz(flags, ConstantPoolCacheEntry::has_appendix_shift, L_no_push);
__ mov(temp, index);
@ -3810,7 +3870,7 @@ void TemplateTable::invokedynamic(int byte_no) {
const Register Rcallsite = R4_tmp;
const Register R5_method = R5_tmp; // can't reuse Rmethod!
prepare_invoke(byte_no, R5_method, Rcallsite);
load_invokedynamic_entry(R5_method);
// Rcallsite: CallSite object (from cpool->resolved_references[f1])
// Rmethod: MH.linkToCallSite method (from f2)