< prev index next >

test/jdk/java/foreign/callarranger/TestAarch64CallArranger.java

Print this page

 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.aarch64
 30  * @build CallArrangerTestBase
 31  * @run testng TestAarch64CallArranger
 32  */
 33 
 34 import jdk.incubator.foreign.FunctionDescriptor;
 35 import jdk.incubator.foreign.MemoryAddress;
 36 import jdk.incubator.foreign.MemoryLayout;
 37 import jdk.incubator.foreign.MemorySegment;

 38 import jdk.internal.foreign.abi.Binding;
 39 import jdk.internal.foreign.abi.CallingSequence;
 40 import jdk.internal.foreign.abi.aarch64.CallArranger;
 41 import org.testng.annotations.DataProvider;
 42 import org.testng.annotations.Test;
 43 
 44 import java.lang.invoke.MethodType;
 45 

 46 import static jdk.internal.foreign.PlatformLayouts.AArch64.*;
 47 import static jdk.internal.foreign.abi.Binding.*;
 48 import static jdk.internal.foreign.abi.aarch64.AArch64Architecture.*;
 49 import static org.testng.Assert.assertEquals;
 50 import static org.testng.Assert.assertFalse;
 51 import static org.testng.Assert.assertTrue;
 52 
 53 public class TestAarch64CallArranger extends CallArrangerTestBase {
 54 
 55     @Test
 56     public void testEmpty() {
 57         MethodType mt = MethodType.methodType(void.class);
 58         FunctionDescriptor fd = FunctionDescriptor.ofVoid();
 59         CallArranger.Bindings bindings = CallArranger.LINUX.getBindings(mt, fd, false);
 60 
 61         assertFalse(bindings.isInMemoryReturn);
 62         CallingSequence callingSequence = bindings.callingSequence;
 63         assertEquals(callingSequence.methodType(), mt);
 64         assertEquals(callingSequence.functionDesc(), fd);
 65 
 66         checkArgumentBindings(callingSequence, new Binding[][]{});


 67 
 68         checkReturnBindings(callingSequence, new Binding[]{});
 69     }
 70 
 71     @Test
 72     public void testInteger() {
 73         MethodType mt = MethodType.methodType(void.class,
 74                 int.class, int.class, int.class, int.class,
 75                 int.class, int.class, int.class, int.class,
 76                 int.class, int.class);
 77         FunctionDescriptor fd = FunctionDescriptor.ofVoid(
 78                 C_INT, C_INT, C_INT, C_INT,
 79                 C_INT, C_INT, C_INT, C_INT,
 80                 C_INT, C_INT);
 81         CallArranger.Bindings bindings = CallArranger.LINUX.getBindings(mt, fd, false);
 82 
 83         assertFalse(bindings.isInMemoryReturn);
 84         CallingSequence callingSequence = bindings.callingSequence;
 85         assertEquals(callingSequence.methodType(), mt);
 86         assertEquals(callingSequence.functionDesc(), fd);
 87 
 88         checkArgumentBindings(callingSequence, new Binding[][]{

 89             { vmStore(r0, int.class) },
 90             { vmStore(r1, int.class) },
 91             { vmStore(r2, int.class) },
 92             { vmStore(r3, int.class) },
 93             { vmStore(r4, int.class) },
 94             { vmStore(r5, int.class) },
 95             { vmStore(r6, int.class) },
 96             { vmStore(r7, int.class) },
 97             { vmStore(stackStorage(0), int.class) },
 98             { vmStore(stackStorage(1), int.class) },
 99         });
100 
101         checkReturnBindings(callingSequence, new Binding[]{});
102     }
103 
104     @Test
105     public void testTwoIntTwoFloat() {
106         MethodType mt = MethodType.methodType(void.class,
107                 int.class, int.class, float.class, float.class);
108         FunctionDescriptor fd = FunctionDescriptor.ofVoid(
109                 C_INT, C_INT, C_FLOAT, C_FLOAT);
110         CallArranger.Bindings bindings = CallArranger.LINUX.getBindings(mt, fd, false);
111 
112         assertFalse(bindings.isInMemoryReturn);
113         CallingSequence callingSequence = bindings.callingSequence;
114         assertEquals(callingSequence.methodType(), mt);
115         assertEquals(callingSequence.functionDesc(), fd);
116 
117         checkArgumentBindings(callingSequence, new Binding[][]{

118             { vmStore(r0, int.class) },
119             { vmStore(r1, int.class) },
120             { vmStore(v0, float.class) },
121             { vmStore(v1, float.class) },
122         });
123 
124         checkReturnBindings(callingSequence, new Binding[]{});
125     }
126 
127     @Test(dataProvider = "structs")
128     public void testStruct(MemoryLayout struct, Binding[] expectedBindings) {
129         MethodType mt = MethodType.methodType(void.class, MemorySegment.class);
130         FunctionDescriptor fd = FunctionDescriptor.ofVoid(struct);
131         CallArranger.Bindings bindings = CallArranger.LINUX.getBindings(mt, fd, false);
132 
133         assertFalse(bindings.isInMemoryReturn);
134         CallingSequence callingSequence = bindings.callingSequence;
135         assertEquals(callingSequence.methodType(), mt);
136         assertEquals(callingSequence.functionDesc(), fd);
137 
138         checkArgumentBindings(callingSequence, new Binding[][]{

139             expectedBindings
140         });
141 
142         checkReturnBindings(callingSequence, new Binding[]{});
143     }
144 
145     @DataProvider
146     public static Object[][] structs() {
147         MemoryLayout struct2 = MemoryLayout.structLayout(C_INT, C_INT, C_DOUBLE, C_INT);
148         return new Object[][]{
149             // struct s { int32_t a, b; double c; };
150             { MemoryLayout.structLayout(C_INT, C_INT, C_DOUBLE), new Binding[] {
151                 dup(),
152                     // s.a & s.b
153                     bufferLoad(0, long.class), vmStore(r0, long.class),
154                     // s.c --> note AArch64 passes this in an *integer* register
155                     bufferLoad(8, long.class), vmStore(r1, long.class),
156             }},
157             // struct s { int32_t a, b; double c; int32_t d };
158             { struct2, new Binding[] {

174                 dup(),
175                 // s.a
176                 bufferLoad(0, long.class), vmStore(r0, long.class),
177                 // s.b
178                 bufferLoad(8, long.class), vmStore(r1, long.class),
179             }},
180         };
181     }
182 
183     @Test
184     public void testMultipleStructs() {
185         MemoryLayout struct1 = MemoryLayout.structLayout(C_INT, C_INT, C_DOUBLE, C_INT);
186         MemoryLayout struct2 = MemoryLayout.structLayout(C_LONG, C_LONG, C_LONG);
187 
188         MethodType mt = MethodType.methodType(void.class, MemorySegment.class, MemorySegment.class, int.class);
189         FunctionDescriptor fd = FunctionDescriptor.ofVoid(struct1, struct2, C_INT);
190         CallArranger.Bindings bindings = CallArranger.LINUX.getBindings(mt, fd, false);
191 
192         assertFalse(bindings.isInMemoryReturn);
193         CallingSequence callingSequence = bindings.callingSequence;
194         assertEquals(callingSequence.methodType(), mt);
195         assertEquals(callingSequence.functionDesc(), fd);
196 
197         checkArgumentBindings(callingSequence, new Binding[][]{

198             {
199                 copy(struct1),
200                 unboxAddress(MemorySegment.class),
201                 vmStore(r0, long.class)
202             },
203             {
204                 copy(struct2),
205                 unboxAddress(MemorySegment.class),
206                 vmStore(r1, long.class)
207             },
208             { vmStore(r2, int.class) }
209         });
210 
211         checkReturnBindings(callingSequence, new Binding[]{});
212     }
213 
214     @Test
215     public void testReturnStruct1() {
216         MemoryLayout struct = MemoryLayout.structLayout(C_LONG, C_LONG, C_FLOAT);
217 
218         MethodType mt = MethodType.methodType(MemorySegment.class);
219         FunctionDescriptor fd = FunctionDescriptor.of(struct);
220         CallArranger.Bindings bindings = CallArranger.LINUX.getBindings(mt, fd, false);
221 
222         assertTrue(bindings.isInMemoryReturn);
223         CallingSequence callingSequence = bindings.callingSequence;
224         assertEquals(callingSequence.methodType(), MethodType.methodType(void.class, MemoryAddress.class));
225         assertEquals(callingSequence.functionDesc(), FunctionDescriptor.ofVoid(C_POINTER));
226 
227         checkArgumentBindings(callingSequence, new Binding[][]{

228             {
229                 unboxAddress(),
230                 vmStore(r8, long.class)
231             }
232         });
233 
234         checkReturnBindings(callingSequence, new Binding[]{});
235     }
236 
237     @Test
238     public void testReturnStruct2() {
239         MemoryLayout struct = MemoryLayout.structLayout(C_LONG, C_LONG);
240 
241         MethodType mt = MethodType.methodType(MemorySegment.class);
242         FunctionDescriptor fd = FunctionDescriptor.of(struct);
243         CallArranger.Bindings bindings = CallArranger.LINUX.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         checkReturnBindings(callingSequence, new Binding[]{
253             allocate(struct),
254             dup(),
255             vmLoad(r0, long.class),
256             bufferStore(0, long.class),
257             dup(),
258             vmLoad(r1, long.class),
259             bufferStore(8, long.class),
260         });
261     }
262 
263     @Test
264     public void testStructHFA1() {
265         MemoryLayout hfa = MemoryLayout.structLayout(C_FLOAT, C_FLOAT);
266 
267         MethodType mt = MethodType.methodType(MemorySegment.class, float.class, int.class, MemorySegment.class);
268         FunctionDescriptor fd = FunctionDescriptor.of(hfa, C_FLOAT, C_INT, hfa);
269         CallArranger.Bindings bindings = CallArranger.LINUX.getBindings(mt, fd, false);
270 
271         assertFalse(bindings.isInMemoryReturn);
272         CallingSequence callingSequence = bindings.callingSequence;
273         assertEquals(callingSequence.methodType(), mt);
274         assertEquals(callingSequence.functionDesc(), fd);
275 
276         checkArgumentBindings(callingSequence, new Binding[][]{


277             { vmStore(v0, float.class) },
278             { vmStore(r0, int.class) },
279             {
280                 dup(),
281                 bufferLoad(0, float.class),
282                 vmStore(v1, float.class),
283                 bufferLoad(4, float.class),
284                 vmStore(v2, float.class)
285             }
286         });
287 
288         checkReturnBindings(callingSequence, new Binding[]{
289             allocate(hfa),
290             dup(),
291             vmLoad(v0, float.class),
292             bufferStore(0, float.class),
293             dup(),
294             vmLoad(v1, float.class),
295             bufferStore(4, float.class),
296         });
297     }
298 
299     @Test
300     public void testStructHFA3() {
301         MemoryLayout struct = MemoryLayout.structLayout(C_FLOAT, C_FLOAT, C_FLOAT);
302 
303         MethodType mt = MethodType.methodType(void.class, MemorySegment.class, MemorySegment.class, MemorySegment.class);
304         FunctionDescriptor fd = FunctionDescriptor.ofVoid(struct, struct, struct);
305         CallArranger.Bindings bindings = CallArranger.LINUX.getBindings(mt, fd, false);
306 
307         assertFalse(bindings.isInMemoryReturn);
308         CallingSequence callingSequence = bindings.callingSequence;
309         assertEquals(callingSequence.methodType(), mt);
310         assertEquals(callingSequence.functionDesc(), fd);
311 
312         checkArgumentBindings(callingSequence, new Binding[][]{

313             {
314                 dup(),
315                 bufferLoad(0, float.class),
316                 vmStore(v0, float.class),
317                 dup(),
318                 bufferLoad(4, float.class),
319                 vmStore(v1, float.class),
320                 bufferLoad(8, float.class),
321                 vmStore(v2, float.class)
322             },
323             {
324                 dup(),
325                 bufferLoad(0, float.class),
326                 vmStore(v3, float.class),
327                 dup(),
328                 bufferLoad(4, float.class),
329                 vmStore(v4, float.class),
330                 bufferLoad(8, float.class),
331                 vmStore(v5, float.class)
332             },

342         checkReturnBindings(callingSequence, new Binding[]{});
343     }
344 
345     @Test
346     public void testStructStackSpill() {
347         // A large (> 16 byte) struct argument that is spilled to the
348         // stack should be passed as a pointer to a copy and occupy one
349         // stack slot.
350 
351         MemoryLayout struct = MemoryLayout.structLayout(C_INT, C_INT, C_DOUBLE, C_INT);
352 
353         MethodType mt = MethodType.methodType(
354             void.class, MemorySegment.class, MemorySegment.class, int.class, int.class,
355             int.class, int.class, int.class, int.class, MemorySegment.class, int.class);
356         FunctionDescriptor fd = FunctionDescriptor.ofVoid(
357             struct, struct, C_INT, C_INT, C_INT, C_INT, C_INT, C_INT, struct, C_INT);
358         CallArranger.Bindings bindings = CallArranger.LINUX.getBindings(mt, fd, false);
359 
360         assertFalse(bindings.isInMemoryReturn);
361         CallingSequence callingSequence = bindings.callingSequence;
362         assertEquals(callingSequence.methodType(), mt);
363         assertEquals(callingSequence.functionDesc(), fd);
364 
365         checkArgumentBindings(callingSequence, new Binding[][]{

366             { copy(struct), unboxAddress(MemorySegment.class), vmStore(r0, long.class) },
367             { copy(struct), unboxAddress(MemorySegment.class), vmStore(r1, long.class) },
368             { vmStore(r2, int.class) },
369             { vmStore(r3, int.class) },
370             { vmStore(r4, int.class) },
371             { vmStore(r5, int.class) },
372             { vmStore(r6, int.class) },
373             { vmStore(r7, int.class) },
374             { copy(struct), unboxAddress(MemorySegment.class), vmStore(stackStorage(0), long.class) },
375             { vmStore(stackStorage(1), int.class) },
376         });
377 
378         checkReturnBindings(callingSequence, new Binding[]{});
379     }
380 
381     @Test
382     public void testVarArgsInRegs() {
383         MethodType mt = MethodType.methodType(void.class, int.class, int.class, float.class);
384         FunctionDescriptor fd = FunctionDescriptor.ofVoid(C_INT).asVariadic(C_INT, C_FLOAT);

385         CallArranger.Bindings bindings = CallArranger.LINUX.getBindings(mt, fd, false);
386 
387         assertFalse(bindings.isInMemoryReturn);
388         CallingSequence callingSequence = bindings.callingSequence;
389         assertEquals(callingSequence.methodType(), mt);
390         assertEquals(callingSequence.functionDesc(), fd);
391 
392         // This is identical to the non-variadic calling sequence
393         checkArgumentBindings(callingSequence, new Binding[][]{

394             { vmStore(r0, int.class) },
395             { vmStore(r1, int.class) },
396             { vmStore(v0, float.class) },
397         });
398 
399         checkReturnBindings(callingSequence, new Binding[]{});
400     }
401 
402     @Test
403     public void testVarArgsOnStack() {
404         MethodType mt = MethodType.methodType(void.class, int.class, int.class, float.class);
405         FunctionDescriptor fd = FunctionDescriptor.ofVoid(C_INT).asVariadic(C_INT, C_FLOAT);

406         CallArranger.Bindings bindings = CallArranger.MACOS.getBindings(mt, fd, false);
407 
408         assertFalse(bindings.isInMemoryReturn);
409         CallingSequence callingSequence = bindings.callingSequence;
410         assertEquals(callingSequence.methodType(), mt);
411         assertEquals(callingSequence.functionDesc(), fd);
412 
413         // The two variadic arguments should be allocated on the stack
414         checkArgumentBindings(callingSequence, new Binding[][]{

415             { vmStore(r0, int.class) },
416             { vmStore(stackStorage(0), int.class) },
417             { vmStore(stackStorage(1), float.class) },
418         });
419 
420         checkReturnBindings(callingSequence, new Binding[]{});
421     }
422 }

 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.aarch64
 30  * @build CallArrangerTestBase
 31  * @run testng TestAarch64CallArranger
 32  */
 33 
 34 import jdk.incubator.foreign.FunctionDescriptor;
 35 import jdk.incubator.foreign.MemoryAddress;
 36 import jdk.incubator.foreign.MemoryLayout;
 37 import jdk.incubator.foreign.MemorySegment;
 38 import jdk.incubator.foreign.NativeSymbol;
 39 import jdk.internal.foreign.abi.Binding;
 40 import jdk.internal.foreign.abi.CallingSequence;
 41 import jdk.internal.foreign.abi.aarch64.CallArranger;
 42 import org.testng.annotations.DataProvider;
 43 import org.testng.annotations.Test;
 44 
 45 import java.lang.invoke.MethodType;
 46 
 47 import static jdk.incubator.foreign.ValueLayout.ADDRESS;
 48 import static jdk.internal.foreign.PlatformLayouts.AArch64.*;
 49 import static jdk.internal.foreign.abi.Binding.*;
 50 import static jdk.internal.foreign.abi.aarch64.AArch64Architecture.*;
 51 import static org.testng.Assert.assertEquals;
 52 import static org.testng.Assert.assertFalse;
 53 import static org.testng.Assert.assertTrue;
 54 
 55 public class TestAarch64CallArranger extends CallArrangerTestBase {
 56 
 57     @Test
 58     public void testEmpty() {
 59         MethodType mt = MethodType.methodType(void.class);
 60         FunctionDescriptor fd = FunctionDescriptor.ofVoid();
 61         CallArranger.Bindings bindings = CallArranger.LINUX.getBindings(mt, fd, false);
 62 
 63         assertFalse(bindings.isInMemoryReturn);
 64         CallingSequence callingSequence = bindings.callingSequence;
 65         assertEquals(callingSequence.methodType(), mt.insertParameterTypes(0, NativeSymbol.class));
 66         assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS));
 67 
 68         checkArgumentBindings(callingSequence, new Binding[][]{
 69             { unboxAddress(NativeSymbol.class), vmStore(r9, long.class) }
 70         });
 71 
 72         checkReturnBindings(callingSequence, new Binding[]{});
 73     }
 74 
 75     @Test
 76     public void testInteger() {
 77         MethodType mt = MethodType.methodType(void.class,
 78                 int.class, int.class, int.class, int.class,
 79                 int.class, int.class, int.class, int.class,
 80                 int.class, int.class);
 81         FunctionDescriptor fd = FunctionDescriptor.ofVoid(
 82                 C_INT, C_INT, C_INT, C_INT,
 83                 C_INT, C_INT, C_INT, C_INT,
 84                 C_INT, C_INT);
 85         CallArranger.Bindings bindings = CallArranger.LINUX.getBindings(mt, fd, false);
 86 
 87         assertFalse(bindings.isInMemoryReturn);
 88         CallingSequence callingSequence = bindings.callingSequence;
 89         assertEquals(callingSequence.methodType(), mt.insertParameterTypes(0, NativeSymbol.class));
 90         assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS));
 91 
 92         checkArgumentBindings(callingSequence, new Binding[][]{
 93             { unboxAddress(NativeSymbol.class), vmStore(r9, long.class) },
 94             { vmStore(r0, int.class) },
 95             { vmStore(r1, int.class) },
 96             { vmStore(r2, int.class) },
 97             { vmStore(r3, int.class) },
 98             { vmStore(r4, int.class) },
 99             { vmStore(r5, int.class) },
100             { vmStore(r6, int.class) },
101             { vmStore(r7, int.class) },
102             { vmStore(stackStorage(0), int.class) },
103             { vmStore(stackStorage(1), int.class) },
104         });
105 
106         checkReturnBindings(callingSequence, new Binding[]{});
107     }
108 
109     @Test
110     public void testTwoIntTwoFloat() {
111         MethodType mt = MethodType.methodType(void.class,
112                 int.class, int.class, float.class, float.class);
113         FunctionDescriptor fd = FunctionDescriptor.ofVoid(
114                 C_INT, C_INT, C_FLOAT, C_FLOAT);
115         CallArranger.Bindings bindings = CallArranger.LINUX.getBindings(mt, fd, false);
116 
117         assertFalse(bindings.isInMemoryReturn);
118         CallingSequence callingSequence = bindings.callingSequence;
119         assertEquals(callingSequence.methodType(), mt.insertParameterTypes(0, NativeSymbol.class));
120         assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS));
121 
122         checkArgumentBindings(callingSequence, new Binding[][]{
123             { unboxAddress(NativeSymbol.class), vmStore(r9, long.class) },
124             { vmStore(r0, int.class) },
125             { vmStore(r1, int.class) },
126             { vmStore(v0, float.class) },
127             { vmStore(v1, float.class) },
128         });
129 
130         checkReturnBindings(callingSequence, new Binding[]{});
131     }
132 
133     @Test(dataProvider = "structs")
134     public void testStruct(MemoryLayout struct, Binding[] expectedBindings) {
135         MethodType mt = MethodType.methodType(void.class, MemorySegment.class);
136         FunctionDescriptor fd = FunctionDescriptor.ofVoid(struct);
137         CallArranger.Bindings bindings = CallArranger.LINUX.getBindings(mt, fd, false);
138 
139         assertFalse(bindings.isInMemoryReturn);
140         CallingSequence callingSequence = bindings.callingSequence;
141         assertEquals(callingSequence.methodType(), mt.insertParameterTypes(0, NativeSymbol.class));
142         assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS));
143 
144         checkArgumentBindings(callingSequence, new Binding[][]{
145             { unboxAddress(NativeSymbol.class), vmStore(r9, long.class) },
146             expectedBindings
147         });
148 
149         checkReturnBindings(callingSequence, new Binding[]{});
150     }
151 
152     @DataProvider
153     public static Object[][] structs() {
154         MemoryLayout struct2 = MemoryLayout.structLayout(C_INT, C_INT, C_DOUBLE, C_INT);
155         return new Object[][]{
156             // struct s { int32_t a, b; double c; };
157             { MemoryLayout.structLayout(C_INT, C_INT, C_DOUBLE), new Binding[] {
158                 dup(),
159                     // s.a & s.b
160                     bufferLoad(0, long.class), vmStore(r0, long.class),
161                     // s.c --> note AArch64 passes this in an *integer* register
162                     bufferLoad(8, long.class), vmStore(r1, long.class),
163             }},
164             // struct s { int32_t a, b; double c; int32_t d };
165             { struct2, new Binding[] {

181                 dup(),
182                 // s.a
183                 bufferLoad(0, long.class), vmStore(r0, long.class),
184                 // s.b
185                 bufferLoad(8, long.class), vmStore(r1, long.class),
186             }},
187         };
188     }
189 
190     @Test
191     public void testMultipleStructs() {
192         MemoryLayout struct1 = MemoryLayout.structLayout(C_INT, C_INT, C_DOUBLE, C_INT);
193         MemoryLayout struct2 = MemoryLayout.structLayout(C_LONG, C_LONG, C_LONG);
194 
195         MethodType mt = MethodType.methodType(void.class, MemorySegment.class, MemorySegment.class, int.class);
196         FunctionDescriptor fd = FunctionDescriptor.ofVoid(struct1, struct2, C_INT);
197         CallArranger.Bindings bindings = CallArranger.LINUX.getBindings(mt, fd, false);
198 
199         assertFalse(bindings.isInMemoryReturn);
200         CallingSequence callingSequence = bindings.callingSequence;
201         assertEquals(callingSequence.methodType(), mt.insertParameterTypes(0, NativeSymbol.class));
202         assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS));
203 
204         checkArgumentBindings(callingSequence, new Binding[][]{
205             { unboxAddress(NativeSymbol.class), vmStore(r9, long.class) },
206             {
207                 copy(struct1),
208                 unboxAddress(MemorySegment.class),
209                 vmStore(r0, long.class)
210             },
211             {
212                 copy(struct2),
213                 unboxAddress(MemorySegment.class),
214                 vmStore(r1, long.class)
215             },
216             { vmStore(r2, int.class) }
217         });
218 
219         checkReturnBindings(callingSequence, new Binding[]{});
220     }
221 
222     @Test
223     public void testReturnStruct1() {
224         MemoryLayout struct = MemoryLayout.structLayout(C_LONG, C_LONG, C_FLOAT);
225 
226         MethodType mt = MethodType.methodType(MemorySegment.class);
227         FunctionDescriptor fd = FunctionDescriptor.of(struct);
228         CallArranger.Bindings bindings = CallArranger.LINUX.getBindings(mt, fd, false);
229 
230         assertTrue(bindings.isInMemoryReturn);
231         CallingSequence callingSequence = bindings.callingSequence;
232         assertEquals(callingSequence.methodType(), MethodType.methodType(void.class, NativeSymbol.class, MemoryAddress.class));
233         assertEquals(callingSequence.functionDesc(), FunctionDescriptor.ofVoid(ADDRESS, C_POINTER));
234 
235         checkArgumentBindings(callingSequence, new Binding[][]{
236             { unboxAddress(NativeSymbol.class), vmStore(r9, long.class) },
237             {
238                 unboxAddress(),
239                 vmStore(r8, long.class)
240             }
241         });
242 
243         checkReturnBindings(callingSequence, new Binding[]{});
244     }
245 
246     @Test
247     public void testReturnStruct2() {
248         MemoryLayout struct = MemoryLayout.structLayout(C_LONG, C_LONG);
249 
250         MethodType mt = MethodType.methodType(MemorySegment.class);
251         FunctionDescriptor fd = FunctionDescriptor.of(struct);
252         CallArranger.Bindings bindings = CallArranger.LINUX.getBindings(mt, fd, false);
253 
254         assertFalse(bindings.isInMemoryReturn);
255         CallingSequence callingSequence = bindings.callingSequence;
256         assertEquals(callingSequence.methodType(), mt.insertParameterTypes(0, MemorySegment.class, NativeSymbol.class));
257         assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS, ADDRESS));
258 
259         checkArgumentBindings(callingSequence, new Binding[][]{
260             { unboxAddress(MemorySegment.class), vmStore(r10, long.class) },
261             { unboxAddress(NativeSymbol.class), vmStore(r9, long.class) }
262         });
263 
264         checkReturnBindings(callingSequence, new Binding[]{
265             allocate(struct),
266             dup(),
267             vmLoad(r0, long.class),
268             bufferStore(0, long.class),
269             dup(),
270             vmLoad(r1, long.class),
271             bufferStore(8, long.class),
272         });
273     }
274 
275     @Test
276     public void testStructHFA1() {
277         MemoryLayout hfa = MemoryLayout.structLayout(C_FLOAT, C_FLOAT);
278 
279         MethodType mt = MethodType.methodType(MemorySegment.class, float.class, int.class, MemorySegment.class);
280         FunctionDescriptor fd = FunctionDescriptor.of(hfa, C_FLOAT, C_INT, hfa);
281         CallArranger.Bindings bindings = CallArranger.LINUX.getBindings(mt, fd, false);
282 
283         assertFalse(bindings.isInMemoryReturn);
284         CallingSequence callingSequence = bindings.callingSequence;
285         assertEquals(callingSequence.methodType(), mt.insertParameterTypes(0, MemorySegment.class, NativeSymbol.class));
286         assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS, ADDRESS));
287 
288         checkArgumentBindings(callingSequence, new Binding[][]{
289             { unboxAddress(MemorySegment.class), vmStore(r10, long.class) },
290             { unboxAddress(NativeSymbol.class), vmStore(r9, long.class) },
291             { vmStore(v0, float.class) },
292             { vmStore(r0, int.class) },
293             {
294                 dup(),
295                 bufferLoad(0, float.class),
296                 vmStore(v1, float.class),
297                 bufferLoad(4, float.class),
298                 vmStore(v2, float.class)
299             }
300         });
301 
302         checkReturnBindings(callingSequence, new Binding[]{
303             allocate(hfa),
304             dup(),
305             vmLoad(v0, float.class),
306             bufferStore(0, float.class),
307             dup(),
308             vmLoad(v1, float.class),
309             bufferStore(4, float.class),
310         });
311     }
312 
313     @Test
314     public void testStructHFA3() {
315         MemoryLayout struct = MemoryLayout.structLayout(C_FLOAT, C_FLOAT, C_FLOAT);
316 
317         MethodType mt = MethodType.methodType(void.class, MemorySegment.class, MemorySegment.class, MemorySegment.class);
318         FunctionDescriptor fd = FunctionDescriptor.ofVoid(struct, struct, struct);
319         CallArranger.Bindings bindings = CallArranger.LINUX.getBindings(mt, fd, false);
320 
321         assertFalse(bindings.isInMemoryReturn);
322         CallingSequence callingSequence = bindings.callingSequence;
323         assertEquals(callingSequence.methodType(), mt.insertParameterTypes(0, NativeSymbol.class));
324         assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS));
325 
326         checkArgumentBindings(callingSequence, new Binding[][]{
327             { unboxAddress(NativeSymbol.class), vmStore(r9, long.class) },
328             {
329                 dup(),
330                 bufferLoad(0, float.class),
331                 vmStore(v0, float.class),
332                 dup(),
333                 bufferLoad(4, float.class),
334                 vmStore(v1, float.class),
335                 bufferLoad(8, float.class),
336                 vmStore(v2, float.class)
337             },
338             {
339                 dup(),
340                 bufferLoad(0, float.class),
341                 vmStore(v3, float.class),
342                 dup(),
343                 bufferLoad(4, float.class),
344                 vmStore(v4, float.class),
345                 bufferLoad(8, float.class),
346                 vmStore(v5, float.class)
347             },

357         checkReturnBindings(callingSequence, new Binding[]{});
358     }
359 
360     @Test
361     public void testStructStackSpill() {
362         // A large (> 16 byte) struct argument that is spilled to the
363         // stack should be passed as a pointer to a copy and occupy one
364         // stack slot.
365 
366         MemoryLayout struct = MemoryLayout.structLayout(C_INT, C_INT, C_DOUBLE, C_INT);
367 
368         MethodType mt = MethodType.methodType(
369             void.class, MemorySegment.class, MemorySegment.class, int.class, int.class,
370             int.class, int.class, int.class, int.class, MemorySegment.class, int.class);
371         FunctionDescriptor fd = FunctionDescriptor.ofVoid(
372             struct, struct, C_INT, C_INT, C_INT, C_INT, C_INT, C_INT, struct, C_INT);
373         CallArranger.Bindings bindings = CallArranger.LINUX.getBindings(mt, fd, false);
374 
375         assertFalse(bindings.isInMemoryReturn);
376         CallingSequence callingSequence = bindings.callingSequence;
377         assertEquals(callingSequence.methodType(), mt.insertParameterTypes(0, NativeSymbol.class));
378         assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS));
379 
380         checkArgumentBindings(callingSequence, new Binding[][]{
381             { unboxAddress(NativeSymbol.class), vmStore(r9, long.class) },
382             { copy(struct), unboxAddress(MemorySegment.class), vmStore(r0, long.class) },
383             { copy(struct), unboxAddress(MemorySegment.class), vmStore(r1, long.class) },
384             { vmStore(r2, int.class) },
385             { vmStore(r3, int.class) },
386             { vmStore(r4, int.class) },
387             { vmStore(r5, int.class) },
388             { vmStore(r6, int.class) },
389             { vmStore(r7, int.class) },
390             { copy(struct), unboxAddress(MemorySegment.class), vmStore(stackStorage(0), long.class) },
391             { vmStore(stackStorage(1), int.class) },
392         });
393 
394         checkReturnBindings(callingSequence, new Binding[]{});
395     }
396 
397     @Test
398     public void testVarArgsInRegs() {
399         MethodType mt = MethodType.methodType(void.class, int.class, int.class, float.class);
400         FunctionDescriptor fd = FunctionDescriptor.ofVoid(C_INT).asVariadic(C_INT, C_FLOAT);
401         FunctionDescriptor fdExpected = FunctionDescriptor.ofVoid(ADDRESS, C_INT).asVariadic(C_INT, C_FLOAT);
402         CallArranger.Bindings bindings = CallArranger.LINUX.getBindings(mt, fd, false);
403 
404         assertFalse(bindings.isInMemoryReturn);
405         CallingSequence callingSequence = bindings.callingSequence;
406         assertEquals(callingSequence.methodType(), mt.insertParameterTypes(0, NativeSymbol.class));
407         assertEquals(callingSequence.functionDesc(), fdExpected);
408 
409         // This is identical to the non-variadic calling sequence
410         checkArgumentBindings(callingSequence, new Binding[][]{
411             { unboxAddress(NativeSymbol.class), vmStore(r9, long.class) },
412             { vmStore(r0, int.class) },
413             { vmStore(r1, int.class) },
414             { vmStore(v0, float.class) },
415         });
416 
417         checkReturnBindings(callingSequence, new Binding[]{});
418     }
419 
420     @Test
421     public void testVarArgsOnStack() {
422         MethodType mt = MethodType.methodType(void.class, int.class, int.class, float.class);
423         FunctionDescriptor fd = FunctionDescriptor.ofVoid(C_INT).asVariadic(C_INT, C_FLOAT);
424         FunctionDescriptor fdExpected = FunctionDescriptor.ofVoid(ADDRESS, C_INT).asVariadic(C_INT, C_FLOAT);
425         CallArranger.Bindings bindings = CallArranger.MACOS.getBindings(mt, fd, false);
426 
427         assertFalse(bindings.isInMemoryReturn);
428         CallingSequence callingSequence = bindings.callingSequence;
429         assertEquals(callingSequence.methodType(), mt.insertParameterTypes(0, NativeSymbol.class));
430         assertEquals(callingSequence.functionDesc(), fdExpected);
431 
432         // The two variadic arguments should be allocated on the stack
433         checkArgumentBindings(callingSequence, new Binding[][]{
434             { unboxAddress(NativeSymbol.class), vmStore(r9, long.class) },
435             { vmStore(r0, int.class) },
436             { vmStore(stackStorage(0), int.class) },
437             { vmStore(stackStorage(1), float.class) },
438         });
439 
440         checkReturnBindings(callingSequence, new Binding[]{});
441     }
442 }
< prev index next >