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 }