diff --git a/src/hotspot/cpu/arm/interp_masm_arm.cpp b/src/hotspot/cpu/arm/interp_masm_arm.cpp index 84dfbdc5fa4..b3c4e85474a 100644 --- a/src/hotspot/cpu/arm/interp_masm_arm.cpp +++ b/src/hotspot/cpu/arm/interp_masm_arm.cpp @@ -290,6 +290,27 @@ void InterpreterMacroAssembler::load_resolved_klass_at_offset( ldr(Rklass, Address(Rklass, Array::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::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) diff --git a/src/hotspot/cpu/arm/interp_masm_arm.hpp b/src/hotspot/cpu/arm/interp_masm_arm.hpp index 067d50a8360..9e2c3d58a22 100644 --- a/src/hotspot/cpu/arm/interp_masm_arm.hpp +++ b/src/hotspot/cpu/arm/interp_masm_arm.hpp @@ -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); diff --git a/src/hotspot/cpu/arm/templateInterpreterGenerator_arm.cpp b/src/hotspot/cpu/arm/templateInterpreterGenerator_arm.cpp index f42c53d0f5b..d4e8c1f8859 100644 --- a/src/hotspot/cpu/arm/templateInterpreterGenerator_arm.cpp +++ b/src/hotspot/cpu/arm/templateInterpreterGenerator_arm.cpp @@ -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(); diff --git a/src/hotspot/cpu/arm/templateTable_arm.cpp b/src/hotspot/cpu/arm/templateTable_arm.cpp index 99c814bab90..8b826d55244 100644 --- a/src/hotspot/cpu/arm/templateTable_arm.cpp +++ b/src/hotspot/cpu/arm/templateTable_arm.cpp @@ -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)