1 /* 2 * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /* 25 * @test id=specialized 26 * @library ../ 27 * @requires (!(os.name == "Mac OS X" & os.arch == "aarch64") | jdk.foreign.linker != "FALLBACK") 28 * @modules java.base/jdk.internal.foreign 29 * @run testng/othervm 30 * --enable-native-access=ALL-UNNAMED 31 * -Djdk.internal.foreign.DowncallLinker.USE_SPEC=true 32 * -Djdk.internal.foreign.UpcallLinker.USE_SPEC=true 33 * TestArrayStructs 34 */ 35 36 /* 37 * @test id=interpreted 38 * @library ../ 39 * @requires (!(os.name == "Mac OS X" & os.arch == "aarch64") | jdk.foreign.linker != "FALLBACK") 40 * @modules java.base/jdk.internal.foreign 41 * @run testng/othervm 42 * --enable-native-access=ALL-UNNAMED 43 * -Djdk.internal.foreign.DowncallLinker.USE_SPEC=false 44 * -Djdk.internal.foreign.UpcallLinker.USE_SPEC=false 45 * TestArrayStructs 46 */ 47 48 import org.testng.annotations.DataProvider; 49 import org.testng.annotations.Test; 50 51 import java.lang.foreign.Arena; 52 import java.lang.foreign.FunctionDescriptor; 53 import java.lang.foreign.MemoryLayout; 54 import java.lang.foreign.MemorySegment; 55 import java.lang.foreign.StructLayout; 56 import java.lang.invoke.MethodHandle; 57 import java.util.ArrayList; 58 import java.util.Collections; 59 import java.util.List; 60 import java.util.concurrent.atomic.AtomicReference; 61 import java.util.function.Consumer; 62 import java.util.stream.Stream; 63 64 import static java.lang.foreign.MemoryLayout.sequenceLayout; 65 import static java.lang.foreign.MemoryLayout.structLayout; 66 67 public class TestArrayStructs extends NativeTestHelper { 68 static { 69 System.loadLibrary("ArrayStructs"); 70 } 71 72 // Test if structs of various different sizes, including non-powers of two, work correctly 73 @Test(dataProvider = "arrayStructs") 74 public void testArrayStruct(String functionName, FunctionDescriptor baseDesc, int numPrefixArgs, int numElements) throws Throwable { 75 FunctionDescriptor downcallDesc = baseDesc.insertArgumentLayouts(0, C_POINTER); // CB 76 MemoryLayout[] elementLayouts = Collections.nCopies(numElements, C_CHAR).toArray(MemoryLayout[]::new); 77 FunctionDescriptor upcallDesc = baseDesc.appendArgumentLayouts(elementLayouts); 78 try (Arena arena = Arena.ofConfined()) { 79 TestValue[] testArgs = genTestArgs(baseDesc, arena); 80 81 MethodHandle downcallHandle = downcallHandle(functionName, downcallDesc); 82 Object[] args = new Object[downcallDesc.argumentLayouts().size() + 1]; // +1 for return allocator 83 AtomicReference<Object[]> returnBox = new AtomicReference<>(); 84 int returnIdx = numPrefixArgs; 85 int argIdx = 0; 86 args[argIdx++] = arena; 87 args[argIdx++] = makeArgSaverCB(upcallDesc, arena, returnBox, returnIdx); 88 for (TestValue testArg : testArgs) { 89 args[argIdx++] = testArg.value(); 90 } 91 92 MemorySegment returned = (MemorySegment) downcallHandle.invokeWithArguments(args); 93 Consumer<Object> structCheck = testArgs[returnIdx].check(); 94 95 structCheck.accept(returned); 96 97 Object[] capturedArgs = returnBox.get(); 98 int capturedArgIdx; 99 for (capturedArgIdx = numPrefixArgs; capturedArgIdx < testArgs.length; capturedArgIdx++) { 100 testArgs[capturedArgIdx].check().accept(capturedArgs[capturedArgIdx]); 101 } 102 103 byte[] elements = new byte[numElements]; 104 for (int elIdx = 0; elIdx < numElements; elIdx++, capturedArgIdx++) { 105 elements[elIdx] = (byte) capturedArgs[capturedArgIdx]; 106 } 107 108 structCheck.accept(MemorySegment.ofArray(elements)); // reuse the check for the struct 109 } 110 } 111 112 @DataProvider 113 public static Object[][] arrayStructs() { 114 List<Object[]> cases = new ArrayList<>(); 115 for (int i = 0; i < layouts.size(); i++) { 116 StructLayout layout = layouts.get(i); 117 int numElements = i + 1; 118 cases.add(new Object[]{"F" + numElements, FunctionDescriptor.of(layout, layout), 0, numElements}); 119 } 120 for (int i = 0; i < layouts.size(); i++) { 121 StructLayout layout = layouts.get(i); 122 MemoryLayout[] argLayouts = Stream.concat(PREFIX_LAYOUTS.stream(), Stream.of(layout)).toArray(MemoryLayout[]::new); 123 int numElements = i + 1; 124 cases.add(new Object[]{"F" + numElements + "_stack", FunctionDescriptor.of(layout, argLayouts), PREFIX_LAYOUTS.size(), numElements}); 125 } 126 127 return cases.toArray(Object[][]::new); 128 } 129 130 static final List<MemoryLayout> PREFIX_LAYOUTS = List.of( 131 C_LONG_LONG, C_LONG_LONG, C_LONG_LONG, C_LONG_LONG, C_LONG_LONG, C_LONG_LONG, C_LONG_LONG, C_LONG_LONG, 132 C_DOUBLE, C_DOUBLE, C_DOUBLE, C_DOUBLE, C_DOUBLE, C_DOUBLE, C_DOUBLE, C_DOUBLE); 133 134 static final List<StructLayout> layouts = List.of( 135 structLayout(sequenceLayout(1, C_CHAR).withName("f0")).withName("S1"), 136 structLayout(sequenceLayout(2, C_CHAR).withName("f0")).withName("S2"), 137 structLayout(sequenceLayout(3, C_CHAR).withName("f0")).withName("S3"), 138 structLayout(sequenceLayout(4, C_CHAR).withName("f0")).withName("S4"), 139 structLayout(sequenceLayout(5, C_CHAR).withName("f0")).withName("S5"), 140 structLayout(sequenceLayout(6, C_CHAR).withName("f0")).withName("S6"), 141 structLayout(sequenceLayout(7, C_CHAR).withName("f0")).withName("S7"), 142 structLayout(sequenceLayout(8, C_CHAR).withName("f0")).withName("S8"), 143 structLayout(sequenceLayout(9, C_CHAR).withName("f0")).withName("S9"), 144 structLayout(sequenceLayout(10, C_CHAR).withName("f0")).withName("S10"), 145 structLayout(sequenceLayout(11, C_CHAR).withName("f0")).withName("S11"), 146 structLayout(sequenceLayout(12, C_CHAR).withName("f0")).withName("S12"), 147 structLayout(sequenceLayout(13, C_CHAR).withName("f0")).withName("S13"), 148 structLayout(sequenceLayout(14, C_CHAR).withName("f0")).withName("S14"), 149 structLayout(sequenceLayout(15, C_CHAR).withName("f0")).withName("S15"), 150 structLayout(sequenceLayout(16, C_CHAR).withName("f0")).withName("S16")); 151 }