< prev index next > src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp
Print this page
// store result depending on type (everything that is not
// T_OBJECT, T_LONG, T_FLOAT or T_DOUBLE is treated as T_INT)
// n.b. this assumes Java returns an integral result in r0
// and a floating result in j_farg0
! __ ldr(j_rarg2, result);
! Label is_long, is_float, is_double, exit;
! __ ldr(j_rarg1, result_type);
! __ cmp(j_rarg1, (u1)T_OBJECT);
__ br(Assembler::EQ, is_long);
! __ cmp(j_rarg1, (u1)T_LONG);
- __ br(Assembler::EQ, is_long);
- __ cmp(j_rarg1, (u1)T_FLOAT);
__ br(Assembler::EQ, is_float);
! __ cmp(j_rarg1, (u1)T_DOUBLE);
__ br(Assembler::EQ, is_double);
// handle T_INT case
! __ strw(r0, Address(j_rarg2));
__ BIND(exit);
// pop parameters
__ sub(esp, rfp, -sp_after_call_off * wordSize);
// store result depending on type (everything that is not
// T_OBJECT, T_LONG, T_FLOAT or T_DOUBLE is treated as T_INT)
// n.b. this assumes Java returns an integral result in r0
// and a floating result in j_farg0
! // All of j_rargN may be used to return inline type fields so be careful
! // not to clobber those.
! // SharedRuntime::generate_buffered_inline_type_adapter() knows the register
! // assignment of Rresult below.
+ Register Rresult = r14, Rresult_type = r15;
+ __ ldr(Rresult, result);
+ Label is_long, is_float, is_double, check_prim, exit;
+ __ ldr(Rresult_type, result_type);
+ __ cmp(Rresult_type, (u1)T_OBJECT);
+ __ br(Assembler::EQ, check_prim);
+ __ cmp(Rresult_type, (u1)T_LONG);
__ br(Assembler::EQ, is_long);
! __ cmp(Rresult_type, (u1)T_FLOAT);
__ br(Assembler::EQ, is_float);
! __ cmp(Rresult_type, (u1)T_DOUBLE);
__ br(Assembler::EQ, is_double);
// handle T_INT case
! __ strw(r0, Address(Rresult));
__ BIND(exit);
// pop parameters
__ sub(esp, rfp, -sp_after_call_off * wordSize);
// leave frame and return to caller
__ leave();
__ ret(lr);
// handle return types different from T_INT
__ BIND(is_long);
! __ str(r0, Address(j_rarg2, 0));
__ br(Assembler::AL, exit);
__ BIND(is_float);
! __ strs(j_farg0, Address(j_rarg2, 0));
__ br(Assembler::AL, exit);
__ BIND(is_double);
! __ strd(j_farg0, Address(j_rarg2, 0));
__ br(Assembler::AL, exit);
return start;
}
// leave frame and return to caller
__ leave();
__ ret(lr);
// handle return types different from T_INT
+ __ BIND(check_prim);
+ if (InlineTypeReturnedAsFields) {
+ // Check for scalarized return value
+ __ tbz(r0, 0, is_long);
+ // Load pack handler address
+ __ andr(rscratch1, r0, -2);
+ __ ldr(rscratch1, Address(rscratch1, InstanceKlass::adr_inlineklass_fixed_block_offset()));
+ __ ldr(rscratch1, Address(rscratch1, InlineKlass::pack_handler_jobject_offset()));
+ __ blr(rscratch1);
+ __ b(exit);
+ }
__ BIND(is_long);
! __ str(r0, Address(Rresult, 0));
__ br(Assembler::AL, exit);
__ BIND(is_float);
! __ strs(j_farg0, Address(Rresult, 0));
__ br(Assembler::AL, exit);
__ BIND(is_double);
! __ strd(j_farg0, Address(Rresult, 0));
__ br(Assembler::AL, exit);
return start;
}
// if (src->klass() != dst->klass()) return -1;
__ load_klass(rscratch2, dst);
__ eor(rscratch2, rscratch2, scratch_src_klass);
__ cbnz(rscratch2, L_failed);
+ // Check for flat inline type array -> return -1
+ __ test_flat_array_oop(src, rscratch2, L_failed);
+
+ // Check for null-free (non-flat) inline type array -> handle as object array
+ __ test_null_free_array_oop(src, rscratch2, L_objArray);
+
// if (!src->is_Array()) return -1;
__ tbz(lh, 31, L_failed); // i.e. (lh >= 0)
// At this point, it is known to be a typeArray (array_tag 0x3).
#ifdef ASSERT
// t0 = sub(Pm_base, Pn_base, t0, len);
// }
};
+ // Call here from the interpreter or compiled code to either load
+ // multiple returned values from the inline type instance being
+ // returned to registers or to store returned values to a newly
+ // allocated inline type instance.
+ address generate_return_value_stub(address destination, const char* name, bool has_res) {
+ // We need to save all registers the calling convention may use so
+ // the runtime calls read or update those registers. This needs to
+ // be in sync with SharedRuntime::java_return_convention().
+ // n.b. aarch64 asserts that frame::arg_reg_save_area_bytes == 0
+ enum layout {
+ j_rarg7_off = 0, j_rarg7_2, // j_rarg7 is r0
+ j_rarg6_off, j_rarg6_2,
+ j_rarg5_off, j_rarg5_2,
+ j_rarg4_off, j_rarg4_2,
+ j_rarg3_off, j_rarg3_2,
+ j_rarg2_off, j_rarg2_2,
+ j_rarg1_off, j_rarg1_2,
+ j_rarg0_off, j_rarg0_2,
+
+ j_farg7_off, j_farg7_2,
+ j_farg6_off, j_farg6_2,
+ j_farg5_off, j_farg5_2,
+ j_farg4_off, j_farg4_2,
+ j_farg3_off, j_farg3_2,
+ j_farg2_off, j_farg2_2,
+ j_farg1_off, j_farg1_2,
+ j_farg0_off, j_farg0_2,
+
+ rfp_off, rfp_off2,
+ return_off, return_off2,
+
+ framesize // inclusive of return address
+ };
+
+ CodeBuffer code(name, 512, 64);
+ MacroAssembler* masm = new MacroAssembler(&code);
+
+ int frame_size_in_bytes = align_up(framesize*BytesPerInt, 16);
+ assert(frame_size_in_bytes == framesize*BytesPerInt, "misaligned");
+ int frame_size_in_slots = frame_size_in_bytes / BytesPerInt;
+ int frame_size_in_words = frame_size_in_bytes / wordSize;
+
+ OopMapSet* oop_maps = new OopMapSet();
+ OopMap* map = new OopMap(frame_size_in_slots, 0);
+
+ map->set_callee_saved(VMRegImpl::stack2reg(j_rarg7_off), j_rarg7->as_VMReg());
+ map->set_callee_saved(VMRegImpl::stack2reg(j_rarg6_off), j_rarg6->as_VMReg());
+ map->set_callee_saved(VMRegImpl::stack2reg(j_rarg5_off), j_rarg5->as_VMReg());
+ map->set_callee_saved(VMRegImpl::stack2reg(j_rarg4_off), j_rarg4->as_VMReg());
+ map->set_callee_saved(VMRegImpl::stack2reg(j_rarg3_off), j_rarg3->as_VMReg());
+ map->set_callee_saved(VMRegImpl::stack2reg(j_rarg2_off), j_rarg2->as_VMReg());
+ map->set_callee_saved(VMRegImpl::stack2reg(j_rarg1_off), j_rarg1->as_VMReg());
+ map->set_callee_saved(VMRegImpl::stack2reg(j_rarg0_off), j_rarg0->as_VMReg());
+
+ map->set_callee_saved(VMRegImpl::stack2reg(j_farg0_off), j_farg0->as_VMReg());
+ map->set_callee_saved(VMRegImpl::stack2reg(j_farg1_off), j_farg1->as_VMReg());
+ map->set_callee_saved(VMRegImpl::stack2reg(j_farg2_off), j_farg2->as_VMReg());
+ map->set_callee_saved(VMRegImpl::stack2reg(j_farg3_off), j_farg3->as_VMReg());
+ map->set_callee_saved(VMRegImpl::stack2reg(j_farg4_off), j_farg4->as_VMReg());
+ map->set_callee_saved(VMRegImpl::stack2reg(j_farg5_off), j_farg5->as_VMReg());
+ map->set_callee_saved(VMRegImpl::stack2reg(j_farg6_off), j_farg6->as_VMReg());
+ map->set_callee_saved(VMRegImpl::stack2reg(j_farg7_off), j_farg7->as_VMReg());
+
+ address start = __ pc();
+
+ __ enter(); // Save FP and LR before call
+
+ __ stpd(j_farg1, j_farg0, Address(__ pre(sp, -2 * wordSize)));
+ __ stpd(j_farg3, j_farg2, Address(__ pre(sp, -2 * wordSize)));
+ __ stpd(j_farg5, j_farg4, Address(__ pre(sp, -2 * wordSize)));
+ __ stpd(j_farg7, j_farg6, Address(__ pre(sp, -2 * wordSize)));
+
+ __ stp(j_rarg1, j_rarg0, Address(__ pre(sp, -2 * wordSize)));
+ __ stp(j_rarg3, j_rarg2, Address(__ pre(sp, -2 * wordSize)));
+ __ stp(j_rarg5, j_rarg4, Address(__ pre(sp, -2 * wordSize)));
+ __ stp(j_rarg7, j_rarg6, Address(__ pre(sp, -2 * wordSize)));
+
+ int frame_complete = __ offset();
+
+ // Set up last_Java_sp and last_Java_fp
+ address the_pc = __ pc();
+ __ set_last_Java_frame(sp, noreg, the_pc, rscratch1);
+
+ // Call runtime
+ __ mov(c_rarg1, r0);
+ __ mov(c_rarg0, rthread);
+
+ __ mov(rscratch1, destination);
+ __ blr(rscratch1);
+
+ oop_maps->add_gc_map(the_pc - start, map);
+
+ __ reset_last_Java_frame(false);
+
+ __ ldp(j_rarg7, j_rarg6, Address(__ post(sp, 2 * wordSize)));
+ __ ldp(j_rarg5, j_rarg4, Address(__ post(sp, 2 * wordSize)));
+ __ ldp(j_rarg3, j_rarg2, Address(__ post(sp, 2 * wordSize)));
+ __ ldp(j_rarg1, j_rarg0, Address(__ post(sp, 2 * wordSize)));
+
+ __ ldpd(j_farg7, j_farg6, Address(__ post(sp, 2 * wordSize)));
+ __ ldpd(j_farg5, j_farg4, Address(__ post(sp, 2 * wordSize)));
+ __ ldpd(j_farg3, j_farg2, Address(__ post(sp, 2 * wordSize)));
+ __ ldpd(j_farg1, j_farg0, Address(__ post(sp, 2 * wordSize)));
+
+ __ leave();
+
+ // check for pending exceptions
+ Label pending;
+ __ ldr(rscratch1, Address(rthread, in_bytes(Thread::pending_exception_offset())));
+ __ cbnz(rscratch1, pending);
+
+ if (has_res) {
+ __ get_vm_result(r0, rthread);
+ }
+
+ __ ret(lr);
+
+ __ bind(pending);
+ __ far_jump(RuntimeAddress(StubRoutines::forward_exception_entry()));
+
+ // -------------
+ // make sure all code is generated
+ masm->flush();
+
+ RuntimeStub* stub = RuntimeStub::new_runtime_stub(name, &code, frame_complete, frame_size_in_words, oop_maps, false);
+ return stub->entry_point();
+ }
+
// Initialization
void generate_initial_stubs() {
// Generate initial stubs and initializes the entry points
// entry points that exist in all platforms Note: This is code
if (vmIntrinsics::is_intrinsic_available(vmIntrinsics::_float16ToFloat) &&
vmIntrinsics::is_intrinsic_available(vmIntrinsics::_floatToFloat16)) {
StubRoutines::_hf2f = generate_float16ToFloat();
StubRoutines::_f2hf = generate_floatToFloat16();
}
+
+ if (InlineTypeReturnedAsFields) {
+ StubRoutines::_load_inline_type_fields_in_regs =
+ generate_return_value_stub(CAST_FROM_FN_PTR(address, SharedRuntime::load_inline_type_fields_in_regs), "load_inline_type_fields_in_regs", false);
+ StubRoutines::_store_inline_type_fields_to_buf =
+ generate_return_value_stub(CAST_FROM_FN_PTR(address, SharedRuntime::store_inline_type_fields_to_buf), "store_inline_type_fields_to_buf", true);
+ }
+
}
void generate_continuation_stubs() {
// Continuation stubs:
StubRoutines::_cont_thaw = generate_cont_thaw();
< prev index next >