< prev index next >

src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/ProgrammableInvoker.java

Print this page

  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 package jdk.internal.foreign.abi;
 24 
 25 import jdk.incubator.foreign.FunctionDescriptor;
 26 import jdk.incubator.foreign.MemoryAddress;
 27 import jdk.incubator.foreign.MemoryHandles;
 28 import jdk.incubator.foreign.MemorySegment;



 29 import jdk.internal.foreign.MemoryAddressImpl;

 30 
 31 import java.lang.invoke.MethodHandle;
 32 import java.lang.invoke.MethodHandles;
 33 import java.lang.invoke.MethodType;
 34 import java.lang.invoke.VarHandle;
 35 import java.nio.ByteOrder;
 36 import java.util.ArrayList;

 37 import java.util.List;
 38 import java.util.Map;
 39 import java.util.concurrent.ConcurrentHashMap;


 40 









 41 import static sun.security.action.GetBooleanAction.privilegedGetProperty;
 42 
 43 /**
 44  * This class implements native call invocation through a so called 'universal adapter'. A universal adapter takes
 45  * an array of longs together with a call 'recipe', which is used to move the arguments in the right places as
 46  * expected by the system ABI.
 47  */
 48 public class ProgrammableInvoker {
 49     private static final boolean DEBUG =
 50         privilegedGetProperty("jdk.internal.foreign.ProgrammableInvoker.DEBUG");


 51 
 52     private static final VarHandle VH_LONG = MemoryHandles.varHandle(long.class, ByteOrder.nativeOrder());
 53 
 54     // Unbound MH for the invoke() method
 55     private static final MethodHandle INVOKE_MH;








 56 
 57     private static final Map<ABIDescriptor, Long> adapterStubs = new ConcurrentHashMap<>();
 58 
 59     static {
 60         try {
 61             INVOKE_MH = MethodHandles.lookup().findVirtual(ProgrammableInvoker.class, "invoke", MethodType.methodType(Object.class, Object[].class));


















 62         } catch (ReflectiveOperationException e) {
 63             throw new RuntimeException(e);
 64         }
 65     }
 66 
 67     private final ABIDescriptor abi;
 68     private final BufferLayout layout;
 69     private final long stackArgsBytes;
 70 
 71     private final MethodType type;
 72     private final FunctionDescriptor function;
 73     private final CallingSequence callingSequence;
 74 
 75     private final MemoryAddress addr;
 76     private final long stubAddress;
 77 


 78     public ProgrammableInvoker(ABIDescriptor abi, MemoryAddress addr, CallingSequence callingSequence) {
 79         this.abi = abi;
 80         this.layout = BufferLayout.of(abi);
 81         this.stubAddress = adapterStubs.computeIfAbsent(abi, key -> generateAdapter(key, layout));
 82 
 83         this.addr = addr;
 84         this.callingSequence = callingSequence;
 85         this.type = callingSequence.methodType();
 86         this.function = callingSequence.functionDesc();
 87 
 88         this.stackArgsBytes = callingSequence.moveBindings()
 89                 .map(Binding.Move::storage)
 90                 .filter(s -> abi.arch.isStackType(s.type()))
 91                 .count()
 92                 * abi.arch.typeSize(abi.arch.stackType());



















 93     }
 94 
 95     public MethodHandle getBoundMethodHandle() {
 96         return INVOKE_MH.bindTo(this).asCollector(Object[].class, type.parameterCount()).asType(type);



























 97     }
 98 
 99     Object invoke(Object[] args) {
100         List<MemorySegment> tempBuffers = new ArrayList<>();












































































































































101         try (MemorySegment argBuffer = MemorySegment.allocateNative(layout.size, 64)) {
102             MemoryAddress argsPtr = argBuffer.baseAddress();
103             MemoryAddress stackArgs;
104             if (stackArgsBytes > 0) {
105                 MemorySegment stackArgsSeg = MemorySegment.allocateNative(stackArgsBytes, 8);
106                 tempBuffers.add(stackArgsSeg);
107                 stackArgs = stackArgsSeg.baseAddress();
108             } else {
109                 stackArgs = MemoryAddressImpl.NULL;
110             }
111 
112             VH_LONG.set(argsPtr.addOffset(layout.arguments_next_pc), addr.toRawLongValue());
113             VH_LONG.set(argsPtr.addOffset(layout.stack_args_bytes), stackArgsBytes);
114             VH_LONG.set(argsPtr.addOffset(layout.stack_args), stackArgs.toRawLongValue());
115 
116             for (int i = 0; i < args.length; i++) {
117                 Object arg = args[i];
118                 jdk.internal.foreign.abi.BindingInterpreter.unbox(arg, callingSequence.argumentBindings(i),
119                         s -> {
120                             if (abi.arch.isStackType(s.type())) {
121                                 return stackArgs.addOffset(s.index() * abi.arch.typeSize(abi.arch.stackType()));
122                             }
123                             return argsPtr.addOffset(layout.argOffset(s));
124                         }, tempBuffers);
125             }
126 
127             if (DEBUG) {
128                 System.err.println("Buffer state before:");
129                 layout.dump(abi.arch, argsPtr, System.err);
130             }
131 
132             invokeNative(stubAddress, argsPtr.toRawLongValue());
133 
134             if (DEBUG) {
135                 System.err.println("Buffer state after:");
136                 layout.dump(abi.arch, argsPtr, System.err);
137             }
138 
139             return function.returnLayout().isEmpty()
140                     ? null
141                     : jdk.internal.foreign.abi.BindingInterpreter.box(callingSequence.returnBindings(),
142                     s -> argsPtr.addOffset(layout.retOffset(s))); // buffers are leaked














































143         } finally {
144             tempBuffers.forEach(MemorySegment::close);
145         }
146     }
147 
148     //natives
149 
150     static native void invokeNative(long adapterStub, long buff);
151     static native long generateAdapter(ABIDescriptor abi, BufferLayout layout);
152 
153     private static native void registerNatives();
154     static {
155         registerNatives();
156     }
157 }
158 

  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 package jdk.internal.foreign.abi;
 24 

 25 import jdk.incubator.foreign.MemoryAddress;
 26 import jdk.incubator.foreign.MemoryHandles;
 27 import jdk.incubator.foreign.MemorySegment;
 28 import jdk.incubator.foreign.NativeAllocationScope;
 29 import jdk.internal.access.JavaLangInvokeAccess;
 30 import jdk.internal.access.SharedSecrets;
 31 import jdk.internal.foreign.MemoryAddressImpl;
 32 import jdk.internal.foreign.Utils;
 33 
 34 import java.lang.invoke.MethodHandle;
 35 import java.lang.invoke.MethodHandles;
 36 import java.lang.invoke.MethodType;
 37 import java.lang.invoke.VarHandle;
 38 import java.nio.ByteOrder;
 39 import java.util.ArrayList;
 40 import java.util.Arrays;
 41 import java.util.List;
 42 import java.util.Map;
 43 import java.util.concurrent.ConcurrentHashMap;
 44 import java.util.stream.Collectors;
 45 import java.util.stream.IntStream;
 46 
 47 import static java.lang.invoke.MethodHandles.collectArguments;
 48 import static java.lang.invoke.MethodHandles.dropArguments;
 49 import static java.lang.invoke.MethodHandles.empty;
 50 import static java.lang.invoke.MethodHandles.filterArguments;
 51 import static java.lang.invoke.MethodHandles.identity;
 52 import static java.lang.invoke.MethodHandles.insertArguments;
 53 import static java.lang.invoke.MethodHandles.permuteArguments;
 54 import static java.lang.invoke.MethodHandles.tryFinally;
 55 import static java.lang.invoke.MethodType.methodType;
 56 import static sun.security.action.GetBooleanAction.privilegedGetProperty;
 57 
 58 /**
 59  * This class implements native call invocation through a so called 'universal adapter'. A universal adapter takes
 60  * an array of longs together with a call 'recipe', which is used to move the arguments in the right places as
 61  * expected by the system ABI.
 62  */
 63 public class ProgrammableInvoker {
 64     private static final boolean DEBUG =
 65         privilegedGetProperty("jdk.internal.foreign.ProgrammableInvoker.DEBUG");
 66     private static final boolean NO_SPEC =
 67         privilegedGetProperty("jdk.internal.foreign.ProgrammableInvoker.NO_SPEC");
 68 
 69     private static final VarHandle VH_LONG = MemoryHandles.varHandle(long.class, ByteOrder.nativeOrder());
 70 
 71     private static final MethodHandle MH_INVOKE_MOVES;
 72     private static final MethodHandle MH_INVOKE_INTERP_BINDINGS;
 73 
 74     private static final MethodHandle MH_UNBOX_ADDRESS;
 75     private static final MethodHandle MH_BOX_ADDRESS;
 76     private static final MethodHandle MH_BASE_ADDRESS;
 77     private static final MethodHandle MH_COPY_BUFFER;
 78     private static final MethodHandle MH_MAKE_ALLOCATOR;
 79     private static final MethodHandle MH_CLOSE_ALLOCATOR;
 80     private static final MethodHandle MH_ALLOCATE_BUFFER;
 81 
 82     private static final Map<ABIDescriptor, Long> adapterStubs = new ConcurrentHashMap<>();
 83 
 84     static {
 85         try {
 86             MethodHandles.Lookup lookup = MethodHandles.lookup();
 87             MH_INVOKE_MOVES = lookup.findVirtual(ProgrammableInvoker.class, "invokeMoves",
 88                     methodType(Object.class, Object[].class, Binding.Move[].class, Binding.Move[].class));
 89             MH_INVOKE_INTERP_BINDINGS = lookup.findVirtual(ProgrammableInvoker.class, "invokeInterpBindings",
 90                     methodType(Object.class, Object[].class, MethodHandle.class, Map.class, Map.class));
 91             MH_UNBOX_ADDRESS = lookup.findStatic(ProgrammableInvoker.class, "toRawLongValue",
 92                     methodType(long.class, MemoryAddress.class));
 93             MH_BOX_ADDRESS = lookup.findStatic(ProgrammableInvoker.class, "ofLong",
 94                     methodType(MemoryAddress.class, long.class));
 95             MH_BASE_ADDRESS = lookup.findVirtual(MemorySegment.class, "baseAddress",
 96                     methodType(MemoryAddress.class));
 97             MH_COPY_BUFFER = lookup.findStatic(ProgrammableInvoker.class, "copyBuffer",
 98                     methodType(MemorySegment.class, MemorySegment.class, long.class, long.class, NativeAllocationScope.class));
 99             MH_MAKE_ALLOCATOR = lookup.findStatic(NativeAllocationScope.class, "boundedScope",
100                     methodType(NativeAllocationScope.class, long.class));
101             MH_CLOSE_ALLOCATOR = lookup.findVirtual(NativeAllocationScope.class, "close",
102                     methodType(void.class));
103             MH_ALLOCATE_BUFFER = lookup.findStatic(MemorySegment.class, "allocateNative",
104                     methodType(MemorySegment.class, long.class, long.class));
105         } catch (ReflectiveOperationException e) {
106             throw new RuntimeException(e);
107         }
108     }
109 
110     private final ABIDescriptor abi;
111     private final BufferLayout layout;
112     private final long stackArgsBytes;
113 


114     private final CallingSequence callingSequence;
115 
116     private final MemoryAddress addr;
117     private final long stubAddress;
118 
119     private final long bufferCopySize;
120 
121     public ProgrammableInvoker(ABIDescriptor abi, MemoryAddress addr, CallingSequence callingSequence) {
122         this.abi = abi;
123         this.layout = BufferLayout.of(abi);
124         this.stubAddress = adapterStubs.computeIfAbsent(abi, key -> generateAdapter(key, layout));
125 
126         this.addr = addr;
127         this.callingSequence = callingSequence;


128 
129         this.stackArgsBytes = callingSequence.argMoveBindings()
130                 .map(Binding.Move::storage)
131                 .filter(s -> abi.arch.isStackType(s.type()))
132                 .count()
133                 * abi.arch.typeSize(abi.arch.stackType());
134 
135         this.bufferCopySize = bufferCopySize(callingSequence);
136     }
137 
138     private static long bufferCopySize(CallingSequence callingSequence) {
139         // FIXME: > 16 bytes alignment might need extra space since the
140         // starting address of the allocator might be un-aligned.
141         long size = 0;
142         for (int i = 0; i < callingSequence.argumentCount(); i++) {
143             List<Binding> bindings = callingSequence.argumentBindings(i);
144             for (Binding b : bindings) {
145                 if (b instanceof Binding.Copy) {
146                     Binding.Copy c = (Binding.Copy) b;
147                     size = Utils.alignUp(size, c.alignment());
148                     size += c.size();
149                 }
150             }
151         }
152         return size;
153     }
154 
155     public MethodHandle getBoundMethodHandle() {
156         Binding.Move[] argMoves = callingSequence.argMoveBindings().toArray(Binding.Move[]::new);
157         Class<?>[] argMoveTypes = Arrays.stream(argMoves).map(Binding.Move::type).toArray(Class<?>[]::new);
158 
159         Binding.Move[] retMoves = callingSequence.retMoveBindings().toArray(Binding.Move[]::new);
160         Class<?> returnType = retMoves.length == 0
161                 ? void.class
162                 : retMoves.length == 1
163                     ? retMoves[0].type()
164                     : Object[].class;
165 
166         MethodType intrinsicType = methodType(returnType, argMoveTypes);
167 
168         MethodHandle handle = insertArguments(MH_INVOKE_MOVES.bindTo(this), 1, argMoves, retMoves)
169                                             .asCollector(Object[].class, intrinsicType.parameterCount())
170                                             .asType(intrinsicType);
171 
172         if (NO_SPEC || retMoves.length > 1) {
173             Map<VMStorage, Integer> argIndexMap = indexMap(argMoves);
174             Map<VMStorage, Integer> retIndexMap = indexMap(retMoves);
175 
176             handle = insertArguments(MH_INVOKE_INTERP_BINDINGS.bindTo(this), 1, handle, argIndexMap, retIndexMap);
177             handle = handle.asCollector(Object[].class, callingSequence.methodType().parameterCount())
178                                              .asType(callingSequence.methodType());
179          } else {
180              handle = specialize(handle);
181          }
182 
183         return handle;
184     }
185 
186     private MethodHandle specialize(MethodHandle intrinsicHandle) {
187         MethodType type = callingSequence.methodType();
188         MethodType intrinsicType = intrinsicHandle.type();
189 
190         int insertPos = -1;
191         if (bufferCopySize > 0) {
192             intrinsicHandle = dropArguments(intrinsicHandle, 0, NativeAllocationScope.class);
193             insertPos++;
194         }
195         for (int i = 0; i < type.parameterCount(); i++) {
196             List<Binding> bindings = callingSequence.argumentBindings(i);
197             insertPos += bindings.stream().filter(Binding.Move.class::isInstance).count() + 1;
198             // We interpret the bindings in reverse since we have to construct a MethodHandle from the bottom up
199             for (int j = bindings.size() - 1; j >= 0; j--) {
200                 Binding binding = bindings.get(j);
201                 switch (binding.tag()) {
202                     case MOVE -> insertPos--; // handled by fallback
203                     case DUP ->
204                         intrinsicHandle = mergeArguments(intrinsicHandle, insertPos, insertPos + 1);
205                     case CONVERT_ADDRESS ->
206                         intrinsicHandle = filterArguments(intrinsicHandle, insertPos, MH_UNBOX_ADDRESS);
207                     case BASE_ADDRESS ->
208                         intrinsicHandle = filterArguments(intrinsicHandle, insertPos, MH_BASE_ADDRESS);
209                     case DEREFERENCE -> {
210                         Binding.Dereference deref = (Binding.Dereference) binding;
211                         MethodHandle filter = filterArguments(
212                             deref.varHandle()
213                             .toMethodHandle(VarHandle.AccessMode.GET)
214                             .asType(methodType(deref.type(), MemoryAddress.class)), 0, MH_BASE_ADDRESS);
215                         intrinsicHandle = filterArguments(intrinsicHandle, insertPos, filter);
216                     }
217                     case COPY_BUFFER -> {
218                         Binding.Copy copy = (Binding.Copy) binding;
219                         MethodHandle filter = insertArguments(MH_COPY_BUFFER, 1, copy.size(), copy.alignment());
220                         intrinsicHandle = collectArguments(intrinsicHandle, insertPos, filter);
221                         intrinsicHandle = mergeArguments(intrinsicHandle, 0, insertPos + 1);
222                     }
223                     default -> throw new IllegalArgumentException("Illegal tag: " + binding.tag());
224                 }
225             }
226         }
227 
228         if (type.returnType() != void.class) {
229             MethodHandle returnFilter = identity(type.returnType());
230             List<Binding> bindings = callingSequence.returnBindings();
231             for (int j = bindings.size() - 1; j >= 0; j--) {
232                 Binding binding = bindings.get(j);
233                 switch (binding.tag()) {
234                     case MOVE -> { /* handled by fallback */ }
235                     case CONVERT_ADDRESS ->
236                         returnFilter = filterArguments(returnFilter, 0, MH_BOX_ADDRESS);
237                     case DEREFERENCE -> {
238                         Binding.Dereference deref = (Binding.Dereference) binding;
239                         MethodHandle setter = deref.varHandle().toMethodHandle(VarHandle.AccessMode.SET);
240                         setter = filterArguments(
241                             setter.asType(methodType(void.class, MemoryAddress.class, deref.type())),
242                             0, MH_BASE_ADDRESS);
243                         returnFilter = collectArguments(returnFilter, returnFilter.type().parameterCount(), setter);
244                     }
245                     case DUP ->
246                         // FIXME assumes shape like: (MS, ..., MS, T) R, is that good enough?
247                         returnFilter = mergeArguments(returnFilter, 0, returnFilter.type().parameterCount() - 2);
248                     case ALLOC_BUFFER -> {
249                         Binding.Allocate alloc = (Binding.Allocate) binding;
250                         returnFilter = collectArguments(returnFilter, 0,
251                                 insertArguments(MH_ALLOCATE_BUFFER, 0, alloc.size(), alloc.alignment()));
252                     }
253                     default ->
254                         throw new IllegalArgumentException("Illegal tag: " + binding.tag());
255                 }
256             }
257 
258             intrinsicHandle = MethodHandles.filterReturnValue(intrinsicHandle, returnFilter);
259         }
260 
261         if (bufferCopySize > 0) {
262             MethodHandle closer = intrinsicType.returnType() == void.class
263                   // (Throwable, NativeAllocationScope) -> void
264                 ? collectArguments(empty(methodType(void.class, Throwable.class)), 1, MH_CLOSE_ALLOCATOR)
265                   // (Throwable, V, NativeAllocationScope) -> V
266                 : collectArguments(dropArguments(identity(intrinsicHandle.type().returnType()), 0, Throwable.class),
267                                    2, MH_CLOSE_ALLOCATOR);
268             intrinsicHandle = tryFinally(intrinsicHandle, closer);
269             intrinsicHandle = collectArguments(intrinsicHandle, 0, insertArguments(MH_MAKE_ALLOCATOR, 0, bufferCopySize));
270         }
271         return intrinsicHandle;
272     }
273 
274     private static MethodHandle mergeArguments(MethodHandle mh, int sourceIndex, int destIndex) {
275         MethodType oldType = mh.type();
276         Class<?> sourceType = oldType.parameterType(sourceIndex);
277         Class<?> destType = oldType.parameterType(destIndex);
278         if (sourceType != destType) {
279             // TODO meet?
280             throw new IllegalArgumentException("Parameter types differ: " + sourceType + " != " + destType);
281         }
282         MethodType newType = oldType.dropParameterTypes(destIndex, destIndex + 1);
283         int[] reorder = new int[oldType.parameterCount()];
284         assert destIndex > sourceIndex;
285         for (int i = 0, index = 0; i < reorder.length; i++) {
286             if (i != destIndex) {
287                 reorder[i] = index++;
288             } else {
289                 reorder[i] = sourceIndex;
290             }
291         }
292         return permuteArguments(mh, newType, reorder);
293     }
294 
295     private static MemorySegment copyBuffer(MemorySegment operand, long size, long alignment,
296                                     NativeAllocationScope allocator) {
297         assert operand.byteSize() == size : "operand size mismatch";
298         MemorySegment copy = allocator.allocate(size, alignment).segment();
299         copy.copyFrom(operand.asSlice(0, size));
300         return copy;
301     }
302 
303     private static long toRawLongValue(MemoryAddress address) {
304         return address.toRawLongValue(); // Workaround for JDK-8239083
305     }
306 
307     private static MemoryAddress ofLong(long address) {
308         return MemoryAddress.ofLong(address); // Workaround for JDK-8239083
309     }
310 
311     private Map<VMStorage, Integer> indexMap(Binding.Move[] moves) {
312         return IntStream.range(0, moves.length)
313                         .boxed()
314                         .collect(Collectors.toMap(i -> moves[i].storage(), i -> i));
315     }
316 
317     /**
318      * Does a native invocation by moving primitive values from the arg array into an intermediate buffer
319      * and calling the assembly stub that forwards arguments from the buffer to the target function
320      *
321      * @param args an array of primitive values to be copied in to the buffer
322      * @param argBindings Binding.Move values describing how arguments should be copied
323      * @param returnBindings Binding.Move values describing how return values should be copied
324      * @return null, a single primitive value, or an Object[] of primitive values
325      */
326     Object invokeMoves(Object[] args, Binding.Move[] argBindings, Binding.Move[] returnBindings) {
327         MemorySegment stackArgsSeg = null;
328         try (MemorySegment argBuffer = MemorySegment.allocateNative(layout.size, 64)) {
329             MemoryAddress argsPtr = argBuffer.baseAddress();
330             MemoryAddress stackArgs;
331             if (stackArgsBytes > 0) {
332                 stackArgsSeg = MemorySegment.allocateNative(stackArgsBytes, 8);

333                 stackArgs = stackArgsSeg.baseAddress();
334             } else {
335                 stackArgs = MemoryAddressImpl.NULL;
336             }
337 
338             VH_LONG.set(argsPtr.addOffset(layout.arguments_next_pc), addr.toRawLongValue());
339             VH_LONG.set(argsPtr.addOffset(layout.stack_args_bytes), stackArgsBytes);
340             VH_LONG.set(argsPtr.addOffset(layout.stack_args), stackArgs.toRawLongValue());
341 
342             for (int i = 0; i < argBindings.length; i++) {
343                 Binding.Move binding = argBindings[i];
344                 VMStorage storage = binding.storage();
345                 MemoryAddress ptr = abi.arch.isStackType(storage.type())
346                     ? stackArgs.addOffset(storage.index() * abi.arch.typeSize(abi.arch.stackType()))
347                     : argsPtr.addOffset(layout.argOffset(storage));
348                 SharedUtils.writeOverSized(ptr, binding.type(), args[i]);


349             }
350 
351             if (DEBUG) {
352                 System.err.println("Buffer state before:");
353                 layout.dump(abi.arch, argsPtr, System.err);
354             }
355 
356             invokeNative(stubAddress, argsPtr.toRawLongValue());
357 
358             if (DEBUG) {
359                 System.err.println("Buffer state after:");
360                 layout.dump(abi.arch, argsPtr, System.err);
361             }
362 
363             if (returnBindings.length == 0) {
364                 return null;
365             } else if (returnBindings.length == 1) {
366                 Binding.Move move = returnBindings[0];
367                 VMStorage storage = move.storage();
368                 return SharedUtils.read(argsPtr.addOffset(layout.retOffset(storage)), move.type());
369             } else { // length > 1
370                 Object[] returns = new Object[returnBindings.length];
371                 for (int i = 0; i < returnBindings.length; i++) {
372                     Binding.Move move = returnBindings[i];
373                     VMStorage storage = move.storage();
374                     returns[i] = SharedUtils.read(argsPtr.addOffset(layout.retOffset(storage)), move.type());
375                 }
376                 return returns;
377             }
378         } finally {
379             if (stackArgsSeg != null) {
380                 stackArgsSeg.close();
381             }
382         }
383     }
384 
385     Object invokeInterpBindings(Object[] args, MethodHandle leaf,
386                                 Map<VMStorage, Integer> argIndexMap,
387                                 Map<VMStorage, Integer> retIndexMap) throws Throwable {
388         List<MemorySegment> tempBuffers = new ArrayList<>();
389         try {
390             // do argument processing, get Object[] as result
391             Object[] moves = new Object[leaf.type().parameterCount()];
392             for (int i = 0; i < args.length; i++) {
393                 Object arg = args[i];
394                 BindingInterpreter.unbox(arg, callingSequence.argumentBindings(i),
395                         (storage, type, value) -> {
396                             moves[argIndexMap.get(storage)] = value;
397                         }, tempBuffers);
398             }
399 
400             // call leaf
401             Object o = leaf.invokeWithArguments(moves);
402 
403             // return value processing
404             if (o == null) {
405                 return null;
406             } else if (o instanceof Object[]) {
407                 Object[] oArr = (Object[]) o;
408                 return BindingInterpreter.box(callingSequence.returnBindings(),
409                         (storage, type) -> oArr[retIndexMap.get(storage)]);
410             } else {
411                 return BindingInterpreter.box(callingSequence.returnBindings(), (storage, type) -> o);
412             }
413         } finally {
414             tempBuffers.forEach(MemorySegment::close);
415         }
416     }
417 
418     //natives
419 
420     static native void invokeNative(long adapterStub, long buff);
421     static native long generateAdapter(ABIDescriptor abi, BufferLayout layout);
422 
423     private static native void registerNatives();
424     static {
425         registerNatives();
426     }
427 }
428 
< prev index next >