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                 baseAddress(),
160                 unboxAddress(),
161                 vmStore(r8, long.class)
162             },
163             { vmStore(r9, int.class) },
164             { vmStore(stackStorage(0), int.class) },
165             { vmStore(stackStorage(1), double.class) },
166             { vmStore(stackStorage(2), double.class) },
167             { vmStore(stackStorage(3), double.class) },
168             { vmStore(stackStorage(4), int.class) },
169             { vmStore(stackStorage(5), int.class) },
170             { vmStore(stackStorage(6), int.class) }
171         });
172 
173         checkReturnBindings(callingSequence, new Binding[]{});
174     }
175 
176     @Test
177     public void testAbiExampleVarargs() {
178         MethodType mt = MethodType.methodType(void.class,
179                 int.class, double.class, int.class, double.class, double.class);
180         FunctionDescriptor fd = FunctionDescriptor.ofVoid(
181                 C_INT, C_DOUBLE, asVarArg(C_INT), asVarArg(C_DOUBLE), asVarArg(C_DOUBLE));
182         CallArranger.Bindings bindings = CallArranger.getBindings(mt, fd, false);
183 
184         assertFalse(bindings.isInMemoryReturn);
185         CallingSequence callingSequence = bindings.callingSequence;
186         assertEquals(callingSequence.methodType(), mt);
187         assertEquals(callingSequence.functionDesc(), fd);
188 
189         checkArgumentBindings(callingSequence, new Binding[][]{
190             { vmStore(rcx, int.class) },
191             { vmStore(xmm1, double.class) },
192             { vmStore(r8, int.class) },
193             { dup(), vmStore(r9, double.class), vmStore(xmm3, double.class) },
194             { vmStore(stackStorage(0), double.class) },
195         });
196 
197         checkReturnBindings(callingSequence, new Binding[]{});
198     }
199 
200     /**
201      * struct s {
202      *   uint64_t u0;
203      * } s;
204      *
205      * void m(struct s s);
206      *
207      * m(s);
208      */
209     @Test
210     public void testStructRegister() {
211         MemoryLayout struct = MemoryLayout.structLayout(C_LONG_LONG);
212 
213         MethodType mt = MethodType.methodType(void.class, MemorySegment.class);
214         FunctionDescriptor fd = FunctionDescriptor.ofVoid(struct);
215         CallArranger.Bindings bindings = CallArranger.getBindings(mt, fd, false);
216 
217         assertFalse(bindings.isInMemoryReturn);
218         CallingSequence callingSequence = bindings.callingSequence;
219         assertEquals(callingSequence.methodType(), mt);
220         assertEquals(callingSequence.functionDesc(), fd);
221 
222         checkArgumentBindings(callingSequence, new Binding[][]{
223             { bufferLoad(0, long.class), vmStore(rcx, long.class) }
224         });
225 
226         checkReturnBindings(callingSequence, new Binding[]{});
227     }
228 
229     /**
230      * struct s {
231      *   uint64_t u0, u1;
232      * } s;
233      *
234      * void m(struct s s);
235      *
236      * m(s);
237      */
238     @Test
239     public void testStructReference() {
240         MemoryLayout struct = MemoryLayout.structLayout(C_LONG_LONG, C_LONG_LONG);
241 
242         MethodType mt = MethodType.methodType(void.class, MemorySegment.class);
243         FunctionDescriptor fd = FunctionDescriptor.ofVoid(struct);
244         CallArranger.Bindings bindings = CallArranger.getBindings(mt, fd, false);
245 
246         assertFalse(bindings.isInMemoryReturn);
247         CallingSequence callingSequence = bindings.callingSequence;
248         assertEquals(callingSequence.methodType(), mt);
249         assertEquals(callingSequence.functionDesc(), fd);
250 
251         checkArgumentBindings(callingSequence, new Binding[][]{
252             {
253                 copy(struct),
254                 baseAddress(),
255                 unboxAddress(),
256                 vmStore(rcx, long.class)
257             }
258         });
259 
260         checkReturnBindings(callingSequence, new Binding[]{});
261     }
262 
263     /**
264      * typedef void (*f)(void);
265      *
266      * void m(f f);
267      * void f_impl(void);
268      *
269      * m(f_impl);
270      */
271     @Test
272     public void testMemoryAddress() {
273         MethodType mt = MethodType.methodType(void.class, MemoryAddress.class);
274         FunctionDescriptor fd = FunctionDescriptor.ofVoid(C_POINTER);
275         CallArranger.Bindings bindings = CallArranger.getBindings(mt, fd, false);
276 
277         assertFalse(bindings.isInMemoryReturn);
278         CallingSequence callingSequence = bindings.callingSequence;
279         assertEquals(callingSequence.methodType(), mt);
280         assertEquals(callingSequence.functionDesc(), fd);
281 
282         checkArgumentBindings(callingSequence, new Binding[][]{
283             { unboxAddress(), vmStore(rcx, long.class) }
284         });
285 
286         checkReturnBindings(callingSequence, new Binding[]{});
287     }
288 
289     @Test
290     public void testReturnRegisterStruct() {
291         MemoryLayout struct = MemoryLayout.structLayout(C_LONG_LONG);
292 
293         MethodType mt = MethodType.methodType(MemorySegment.class);
294         FunctionDescriptor fd = FunctionDescriptor.of(struct);
295         CallArranger.Bindings bindings = CallArranger.getBindings(mt, fd, false);
296 
297         assertFalse(bindings.isInMemoryReturn);
298         CallingSequence callingSequence = bindings.callingSequence;
299         assertEquals(callingSequence.methodType(), mt);
300         assertEquals(callingSequence.functionDesc(), fd);
301 
302         checkArgumentBindings(callingSequence, new Binding[][]{});
303 
304         checkReturnBindings(callingSequence,
305             new Binding[]{ allocate(struct),
306                 dup(),
307                 vmLoad(rax, long.class),
308                 bufferStore(0, long.class) });
309     }
310 
311     @Test
312     public void testIMR() {
313         MemoryLayout struct = MemoryLayout.structLayout(C_LONG_LONG, C_LONG_LONG);
314 
315         MethodType mt = MethodType.methodType(MemorySegment.class);
316         FunctionDescriptor fd = FunctionDescriptor.of(struct);
317         CallArranger.Bindings bindings = CallArranger.getBindings(mt, fd, false);
318 
319         assertTrue(bindings.isInMemoryReturn);
320         CallingSequence callingSequence = bindings.callingSequence;
321         assertEquals(callingSequence.methodType(), MethodType.methodType(void.class, MemoryAddress.class));
322         assertEquals(callingSequence.functionDesc(), FunctionDescriptor.ofVoid(C_POINTER));
323 
324         checkArgumentBindings(callingSequence, new Binding[][]{
325             { unboxAddress(), vmStore(rcx, long.class) }
326         });
327 
328         checkReturnBindings(callingSequence, new Binding[]{});
329     }
330 
331     @Test
332     public void testStackStruct() {
333         MemoryLayout struct = MemoryLayout.structLayout(C_POINTER, C_DOUBLE, C_INT);
334 
335         MethodType mt = MethodType.methodType(void.class,
336             MemorySegment.class, int.class, double.class, MemoryAddress.class,
337             MemorySegment.class, int.class, double.class, MemoryAddress.class,
338             MemorySegment.class, int.class, double.class, MemoryAddress.class,
339             MemorySegment.class, int.class, double.class, MemoryAddress.class);
340         FunctionDescriptor fd = FunctionDescriptor.ofVoid(
341             struct, C_INT, C_DOUBLE, C_POINTER,
342             struct, C_INT, C_DOUBLE, C_POINTER,
343             struct, C_INT, C_DOUBLE, C_POINTER,
344             struct, C_INT, C_DOUBLE, C_POINTER);
345         CallArranger.Bindings bindings = CallArranger.getBindings(mt, fd, false);
346 
347         assertFalse(bindings.isInMemoryReturn);
348         CallingSequence callingSequence = bindings.callingSequence;
349         assertEquals(callingSequence.methodType(), mt);
350         assertEquals(callingSequence.functionDesc(), fd);
351 
352         checkArgumentBindings(callingSequence, new Binding[][]{
353             { copy(struct), baseAddress(), unboxAddress(), vmStore(rcx, long.class) },
354             { vmStore(rdx, int.class) },
355             { vmStore(xmm2, double.class) },
356             { unboxAddress(), vmStore(r9, long.class) },
357             { copy(struct), baseAddress(), unboxAddress(), vmStore(stackStorage(0), long.class) },
358             { vmStore(stackStorage(1), int.class) },
359             { vmStore(stackStorage(2), double.class) },
360             { unboxAddress(), vmStore(stackStorage(3), long.class) },
361             { copy(struct), baseAddress(), unboxAddress(), vmStore(stackStorage(4), long.class) },
362             { vmStore(stackStorage(5), int.class) },
363             { vmStore(stackStorage(6), double.class) },
364             { unboxAddress(), vmStore(stackStorage(7), long.class) },
365             { copy(struct), baseAddress(), unboxAddress(), vmStore(stackStorage(8), long.class) },
366             { vmStore(stackStorage(9), int.class) },
367             { vmStore(stackStorage(10), double.class) },
368             { unboxAddress(), vmStore(stackStorage(11), long.class) },
369         });
370 
371         checkReturnBindings(callingSequence, new Binding[]{});
372     }
373 }