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.sysv
 31  * @build CallArrangerTestBase
 32  * @run testng TestSysVCallArranger
 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.incubator.foreign.NativeSymbol;
 40 import jdk.internal.foreign.abi.Binding;
 41 import jdk.internal.foreign.abi.CallingSequence;
 42 import jdk.internal.foreign.abi.x64.sysv.CallArranger;
 43 import org.testng.annotations.DataProvider;
 44 import org.testng.annotations.Test;
 45 
 46 import java.lang.invoke.MethodType;
 47 
 48 import static jdk.incubator.foreign.ValueLayout.ADDRESS;
 49 import static jdk.internal.foreign.PlatformLayouts.SysV.*;
 50 import static jdk.internal.foreign.abi.Binding.*;
 51 import static jdk.internal.foreign.abi.x64.X86_64Architecture.*;
 52 import static org.testng.Assert.assertEquals;
 53 import static org.testng.Assert.assertFalse;
 54 import static org.testng.Assert.assertTrue;
 55 
 56 public class TestSysVCallArranger extends CallArrangerTestBase {
 57 
 58     @Test
 59     public void testEmpty() {
 60         MethodType mt = MethodType.methodType(void.class);
 61         FunctionDescriptor fd = FunctionDescriptor.ofVoid();
 62         CallArranger.Bindings bindings = CallArranger.getBindings(mt, fd, false);
 63 
 64         assertFalse(bindings.isInMemoryReturn);
 65         CallingSequence callingSequence = bindings.callingSequence;
 66         assertEquals(callingSequence.methodType(), mt.appendParameterTypes(long.class).insertParameterTypes(0, NativeSymbol.class));
 67         assertEquals(callingSequence.functionDesc(), fd.appendArgumentLayouts(C_LONG).insertArgumentLayouts(0, ADDRESS));
 68 
 69         checkArgumentBindings(callingSequence, new Binding[][]{
 70             { unboxAddress(NativeSymbol.class), vmStore(r10, long.class) },
 71             { vmStore(rax, long.class) }
 72         });
 73 
 74         checkReturnBindings(callingSequence, new Binding[]{});
 75 
 76         assertEquals(bindings.nVectorArgs, 0);
 77     }
 78 
 79     @Test
 80     public void testNestedStructs() {
 81         MemoryLayout POINT = MemoryLayout.structLayout(
 82                 C_INT,
 83                 MemoryLayout.structLayout(
 84                         C_INT,
 85                         C_INT
 86                 )
 87         );
 88         MethodType mt = MethodType.methodType(void.class, MemorySegment.class);
 89         FunctionDescriptor fd = FunctionDescriptor.ofVoid(POINT);
 90         CallArranger.Bindings bindings = CallArranger.getBindings(mt, fd, false);
 91 
 92         assertFalse(bindings.isInMemoryReturn);
 93         CallingSequence callingSequence = bindings.callingSequence;
 94         assertEquals(callingSequence.methodType(), mt.appendParameterTypes(long.class).insertParameterTypes(0, NativeSymbol.class));
 95         assertEquals(callingSequence.functionDesc(), fd.appendArgumentLayouts(C_LONG).insertArgumentLayouts(0, ADDRESS));
 96 
 97         checkArgumentBindings(callingSequence, new Binding[][]{
 98             { unboxAddress(NativeSymbol.class), vmStore(r10, long.class) },
 99             { dup(), bufferLoad(0, long.class), vmStore(rdi, long.class),
100               bufferLoad(8, int.class), vmStore(rsi, int.class)},
101             { vmStore(rax, long.class) },
102         });
103 
104         checkReturnBindings(callingSequence, new Binding[]{});
105 
106         assertEquals(bindings.nVectorArgs, 0);
107     }
108 
109     @Test
110     public void testNestedUnion() {
111         MemoryLayout POINT = MemoryLayout.structLayout(
112                 C_INT,
113                 MemoryLayout.paddingLayout(32),
114                 MemoryLayout.unionLayout(
115                         MemoryLayout.structLayout(C_INT, C_INT),
116                         C_LONG
117                 )
118         );
119         MethodType mt = MethodType.methodType(void.class, MemorySegment.class);
120         FunctionDescriptor fd = FunctionDescriptor.ofVoid(POINT);
121         CallArranger.Bindings bindings = CallArranger.getBindings(mt, fd, false);
122 
123         assertFalse(bindings.isInMemoryReturn);
124         CallingSequence callingSequence = bindings.callingSequence;
125         assertEquals(callingSequence.methodType(), mt.appendParameterTypes(long.class).insertParameterTypes(0, NativeSymbol.class));
126         assertEquals(callingSequence.functionDesc(), fd.appendArgumentLayouts(C_LONG).insertArgumentLayouts(0, ADDRESS));
127 
128         checkArgumentBindings(callingSequence, new Binding[][]{
129             { unboxAddress(NativeSymbol.class), vmStore(r10, long.class) },
130             { dup(), bufferLoad(0, long.class), vmStore(rdi, long.class),
131                     bufferLoad(8, long.class), vmStore(rsi, long.class)},
132             { vmStore(rax, long.class) },
133         });
134 
135         checkReturnBindings(callingSequence, new Binding[]{});
136 
137         assertEquals(bindings.nVectorArgs, 0);
138     }
139 
140     @Test
141     public void testNestedStructsUnaligned() {
142         MemoryLayout POINT = MemoryLayout.structLayout(
143                 C_INT,
144                 MemoryLayout.structLayout(
145                         C_LONG,
146                         C_INT
147                 )
148         );
149         MethodType mt = MethodType.methodType(void.class, MemorySegment.class);
150         FunctionDescriptor fd = FunctionDescriptor.ofVoid(POINT);
151         CallArranger.Bindings bindings = CallArranger.getBindings(mt, fd, false);
152 
153         assertFalse(bindings.isInMemoryReturn);
154         CallingSequence callingSequence = bindings.callingSequence;
155         assertEquals(callingSequence.methodType(), mt.appendParameterTypes(long.class).insertParameterTypes(0, NativeSymbol.class));
156         assertEquals(callingSequence.functionDesc(), fd.appendArgumentLayouts(C_LONG).insertArgumentLayouts(0, ADDRESS));
157 
158         checkArgumentBindings(callingSequence, new Binding[][]{
159             { unboxAddress(NativeSymbol.class), vmStore(r10, long.class) },
160             { dup(), bufferLoad(0, long.class), vmStore(stackStorage(0), long.class),
161                     bufferLoad(8, long.class), vmStore(stackStorage(1), long.class)},
162             { vmStore(rax, long.class) },
163         });
164 
165         checkReturnBindings(callingSequence, new Binding[]{});
166 
167         assertEquals(bindings.nVectorArgs, 0);
168     }
169 
170     @Test
171     public void testNestedUnionUnaligned() {
172         MemoryLayout POINT = MemoryLayout.structLayout(
173                 C_INT,
174                 MemoryLayout.unionLayout(
175                         MemoryLayout.structLayout(C_INT, C_INT),
176                         C_LONG
177                 )
178         );
179         MethodType mt = MethodType.methodType(void.class, MemorySegment.class);
180         FunctionDescriptor fd = FunctionDescriptor.ofVoid(POINT);
181         CallArranger.Bindings bindings = CallArranger.getBindings(mt, fd, false);
182 
183         assertFalse(bindings.isInMemoryReturn);
184         CallingSequence callingSequence = bindings.callingSequence;
185         assertEquals(callingSequence.methodType(), mt.appendParameterTypes(long.class).insertParameterTypes(0, NativeSymbol.class));
186         assertEquals(callingSequence.functionDesc(), fd.appendArgumentLayouts(C_LONG).insertArgumentLayouts(0, ADDRESS));
187 
188         checkArgumentBindings(callingSequence, new Binding[][]{
189             { unboxAddress(NativeSymbol.class), vmStore(r10, long.class) },
190             { dup(), bufferLoad(0, long.class), vmStore(stackStorage(0), long.class),
191                     bufferLoad(8, int.class), vmStore(stackStorage(1), int.class)},
192             { vmStore(rax, long.class) },
193         });
194 
195         checkReturnBindings(callingSequence, new Binding[]{});
196 
197         assertEquals(bindings.nVectorArgs, 0);
198     }
199 
200     @Test
201     public void testIntegerRegs() {
202         MethodType mt = MethodType.methodType(void.class,
203                 int.class, int.class, int.class, int.class, int.class, int.class);
204         FunctionDescriptor fd = FunctionDescriptor.ofVoid(
205                 C_INT, C_INT, C_INT, C_INT, C_INT, C_INT);
206         CallArranger.Bindings bindings = CallArranger.getBindings(mt, fd, false);
207 
208         assertFalse(bindings.isInMemoryReturn);
209         CallingSequence callingSequence = bindings.callingSequence;
210         assertEquals(callingSequence.methodType(), mt.appendParameterTypes(long.class).insertParameterTypes(0, NativeSymbol.class));
211         assertEquals(callingSequence.functionDesc(), fd.appendArgumentLayouts(C_LONG).insertArgumentLayouts(0, ADDRESS));
212 
213         checkArgumentBindings(callingSequence, new Binding[][]{
214             { unboxAddress(NativeSymbol.class), vmStore(r10, long.class) },
215             { vmStore(rdi, int.class) },
216             { vmStore(rsi, int.class) },
217             { vmStore(rdx, int.class) },
218             { vmStore(rcx, int.class) },
219             { vmStore(r8, int.class) },
220             { vmStore(r9, int.class) },
221             { vmStore(rax, long.class) },
222         });
223 
224         checkReturnBindings(callingSequence, new Binding[]{});
225 
226         assertEquals(bindings.nVectorArgs, 0);
227     }
228 
229     @Test
230     public void testDoubleRegs() {
231         MethodType mt = MethodType.methodType(void.class,
232                 double.class, double.class, double.class, double.class,
233                 double.class, double.class, double.class, double.class);
234         FunctionDescriptor fd = FunctionDescriptor.ofVoid(
235                 C_DOUBLE, C_DOUBLE, C_DOUBLE, C_DOUBLE,
236                 C_DOUBLE, C_DOUBLE, C_DOUBLE, C_DOUBLE);
237         CallArranger.Bindings bindings = CallArranger.getBindings(mt, fd, false);
238 
239         assertFalse(bindings.isInMemoryReturn);
240         CallingSequence callingSequence = bindings.callingSequence;
241         assertEquals(callingSequence.methodType(), mt.appendParameterTypes(long.class).insertParameterTypes(0, NativeSymbol.class));
242         assertEquals(callingSequence.functionDesc(), fd.appendArgumentLayouts(C_LONG).insertArgumentLayouts(0, ADDRESS));
243 
244         checkArgumentBindings(callingSequence, new Binding[][]{
245             { unboxAddress(NativeSymbol.class), vmStore(r10, long.class) },
246             { vmStore(xmm0, double.class) },
247             { vmStore(xmm1, double.class) },
248             { vmStore(xmm2, double.class) },
249             { vmStore(xmm3, double.class) },
250             { vmStore(xmm4, double.class) },
251             { vmStore(xmm5, double.class) },
252             { vmStore(xmm6, double.class) },
253             { vmStore(xmm7, double.class) },
254             { vmStore(rax, long.class) },
255         });
256 
257         checkReturnBindings(callingSequence, new Binding[]{});
258 
259         assertEquals(bindings.nVectorArgs, 8);
260     }
261 
262     @Test
263     public void testMixed() {
264         MethodType mt = MethodType.methodType(void.class,
265                 long.class, long.class, long.class, long.class, long.class, long.class, long.class, long.class,
266                 float.class, float.class, float.class, float.class,
267                 float.class, float.class, float.class, float.class, float.class, float.class);
268         FunctionDescriptor fd = FunctionDescriptor.ofVoid(
269                 C_LONG, C_LONG, C_LONG, C_LONG, C_LONG, C_LONG, C_LONG, C_LONG,
270                 C_FLOAT, C_FLOAT, C_FLOAT, C_FLOAT,
271                 C_FLOAT, C_FLOAT, C_FLOAT, C_FLOAT, C_FLOAT, C_FLOAT);
272         CallArranger.Bindings bindings = CallArranger.getBindings(mt, fd, false);
273 
274         assertFalse(bindings.isInMemoryReturn);
275         CallingSequence callingSequence = bindings.callingSequence;
276         assertEquals(callingSequence.methodType(), mt.appendParameterTypes(long.class).insertParameterTypes(0, NativeSymbol.class));
277         assertEquals(callingSequence.functionDesc(), fd.appendArgumentLayouts(C_LONG).insertArgumentLayouts(0, ADDRESS));
278 
279         checkArgumentBindings(callingSequence, new Binding[][]{
280             { unboxAddress(NativeSymbol.class), vmStore(r10, long.class) },
281             { vmStore(rdi, long.class) },
282             { vmStore(rsi, long.class) },
283             { vmStore(rdx, long.class) },
284             { vmStore(rcx, long.class) },
285             { vmStore(r8, long.class) },
286             { vmStore(r9, long.class) },
287             { vmStore(stackStorage(0), long.class) },
288             { vmStore(stackStorage(1), long.class) },
289             { vmStore(xmm0, float.class) },
290             { vmStore(xmm1, float.class) },
291             { vmStore(xmm2, float.class) },
292             { vmStore(xmm3, float.class) },
293             { vmStore(xmm4, float.class) },
294             { vmStore(xmm5, float.class) },
295             { vmStore(xmm6, float.class) },
296             { vmStore(xmm7, float.class) },
297             { vmStore(stackStorage(2), float.class) },
298             { vmStore(stackStorage(3), float.class) },
299             { vmStore(rax, long.class) },
300         });
301 
302         checkReturnBindings(callingSequence, new Binding[]{});
303 
304         assertEquals(bindings.nVectorArgs, 8);
305     }
306 
307     /**
308      * This is the example from the System V ABI AMD64 document
309      *
310      * struct structparm {
311      *   int32_t a, int32_t b, double d;
312      * } s;
313      * int32_t e, f, g, h, i, j, k;
314      * double m, n;
315      *
316      * void m(e, f, s, g, h, m, n, i, j, k);
317      *
318      * m(s);
319      */
320     @Test
321     public void testAbiExample() {
322         MemoryLayout struct = MemoryLayout.structLayout(C_INT, C_INT, C_DOUBLE);
323 
324         MethodType mt = MethodType.methodType(void.class,
325                 int.class, int.class, MemorySegment.class, int.class, int.class,
326                 double.class, double.class, int.class, int.class, int.class);
327         FunctionDescriptor fd = FunctionDescriptor.ofVoid(
328                 C_INT, C_INT, struct, C_INT, C_INT, C_DOUBLE, C_DOUBLE, C_INT, C_INT, C_INT);
329         CallArranger.Bindings bindings = CallArranger.getBindings(mt, fd, false);
330 
331         assertFalse(bindings.isInMemoryReturn);
332         CallingSequence callingSequence = bindings.callingSequence;
333         assertEquals(callingSequence.methodType(), mt.appendParameterTypes(long.class).insertParameterTypes(0, NativeSymbol.class));
334         assertEquals(callingSequence.functionDesc(), fd.appendArgumentLayouts(C_LONG).insertArgumentLayouts(0, ADDRESS));
335 
336         checkArgumentBindings(callingSequence, new Binding[][]{
337             { unboxAddress(NativeSymbol.class), vmStore(r10, long.class) },
338             { vmStore(rdi, int.class) },
339             { vmStore(rsi, int.class) },
340             {
341                 dup(),
342                 bufferLoad(0, long.class), vmStore(rdx, long.class),
343                 bufferLoad(8, double.class), vmStore(xmm0, double.class)
344             },
345             { vmStore(rcx, int.class) },
346             { vmStore(r8, int.class) },
347             { vmStore(xmm1, double.class) },
348             { vmStore(xmm2, double.class) },
349             { vmStore(r9, int.class) },
350             { vmStore(stackStorage(0), int.class) },
351             { vmStore(stackStorage(1), int.class) },
352             { vmStore(rax, long.class) },
353         });
354 
355         checkReturnBindings(callingSequence, new Binding[]{});
356 
357         assertEquals(bindings.nVectorArgs, 3);
358     }
359 
360     /**
361      * typedef void (*f)(void);
362      *
363      * void m(f f);
364      * void f_impl(void);
365      *
366      * m(f_impl);
367      */
368     @Test
369     public void testMemoryAddress() {
370         MethodType mt = MethodType.methodType(void.class, MemoryAddress.class);
371         FunctionDescriptor fd = FunctionDescriptor.ofVoid( C_POINTER);
372         CallArranger.Bindings bindings = CallArranger.getBindings(mt, fd, false);
373 
374         assertFalse(bindings.isInMemoryReturn);
375         CallingSequence callingSequence = bindings.callingSequence;
376         assertEquals(callingSequence.methodType(), mt.appendParameterTypes(long.class).insertParameterTypes(0, NativeSymbol.class));
377         assertEquals(callingSequence.functionDesc(), fd.appendArgumentLayouts(C_LONG).insertArgumentLayouts(0, ADDRESS));
378 
379         checkArgumentBindings(callingSequence, new Binding[][]{
380             { unboxAddress(NativeSymbol.class), vmStore(r10, long.class) },
381             { unboxAddress(), vmStore(rdi, long.class) },
382             { vmStore(rax, long.class) },
383         });
384 
385         checkReturnBindings(callingSequence, new Binding[]{});
386 
387         assertEquals(bindings.nVectorArgs, 0);
388     }
389 
390     @Test(dataProvider = "structs")
391     public void testStruct(MemoryLayout struct, Binding[] expectedBindings) {
392         MethodType mt = MethodType.methodType(void.class, MemorySegment.class);
393         FunctionDescriptor fd = FunctionDescriptor.ofVoid(struct);
394         CallArranger.Bindings bindings = CallArranger.getBindings(mt, fd, false);
395 
396         assertFalse(bindings.isInMemoryReturn);
397         CallingSequence callingSequence = bindings.callingSequence;
398         assertEquals(callingSequence.methodType(), mt.appendParameterTypes(long.class).insertParameterTypes(0, NativeSymbol.class));
399         assertEquals(callingSequence.functionDesc(), fd.appendArgumentLayouts(C_LONG).insertArgumentLayouts(0, ADDRESS));
400 
401         checkArgumentBindings(callingSequence, new Binding[][]{
402             { unboxAddress(NativeSymbol.class), vmStore(r10, long.class) },
403             expectedBindings,
404             { vmStore(rax, long.class) },
405         });
406 
407         checkReturnBindings(callingSequence, new Binding[]{});
408 
409         assertEquals(bindings.nVectorArgs, 0);
410     }
411 
412 
413     @DataProvider
414     public static Object[][] structs() {
415         return new Object[][]{
416             { MemoryLayout.structLayout(C_LONG), new Binding[]{
417                     bufferLoad(0, long.class), vmStore(rdi, long.class)
418                 }
419             },
420             { MemoryLayout.structLayout(C_LONG, C_LONG), new Binding[]{
421                     dup(),
422                     bufferLoad(0, long.class), vmStore(rdi, long.class),
423                     bufferLoad(8, long.class), vmStore(rsi, long.class)
424                 }
425             },
426             { MemoryLayout.structLayout(C_LONG, C_LONG, C_LONG), new Binding[]{
427                     dup(),
428                     bufferLoad(0, long.class), vmStore(stackStorage(0), long.class),
429                     dup(),
430                     bufferLoad(8, long.class), vmStore(stackStorage(1), long.class),
431                     bufferLoad(16, long.class), vmStore(stackStorage(2), long.class)
432                 }
433             },
434             { MemoryLayout.structLayout(C_LONG, C_LONG, C_LONG, C_LONG), new Binding[]{
435                     dup(),
436                     bufferLoad(0, long.class), vmStore(stackStorage(0), long.class),
437                     dup(),
438                     bufferLoad(8, long.class), vmStore(stackStorage(1), long.class),
439                     dup(),
440                     bufferLoad(16, long.class), vmStore(stackStorage(2), long.class),
441                     bufferLoad(24, long.class), vmStore(stackStorage(3), long.class)
442                 }
443             },
444         };
445     }
446 
447     @Test
448     public void testReturnRegisterStruct() {
449         MemoryLayout struct = MemoryLayout.structLayout(C_LONG, C_LONG);
450 
451         MethodType mt = MethodType.methodType(MemorySegment.class);
452         FunctionDescriptor fd = FunctionDescriptor.of(struct);
453         CallArranger.Bindings bindings = CallArranger.getBindings(mt, fd, false);
454 
455         assertFalse(bindings.isInMemoryReturn);
456         CallingSequence callingSequence = bindings.callingSequence;
457         assertEquals(callingSequence.methodType(), mt.appendParameterTypes(long.class).insertParameterTypes(0, MemorySegment.class, NativeSymbol.class));
458         assertEquals(callingSequence.functionDesc(), fd.appendArgumentLayouts(C_LONG).insertArgumentLayouts(0, ADDRESS, ADDRESS));
459 
460         checkArgumentBindings(callingSequence, new Binding[][]{
461             { unboxAddress(MemorySegment.class), vmStore(r11, long.class) },
462             { unboxAddress(NativeSymbol.class), vmStore(r10, long.class) },
463             { vmStore(rax, long.class) }
464         });
465 
466         checkReturnBindings(callingSequence, new Binding[] {
467             allocate(struct),
468             dup(),
469             vmLoad(rax, long.class),
470             bufferStore(0, long.class),
471             dup(),
472             vmLoad(rdx, long.class),
473             bufferStore(8, long.class)
474         });
475 
476         assertEquals(bindings.nVectorArgs, 0);
477     }
478 
479     @Test
480     public void testIMR() {
481         MemoryLayout struct = MemoryLayout.structLayout(C_LONG, C_LONG, C_LONG);
482 
483         MethodType mt = MethodType.methodType(MemorySegment.class);
484         FunctionDescriptor fd = FunctionDescriptor.of(struct);
485         CallArranger.Bindings bindings = CallArranger.getBindings(mt, fd, false);
486 
487         assertTrue(bindings.isInMemoryReturn);
488         CallingSequence callingSequence = bindings.callingSequence;
489         assertEquals(callingSequence.methodType(), MethodType.methodType(void.class, NativeSymbol.class, MemoryAddress.class, long.class));
490         assertEquals(callingSequence.functionDesc(), FunctionDescriptor.ofVoid(ADDRESS, C_POINTER, C_LONG));
491 
492         checkArgumentBindings(callingSequence, new Binding[][]{
493             { unboxAddress(NativeSymbol.class), vmStore(r10, long.class) },
494             { unboxAddress(), vmStore(rdi, long.class) },
495             { vmStore(rax, long.class) }
496         });
497 
498         checkReturnBindings(callingSequence, new Binding[] {});
499 
500         assertEquals(bindings.nVectorArgs, 0);
501     }
502 
503     @Test
504     public void testFloatStructsUpcall() {
505         MemoryLayout struct = MemoryLayout.structLayout(C_FLOAT); // should be passed in float regs
506 
507         MethodType mt = MethodType.methodType(MemorySegment.class, MemorySegment.class);
508         FunctionDescriptor fd = FunctionDescriptor.of(struct, struct);
509         CallArranger.Bindings bindings = CallArranger.getBindings(mt, fd, true);
510 
511         assertFalse(bindings.isInMemoryReturn);
512         CallingSequence callingSequence = bindings.callingSequence;
513         assertEquals(callingSequence.methodType(), mt);
514         assertEquals(callingSequence.functionDesc(), fd);
515 
516         checkArgumentBindings(callingSequence, new Binding[][]{
517             { allocate(struct), dup(), vmLoad(xmm0, float.class), bufferStore(0, float.class) },
518         });
519 
520         checkReturnBindings(callingSequence, new Binding[] {
521             bufferLoad(0, float.class), vmStore(xmm0, float.class)
522         });
523 
524         assertEquals(bindings.nVectorArgs, 1);
525     }
526 
527 }