1 /*
  2  * Copyright (c) 2020, 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  * @modules jdk.incubator.foreign/jdk.internal.foreign
 28  *          jdk.incubator.foreign/jdk.internal.foreign.abi
 29  *          jdk.incubator.foreign/jdk.internal.foreign.abi.x64
 30  *          jdk.incubator.foreign/jdk.internal.foreign.abi.x64.windows
 31  * @build CallArrangerTestBase
 32  * @run testng TestWindowsCallArranger
 33  */
 34 
 35 import jdk.incubator.foreign.FunctionDescriptor;
 36 import jdk.incubator.foreign.MemoryAddress;
 37 import jdk.incubator.foreign.MemoryLayout;
 38 import jdk.incubator.foreign.MemorySegment;
 39 import jdk.internal.foreign.abi.Binding;
 40 import jdk.internal.foreign.abi.CallingSequence;
 41 import jdk.internal.foreign.abi.x64.windows.CallArranger;
 42 import org.testng.annotations.Test;
 43 
 44 import java.lang.invoke.MethodType;
 45 
 46 import static jdk.internal.foreign.PlatformLayouts.Win64.*;
 47 import static jdk.internal.foreign.abi.Binding.*;
 48 import static jdk.internal.foreign.abi.Binding.copy;
 49 import static jdk.internal.foreign.abi.x64.X86_64Architecture.*;
 50 import static org.testng.Assert.*;
 51 
 52 public class TestWindowsCallArranger extends CallArrangerTestBase {
 53 
 54     @Test
 55     public void testEmpty() {
 56         MethodType mt = MethodType.methodType(void.class);
 57         FunctionDescriptor fd = FunctionDescriptor.ofVoid();
 58         CallArranger.Bindings bindings = CallArranger.getBindings(mt, fd, false);
 59 
 60         assertFalse(bindings.isInMemoryReturn);
 61         CallingSequence callingSequence = bindings.callingSequence;
 62         assertEquals(callingSequence.methodType(), mt);
 63         assertEquals(callingSequence.functionDesc(), fd);
 64 
 65         checkArgumentBindings(callingSequence, new Binding[][]{});
 66         checkReturnBindings(callingSequence, new Binding[]{});
 67     }
 68 
 69     @Test
 70     public void testIntegerRegs() {
 71         MethodType mt = MethodType.methodType(void.class, int.class, int.class, int.class, int.class);
 72         FunctionDescriptor fd = FunctionDescriptor.ofVoid(C_INT, C_INT, C_INT, C_INT);
 73         CallArranger.Bindings bindings = CallArranger.getBindings(mt, fd, false);
 74 
 75         assertFalse(bindings.isInMemoryReturn);
 76         CallingSequence callingSequence = bindings.callingSequence;
 77         assertEquals(callingSequence.methodType(), mt);
 78         assertEquals(callingSequence.functionDesc(), fd);
 79 
 80         checkArgumentBindings(callingSequence, new Binding[][]{
 81             { vmStore(rcx, int.class) },
 82             { vmStore(rdx, int.class) },
 83             { vmStore(r8, int.class) },
 84             { vmStore(r9, int.class) }
 85         });
 86 
 87         checkReturnBindings(callingSequence, new Binding[]{});
 88     }
 89 
 90     @Test
 91     public void testDoubleRegs() {
 92         MethodType mt = MethodType.methodType(void.class, double.class, double.class, double.class, double.class);
 93         FunctionDescriptor fd = FunctionDescriptor.ofVoid(C_DOUBLE, C_DOUBLE, C_DOUBLE, C_DOUBLE);
 94         CallArranger.Bindings bindings = CallArranger.getBindings(mt, fd, false);
 95 
 96         assertFalse(bindings.isInMemoryReturn);
 97         CallingSequence callingSequence = bindings.callingSequence;
 98         assertEquals(callingSequence.methodType(), mt);
 99         assertEquals(callingSequence.functionDesc(), fd);
100 
101         checkArgumentBindings(callingSequence, new Binding[][]{
102             { vmStore(xmm0, double.class) },
103             { vmStore(xmm1, double.class) },
104             { vmStore(xmm2, double.class) },
105             { vmStore(xmm3, double.class) }
106         });
107 
108         checkReturnBindings(callingSequence, new Binding[]{});
109     }
110 
111     @Test
112     public void testMixed() {
113         MethodType mt = MethodType.methodType(void.class,
114                 long.class, long.class, float.class, float.class, long.class, long.class, float.class, float.class);
115         FunctionDescriptor fd = FunctionDescriptor.ofVoid(
116                 C_LONG_LONG, C_LONG_LONG, C_FLOAT, C_FLOAT, C_LONG_LONG, C_LONG_LONG, C_FLOAT, C_FLOAT);
117         CallArranger.Bindings bindings = CallArranger.getBindings(mt, fd, false);
118 
119         assertFalse(bindings.isInMemoryReturn);
120         CallingSequence callingSequence = bindings.callingSequence;
121         assertEquals(callingSequence.methodType(), mt);
122         assertEquals(callingSequence.functionDesc(), fd);
123 
124         checkArgumentBindings(callingSequence, new Binding[][]{
125             { vmStore(rcx, long.class) },
126             { vmStore(rdx, long.class) },
127             { vmStore(xmm2, float.class) },
128             { vmStore(xmm3, float.class) },
129             { vmStore(stackStorage(0), long.class) },
130             { vmStore(stackStorage(1), long.class) },
131             { vmStore(stackStorage(2), float.class) },
132             { vmStore(stackStorage(3), float.class) }
133         });
134 
135         checkReturnBindings(callingSequence, new Binding[]{});
136     }
137 
138     @Test
139     public void testAbiExample() {
140         MemoryLayout structLayout = MemoryLayout.structLayout(C_INT, C_INT, C_DOUBLE);
141         MethodType mt = MethodType.methodType(void.class,
142                 int.class, int.class, MemorySegment.class, int.class, int.class,
143                 double.class, double.class, double.class, int.class, int.class, int.class);
144         FunctionDescriptor fd = FunctionDescriptor.ofVoid(
145                 C_INT, C_INT, structLayout, C_INT, C_INT,
146                 C_DOUBLE, C_DOUBLE, C_DOUBLE, C_INT, C_INT, C_INT);
147         CallArranger.Bindings bindings = CallArranger.getBindings(mt, fd, false);
148 
149         assertFalse(bindings.isInMemoryReturn);
150         CallingSequence callingSequence = bindings.callingSequence;
151         assertEquals(callingSequence.methodType(), mt);
152         assertEquals(callingSequence.functionDesc(), fd);
153 
154         checkArgumentBindings(callingSequence, new Binding[][]{
155             { vmStore(rcx, int.class) },
156             { vmStore(rdx, int.class) },
157             {
158                 copy(structLayout),
159                 unboxAddress(MemorySegment.class),
160                 vmStore(r8, long.class)
161             },
162             { vmStore(r9, int.class) },
163             { vmStore(stackStorage(0), int.class) },
164             { vmStore(stackStorage(1), double.class) },
165             { vmStore(stackStorage(2), double.class) },
166             { vmStore(stackStorage(3), double.class) },
167             { vmStore(stackStorage(4), int.class) },
168             { vmStore(stackStorage(5), int.class) },
169             { vmStore(stackStorage(6), int.class) }
170         });
171 
172         checkReturnBindings(callingSequence, new Binding[]{});
173     }
174 
175     @Test
176     public void testAbiExampleVarargs() {
177         MethodType mt = MethodType.methodType(void.class,
178                 int.class, double.class, int.class, double.class, double.class);
179         FunctionDescriptor fd = FunctionDescriptor.ofVoid(
180                 C_INT, C_DOUBLE).asVariadic(C_INT, C_DOUBLE, C_DOUBLE);
181         CallArranger.Bindings bindings = CallArranger.getBindings(mt, fd, false);
182 
183         assertFalse(bindings.isInMemoryReturn);
184         CallingSequence callingSequence = bindings.callingSequence;
185         assertEquals(callingSequence.methodType(), mt);
186         assertEquals(callingSequence.functionDesc(), fd);
187 
188         checkArgumentBindings(callingSequence, new Binding[][]{
189             { vmStore(rcx, int.class) },
190             { vmStore(xmm1, double.class) },
191             { vmStore(r8, int.class) },
192             { dup(), vmStore(r9, double.class), vmStore(xmm3, double.class) },
193             { vmStore(stackStorage(0), double.class) },
194         });
195 
196         checkReturnBindings(callingSequence, new Binding[]{});
197     }
198 
199     /**
200      * struct s {
201      *   uint64_t u0;
202      * } s;
203      *
204      * void m(struct s s);
205      *
206      * m(s);
207      */
208     @Test
209     public void testStructRegister() {
210         MemoryLayout struct = MemoryLayout.structLayout(C_LONG_LONG);
211 
212         MethodType mt = MethodType.methodType(void.class, MemorySegment.class);
213         FunctionDescriptor fd = FunctionDescriptor.ofVoid(struct);
214         CallArranger.Bindings bindings = CallArranger.getBindings(mt, fd, false);
215 
216         assertFalse(bindings.isInMemoryReturn);
217         CallingSequence callingSequence = bindings.callingSequence;
218         assertEquals(callingSequence.methodType(), mt);
219         assertEquals(callingSequence.functionDesc(), fd);
220 
221         checkArgumentBindings(callingSequence, new Binding[][]{
222             { bufferLoad(0, long.class), vmStore(rcx, long.class) }
223         });
224 
225         checkReturnBindings(callingSequence, new Binding[]{});
226     }
227 
228     /**
229      * struct s {
230      *   uint64_t u0, u1;
231      * } s;
232      *
233      * void m(struct s s);
234      *
235      * m(s);
236      */
237     @Test
238     public void testStructReference() {
239         MemoryLayout struct = MemoryLayout.structLayout(C_LONG_LONG, C_LONG_LONG);
240 
241         MethodType mt = MethodType.methodType(void.class, MemorySegment.class);
242         FunctionDescriptor fd = FunctionDescriptor.ofVoid(struct);
243         CallArranger.Bindings bindings = CallArranger.getBindings(mt, fd, false);
244 
245         assertFalse(bindings.isInMemoryReturn);
246         CallingSequence callingSequence = bindings.callingSequence;
247         assertEquals(callingSequence.methodType(), mt);
248         assertEquals(callingSequence.functionDesc(), fd);
249 
250         checkArgumentBindings(callingSequence, new Binding[][]{
251             {
252                 copy(struct),
253                 unboxAddress(MemorySegment.class),
254                 vmStore(rcx, long.class)
255             }
256         });
257 
258         checkReturnBindings(callingSequence, new Binding[]{});
259     }
260 
261     /**
262      * typedef void (*f)(void);
263      *
264      * void m(f f);
265      * void f_impl(void);
266      *
267      * m(f_impl);
268      */
269     @Test
270     public void testMemoryAddress() {
271         MethodType mt = MethodType.methodType(void.class, MemoryAddress.class);
272         FunctionDescriptor fd = FunctionDescriptor.ofVoid(C_POINTER);
273         CallArranger.Bindings bindings = CallArranger.getBindings(mt, fd, false);
274 
275         assertFalse(bindings.isInMemoryReturn);
276         CallingSequence callingSequence = bindings.callingSequence;
277         assertEquals(callingSequence.methodType(), mt);
278         assertEquals(callingSequence.functionDesc(), fd);
279 
280         checkArgumentBindings(callingSequence, new Binding[][]{
281             { unboxAddress(), vmStore(rcx, long.class) }
282         });
283 
284         checkReturnBindings(callingSequence, new Binding[]{});
285     }
286 
287     @Test
288     public void testReturnRegisterStruct() {
289         MemoryLayout struct = MemoryLayout.structLayout(C_LONG_LONG);
290 
291         MethodType mt = MethodType.methodType(MemorySegment.class);
292         FunctionDescriptor fd = FunctionDescriptor.of(struct);
293         CallArranger.Bindings bindings = CallArranger.getBindings(mt, fd, false);
294 
295         assertFalse(bindings.isInMemoryReturn);
296         CallingSequence callingSequence = bindings.callingSequence;
297         assertEquals(callingSequence.methodType(), mt);
298         assertEquals(callingSequence.functionDesc(), fd);
299 
300         checkArgumentBindings(callingSequence, new Binding[][]{});
301 
302         checkReturnBindings(callingSequence,
303             new Binding[]{ allocate(struct),
304                 dup(),
305                 vmLoad(rax, long.class),
306                 bufferStore(0, long.class) });
307     }
308 
309     @Test
310     public void testIMR() {
311         MemoryLayout struct = MemoryLayout.structLayout(C_LONG_LONG, C_LONG_LONG);
312 
313         MethodType mt = MethodType.methodType(MemorySegment.class);
314         FunctionDescriptor fd = FunctionDescriptor.of(struct);
315         CallArranger.Bindings bindings = CallArranger.getBindings(mt, fd, false);
316 
317         assertTrue(bindings.isInMemoryReturn);
318         CallingSequence callingSequence = bindings.callingSequence;
319         assertEquals(callingSequence.methodType(), MethodType.methodType(void.class, MemoryAddress.class));
320         assertEquals(callingSequence.functionDesc(), FunctionDescriptor.ofVoid(C_POINTER));
321 
322         checkArgumentBindings(callingSequence, new Binding[][]{
323             { unboxAddress(), vmStore(rcx, long.class) }
324         });
325 
326         checkReturnBindings(callingSequence, new Binding[]{});
327     }
328 
329     @Test
330     public void testStackStruct() {
331         MemoryLayout struct = MemoryLayout.structLayout(C_POINTER, C_DOUBLE, C_INT);
332 
333         MethodType mt = MethodType.methodType(void.class,
334             MemorySegment.class, int.class, double.class, MemoryAddress.class,
335             MemorySegment.class, int.class, double.class, MemoryAddress.class,
336             MemorySegment.class, int.class, double.class, MemoryAddress.class,
337             MemorySegment.class, int.class, double.class, MemoryAddress.class);
338         FunctionDescriptor fd = FunctionDescriptor.ofVoid(
339             struct, C_INT, C_DOUBLE, C_POINTER,
340             struct, C_INT, C_DOUBLE, C_POINTER,
341             struct, C_INT, C_DOUBLE, C_POINTER,
342             struct, C_INT, C_DOUBLE, C_POINTER);
343         CallArranger.Bindings bindings = CallArranger.getBindings(mt, fd, false);
344 
345         assertFalse(bindings.isInMemoryReturn);
346         CallingSequence callingSequence = bindings.callingSequence;
347         assertEquals(callingSequence.methodType(), mt);
348         assertEquals(callingSequence.functionDesc(), fd);
349 
350         checkArgumentBindings(callingSequence, new Binding[][]{
351             { copy(struct), unboxAddress(MemorySegment.class), vmStore(rcx, long.class) },
352             { vmStore(rdx, int.class) },
353             { vmStore(xmm2, double.class) },
354             { unboxAddress(), vmStore(r9, long.class) },
355             { copy(struct), unboxAddress(MemorySegment.class), vmStore(stackStorage(0), long.class) },
356             { vmStore(stackStorage(1), int.class) },
357             { vmStore(stackStorage(2), double.class) },
358             { unboxAddress(), vmStore(stackStorage(3), long.class) },
359             { copy(struct), unboxAddress(MemorySegment.class), vmStore(stackStorage(4), long.class) },
360             { vmStore(stackStorage(5), int.class) },
361             { vmStore(stackStorage(6), double.class) },
362             { unboxAddress(), vmStore(stackStorage(7), long.class) },
363             { copy(struct), unboxAddress(MemorySegment.class), vmStore(stackStorage(8), long.class) },
364             { vmStore(stackStorage(9), int.class) },
365             { vmStore(stackStorage(10), double.class) },
366             { unboxAddress(), vmStore(stackStorage(11), long.class) },
367         });
368 
369         checkReturnBindings(callingSequence, new Binding[]{});
370     }
371 }