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  * @enablePreview
 28  * @compile platform/PlatformLayouts.java
 29  * @modules java.base/jdk.internal.foreign
 30  *          java.base/jdk.internal.foreign.abi
 31  *          java.base/jdk.internal.foreign.abi.aarch64
 32  * @build CallArrangerTestBase
 33  * @run testng TestWindowsAArch64CallArranger
 34  */
 35 
 36 import java.lang.foreign.FunctionDescriptor;
 37 import java.lang.foreign.MemoryLayout;
 38 import java.lang.foreign.MemorySegment;
 39 import jdk.internal.foreign.abi.Binding;
 40 import jdk.internal.foreign.abi.CallingSequence;
 41 import jdk.internal.foreign.abi.LinkerOptions;
 42 import jdk.internal.foreign.abi.StubLocations;
 43 import jdk.internal.foreign.abi.VMStorage;
 44 import jdk.internal.foreign.abi.aarch64.CallArranger;
 45 import org.testng.annotations.DataProvider;
 46 import org.testng.annotations.Test;
 47 
 48 import java.lang.invoke.MethodType;
 49 
 50 import static java.lang.foreign.Linker.Option.firstVariadicArg;
 51 import static java.lang.foreign.ValueLayout.ADDRESS;
 52 import static jdk.internal.foreign.abi.Binding.*;
 53 import static jdk.internal.foreign.abi.aarch64.AArch64Architecture.*;
 54 import static jdk.internal.foreign.abi.aarch64.AArch64Architecture.Regs.*;
 55 import static platform.PlatformLayouts.AArch64.*;
 56 import static org.testng.Assert.assertEquals;
 57 import static org.testng.Assert.assertFalse;
 58 import static org.testng.Assert.assertTrue;
 59 
 60 public class TestWindowsAArch64CallArranger extends CallArrangerTestBase {
 61 
 62     private static final VMStorage TARGET_ADDRESS_STORAGE = StubLocations.TARGET_ADDRESS.storage(StorageType.PLACEHOLDER);
 63     private static final VMStorage RETURN_BUFFER_STORAGE = StubLocations.RETURN_BUFFER.storage(StorageType.PLACEHOLDER);
 64 
 65     @Test
 66     public void testWindowsArgsInRegs() {
 67         MethodType mt = MethodType.methodType(void.class, int.class, int.class, float.class, double.class);
 68         FunctionDescriptor fd = FunctionDescriptor.ofVoid(C_INT, C_INT, C_FLOAT, C_DOUBLE);
 69         CallArranger.Bindings bindings = CallArranger.WINDOWS.getBindings(mt, fd, false);
 70 
 71         assertFalse(bindings.isInMemoryReturn());
 72         CallingSequence callingSequence = bindings.callingSequence();
 73         assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class));
 74         assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS));
 75 
 76         checkArgumentBindings(callingSequence, new Binding[][]{
 77             { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) },
 78             { vmStore(r0, int.class) },
 79             { vmStore(r1, int.class) },
 80             { vmStore(v0, float.class) },
 81             { vmStore(v1, double.class) },
 82         });
 83 
 84         checkReturnBindings(callingSequence, new Binding[]{});
 85     }
 86 
 87     @Test
 88     public void testWindowsVarArgsInRegs() {
 89         MethodType mt = MethodType.methodType(void.class, int.class, int.class, float.class, double.class);
 90         FunctionDescriptor fd = FunctionDescriptor.ofVoid(C_INT, C_INT, C_FLOAT, C_DOUBLE);
 91         FunctionDescriptor fdExpected = FunctionDescriptor.ofVoid(ADDRESS, C_INT, C_INT, C_FLOAT, C_DOUBLE);
 92         CallArranger.Bindings bindings = CallArranger.WINDOWS.getBindings(mt, fd, false, LinkerOptions.forDowncall(fd, firstVariadicArg(1)));
 93 
 94         assertFalse(bindings.isInMemoryReturn());
 95         CallingSequence callingSequence = bindings.callingSequence();
 96         assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class));
 97         assertEquals(callingSequence.functionDesc(), fdExpected);
 98 
 99         checkArgumentBindings(callingSequence, new Binding[][]{
100             { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) },
101             { vmStore(r0, int.class) },
102             { vmStore(r1, int.class) },
103             { vmStore(r2, float.class) },
104             { vmStore(r3, double.class) },
105         });
106 
107         checkReturnBindings(callingSequence, new Binding[]{});
108     }
109 
110     @Test
111     public void testWindowsArgsInRegsAndOnStack() {
112         MethodType mt = MethodType.methodType(void.class, double.class, int.class, float.class,
113                                               double.class, float.class, float.class, double.class,
114                                               float.class, float.class, float.class, int.class);
115         FunctionDescriptor fd = FunctionDescriptor.ofVoid(C_DOUBLE, C_INT, C_FLOAT,
116                                               C_DOUBLE, C_FLOAT, C_FLOAT, C_DOUBLE,
117                                               C_FLOAT, C_FLOAT, C_FLOAT, C_INT);
118         CallArranger.Bindings bindings = CallArranger.WINDOWS.getBindings(mt, fd, false);
119 
120         assertFalse(bindings.isInMemoryReturn());
121         CallingSequence callingSequence = bindings.callingSequence();
122         assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class));
123         assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS));
124 
125         checkArgumentBindings(callingSequence, new Binding[][]{
126             { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) },
127             { vmStore(v0, double.class) },
128             { vmStore(r0, int.class) },
129             { vmStore(v1, float.class) },
130             { vmStore(v2, double.class) },
131             { vmStore(v3, float.class) },
132             { vmStore(v4, float.class) },
133             { vmStore(v5, double.class) },
134             { vmStore(v6, float.class) },
135             { vmStore(v7, float.class) },
136             { vmStore(stackStorage((short) 4, 0), float.class) },
137             { vmStore(r1, int.class) },
138         });
139 
140         checkReturnBindings(callingSequence, new Binding[]{});
141     }
142 
143     @Test
144     public void testWindowsVarArgsInRegsAndOnStack() {
145         MethodType mt = MethodType.methodType(void.class, double.class, int.class, float.class,
146                                               double.class, float.class, float.class, double.class,
147                                               float.class, float.class, float.class);
148         FunctionDescriptor fd = FunctionDescriptor.ofVoid(C_DOUBLE, C_INT, C_FLOAT,
149                                               C_DOUBLE, C_FLOAT, C_FLOAT, C_DOUBLE,
150                                               C_FLOAT, C_FLOAT, C_FLOAT);
151         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);
152         CallArranger.Bindings bindings = CallArranger.WINDOWS.getBindings(mt, fd, false, LinkerOptions.forDowncall(fd, firstVariadicArg(1)));
153 
154         assertFalse(bindings.isInMemoryReturn());
155         CallingSequence callingSequence = bindings.callingSequence();
156         assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class));
157         assertEquals(callingSequence.functionDesc(), fdExpected);
158 
159         checkArgumentBindings(callingSequence, new Binding[][]{
160             { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) },
161             { vmStore(r0, double.class) },
162             { vmStore(r1, int.class) },
163             { vmStore(r2, float.class) },
164             { vmStore(r3, double.class) },
165             { vmStore(r4, float.class) },
166             { vmStore(r5, float.class) },
167             { vmStore(r6, double.class) },
168             { vmStore(r7, float.class) },
169             { vmStore(stackStorage((short) 4, 0), float.class) },
170             { vmStore(stackStorage((short) 4, 8), float.class) },
171         });
172 
173         checkReturnBindings(callingSequence, new Binding[]{});
174     }
175 
176     @Test
177     public void testWindowsHfa4FloatsInFloatRegs() {
178         MemoryLayout struct = MemoryLayout.structLayout(C_FLOAT, C_FLOAT, C_FLOAT, C_FLOAT);
179 
180         MethodType mt = MethodType.methodType(void.class, MemorySegment.class, int.class);
181         FunctionDescriptor fd = FunctionDescriptor.ofVoid(struct, C_INT);
182         CallArranger.Bindings bindings = CallArranger.WINDOWS.getBindings(mt, fd, false);
183 
184         assertFalse(bindings.isInMemoryReturn());
185         CallingSequence callingSequence = bindings.callingSequence();
186         assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class));
187         assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS));
188 
189         checkArgumentBindings(callingSequence, new Binding[][]{
190             { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) },
191             {
192                 dup(),
193                 bufferLoad(0, float.class),
194                 vmStore(v0, float.class),
195                 dup(),
196                 bufferLoad(4, float.class),
197                 vmStore(v1, float.class),
198                 dup(),
199                 bufferLoad(8, float.class),
200                 vmStore(v2, float.class),
201                 bufferLoad(12, float.class),
202                 vmStore(v3, float.class),
203             },
204             { vmStore(r0, int.class) },
205         });
206 
207         checkReturnBindings(callingSequence, new Binding[]{});
208     }
209 
210     @Test
211     public void testWindowsVariadicHfa4FloatsInIntRegs() {
212         MemoryLayout struct = MemoryLayout.structLayout(C_FLOAT, C_FLOAT, C_FLOAT, C_FLOAT);
213 
214         MethodType mt = MethodType.methodType(void.class, MemorySegment.class, int.class);
215         FunctionDescriptor fd = FunctionDescriptor.ofVoid(struct, C_INT);
216         CallArranger.Bindings bindings = CallArranger.WINDOWS.getBindings(mt, fd, false, LinkerOptions.forDowncall(fd, firstVariadicArg(0)));
217 
218         assertFalse(bindings.isInMemoryReturn());
219         CallingSequence callingSequence = bindings.callingSequence();
220         assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class));
221         assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS));
222 
223         checkArgumentBindings(callingSequence, new Binding[][]{
224             { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) },
225             {
226                 dup(),
227                 bufferLoad(0, long.class),
228                 vmStore(r0, long.class),
229                 bufferLoad(8, long.class),
230                 vmStore(r1, long.class),
231             },
232             { vmStore(r2, int.class) },
233         });
234 
235         checkReturnBindings(callingSequence, new Binding[]{});
236     }
237 
238     @Test
239     public void testWindowsHfa2DoublesInFloatRegs() {
240         MemoryLayout struct = MemoryLayout.structLayout(C_DOUBLE, C_DOUBLE);
241 
242         MethodType mt = MethodType.methodType(
243             void.class, MemorySegment.class, int.class);
244         FunctionDescriptor fd = FunctionDescriptor.ofVoid(struct, C_INT);
245         CallArranger.Bindings bindings = CallArranger.WINDOWS.getBindings(mt, fd, false);
246 
247         assertFalse(bindings.isInMemoryReturn());
248         CallingSequence callingSequence = bindings.callingSequence();
249         assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class));
250         assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS));
251 
252         checkArgumentBindings(callingSequence, new Binding[][]{
253             { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) },
254             {
255                 dup(),
256                 bufferLoad(0, double.class),
257                 vmStore(v0, double.class),
258                 bufferLoad(8, double.class),
259                 vmStore(v1, double.class),
260             },
261             { vmStore(r0, int.class) },
262         });
263 
264         checkReturnBindings(callingSequence, new Binding[]{});
265     }
266 
267     @Test
268     public void testWindowsVariadicHfa2DoublesInIntRegs() {
269         MemoryLayout struct = MemoryLayout.structLayout(C_DOUBLE, C_DOUBLE);
270 
271         MethodType mt = MethodType.methodType(
272             void.class, MemorySegment.class, int.class);
273         FunctionDescriptor fd = FunctionDescriptor.ofVoid(struct, C_INT);
274         CallArranger.Bindings bindings = CallArranger.WINDOWS.getBindings(mt, fd, false, LinkerOptions.forDowncall(fd, firstVariadicArg(0)));
275 
276         assertFalse(bindings.isInMemoryReturn());
277         CallingSequence callingSequence = bindings.callingSequence();
278         assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class));
279         assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS));
280 
281         checkArgumentBindings(callingSequence, new Binding[][]{
282             { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) },
283             {
284                 dup(),
285                 bufferLoad(0, long.class),
286                 vmStore(r0, long.class),
287                 bufferLoad(8, long.class),
288                 vmStore(r1, long.class),
289             },
290             { vmStore(r2, int.class) },
291         });
292 
293         checkReturnBindings(callingSequence, new Binding[]{});
294     }
295 
296     @Test
297     public void testWindowsHfa3DoublesInFloatRegs() {
298         MemoryLayout struct = MemoryLayout.structLayout(C_DOUBLE, C_DOUBLE, C_DOUBLE);
299 
300         MethodType mt = MethodType.methodType(
301             void.class, MemorySegment.class, int.class);
302         FunctionDescriptor fd = FunctionDescriptor.ofVoid(struct, C_INT);
303         CallArranger.Bindings bindings = CallArranger.WINDOWS.getBindings(mt, fd, false);
304 
305         assertFalse(bindings.isInMemoryReturn());
306         CallingSequence callingSequence = bindings.callingSequence();
307         assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class));
308         assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS));
309 
310         checkArgumentBindings(callingSequence, new Binding[][]{
311             { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) },
312             {
313                 dup(),
314                 bufferLoad(0, double.class),
315                 vmStore(v0, double.class),
316                 dup(),
317                 bufferLoad(8, double.class),
318                 vmStore(v1, double.class),
319                 bufferLoad(16, double.class),
320                 vmStore(v2, double.class),
321             },
322             { vmStore(r0, int.class) },
323         });
324 
325         checkReturnBindings(callingSequence, new Binding[]{});
326     }
327 
328     @Test
329     public void testWindowsVariadicHfa3DoublesAsReferenceStruct() {
330         MemoryLayout struct = MemoryLayout.structLayout(C_DOUBLE, C_DOUBLE, C_DOUBLE);
331 
332         MethodType mt = MethodType.methodType(
333             void.class, MemorySegment.class, int.class);
334         FunctionDescriptor fd = FunctionDescriptor.ofVoid(struct, C_INT);
335         CallArranger.Bindings bindings = CallArranger.WINDOWS.getBindings(mt, fd, false, LinkerOptions.forDowncall(fd, firstVariadicArg(0)));
336 
337         assertFalse(bindings.isInMemoryReturn());
338         CallingSequence callingSequence = bindings.callingSequence();
339         assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class));
340         assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS));
341 
342         checkArgumentBindings(callingSequence, new Binding[][]{
343             { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) },
344             { copy(struct), unboxAddress(), vmStore(r0, long.class) },
345             { vmStore(r1, int.class) },
346         });
347 
348         checkReturnBindings(callingSequence, new Binding[]{});
349     }
350 }