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 objArrayOop 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 objArrayOop 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 objArrayOop 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 }