< prev index next >

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

Print this page

  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;

 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));

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)) {

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 

  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.NativeScope;


 29 import jdk.internal.foreign.MemoryAddressImpl;
 30 import jdk.internal.foreign.Utils;
 31 
 32 import java.lang.invoke.MethodHandle;
 33 import java.lang.invoke.MethodHandles;
 34 import java.lang.invoke.MethodType;
 35 import java.lang.invoke.VarHandle;
 36 import java.nio.ByteOrder;
 37 import java.util.ArrayList;
 38 import java.util.Arrays;
 39 import java.util.List;
 40 import java.util.Map;
 41 import java.util.concurrent.ConcurrentHashMap;
 42 import java.util.stream.Collectors;
 43 import java.util.stream.IntStream;
 44 
 45 import static java.lang.invoke.MethodHandles.collectArguments;
 46 import static java.lang.invoke.MethodHandles.dropArguments;
 47 import static java.lang.invoke.MethodHandles.empty;
 48 import static java.lang.invoke.MethodHandles.filterArguments;

 52 import static java.lang.invoke.MethodHandles.tryFinally;
 53 import static java.lang.invoke.MethodType.methodType;
 54 import static sun.security.action.GetBooleanAction.privilegedGetProperty;
 55 
 56 /**
 57  * This class implements native call invocation through a so called 'universal adapter'. A universal adapter takes
 58  * an array of longs together with a call 'recipe', which is used to move the arguments in the right places as
 59  * expected by the system ABI.
 60  */
 61 public class ProgrammableInvoker {
 62     private static final boolean DEBUG =
 63         privilegedGetProperty("jdk.internal.foreign.ProgrammableInvoker.DEBUG");
 64     private static final boolean NO_SPEC =
 65         privilegedGetProperty("jdk.internal.foreign.ProgrammableInvoker.NO_SPEC");
 66 
 67     private static final VarHandle VH_LONG = MemoryHandles.varHandle(long.class, ByteOrder.nativeOrder());
 68 
 69     private static final MethodHandle MH_INVOKE_MOVES;
 70     private static final MethodHandle MH_INVOKE_INTERP_BINDINGS;
 71 




 72     private static final MethodHandle MH_MAKE_ALLOCATOR;
 73     private static final MethodHandle MH_CLOSE_ALLOCATOR;

 74 
 75     private static final Map<ABIDescriptor, Long> adapterStubs = new ConcurrentHashMap<>();
 76 
 77     static {
 78         try {
 79             MethodHandles.Lookup lookup = MethodHandles.lookup();
 80             MH_INVOKE_MOVES = lookup.findVirtual(ProgrammableInvoker.class, "invokeMoves",
 81                     methodType(Object.class, Object[].class, Binding.Move[].class, Binding.Move[].class));
 82             MH_INVOKE_INTERP_BINDINGS = lookup.findVirtual(ProgrammableInvoker.class, "invokeInterpBindings",
 83                     methodType(Object.class, Object[].class, MethodHandle.class, Map.class, Map.class));
 84             MH_MAKE_ALLOCATOR = lookup.findStatic(NativeScope.class, "boundedScope",
 85                     methodType(NativeScope.class, long.class));
 86             MH_CLOSE_ALLOCATOR = lookup.findVirtual(NativeScope.class, "close",








 87                     methodType(void.class));


 88         } catch (ReflectiveOperationException e) {
 89             throw new RuntimeException(e);
 90         }
 91     }
 92 
 93     private final ABIDescriptor abi;
 94     private final BufferLayout layout;
 95     private final long stackArgsBytes;
 96 
 97     private final CallingSequence callingSequence;
 98 
 99     private final MemoryAddress addr;
100     private final long stubAddress;
101 
102     private final long bufferCopySize;
103 
104     public ProgrammableInvoker(ABIDescriptor abi, MemoryAddress addr, CallingSequence callingSequence) {
105         this.abi = abi;
106         this.layout = BufferLayout.of(abi);
107         this.stubAddress = adapterStubs.computeIfAbsent(abi, key -> generateAdapter(key, layout));

129                     Binding.Copy c = (Binding.Copy) b;
130                     size = Utils.alignUp(size, c.alignment());
131                     size += c.size();
132                 }
133             }
134         }
135         return size;
136     }
137 
138     public MethodHandle getBoundMethodHandle() {
139         Binding.Move[] argMoves = callingSequence.argMoveBindings().toArray(Binding.Move[]::new);
140         Class<?>[] argMoveTypes = Arrays.stream(argMoves).map(Binding.Move::type).toArray(Class<?>[]::new);
141 
142         Binding.Move[] retMoves = callingSequence.retMoveBindings().toArray(Binding.Move[]::new);
143         Class<?> returnType = retMoves.length == 0
144                 ? void.class
145                 : retMoves.length == 1
146                     ? retMoves[0].type()
147                     : Object[].class;
148 
149         MethodType leafType = methodType(returnType, argMoveTypes);
150 
151         MethodHandle handle = insertArguments(MH_INVOKE_MOVES.bindTo(this), 1, argMoves, retMoves)
152                                             .asCollector(Object[].class, leafType.parameterCount())
153                                             .asType(leafType);
154 
155         if (NO_SPEC || retMoves.length > 1) {
156             Map<VMStorage, Integer> argIndexMap = indexMap(argMoves);
157             Map<VMStorage, Integer> retIndexMap = indexMap(retMoves);
158 
159             handle = insertArguments(MH_INVOKE_INTERP_BINDINGS.bindTo(this), 1, handle, argIndexMap, retIndexMap);
160             handle = handle.asCollector(Object[].class, callingSequence.methodType().parameterCount())
161                                              .asType(callingSequence.methodType());
162          } else {
163              handle = specialize(handle);
164          }
165 
166         return handle;
167     }
168 
169     private MethodHandle specialize(MethodHandle leafHandle) {
170         MethodType highLevelType = callingSequence.methodType();
171         MethodType leafType = leafHandle.type();
172 
173         MethodHandle specializedHandle = leafHandle; // initial
174 
175         int insertPos = -1;
176         if (bufferCopySize > 0) {
177             specializedHandle = dropArguments(specializedHandle, 0, NativeScope.class);
178             insertPos++;
179         }
180         for (int i = 0; i < highLevelType.parameterCount(); i++) {
181             List<Binding> bindings = callingSequence.argumentBindings(i);
182             insertPos += bindings.stream().filter(Binding.Move.class::isInstance).count() + 1;
183             // We interpret the bindings in reverse since we have to construct a MethodHandle from the bottom up
184             for (int j = bindings.size() - 1; j >= 0; j--) {
185                 Binding binding = bindings.get(j);
186                 if (binding.tag() == Binding.Tag.MOVE) {
187                     insertPos--;
188                 } else {
189                     specializedHandle = binding.specializeUnbox(specializedHandle, insertPos);



















190                 }
191             }
192         }
193 
194         if (highLevelType.returnType() != void.class) {
195             MethodHandle returnFilter = identity(highLevelType.returnType());
196             List<Binding> bindings = callingSequence.returnBindings();
197             for (int j = bindings.size() - 1; j >= 0; j--) {
198                 Binding binding = bindings.get(j);
199                 returnFilter = binding.specializeBox(returnFilter);






















200             }
201             specializedHandle = MethodHandles.filterReturnValue(specializedHandle, returnFilter);

202         }
203 
204         if (bufferCopySize > 0) {
205             // insert try-finally to close the NativeScope used for Binding.Copy
206             MethodHandle closer = leafType.returnType() == void.class
207                   // (Throwable, NativeScope) -> void
208                 ? collectArguments(empty(methodType(void.class, Throwable.class)), 1, MH_CLOSE_ALLOCATOR)
209                   // (Throwable, V, NativeScope) -> V
210                 : collectArguments(dropArguments(identity(specializedHandle.type().returnType()), 0, Throwable.class),
211                                    2, MH_CLOSE_ALLOCATOR);
212             specializedHandle = tryFinally(specializedHandle, closer);
213             specializedHandle = collectArguments(specializedHandle, 0, insertArguments(MH_MAKE_ALLOCATOR, 0, bufferCopySize));





















214         }
215         return specializedHandle;
















216     }
217 
218     private Map<VMStorage, Integer> indexMap(Binding.Move[] moves) {
219         return IntStream.range(0, moves.length)
220                         .boxed()
221                         .collect(Collectors.toMap(i -> moves[i].storage(), i -> i));
222     }
223 
224     /**
225      * Does a native invocation by moving primitive values from the arg array into an intermediate buffer
226      * and calling the assembly stub that forwards arguments from the buffer to the target function
227      *
228      * @param args an array of primitive values to be copied in to the buffer
229      * @param argBindings Binding.Move values describing how arguments should be copied
230      * @param returnBindings Binding.Move values describing how return values should be copied
231      * @return null, a single primitive value, or an Object[] of primitive values
232      */
233     Object invokeMoves(Object[] args, Binding.Move[] argBindings, Binding.Move[] returnBindings) {
234         MemorySegment stackArgsSeg = null;
235         try (MemorySegment argBuffer = MemorySegment.allocateNative(layout.size, 64)) {

275                 return SharedUtils.read(argsPtr.addOffset(layout.retOffset(storage)), move.type());
276             } else { // length > 1
277                 Object[] returns = new Object[returnBindings.length];
278                 for (int i = 0; i < returnBindings.length; i++) {
279                     Binding.Move move = returnBindings[i];
280                     VMStorage storage = move.storage();
281                     returns[i] = SharedUtils.read(argsPtr.addOffset(layout.retOffset(storage)), move.type());
282                 }
283                 return returns;
284             }
285         } finally {
286             if (stackArgsSeg != null) {
287                 stackArgsSeg.close();
288             }
289         }
290     }
291 
292     Object invokeInterpBindings(Object[] args, MethodHandle leaf,
293                                 Map<VMStorage, Integer> argIndexMap,
294                                 Map<VMStorage, Integer> retIndexMap) throws Throwable {
295         NativeScope scope = bufferCopySize != 0 ? NativeScope.boundedScope(bufferCopySize) : null;
296         try {
297             // do argument processing, get Object[] as result
298             Object[] moves = new Object[leaf.type().parameterCount()];
299             for (int i = 0; i < args.length; i++) {
300                 Object arg = args[i];
301                 BindingInterpreter.unbox(arg, callingSequence.argumentBindings(i),
302                         (storage, type, value) -> {
303                             moves[argIndexMap.get(storage)] = value;
304                         }, scope);
305             }
306 
307             // call leaf
308             Object o = leaf.invokeWithArguments(moves);
309 
310             // return value processing
311             if (o == null) {
312                 return null;
313             } else if (o instanceof Object[]) {
314                 Object[] oArr = (Object[]) o;
315                 return BindingInterpreter.box(callingSequence.returnBindings(),
316                         (storage, type) -> oArr[retIndexMap.get(storage)]);
317             } else {
318                 return BindingInterpreter.box(callingSequence.returnBindings(), (storage, type) -> o);
319             }
320         } finally {
321             if (scope != null) {
322                 scope.close();
323             }
324         }
325     }
326 
327     //natives
328 
329     static native void invokeNative(long adapterStub, long buff);
330     static native long generateAdapter(ABIDescriptor abi, BufferLayout layout);
331 
332     private static native void registerNatives();
333     static {
334         registerNatives();
335     }
336 }
337 
< prev index next >