1 /*
2 * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
3 * Copyright (c) 2019, Arm Limited. All rights reserved.
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 *
6 * This code is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 only, as
8 * published by the Free Software Foundation.
9 *
10 * This code is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * version 2 for more details (a copy is included in the LICENSE file that
14 * accompanied this code).
15 *
16 * You should have received a copy of the GNU General Public License version
17 * 2 along with this work; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19 *
20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21 * or visit www.oracle.com if you need additional information or have any
22 * questions.
23 */
24
25 #include "precompiled.hpp"
26 #include "asm/macroAssembler.hpp"
27 #include "memory/resourceArea.hpp"
28 #include "prims/universalUpcallHandler.hpp"
29
30 #define __ _masm->
31
32 // 1. Create buffer according to layout
33 // 2. Load registers & stack args into buffer
34 // 3. Call upcall helper with upcall handler instance & buffer pointer (C++ ABI)
35 // 4. Load return value from buffer into foreign ABI registers
36 // 5. Return
generate_upcall_stub(jobject rec,jobject jabi,jobject jlayout)37 address ProgrammableUpcallHandler::generate_upcall_stub(jobject rec, jobject jabi, jobject jlayout) {
38 ResourceMark rm;
39 const ABIDescriptor abi = ForeignGlobals::parse_abi_descriptor(jabi);
40 const BufferLayout layout = ForeignGlobals::parse_buffer_layout(jlayout);
41
42 CodeBuffer buffer("upcall_stub", 1024, upcall_stub_size);
43
44 MacroAssembler* _masm = new MacroAssembler(&buffer);
45
46 // stub code
47 __ enter();
48
49 // save pointer to JNI receiver handle into constant segment
50 Address rec_adr = InternalAddress(__ address_constant((address)rec));
51
52 assert(abi._stack_alignment_bytes % 16 == 0, "stack must be 16 byte aligned");
53
54 __ sub(sp, sp, (int) align_up(layout.buffer_size, abi._stack_alignment_bytes));
55
56 // TODO: This stub only uses registers which are caller-save in the
57 // standard C ABI. If this is called from a different ABI then
58 // we need to save registers here according to abi.is_volatile_reg.
59
60 for (int i = 0; i < abi._integer_argument_registers.length(); i++) {
61 Register reg = abi._integer_argument_registers.at(i);
62 ssize_t offset = layout.arguments_integer + i * sizeof(uintptr_t);
63 __ str(reg, Address(sp, offset));
64 }
65
66 for (int i = 0; i < abi._vector_argument_registers.length(); i++) {
67 FloatRegister reg = abi._vector_argument_registers.at(i);
68 ssize_t offset = layout.arguments_vector + i * float_reg_size;
69 __ strq(reg, Address(sp, offset));
70 }
71
72 // Capture prev stack pointer (stack arguments base)
73 __ add(rscratch1, rfp, 16); // Skip saved FP and LR
74 __ str(rscratch1, Address(sp, layout.stack_args));
75
76 // Call upcall helper
77 __ ldr(c_rarg0, rec_adr);
78 __ mov(c_rarg1, sp);
79 __ movptr(rscratch1, CAST_FROM_FN_PTR(uint64_t, ProgrammableUpcallHandler::attach_thread_and_do_upcall));
80 __ blr(rscratch1);
81
82 for (int i = 0; i < abi._integer_return_registers.length(); i++) {
83 ssize_t offs = layout.returns_integer + i * sizeof(uintptr_t);
84 __ ldr(abi._integer_return_registers.at(i), Address(sp, offs));
85 }
86
87 for (int i = 0; i < abi._vector_return_registers.length(); i++) {
88 FloatRegister reg = abi._vector_return_registers.at(i);
89 ssize_t offs = layout.returns_vector + i * float_reg_size;
90 __ ldrq(reg, Address(sp, offs));
91 }
92
93 __ leave();
94 __ ret(lr);
95
96 __ flush();
97
98 BufferBlob* blob = BufferBlob::create("upcall_stub", &buffer);
99
100 return blob->code_begin();
101 }
102