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   __ 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 
103 address ProgrammableUpcallHandler::generate_optimized_upcall_stub(jobject mh, Method* entry, jobject jabi, jobject jconv) {
104   ShouldNotCallThis();
105   return nullptr;
106 }
107 
108 bool ProgrammableUpcallHandler::supports_optimized_upcalls() {
109   return false;
110 }