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  *
 29  * @run testng/othervm --enable-native-access=ALL-UNNAMED TestHFA
 30  */
 31 
 32 import java.lang.foreign.*;
 33 import java.lang.invoke.MethodHandle;
 34 import java.lang.invoke.MethodHandles;
 35 import java.lang.invoke.MethodType;
 36 import org.testng.annotations.Test;
 37 
 38 import static java.lang.foreign.ValueLayout.*;
 39 
 40 public class TestHFA {
 41 
 42     static {
 43         System.loadLibrary("TestHFA");
 44     }
 45 
 46     final static Linker abi = Linker.nativeLinker();
 47     final static SymbolLookup lookup = SymbolLookup.loaderLookup();
 48 
 49     static final OfFloat FLOAT = JAVA_FLOAT.withByteAlignment(4);
 50 
 51     final static GroupLayout S_FFLayout = MemoryLayout.structLayout(
 52         FLOAT.withName("p0"),
 53         FLOAT.withName("p1")
 54     ).withName("S_FF");
 55 
 56     final static GroupLayout S_FFFFFFFLayout = MemoryLayout.structLayout(
 57         FLOAT.withName("p0"),
 58         FLOAT.withName("p1"),
 59         FLOAT.withName("p2"),
 60         FLOAT.withName("p3"),
 61         FLOAT.withName("p4"),
 62         FLOAT.withName("p5"),
 63         FLOAT.withName("p6")
 64     ).withName("S_FFFF");
 65 
 66     static final FunctionDescriptor fdadd_float_structs = FunctionDescriptor.of(S_FFFFFFFLayout, S_FFFFFFFLayout, S_FFFFFFFLayout);
 67     static final FunctionDescriptor fdadd_float_to_struct_after_floats = FunctionDescriptor.of(S_FFLayout,
 68         JAVA_FLOAT, JAVA_FLOAT, JAVA_FLOAT, JAVA_FLOAT, JAVA_FLOAT,
 69         JAVA_FLOAT, JAVA_FLOAT, JAVA_FLOAT, JAVA_FLOAT, JAVA_FLOAT,
 70         JAVA_FLOAT, JAVA_FLOAT, S_FFLayout, JAVA_FLOAT);
 71     static final FunctionDescriptor fdadd_float_to_struct_after_structs = FunctionDescriptor.of(S_FFLayout,
 72         S_FFLayout, S_FFLayout, S_FFLayout, S_FFLayout, S_FFLayout, S_FFLayout,
 73         S_FFLayout, JAVA_FLOAT);
 74     static final FunctionDescriptor fdadd_double_to_struct_after_structs = FunctionDescriptor.of(S_FFLayout,
 75         S_FFLayout, S_FFLayout, S_FFLayout, S_FFLayout, S_FFLayout, S_FFLayout,
 76         S_FFLayout, JAVA_DOUBLE);
 77     static final FunctionDescriptor fdadd_float_to_large_struct_after_structs = FunctionDescriptor.of(S_FFFFFFFLayout,
 78         S_FFLayout, S_FFLayout, S_FFLayout, S_FFLayout, S_FFLayout, S_FFLayout,
 79         S_FFFFFFFLayout, JAVA_FLOAT);
 80 
 81     static final FunctionDescriptor fdpass_two_large_structs = FunctionDescriptor.of(S_FFFFFFFLayout, ADDRESS, S_FFFFFFFLayout, S_FFFFFFFLayout);
 82     static final FunctionDescriptor fdpass_struct_after_floats = FunctionDescriptor.of(S_FFLayout, ADDRESS, S_FFLayout, JAVA_FLOAT);
 83     static final FunctionDescriptor fdpass_struct_after_structs = FunctionDescriptor.of(S_FFLayout, ADDRESS, S_FFLayout, JAVA_FLOAT);
 84     static final FunctionDescriptor fdpass_struct_after_structs_plus_double = FunctionDescriptor.of(S_FFLayout, ADDRESS, S_FFLayout, JAVA_DOUBLE);
 85     static final FunctionDescriptor fdpass_large_struct_after_structs = FunctionDescriptor.of(S_FFFFFFFLayout, ADDRESS, S_FFFFFFFLayout, JAVA_FLOAT);
 86 
 87     final static MethodHandle mhadd_float_structs = abi.downcallHandle(lookup.find("add_float_structs").orElseThrow(),
 88         fdadd_float_structs);
 89     final static MethodHandle mhadd_float_to_struct_after_floats = abi.downcallHandle(lookup.find("add_float_to_struct_after_floats").orElseThrow(),
 90         fdadd_float_to_struct_after_floats);
 91     final static MethodHandle mhadd_float_to_struct_after_structs = abi.downcallHandle(lookup.find("add_float_to_struct_after_structs").orElseThrow(),
 92         fdadd_float_to_struct_after_structs);
 93     final static MethodHandle mhadd_double_to_struct_after_structs = abi.downcallHandle(lookup.find("add_double_to_struct_after_structs").orElseThrow(),
 94         fdadd_double_to_struct_after_structs);
 95     final static MethodHandle mhadd_float_to_large_struct_after_structs = abi.downcallHandle(lookup.find("add_float_to_large_struct_after_structs").orElseThrow(),
 96         fdadd_float_to_large_struct_after_structs);
 97 
 98     final static MethodHandle mhpass_two_large_structs = abi.downcallHandle(lookup.find("pass_two_large_structs").orElseThrow(),
 99         fdpass_two_large_structs);
100     final static MethodHandle mhpass_struct_after_floats = abi.downcallHandle(lookup.find("pass_struct_after_floats").orElseThrow(),
101         fdpass_struct_after_floats);
102     final static MethodHandle mhpass_struct_after_structs = abi.downcallHandle(lookup.find("pass_struct_after_structs").orElseThrow(),
103         fdpass_struct_after_structs);
104     final static MethodHandle mhpass_struct_after_structs_plus_double = abi.downcallHandle(lookup.find("pass_struct_after_structs_plus_double").orElseThrow(),
105         fdpass_struct_after_structs_plus_double);
106     final static MethodHandle mhpass_large_struct_after_structs = abi.downcallHandle(lookup.find("pass_large_struct_after_structs").orElseThrow(),
107         fdpass_large_struct_after_structs);
108 
109     @Test
110     public static void testAddFloatStructs() {
111         float p0 = 0.0f, p1 = 0.0f, p2 = 0.0f, p3 = 0.0f, p4 = 0.0f, p5 = 0.0f, p6 = 0.0f;
112         try {
113             Arena arena = Arena.ofConfined();
114             MemorySegment s = arena.allocate(S_FFFFFFFLayout);
115             s.set(FLOAT, 0, 1.0f);
116             s.set(FLOAT, 4, 2.0f);
117             s.set(FLOAT, 8, 3.0f);
118             s.set(FLOAT, 12, 4.0f);
119             s.set(FLOAT, 16, 5.0f);
120             s.set(FLOAT, 20, 6.0f);
121             s.set(FLOAT, 24, 7.0f);
122             s = (MemorySegment)mhadd_float_structs.invokeExact((SegmentAllocator)arena, s, s);
123             p0 = s.get(FLOAT, 0);
124             p1 = s.get(FLOAT, 4);
125             p2 = s.get(FLOAT, 8);
126             p3 = s.get(FLOAT, 12);
127             p4 = s.get(FLOAT, 16);
128             p5 = s.get(FLOAT, 20);
129             p6 = s.get(FLOAT, 24);
130             System.out.println("S_FFFFFFF(" + p0 + ";" + p1 + ";" + p2 + ";" + p3 + ";" + p4 + ";" + p5 + ";" + p6 + ")");
131         } catch (Throwable t) {
132             t.printStackTrace();
133         }
134         if (p0 != 2.0f || p1 != 4.0f || p2 != 6.0f || p3 != 8.0f || p4 != 10.0f || p5 != 12.0f || p6 != 14.0f)
135             throw new RuntimeException("add_float_structs error");
136     }
137 
138     @Test
139     public static void testAddFloatToStructAfterFloats() {
140         float p0 = 0.0f, p1 = 0.0f;
141         try {
142             Arena arena = Arena.ofConfined();
143             MemorySegment s = arena.allocate(S_FFLayout);
144             s.set(FLOAT, 0, 1.0f);
145             s.set(FLOAT, 4, 1.0f);
146             s = (MemorySegment)mhadd_float_to_struct_after_floats.invokeExact((SegmentAllocator)arena,
147                 1.0f, 2.0f, 3.0f, 4.0f, 5.0f,
148                 6.0f, 7.0f, 8.0f, 9.0f, 10.0f,
149                 11.0f, 12.0f, s, 1.0f);
150             p0 = s.get(FLOAT, 0);
151             p1 = s.get(FLOAT, 4);
152             System.out.println("S_FF(" + p0 + ";" + p1 + ")");
153         } catch (Throwable t) {
154             t.printStackTrace();
155         }
156         if (p0 != 2.0f || p1 != 1.0f) throw new RuntimeException("add_float_to_struct_after_floats error");
157     }
158 
159     @Test
160     public static void testAddFloatToStructAfterStructs() {
161         float p0 = 0.0f, p1 = 0.0f;
162         try {
163             Arena arena = Arena.ofConfined();
164             MemorySegment s = arena.allocate(S_FFLayout);
165             s.set(FLOAT, 0, 1.0f);
166             s.set(FLOAT, 4, 1.0f);
167             s = (MemorySegment)mhadd_float_to_struct_after_structs.invokeExact((SegmentAllocator)arena,
168                  s, s, s, s, s, s,
169                  s, 1.0f);
170             p0 = s.get(FLOAT, 0);
171             p1 = s.get(FLOAT, 4);
172             System.out.println("S_FF(" + p0 + ";" + p1 + ")");
173         } catch (Throwable t) {
174             t.printStackTrace();
175         }
176         if (p0 != 2.0f || p1 != 1.0f) throw new RuntimeException("add_float_to_struct_after_structs error");
177     }
178 
179     @Test
180     public static void testAddDoubleToStructAfterStructs() {
181         float p0 = 0.0f, p1 = 0.0f;
182         try {
183             Arena arena = Arena.ofConfined();
184             MemorySegment s = arena.allocate(S_FFLayout);
185             s.set(FLOAT, 0, 1.0f);
186             s.set(FLOAT, 4, 1.0f);
187             s = (MemorySegment)mhadd_double_to_struct_after_structs.invokeExact((SegmentAllocator)arena,
188                  s, s, s, s, s, s,
189                  s, 1.0d);
190             p0 = s.get(FLOAT, 0);
191             p1 = s.get(FLOAT, 4);
192             System.out.println("S_FF(" + p0 + ";" + p1 + ")");
193         } catch (Throwable t) {
194             t.printStackTrace();
195         }
196         if (p0 != 2.0f || p1 != 1.0f) throw new RuntimeException("add_double_to_struct_after_structs error");
197     }
198 
199     @Test
200     public static void testAddFloatToLargeStructAfterStructs() {
201         float p0 = 0.0f, p1 = 0.0f, p2 = 0.0f, p3 = 0.0f, p4 = 0.0f, p5 = 0.0f, p6 = 0.0f;
202         try {
203             Arena arena = Arena.ofConfined();
204             MemorySegment s = arena.allocate(S_FFFFFFFLayout);
205             s.set(FLOAT, 0, 1.0f);
206             s.set(FLOAT, 4, 2.0f);
207             s.set(FLOAT, 8, 3.0f);
208             s.set(FLOAT, 12, 4.0f);
209             s.set(FLOAT, 16, 5.0f);
210             s.set(FLOAT, 20, 6.0f);
211             s.set(FLOAT, 24, 7.0f);
212             s = (MemorySegment)mhadd_float_to_large_struct_after_structs.invokeExact((SegmentAllocator)arena,
213                  s, s, s, s, s, s,
214                  s, 1.0f);
215             p0 = s.get(FLOAT, 0);
216             p1 = s.get(FLOAT, 4);
217             p2 = s.get(FLOAT, 8);
218             p3 = s.get(FLOAT, 12);
219             p4 = s.get(FLOAT, 16);
220             p5 = s.get(FLOAT, 20);
221             p6 = s.get(FLOAT, 24);
222             System.out.println("S_FFFFFFF(" + p0 + ";" + p1 + ";" + p2 + ";" + p3 + ";" + p4 + ";" + p5 + ";" + p6 + ")");
223         } catch (Throwable t) {
224             t.printStackTrace();
225         }
226         if (p0 != 2.0f || p1 != 2.0f || p2 != 3.0f || p3 != 4.0f || p4 != 5.0f || p5 != 6.0f || p6 != 7.0f)
227             throw new RuntimeException("add_float_to_large_struct_after_structs error");
228     }
229 
230     // Java versions for Upcall tests.
231     public static MemorySegment addFloatStructs(MemorySegment p0, MemorySegment p1) {
232         float val0 = p0.get(FLOAT,  0) + p1.get(FLOAT,  0);
233         float val1 = p0.get(FLOAT,  4) + p1.get(FLOAT,  4);
234         float val2 = p0.get(FLOAT,  8) + p1.get(FLOAT,  8);
235         float val3 = p0.get(FLOAT, 12) + p1.get(FLOAT, 12);
236         float val4 = p0.get(FLOAT, 16) + p1.get(FLOAT, 16);
237         float val5 = p0.get(FLOAT, 20) + p1.get(FLOAT, 20);
238         float val6 = p0.get(FLOAT, 24) + p1.get(FLOAT, 24);
239         p0.set(FLOAT,  0, val0);
240         p0.set(FLOAT,  4, val1);
241         p0.set(FLOAT,  8, val2);
242         p0.set(FLOAT, 12, val3);
243         p0.set(FLOAT, 16, val4);
244         p0.set(FLOAT, 20, val5);
245         p0.set(FLOAT, 24, val6);
246         return p0;
247     }
248 
249     public static MemorySegment addFloatToStructAfterFloats(
250             float f1, float f2, float f3, float f4, float f5,
251             float f6, float f7, float f8, float f9, float f10,
252             float f11, float f12, MemorySegment s, float f) {
253         float val = s.get(FLOAT, 0);
254         s.set(FLOAT, 0, val + f);
255         return s;
256     }
257 
258     public static MemorySegment addFloatToStructAfterStructs(
259             MemorySegment s1, MemorySegment s2, MemorySegment s3,
260             MemorySegment s4, MemorySegment s5, MemorySegment s6,
261             MemorySegment s, float f) {
262         float val = s.get(FLOAT, 0);
263         s.set(FLOAT, 0, val + f);
264         return s;
265     }
266 
267     public static MemorySegment addDoubleToStructAfterStructs(
268             MemorySegment s1, MemorySegment s2, MemorySegment s3,
269             MemorySegment s4, MemorySegment s5, MemorySegment s6,
270             MemorySegment s, double f) {
271         float val = s.get(FLOAT, 0);
272         s.set(FLOAT, 0, val + (float) f);
273         return s;
274     }
275 
276     @Test
277     public static void testAddFloatStructsUpcall() {
278         float p0 = 0.0f, p1 = 0.0f, p2 = 0.0f, p3 = 0.0f, p4 = 0.0f, p5 = 0.0f, p6 = 0.0f;
279         try {
280             Arena arena = Arena.ofConfined();
281             MemorySegment s = arena.allocate(S_FFFFFFFLayout);
282             s.set(FLOAT,  0, 1.0f);
283             s.set(FLOAT,  4, 2.0f);
284             s.set(FLOAT,  8, 3.0f);
285             s.set(FLOAT, 12, 4.0f);
286             s.set(FLOAT, 16, 5.0f);
287             s.set(FLOAT, 20, 6.0f);
288             s.set(FLOAT, 24, 7.0f);
289             MethodType mt = MethodType.methodType(MemorySegment.class,
290                                                   MemorySegment.class, MemorySegment.class);
291             MemorySegment stub = abi.upcallStub(MethodHandles.lookup().findStatic(TestHFA.class, "addFloatStructs", mt),
292                                                 fdadd_float_structs, arena);
293             s = (MemorySegment)mhpass_two_large_structs.invokeExact((SegmentAllocator)arena, stub, s, s);
294             p0 = s.get(FLOAT,  0);
295             p1 = s.get(FLOAT,  4);
296             p2 = s.get(FLOAT,  8);
297             p3 = s.get(FLOAT, 12);
298             p4 = s.get(FLOAT, 16);
299             p5 = s.get(FLOAT, 20);
300             p6 = s.get(FLOAT, 24);
301             System.out.println("S_FFFFFFF(" + p0 + ";" + p1 + ";" + p2 + ";" + p3 + ";" + p4 + ";" + p5 + ";" + p6 + ")");
302         } catch (Throwable t) {
303             t.printStackTrace();
304         }
305         if (p0 != 2.0f || p1 != 4.0f || p2 != 6.0f || p3 != 8.0f || p4 != 10.0f || p5 != 12.0f || p6 != 14.0f)
306             throw new RuntimeException("add_float_structs (Upcall)");
307     }
308 
309     @Test
310     public static void testAddFloatToStructAfterFloatsUpcall() {
311         float p0 = 0.0f, p1 = 0.0f;
312         try {
313             Arena arena = Arena.ofConfined();
314             MemorySegment s = arena.allocate(S_FFLayout);
315             s.set(FLOAT, 0, 1.0f);
316             s.set(FLOAT, 4, 1.0f);
317             MethodType mt = MethodType.methodType(MemorySegment.class,
318                                                   float.class, float.class, float.class, float.class,
319                                                   float.class, float.class, float.class, float.class,
320                                                   float.class, float.class, float.class, float.class,
321                                                   MemorySegment.class, float.class);
322             MemorySegment stub = abi.upcallStub(MethodHandles.lookup().findStatic(TestHFA.class, "addFloatToStructAfterFloats", mt),
323                                                 fdadd_float_to_struct_after_floats, arena);
324             s = (MemorySegment)mhpass_struct_after_floats.invokeExact((SegmentAllocator)arena, stub, s, 1.0f);
325             p0 = s.get(FLOAT, 0);
326             p1 = s.get(FLOAT, 4);
327             System.out.println("S_FF(" + p0 + ";" + p1 + ")");
328         } catch (Throwable t) {
329             t.printStackTrace();
330         }
331         if (p0 != 2.0f || p1 != 1.0f) throw new RuntimeException("add_float_to_struct_after_floats (Upcall)");
332     }
333 
334     @Test
335     public static void testAddFloatToStructAfterStructsUpcall() {
336         float p0 = 0.0f, p1 = 0.0f;
337         try {
338             Arena arena = Arena.ofConfined();
339             MemorySegment s = arena.allocate(S_FFLayout);
340             s.set(FLOAT, 0, 1.0f);
341             s.set(FLOAT, 4, 1.0f);
342             MethodType mt = MethodType.methodType(MemorySegment.class,
343                                                   MemorySegment.class, MemorySegment.class, MemorySegment.class,
344                                                   MemorySegment.class, MemorySegment.class, MemorySegment.class,
345                                                   MemorySegment.class, float.class);
346             MemorySegment stub = abi.upcallStub(MethodHandles.lookup().findStatic(TestHFA.class, "addFloatToStructAfterStructs", mt),
347                                                 fdadd_float_to_struct_after_structs, arena);
348             s = (MemorySegment)mhpass_struct_after_structs.invokeExact((SegmentAllocator)arena, stub, s, 1.0f);
349             p0 = s.get(FLOAT, 0);
350             p1 = s.get(FLOAT, 4);
351             System.out.println("S_FF(" + p0 + ";" + p1 + ")");
352         } catch (Throwable t) {
353             t.printStackTrace();
354         }
355         if (p0 != 2.0f || p1 != 1.0f) throw new RuntimeException("add_float_to_struct_after_structs (Upcall)");
356     }
357 
358     @Test
359     public static void testAddDoubleToStructAfterStructsUpcall() {
360         float p0 = 0.0f, p1 = 0.0f;
361         try {
362             Arena arena = Arena.ofConfined();
363             MemorySegment s = arena.allocate(S_FFLayout);
364             s.set(FLOAT, 0, 1.0f);
365             s.set(FLOAT, 4, 1.0f);
366             MethodType mt = MethodType.methodType(MemorySegment.class,
367                                                   MemorySegment.class, MemorySegment.class, MemorySegment.class,
368                                                   MemorySegment.class, MemorySegment.class, MemorySegment.class,
369                                                   MemorySegment.class, double.class);
370             MemorySegment stub = abi.upcallStub(MethodHandles.lookup().findStatic(TestHFA.class, "addDoubleToStructAfterStructs", mt),
371                                                 fdadd_double_to_struct_after_structs, arena);
372             s = (MemorySegment)mhpass_struct_after_structs_plus_double.invokeExact((SegmentAllocator)arena, stub, s, 1.0d);
373             p0 = s.get(FLOAT, 0);
374             p1 = s.get(FLOAT, 4);
375             System.out.println("S_FF(" + p0 + ";" + p1 + ")");
376         } catch (Throwable t) {
377             t.printStackTrace();
378         }
379         if (p0 != 2.0f || p1 != 1.0f) throw new RuntimeException("add_double_to_struct_after_structs (Upcall)");
380     }
381 
382     @Test
383     public static void testAddFloatToLargeStructAfterStructsUpcall() {
384         float p0 = 0.0f, p1 = 0.0f, p2 = 0.0f, p3 = 0.0f, p4 = 0.0f, p5 = 0.0f, p6 = 0.0f;
385         try {
386             Arena arena = Arena.ofConfined();
387             MemorySegment s = arena.allocate(S_FFFFFFFLayout);
388             s.set(FLOAT,  0, 1.0f);
389             s.set(FLOAT,  4, 2.0f);
390             s.set(FLOAT,  8, 3.0f);
391             s.set(FLOAT, 12, 4.0f);
392             s.set(FLOAT, 16, 5.0f);
393             s.set(FLOAT, 20, 6.0f);
394             s.set(FLOAT, 24, 7.0f);
395             MethodType mt = MethodType.methodType(MemorySegment.class,
396                                                   MemorySegment.class, MemorySegment.class, MemorySegment.class,
397                                                   MemorySegment.class, MemorySegment.class, MemorySegment.class,
398                                                   MemorySegment.class, float.class);
399             MemorySegment stub = abi.upcallStub(MethodHandles.lookup().findStatic(TestHFA.class, "addFloatToStructAfterStructs", mt),
400                                                 fdadd_float_to_large_struct_after_structs, arena);
401             s = (MemorySegment)mhpass_large_struct_after_structs.invokeExact((SegmentAllocator)arena, stub, s, 1.0f);
402             p0 = s.get(FLOAT,  0);
403             p1 = s.get(FLOAT,  4);
404             p2 = s.get(FLOAT,  8);
405             p3 = s.get(FLOAT, 12);
406             p4 = s.get(FLOAT, 16);
407             p5 = s.get(FLOAT, 20);
408             p6 = s.get(FLOAT, 24);
409             System.out.println("S_FFFFFFF(" + p0 + ";" + p1 + ";" + p2 + ";" + p3 + ";" + p4 + ";" + p5 + ";" + p6 + ")");
410         } catch (Throwable t) {
411             t.printStackTrace();
412         }
413         if (p0 != 2.0f || p1 != 2.0f || p2 != 3.0f || p3 != 4.0f || p4 != 5.0f || p5 != 6.0f || p6 != 7.0f)
414             throw new RuntimeException("add_float_to_large_struct_after_structs (Upcall)");
415     }
416 }