< prev index next >

test/jdk/java/foreign/TestUpcall.java

Print this page

  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 /*
 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 TestUpcall
 30  *
 31  * @run testng/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies
 32  *   --enable-native-access=ALL-UNNAMED -Dgenerator.sample.factor=17

 33  *   TestUpcall
 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 import jdk.incubator.foreign.MemorySegment;
 42 
 43 import jdk.incubator.foreign.ResourceScope;

 44 import org.testng.annotations.BeforeClass;
 45 import org.testng.annotations.Test;
 46 
 47 import java.lang.invoke.MethodHandle;
 48 import java.lang.invoke.MethodHandles;
 49 import java.lang.invoke.MethodType;
 50 import java.util.ArrayList;

 51 import java.util.List;

 52 import java.util.concurrent.atomic.AtomicReference;
 53 import java.util.function.Consumer;
 54 import java.util.stream.Collectors;

 55 
 56 import static java.lang.invoke.MethodHandles.insertArguments;
 57 import static jdk.incubator.foreign.CLinker.C_POINTER;
 58 import static org.testng.Assert.assertEquals;
 59 
 60 
 61 public class TestUpcall extends CallGeneratorHelper {
 62 








 63     static {
 64         System.loadLibrary("TestUpcall");


 65     }
 66     static CLinker abi = CLinker.getInstance();
 67 
 68     static final SymbolLookup LOOKUP = SymbolLookup.loaderLookup();
 69 
 70     static MethodHandle DUMMY;
 71     static MethodHandle PASS_AND_SAVE;
 72 
 73     static {
 74         try {
 75             DUMMY = MethodHandles.lookup().findStatic(TestUpcall.class, "dummy", MethodType.methodType(void.class));
 76             PASS_AND_SAVE = MethodHandles.lookup().findStatic(TestUpcall.class, "passAndSave",
 77                     MethodType.methodType(Object.class, Object[].class, AtomicReference.class));
 78         } catch (Throwable ex) {
 79             throw new IllegalStateException(ex);
 80         }
 81     }
 82 
 83     static MemoryAddress dummyStub;
 84 
 85     @BeforeClass
 86     void setup() {
 87         dummyStub = abi.upcallStub(DUMMY, FunctionDescriptor.ofVoid(), ResourceScope.newImplicitScope());
 88     }
 89 





 90     @Test(dataProvider="functions", dataProviderClass=CallGeneratorHelper.class)
 91     public void testUpcalls(int count, String fName, Ret ret, List<ParamType> paramTypes, List<StructFieldType> fields) throws Throwable {


 92         List<Consumer<Object>> returnChecks = new ArrayList<>();
 93         List<Consumer<Object[]>> argChecks = new ArrayList<>();
 94         MemoryAddress addr = LOOKUP.lookup(fName).get();
 95         MethodType mtype = methodType(ret, paramTypes, fields);
 96         try (NativeScope scope = new NativeScope()) {
 97             MethodHandle mh = abi.downcallHandle(addr, scope, mtype, function(ret, paramTypes, fields));
 98             Object[] args = makeArgs(scope.scope(), ret, paramTypes, fields, returnChecks, argChecks);
 99             Object[] callArgs = args;
100             Object res = mh.invokeWithArguments(callArgs);
101             argChecks.forEach(c -> c.accept(args));
102             if (ret == Ret.NON_VOID) {
103                 returnChecks.forEach(c -> c.accept(res));
104             }
105         }
106     }
107 
108     @Test(dataProvider="functions", dataProviderClass=CallGeneratorHelper.class)
109     public void testUpcallsNoScope(int count, String fName, Ret ret, List<ParamType> paramTypes, List<StructFieldType> fields) throws Throwable {


































110         List<Consumer<Object>> returnChecks = new ArrayList<>();
111         List<Consumer<Object[]>> argChecks = new ArrayList<>();
112         MemoryAddress addr = LOOKUP.lookup(fName).get();
113         MethodType mtype = methodType(ret, paramTypes, fields);
114         MethodHandle mh = abi.downcallHandle(addr, IMPLICIT_ALLOCATOR, mtype, function(ret, paramTypes, fields));
115         Object[] args = makeArgs(ResourceScope.newImplicitScope(), ret, paramTypes, fields, returnChecks, argChecks);
116         Object[] callArgs = args;
117         Object res = mh.invokeWithArguments(callArgs);
118         argChecks.forEach(c -> c.accept(args));
119         if (ret == Ret.NON_VOID) {
120             returnChecks.forEach(c -> c.accept(res));


121         }
122     }
123 
124     static MethodType methodType(Ret ret, List<ParamType> params, List<StructFieldType> fields) {
125         MethodType mt = ret == Ret.VOID ?
126                 MethodType.methodType(void.class) : MethodType.methodType(paramCarrier(params.get(0).layout(fields)));
127         for (ParamType p : params) {
128             mt = mt.appendParameterTypes(paramCarrier(p.layout(fields)));




129         }
130         mt = mt.appendParameterTypes(MemoryAddress.class); //the callback
131         return mt;













132     }
133 
134     static FunctionDescriptor function(Ret ret, List<ParamType> params, List<StructFieldType> fields) {




135         List<MemoryLayout> paramLayouts = params.stream().map(p -> p.layout(fields)).collect(Collectors.toList());
136         paramLayouts.add(C_POINTER); // the callback
137         MemoryLayout[] layouts = paramLayouts.toArray(new MemoryLayout[0]);
138         return ret == Ret.VOID ?
139                 FunctionDescriptor.ofVoid(layouts) :
140                 FunctionDescriptor.of(layouts[0], layouts);




141     }
142 
143     static Object[] makeArgs(ResourceScope scope, Ret ret, List<ParamType> params, List<StructFieldType> fields, List<Consumer<Object>> checks, List<Consumer<Object[]>> argChecks) throws ReflectiveOperationException {
144         Object[] args = new Object[params.size() + 1];








145         for (int i = 0 ; i < params.size() ; i++) {
146             args[i] = makeArg(params.get(i).layout(fields), checks, i == 0);
147         }
148         args[params.size()] = makeCallback(scope, ret, params, fields, checks, argChecks);
149         return args;
150     }
151 
152     @SuppressWarnings("unchecked")
153     static MemoryAddress makeCallback(ResourceScope scope, Ret ret, List<ParamType> params, List<StructFieldType> fields, List<Consumer<Object>> checks, List<Consumer<Object[]>> argChecks) {
154         if (params.isEmpty()) {
155             return dummyStub.address();
156         }
157 
158         AtomicReference<Object[]> box = new AtomicReference<>();
159         MethodHandle mh = insertArguments(PASS_AND_SAVE, 1, box);
160         mh = mh.asCollector(Object[].class, params.size());




161 
162         for (int i = 0; i < params.size(); i++) {
163             ParamType pt = params.get(i);
164             MemoryLayout layout = pt.layout(fields);
165             Class<?> carrier = paramCarrier(layout);
166             mh = mh.asType(mh.type().changeParameterType(i, carrier));
167 
168             final int finalI = i;
169             if (carrier == MemorySegment.class) {
170                 argChecks.add(o -> assertStructEquals((MemorySegment) box.get()[finalI], (MemorySegment) o[finalI], layout));
171             } else {
172                 argChecks.add(o -> assertEquals(box.get()[finalI], o[finalI]));
173             }
174         }
175 
176         ParamType firstParam = params.get(0);
177         MemoryLayout firstlayout = firstParam.layout(fields);
178         Class<?> firstCarrier = paramCarrier(firstlayout);
179 
180         if (firstCarrier == MemorySegment.class) {
181             checks.add(o -> assertStructEquals((MemorySegment) box.get()[0], (MemorySegment) o, firstlayout));
182         } else {
183             checks.add(o -> assertEquals(o, box.get()[0]));
184         }
185 
186         mh = mh.asType(mh.type().changeReturnType(ret == Ret.VOID ? void.class : firstCarrier));
187 
188         MemoryLayout[] paramLayouts = params.stream().map(p -> p.layout(fields)).toArray(MemoryLayout[]::new);
189         FunctionDescriptor func = ret != Ret.VOID
190                 ? FunctionDescriptor.of(firstlayout, paramLayouts)
191                 : FunctionDescriptor.ofVoid(paramLayouts);
192         return abi.upcallStub(mh, func, scope);
193     }
194 
195     static Object passAndSave(Object[] o, AtomicReference<Object[]> ref) {
196         for (int i = 0; i < o.length; i++) {
197             if (o[i] instanceof MemorySegment) {
198                 MemorySegment ms = (MemorySegment) o[i];
199                 MemorySegment copy = MemorySegment.allocateNative(ms.byteSize(), ResourceScope.newImplicitScope());
200                 copy.copyFrom(ms);
201                 o[i] = copy;
202             }
203         }
204         ref.set(o);
205         return o[0];
206     }
207 
208     static void dummy() {
209         //do nothing
210     }













211 }

  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 /*
 26  * @test id=scope
 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 TestUpcall
 30  *
 31  * @run testng/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies
 32  *   --enable-native-access=ALL-UNNAMED -Dgenerator.sample.factor=17
 33  *   -DUPCALL_TEST_TYPE=SCOPE
 34  *   TestUpcall
 35  */
 36 
 37 /*
 38  * @test id=async
 39  * @requires ((os.arch == "amd64" | os.arch == "x86_64") & sun.arch.data.model == "64") | os.arch == "aarch64"
 40  * @modules jdk.incubator.foreign/jdk.internal.foreign
 41  * @build NativeTestHelper CallGeneratorHelper TestUpcall
 42  *
 43  * @run testng/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies
 44  *   --enable-native-access=ALL-UNNAMED -Dgenerator.sample.factor=17
 45  *   -DUPCALL_TEST_TYPE=ASYNC
 46  *   TestUpcall
 47  */
 48 
 49 /*
 50  * @test id=stack
 51  * @requires ((os.arch == "amd64" | os.arch == "x86_64") & sun.arch.data.model == "64") | os.arch == "aarch64"
 52  * @modules jdk.incubator.foreign/jdk.internal.foreign
 53  * @build NativeTestHelper CallGeneratorHelper TestUpcall
 54  *
 55  * @run testng/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies
 56  *   --enable-native-access=ALL-UNNAMED -Dgenerator.sample.factor=17
 57  *   -DUPCALL_TEST_TYPE=STACK
 58  *   TestUpcall
 59  */
 60 
 61 import jdk.incubator.foreign.Addressable;
 62 import jdk.incubator.foreign.CLinker;
 63 import jdk.incubator.foreign.FunctionDescriptor;
 64 import jdk.incubator.foreign.NativeSymbol;
 65 import jdk.incubator.foreign.SegmentAllocator;
 66 import jdk.incubator.foreign.SymbolLookup;
 67 import jdk.incubator.foreign.MemoryAddress;
 68 import jdk.incubator.foreign.MemoryLayout;
 69 import jdk.incubator.foreign.MemorySegment;
 70 
 71 import jdk.incubator.foreign.ResourceScope;
 72 import org.testng.SkipException;
 73 import org.testng.annotations.BeforeClass;
 74 import org.testng.annotations.Test;
 75 
 76 import java.lang.invoke.MethodHandle;
 77 import java.lang.invoke.MethodHandles;
 78 import java.lang.invoke.MethodType;
 79 import java.util.ArrayList;
 80 import java.util.HashMap;
 81 import java.util.List;
 82 import java.util.Map;
 83 import java.util.concurrent.atomic.AtomicReference;
 84 import java.util.function.Consumer;
 85 import java.util.stream.Collectors;
 86 import java.util.stream.Stream;
 87 
 88 import static java.lang.invoke.MethodHandles.insertArguments;

 89 import static org.testng.Assert.assertEquals;
 90 

 91 public class TestUpcall extends CallGeneratorHelper {
 92 
 93     private enum TestType {
 94         SCOPE,
 95         ASYNC,
 96         STACK
 97     }
 98 
 99     private static final TestType UPCALL_TEST_TYPE = TestType.valueOf(System.getProperty("UPCALL_TEST_TYPE"));
100 
101     static {
102         System.loadLibrary("TestUpcall");
103         System.loadLibrary("TestUpcallStack");
104         System.loadLibrary("AsyncInvokers");
105     }
106     static CLinker abi = CLinker.systemCLinker();
107 
108     static final SymbolLookup LOOKUP = SymbolLookup.loaderLookup();
109 
110     static MethodHandle DUMMY;
111     static MethodHandle PASS_AND_SAVE;
112 
113     static {
114         try {
115             DUMMY = MethodHandles.lookup().findStatic(TestUpcall.class, "dummy", MethodType.methodType(void.class));
116             PASS_AND_SAVE = MethodHandles.lookup().findStatic(TestUpcall.class, "passAndSave",
117                     MethodType.methodType(Object.class, Object[].class, AtomicReference.class, int.class));
118         } catch (Throwable ex) {
119             throw new IllegalStateException(ex);
120         }
121     }
122 
123     static NativeSymbol dummyStub;
124 
125     @BeforeClass
126     void setup() {
127         dummyStub = abi.upcallStub(DUMMY, FunctionDescriptor.ofVoid(), ResourceScope.newImplicitScope());
128     }
129 
130     private static void checkSelected(TestType type) {
131         if (UPCALL_TEST_TYPE != type)
132             throw new SkipException("Skipping tests that were not selected");
133     }
134 
135     @Test(dataProvider="functions", dataProviderClass=CallGeneratorHelper.class)
136     public void testUpcalls(int count, String fName, Ret ret, List<ParamType> paramTypes, List<StructFieldType> fields) throws Throwable {
137         checkSelected(TestType.SCOPE);
138 
139         List<Consumer<Object>> returnChecks = new ArrayList<>();
140         List<Consumer<Object[]>> argChecks = new ArrayList<>();
141         NativeSymbol addr = LOOKUP.lookup(fName).get();
142         try (ResourceScope scope = ResourceScope.newConfinedScope()) {
143             SegmentAllocator allocator = SegmentAllocator.newNativeArena(scope);
144             MethodHandle mh = downcallHandle(abi, addr, allocator, function(ret, paramTypes, fields));
145             Object[] args = makeArgs(scope, ret, paramTypes, fields, returnChecks, argChecks);
146             Object[] callArgs = args;
147             Object res = mh.invokeWithArguments(callArgs);
148             argChecks.forEach(c -> c.accept(args));
149             if (ret == Ret.NON_VOID) {
150                 returnChecks.forEach(c -> c.accept(res));
151             }
152         }
153     }
154 
155     @Test(dataProvider="functions", dataProviderClass=CallGeneratorHelper.class)
156     public void testUpcallsAsync(int count, String fName, Ret ret, List<ParamType> paramTypes, List<StructFieldType> fields) throws Throwable {
157         checkSelected(TestType.ASYNC);
158 
159         List<Consumer<Object>> returnChecks = new ArrayList<>();
160         List<Consumer<Object[]>> argChecks = new ArrayList<>();
161         NativeSymbol addr = LOOKUP.lookup(fName).get();
162         try (ResourceScope scope = ResourceScope.newSharedScope()) {
163             SegmentAllocator allocator = SegmentAllocator.newNativeArena(scope);
164             FunctionDescriptor descriptor = function(ret, paramTypes, fields);
165             MethodHandle mh = reverse(downcallHandle(abi, addr, allocator, descriptor));
166             Object[] args = makeArgs(ResourceScope.newImplicitScope(), ret, paramTypes, fields, returnChecks, argChecks);
167 
168             mh = mh.asSpreader(Object[].class, args.length);
169             mh = MethodHandles.insertArguments(mh, 0, (Object) args);
170             FunctionDescriptor callbackDesc = descriptor.returnLayout()
171                     .map(FunctionDescriptor::of)
172                     .orElse(FunctionDescriptor.ofVoid());
173             NativeSymbol callback = abi.upcallStub(mh, callbackDesc, scope);
174 
175             MethodHandle invoker = asyncInvoker(ret, ret == Ret.VOID ? null : paramTypes.get(0), fields);
176 
177             Object res = invoker.type().returnType() == MemorySegment.class
178                     ? invoker.invoke(allocator, callback)
179                     : invoker.invoke(callback);
180             argChecks.forEach(c -> c.accept(args));
181             if (ret == Ret.NON_VOID) {
182                 returnChecks.forEach(c -> c.accept(res));
183             }
184         }
185     }
186 
187     @Test(dataProvider="functions", dataProviderClass=CallGeneratorHelper.class)
188     public void testUpcallsStack(int count, String fName, Ret ret, List<ParamType> paramTypes, List<StructFieldType> fields) throws Throwable {
189         checkSelected(TestType.STACK);
190 
191         List<Consumer<Object>> returnChecks = new ArrayList<>();
192         List<Consumer<Object[]>> argChecks = new ArrayList<>();
193         NativeSymbol addr = LOOKUP.lookup("s" + fName).get();
194         try (ResourceScope scope = ResourceScope.newConfinedScope()) {
195             SegmentAllocator allocator = SegmentAllocator.newNativeArena(scope);
196             MethodHandle mh = downcallHandle(abi, addr, allocator, functionStack(ret, paramTypes, fields));
197             Object[] args = makeArgsStack(scope, ret, paramTypes, fields, returnChecks, argChecks);
198             Object[] callArgs = args;
199             Object res = mh.invokeWithArguments(callArgs);
200             argChecks.forEach(c -> c.accept(args));
201             if (ret == Ret.NON_VOID) {
202                 returnChecks.forEach(c -> c.accept(res));
203             }
204         }
205     }
206 
207     private static final Map<String, MethodHandle> INVOKERS = new HashMap<>();
208 
209     private MethodHandle asyncInvoker(Ret ret, ParamType returnType, List<StructFieldType> fields) {
210         if (ret == Ret.VOID) {
211             String name = "call_async_V";
212             return INVOKERS.computeIfAbsent(name, symbol ->
213                     abi.downcallHandle(
214                             LOOKUP.lookup(symbol).orElseThrow(),
215                             FunctionDescriptor.ofVoid(C_POINTER)));
216         }
217 
218         String name = "call_async_" + returnType.name().charAt(0)
219                 + (returnType == ParamType.STRUCT ? "_" + sigCode(fields) : "");
220 
221         return INVOKERS.computeIfAbsent(name, symbol -> {
222             NativeSymbol invokerSymbol = LOOKUP.lookup(symbol).orElseThrow();
223             MemoryLayout returnLayout = returnType.layout(fields);
224             FunctionDescriptor desc = FunctionDescriptor.of(returnLayout, C_POINTER);
225 
226             return abi.downcallHandle(invokerSymbol, desc);
227         });
228     }
229 
230     static FunctionDescriptor functionStack(Ret ret, List<ParamType> params, List<StructFieldType> fields) {
231         return function(ret, params, fields, STACK_PREFIX_LAYOUTS);
232     }
233 
234     static FunctionDescriptor function(Ret ret, List<ParamType> params, List<StructFieldType> fields) {
235         return function(ret, params, fields, List.of());
236     }
237 
238     static FunctionDescriptor function(Ret ret, List<ParamType> params, List<StructFieldType> fields, List<MemoryLayout> prefix) {
239         List<MemoryLayout> paramLayouts = params.stream().map(p -> p.layout(fields)).collect(Collectors.toList());
240         paramLayouts.add(C_POINTER); // the callback
241         MemoryLayout[] layouts = Stream.concat(prefix.stream(), paramLayouts.stream()).toArray(MemoryLayout[]::new);
242         return ret == Ret.VOID ?
243                 FunctionDescriptor.ofVoid(layouts) :
244                 FunctionDescriptor.of(layouts[prefix.size()], layouts);
245     }
246 
247     static Object[] makeArgsStack(ResourceScope scope, Ret ret, List<ParamType> params, List<StructFieldType> fields, List<Consumer<Object>> checks, List<Consumer<Object[]>> argChecks) throws ReflectiveOperationException {
248         return makeArgs(scope, ret, params, fields, checks, argChecks, STACK_PREFIX_LAYOUTS);
249     }
250 
251     static Object[] makeArgs(ResourceScope scope, Ret ret, List<ParamType> params, List<StructFieldType> fields, List<Consumer<Object>> checks, List<Consumer<Object[]>> argChecks) throws ReflectiveOperationException {
252         return makeArgs(scope, ret, params, fields, checks, argChecks, List.of());
253     }
254 
255     static Object[] makeArgs(ResourceScope scope, Ret ret, List<ParamType> params, List<StructFieldType> fields, List<Consumer<Object>> checks, List<Consumer<Object[]>> argChecks, List<MemoryLayout> prefix) throws ReflectiveOperationException {
256         Object[] args = new Object[prefix.size() + params.size() + 1];
257         int argNum = 0;
258         for (MemoryLayout layout : prefix) {
259             args[argNum++] = makeArg(layout, null, false);
260         }
261         for (int i = 0 ; i < params.size() ; i++) {
262             args[argNum++] = makeArg(params.get(i).layout(fields), checks, i == 0);
263         }
264         args[argNum] = makeCallback(scope, ret, params, fields, checks, argChecks, prefix);
265         return args;
266     }
267 
268     static NativeSymbol makeCallback(ResourceScope scope, Ret ret, List<ParamType> params, List<StructFieldType> fields, List<Consumer<Object>> checks, List<Consumer<Object[]>> argChecks, List<MemoryLayout> prefix) {

269         if (params.isEmpty()) {
270             return dummyStub;
271         }
272 
273         AtomicReference<Object[]> box = new AtomicReference<>();
274         MethodHandle mh = insertArguments(PASS_AND_SAVE, 1, box, prefix.size());
275         mh = mh.asCollector(Object[].class, prefix.size() + params.size());
276 
277         for(int i = 0; i < prefix.size(); i++) {
278             mh = mh.asType(mh.type().changeParameterType(i, carrier(prefix.get(i), false)));
279         }
280 
281         for (int i = 0; i < params.size(); i++) {
282             ParamType pt = params.get(i);
283             MemoryLayout layout = pt.layout(fields);
284             Class<?> carrier = carrier(layout, false);
285             mh = mh.asType(mh.type().changeParameterType(prefix.size() + i, carrier));
286 
287             final int finalI = prefix.size() + i;
288             if (carrier == MemorySegment.class) {
289                 argChecks.add(o -> assertStructEquals((MemorySegment) box.get()[finalI], (MemorySegment) o[finalI], layout));
290             } else {
291                 argChecks.add(o -> assertEquals(box.get()[finalI], o[finalI]));
292             }
293         }
294 
295         ParamType firstParam = params.get(0);
296         MemoryLayout firstlayout = firstParam.layout(fields);
297         Class<?> firstCarrier = carrier(firstlayout, true);
298 
299         if (firstCarrier == MemorySegment.class) {
300             checks.add(o -> assertStructEquals((MemorySegment) box.get()[prefix.size()], (MemorySegment) o, firstlayout));
301         } else {
302             checks.add(o -> assertEquals(o, box.get()[prefix.size()]));
303         }
304 
305         mh = mh.asType(mh.type().changeReturnType(ret == Ret.VOID ? void.class : firstCarrier));
306 
307         MemoryLayout[] paramLayouts = Stream.concat(prefix.stream(), params.stream().map(p -> p.layout(fields))).toArray(MemoryLayout[]::new);
308         FunctionDescriptor func = ret != Ret.VOID
309                 ? FunctionDescriptor.of(firstlayout, paramLayouts)
310                 : FunctionDescriptor.ofVoid(paramLayouts);
311         return abi.upcallStub(mh, func, scope);
312     }
313 
314     static Object passAndSave(Object[] o, AtomicReference<Object[]> ref, int retArg) {
315         for (int i = 0; i < o.length; i++) {
316             if (o[i] instanceof MemorySegment) {
317                 MemorySegment ms = (MemorySegment) o[i];
318                 MemorySegment copy = MemorySegment.allocateNative(ms.byteSize(), ResourceScope.newImplicitScope());
319                 copy.copyFrom(ms);
320                 o[i] = copy;
321             }
322         }
323         ref.set(o);
324         return o[retArg];
325     }
326 
327     static void dummy() {
328         //do nothing
329     }
330 
331     static MethodHandle reverse(MethodHandle handle) {
332         MethodType type = handle.type();
333         if (type.returnType().equals(MemoryAddress.class)) {
334             type = type.changeReturnType(Addressable.class);
335         }
336         for (int i = 0 ; i < type.parameterCount() ; i++) {
337             if (type.parameterType(i).equals(Addressable.class)) {
338                 type.changeParameterType(i, MemoryAddress.class);
339             }
340         }
341         return handle.asType(type);
342     }
343 }
< prev index next >