1 /*
  2  * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved.
  3  * Copyright (c) 2023 SAP SE. All rights reserved.
  4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  5  *
  6  * This code is free software; you can redistribute it and/or modify it
  7  * under the terms of the GNU General Public License version 2 only, as
  8  * published by the Free Software Foundation.
  9  *
 10  * This code is distributed in the hope that it will be useful, but WITHOUT
 11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 13  * version 2 for more details (a copy is included in the LICENSE file that
 14  * accompanied this code).
 15  *
 16  * You should have received a copy of the GNU General Public License version
 17  * 2 along with this work; if not, write to the Free Software Foundation,
 18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 19  *
 20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 21  * or visit www.oracle.com if you need additional information or have any
 22  * questions.
 23  */
 24 
 25 /*
 26  * @test
 27  * @summary Test passing of Homogeneous Float Aggregates.
 28  * @enablePreview
 29  * @requires jdk.foreign.linker != "UNSUPPORTED"
 30  *
 31  * @run testng/othervm --enable-native-access=ALL-UNNAMED TestHFA
 32  */
 33 
 34 import java.lang.foreign.*;
 35 import java.lang.invoke.MethodHandle;
 36 import java.lang.invoke.MethodHandles;
 37 import java.lang.invoke.MethodType;
 38 import org.testng.annotations.Test;
 39 
 40 import static java.lang.foreign.ValueLayout.*;
 41 
 42 public class TestHFA {
 43 
 44     static {
 45         System.loadLibrary("TestHFA");
 46     }
 47 
 48     final static Linker abi = Linker.nativeLinker();
 49     final static SymbolLookup lookup = SymbolLookup.loaderLookup();
 50 
 51     static final OfFloat FLOAT = JAVA_FLOAT.withByteAlignment(4);
 52 
 53     final static GroupLayout S_FFLayout = MemoryLayout.structLayout(
 54         FLOAT.withName("p0"),
 55         FLOAT.withName("p1")
 56     ).withName("S_FF");
 57 
 58     final static GroupLayout S_FFFFFFFLayout = MemoryLayout.structLayout(
 59         FLOAT.withName("p0"),
 60         FLOAT.withName("p1"),
 61         FLOAT.withName("p2"),
 62         FLOAT.withName("p3"),
 63         FLOAT.withName("p4"),
 64         FLOAT.withName("p5"),
 65         FLOAT.withName("p6")
 66     ).withName("S_FFFF");
 67 
 68     static final FunctionDescriptor fdadd_float_structs = FunctionDescriptor.of(S_FFFFFFFLayout, S_FFFFFFFLayout, S_FFFFFFFLayout);
 69     static final FunctionDescriptor fdadd_float_to_struct_after_floats = FunctionDescriptor.of(S_FFLayout,
 70         JAVA_FLOAT, JAVA_FLOAT, JAVA_FLOAT, JAVA_FLOAT, JAVA_FLOAT,
 71         JAVA_FLOAT, JAVA_FLOAT, JAVA_FLOAT, JAVA_FLOAT, JAVA_FLOAT,
 72         JAVA_FLOAT, JAVA_FLOAT, S_FFLayout, JAVA_FLOAT);
 73     static final FunctionDescriptor fdadd_float_to_struct_after_structs = FunctionDescriptor.of(S_FFLayout,
 74         S_FFLayout, S_FFLayout, S_FFLayout, S_FFLayout, S_FFLayout, S_FFLayout,
 75         S_FFLayout, JAVA_FLOAT);
 76     static final FunctionDescriptor fdadd_double_to_struct_after_structs = FunctionDescriptor.of(S_FFLayout,
 77         S_FFLayout, S_FFLayout, S_FFLayout, S_FFLayout, S_FFLayout, S_FFLayout,
 78         S_FFLayout, JAVA_DOUBLE);
 79     static final FunctionDescriptor fdadd_float_to_large_struct_after_structs = FunctionDescriptor.of(S_FFFFFFFLayout,
 80         S_FFLayout, S_FFLayout, S_FFLayout, S_FFLayout, S_FFLayout, S_FFLayout,
 81         S_FFFFFFFLayout, JAVA_FLOAT);
 82 
 83     static final FunctionDescriptor fdpass_two_large_structs = FunctionDescriptor.of(S_FFFFFFFLayout, ADDRESS, S_FFFFFFFLayout, S_FFFFFFFLayout);
 84     static final FunctionDescriptor fdpass_struct_after_floats = FunctionDescriptor.of(S_FFLayout, ADDRESS, S_FFLayout, JAVA_FLOAT);
 85     static final FunctionDescriptor fdpass_struct_after_structs = FunctionDescriptor.of(S_FFLayout, ADDRESS, S_FFLayout, JAVA_FLOAT);
 86     static final FunctionDescriptor fdpass_struct_after_structs_plus_double = FunctionDescriptor.of(S_FFLayout, ADDRESS, S_FFLayout, JAVA_DOUBLE);
 87     static final FunctionDescriptor fdpass_large_struct_after_structs = FunctionDescriptor.of(S_FFFFFFFLayout, ADDRESS, S_FFFFFFFLayout, JAVA_FLOAT);
 88 
 89     final static MethodHandle mhadd_float_structs = abi.downcallHandle(lookup.find("add_float_structs").orElseThrow(),
 90         fdadd_float_structs);
 91     final static MethodHandle mhadd_float_to_struct_after_floats = abi.downcallHandle(lookup.find("add_float_to_struct_after_floats").orElseThrow(),
 92         fdadd_float_to_struct_after_floats);
 93     final static MethodHandle mhadd_float_to_struct_after_structs = abi.downcallHandle(lookup.find("add_float_to_struct_after_structs").orElseThrow(),
 94         fdadd_float_to_struct_after_structs);
 95     final static MethodHandle mhadd_double_to_struct_after_structs = abi.downcallHandle(lookup.find("add_double_to_struct_after_structs").orElseThrow(),
 96         fdadd_double_to_struct_after_structs);
 97     final static MethodHandle mhadd_float_to_large_struct_after_structs = abi.downcallHandle(lookup.find("add_float_to_large_struct_after_structs").orElseThrow(),
 98         fdadd_float_to_large_struct_after_structs);
 99 
100     final static MethodHandle mhpass_two_large_structs = abi.downcallHandle(lookup.find("pass_two_large_structs").orElseThrow(),
101         fdpass_two_large_structs);
102     final static MethodHandle mhpass_struct_after_floats = abi.downcallHandle(lookup.find("pass_struct_after_floats").orElseThrow(),
103         fdpass_struct_after_floats);
104     final static MethodHandle mhpass_struct_after_structs = abi.downcallHandle(lookup.find("pass_struct_after_structs").orElseThrow(),
105         fdpass_struct_after_structs);
106     final static MethodHandle mhpass_struct_after_structs_plus_double = abi.downcallHandle(lookup.find("pass_struct_after_structs_plus_double").orElseThrow(),
107         fdpass_struct_after_structs_plus_double);
108     final static MethodHandle mhpass_large_struct_after_structs = abi.downcallHandle(lookup.find("pass_large_struct_after_structs").orElseThrow(),
109         fdpass_large_struct_after_structs);
110 
111     @Test
112     public static void testAddFloatStructs() {
113         float p0 = 0.0f, p1 = 0.0f, p2 = 0.0f, p3 = 0.0f, p4 = 0.0f, p5 = 0.0f, p6 = 0.0f;
114         try {
115             Arena arena = Arena.ofConfined();
116             MemorySegment s = arena.allocate(S_FFFFFFFLayout);
117             s.set(FLOAT, 0, 1.0f);
118             s.set(FLOAT, 4, 2.0f);
119             s.set(FLOAT, 8, 3.0f);
120             s.set(FLOAT, 12, 4.0f);
121             s.set(FLOAT, 16, 5.0f);
122             s.set(FLOAT, 20, 6.0f);
123             s.set(FLOAT, 24, 7.0f);
124             s = (MemorySegment)mhadd_float_structs.invokeExact((SegmentAllocator)arena, s, s);
125             p0 = s.get(FLOAT, 0);
126             p1 = s.get(FLOAT, 4);
127             p2 = s.get(FLOAT, 8);
128             p3 = s.get(FLOAT, 12);
129             p4 = s.get(FLOAT, 16);
130             p5 = s.get(FLOAT, 20);
131             p6 = s.get(FLOAT, 24);
132             System.out.println("S_FFFFFFF(" + p0 + ";" + p1 + ";" + p2 + ";" + p3 + ";" + p4 + ";" + p5 + ";" + p6 + ")");
133         } catch (Throwable t) {
134             t.printStackTrace();
135         }
136         if (p0 != 2.0f || p1 != 4.0f || p2 != 6.0f || p3 != 8.0f || p4 != 10.0f || p5 != 12.0f || p6 != 14.0f)
137             throw new RuntimeException("add_float_structs error");
138     }
139 
140     @Test
141     public static void testAddFloatToStructAfterFloats() {
142         float p0 = 0.0f, p1 = 0.0f;
143         try {
144             Arena arena = Arena.ofConfined();
145             MemorySegment s = arena.allocate(S_FFLayout);
146             s.set(FLOAT, 0, 1.0f);
147             s.set(FLOAT, 4, 1.0f);
148             s = (MemorySegment)mhadd_float_to_struct_after_floats.invokeExact((SegmentAllocator)arena,
149                 1.0f, 2.0f, 3.0f, 4.0f, 5.0f,
150                 6.0f, 7.0f, 8.0f, 9.0f, 10.0f,
151                 11.0f, 12.0f, s, 1.0f);
152             p0 = s.get(FLOAT, 0);
153             p1 = s.get(FLOAT, 4);
154             System.out.println("S_FF(" + p0 + ";" + p1 + ")");
155         } catch (Throwable t) {
156             t.printStackTrace();
157         }
158         if (p0 != 2.0f || p1 != 1.0f) throw new RuntimeException("add_float_to_struct_after_floats error");
159     }
160 
161     @Test
162     public static void testAddFloatToStructAfterStructs() {
163         float p0 = 0.0f, p1 = 0.0f;
164         try {
165             Arena arena = Arena.ofConfined();
166             MemorySegment s = arena.allocate(S_FFLayout);
167             s.set(FLOAT, 0, 1.0f);
168             s.set(FLOAT, 4, 1.0f);
169             s = (MemorySegment)mhadd_float_to_struct_after_structs.invokeExact((SegmentAllocator)arena,
170                  s, s, s, s, s, s,
171                  s, 1.0f);
172             p0 = s.get(FLOAT, 0);
173             p1 = s.get(FLOAT, 4);
174             System.out.println("S_FF(" + p0 + ";" + p1 + ")");
175         } catch (Throwable t) {
176             t.printStackTrace();
177         }
178         if (p0 != 2.0f || p1 != 1.0f) throw new RuntimeException("add_float_to_struct_after_structs error");
179     }
180 
181     @Test
182     public static void testAddDoubleToStructAfterStructs() {
183         float p0 = 0.0f, p1 = 0.0f;
184         try {
185             Arena arena = Arena.ofConfined();
186             MemorySegment s = arena.allocate(S_FFLayout);
187             s.set(FLOAT, 0, 1.0f);
188             s.set(FLOAT, 4, 1.0f);
189             s = (MemorySegment)mhadd_double_to_struct_after_structs.invokeExact((SegmentAllocator)arena,
190                  s, s, s, s, s, s,
191                  s, 1.0d);
192             p0 = s.get(FLOAT, 0);
193             p1 = s.get(FLOAT, 4);
194             System.out.println("S_FF(" + p0 + ";" + p1 + ")");
195         } catch (Throwable t) {
196             t.printStackTrace();
197         }
198         if (p0 != 2.0f || p1 != 1.0f) throw new RuntimeException("add_double_to_struct_after_structs error");
199     }
200 
201     @Test
202     public static void testAddFloatToLargeStructAfterStructs() {
203         float p0 = 0.0f, p1 = 0.0f, p2 = 0.0f, p3 = 0.0f, p4 = 0.0f, p5 = 0.0f, p6 = 0.0f;
204         try {
205             Arena arena = Arena.ofConfined();
206             MemorySegment s = arena.allocate(S_FFFFFFFLayout);
207             s.set(FLOAT, 0, 1.0f);
208             s.set(FLOAT, 4, 2.0f);
209             s.set(FLOAT, 8, 3.0f);
210             s.set(FLOAT, 12, 4.0f);
211             s.set(FLOAT, 16, 5.0f);
212             s.set(FLOAT, 20, 6.0f);
213             s.set(FLOAT, 24, 7.0f);
214             s = (MemorySegment)mhadd_float_to_large_struct_after_structs.invokeExact((SegmentAllocator)arena,
215                  s, s, s, s, s, s,
216                  s, 1.0f);
217             p0 = s.get(FLOAT, 0);
218             p1 = s.get(FLOAT, 4);
219             p2 = s.get(FLOAT, 8);
220             p3 = s.get(FLOAT, 12);
221             p4 = s.get(FLOAT, 16);
222             p5 = s.get(FLOAT, 20);
223             p6 = s.get(FLOAT, 24);
224             System.out.println("S_FFFFFFF(" + p0 + ";" + p1 + ";" + p2 + ";" + p3 + ";" + p4 + ";" + p5 + ";" + p6 + ")");
225         } catch (Throwable t) {
226             t.printStackTrace();
227         }
228         if (p0 != 2.0f || p1 != 2.0f || p2 != 3.0f || p3 != 4.0f || p4 != 5.0f || p5 != 6.0f || p6 != 7.0f)
229             throw new RuntimeException("add_float_to_large_struct_after_structs error");
230     }
231 
232     // Java versions for Upcall tests.
233     public static MemorySegment addFloatStructs(MemorySegment p0, MemorySegment p1) {
234         float val0 = p0.get(FLOAT,  0) + p1.get(FLOAT,  0);
235         float val1 = p0.get(FLOAT,  4) + p1.get(FLOAT,  4);
236         float val2 = p0.get(FLOAT,  8) + p1.get(FLOAT,  8);
237         float val3 = p0.get(FLOAT, 12) + p1.get(FLOAT, 12);
238         float val4 = p0.get(FLOAT, 16) + p1.get(FLOAT, 16);
239         float val5 = p0.get(FLOAT, 20) + p1.get(FLOAT, 20);
240         float val6 = p0.get(FLOAT, 24) + p1.get(FLOAT, 24);
241         p0.set(FLOAT,  0, val0);
242         p0.set(FLOAT,  4, val1);
243         p0.set(FLOAT,  8, val2);
244         p0.set(FLOAT, 12, val3);
245         p0.set(FLOAT, 16, val4);
246         p0.set(FLOAT, 20, val5);
247         p0.set(FLOAT, 24, val6);
248         return p0;
249     }
250 
251     public static MemorySegment addFloatToStructAfterFloats(
252             float f1, float f2, float f3, float f4, float f5,
253             float f6, float f7, float f8, float f9, float f10,
254             float f11, float f12, MemorySegment s, float f) {
255         float val = s.get(FLOAT, 0);
256         s.set(FLOAT, 0, val + f);
257         return s;
258     }
259 
260     public static MemorySegment addFloatToStructAfterStructs(
261             MemorySegment s1, MemorySegment s2, MemorySegment s3,
262             MemorySegment s4, MemorySegment s5, MemorySegment s6,
263             MemorySegment s, float f) {
264         float val = s.get(FLOAT, 0);
265         s.set(FLOAT, 0, val + f);
266         return s;
267     }
268 
269     public static MemorySegment addDoubleToStructAfterStructs(
270             MemorySegment s1, MemorySegment s2, MemorySegment s3,
271             MemorySegment s4, MemorySegment s5, MemorySegment s6,
272             MemorySegment s, double f) {
273         float val = s.get(FLOAT, 0);
274         s.set(FLOAT, 0, val + (float) f);
275         return s;
276     }
277 
278     @Test
279     public static void testAddFloatStructsUpcall() {
280         float p0 = 0.0f, p1 = 0.0f, p2 = 0.0f, p3 = 0.0f, p4 = 0.0f, p5 = 0.0f, p6 = 0.0f;
281         try {
282             Arena arena = Arena.ofConfined();
283             MemorySegment s = arena.allocate(S_FFFFFFFLayout);
284             s.set(FLOAT,  0, 1.0f);
285             s.set(FLOAT,  4, 2.0f);
286             s.set(FLOAT,  8, 3.0f);
287             s.set(FLOAT, 12, 4.0f);
288             s.set(FLOAT, 16, 5.0f);
289             s.set(FLOAT, 20, 6.0f);
290             s.set(FLOAT, 24, 7.0f);
291             MethodType mt = MethodType.methodType(MemorySegment.class,
292                                                   MemorySegment.class, MemorySegment.class);
293             MemorySegment stub = abi.upcallStub(MethodHandles.lookup().findStatic(TestHFA.class, "addFloatStructs", mt),
294                                                 fdadd_float_structs, arena);
295             s = (MemorySegment)mhpass_two_large_structs.invokeExact((SegmentAllocator)arena, stub, s, s);
296             p0 = s.get(FLOAT,  0);
297             p1 = s.get(FLOAT,  4);
298             p2 = s.get(FLOAT,  8);
299             p3 = s.get(FLOAT, 12);
300             p4 = s.get(FLOAT, 16);
301             p5 = s.get(FLOAT, 20);
302             p6 = s.get(FLOAT, 24);
303             System.out.println("S_FFFFFFF(" + p0 + ";" + p1 + ";" + p2 + ";" + p3 + ";" + p4 + ";" + p5 + ";" + p6 + ")");
304         } catch (Throwable t) {
305             t.printStackTrace();
306         }
307         if (p0 != 2.0f || p1 != 4.0f || p2 != 6.0f || p3 != 8.0f || p4 != 10.0f || p5 != 12.0f || p6 != 14.0f)
308             throw new RuntimeException("add_float_structs (Upcall)");
309     }
310 
311     @Test
312     public static void testAddFloatToStructAfterFloatsUpcall() {
313         float p0 = 0.0f, p1 = 0.0f;
314         try {
315             Arena arena = Arena.ofConfined();
316             MemorySegment s = arena.allocate(S_FFLayout);
317             s.set(FLOAT, 0, 1.0f);
318             s.set(FLOAT, 4, 1.0f);
319             MethodType mt = MethodType.methodType(MemorySegment.class,
320                                                   float.class, float.class, float.class, float.class,
321                                                   float.class, float.class, float.class, float.class,
322                                                   float.class, float.class, float.class, float.class,
323                                                   MemorySegment.class, float.class);
324             MemorySegment stub = abi.upcallStub(MethodHandles.lookup().findStatic(TestHFA.class, "addFloatToStructAfterFloats", mt),
325                                                 fdadd_float_to_struct_after_floats, arena);
326             s = (MemorySegment)mhpass_struct_after_floats.invokeExact((SegmentAllocator)arena, stub, s, 1.0f);
327             p0 = s.get(FLOAT, 0);
328             p1 = s.get(FLOAT, 4);
329             System.out.println("S_FF(" + p0 + ";" + p1 + ")");
330         } catch (Throwable t) {
331             t.printStackTrace();
332         }
333         if (p0 != 2.0f || p1 != 1.0f) throw new RuntimeException("add_float_to_struct_after_floats (Upcall)");
334     }
335 
336     @Test
337     public static void testAddFloatToStructAfterStructsUpcall() {
338         float p0 = 0.0f, p1 = 0.0f;
339         try {
340             Arena arena = Arena.ofConfined();
341             MemorySegment s = arena.allocate(S_FFLayout);
342             s.set(FLOAT, 0, 1.0f);
343             s.set(FLOAT, 4, 1.0f);
344             MethodType mt = MethodType.methodType(MemorySegment.class,
345                                                   MemorySegment.class, MemorySegment.class, MemorySegment.class,
346                                                   MemorySegment.class, MemorySegment.class, MemorySegment.class,
347                                                   MemorySegment.class, float.class);
348             MemorySegment stub = abi.upcallStub(MethodHandles.lookup().findStatic(TestHFA.class, "addFloatToStructAfterStructs", mt),
349                                                 fdadd_float_to_struct_after_structs, arena);
350             s = (MemorySegment)mhpass_struct_after_structs.invokeExact((SegmentAllocator)arena, stub, s, 1.0f);
351             p0 = s.get(FLOAT, 0);
352             p1 = s.get(FLOAT, 4);
353             System.out.println("S_FF(" + p0 + ";" + p1 + ")");
354         } catch (Throwable t) {
355             t.printStackTrace();
356         }
357         if (p0 != 2.0f || p1 != 1.0f) throw new RuntimeException("add_float_to_struct_after_structs (Upcall)");
358     }
359 
360     @Test
361     public static void testAddDoubleToStructAfterStructsUpcall() {
362         float p0 = 0.0f, p1 = 0.0f;
363         try {
364             Arena arena = Arena.ofConfined();
365             MemorySegment s = arena.allocate(S_FFLayout);
366             s.set(FLOAT, 0, 1.0f);
367             s.set(FLOAT, 4, 1.0f);
368             MethodType mt = MethodType.methodType(MemorySegment.class,
369                                                   MemorySegment.class, MemorySegment.class, MemorySegment.class,
370                                                   MemorySegment.class, MemorySegment.class, MemorySegment.class,
371                                                   MemorySegment.class, double.class);
372             MemorySegment stub = abi.upcallStub(MethodHandles.lookup().findStatic(TestHFA.class, "addDoubleToStructAfterStructs", mt),
373                                                 fdadd_double_to_struct_after_structs, arena);
374             s = (MemorySegment)mhpass_struct_after_structs_plus_double.invokeExact((SegmentAllocator)arena, stub, s, 1.0d);
375             p0 = s.get(FLOAT, 0);
376             p1 = s.get(FLOAT, 4);
377             System.out.println("S_FF(" + p0 + ";" + p1 + ")");
378         } catch (Throwable t) {
379             t.printStackTrace();
380         }
381         if (p0 != 2.0f || p1 != 1.0f) throw new RuntimeException("add_double_to_struct_after_structs (Upcall)");
382     }
383 
384     @Test
385     public static void testAddFloatToLargeStructAfterStructsUpcall() {
386         float p0 = 0.0f, p1 = 0.0f, p2 = 0.0f, p3 = 0.0f, p4 = 0.0f, p5 = 0.0f, p6 = 0.0f;
387         try {
388             Arena arena = Arena.ofConfined();
389             MemorySegment s = arena.allocate(S_FFFFFFFLayout);
390             s.set(FLOAT,  0, 1.0f);
391             s.set(FLOAT,  4, 2.0f);
392             s.set(FLOAT,  8, 3.0f);
393             s.set(FLOAT, 12, 4.0f);
394             s.set(FLOAT, 16, 5.0f);
395             s.set(FLOAT, 20, 6.0f);
396             s.set(FLOAT, 24, 7.0f);
397             MethodType mt = MethodType.methodType(MemorySegment.class,
398                                                   MemorySegment.class, MemorySegment.class, MemorySegment.class,
399                                                   MemorySegment.class, MemorySegment.class, MemorySegment.class,
400                                                   MemorySegment.class, float.class);
401             MemorySegment stub = abi.upcallStub(MethodHandles.lookup().findStatic(TestHFA.class, "addFloatToStructAfterStructs", mt),
402                                                 fdadd_float_to_large_struct_after_structs, arena);
403             s = (MemorySegment)mhpass_large_struct_after_structs.invokeExact((SegmentAllocator)arena, stub, s, 1.0f);
404             p0 = s.get(FLOAT,  0);
405             p1 = s.get(FLOAT,  4);
406             p2 = s.get(FLOAT,  8);
407             p3 = s.get(FLOAT, 12);
408             p4 = s.get(FLOAT, 16);
409             p5 = s.get(FLOAT, 20);
410             p6 = s.get(FLOAT, 24);
411             System.out.println("S_FFFFFFF(" + p0 + ";" + p1 + ";" + p2 + ";" + p3 + ";" + p4 + ";" + p5 + ";" + p6 + ")");
412         } catch (Throwable t) {
413             t.printStackTrace();
414         }
415         if (p0 != 2.0f || p1 != 2.0f || p2 != 3.0f || p3 != 4.0f || p4 != 5.0f || p5 != 6.0f || p6 != 7.0f)
416             throw new RuntimeException("add_float_to_large_struct_after_structs (Upcall)");
417     }
418 }