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