< prev index next >

test/jdk/java/foreign/TestDowncall.java

Print this page

 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  * @requires ((os.arch == "amd64" | os.arch == "x86_64") & sun.arch.data.model == "64") | os.arch == "aarch64"
 28  * @modules jdk.incubator.foreign/jdk.internal.foreign
 29  * @build NativeTestHelper CallGeneratorHelper TestDowncall
 30  *
 31  * @run testng/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies
 32  *   --enable-native-access=ALL-UNNAMED -Dgenerator.sample.factor=17
 33  *   TestDowncall
 34  */
 35 
 36 import jdk.incubator.foreign.CLinker;
 37 import jdk.incubator.foreign.FunctionDescriptor;



 38 import jdk.incubator.foreign.SymbolLookup;
 39 import jdk.incubator.foreign.MemoryAddress;
 40 import jdk.incubator.foreign.MemoryLayout;
 41 
 42 import java.lang.invoke.MethodHandle;
 43 import java.lang.invoke.MethodType;
 44 import java.util.ArrayList;
 45 import java.util.List;
 46 import java.util.function.Consumer;

 47 
 48 import jdk.incubator.foreign.MemorySegment;
 49 import jdk.incubator.foreign.SegmentAllocator;
 50 import org.testng.annotations.*;
 51 import static org.testng.Assert.*;
 52 
 53 public class TestDowncall extends CallGeneratorHelper {
 54 
 55     static CLinker abi = CLinker.getInstance();
 56     static {
 57         System.loadLibrary("TestDowncall");

 58     }
 59 
 60     static final SymbolLookup LOOKUP = SymbolLookup.loaderLookup();
 61 
 62     @Test(dataProvider="functions", dataProviderClass=CallGeneratorHelper.class)
 63     public void testDowncall(int count, String fName, Ret ret, List<ParamType> paramTypes, List<StructFieldType> fields) throws Throwable {
 64         List<Consumer<Object>> checks = new ArrayList<>();
 65         MemoryAddress addr = LOOKUP.lookup(fName).get();
 66         MethodType mt = methodType(ret, paramTypes, fields);
 67         FunctionDescriptor descriptor = function(ret, paramTypes, fields);
 68         Object[] args = makeArgs(paramTypes, fields, checks);
 69         try (NativeScope scope = new NativeScope()) {
 70             boolean needsScope = mt.returnType().equals(MemorySegment.class);
 71             Object res = doCall(addr, scope, mt, descriptor, args);



 72             if (ret == Ret.NON_VOID) {
 73                 checks.forEach(c -> c.accept(res));
 74                 if (needsScope) {
 75                     // check that return struct has indeed been allocated in the native scope
 76                     assertEquals(((MemorySegment) res).scope(), scope.scope());
 77                     assertEquals(scope.allocatedBytes(), descriptor.returnLayout().get().byteSize());
 78                 } else {
 79                     // if here, there should be no allocation through the scope!
 80                     assertEquals(scope.allocatedBytes(), 0L);
 81                 }
 82             } else {
 83                 // if here, there should be no allocation through the scope!
 84                 assertEquals(scope.allocatedBytes(), 0L);
 85             }
 86         }
 87     }
 88 
 89     @Test(dataProvider="functions", dataProviderClass=CallGeneratorHelper.class)
 90     public void testDowncallNoScope(int count, String fName, Ret ret, List<ParamType> paramTypes, List<StructFieldType> fields) throws Throwable {
 91         List<Consumer<Object>> checks = new ArrayList<>();
 92         MemoryAddress addr = LOOKUP.lookup(fName).get();
 93         MethodType mt = methodType(ret, paramTypes, fields);
 94         FunctionDescriptor descriptor = function(ret, paramTypes, fields);
 95         Object[] args = makeArgs(paramTypes, fields, checks);
 96         boolean needsScope = mt.returnType().equals(MemorySegment.class);
 97         Object res = doCall(addr, IMPLICIT_ALLOCATOR, mt, descriptor, args);
 98         if (ret == Ret.NON_VOID) {
 99             checks.forEach(c -> c.accept(res));
100             if (needsScope) {
101                 // check that return struct has indeed been allocated in the default scope
102                 try {
103                     ((MemorySegment)res).scope().close(); // should throw
104                     fail("Expected exception!");
105                 } catch (UnsupportedOperationException ex) {
106                     // ok
107                 }
108             }
109         }
110     }
111 
112     Object doCall(MemoryAddress addr, SegmentAllocator allocator, MethodType type, FunctionDescriptor descriptor, Object[] args) throws Throwable {
113         MethodHandle mh = abi.downcallHandle(addr, allocator, type, descriptor);
114         Object res = mh.invokeWithArguments(args);
115         return res;
116     }
117 
118     static MethodType methodType(Ret ret, List<ParamType> params, List<StructFieldType> fields) {
119         MethodType mt = ret == Ret.VOID ?
120                 MethodType.methodType(void.class) : MethodType.methodType(paramCarrier(params.get(0).layout(fields)));
121         for (ParamType p : params) {
122             mt = mt.appendParameterTypes(paramCarrier(p.layout(fields)));
123         }
124         return mt;
125     }
126 
127     static FunctionDescriptor function(Ret ret, List<ParamType> params, List<StructFieldType> fields) {
128         MemoryLayout[] paramLayouts = params.stream().map(p -> p.layout(fields)).toArray(MemoryLayout[]::new);





129         return ret == Ret.VOID ?
130                 FunctionDescriptor.ofVoid(paramLayouts) :
131                 FunctionDescriptor.of(paramLayouts[0], paramLayouts);




132     }
133 
134     static Object[] makeArgs(List<ParamType> params, List<StructFieldType> fields, List<Consumer<Object>> checks) throws ReflectiveOperationException {
135         Object[] args = new Object[params.size()];








136         for (int i = 0 ; i < params.size() ; i++) {
137             args[i] = makeArg(params.get(i).layout(fields), checks, i == 0);
138         }
139         return args;
140     }
141 }

 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  * @requires ((os.arch == "amd64" | os.arch == "x86_64") & sun.arch.data.model == "64") | os.arch == "aarch64"
 28  * @modules jdk.incubator.foreign/jdk.internal.foreign
 29  * @build NativeTestHelper CallGeneratorHelper TestDowncall
 30  *
 31  * @run testng/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies
 32  *   --enable-native-access=ALL-UNNAMED -Dgenerator.sample.factor=17
 33  *   TestDowncall
 34  */
 35 
 36 import jdk.incubator.foreign.CLinker;
 37 import jdk.incubator.foreign.FunctionDescriptor;
 38 import jdk.incubator.foreign.GroupLayout;
 39 import jdk.incubator.foreign.NativeSymbol;
 40 import jdk.incubator.foreign.ResourceScope;
 41 import jdk.incubator.foreign.SymbolLookup;

 42 import jdk.incubator.foreign.MemoryLayout;
 43 
 44 import java.lang.invoke.MethodHandle;

 45 import java.util.ArrayList;
 46 import java.util.List;
 47 import java.util.function.Consumer;
 48 import java.util.stream.Stream;
 49 
 50 import jdk.incubator.foreign.MemorySegment;
 51 import jdk.incubator.foreign.SegmentAllocator;
 52 import org.testng.annotations.*;
 53 import static org.testng.Assert.*;
 54 
 55 public class TestDowncall extends CallGeneratorHelper {
 56 
 57     static CLinker abi = CLinker.systemCLinker();
 58     static {
 59         System.loadLibrary("TestDowncall");
 60         System.loadLibrary("TestDowncallStack");
 61     }
 62 
 63     static final SymbolLookup LOOKUP = SymbolLookup.loaderLookup();
 64 
 65     @Test(dataProvider="functions", dataProviderClass=CallGeneratorHelper.class)
 66     public void testDowncall(int count, String fName, Ret ret, List<ParamType> paramTypes, List<StructFieldType> fields) throws Throwable {
 67         List<Consumer<Object>> checks = new ArrayList<>();
 68         NativeSymbol addr = LOOKUP.lookup(fName).get();

 69         FunctionDescriptor descriptor = function(ret, paramTypes, fields);
 70         Object[] args = makeArgs(paramTypes, fields, checks);
 71         try (ResourceScope scope = ResourceScope.newSharedScope()) {
 72             boolean needsScope = descriptor.returnLayout().map(GroupLayout.class::isInstance).orElse(false);
 73             SegmentAllocator allocator = needsScope ?
 74                     SegmentAllocator.newNativeArena(scope) :
 75                     THROWING_ALLOCATOR;
 76             Object res = doCall(addr, allocator, descriptor, args);
 77             if (ret == Ret.NON_VOID) {
 78                 checks.forEach(c -> c.accept(res));
 79                 if (needsScope) {
 80                     // check that return struct has indeed been allocated in the native scope
 81                     assertEquals(((MemorySegment) res).scope(), scope);




 82                 }



 83             }
 84         }
 85     }
 86 
 87     @Test(dataProvider="functions", dataProviderClass=CallGeneratorHelper.class)
 88     public void testDowncallStack(int count, String fName, Ret ret, List<ParamType> paramTypes, List<StructFieldType> fields) throws Throwable {
 89         List<Consumer<Object>> checks = new ArrayList<>();
 90         NativeSymbol addr = LOOKUP.lookup("s" + fName).get();
 91         FunctionDescriptor descriptor = functionStack(ret, paramTypes, fields);
 92         Object[] args = makeArgsStack(paramTypes, fields, checks);
 93         try (ResourceScope scope = ResourceScope.newSharedScope()) {
 94             boolean needsScope = descriptor.returnLayout().map(GroupLayout.class::isInstance).orElse(false);
 95             SegmentAllocator allocator = needsScope ?
 96                     SegmentAllocator.newNativeArena(scope) :
 97                     THROWING_ALLOCATOR;
 98             Object res = doCall(addr, allocator, descriptor, args);
 99             if (ret == Ret.NON_VOID) {
100                 checks.forEach(c -> c.accept(res));
101                 if (needsScope) {
102                     // check that return struct has indeed been allocated in the native scope
103                     assertEquals(((MemorySegment) res).scope(), scope);

104                 }
105             }
106         }
107     }
108 
109     Object doCall(NativeSymbol symbol, SegmentAllocator allocator, FunctionDescriptor descriptor, Object[] args) throws Throwable {
110         MethodHandle mh = downcallHandle(abi, symbol, allocator, descriptor);
111         Object res = mh.invokeWithArguments(args);
112         return res;
113     }
114 
115     static FunctionDescriptor functionStack(Ret ret, List<ParamType> params, List<StructFieldType> fields) {
116         return function(ret, params, fields, STACK_PREFIX_LAYOUTS);





117     }
118 
119     static FunctionDescriptor function(Ret ret, List<ParamType> params, List<StructFieldType> fields) {
120         return function(ret, params, fields, List.of());
121     }
122 
123     static FunctionDescriptor function(Ret ret, List<ParamType> params, List<StructFieldType> fields, List<MemoryLayout> prefix) {
124         List<MemoryLayout> pLayouts = params.stream().map(p -> p.layout(fields)).toList();
125         MemoryLayout[] paramLayouts = Stream.concat(prefix.stream(), pLayouts.stream()).toArray(MemoryLayout[]::new);
126         return ret == Ret.VOID ?
127                 FunctionDescriptor.ofVoid(paramLayouts) :
128                 FunctionDescriptor.of(paramLayouts[prefix.size()], paramLayouts);
129     }
130 
131     static Object[] makeArgsStack(List<ParamType> params, List<StructFieldType> fields, List<Consumer<Object>> checks) throws ReflectiveOperationException {
132         return makeArgs(params, fields, checks, STACK_PREFIX_LAYOUTS);
133     }
134 
135     static Object[] makeArgs(List<ParamType> params, List<StructFieldType> fields, List<Consumer<Object>> checks) throws ReflectiveOperationException {
136         return makeArgs(params, fields, checks, List.of());
137     }
138 
139     static Object[] makeArgs(List<ParamType> params, List<StructFieldType> fields, List<Consumer<Object>> checks, List<MemoryLayout> prefix) throws ReflectiveOperationException {
140         Object[] args = new Object[prefix.size() + params.size()];
141         int argNum = 0;
142         for (MemoryLayout layout : prefix) {
143             args[argNum++] = makeArg(layout, null, false);
144         }
145         for (int i = 0 ; i < params.size() ; i++) {
146             args[argNum++] = makeArg(params.get(i).layout(fields), checks, i == 0);
147         }
148         return args;
149     }
150 }
< prev index next >