< prev index next > src/hotspot/cpu/x86/universalNativeInvoker_x86_64.cpp
Print this page
*/
#include "precompiled.hpp"
#include "asm/macroAssembler.hpp"
#include "code/codeBlob.hpp"
+ #include "logging/logStream.hpp"
#include "memory/resourceArea.hpp"
+ #include "prims/foreign_globals.inline.hpp"
#include "prims/universalNativeInvoker.hpp"
+ #include "runtime/sharedRuntime.hpp"
+ #include "runtime/stubCodeGenerator.hpp"
+ #include "utilities/formatBuffer.hpp"
#define __ _masm->
- void ProgrammableInvoker::Generator::generate() {
- __ enter();
+ class NativeInvokerGenerator : public StubCodeGenerator {
+ BasicType* _signature;
+ int _num_args;
+ BasicType _ret_bt;
- // Put the context pointer in ebx/rbx - it's going to be heavily used below both before and after the call
- Register ctxt_reg = rbx;
- Register used_regs[] = { ctxt_reg, rcx, rsi, rdi };
- GrowableArray<Register> preserved_regs;
+ const ABIDescriptor& _abi;
+ const GrowableArray<VMReg>& _input_registers;
+ const GrowableArray<VMReg>& _output_registers;
- for (size_t i = 0; i < sizeof(used_regs)/sizeof(Register); i++) {
- Register used_reg = used_regs[i];
- if (!_abi->is_volatile_reg(used_reg)) {
- preserved_regs.push(used_reg);
- }
+ 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) {
}
- __ block_comment("init_and_alloc_stack");
+ void generate();
- for (int i = 0; i < preserved_regs.length(); i++) {
- __ push(preserved_regs.at(i));
+ int frame_complete() const {
+ return _frame_complete;
}
- __ movptr(ctxt_reg, c_rarg0); // FIXME c args? or java?
+ int framesize() const {
+ return (_framesize >> (LogBytesPerWord - LogBytesPerInt));
+ }
- __ block_comment("allocate_stack");
- __ movptr(rcx, Address(ctxt_reg, (int) _layout->stack_args_bytes));
- __ subptr(rsp, rcx);
- __ andptr(rsp, -_abi->_stack_alignment_bytes);
+ OopMapSet* oop_maps() const {
+ return _oop_maps;
+ }
+ };
- // Note: rcx is used below!
+ 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");
- __ block_comment("load_arguments");
+ RuntimeStub* stub =
+ RuntimeStub::new_runtime_stub("nep_invoker_blob",
+ &code,
+ g.frame_complete(),
+ g.framesize(),
+ g.oop_maps(), false);
- __ shrptr(rcx, LogBytesPerWord); // bytes -> words
- __ movptr(rsi, Address(ctxt_reg, (int) _layout->stack_args));
- __ movptr(rdi, rsp);
- __ rep_mov();
+ if (TraceNativeInvokers) {
+ stub->print_on(tty);
+ }
+ return stub;
+ }
+
+ void NativeInvokerGenerator::generate() {
+ enum layout {
+ rbp_off,
+ rbp_off2,
+ return_off,
+ return_off2,
+ framesize_base // inclusive of return address
+ // The following are also computed dynamically:
+ // shadow space
+ // spill area
+ // out arg area (e.g. for stack args)
+ };
- for (int i = 0; i < _abi->_vector_argument_registers.length(); i++) {
- // [1] -> 64 bit -> xmm
- // [2] -> 128 bit -> xmm
- // [4] -> 256 bit -> ymm
- // [8] -> 512 bit -> zmm
+ Register shufffle_reg = rbx;
+ JavaCallConv in_conv;
+ NativeCallConv out_conv(_input_registers);
+ ArgumentShuffle arg_shuffle(_signature, _num_args, _signature, _num_args, &in_conv, &out_conv, shufffle_reg->as_VMReg());
- XMMRegister reg = _abi->_vector_argument_registers.at(i);
- size_t offs = _layout->arguments_vector + i * xmm_reg_size;
- __ movdqu(reg, Address(ctxt_reg, (int)offs));
+ #ifdef ASSERT
+ LogTarget(Trace, panama) lt;
+ if (lt.is_enabled()) {
+ ResourceMark rm;
+ LogStream ls(lt);
+ arg_shuffle.print_on(&ls);
}
+ #endif
- for (int i = 0; i < _abi->_integer_argument_registers.length(); i++) {
- size_t offs = _layout->arguments_integer + i * sizeof(uintptr_t);
- __ movptr(_abi->_integer_argument_registers.at(i), Address(ctxt_reg, (int)offs));
+ // in bytes
+ int allocated_frame_size = 0;
+ if (_needs_return_buffer) {
+ allocated_frame_size += 8; // store address
}
+ allocated_frame_size += arg_shuffle.out_arg_stack_slots() << LogBytesPerInt;
+ allocated_frame_size += _abi._shadow_space_bytes;
- if (_abi->_shadow_space_bytes != 0) {
- __ block_comment("allocate shadow space for argument register spill");
- __ subptr(rsp, _abi->_shadow_space_bytes);
+ int ret_buf_addr_rsp_offset = -1;
+ if (_needs_return_buffer) {
+ // the above
+ ret_buf_addr_rsp_offset = allocated_frame_size - 8;
}
- // call target function
- __ block_comment("call target function");
- __ call(Address(ctxt_reg, (int) _layout->arguments_next_pc));
+ // when we don't use a return buffer we need to spill the return value around our slowpath calls
+ // when we use a return buffer case this SHOULD be unused.
+ RegSpiller out_reg_spiller(_output_registers);
+ int spill_rsp_offset = -1;
- if (_abi->_shadow_space_bytes != 0) {
- __ block_comment("pop shadow space");
- __ addptr(rsp, _abi->_shadow_space_bytes);
+ if (!_needs_return_buffer) {
+ spill_rsp_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;
}
+ allocated_frame_size = align_up(allocated_frame_size, 16);
+ // _framesize is in 32-bit stack slots:
+ _framesize += framesize_base + (allocated_frame_size >> LogBytesPerInt);
+ assert(is_even(_framesize/2), "sp not 16-byte aligned");
+
+ _oop_maps = new OopMapSet();
+ address start = __ pc();
+
+ __ enter();
- __ 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);
- __ movptr(Address(ctxt_reg, offs), _abi->_integer_return_registers.at(i));
+ // return address and rbp are already in place
+ __ subptr(rsp, allocated_frame_size); // prolog
+
+ _frame_complete = __ pc() - start;
+
+ address the_pc = __ pc();
+
+ __ block_comment("{ thread java2native");
+ __ set_last_Java_frame(rsp, rbp, (address)the_pc);
+ OopMap* map = new OopMap(_framesize, 0);
+ _oop_maps->add_gc_map(the_pc - start, map);
+
+ // State transition
+ __ movl(Address(r15_thread, JavaThread::thread_state_offset()), _thread_in_native);
+ __ block_comment("} thread java2native");
+
+ __ block_comment("{ argument shuffle");
+ arg_shuffle.generate(_masm, shufffle_reg->as_VMReg(), 0, _abi._shadow_space_bytes);
+ if (_needs_return_buffer) {
+ // spill our return buffer address
+ assert(ret_buf_addr_rsp_offset != -1, "no return buffer addr spill");
+ __ movptr(Address(rsp, ret_buf_addr_rsp_offset), _abi._ret_buf_addr_reg);
+ }
+ __ block_comment("} argument shuffle");
+
+ __ call(_abi._target_addr_reg);
+ // this call is assumed not to have killed r15_thread
+
+ if (!_needs_return_buffer) {
+ // FIXME: this assumes we return in rax/xmm0, which might not be the case
+ // Unpack native results.
+ switch (_ret_bt) {
+ case T_BOOLEAN: __ c2bool(rax); break;
+ case T_CHAR : __ movzwl(rax, rax); break;
+ case T_BYTE : __ sign_extend_byte (rax); break;
+ case T_SHORT : __ sign_extend_short(rax); break;
+ case T_INT : /* nothing to do */ break;
+ case T_DOUBLE :
+ case T_FLOAT :
+ // Result is in xmm0 we'll save as needed
+ break;
+ case T_VOID: break;
+ case T_LONG: break;
+ default : ShouldNotReachHere();
+ }
+ } else {
+ assert(ret_buf_addr_rsp_offset != -1, "no return buffer addr spill");
+ __ movptr(rscratch1, Address(rsp, ret_buf_addr_rsp_offset));
+ int offset = 0;
+ for (int i = 0; i < _output_registers.length(); i++) {
+ VMReg reg = _output_registers.at(i);
+ if (reg->is_Register()) {
+ __ movptr(Address(rscratch1, offset), reg->as_Register());
+ offset += 8;
+ } else if (reg->is_XMMRegister()) {
+ __ movdqu(Address(rscratch1, offset), reg->as_XMMRegister());
+ offset += 16;
+ } else {
+ ShouldNotReachHere();
+ }
+ }
}
- for (int i = 0; i < _abi->_vector_return_registers.length(); i++) {
- // [1] -> 64 bit -> xmm
- // [2] -> 128 bit -> xmm (SSE)
- // [4] -> 256 bit -> ymm (AVX)
- // [8] -> 512 bit -> zmm (AVX-512, aka AVX3)
+ __ block_comment("{ thread native2java");
+ __ restore_cpu_control_state_after_jni();
- XMMRegister reg = _abi->_vector_return_registers.at(i);
- size_t offs = _layout->returns_vector + i * xmm_reg_size;
- __ movdqu(Address(ctxt_reg, (int)offs), reg);
+ __ movl(Address(r15_thread, JavaThread::thread_state_offset()), _thread_in_native_trans);
+
+ // Force this write out before the read below
+ __ membar(Assembler::Membar_mask_bits(
+ Assembler::LoadLoad | Assembler::LoadStore |
+ Assembler::StoreLoad | Assembler::StoreStore));
+
+ Label L_after_safepoint_poll;
+ Label L_safepoint_poll_slow_path;
+
+ __ safepoint_poll(L_safepoint_poll_slow_path, r15_thread, true /* at_return */, false /* in_nmethod */);
+ __ cmpl(Address(r15_thread, JavaThread::suspend_flags_offset()), 0);
+ __ jcc(Assembler::notEqual, L_safepoint_poll_slow_path);
+
+ __ bind(L_after_safepoint_poll);
+
+ // change thread state
+ __ movl(Address(r15_thread, JavaThread::thread_state_offset()), _thread_in_Java);
+
+ __ block_comment("reguard stack check");
+ Label L_reguard;
+ Label L_after_reguard;
+ __ cmpl(Address(r15_thread, JavaThread::stack_guard_state_offset()), StackOverflow::stack_guard_yellow_reserved_disabled);
+ __ jcc(Assembler::equal, L_reguard);
+ __ bind(L_after_reguard);
+
+ __ reset_last_Java_frame(r15_thread, true);
+ __ block_comment("} thread native2java");
+
+ __ leave(); // required for proper stackwalking of RuntimeStub frame
+ __ ret(0);
+
+ //////////////////////////////////////////////////////////////////////////////
+
+ __ block_comment("{ L_safepoint_poll_slow_path");
+ __ bind(L_safepoint_poll_slow_path);
+ __ vzeroupper();
+
+ if(!_needs_return_buffer) {
+ out_reg_spiller.generate_spill(_masm, spill_rsp_offset);
}
- for (size_t i = 0; i < _abi->_X87_return_registers_noof; i++) {
- size_t offs = _layout->returns_x87 + i * (sizeof(long double));
- __ fstp_x(Address(ctxt_reg, (int)offs)); //pop ST(0)
+ __ mov(c_rarg0, r15_thread);
+ __ mov(r12, rsp); // remember sp
+ __ subptr(rsp, frame::arg_reg_save_area_bytes); // windows
+ __ andptr(rsp, -16); // align stack as required by ABI
+ __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans)));
+ __ mov(rsp, r12); // restore sp
+ __ reinit_heapbase();
+
+ if(!_needs_return_buffer) {
+ out_reg_spiller.generate_fill(_masm, spill_rsp_offset);
}
- // Restore backed up preserved register
- for (int i = 0; i < preserved_regs.length(); i++) {
- __ movptr(preserved_regs.at(i), Address(rbp, -(int)(sizeof(uintptr_t) * (i + 1))));
+ __ jmp(L_after_safepoint_poll);
+ __ block_comment("} L_safepoint_poll_slow_path");
+
+ //////////////////////////////////////////////////////////////////////////////
+
+ __ block_comment("{ L_reguard");
+ __ bind(L_reguard);
+ __ vzeroupper();
+
+ if(!_needs_return_buffer) {
+ out_reg_spiller.generate_spill(_masm, spill_rsp_offset);
}
- __ leave();
- __ ret(0);
+ __ mov(r12, rsp); // remember sp
+ __ subptr(rsp, frame::arg_reg_save_area_bytes); // windows
+ __ andptr(rsp, -16); // align stack as required by ABI
+ __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, SharedRuntime::reguard_yellow_pages)));
+ __ mov(rsp, r12); // restore sp
+ __ reinit_heapbase();
- __ flush();
- }
+ if(!_needs_return_buffer) {
+ out_reg_spiller.generate_fill(_masm, spill_rsp_offset);
+ }
- 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);
+ __ jmp(L_after_reguard);
- BufferBlob* _invoke_native_blob = BufferBlob::create("invoke_native_blob", native_invoker_size);
+ __ block_comment("} L_reguard");
- CodeBuffer code2(_invoke_native_blob);
- ProgrammableInvoker::Generator g2(&code2, &abi, &layout);
- g2.generate();
- code2.log_section_sizes("InvokeNativeBlob");
+ //////////////////////////////////////////////////////////////////////////////
- return _invoke_native_blob->code_begin();
+ __ flush();
}
< prev index next >