< prev index next > src/hotspot/cpu/aarch64/universalNativeInvoker_aarch64.cpp
Print this page
*/
#include "precompiled.hpp"
#include "asm/macroAssembler.hpp"
#include "code/codeBlob.hpp"
#include "memory/resourceArea.hpp"
#include "prims/universalNativeInvoker.hpp"
#define __ _masm->
! void ProgrammableInvoker::Generator::generate() {
! __ enter();
! // Name registers used in the stub code. These are all caller-save so
! // may be clobbered by the call to the native function. Avoid using
- // rscratch1 here as it's r8 which is the indirect result register in
- // the standard ABI.
- Register Rctx = r10, Rstack_size = r11;
- Register Rwords = r12, Rtmp = r13;
- Register Rsrc_ptr = r14, Rdst_ptr = r15;
! assert_different_registers(Rctx, Rstack_size, rscratch1, rscratch2);
! // TODO: if the callee is not using the standard C ABI then we need to
! // preserve more registers here.
! __ block_comment("init_and_alloc_stack");
! __ mov(Rctx, c_rarg0);
! __ str(Rctx, Address(__ pre(sp, -2 * wordSize)));
! assert(_abi->_stack_alignment_bytes % 16 == 0, "stack must be 16 byte aligned");
! __ block_comment("allocate_stack");
! __ ldr(Rstack_size, Address(Rctx, (int) _layout->stack_args_bytes));
! __ add(rscratch2, Rstack_size, _abi->_stack_alignment_bytes - 1);
! __ andr(rscratch2, rscratch2, -_abi->_stack_alignment_bytes);
- __ sub(sp, sp, rscratch2);
! __ block_comment("load_arguments");
! __ ldr(Rsrc_ptr, Address(Rctx, (int) _layout->stack_args));
! __ lsr(Rwords, Rstack_size, LogBytesPerWord);
! __ mov(Rdst_ptr, sp);
! Label Ldone, Lnext;
! __ bind(Lnext);
! __ cbz(Rwords, Ldone);
! __ ldr(Rtmp, __ post(Rsrc_ptr, wordSize));
! __ str(Rtmp, __ post(Rdst_ptr, wordSize));
! __ sub(Rwords, Rwords, 1);
- __ b(Lnext);
- __ bind(Ldone);
! for (int i = 0; i < _abi->_vector_argument_registers.length(); i++) {
! ssize_t offs = _layout->arguments_vector + i * float_reg_size;
- __ ldrq(_abi->_vector_argument_registers.at(i), Address(Rctx, offs));
}
! for (int i = 0; i < _abi->_integer_argument_registers.length(); i++) {
! ssize_t offs = _layout->arguments_integer + i * sizeof(uintptr_t);
! __ ldr(_abi->_integer_argument_registers.at(i), Address(Rctx, offs));
}
! assert(_abi->_shadow_space_bytes == 0, "shadow space not supported on AArch64");
! // call target function
! __ block_comment("call target function");
! __ ldr(rscratch2, Address(Rctx, (int) _layout->arguments_next_pc));
! __ blr(rscratch2);
! __ ldr(Rctx, Address(rfp, -2 * wordSize)); // Might have clobbered Rctx
! __ block_comment("store_registers");
! for (int i = 0; i < _abi->_integer_return_registers.length(); i++) {
! ssize_t offs = _layout->returns_integer + i * sizeof(uintptr_t);
! __ str(_abi->_integer_return_registers.at(i), Address(Rctx, offs));
}
! for (int i = 0; i < _abi->_vector_return_registers.length(); i++) {
! ssize_t offs = _layout->returns_vector + i * float_reg_size;
! __ strq(_abi->_vector_return_registers.at(i), Address(Rctx, offs));
}
! __ leave();
__ ret(lr);
! __ flush();
! }
! address ProgrammableInvoker::generate_adapter(jobject jabi, jobject jlayout) {
! ResourceMark rm;
! const ABIDescriptor abi = ForeignGlobals::parse_abi_descriptor(jabi);
! const BufferLayout layout = ForeignGlobals::parse_buffer_layout(jlayout);
! BufferBlob* _invoke_native_blob = BufferBlob::create("invoke_native_blob", native_invoker_size);
! CodeBuffer code2(_invoke_native_blob);
- ProgrammableInvoker::Generator g2(&code2, &abi, &layout);
- g2.generate();
- code2.log_section_sizes("InvokeNativeBlob");
! return _invoke_native_blob->code_begin();
}
*/
#include "precompiled.hpp"
#include "asm/macroAssembler.hpp"
#include "code/codeBlob.hpp"
+ #include "code/codeCache.hpp"
+ #include "code/vmreg.inline.hpp"
+ #include "compiler/oopMap.hpp"
+ #include "logging/logStream.hpp"
#include "memory/resourceArea.hpp"
#include "prims/universalNativeInvoker.hpp"
+ #include "runtime/stubCodeGenerator.hpp"
#define __ _masm->
! class NativeInvokerGenerator : public StubCodeGenerator {
! BasicType* _signature;
+ int _num_args;
+ BasicType _ret_bt;
+ const ABIDescriptor& _abi;
! const GrowableArray<VMReg>& _input_registers;
! const GrowableArray<VMReg>& _output_registers;
! bool _needs_return_buffer;
! int _frame_complete;
! int _framesize;
+ OopMapSet* _oop_maps;
+ public:
+ NativeInvokerGenerator(CodeBuffer* buffer,
+ BasicType* signature,
+ int num_args,
+ BasicType ret_bt,
+ const ABIDescriptor& abi,
+ const GrowableArray<VMReg>& input_registers,
+ const GrowableArray<VMReg>& output_registers,
+ bool needs_return_buffer)
+ : StubCodeGenerator(buffer, PrintMethodHandleStubs),
+ _signature(signature),
+ _num_args(num_args),
+ _ret_bt(ret_bt),
+ _abi(abi),
+ _input_registers(input_registers),
+ _output_registers(output_registers),
+ _needs_return_buffer(needs_return_buffer),
+ _frame_complete(0),
+ _framesize(0),
+ _oop_maps(NULL) {
+ }
! void generate();
! int frame_complete() const {
! return _frame_complete;
+ }
! int framesize() const {
+ return (_framesize >> (LogBytesPerWord - LogBytesPerInt));
+ }
! OopMapSet* oop_maps() const {
! return _oop_maps;
! }
! };
! static const int native_invoker_code_size = 1024;
! RuntimeStub* ProgrammableInvoker::make_native_invoker(BasicType* signature,
! int num_args,
! BasicType ret_bt,
+ const ABIDescriptor& abi,
+ const GrowableArray<VMReg>& input_registers,
+ const GrowableArray<VMReg>& output_registers,
+ bool needs_return_buffer) {
+ int locs_size = 64;
+ CodeBuffer code("nep_invoker_blob", native_invoker_code_size, locs_size);
+ NativeInvokerGenerator g(&code, signature, num_args, ret_bt, abi, input_registers, output_registers, needs_return_buffer);
+ g.generate();
+ code.log_section_sizes("nep_invoker_blob");
! RuntimeStub* stub =
! RuntimeStub::new_runtime_stub("nep_invoker_blob",
! &code,
! g.frame_complete(),
! g.framesize(),
! g.oop_maps(), false);
! if (TraceNativeInvokers) {
! stub->print_on(tty);
}
! return stub;
! }
!
+ void NativeInvokerGenerator::generate() {
+ enum layout {
+ rfp_off,
+ rfp_off2,
+ lr_off,
+ lr_off2,
+ framesize // inclusive of return address
+ // The following are also computed dynamically:
+ // spill area for return value
+ // out arg area (e.g. for stack args)
+ };
+
+ // we can't use rscratch1 because it is r8, and used by the ABI
+ Register tmp1 = r9;
+ Register tmp2 = r10;
+
+ Register shuffle_reg = r19;
+ JavaCallConv in_conv;
+ NativeCallConv out_conv(_input_registers);
+ ArgumentShuffle arg_shuffle(_signature, _num_args, _signature, _num_args, &in_conv, &out_conv, shuffle_reg->as_VMReg());
+
+ #ifdef ASSERT
+ LogTarget(Trace, panama) lt;
+ if (lt.is_enabled()) {
+ ResourceMark rm;
+ LogStream ls(lt);
+ arg_shuffle.print_on(&ls);
}
+ #endif
! int allocated_frame_size = 0;
+ if (_needs_return_buffer) {
+ allocated_frame_size += 8; // for address spill
+ }
+ allocated_frame_size += arg_shuffle.out_arg_stack_slots() <<LogBytesPerInt;
+ assert(_abi._shadow_space_bytes == 0, "not expecting shadow space on AArch64");
! int ret_buf_addr_sp_offset = -1;
! if (_needs_return_buffer) {
! // in sync with the above
! ret_buf_addr_sp_offset = allocated_frame_size - 8;
+ }
! RegSpiller out_reg_spiller(_output_registers);
+ int spill_offset = -1;
! if (!_needs_return_buffer) {
+ spill_offset = 0;
+ // spill area can be shared with the above, so we take the max of the 2
+ allocated_frame_size = out_reg_spiller.spill_size_bytes() > allocated_frame_size
+ ? out_reg_spiller.spill_size_bytes()
+ : allocated_frame_size;
+ }
! _framesize = align_up(framesize
! + (allocated_frame_size >> LogBytesPerInt), 4);
! assert(is_even(_framesize/2), "sp not 16-byte aligned");
+
+ _oop_maps = new OopMapSet();
+ address start = __ pc();
+
+ __ enter();
+
+ // lr and fp are already in place
+ __ sub(sp, rfp, ((unsigned)_framesize-4) << LogBytesPerInt); // prolog
+
+ _frame_complete = __ pc() - start;
+
+ address the_pc = __ pc();
+ __ set_last_Java_frame(sp, rfp, the_pc, tmp1);
+ OopMap* map = new OopMap(_framesize, 0);
+ _oop_maps->add_gc_map(the_pc - start, map);
+
+ // State transition
+ __ mov(tmp1, _thread_in_native);
+ __ lea(tmp2, Address(rthread, JavaThread::thread_state_offset()));
+ __ stlrw(tmp1, tmp2);
+
+ __ block_comment("{ argument shuffle");
+ arg_shuffle.generate(_masm, shuffle_reg->as_VMReg(), 0, _abi._shadow_space_bytes);
+ if (_needs_return_buffer) {
+ assert(ret_buf_addr_sp_offset != -1, "no return buffer addr spill");
+ __ str(_abi._ret_buf_addr_reg, Address(sp, ret_buf_addr_sp_offset));
}
+ __ block_comment("} argument shuffle");
+
+ __ blr(_abi._target_addr_reg);
+ // this call is assumed not to have killed rthread
! if (!_needs_return_buffer) {
! // Unpack native results.
! switch (_ret_bt) {
+ case T_BOOLEAN: __ c2bool(r0); break;
+ case T_CHAR : __ ubfx(r0, r0, 0, 16); break;
+ case T_BYTE : __ sbfx(r0, r0, 0, 8); break;
+ case T_SHORT : __ sbfx(r0, r0, 0, 16); break;
+ case T_INT : __ sbfx(r0, r0, 0, 32); break;
+ case T_DOUBLE :
+ case T_FLOAT :
+ // Result is in v0 we'll save as needed
+ break;
+ case T_VOID: break;
+ case T_LONG: break;
+ default : ShouldNotReachHere();
+ }
+ } else {
+ assert(ret_buf_addr_sp_offset != -1, "no return buffer addr spill");
+ __ ldr(tmp1, Address(sp, ret_buf_addr_sp_offset));
+ int offset = 0;
+ for (int i = 0; i < _output_registers.length(); i++) {
+ VMReg reg = _output_registers.at(i);
+ if (reg->is_Register()) {
+ __ str(reg->as_Register(), Address(tmp1, offset));
+ offset += 8;
+ } else if(reg->is_FloatRegister()) {
+ __ strd(reg->as_FloatRegister(), Address(tmp1, offset));
+ offset += 16;
+ } else {
+ ShouldNotReachHere();
+ }
+ }
}
! __ mov(tmp1, _thread_in_native_trans);
+ __ strw(tmp1, Address(rthread, JavaThread::thread_state_offset()));
+
+ // Force this write out before the read below
+ __ membar(Assembler::LoadLoad | Assembler::LoadStore |
+ Assembler::StoreLoad | Assembler::StoreStore);
+
+ __ verify_sve_vector_length(tmp1);
+
+ Label L_after_safepoint_poll;
+ Label L_safepoint_poll_slow_path;
+
+ __ safepoint_poll(L_safepoint_poll_slow_path, true /* at_return */, true /* acquire */, false /* in_nmethod */, tmp1);
+
+ __ ldrw(tmp1, Address(rthread, JavaThread::suspend_flags_offset()));
+ __ cbnzw(tmp1, L_safepoint_poll_slow_path);
+
+ __ bind(L_after_safepoint_poll);
+
+ // change thread state
+ __ mov(tmp1, _thread_in_Java);
+ __ lea(tmp2, Address(rthread, JavaThread::thread_state_offset()));
+ __ stlrw(tmp1, tmp2);
+
+ __ block_comment("reguard stack check");
+ Label L_reguard;
+ Label L_after_reguard;
+ __ ldrb(tmp1, Address(rthread, JavaThread::stack_guard_state_offset()));
+ __ cmpw(tmp1, StackOverflow::stack_guard_yellow_reserved_disabled);
+ __ br(Assembler::EQ, L_reguard);
+ __ bind(L_after_reguard);
+
+ __ reset_last_Java_frame(true);
+
+ __ leave(); // required for proper stackwalking of RuntimeStub frame
__ ret(lr);
! //////////////////////////////////////////////////////////////////////////////
!
+ __ block_comment("{ L_safepoint_poll_slow_path");
+ __ bind(L_safepoint_poll_slow_path);
+
+ if (!_needs_return_buffer) {
+ // Need to save the native result registers around any runtime calls.
+ out_reg_spiller.generate_spill(_masm, spill_offset);
+ }
! __ mov(c_rarg0, rthread);
! assert(frame::arg_reg_save_area_bytes == 0, "not expecting frame reg save area");
! __ lea(tmp1, RuntimeAddress(CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans)));
! __ blr(tmp1);
! if (!_needs_return_buffer) {
+ out_reg_spiller.generate_fill(_masm, spill_offset);
+ }
+
+ __ b(L_after_safepoint_poll);
+ __ block_comment("} L_safepoint_poll_slow_path");
+
+ //////////////////////////////////////////////////////////////////////////////
+
+ __ block_comment("{ L_reguard");
+ __ bind(L_reguard);
+
+ if (!_needs_return_buffer) {
+ out_reg_spiller.generate_spill(_masm, spill_offset);
+ }
! __ rt_call(CAST_FROM_FN_PTR(address, SharedRuntime::reguard_yellow_pages), tmp1);
! if (!_needs_return_buffer) {
+ out_reg_spiller.generate_fill(_masm, spill_offset);
+ }
+
+ __ b(L_after_reguard);
+
+ __ block_comment("} L_reguard");
+
+ //////////////////////////////////////////////////////////////////////////////
+
+ __ flush();
}
< prev index next >