< prev index next >

test/jdk/java/foreign/TestVarArgs.java

Print this page

  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,
< prev index next >