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
 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   Address slot = __ legitimize_address(Address(sp, layout.stack_args), wordSize, rscratch2);
 75   __ str(rscratch1, slot);
 76 
 77   // Call upcall helper
 78   __ ldr(c_rarg0, rec_adr);
 79   __ mov(c_rarg1, sp);
 80   __ movptr(rscratch1, CAST_FROM_FN_PTR(uint64_t, ProgrammableUpcallHandler::attach_thread_and_do_upcall));
 81   __ blr(rscratch1);
 82 
 83   for (int i = 0; i < abi._integer_return_registers.length(); i++) {
 84     ssize_t offs = layout.returns_integer + i * sizeof(uintptr_t);
 85     __ ldr(abi._integer_return_registers.at(i), Address(sp, offs));
 86   }
 87 
 88   for (int i = 0; i < abi._vector_return_registers.length(); i++) {
 89     FloatRegister reg = abi._vector_return_registers.at(i);
 90     ssize_t offs = layout.returns_vector + i * float_reg_size;
 91     __ ldrq(reg, Address(sp, offs));
 92   }
 93 
 94   __ leave();
 95   __ ret(lr);
 96 
 97   __ flush();
 98 
 99   BufferBlob* blob = BufferBlob::create("upcall_stub", &buffer);
100 
101   return blob->code_begin();
102 }
103 
104 address ProgrammableUpcallHandler::generate_optimized_upcall_stub(jobject mh, Method* entry, jobject jabi, jobject jconv) {
105   ShouldNotCallThis();
106   return nullptr;
107 }
108 
109 bool ProgrammableUpcallHandler::supports_optimized_upcalls() {
110   return false;
111 }