1 /*
  2  * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved.
  3  * Copyright (c) 2020, 2023, Huawei Technologies Co., Ltd. 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 
 26 #include "code/vmreg.inline.hpp"
 27 #include "runtime/jniHandles.hpp"
 28 #include "runtime/jniHandles.inline.hpp"
 29 #include "oops/typeArrayOop.inline.hpp"
 30 #include "oops/oopCast.inline.hpp"
 31 #include "prims/foreignGlobals.hpp"
 32 #include "prims/foreignGlobals.inline.hpp"
 33 #include "prims/vmstorage.hpp"
 34 #include "utilities/formatBuffer.hpp"
 35 
 36 bool ABIDescriptor::is_volatile_reg(Register reg) const {
 37   return _integer_argument_registers.contains(reg)
 38          || _integer_additional_volatile_registers.contains(reg);
 39 }
 40 
 41 bool ABIDescriptor::is_volatile_reg(FloatRegister reg) const {
 42   return _float_argument_registers.contains(reg)
 43          || _float_additional_volatile_registers.contains(reg);
 44 }
 45 
 46 bool ForeignGlobals::is_foreign_linker_supported() {
 47   return true;
 48 }
 49 
 50 const ABIDescriptor ForeignGlobals::parse_abi_descriptor(jobject jabi) {
 51   oop abi_oop = JNIHandles::resolve_non_null(jabi);
 52   ABIDescriptor abi;
 53 
 54   refArrayOop inputStorage = jdk_internal_foreign_abi_ABIDescriptor::inputStorage(abi_oop);
 55   parse_register_array(inputStorage, StorageType::INTEGER, abi._integer_argument_registers, as_Register);
 56   parse_register_array(inputStorage, StorageType::FLOAT, abi._float_argument_registers, as_FloatRegister);
 57 
 58   refArrayOop outputStorage = jdk_internal_foreign_abi_ABIDescriptor::outputStorage(abi_oop);
 59   parse_register_array(outputStorage, StorageType::INTEGER, abi._integer_return_registers, as_Register);
 60   parse_register_array(outputStorage, StorageType::FLOAT, abi._float_return_registers, as_FloatRegister);
 61 
 62   refArrayOop volatileStorage = jdk_internal_foreign_abi_ABIDescriptor::volatileStorage(abi_oop);
 63   parse_register_array(volatileStorage, StorageType::INTEGER, abi._integer_additional_volatile_registers, as_Register);
 64   parse_register_array(volatileStorage, StorageType::FLOAT, abi._float_additional_volatile_registers, as_FloatRegister);
 65 
 66   abi._stack_alignment_bytes = jdk_internal_foreign_abi_ABIDescriptor::stackAlignment(abi_oop);
 67   abi._shadow_space_bytes = jdk_internal_foreign_abi_ABIDescriptor::shadowSpace(abi_oop);
 68 
 69   abi._scratch1 = parse_vmstorage(jdk_internal_foreign_abi_ABIDescriptor::scratch1(abi_oop));
 70   abi._scratch2 = parse_vmstorage(jdk_internal_foreign_abi_ABIDescriptor::scratch2(abi_oop));
 71 
 72   return abi;
 73 }
 74 
 75 int RegSpiller::pd_reg_size(VMStorage reg) {
 76   if (reg.type() == StorageType::INTEGER || reg.type() == StorageType::FLOAT) {
 77     return 8;
 78   }
 79   return 0; // stack and BAD
 80 }
 81 
 82 void RegSpiller::pd_store_reg(MacroAssembler* masm, int offset, VMStorage reg) {
 83   if (reg.type() == StorageType::INTEGER) {
 84     masm->sd(as_Register(reg), Address(sp, offset));
 85   } else if (reg.type() == StorageType::FLOAT) {
 86     masm->fsd(as_FloatRegister(reg), Address(sp, offset));
 87   } else {
 88     // stack and BAD
 89   }
 90 }
 91 
 92 void RegSpiller::pd_load_reg(MacroAssembler* masm, int offset, VMStorage reg) {
 93   if (reg.type() == StorageType::INTEGER) {
 94     masm->ld(as_Register(reg), Address(sp, offset));
 95   } else if (reg.type() == StorageType::FLOAT) {
 96     masm->fld(as_FloatRegister(reg), Address(sp, offset));
 97   } else {
 98     // stack and BAD
 99   }
100 }
101 
102 static constexpr int FP_BIAS = 0; // sender_sp_offset is 0 on RISCV
103 
104 static void move_reg64(MacroAssembler* masm, int out_stk_bias,
105                        Register from_reg, VMStorage to_reg) {
106   int out_bias = 0;
107   switch (to_reg.type()) {
108     case StorageType::INTEGER:
109       assert(to_reg.segment_mask() == REG64_MASK, "only moves to 64-bit integer registers supported");
110       masm->mv(as_Register(to_reg), from_reg);
111       break;
112     case StorageType::STACK:
113       out_bias = out_stk_bias;
114     case StorageType::FRAME_DATA: {
115       Address dest(sp, to_reg.offset() + out_bias);
116       masm->sd(from_reg, dest);
117     } break;
118     default: ShouldNotReachHere();
119   }
120 }
121 
122 static void move_stack(MacroAssembler* masm, Register tmp_reg, int in_stk_bias, int out_stk_bias,
123                        VMStorage from_reg, VMStorage to_reg) {
124   Address from_addr(fp, FP_BIAS + from_reg.offset() + in_stk_bias);
125   int out_bias = 0;
126   switch (to_reg.type()) {
127     case StorageType::INTEGER:
128       assert(to_reg.segment_mask() == REG64_MASK, "only moves to 64-bit integer registers supported");
129       masm->ld(as_Register(to_reg), from_addr);
130       break;
131     case StorageType::FLOAT:
132       assert(to_reg.segment_mask() == FP_MASK, "only moves to floating-point registers supported");
133       masm->fld(as_FloatRegister(to_reg), from_addr);
134       break;
135     case StorageType::STACK:
136       out_bias = out_stk_bias;
137     case StorageType::FRAME_DATA: {
138       masm->ld(tmp_reg, from_addr);
139       Address dest(sp, to_reg.offset() + out_bias);
140       masm->sd(tmp_reg, dest); break;
141     } break;
142     default: ShouldNotReachHere();
143   }
144 }
145 
146 static void move_fp(MacroAssembler* masm, int out_stk_bias,
147                     FloatRegister from_reg, VMStorage to_reg) {
148   switch (to_reg.type()) {
149     case StorageType::INTEGER:
150       assert(to_reg.segment_mask() == REG64_MASK, "only moves to 64-bit integer registers supported");
151       masm->fmv_x_d(as_Register(to_reg), from_reg);
152       break;
153     case StorageType::FLOAT:
154       assert(to_reg.segment_mask() == FP_MASK, "only moves to floating-point registers supported");
155       masm->fmv_d(as_FloatRegister(to_reg), from_reg); break;
156       break;
157     case StorageType::STACK: {
158       Address dest(sp, to_reg.offset() + out_stk_bias);
159       masm->fsd(from_reg, dest); break;
160     } break;
161     default: ShouldNotReachHere();
162   }
163 }
164 
165 void ArgumentShuffle::pd_generate(MacroAssembler* masm, VMStorage tmp, int in_stk_bias, int out_stk_bias) const {
166   Register tmp_reg = as_Register(tmp);
167   for (int i = 0; i < _moves.length(); i++) {
168     Move move = _moves.at(i);
169     VMStorage from_reg = move.from;
170     VMStorage to_reg   = move.to;
171 
172     switch (from_reg.type()) {
173       case StorageType::INTEGER:
174         assert(from_reg.segment_mask() == REG64_MASK, "only 64-bit integer register supported");
175         move_reg64(masm, out_stk_bias, as_Register(from_reg), to_reg);
176         break;
177       case StorageType::FLOAT:
178         assert(from_reg.segment_mask() == FP_MASK, "only floating-point register supported");
179         move_fp(masm, out_stk_bias, as_FloatRegister(from_reg), to_reg);
180         break;
181       case StorageType::STACK:
182         move_stack(masm, tmp_reg, in_stk_bias, out_stk_bias, from_reg, to_reg);
183         break;
184       default: ShouldNotReachHere();
185     }
186   }
187 }