< prev index next >

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

Print this page

 37 import jdk.internal.foreign.abi.ppc64.linux.LinuxPPC64leLinker;
 38 import jdk.internal.foreign.abi.riscv64.linux.LinuxRISCV64Linker;
 39 import jdk.internal.foreign.abi.s390.linux.LinuxS390Linker;
 40 import jdk.internal.foreign.abi.x64.sysv.SysVx64Linker;
 41 import jdk.internal.foreign.abi.x64.windows.Windowsx64Linker;
 42 import jdk.internal.vm.annotation.ForceInline;
 43 
 44 import java.lang.foreign.AddressLayout;
 45 import java.lang.foreign.Arena;
 46 import java.lang.foreign.Linker;
 47 import java.lang.foreign.FunctionDescriptor;
 48 import java.lang.foreign.GroupLayout;
 49 import java.lang.foreign.MemoryLayout;
 50 import java.lang.foreign.MemorySegment;
 51 import java.lang.foreign.MemorySegment.Scope;
 52 import java.lang.foreign.SegmentAllocator;
 53 import java.lang.foreign.ValueLayout;
 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.ByteOrder;
 60 import java.nio.charset.StandardCharsets;
 61 import java.util.Arrays;
 62 import java.util.Map;
 63 import java.util.Objects;
 64 import java.util.stream.Collectors;
 65 import java.util.stream.IntStream;
 66 
 67 import static java.lang.foreign.ValueLayout.*;
 68 import static java.lang.invoke.MethodHandles.*;
 69 import static java.lang.invoke.MethodType.methodType;
 70 
 71 public final class SharedUtils {
 72 
 73     private SharedUtils() {
 74     }
 75 
 76     private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
 77     private static final JavaLangInvokeAccess JLIA = SharedSecrets.getJavaLangInvokeAccess();
 78 
 79     private static final MethodHandle MH_ALLOC_BUFFER;
 80     private static final MethodHandle MH_BUFFER_COPY;
 81     private static final MethodHandle MH_REACHABILITY_FENCE;
 82     public static final MethodHandle MH_CHECK_SYMBOL;
 83     private static final MethodHandle MH_CHECK_CAPTURE_SEGMENT;
 84 
 85     public static final AddressLayout C_POINTER = ADDRESS
 86             .withTargetLayout(MemoryLayout.sequenceLayout(JAVA_BYTE));
 87 
 88     public static final Arena DUMMY_ARENA = new Arena() {
 89         @Override
 90         public Scope scope() {
 91             throw new UnsupportedOperationException();
 92         }
 93 
 94         @Override
 95         public MemorySegment allocate(long byteSize) {
 96             throw new UnsupportedOperationException();
 97         }
 98 
 99         @Override
100         public void close() {
101             // do nothing
102         }
103     };
104 
105     static {
106         try {
107             MethodHandles.Lookup lookup = MethodHandles.lookup();
108             MH_ALLOC_BUFFER = lookup.findVirtual(SegmentAllocator.class, "allocate",
109                     methodType(MemorySegment.class, MemoryLayout.class));
110             MH_BUFFER_COPY = lookup.findStatic(SharedUtils.class, "bufferCopy",
111                     methodType(MemorySegment.class, MemorySegment.class, MemorySegment.class));
112             MH_REACHABILITY_FENCE = lookup.findStatic(Reference.class, "reachabilityFence",
113                     methodType(void.class, Object.class));
114             MH_CHECK_SYMBOL = lookup.findStatic(SharedUtils.class, "checkSymbol",
115                     methodType(void.class, MemorySegment.class));
116             MH_CHECK_CAPTURE_SEGMENT = lookup.findStatic(SharedUtils.class, "checkCaptureSegment",
117                     methodType(MemorySegment.class, MemorySegment.class));
118         } catch (ReflectiveOperationException e) {
119             throw new BootstrapMethodError(e);
120         }
121     }
122 
123     // this allocator should be used when no allocation is expected
124     public static final SegmentAllocator THROWING_ALLOCATOR = (size, align) -> {
125         throw new IllegalStateException("Cannot get here");
126     };
127 
128     public static long alignUp(long addr, long alignment) {
129         return ((addr - 1) | (alignment - 1)) + 1;
130     }
131 




132     /**
133      * Takes a MethodHandle that takes an input buffer as a first argument (a MemorySegment), and returns nothing,
134      * and adapts it to return a MemorySegment, by allocating a MemorySegment for the input
135      * buffer, calling the target MethodHandle, and then returning the allocated MemorySegment.
136      *
137      * This allows viewing a MethodHandle that makes use of in memory return (IMR) as a MethodHandle that just returns
138      * a MemorySegment without requiring a pre-allocated buffer as an explicit input.
139      *
140      * @param handle the target handle to adapt
141      * @param cDesc the function descriptor of the native function (with actual return layout)
142      * @return the adapted handle
143      */
144     public static MethodHandle adaptDowncallForIMR(MethodHandle handle, FunctionDescriptor cDesc, CallingSequence sequence) {
145         if (handle.type().returnType() != void.class)
146             throw new IllegalArgumentException("return expected to be void for in memory returns: " + handle.type());
147         int imrAddrIdx = sequence.numLeadingParams();
148         if (handle.type().parameterType(imrAddrIdx) != MemorySegment.class)
149             throw new IllegalArgumentException("MemorySegment expected as third param: " + handle.type());
150         if (cDesc.returnLayout().isEmpty())
151             throw new IllegalArgumentException("Return layout needed: " + cDesc);

234 
235         throw new IllegalArgumentException("No layout for size: " + size + " isFloat=" + useFloat);
236     }
237 
238     public static Linker getSystemLinker() {
239         return switch (CABI.current()) {
240             case WIN_64 -> Windowsx64Linker.getInstance();
241             case SYS_V -> SysVx64Linker.getInstance();
242             case LINUX_AARCH_64 -> LinuxAArch64Linker.getInstance();
243             case MAC_OS_AARCH_64 -> MacOsAArch64Linker.getInstance();
244             case WIN_AARCH_64 -> WindowsAArch64Linker.getInstance();
245             case LINUX_PPC_64 -> LinuxPPC64Linker.getInstance();
246             case LINUX_PPC_64_LE -> LinuxPPC64leLinker.getInstance();
247             case LINUX_RISCV_64 -> LinuxRISCV64Linker.getInstance();
248             case LINUX_S390 -> LinuxS390Linker.getInstance();
249             case FALLBACK -> FallbackLinker.getInstance();
250             case UNSUPPORTED -> throw new UnsupportedOperationException("Platform does not support native linker");
251         };
252     }
253 
254     public static String toJavaStringInternal(MemorySegment segment, long start) {
255         int len = strlen(segment, start);
256         byte[] bytes = new byte[len];
257         MemorySegment.copy(segment, JAVA_BYTE, start, bytes, 0, len);
258         return new String(bytes, StandardCharsets.UTF_8);
259     }
260 
261     private static int strlen(MemorySegment segment, long start) {
262         // iterate until overflow (String can only hold a byte[], whose length can be expressed as an int)
263         for (int offset = 0; offset >= 0; offset++) {
264             byte curr = segment.get(JAVA_BYTE, start + offset);
265             if (curr == 0) {
266                 return offset;
267             }
268         }
269         throw new IllegalArgumentException("String too large");
270     }
271 
272     static Map<VMStorage, Integer> indexMap(Binding.Move[] moves) {
273         return IntStream.range(0, moves.length)
274                         .boxed()
275                         .collect(Collectors.toMap(i -> moves[i].storage(), i -> i));
276     }
277 
278     static MethodHandle mergeArguments(MethodHandle mh, int sourceIndex, int destIndex) {
279         MethodType oldType = mh.type();
280         Class<?> sourceType = oldType.parameterType(sourceIndex);
281         Class<?> destType = oldType.parameterType(destIndex);
282         if (sourceType != destType) {
283             // TODO meet?
284             throw new IllegalArgumentException("Parameter types differ: " + sourceType + " != " + destType);
285         }
286         MethodType newType = oldType.dropParameterTypes(destIndex, destIndex + 1);
287         int[] reorder = new int[oldType.parameterCount()];
288         if (destIndex < sourceIndex) {
289             sourceIndex--;
290         }
291         for (int i = 0, index = 0; i < reorder.length; i++) {

417         return new Arena() {
418             final Arena arena = Arena.ofConfined();
419 
420             @Override
421             public Scope scope() {
422                 return arena.scope();
423             }
424 
425             @Override
426             public void close() {
427                 arena.close();
428             }
429 
430             @Override
431             public MemorySegment allocate(long byteSize, long byteAlignment) {
432                 throw new UnsupportedOperationException();
433             }
434         };
435     }
436 
437     public static final class SimpleVaArg {
438         public final MemoryLayout layout;
439         public final Object value;
440 
441         public SimpleVaArg(MemoryLayout layout, Object value) {
442             this.layout = layout;
443             this.value = value;
444         }
445 
446         public VarHandle varHandle() {
447             return layout.varHandle();
448         }
449     }
450 
451     static void writeOverSized(MemorySegment ptr, Class<?> type, Object o) {
452         // use VH_LONG for integers to zero out the whole register in the process
453         if (type == long.class) {
454             ptr.set(JAVA_LONG_UNALIGNED, 0, (long) o);
455         } else if (type == int.class) {
456             ptr.set(JAVA_LONG_UNALIGNED, 0, (int) o);
457         } else if (type == short.class) {
458             ptr.set(JAVA_LONG_UNALIGNED, 0, (short) o);
459         } else if (type == char.class) {
460             ptr.set(JAVA_LONG_UNALIGNED, 0, (char) o);
461         } else if (type == byte.class) {
462             ptr.set(JAVA_LONG_UNALIGNED, 0, (byte) o);
463         } else if (type == float.class) {
464             ptr.set(JAVA_FLOAT_UNALIGNED, 0, (float) o);
465         } else if (type == double.class) {
466             ptr.set(JAVA_DOUBLE_UNALIGNED, 0, (double) o);
467         } else if (type == boolean.class) {
468             boolean b = (boolean)o;
469             ptr.set(JAVA_LONG_UNALIGNED, 0, b ? (long)1 : (long)0);
470         } else {

498         if (type == long.class) {
499             return ptr.get(JAVA_LONG_UNALIGNED, offset);
500         } else if (type == int.class) {
501             return ptr.get(JAVA_INT_UNALIGNED, offset);
502         } else if (type == short.class) {
503             return ptr.get(JAVA_SHORT_UNALIGNED, offset);
504         } else if (type == char.class) {
505             return ptr.get(JAVA_CHAR_UNALIGNED, offset);
506         } else if (type == byte.class) {
507             return ptr.get(JAVA_BYTE, offset);
508         } else if (type == float.class) {
509             return ptr.get(JAVA_FLOAT_UNALIGNED, offset);
510         } else if (type == double.class) {
511             return ptr.get(JAVA_DOUBLE_UNALIGNED, offset);
512         } else if (type == boolean.class) {
513             return ptr.get(JAVA_BOOLEAN, offset);
514         } else {
515             throw new IllegalArgumentException("Unsupported carrier: " + type);
516         }
517     }































518 }

 37 import jdk.internal.foreign.abi.ppc64.linux.LinuxPPC64leLinker;
 38 import jdk.internal.foreign.abi.riscv64.linux.LinuxRISCV64Linker;
 39 import jdk.internal.foreign.abi.s390.linux.LinuxS390Linker;
 40 import jdk.internal.foreign.abi.x64.sysv.SysVx64Linker;
 41 import jdk.internal.foreign.abi.x64.windows.Windowsx64Linker;
 42 import jdk.internal.vm.annotation.ForceInline;
 43 
 44 import java.lang.foreign.AddressLayout;
 45 import java.lang.foreign.Arena;
 46 import java.lang.foreign.Linker;
 47 import java.lang.foreign.FunctionDescriptor;
 48 import java.lang.foreign.GroupLayout;
 49 import java.lang.foreign.MemoryLayout;
 50 import java.lang.foreign.MemorySegment;
 51 import java.lang.foreign.MemorySegment.Scope;
 52 import java.lang.foreign.SegmentAllocator;
 53 import java.lang.foreign.ValueLayout;
 54 import java.lang.invoke.MethodHandle;
 55 import java.lang.invoke.MethodHandles;
 56 import java.lang.invoke.MethodType;

 57 import java.lang.ref.Reference;
 58 import java.nio.ByteOrder;

 59 import java.util.Arrays;
 60 import java.util.Map;
 61 import java.util.Objects;
 62 import java.util.stream.Collectors;
 63 import java.util.stream.IntStream;
 64 
 65 import static java.lang.foreign.ValueLayout.*;
 66 import static java.lang.invoke.MethodHandles.*;
 67 import static java.lang.invoke.MethodType.methodType;
 68 
 69 public final class SharedUtils {
 70 
 71     private SharedUtils() {
 72     }
 73 
 74     private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
 75     private static final JavaLangInvokeAccess JLIA = SharedSecrets.getJavaLangInvokeAccess();
 76 
 77     private static final MethodHandle MH_ALLOC_BUFFER;
 78     private static final MethodHandle MH_BUFFER_COPY;
 79     private static final MethodHandle MH_REACHABILITY_FENCE;
 80     public static final MethodHandle MH_CHECK_SYMBOL;
 81     private static final MethodHandle MH_CHECK_CAPTURE_SEGMENT;
 82 
 83     public static final AddressLayout C_POINTER = ADDRESS
 84             .withTargetLayout(MemoryLayout.sequenceLayout(Long.MAX_VALUE, JAVA_BYTE));
 85 
 86     public static final Arena DUMMY_ARENA = new Arena() {
 87         @Override
 88         public Scope scope() {
 89             throw new UnsupportedOperationException();
 90         }
 91 
 92         @Override
 93         public MemorySegment allocate(long byteSize, long byteAlignment) {
 94             throw new UnsupportedOperationException();
 95         }
 96 
 97         @Override
 98         public void close() {
 99             // do nothing
100         }
101     };
102 
103     static {
104         try {
105             MethodHandles.Lookup lookup = MethodHandles.lookup();
106             MH_ALLOC_BUFFER = lookup.findVirtual(SegmentAllocator.class, "allocate",
107                     methodType(MemorySegment.class, MemoryLayout.class));
108             MH_BUFFER_COPY = lookup.findStatic(SharedUtils.class, "bufferCopy",
109                     methodType(MemorySegment.class, MemorySegment.class, MemorySegment.class));
110             MH_REACHABILITY_FENCE = lookup.findStatic(Reference.class, "reachabilityFence",
111                     methodType(void.class, Object.class));
112             MH_CHECK_SYMBOL = lookup.findStatic(SharedUtils.class, "checkSymbol",
113                     methodType(void.class, MemorySegment.class));
114             MH_CHECK_CAPTURE_SEGMENT = lookup.findStatic(SharedUtils.class, "checkCaptureSegment",
115                     methodType(MemorySegment.class, MemorySegment.class));
116         } catch (ReflectiveOperationException e) {
117             throw new BootstrapMethodError(e);
118         }
119     }
120 
121     // this allocator should be used when no allocation is expected
122     public static final SegmentAllocator THROWING_ALLOCATOR = (size, align) -> {
123         throw new IllegalStateException("Cannot get here");
124     };
125 
126     public static long alignUp(long addr, long alignment) {
127         return ((addr - 1) | (alignment - 1)) + 1;
128     }
129 
130     public static long remainsToAlignment(long addr, long alignment) {
131         return alignUp(addr, alignment) - addr;
132     }
133 
134     /**
135      * Takes a MethodHandle that takes an input buffer as a first argument (a MemorySegment), and returns nothing,
136      * and adapts it to return a MemorySegment, by allocating a MemorySegment for the input
137      * buffer, calling the target MethodHandle, and then returning the allocated MemorySegment.
138      *
139      * This allows viewing a MethodHandle that makes use of in memory return (IMR) as a MethodHandle that just returns
140      * a MemorySegment without requiring a pre-allocated buffer as an explicit input.
141      *
142      * @param handle the target handle to adapt
143      * @param cDesc the function descriptor of the native function (with actual return layout)
144      * @return the adapted handle
145      */
146     public static MethodHandle adaptDowncallForIMR(MethodHandle handle, FunctionDescriptor cDesc, CallingSequence sequence) {
147         if (handle.type().returnType() != void.class)
148             throw new IllegalArgumentException("return expected to be void for in memory returns: " + handle.type());
149         int imrAddrIdx = sequence.numLeadingParams();
150         if (handle.type().parameterType(imrAddrIdx) != MemorySegment.class)
151             throw new IllegalArgumentException("MemorySegment expected as third param: " + handle.type());
152         if (cDesc.returnLayout().isEmpty())
153             throw new IllegalArgumentException("Return layout needed: " + cDesc);

236 
237         throw new IllegalArgumentException("No layout for size: " + size + " isFloat=" + useFloat);
238     }
239 
240     public static Linker getSystemLinker() {
241         return switch (CABI.current()) {
242             case WIN_64 -> Windowsx64Linker.getInstance();
243             case SYS_V -> SysVx64Linker.getInstance();
244             case LINUX_AARCH_64 -> LinuxAArch64Linker.getInstance();
245             case MAC_OS_AARCH_64 -> MacOsAArch64Linker.getInstance();
246             case WIN_AARCH_64 -> WindowsAArch64Linker.getInstance();
247             case LINUX_PPC_64 -> LinuxPPC64Linker.getInstance();
248             case LINUX_PPC_64_LE -> LinuxPPC64leLinker.getInstance();
249             case LINUX_RISCV_64 -> LinuxRISCV64Linker.getInstance();
250             case LINUX_S390 -> LinuxS390Linker.getInstance();
251             case FALLBACK -> FallbackLinker.getInstance();
252             case UNSUPPORTED -> throw new UnsupportedOperationException("Platform does not support native linker");
253         };
254     }
255 


















256     static Map<VMStorage, Integer> indexMap(Binding.Move[] moves) {
257         return IntStream.range(0, moves.length)
258                         .boxed()
259                         .collect(Collectors.toMap(i -> moves[i].storage(), i -> i));
260     }
261 
262     static MethodHandle mergeArguments(MethodHandle mh, int sourceIndex, int destIndex) {
263         MethodType oldType = mh.type();
264         Class<?> sourceType = oldType.parameterType(sourceIndex);
265         Class<?> destType = oldType.parameterType(destIndex);
266         if (sourceType != destType) {
267             // TODO meet?
268             throw new IllegalArgumentException("Parameter types differ: " + sourceType + " != " + destType);
269         }
270         MethodType newType = oldType.dropParameterTypes(destIndex, destIndex + 1);
271         int[] reorder = new int[oldType.parameterCount()];
272         if (destIndex < sourceIndex) {
273             sourceIndex--;
274         }
275         for (int i = 0, index = 0; i < reorder.length; i++) {

401         return new Arena() {
402             final Arena arena = Arena.ofConfined();
403 
404             @Override
405             public Scope scope() {
406                 return arena.scope();
407             }
408 
409             @Override
410             public void close() {
411                 arena.close();
412             }
413 
414             @Override
415             public MemorySegment allocate(long byteSize, long byteAlignment) {
416                 throw new UnsupportedOperationException();
417             }
418         };
419     }
420 














421     static void writeOverSized(MemorySegment ptr, Class<?> type, Object o) {
422         // use VH_LONG for integers to zero out the whole register in the process
423         if (type == long.class) {
424             ptr.set(JAVA_LONG_UNALIGNED, 0, (long) o);
425         } else if (type == int.class) {
426             ptr.set(JAVA_LONG_UNALIGNED, 0, (int) o);
427         } else if (type == short.class) {
428             ptr.set(JAVA_LONG_UNALIGNED, 0, (short) o);
429         } else if (type == char.class) {
430             ptr.set(JAVA_LONG_UNALIGNED, 0, (char) o);
431         } else if (type == byte.class) {
432             ptr.set(JAVA_LONG_UNALIGNED, 0, (byte) o);
433         } else if (type == float.class) {
434             ptr.set(JAVA_FLOAT_UNALIGNED, 0, (float) o);
435         } else if (type == double.class) {
436             ptr.set(JAVA_DOUBLE_UNALIGNED, 0, (double) o);
437         } else if (type == boolean.class) {
438             boolean b = (boolean)o;
439             ptr.set(JAVA_LONG_UNALIGNED, 0, b ? (long)1 : (long)0);
440         } else {

468         if (type == long.class) {
469             return ptr.get(JAVA_LONG_UNALIGNED, offset);
470         } else if (type == int.class) {
471             return ptr.get(JAVA_INT_UNALIGNED, offset);
472         } else if (type == short.class) {
473             return ptr.get(JAVA_SHORT_UNALIGNED, offset);
474         } else if (type == char.class) {
475             return ptr.get(JAVA_CHAR_UNALIGNED, offset);
476         } else if (type == byte.class) {
477             return ptr.get(JAVA_BYTE, offset);
478         } else if (type == float.class) {
479             return ptr.get(JAVA_FLOAT_UNALIGNED, offset);
480         } else if (type == double.class) {
481             return ptr.get(JAVA_DOUBLE_UNALIGNED, offset);
482         } else if (type == boolean.class) {
483             return ptr.get(JAVA_BOOLEAN, offset);
484         } else {
485             throw new IllegalArgumentException("Unsupported carrier: " + type);
486         }
487     }
488 
489     public static Map<String, MemoryLayout> canonicalLayouts(ValueLayout longLayout, ValueLayout sizetLayout, ValueLayout wchartLayout) {
490         return Map.ofEntries(
491                 // specified canonical layouts
492                 Map.entry("bool", ValueLayout.JAVA_BOOLEAN),
493                 Map.entry("char", ValueLayout.JAVA_BYTE),
494                 Map.entry("short", ValueLayout.JAVA_SHORT),
495                 Map.entry("int", ValueLayout.JAVA_INT),
496                 Map.entry("float", ValueLayout.JAVA_FLOAT),
497                 Map.entry("long", longLayout),
498                 Map.entry("long long", ValueLayout.JAVA_LONG),
499                 Map.entry("double", ValueLayout.JAVA_DOUBLE),
500                 Map.entry("void*", ValueLayout.ADDRESS),
501                 Map.entry("size_t", sizetLayout),
502                 Map.entry("wchar_t", wchartLayout),
503                 // unspecified size-dependent layouts
504                 Map.entry("int8_t", ValueLayout.JAVA_BYTE),
505                 Map.entry("int16_t", ValueLayout.JAVA_SHORT),
506                 Map.entry("int32_t", ValueLayout.JAVA_INT),
507                 Map.entry("int64_t", ValueLayout.JAVA_LONG),
508                 // unspecified JNI layouts
509                 Map.entry("jboolean", ValueLayout.JAVA_BOOLEAN),
510                 Map.entry("jchar", ValueLayout.JAVA_CHAR),
511                 Map.entry("jbyte", ValueLayout.JAVA_BYTE),
512                 Map.entry("jshort", ValueLayout.JAVA_SHORT),
513                 Map.entry("jint", ValueLayout.JAVA_INT),
514                 Map.entry("jlong", ValueLayout.JAVA_LONG),
515                 Map.entry("jfloat", ValueLayout.JAVA_FLOAT),
516                 Map.entry("jdouble", ValueLayout.JAVA_DOUBLE)
517         );
518     }
519 }
< prev index next >