< prev index next >

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

Print this page

  8  * particular file as subject to the "Classpath" exception as provided
  9  * by Oracle in the LICENSE file that accompanied this code.
 10  *
 11  * This code is distributed in the hope that it will be useful, but WITHOUT
 12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 14  * version 2 for more details (a copy is included in the LICENSE file that
 15  * accompanied this code).
 16  *
 17  * You should have received a copy of the GNU General Public License version
 18  * 2 along with this work; if not, write to the Free Software Foundation,
 19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 20  *
 21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 22  * or visit www.oracle.com if you need additional information or have any
 23  * questions.
 24  */
 25 package jdk.internal.foreign.abi;
 26 
 27 import jdk.incubator.foreign.Addressable;

 28 import jdk.incubator.foreign.FunctionDescriptor;
 29 import jdk.incubator.foreign.GroupLayout;
 30 import jdk.incubator.foreign.MemoryAccess;
 31 import jdk.incubator.foreign.MemoryAddress;
 32 import jdk.incubator.foreign.MemoryHandles;
 33 import jdk.incubator.foreign.MemoryLayout;
 34 import jdk.incubator.foreign.MemorySegment;

 35 import jdk.incubator.foreign.ResourceScope;
 36 import jdk.incubator.foreign.SegmentAllocator;
 37 import jdk.incubator.foreign.SequenceLayout;
 38 import jdk.incubator.foreign.CLinker;
 39 import jdk.incubator.foreign.ValueLayout;
 40 import jdk.internal.access.JavaLangAccess;

 41 import jdk.internal.access.SharedSecrets;

 42 import jdk.internal.foreign.CABI;
 43 import jdk.internal.foreign.MemoryAddressImpl;

 44 import jdk.internal.foreign.Utils;
 45 import jdk.internal.foreign.abi.aarch64.linux.LinuxAArch64Linker;
 46 import jdk.internal.foreign.abi.aarch64.macos.MacOsAArch64Linker;
 47 import jdk.internal.foreign.abi.x64.sysv.SysVx64Linker;
 48 import jdk.internal.foreign.abi.x64.windows.Windowsx64Linker;

 49 
 50 import java.lang.invoke.MethodHandle;
 51 import java.lang.invoke.MethodHandles;
 52 import java.lang.invoke.MethodType;
 53 import java.lang.invoke.VarHandle;
 54 import java.lang.ref.Reference;
 55 import java.nio.charset.Charset;
 56 import java.nio.charset.StandardCharsets;

 57 import java.util.Arrays;
 58 import java.util.List;
 59 import java.util.Map;
 60 import java.util.Objects;
 61 import java.util.function.Consumer;

 62 import java.util.stream.Collectors;
 63 import java.util.stream.IntStream;
 64 
 65 import static java.lang.invoke.MethodHandles.collectArguments;
 66 import static java.lang.invoke.MethodHandles.constant;
 67 import static java.lang.invoke.MethodHandles.dropArguments;
 68 import static java.lang.invoke.MethodHandles.dropReturn;
 69 import static java.lang.invoke.MethodHandles.empty;
 70 import static java.lang.invoke.MethodHandles.filterArguments;
 71 import static java.lang.invoke.MethodHandles.identity;
 72 import static java.lang.invoke.MethodHandles.insertArguments;
 73 import static java.lang.invoke.MethodHandles.permuteArguments;
 74 import static java.lang.invoke.MethodHandles.tryFinally;
 75 import static java.lang.invoke.MethodType.methodType;
 76 import static jdk.incubator.foreign.CLinker.*;








 77 
 78 public class SharedUtils {
 79 
 80     private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();

 81 
 82     private static final MethodHandle MH_ALLOC_BUFFER;
 83     private static final MethodHandle MH_BASEADDRESS;
 84     private static final MethodHandle MH_BUFFER_COPY;
 85     private static final MethodHandle MH_MAKE_CONTEXT_NO_ALLOCATOR;
 86     private static final MethodHandle MH_MAKE_CONTEXT_BOUNDED_ALLOCATOR;
 87     private static final MethodHandle MH_CLOSE_CONTEXT;
 88     private static final MethodHandle MH_REACHBILITY_FENCE;
 89     private static final MethodHandle MH_HANDLE_UNCAUGHT_EXCEPTION;


 90 
 91     static {
 92         try {
 93             MethodHandles.Lookup lookup = MethodHandles.lookup();
 94             MH_ALLOC_BUFFER = lookup.findVirtual(SegmentAllocator.class, "allocate",
 95                     methodType(MemorySegment.class, MemoryLayout.class));
 96             MH_BASEADDRESS = lookup.findVirtual(MemorySegment.class, "address",
 97                     methodType(MemoryAddress.class));
 98             MH_BUFFER_COPY = lookup.findStatic(SharedUtils.class, "bufferCopy",
 99                     methodType(MemoryAddress.class, MemoryAddress.class, MemorySegment.class));
100             MH_MAKE_CONTEXT_NO_ALLOCATOR = lookup.findStatic(Binding.Context.class, "ofScope",
101                     methodType(Binding.Context.class));
102             MH_MAKE_CONTEXT_BOUNDED_ALLOCATOR = lookup.findStatic(Binding.Context.class, "ofBoundedAllocator",
103                     methodType(Binding.Context.class, long.class));
104             MH_CLOSE_CONTEXT = lookup.findVirtual(Binding.Context.class, "close",
105                     methodType(void.class));
106             MH_REACHBILITY_FENCE = lookup.findStatic(Reference.class, "reachabilityFence",
107                     methodType(void.class, Object.class));
108             MH_HANDLE_UNCAUGHT_EXCEPTION = lookup.findStatic(SharedUtils.class, "handleUncaughtException",
109                     methodType(void.class, Throwable.class));




110         } catch (ReflectiveOperationException e) {
111             throw new BootstrapMethodError(e);
112         }
113     }
114 
115     // this allocator should be used when no allocation is expected
116     public static final SegmentAllocator THROWING_ALLOCATOR = (size, align) -> { throw new IllegalStateException("Cannot get here"); };


117 
118     /**
119      * Align the specified type from a given address
120      * @return The address the data should be at based on alignment requirement
121      */
122     public static long align(MemoryLayout t, boolean isVar, long addr) {
123         return alignUp(addr, alignment(t, isVar));
124     }
125 
126     public static long alignUp(long addr, long alignment) {
127         return ((addr - 1) | (alignment - 1)) + 1;
128     }
129 
130     /**
131      * The alignment requirement for a given type
132      * @param isVar indicate if the type is a standalone variable. This change how
133      * array is aligned. for example.
134      */
135     public static long alignment(MemoryLayout t, boolean isVar) {
136         if (t instanceof ValueLayout) {

208      * @return the adapted handle
209      */
210     public static MethodHandle adaptUpcallForIMR(MethodHandle target, boolean dropReturn) {
211         if (target.type().returnType() != MemorySegment.class)
212             throw new IllegalArgumentException("Must return MemorySegment for IMR");
213 
214         target = collectArguments(MH_BUFFER_COPY, 1, target); // (MemoryAddress, ...) MemoryAddress
215 
216         if (dropReturn) { // no handling for return value, need to drop it
217             target = dropReturn(target);
218         }
219 
220         return target;
221     }
222 
223     private static MemoryAddress bufferCopy(MemoryAddress dest, MemorySegment buffer) {
224         MemoryAddressImpl.ofLongUnchecked(dest.toRawLongValue(), buffer.byteSize()).copyFrom(buffer);
225         return dest;
226     }
227 
228     public static void checkCompatibleType(Class<?> carrier, MemoryLayout layout, long addressSize) {
229         if (carrier.isPrimitive()) {
230             Utils.checkPrimitiveCarrierCompat(carrier, layout);
231         } else if (carrier == MemoryAddress.class) {
232             Utils.checkLayoutType(layout, ValueLayout.class);
233             if (layout.bitSize() != addressSize)
234                 throw new IllegalArgumentException("Address size mismatch: " + addressSize + " != " + layout.bitSize());
235         } else if (carrier == MemorySegment.class) {
236             Utils.checkLayoutType(layout, GroupLayout.class);
237         } else {
238             throw new IllegalArgumentException("Unsupported carrier: " + carrier);
239         }
240     }
241 
242     public static void checkFunctionTypes(MethodType mt, FunctionDescriptor cDesc, long addressSize) {
243         if (mt.returnType() == void.class != cDesc.returnLayout().isEmpty())
244             throw new IllegalArgumentException("Return type mismatch: " + mt + " != " + cDesc);
245         List<MemoryLayout> argLayouts = cDesc.argumentLayouts();
246         if (mt.parameterCount() != argLayouts.size())
247             throw new IllegalArgumentException("Arity mismatch: " + mt + " != " + cDesc);
248 
249         int paramCount = mt.parameterCount();
250         for (int i = 0; i < paramCount; i++) {
251             checkCompatibleType(mt.parameterType(i), argLayouts.get(i), addressSize);
252         }
253         cDesc.returnLayout().ifPresent(rl -> checkCompatibleType(mt.returnType(), rl, addressSize));
254     }
255 
256     public static Class<?> primitiveCarrierForSize(long size, boolean useFloat) {
257         if (useFloat) {
258             if (size == 4) {
259                 return float.class;
260             } else if (size == 8) {
261                 return double.class;
262             }
263         } else {
264             if (size == 1) {
265                 return byte.class;
266             } else if (size == 2) {
267                 return short.class;
268             } else if (size <= 4) {
269                 return int.class;
270             } else if (size <= 8) {
271                 return long.class;
272             }
273         }
274 
275         throw new IllegalArgumentException("No type for size: " + size + " isFloat=" + useFloat);
276     }
277 
278     public static CLinker getSystemLinker() {
279         return switch (CABI.current()) {
280             case Win64 -> Windowsx64Linker.getInstance();
281             case SysV -> SysVx64Linker.getInstance();
282             case LinuxAArch64 -> LinuxAArch64Linker.getInstance();
283             case MacOsAArch64 -> MacOsAArch64Linker.getInstance();
284         };
285     }
286 
287     public static String toJavaStringInternal(MemorySegment segment, long start) {
288         int len = strlen(segment, start);
289         byte[] bytes = new byte[len];
290         MemorySegment.ofArray(bytes)
291                 .copyFrom(segment.asSlice(start, len));
292         return new String(bytes, StandardCharsets.UTF_8);
293     }
294 
295     private static int strlen(MemorySegment segment, long start) {
296         // iterate until overflow (String can only hold a byte[], whose length can be expressed as an int)
297         for (int offset = 0; offset >= 0; offset++) {
298             byte curr = MemoryAccess.getByteAtOffset(segment, start + offset);
299             if (curr == 0) {
300                 return offset;
301             }
302         }
303         throw new IllegalArgumentException("String too large");
304     }
305 
306     static long bufferCopySize(CallingSequence callingSequence) {
307         // FIXME: > 16 bytes alignment might need extra space since the
308         // starting address of the allocator might be un-aligned.
309         long size = 0;
310         for (int i = 0; i < callingSequence.argumentCount(); i++) {
311             List<Binding> bindings = callingSequence.argumentBindings(i);
312             for (Binding b : bindings) {
313                 if (b instanceof Binding.Copy) {
314                     Binding.Copy c = (Binding.Copy) b;
315                     size = Utils.alignUp(size, c.alignment());
316                     size += c.size();
317                 } else if (b instanceof Binding.Allocate) {
318                     Binding.Allocate c = (Binding.Allocate) b;

375             t.printStackTrace();
376             JLA.exit(1);
377         }
378     }
379 
380     static MethodHandle wrapWithAllocator(MethodHandle specializedHandle,
381                                           int allocatorPos, long bufferCopySize,
382                                           boolean upcall) {
383         // insert try-finally to close the NativeScope used for Binding.Copy
384         MethodHandle closer;
385         int insertPos;
386         if (specializedHandle.type().returnType() == void.class) {
387             if (!upcall) {
388                 closer = empty(methodType(void.class, Throwable.class)); // (Throwable) -> void
389             } else {
390                 closer = MH_HANDLE_UNCAUGHT_EXCEPTION;
391             }
392             insertPos = 1;
393         } else {
394             closer = identity(specializedHandle.type().returnType()); // (V) -> V
395             closer = dropArguments(closer, 0, Throwable.class); // (Throwable, V) -> V




396             insertPos = 2;
397         }
398 
399         // downcalls get the leading Addressable/SegmentAllocator param as well
400         if (!upcall) {
401             closer = collectArguments(closer, insertPos++, reachabilityFenceHandle(Addressable.class));
402             closer = dropArguments(closer, insertPos++, SegmentAllocator.class); // (Throwable, V?, Addressable, SegmentAllocator) -> V/void
403         }
404 
405         closer = collectArguments(closer, insertPos++, MH_CLOSE_CONTEXT); // (Throwable, V?, Addressable?, BindingContext) -> V/void
406 
407         if (!upcall) {
408             // now for each Addressable parameter, add a reachability fence
409             MethodType specType = specializedHandle.type();
410             // skip 3 for address, segment allocator, and binding context
411             for (int i = 3; i < specType.parameterCount(); i++) {
412                 Class<?> param = specType.parameterType(i);
413                 if (Addressable.class.isAssignableFrom(param)) {
414                     closer = collectArguments(closer, insertPos++, reachabilityFenceHandle(param));
415                 } else {
416                     closer = dropArguments(closer, insertPos++, param);
417                 }
418             }
419         }
420 
421         MethodHandle contextFactory;
422 
423         if (bufferCopySize > 0) {
424             contextFactory = MethodHandles.insertArguments(MH_MAKE_CONTEXT_BOUNDED_ALLOCATOR, 0, bufferCopySize);
425         } else if (upcall) {
426             contextFactory = MH_MAKE_CONTEXT_NO_ALLOCATOR;
427         } else {
428             // this path is probably never used now, since ProgrammableInvoker never calls this routine with bufferCopySize == 0
429             contextFactory = constant(Binding.Context.class, Binding.Context.DUMMY);
430         }
431 
432         specializedHandle = tryFinally(specializedHandle, closer);
433         specializedHandle = collectArguments(specializedHandle, allocatorPos, contextFactory);
434         return specializedHandle;
435     }
436 













































































































































437     // lazy init MH_ALLOC and MH_FREE handles
438     private static class AllocHolder {
439 
440         private static final CLinker SYS_LINKER = getSystemLinker();
441 
442         static final MethodHandle MH_MALLOC = SYS_LINKER.downcallHandle(CLinker.systemLookup().lookup("malloc").get(),
443                         MethodType.methodType(MemoryAddress.class, long.class),
444                 FunctionDescriptor.of(C_POINTER, C_LONG_LONG));
445 
446         static final MethodHandle MH_FREE = SYS_LINKER.downcallHandle(CLinker.systemLookup().lookup("free").get(),
447                         MethodType.methodType(void.class, MemoryAddress.class),
448                 FunctionDescriptor.ofVoid(C_POINTER));
449     }
450 
451     public static MemoryAddress checkSymbol(Addressable symbol) {
452         return checkAddressable(symbol, "Symbol is NULL");
453     }
454 
455     public static MemoryAddress checkAddress(MemoryAddress address) {
456         return checkAddressable(address, "Address is NULL");
457     }
458 
459     private static MemoryAddress checkAddressable(Addressable symbol, String msg) {
460         Objects.requireNonNull(symbol);
461         MemoryAddress symbolAddr = symbol.address();
462         if (symbolAddr.equals(MemoryAddress.NULL))
463             throw new IllegalArgumentException("Symbol is NULL: " + symbolAddr);
464         return symbolAddr;
465     }
466 
467     public static MemoryAddress allocateMemoryInternal(long size) {
468         try {
469             return (MemoryAddress) AllocHolder.MH_MALLOC.invokeExact(size);
470         } catch (Throwable th) {
471             throw new RuntimeException(th);
472         }
473     }
474 
475     public static void freeMemoryInternal(MemoryAddress addr) {
476         try {
477             AllocHolder.MH_FREE.invokeExact(addr);
478         } catch (Throwable th) {
479             throw new RuntimeException(th);
480         }
481     }
482 
483     public static VaList newVaList(Consumer<VaList.Builder> actions, ResourceScope scope) {
484         return switch (CABI.current()) {
485             case Win64 -> Windowsx64Linker.newVaList(actions, scope);
486             case SysV -> SysVx64Linker.newVaList(actions, scope);
487             case LinuxAArch64 -> LinuxAArch64Linker.newVaList(actions, scope);
488             case MacOsAArch64 -> MacOsAArch64Linker.newVaList(actions, scope);
489         };
490     }
491 
492     public static VarHandle vhPrimitiveOrAddress(Class<?> carrier, MemoryLayout layout) {
493         return carrier == MemoryAddress.class
494             ? MemoryHandles.asAddressVarHandle(layout.varHandle(primitiveCarrierForSize(layout.byteSize(), false)))
495             : layout.varHandle(carrier);
496     }
497 
498     public static VaList newVaListOfAddress(MemoryAddress ma, ResourceScope scope) {
499         return switch (CABI.current()) {
500             case Win64 -> Windowsx64Linker.newVaListOfAddress(ma, scope);
501             case SysV -> SysVx64Linker.newVaListOfAddress(ma, scope);
502             case LinuxAArch64 -> LinuxAArch64Linker.newVaListOfAddress(ma, scope);
503             case MacOsAArch64 -> MacOsAArch64Linker.newVaListOfAddress(ma, scope);
504         };
505     }
506 
507     public static VaList emptyVaList() {
508         return switch (CABI.current()) {
509             case Win64 -> Windowsx64Linker.emptyVaList();
510             case SysV -> SysVx64Linker.emptyVaList();
511             case LinuxAArch64 -> LinuxAArch64Linker.emptyVaList();
512             case MacOsAArch64 -> MacOsAArch64Linker.emptyVaList();
513         };
514     }
515 
516     public static MethodType convertVaListCarriers(MethodType mt, Class<?> carrier) {
517         Class<?>[] params = new Class<?>[mt.parameterCount()];
518         for (int i = 0; i < params.length; i++) {
519             Class<?> pType = mt.parameterType(i);
520             params[i] = ((pType == VaList.class) ? carrier : pType);
521         }
522         return methodType(mt.returnType(), params);
523     }
524 
525     public static MethodHandle unboxVaLists(MethodType type, MethodHandle handle, MethodHandle unboxer) {
526         for (int i = 0; i < type.parameterCount(); i++) {
527             if (type.parameterType(i) == VaList.class) {
528                handle = filterArguments(handle, i + 1, unboxer); // +1 for leading address
529             }
530         }
531         return handle;
532     }
533 
534     public static MethodHandle boxVaLists(MethodHandle handle, MethodHandle boxer) {
535         MethodType type = handle.type();
536         for (int i = 0; i < type.parameterCount(); i++) {
537             if (type.parameterType(i) == VaList.class) {
538                handle = filterArguments(handle, i, boxer);
539             }
540         }
541         return handle;
542     }
543 
544     static void checkType(Class<?> actualType, Class<?> expectedType) {
545         if (expectedType != actualType) {
546             throw new IllegalArgumentException(
547                     String.format("Invalid operand type: %s. %s expected", actualType, expectedType));
548         }
549     }
550 
551     public static boolean isTrivial(FunctionDescriptor cDesc) {
552         return cDesc.attribute(FunctionDescriptor.TRIVIAL_ATTRIBUTE_NAME)
553                 .map(Boolean.class::cast)
554                 .orElse(false);



555     }
556 
557     public static class SimpleVaArg {
558         public final Class<?> carrier;
559         public final MemoryLayout layout;
560         public final Object value;
561 
562         public SimpleVaArg(Class<?> carrier, MemoryLayout layout, Object value) {
563             this.carrier = carrier;
564             this.layout = layout;
565             this.value = value;
566         }
567 
568         public VarHandle varHandle() {
569             return carrier == MemoryAddress.class
570                 ? MemoryHandles.asAddressVarHandle(layout.varHandle(primitiveCarrierForSize(layout.byteSize(), false)))
571                 : layout.varHandle(carrier);
572         }
573     }
574 
575     public static non-sealed class EmptyVaList implements VaList {
576 
577         private final MemoryAddress address;
578 
579         public EmptyVaList(MemoryAddress address) {
580             this.address = address;
581         }
582 
583         private static UnsupportedOperationException uoe() {
584             return new UnsupportedOperationException("Empty VaList");
585         }
586 
587         @Override
588         public int vargAsInt(MemoryLayout layout) {
589             throw uoe();
590         }
591 
592         @Override
593         public long vargAsLong(MemoryLayout layout) {
594             throw uoe();
595         }
596 
597         @Override
598         public double vargAsDouble(MemoryLayout layout) {
599             throw uoe();
600         }
601 
602         @Override
603         public MemoryAddress vargAsAddress(MemoryLayout layout) {
604             throw uoe();
605         }
606 
607         @Override
608         public MemorySegment vargAsSegment(MemoryLayout layout, SegmentAllocator allocator) {
609             throw uoe();
610         }
611 
612         @Override
613         public MemorySegment vargAsSegment(MemoryLayout layout, ResourceScope scope) {
614             throw uoe();
615         }
616 
617         @Override
618         public void skip(MemoryLayout... layouts) {
619             throw uoe();
620         }
621 
622         @Override
623         public ResourceScope scope() {
624             return ResourceScope.globalScope();
625         }
626 
627         @Override
628         public VaList copy() {
629             return this;
630         }
631 
632         @Override
633         public MemoryAddress address() {
634             return address;
635         }
636     }
637 
638     static void writeOverSized(MemorySegment ptr, Class<?> type, Object o) {
639         // use VH_LONG for integers to zero out the whole register in the process
640         if (type == long.class) {
641             MemoryAccess.setLong(ptr, (long) o);
642         } else if (type == int.class) {
643             MemoryAccess.setLong(ptr, (int) o);
644         } else if (type == short.class) {
645             MemoryAccess.setLong(ptr, (short) o);
646         } else if (type == char.class) {
647             MemoryAccess.setLong(ptr, (char) o);
648         } else if (type == byte.class) {
649             MemoryAccess.setLong(ptr, (byte) o);
650         } else if (type == float.class) {
651             MemoryAccess.setFloat(ptr, (float) o);
652         } else if (type == double.class) {
653             MemoryAccess.setDouble(ptr, (double) o);


654         } else {
655             throw new IllegalArgumentException("Unsupported carrier: " + type);
656         }
657     }
658 
659     static void write(MemorySegment ptr, Class<?> type, Object o) {
660         if (type == long.class) {
661             MemoryAccess.setLong(ptr, (long) o);
662         } else if (type == int.class) {
663             MemoryAccess.setInt(ptr, (int) o);
664         } else if (type == short.class) {
665             MemoryAccess.setShort(ptr, (short) o);
666         } else if (type == char.class) {
667             MemoryAccess.setChar(ptr, (char) o);
668         } else if (type == byte.class) {
669             MemoryAccess.setByte(ptr, (byte) o);
670         } else if (type == float.class) {
671             MemoryAccess.setFloat(ptr, (float) o);
672         } else if (type == double.class) {
673             MemoryAccess.setDouble(ptr, (double) o);


674         } else {
675             throw new IllegalArgumentException("Unsupported carrier: " + type);
676         }
677     }
678 
679     static Object read(MemorySegment ptr, Class<?> type) {
680         if (type == long.class) {
681             return MemoryAccess.getLong(ptr);
682         } else if (type == int.class) {
683             return MemoryAccess.getInt(ptr);
684         } else if (type == short.class) {
685             return MemoryAccess.getShort(ptr);
686         } else if (type == char.class) {
687             return MemoryAccess.getChar(ptr);
688         } else if (type == byte.class) {
689             return MemoryAccess.getByte(ptr);
690         } else if (type == float.class) {
691             return MemoryAccess.getFloat(ptr);
692         } else if (type == double.class) {
693             return MemoryAccess.getDouble(ptr);


694         } else {
695             throw new IllegalArgumentException("Unsupported carrier: " + type);
696         }
697     }




















698 }

  8  * particular file as subject to the "Classpath" exception as provided
  9  * by Oracle in the LICENSE file that accompanied this code.
 10  *
 11  * This code is distributed in the hope that it will be useful, but WITHOUT
 12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 14  * version 2 for more details (a copy is included in the LICENSE file that
 15  * accompanied this code).
 16  *
 17  * You should have received a copy of the GNU General Public License version
 18  * 2 along with this work; if not, write to the Free Software Foundation,
 19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 20  *
 21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 22  * or visit www.oracle.com if you need additional information or have any
 23  * questions.
 24  */
 25 package jdk.internal.foreign.abi;
 26 
 27 import jdk.incubator.foreign.Addressable;
 28 import jdk.incubator.foreign.CLinker;
 29 import jdk.incubator.foreign.FunctionDescriptor;
 30 import jdk.incubator.foreign.GroupLayout;

 31 import jdk.incubator.foreign.MemoryAddress;

 32 import jdk.incubator.foreign.MemoryLayout;
 33 import jdk.incubator.foreign.MemorySegment;
 34 import jdk.incubator.foreign.NativeSymbol;
 35 import jdk.incubator.foreign.ResourceScope;
 36 import jdk.incubator.foreign.SegmentAllocator;
 37 import jdk.incubator.foreign.SequenceLayout;
 38 import jdk.incubator.foreign.VaList;
 39 import jdk.incubator.foreign.ValueLayout;
 40 import jdk.internal.access.JavaLangAccess;
 41 import jdk.internal.access.JavaLangInvokeAccess;
 42 import jdk.internal.access.SharedSecrets;
 43 import jdk.internal.foreign.Scoped;
 44 import jdk.internal.foreign.CABI;
 45 import jdk.internal.foreign.MemoryAddressImpl;
 46 import jdk.internal.foreign.ResourceScopeImpl;
 47 import jdk.internal.foreign.Utils;
 48 import jdk.internal.foreign.abi.aarch64.linux.LinuxAArch64Linker;
 49 import jdk.internal.foreign.abi.aarch64.macos.MacOsAArch64Linker;
 50 import jdk.internal.foreign.abi.x64.sysv.SysVx64Linker;
 51 import jdk.internal.foreign.abi.x64.windows.Windowsx64Linker;
 52 import jdk.internal.vm.annotation.ForceInline;
 53 
 54 import java.lang.invoke.MethodHandle;
 55 import java.lang.invoke.MethodHandles;
 56 import java.lang.invoke.MethodType;
 57 import java.lang.invoke.VarHandle;
 58 import java.lang.ref.Reference;

 59 import java.nio.charset.StandardCharsets;
 60 import java.util.ArrayList;
 61 import java.util.Arrays;
 62 import java.util.List;
 63 import java.util.Map;
 64 import java.util.Objects;
 65 import java.util.function.Consumer;
 66 import java.util.function.UnaryOperator;
 67 import java.util.stream.Collectors;
 68 import java.util.stream.IntStream;
 69 
 70 import static java.lang.invoke.MethodHandles.collectArguments;
 71 import static java.lang.invoke.MethodHandles.constant;
 72 import static java.lang.invoke.MethodHandles.dropArguments;
 73 import static java.lang.invoke.MethodHandles.dropReturn;
 74 import static java.lang.invoke.MethodHandles.empty;
 75 import static java.lang.invoke.MethodHandles.foldArguments;
 76 import static java.lang.invoke.MethodHandles.identity;
 77 import static java.lang.invoke.MethodHandles.insertArguments;
 78 import static java.lang.invoke.MethodHandles.permuteArguments;
 79 import static java.lang.invoke.MethodHandles.tryFinally;
 80 import static java.lang.invoke.MethodType.methodType;
 81 import static jdk.incubator.foreign.ValueLayout.ADDRESS;
 82 import static jdk.incubator.foreign.ValueLayout.JAVA_BOOLEAN;
 83 import static jdk.incubator.foreign.ValueLayout.JAVA_BYTE;
 84 import static jdk.incubator.foreign.ValueLayout.JAVA_CHAR;
 85 import static jdk.incubator.foreign.ValueLayout.JAVA_DOUBLE;
 86 import static jdk.incubator.foreign.ValueLayout.JAVA_FLOAT;
 87 import static jdk.incubator.foreign.ValueLayout.JAVA_INT;
 88 import static jdk.incubator.foreign.ValueLayout.JAVA_LONG;
 89 import static jdk.incubator.foreign.ValueLayout.JAVA_SHORT;
 90 
 91 public class SharedUtils {
 92 
 93     private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
 94     private static final JavaLangInvokeAccess JLIA = SharedSecrets.getJavaLangInvokeAccess();
 95 
 96     private static final MethodHandle MH_ALLOC_BUFFER;
 97     private static final MethodHandle MH_BASEADDRESS;
 98     private static final MethodHandle MH_BUFFER_COPY;
 99     private static final MethodHandle MH_MAKE_CONTEXT_NO_ALLOCATOR;
100     private static final MethodHandle MH_MAKE_CONTEXT_BOUNDED_ALLOCATOR;
101     private static final MethodHandle MH_CLOSE_CONTEXT;
102     private static final MethodHandle MH_REACHBILITY_FENCE;
103     private static final MethodHandle MH_HANDLE_UNCAUGHT_EXCEPTION;
104     private static final MethodHandle ACQUIRE_MH;
105     private static final MethodHandle RELEASE_MH;
106 
107     static {
108         try {
109             MethodHandles.Lookup lookup = MethodHandles.lookup();
110             MH_ALLOC_BUFFER = lookup.findVirtual(SegmentAllocator.class, "allocate",
111                     methodType(MemorySegment.class, MemoryLayout.class));
112             MH_BASEADDRESS = lookup.findVirtual(MemorySegment.class, "address",
113                     methodType(MemoryAddress.class));
114             MH_BUFFER_COPY = lookup.findStatic(SharedUtils.class, "bufferCopy",
115                     methodType(MemoryAddress.class, MemoryAddress.class, MemorySegment.class));
116             MH_MAKE_CONTEXT_NO_ALLOCATOR = lookup.findStatic(Binding.Context.class, "ofScope",
117                     methodType(Binding.Context.class));
118             MH_MAKE_CONTEXT_BOUNDED_ALLOCATOR = lookup.findStatic(Binding.Context.class, "ofBoundedAllocator",
119                     methodType(Binding.Context.class, long.class));
120             MH_CLOSE_CONTEXT = lookup.findVirtual(Binding.Context.class, "close",
121                     methodType(void.class));
122             MH_REACHBILITY_FENCE = lookup.findStatic(Reference.class, "reachabilityFence",
123                     methodType(void.class, Object.class));
124             MH_HANDLE_UNCAUGHT_EXCEPTION = lookup.findStatic(SharedUtils.class, "handleUncaughtException",
125                     methodType(void.class, Throwable.class));
126             ACQUIRE_MH = MethodHandles.lookup().findStatic(SharedUtils.class, "acquire",
127                     MethodType.methodType(void.class, Scoped[].class));
128             RELEASE_MH = MethodHandles.lookup().findStatic(SharedUtils.class, "release",
129                     MethodType.methodType(void.class, Scoped[].class));
130         } catch (ReflectiveOperationException e) {
131             throw new BootstrapMethodError(e);
132         }
133     }
134 
135     // this allocator should be used when no allocation is expected
136     public static final SegmentAllocator THROWING_ALLOCATOR = (size, align) -> {
137         throw new IllegalStateException("Cannot get here");
138     };
139 
140     /**
141      * Align the specified type from a given address
142      * @return The address the data should be at based on alignment requirement
143      */
144     public static long align(MemoryLayout t, boolean isVar, long addr) {
145         return alignUp(addr, alignment(t, isVar));
146     }
147 
148     public static long alignUp(long addr, long alignment) {
149         return ((addr - 1) | (alignment - 1)) + 1;
150     }
151 
152     /**
153      * The alignment requirement for a given type
154      * @param isVar indicate if the type is a standalone variable. This change how
155      * array is aligned. for example.
156      */
157     public static long alignment(MemoryLayout t, boolean isVar) {
158         if (t instanceof ValueLayout) {

230      * @return the adapted handle
231      */
232     public static MethodHandle adaptUpcallForIMR(MethodHandle target, boolean dropReturn) {
233         if (target.type().returnType() != MemorySegment.class)
234             throw new IllegalArgumentException("Must return MemorySegment for IMR");
235 
236         target = collectArguments(MH_BUFFER_COPY, 1, target); // (MemoryAddress, ...) MemoryAddress
237 
238         if (dropReturn) { // no handling for return value, need to drop it
239             target = dropReturn(target);
240         }
241 
242         return target;
243     }
244 
245     private static MemoryAddress bufferCopy(MemoryAddress dest, MemorySegment buffer) {
246         MemoryAddressImpl.ofLongUnchecked(dest.toRawLongValue(), buffer.byteSize()).copyFrom(buffer);
247         return dest;
248     }
249 




























250     public static Class<?> primitiveCarrierForSize(long size, boolean useFloat) {
251         if (useFloat) {
252             if (size == 4) {
253                 return float.class;
254             } else if (size == 8) {
255                 return double.class;
256             }
257         } else {
258             if (size == 1) {
259                 return byte.class;
260             } else if (size == 2) {
261                 return short.class;
262             } else if (size <= 4) {
263                 return int.class;
264             } else if (size <= 8) {
265                 return long.class;
266             }
267         }
268 
269         throw new IllegalArgumentException("No type for size: " + size + " isFloat=" + useFloat);
270     }
271 
272     public static CLinker getSystemLinker() {
273         return switch (CABI.current()) {
274             case Win64 -> Windowsx64Linker.getInstance();
275             case SysV -> SysVx64Linker.getInstance();
276             case LinuxAArch64 -> LinuxAArch64Linker.getInstance();
277             case MacOsAArch64 -> MacOsAArch64Linker.getInstance();
278         };
279     }
280 
281     public static String toJavaStringInternal(MemorySegment segment, long start) {
282         int len = strlen(segment, start);
283         byte[] bytes = new byte[len];
284         MemorySegment.copy(segment, JAVA_BYTE, start, bytes, 0, len);

285         return new String(bytes, StandardCharsets.UTF_8);
286     }
287 
288     private static int strlen(MemorySegment segment, long start) {
289         // iterate until overflow (String can only hold a byte[], whose length can be expressed as an int)
290         for (int offset = 0; offset >= 0; offset++) {
291             byte curr = segment.get(JAVA_BYTE, start + offset);
292             if (curr == 0) {
293                 return offset;
294             }
295         }
296         throw new IllegalArgumentException("String too large");
297     }
298 
299     static long bufferCopySize(CallingSequence callingSequence) {
300         // FIXME: > 16 bytes alignment might need extra space since the
301         // starting address of the allocator might be un-aligned.
302         long size = 0;
303         for (int i = 0; i < callingSequence.argumentCount(); i++) {
304             List<Binding> bindings = callingSequence.argumentBindings(i);
305             for (Binding b : bindings) {
306                 if (b instanceof Binding.Copy) {
307                     Binding.Copy c = (Binding.Copy) b;
308                     size = Utils.alignUp(size, c.alignment());
309                     size += c.size();
310                 } else if (b instanceof Binding.Allocate) {
311                     Binding.Allocate c = (Binding.Allocate) b;

368             t.printStackTrace();
369             JLA.exit(1);
370         }
371     }
372 
373     static MethodHandle wrapWithAllocator(MethodHandle specializedHandle,
374                                           int allocatorPos, long bufferCopySize,
375                                           boolean upcall) {
376         // insert try-finally to close the NativeScope used for Binding.Copy
377         MethodHandle closer;
378         int insertPos;
379         if (specializedHandle.type().returnType() == void.class) {
380             if (!upcall) {
381                 closer = empty(methodType(void.class, Throwable.class)); // (Throwable) -> void
382             } else {
383                 closer = MH_HANDLE_UNCAUGHT_EXCEPTION;
384             }
385             insertPos = 1;
386         } else {
387             closer = identity(specializedHandle.type().returnType()); // (V) -> V
388             if (!upcall) {
389                 closer = dropArguments(closer, 0, Throwable.class); // (Throwable, V) -> V
390             } else {
391                 closer = collectArguments(closer, 0, MH_HANDLE_UNCAUGHT_EXCEPTION); // (Throwable, V) -> V
392             }
393             insertPos = 2;
394         }
395 
396         // downcalls get the leading NativeSymbol/SegmentAllocator param as well
397         if (!upcall) {
398             closer = collectArguments(closer, insertPos++, reachabilityFenceHandle(NativeSymbol.class));
399             closer = dropArguments(closer, insertPos++, SegmentAllocator.class); // (Throwable, V?, NativeSymbol, SegmentAllocator) -> V/void
400         }
401 
402         closer = collectArguments(closer, insertPos++, MH_CLOSE_CONTEXT); // (Throwable, V?, NativeSymbol?, BindingContext) -> V/void














403 
404         MethodHandle contextFactory;
405 
406         if (bufferCopySize > 0) {
407             contextFactory = MethodHandles.insertArguments(MH_MAKE_CONTEXT_BOUNDED_ALLOCATOR, 0, bufferCopySize);
408         } else if (upcall) {
409             contextFactory = MH_MAKE_CONTEXT_NO_ALLOCATOR;
410         } else {
411             // this path is probably never used now, since ProgrammableInvoker never calls this routine with bufferCopySize == 0
412             contextFactory = constant(Binding.Context.class, Binding.Context.DUMMY);
413         }
414 
415         specializedHandle = tryFinally(specializedHandle, closer);
416         specializedHandle = collectArguments(specializedHandle, allocatorPos, contextFactory);
417         return specializedHandle;
418     }
419 
420     @ForceInline
421     @SuppressWarnings("fallthrough")
422     public static void acquire(Scoped[] args) {
423         ResourceScope scope4 = null;
424         ResourceScope scope3 = null;
425         ResourceScope scope2 = null;
426         ResourceScope scope1 = null;
427         ResourceScope scope0 = null;
428         switch (args.length) {
429             default:
430                 // slow path, acquire all remaining addressable parameters in isolation
431                 for (int i = 5 ; i < args.length ; i++) {
432                     acquire(args[i].scope());
433                 }
434             // fast path, acquire only scopes not seen in other parameters
435             case 5:
436                 scope4 = args[4].scope();
437                 acquire(scope4);
438             case 4:
439                 scope3 = args[3].scope();
440                 if (scope3 != scope4)
441                     acquire(scope3);
442             case 3:
443                 scope2 = args[2].scope();
444                 if (scope2 != scope3 && scope2 != scope4)
445                     acquire(scope2);
446             case 2:
447                 scope1 = args[1].scope();
448                 if (scope1 != scope2 && scope1 != scope3 && scope1 != scope4)
449                     acquire(scope1);
450             case 1:
451                 scope0 = args[0].scope();
452                 if (scope0 != scope1 && scope0 != scope2 && scope0 != scope3 && scope0 != scope4)
453                     acquire(scope0);
454             case 0: break;
455         }
456     }
457 
458     @ForceInline
459     @SuppressWarnings("fallthrough")
460     public static void release(Scoped[] args) {
461         ResourceScope scope4 = null;
462         ResourceScope scope3 = null;
463         ResourceScope scope2 = null;
464         ResourceScope scope1 = null;
465         ResourceScope scope0 = null;
466         switch (args.length) {
467             default:
468                 // slow path, release all remaining addressable parameters in isolation
469                 for (int i = 5 ; i < args.length ; i++) {
470                     release(args[i].scope());
471                 }
472             // fast path, release only scopes not seen in other parameters
473             case 5:
474                 scope4 = args[4].scope();
475                 release(scope4);
476             case 4:
477                 scope3 = args[3].scope();
478                 if (scope3 != scope4)
479                     release(scope3);
480             case 3:
481                 scope2 = args[2].scope();
482                 if (scope2 != scope3 && scope2 != scope4)
483                     release(scope2);
484             case 2:
485                 scope1 = args[1].scope();
486                 if (scope1 != scope2 && scope1 != scope3 && scope1 != scope4)
487                     release(scope1);
488             case 1:
489                 scope0 = args[0].scope();
490                 if (scope0 != scope1 && scope0 != scope2 && scope0 != scope3 && scope0 != scope4)
491                     release(scope0);
492             case 0: break;
493         }
494     }
495 
496     @ForceInline
497     private static void acquire(ResourceScope scope) {
498         ((ResourceScopeImpl)scope).acquire0();
499     }
500 
501     @ForceInline
502     private static void release(ResourceScope scope) {
503         ((ResourceScopeImpl)scope).release0();
504     }
505 
506     /*
507      * This method adds a try/finally block to a downcall method handle, to make sure that all by-reference
508      * parameters (including the target address of the native function) are kept alive for the duration of
509      * the downcall.
510      */
511     public static MethodHandle wrapDowncall(MethodHandle downcallHandle, FunctionDescriptor descriptor) {
512         boolean hasReturn = descriptor.returnLayout().isPresent();
513         MethodHandle tryBlock = downcallHandle;
514         MethodHandle cleanup = hasReturn ?
515                 MethodHandles.identity(downcallHandle.type().returnType()) :
516                 MethodHandles.empty(MethodType.methodType(void.class));
517         int addressableCount = 0;
518         List<UnaryOperator<MethodHandle>> adapters = new ArrayList<>();
519         for (int i = 0 ; i < downcallHandle.type().parameterCount() ; i++) {
520             Class<?> ptype = downcallHandle.type().parameterType(i);
521             if (ptype == Addressable.class || ptype == NativeSymbol.class) {
522                 addressableCount++;
523             } else {
524                 int pos = i;
525                 adapters.add(mh -> dropArguments(mh, pos, ptype));
526             }
527         }
528 
529         if (addressableCount > 0) {
530             cleanup = dropArguments(cleanup, 0, Throwable.class);
531 
532             MethodType adapterType = MethodType.methodType(void.class);
533             for (int i = 0 ; i < addressableCount ; i++) {
534                 adapterType = adapterType.appendParameterTypes(i == 0 ? NativeSymbol.class : Addressable.class);
535             }
536 
537             MethodHandle acquireHandle = ACQUIRE_MH.asCollector(Scoped[].class, addressableCount).asType(adapterType);
538             MethodHandle releaseHandle = RELEASE_MH.asCollector(Scoped[].class, addressableCount).asType(adapterType);
539 
540             for (UnaryOperator<MethodHandle> adapter : adapters) {
541                 acquireHandle = adapter.apply(acquireHandle);
542                 releaseHandle = adapter.apply(releaseHandle);
543             }
544 
545             tryBlock = foldArguments(tryBlock, acquireHandle);
546             cleanup = collectArguments(cleanup, hasReturn ? 2 : 1, releaseHandle);
547 
548             return tryFinally(tryBlock, cleanup);
549         } else {
550             return downcallHandle;
551         }
552     }
553 
554     public static void checkExceptions(MethodHandle target) {
555         Class<?>[] exceptions = JLIA.exceptionTypes(target);
556         if (exceptions != null && exceptions.length != 0) {
557             throw new IllegalArgumentException("Target handle may throw exceptions: " + Arrays.toString(exceptions));
558         }
559     }
560 
561     // lazy init MH_ALLOC and MH_FREE handles
562     private static class AllocHolder {
563 
564         private static final CLinker SYS_LINKER = getSystemLinker();
565 
566         static final MethodHandle MH_MALLOC = SYS_LINKER.downcallHandle(CLinker.systemCLinker().lookup("malloc").get(),
567                 FunctionDescriptor.of(ADDRESS, JAVA_LONG));

568 
569         static final MethodHandle MH_FREE = SYS_LINKER.downcallHandle(CLinker.systemCLinker().lookup("free").get(),
570                 FunctionDescriptor.ofVoid(ADDRESS));

571     }
572 
573     public static void checkSymbol(NativeSymbol symbol) {
574         checkAddressable(symbol, "Symbol is NULL");
575     }
576 
577     public static void checkAddress(MemoryAddress address) {
578         checkAddressable(address, "Address is NULL");
579     }
580 
581     private static void checkAddressable(Addressable symbol, String msg) {
582         Objects.requireNonNull(symbol);
583         if (symbol.address().toRawLongValue() == 0)
584             throw new IllegalArgumentException("Symbol is NULL: " + symbol);


585     }
586 
587     public static MemoryAddress allocateMemoryInternal(long size) {
588         try {
589             return (MemoryAddress) AllocHolder.MH_MALLOC.invokeExact(size);
590         } catch (Throwable th) {
591             throw new RuntimeException(th);
592         }
593     }
594 
595     public static void freeMemoryInternal(MemoryAddress addr) {
596         try {
597             AllocHolder.MH_FREE.invokeExact((Addressable)addr);
598         } catch (Throwable th) {
599             throw new RuntimeException(th);
600         }
601     }
602 
603     public static VaList newVaList(Consumer<VaList.Builder> actions, ResourceScope scope) {
604         return switch (CABI.current()) {
605             case Win64 -> Windowsx64Linker.newVaList(actions, scope);
606             case SysV -> SysVx64Linker.newVaList(actions, scope);
607             case LinuxAArch64 -> LinuxAArch64Linker.newVaList(actions, scope);
608             case MacOsAArch64 -> MacOsAArch64Linker.newVaList(actions, scope);
609         };
610     }
611 






612     public static VaList newVaListOfAddress(MemoryAddress ma, ResourceScope scope) {
613         return switch (CABI.current()) {
614             case Win64 -> Windowsx64Linker.newVaListOfAddress(ma, scope);
615             case SysV -> SysVx64Linker.newVaListOfAddress(ma, scope);
616             case LinuxAArch64 -> LinuxAArch64Linker.newVaListOfAddress(ma, scope);
617             case MacOsAArch64 -> MacOsAArch64Linker.newVaListOfAddress(ma, scope);
618         };
619     }
620 
621     public static VaList emptyVaList() {
622         return switch (CABI.current()) {
623             case Win64 -> Windowsx64Linker.emptyVaList();
624             case SysV -> SysVx64Linker.emptyVaList();
625             case LinuxAArch64 -> LinuxAArch64Linker.emptyVaList();
626             case MacOsAArch64 -> MacOsAArch64Linker.emptyVaList();
627         };
628     }
629 




























630     static void checkType(Class<?> actualType, Class<?> expectedType) {
631         if (expectedType != actualType) {
632             throw new IllegalArgumentException(
633                     String.format("Invalid operand type: %s. %s expected", actualType, expectedType));
634         }
635     }
636 
637     public static boolean isTrivial(FunctionDescriptor cDesc) {
638         return false; // FIXME: use system property?
639     }
640 
641     public static boolean isVarargsIndex(FunctionDescriptor descriptor, int argIndex) {
642         int firstPos = descriptor.firstVariadicArgumentIndex();
643         return firstPos != -1 && argIndex >= firstPos;
644     }
645 
646     public static class SimpleVaArg {
647         public final Class<?> carrier;
648         public final MemoryLayout layout;
649         public final Object value;
650 
651         public SimpleVaArg(Class<?> carrier, MemoryLayout layout, Object value) {
652             this.carrier = carrier;
653             this.layout = layout;
654             this.value = value;
655         }
656 
657         public VarHandle varHandle() {
658             return layout.varHandle();


659         }
660     }
661 
662     public static non-sealed class EmptyVaList implements VaList, Scoped {
663 
664         private final MemoryAddress address;
665 
666         public EmptyVaList(MemoryAddress address) {
667             this.address = address;
668         }
669 
670         private static UnsupportedOperationException uoe() {
671             return new UnsupportedOperationException("Empty VaList");
672         }
673 
674         @Override
675         public int nextVarg(ValueLayout.OfInt layout) {





676             throw uoe();
677         }
678 
679         @Override
680         public long nextVarg(ValueLayout.OfLong layout) {
681             throw uoe();
682         }
683 
684         @Override
685         public double nextVarg(ValueLayout.OfDouble layout) {
686             throw uoe();
687         }
688 
689         @Override
690         public MemoryAddress nextVarg(ValueLayout.OfAddress layout) {
691             throw uoe();
692         }
693 
694         @Override
695         public MemorySegment nextVarg(GroupLayout layout, SegmentAllocator allocator) {
696             throw uoe();
697         }
698 
699         @Override
700         public void skip(MemoryLayout... layouts) {
701             throw uoe();
702         }
703 
704         @Override
705         public ResourceScope scope() {
706             return ResourceScope.globalScope();
707         }
708 
709         @Override
710         public VaList copy() {
711             return this;
712         }
713 
714         @Override
715         public MemoryAddress address() {
716             return address;
717         }
718     }
719 
720     static void writeOverSized(MemorySegment ptr, Class<?> type, Object o) {
721         // use VH_LONG for integers to zero out the whole register in the process
722         if (type == long.class) {
723             ptr.set(JAVA_LONG, 0, (long) o);
724         } else if (type == int.class) {
725             ptr.set(JAVA_LONG, 0, (int) o);
726         } else if (type == short.class) {
727             ptr.set(JAVA_LONG, 0, (short) o);
728         } else if (type == char.class) {
729             ptr.set(JAVA_LONG, 0, (char) o);
730         } else if (type == byte.class) {
731             ptr.set(JAVA_LONG, 0, (byte) o);
732         } else if (type == float.class) {
733             ptr.set(JAVA_FLOAT, 0, (float) o);
734         } else if (type == double.class) {
735             ptr.set(JAVA_DOUBLE, 0, (double) o);
736         } else if (type == boolean.class) {
737             ptr.set(JAVA_BOOLEAN, 0, (boolean) o);
738         } else {
739             throw new IllegalArgumentException("Unsupported carrier: " + type);
740         }
741     }
742 
743     static void write(MemorySegment ptr, Class<?> type, Object o) {
744         if (type == long.class) {
745             ptr.set(JAVA_LONG, 0, (long) o);
746         } else if (type == int.class) {
747             ptr.set(JAVA_INT, 0, (int) o);
748         } else if (type == short.class) {
749             ptr.set(JAVA_SHORT, 0, (short) o);
750         } else if (type == char.class) {
751             ptr.set(JAVA_CHAR, 0, (char) o);
752         } else if (type == byte.class) {
753             ptr.set(JAVA_BYTE, 0, (byte) o);
754         } else if (type == float.class) {
755             ptr.set(JAVA_FLOAT, 0, (float) o);
756         } else if (type == double.class) {
757             ptr.set(JAVA_DOUBLE, 0, (double) o);
758         } else if (type == boolean.class) {
759             ptr.set(JAVA_BOOLEAN, 0, (boolean) o);
760         } else {
761             throw new IllegalArgumentException("Unsupported carrier: " + type);
762         }
763     }
764 
765     static Object read(MemorySegment ptr, Class<?> type) {
766         if (type == long.class) {
767             return ptr.get(JAVA_LONG, 0);
768         } else if (type == int.class) {
769             return ptr.get(JAVA_INT, 0);
770         } else if (type == short.class) {
771             return ptr.get(JAVA_SHORT, 0);
772         } else if (type == char.class) {
773             return ptr.get(JAVA_CHAR, 0);
774         } else if (type == byte.class) {
775             return ptr.get(JAVA_BYTE, 0);
776         } else if (type == float.class) {
777             return ptr.get(JAVA_FLOAT, 0);
778         } else if (type == double.class) {
779             return ptr.get(JAVA_DOUBLE, 0);
780         } else if (type == boolean.class) {
781             return ptr.get(JAVA_BOOLEAN, 0);
782         } else {
783             throw new IllegalArgumentException("Unsupported carrier: " + type);
784         }
785     }
786 
787     public static MethodType inferMethodType(FunctionDescriptor descriptor, boolean upcall) {
788         MethodType type = MethodType.methodType(descriptor.returnLayout().isPresent() ?
789                 carrierFor(descriptor.returnLayout().get(), upcall) : void.class);
790         for (MemoryLayout argLayout : descriptor.argumentLayouts()) {
791             type = type.appendParameterTypes(carrierFor(argLayout, !upcall));
792         }
793         return type;
794     }
795 
796     static Class<?> carrierFor(MemoryLayout layout, boolean forArg) {
797         if (layout instanceof ValueLayout valueLayout) {
798             return (forArg && valueLayout.carrier().equals(MemoryAddress.class)) ?
799                     Addressable.class : valueLayout.carrier();
800         } else if (layout instanceof GroupLayout) {
801             return MemorySegment.class;
802         } else {
803             throw new IllegalArgumentException("Unsupported layout: " + layout);
804         }
805     }
806 }
< prev index next >