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 /*
26 * @test
27 * @enablePreview
28 * @requires jdk.foreign.linker != "UNSUPPORTED"
29 * @modules java.base/jdk.internal.foreign
30 * @run testng/othervm --enable-native-access=ALL-UNNAMED -Dgenerator.sample.factor=17 TestVarArgs
31 */
32
33 import java.lang.foreign.Arena;
34 import java.lang.foreign.Linker;
35 import java.lang.foreign.FunctionDescriptor;
36 import java.lang.foreign.MemoryLayout;
37 import java.lang.foreign.ValueLayout;
38 import java.lang.foreign.MemorySegment;
39
40 import org.testng.annotations.DataProvider;
41 import org.testng.annotations.Test;
42
43 import java.lang.invoke.MethodHandle;
44 import java.lang.invoke.MethodHandles;
45 import java.lang.invoke.MethodType;
46 import java.lang.invoke.VarHandle;
47 import java.util.ArrayList;
48 import java.util.List;
49
50 import static java.lang.foreign.MemoryLayout.PathElement.*;
51
52 public class TestVarArgs extends CallGeneratorHelper {
53
54 static final VarHandle VH_IntArray = C_INT.arrayElementVarHandle();
55 static final MethodHandle MH_CHECK;
56
57 static final Linker LINKER = Linker.nativeLinker();
58 static {
59 System.loadLibrary("VarArgs");
60 try {
61 MH_CHECK = MethodHandles.lookup().findStatic(TestVarArgs.class, "check",
62 MethodType.methodType(void.class, int.class, MemorySegment.class, List.class));
63 } catch (ReflectiveOperationException e) {
64 throw new ExceptionInInitializerError(e);
65 }
66 }
67
68 static final MemorySegment VARARGS_ADDR = findNativeOrThrow("varargs");
69
70 @Test(dataProvider = "variadicFunctions")
71 public void testVarArgs(int count, String fName, Ret ret, // ignore this stuff
72 List<ParamType> paramTypes, List<StructFieldType> fields) throws Throwable {
73 try (Arena arena = Arena.ofConfined()) {
74 List<Arg> args = makeArgs(arena, paramTypes, fields);
75 MethodHandle checker = MethodHandles.insertArguments(MH_CHECK, 2, args);
76 MemorySegment writeBack = LINKER.upcallStub(checker, FunctionDescriptor.ofVoid(C_INT, C_POINTER), arena);
77 MemorySegment callInfo = arena.allocate(CallInfo.LAYOUT);
78 MemoryLayout layout = MemoryLayout.sequenceLayout(args.size(), C_INT);
79 MemorySegment argIDs = arena.allocate(layout);
80
81 CallInfo.writeback(callInfo, writeBack);
82 CallInfo.argIDs(callInfo, argIDs);
83
84 for (int i = 0; i < args.size(); i++) {
85 VH_IntArray.set(argIDs, (long) i, args.get(i).id.ordinal());
86 }
87
88 List<MemoryLayout> argLayouts = new ArrayList<>();
89 argLayouts.add(C_POINTER); // call info
90 argLayouts.add(C_INT); // size
91
92 FunctionDescriptor baseDesc = FunctionDescriptor.ofVoid(argLayouts.toArray(MemoryLayout[]::new));
93 Linker.Option varargIndex = Linker.Option.firstVariadicArg(baseDesc.argumentLayouts().size());
94 FunctionDescriptor desc = baseDesc.appendArgumentLayouts(args.stream().map(a -> a.layout).toArray(MemoryLayout[]::new));
95
96 MethodHandle downcallHandle = LINKER.downcallHandle(VARARGS_ADDR, desc, varargIndex);
97
98 List<Object> argValues = new ArrayList<>();
99 argValues.add(callInfo); // call info
100 argValues.add(args.size()); // size
101 args.forEach(a -> argValues.add(a.value()));
102
103 downcallHandle.invokeWithArguments(argValues);
104
105 // args checked by upcall
180 MethodHandle getter = varArg.getter;
181 try (Arena arena = Arena.ofConfined()) {
182 MemorySegment seg = ptr.asSlice(0, layout)
183 .reinterpret(arena, null);
184 Object obj = getter.invoke(seg);
185 varArg.check(obj);
186 } catch (Throwable e) {
187 throw new RuntimeException(e);
188 }
189 }
190
191 private static class CallInfo {
192 static final MemoryLayout LAYOUT = MemoryLayout.structLayout(
193 C_POINTER.withName("writeback"), // writeback
194 C_POINTER.withName("argIDs")); // arg ids
195
196 static final VarHandle VH_writeback = LAYOUT.varHandle(groupElement("writeback"));
197 static final VarHandle VH_argIDs = LAYOUT.varHandle(groupElement("argIDs"));
198
199 static void writeback(MemorySegment seg, MemorySegment addr) {
200 VH_writeback.set(seg, addr);
201 }
202 static void argIDs(MemorySegment seg, MemorySegment addr) {
203 VH_argIDs.set(seg, addr);
204 }
205 }
206
207 private static final class Arg {
208 private final TestValue value;
209
210 final NativeType id;
211 final MemoryLayout layout;
212 final MethodHandle getter;
213
214 private Arg(NativeType id, MemoryLayout layout, TestValue value, MethodHandle getter) {
215 this.id = id;
216 this.layout = layout;
217 this.value = value;
218 this.getter = getter;
219 }
220
221 private static Arg primitiveArg(NativeType id, MemoryLayout layout, TestValue value) {
222 return new Arg(id, layout, value, layout.varHandle().toMethodHandle(VarHandle.AccessMode.GET));
223 }
224
225 private static Arg structArg(NativeType id, MemoryLayout layout, TestValue value) {
226 return new Arg(id, layout, value, MethodHandles.identity(MemorySegment.class));
227 }
228
229 public void check(Object actual) {
230 value.check().accept(actual);
231 }
232
233 public Object value() {
234 return value.value();
235 }
236
237 enum NativeType {
238 INT,
239 DOUBLE,
240 POINTER,
241 S_I,
242 S_F,
|
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 /*
26 * @test
27 * @modules java.base/jdk.internal.foreign
28 * @run testng/othervm --enable-native-access=ALL-UNNAMED -Dgenerator.sample.factor=17 TestVarArgs
29 */
30
31 import java.lang.foreign.Arena;
32 import java.lang.foreign.Linker;
33 import java.lang.foreign.FunctionDescriptor;
34 import java.lang.foreign.MemoryLayout;
35 import java.lang.foreign.ValueLayout;
36 import java.lang.foreign.MemorySegment;
37
38 import org.testng.annotations.DataProvider;
39 import org.testng.annotations.Test;
40
41 import java.lang.foreign.ValueLayout;
42 import java.lang.invoke.MethodHandle;
43 import java.lang.invoke.MethodHandles;
44 import java.lang.invoke.MethodType;
45 import java.lang.invoke.VarHandle;
46 import java.util.ArrayList;
47 import java.util.List;
48
49 import static java.lang.foreign.MemoryLayout.PathElement.*;
50
51 public class TestVarArgs extends CallGeneratorHelper {
52
53 static final MethodHandle MH_CHECK;
54
55 static final Linker LINKER = Linker.nativeLinker();
56 static {
57 System.loadLibrary("VarArgs");
58 try {
59 MH_CHECK = MethodHandles.lookup().findStatic(TestVarArgs.class, "check",
60 MethodType.methodType(void.class, int.class, MemorySegment.class, List.class));
61 } catch (ReflectiveOperationException e) {
62 throw new ExceptionInInitializerError(e);
63 }
64 }
65
66 static final MemorySegment VARARGS_ADDR = findNativeOrThrow("varargs");
67
68 @Test(dataProvider = "variadicFunctions")
69 public void testVarArgs(int count, String fName, Ret ret, // ignore this stuff
70 List<ParamType> paramTypes, List<StructFieldType> fields) throws Throwable {
71 try (Arena arena = Arena.ofConfined()) {
72 List<Arg> args = makeArgs(arena, paramTypes, fields);
73 MethodHandle checker = MethodHandles.insertArguments(MH_CHECK, 2, args);
74 MemorySegment writeBack = LINKER.upcallStub(checker, FunctionDescriptor.ofVoid(C_INT, C_POINTER), arena);
75 MemorySegment callInfo = arena.allocate(CallInfo.LAYOUT);
76 MemoryLayout layout = MemoryLayout.sequenceLayout(args.size(), C_INT);
77 MemorySegment argIDs = arena.allocate(layout);
78
79 CallInfo.writeback(callInfo, writeBack);
80 CallInfo.argIDs(callInfo, argIDs);
81
82 for (int i = 0; i < args.size(); i++) {
83 argIDs.setAtIndex(ValueLayout.JAVA_INT, i, args.get(i).id.ordinal());
84 }
85
86 List<MemoryLayout> argLayouts = new ArrayList<>();
87 argLayouts.add(C_POINTER); // call info
88 argLayouts.add(C_INT); // size
89
90 FunctionDescriptor baseDesc = FunctionDescriptor.ofVoid(argLayouts.toArray(MemoryLayout[]::new));
91 Linker.Option varargIndex = Linker.Option.firstVariadicArg(baseDesc.argumentLayouts().size());
92 FunctionDescriptor desc = baseDesc.appendArgumentLayouts(args.stream().map(a -> a.layout).toArray(MemoryLayout[]::new));
93
94 MethodHandle downcallHandle = LINKER.downcallHandle(VARARGS_ADDR, desc, varargIndex);
95
96 List<Object> argValues = new ArrayList<>();
97 argValues.add(callInfo); // call info
98 argValues.add(args.size()); // size
99 args.forEach(a -> argValues.add(a.value()));
100
101 downcallHandle.invokeWithArguments(argValues);
102
103 // args checked by upcall
178 MethodHandle getter = varArg.getter;
179 try (Arena arena = Arena.ofConfined()) {
180 MemorySegment seg = ptr.asSlice(0, layout)
181 .reinterpret(arena, null);
182 Object obj = getter.invoke(seg);
183 varArg.check(obj);
184 } catch (Throwable e) {
185 throw new RuntimeException(e);
186 }
187 }
188
189 private static class CallInfo {
190 static final MemoryLayout LAYOUT = MemoryLayout.structLayout(
191 C_POINTER.withName("writeback"), // writeback
192 C_POINTER.withName("argIDs")); // arg ids
193
194 static final VarHandle VH_writeback = LAYOUT.varHandle(groupElement("writeback"));
195 static final VarHandle VH_argIDs = LAYOUT.varHandle(groupElement("argIDs"));
196
197 static void writeback(MemorySegment seg, MemorySegment addr) {
198 VH_writeback.set(seg, 0L, addr);
199 }
200 static void argIDs(MemorySegment seg, MemorySegment addr) {
201 VH_argIDs.set(seg, 0L, addr);
202 }
203 }
204
205 private static final class Arg {
206 private final TestValue value;
207
208 final NativeType id;
209 final MemoryLayout layout;
210 final MethodHandle getter;
211
212 private Arg(NativeType id, MemoryLayout layout, TestValue value, MethodHandle getter) {
213 this.id = id;
214 this.layout = layout;
215 this.value = value;
216 this.getter = getter;
217 }
218
219 private static Arg primitiveArg(NativeType id, MemoryLayout layout, TestValue value) {
220 MethodHandle getterHandle = layout.varHandle().toMethodHandle(VarHandle.AccessMode.GET);
221 getterHandle = MethodHandles.insertArguments(getterHandle, 1, 0L); // align signature with getter for structs
222 return new Arg(id, layout, value, getterHandle);
223 }
224
225 private static Arg structArg(NativeType id, MemoryLayout layout, TestValue value) {
226 return new Arg(id, layout, value, MethodHandles.identity(MemorySegment.class));
227 }
228
229 public void check(Object actual) {
230 value.check().accept(actual);
231 }
232
233 public Object value() {
234 return value.value();
235 }
236
237 enum NativeType {
238 INT,
239 DOUBLE,
240 POINTER,
241 S_I,
242 S_F,
|