1 /*
  2  * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved.
  3  *  DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  *  This code is free software; you can redistribute it and/or modify it
  6  *  under the terms of the GNU General Public License version 2 only, as
  7  *  published by the Free Software Foundation.
  8  *
  9  *  This code is distributed in the hope that it will be useful, but WITHOUT
 10  *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11  *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 12  *  version 2 for more details (a copy is included in the LICENSE file that
 13  *  accompanied this code).
 14  *
 15  *  You should have received a copy of the GNU General Public License version
 16  *  2 along with this work; if not, write to the Free Software Foundation,
 17  *  Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 18  *
 19  *   Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 20  *  or visit www.oracle.com if you need additional information or have any
 21  *  questions.
 22  *
 23  */
 24 
 25 /*
 26  * @test
 27  * @compile platform/PlatformLayouts.java
 28  * @modules java.base/jdk.internal.foreign
 29  *          java.base/jdk.internal.foreign.abi
 30  *          java.base/jdk.internal.foreign.abi.aarch64
 31  * @build CallArrangerTestBase
 32  * @run testng TestWindowsAArch64CallArranger
 33  */
 34 
 35 import java.lang.foreign.FunctionDescriptor;
 36 import java.lang.foreign.MemoryLayout;
 37 import java.lang.foreign.MemorySegment;
 38 import jdk.internal.foreign.abi.Binding;
 39 import jdk.internal.foreign.abi.CallingSequence;
 40 import jdk.internal.foreign.abi.LinkerOptions;
 41 import jdk.internal.foreign.abi.StubLocations;
 42 import jdk.internal.foreign.abi.VMStorage;
 43 import jdk.internal.foreign.abi.aarch64.CallArranger;
 44 import org.testng.annotations.DataProvider;
 45 import org.testng.annotations.Test;
 46 
 47 import java.lang.invoke.MethodType;
 48 
 49 import static java.lang.foreign.Linker.Option.firstVariadicArg;
 50 import static java.lang.foreign.ValueLayout.ADDRESS;
 51 import static jdk.internal.foreign.abi.Binding.*;
 52 import static jdk.internal.foreign.abi.aarch64.AArch64Architecture.*;
 53 import static jdk.internal.foreign.abi.aarch64.AArch64Architecture.Regs.*;
 54 import static platform.PlatformLayouts.AArch64.*;
 55 import static org.testng.Assert.assertEquals;
 56 import static org.testng.Assert.assertFalse;
 57 import static org.testng.Assert.assertTrue;
 58 
 59 public class TestWindowsAArch64CallArranger extends CallArrangerTestBase {
 60 
 61     private static final VMStorage TARGET_ADDRESS_STORAGE = StubLocations.TARGET_ADDRESS.storage(StorageType.PLACEHOLDER);
 62     private static final VMStorage RETURN_BUFFER_STORAGE = StubLocations.RETURN_BUFFER.storage(StorageType.PLACEHOLDER);
 63 
 64     @Test
 65     public void testWindowsArgsInRegs() {
 66         MethodType mt = MethodType.methodType(void.class, int.class, int.class, float.class, double.class);
 67         FunctionDescriptor fd = FunctionDescriptor.ofVoid(C_INT, C_INT, C_FLOAT, C_DOUBLE);
 68         CallArranger.Bindings bindings = CallArranger.WINDOWS.getBindings(mt, fd, false);
 69 
 70         assertFalse(bindings.isInMemoryReturn());
 71         CallingSequence callingSequence = bindings.callingSequence();
 72         assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class));
 73         assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS));
 74 
 75         checkArgumentBindings(callingSequence, new Binding[][]{
 76             { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) },
 77             { vmStore(r0, int.class) },
 78             { vmStore(r1, int.class) },
 79             { vmStore(v0, float.class) },
 80             { vmStore(v1, double.class) },
 81         });
 82 
 83         checkReturnBindings(callingSequence, new Binding[]{});
 84     }
 85 
 86     @Test
 87     public void testWindowsVarArgsInRegs() {
 88         MethodType mt = MethodType.methodType(void.class, int.class, int.class, float.class, double.class);
 89         FunctionDescriptor fd = FunctionDescriptor.ofVoid(C_INT, C_INT, C_FLOAT, C_DOUBLE);
 90         FunctionDescriptor fdExpected = FunctionDescriptor.ofVoid(ADDRESS, C_INT, C_INT, C_FLOAT, C_DOUBLE);
 91         CallArranger.Bindings bindings = CallArranger.WINDOWS.getBindings(mt, fd, false, LinkerOptions.forDowncall(fd, firstVariadicArg(1)));
 92 
 93         assertFalse(bindings.isInMemoryReturn());
 94         CallingSequence callingSequence = bindings.callingSequence();
 95         assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class));
 96         assertEquals(callingSequence.functionDesc(), fdExpected);
 97 
 98         checkArgumentBindings(callingSequence, new Binding[][]{
 99             { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) },
100             { vmStore(r0, int.class) },
101             { vmStore(r1, int.class) },
102             { vmStore(r2, float.class) },
103             { vmStore(r3, double.class) },
104         });
105 
106         checkReturnBindings(callingSequence, new Binding[]{});
107     }
108 
109     @Test
110     public void testWindowsArgsInRegsAndOnStack() {
111         MethodType mt = MethodType.methodType(void.class, double.class, int.class, float.class,
112                                               double.class, float.class, float.class, double.class,
113                                               float.class, float.class, float.class, int.class);
114         FunctionDescriptor fd = FunctionDescriptor.ofVoid(C_DOUBLE, C_INT, C_FLOAT,
115                                               C_DOUBLE, C_FLOAT, C_FLOAT, C_DOUBLE,
116                                               C_FLOAT, C_FLOAT, C_FLOAT, C_INT);
117         CallArranger.Bindings bindings = CallArranger.WINDOWS.getBindings(mt, fd, false);
118 
119         assertFalse(bindings.isInMemoryReturn());
120         CallingSequence callingSequence = bindings.callingSequence();
121         assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class));
122         assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS));
123 
124         checkArgumentBindings(callingSequence, new Binding[][]{
125             { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) },
126             { vmStore(v0, double.class) },
127             { vmStore(r0, int.class) },
128             { vmStore(v1, float.class) },
129             { vmStore(v2, double.class) },
130             { vmStore(v3, float.class) },
131             { vmStore(v4, float.class) },
132             { vmStore(v5, double.class) },
133             { vmStore(v6, float.class) },
134             { vmStore(v7, float.class) },
135             { vmStore(stackStorage((short) 4, 0), float.class) },
136             { vmStore(r1, int.class) },
137         });
138 
139         checkReturnBindings(callingSequence, new Binding[]{});
140     }
141 
142     @Test
143     public void testWindowsVarArgsInRegsAndOnStack() {
144         MethodType mt = MethodType.methodType(void.class, double.class, int.class, float.class,
145                                               double.class, float.class, float.class, double.class,
146                                               float.class, float.class, float.class);
147         FunctionDescriptor fd = FunctionDescriptor.ofVoid(C_DOUBLE, C_INT, C_FLOAT,
148                                               C_DOUBLE, C_FLOAT, C_FLOAT, C_DOUBLE,
149                                               C_FLOAT, C_FLOAT, C_FLOAT);
150         FunctionDescriptor fdExpected = FunctionDescriptor.ofVoid(ADDRESS, C_DOUBLE, C_INT, C_FLOAT, C_DOUBLE, C_FLOAT, C_FLOAT, C_DOUBLE, C_FLOAT, C_FLOAT, C_FLOAT);
151         CallArranger.Bindings bindings = CallArranger.WINDOWS.getBindings(mt, fd, false, LinkerOptions.forDowncall(fd, firstVariadicArg(1)));
152 
153         assertFalse(bindings.isInMemoryReturn());
154         CallingSequence callingSequence = bindings.callingSequence();
155         assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class));
156         assertEquals(callingSequence.functionDesc(), fdExpected);
157 
158         checkArgumentBindings(callingSequence, new Binding[][]{
159             { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) },
160             { vmStore(r0, double.class) },
161             { vmStore(r1, int.class) },
162             { vmStore(r2, float.class) },
163             { vmStore(r3, double.class) },
164             { vmStore(r4, float.class) },
165             { vmStore(r5, float.class) },
166             { vmStore(r6, double.class) },
167             { vmStore(r7, float.class) },
168             { vmStore(stackStorage((short) 4, 0), float.class) },
169             { vmStore(stackStorage((short) 4, 8), float.class) },
170         });
171 
172         checkReturnBindings(callingSequence, new Binding[]{});
173     }
174 
175     @Test
176     public void testWindowsHfa4FloatsInFloatRegs() {
177         MemoryLayout struct = MemoryLayout.structLayout(C_FLOAT, C_FLOAT, C_FLOAT, C_FLOAT);
178 
179         MethodType mt = MethodType.methodType(void.class, MemorySegment.class, int.class);
180         FunctionDescriptor fd = FunctionDescriptor.ofVoid(struct, C_INT);
181         CallArranger.Bindings bindings = CallArranger.WINDOWS.getBindings(mt, fd, false);
182 
183         assertFalse(bindings.isInMemoryReturn());
184         CallingSequence callingSequence = bindings.callingSequence();
185         assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class));
186         assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS));
187 
188         checkArgumentBindings(callingSequence, new Binding[][]{
189             { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) },
190             {
191                 dup(),
192                 bufferLoad(0, float.class),
193                 vmStore(v0, float.class),
194                 dup(),
195                 bufferLoad(4, float.class),
196                 vmStore(v1, float.class),
197                 dup(),
198                 bufferLoad(8, float.class),
199                 vmStore(v2, float.class),
200                 bufferLoad(12, float.class),
201                 vmStore(v3, float.class),
202             },
203             { vmStore(r0, int.class) },
204         });
205 
206         checkReturnBindings(callingSequence, new Binding[]{});
207     }
208 
209     @Test
210     public void testWindowsVariadicHfa4FloatsInIntRegs() {
211         MemoryLayout struct = MemoryLayout.structLayout(C_FLOAT, C_FLOAT, C_FLOAT, C_FLOAT);
212 
213         MethodType mt = MethodType.methodType(void.class, MemorySegment.class, int.class);
214         FunctionDescriptor fd = FunctionDescriptor.ofVoid(struct, C_INT);
215         CallArranger.Bindings bindings = CallArranger.WINDOWS.getBindings(mt, fd, false, LinkerOptions.forDowncall(fd, firstVariadicArg(0)));
216 
217         assertFalse(bindings.isInMemoryReturn());
218         CallingSequence callingSequence = bindings.callingSequence();
219         assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class));
220         assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS));
221 
222         checkArgumentBindings(callingSequence, new Binding[][]{
223             { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) },
224             {
225                 dup(),
226                 bufferLoad(0, long.class),
227                 vmStore(r0, long.class),
228                 bufferLoad(8, long.class),
229                 vmStore(r1, long.class),
230             },
231             { vmStore(r2, int.class) },
232         });
233 
234         checkReturnBindings(callingSequence, new Binding[]{});
235     }
236 
237     @Test
238     public void testWindowsHfa2DoublesInFloatRegs() {
239         MemoryLayout struct = MemoryLayout.structLayout(C_DOUBLE, C_DOUBLE);
240 
241         MethodType mt = MethodType.methodType(
242             void.class, MemorySegment.class, int.class);
243         FunctionDescriptor fd = FunctionDescriptor.ofVoid(struct, C_INT);
244         CallArranger.Bindings bindings = CallArranger.WINDOWS.getBindings(mt, fd, false);
245 
246         assertFalse(bindings.isInMemoryReturn());
247         CallingSequence callingSequence = bindings.callingSequence();
248         assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class));
249         assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS));
250 
251         checkArgumentBindings(callingSequence, new Binding[][]{
252             { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) },
253             {
254                 dup(),
255                 bufferLoad(0, double.class),
256                 vmStore(v0, double.class),
257                 bufferLoad(8, double.class),
258                 vmStore(v1, double.class),
259             },
260             { vmStore(r0, int.class) },
261         });
262 
263         checkReturnBindings(callingSequence, new Binding[]{});
264     }
265 
266     @Test
267     public void testWindowsVariadicHfa2DoublesInIntRegs() {
268         MemoryLayout struct = MemoryLayout.structLayout(C_DOUBLE, C_DOUBLE);
269 
270         MethodType mt = MethodType.methodType(
271             void.class, MemorySegment.class, int.class);
272         FunctionDescriptor fd = FunctionDescriptor.ofVoid(struct, C_INT);
273         CallArranger.Bindings bindings = CallArranger.WINDOWS.getBindings(mt, fd, false, LinkerOptions.forDowncall(fd, firstVariadicArg(0)));
274 
275         assertFalse(bindings.isInMemoryReturn());
276         CallingSequence callingSequence = bindings.callingSequence();
277         assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class));
278         assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS));
279 
280         checkArgumentBindings(callingSequence, new Binding[][]{
281             { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) },
282             {
283                 dup(),
284                 bufferLoad(0, long.class),
285                 vmStore(r0, long.class),
286                 bufferLoad(8, long.class),
287                 vmStore(r1, long.class),
288             },
289             { vmStore(r2, int.class) },
290         });
291 
292         checkReturnBindings(callingSequence, new Binding[]{});
293     }
294 
295     @Test
296     public void testWindowsHfa3DoublesInFloatRegs() {
297         MemoryLayout struct = MemoryLayout.structLayout(C_DOUBLE, C_DOUBLE, C_DOUBLE);
298 
299         MethodType mt = MethodType.methodType(
300             void.class, MemorySegment.class, int.class);
301         FunctionDescriptor fd = FunctionDescriptor.ofVoid(struct, C_INT);
302         CallArranger.Bindings bindings = CallArranger.WINDOWS.getBindings(mt, fd, false);
303 
304         assertFalse(bindings.isInMemoryReturn());
305         CallingSequence callingSequence = bindings.callingSequence();
306         assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class));
307         assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS));
308 
309         checkArgumentBindings(callingSequence, new Binding[][]{
310             { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) },
311             {
312                 dup(),
313                 bufferLoad(0, double.class),
314                 vmStore(v0, double.class),
315                 dup(),
316                 bufferLoad(8, double.class),
317                 vmStore(v1, double.class),
318                 bufferLoad(16, double.class),
319                 vmStore(v2, double.class),
320             },
321             { vmStore(r0, int.class) },
322         });
323 
324         checkReturnBindings(callingSequence, new Binding[]{});
325     }
326 
327     @Test
328     public void testWindowsVariadicHfa3DoublesAsReferenceStruct() {
329         MemoryLayout struct = MemoryLayout.structLayout(C_DOUBLE, C_DOUBLE, C_DOUBLE);
330 
331         MethodType mt = MethodType.methodType(
332             void.class, MemorySegment.class, int.class);
333         FunctionDescriptor fd = FunctionDescriptor.ofVoid(struct, C_INT);
334         CallArranger.Bindings bindings = CallArranger.WINDOWS.getBindings(mt, fd, false, LinkerOptions.forDowncall(fd, firstVariadicArg(0)));
335 
336         assertFalse(bindings.isInMemoryReturn());
337         CallingSequence callingSequence = bindings.callingSequence();
338         assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class));
339         assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS));
340 
341         checkArgumentBindings(callingSequence, new Binding[][]{
342             { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) },
343             { copy(struct), unboxAddress(), vmStore(r0, long.class) },
344             { vmStore(r1, int.class) },
345         });
346 
347         checkReturnBindings(callingSequence, new Binding[]{});
348     }
349 }