< prev index next >

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

Print this page

 37 import jdk.internal.foreign.abi.x64.sysv.SysVx64Linker;
 38 import jdk.internal.foreign.abi.x64.windows.Windowsx64Linker;
 39 import jdk.internal.foreign.layout.AbstractLayout;
 40 import jdk.internal.reflect.CallerSensitive;
 41 import jdk.internal.reflect.Reflection;
 42 
 43 import java.lang.foreign.AddressLayout;
 44 import java.lang.foreign.GroupLayout;
 45 import java.lang.foreign.MemoryLayout;
 46 import java.lang.foreign.Arena;
 47 import java.lang.foreign.FunctionDescriptor;
 48 import java.lang.foreign.Linker;
 49 import java.lang.foreign.MemorySegment;
 50 import java.lang.foreign.PaddingLayout;
 51 import java.lang.foreign.SequenceLayout;
 52 import java.lang.foreign.StructLayout;
 53 import java.lang.foreign.UnionLayout;
 54 import java.lang.foreign.ValueLayout;
 55 import java.lang.invoke.MethodHandle;
 56 import java.lang.invoke.MethodType;

 57 import java.util.List;
 58 import java.nio.ByteOrder;
 59 import java.util.Objects;
 60 import java.util.Set;
 61 
 62 public abstract sealed class AbstractLinker implements Linker permits LinuxAArch64Linker, MacOsAArch64Linker,
 63                                                                       SysVx64Linker, WindowsAArch64Linker,
 64                                                                       Windowsx64Linker,
 65                                                                       LinuxPPC64Linker, LinuxPPC64leLinker,
 66                                                                       LinuxRISCV64Linker, LinuxS390Linker,
 67                                                                       FallbackLinker {
 68 
 69     public interface UpcallStubFactory {
 70         MemorySegment makeStub(MethodHandle target, Arena arena);
 71     }
 72 
 73     private record LinkRequest(FunctionDescriptor descriptor, LinkerOptions options) {}
 74     private final SoftReferenceCache<LinkRequest, MethodHandle> DOWNCALL_CACHE = new SoftReferenceCache<>();
 75     private final SoftReferenceCache<LinkRequest, UpcallStubFactory> UPCALL_CACHE = new SoftReferenceCache<>();

 76 
 77     @Override
 78     @CallerSensitive
 79     public final MethodHandle downcallHandle(MemorySegment symbol, FunctionDescriptor function, Option... options) {
 80         Reflection.ensureNativeAccess(Reflection.getCallerClass(), Linker.class, "downcallHandle");
 81         SharedUtils.checkSymbol(symbol);
 82         return downcallHandle0(function, options).bindTo(symbol);
 83     }
 84 
 85     @Override
 86     @CallerSensitive
 87     public final MethodHandle downcallHandle(FunctionDescriptor function, Option... options) {
 88         Reflection.ensureNativeAccess(Reflection.getCallerClass(), Linker.class, "downcallHandle");
 89         return downcallHandle0(function, options);
 90     }
 91 
 92     private final MethodHandle downcallHandle0(FunctionDescriptor function, Option... options) {
 93         Objects.requireNonNull(function);
 94         Objects.requireNonNull(options);
 95         checkLayouts(function);
 96         function = stripNames(function);
 97         LinkerOptions optionSet = LinkerOptions.forDowncall(function, options);
 98         validateVariadicLayouts(function, optionSet);
 99 
100         return DOWNCALL_CACHE.get(new LinkRequest(function, optionSet), linkRequest ->  {
101             FunctionDescriptor fd = linkRequest.descriptor();
102             MethodType type = fd.toMethodType();
103             MethodHandle handle = arrangeDowncall(type, fd, linkRequest.options());
104             handle = SharedUtils.maybeCheckCaptureSegment(handle, linkRequest.options());
105             handle = SharedUtils.maybeInsertAllocator(fd, handle);
106             return handle;
107         });
108     }
109 
110     protected abstract MethodHandle arrangeDowncall(MethodType inferredMethodType, FunctionDescriptor function, LinkerOptions options);
111 
112     @Override

196                 }
197             }
198             checkGroupSize(sl, lastUnpaddedOffset);
199         } else if (layout instanceof UnionLayout ul) {
200             checkHasNaturalAlignment(layout);
201             long maxUnpaddedLayout = 0;
202             for (MemoryLayout member : ul.memberLayouts()) {
203                 checkLayoutRecursive(member);
204                 if (!(member instanceof PaddingLayout)) {
205                     maxUnpaddedLayout = Long.max(maxUnpaddedLayout, member.byteSize());
206                 }
207             }
208             checkGroupSize(ul, maxUnpaddedLayout);
209         } else if (layout instanceof SequenceLayout sl) {
210             checkHasNaturalAlignment(layout);
211             checkLayoutRecursive(sl.elementLayout());
212         }
213     }
214 
215     // check for trailing padding
216     private static void checkGroupSize(GroupLayout gl, long maxUnpaddedOffset) {
217         long expectedSize = Utils.alignUp(maxUnpaddedOffset, gl.byteAlignment());
218         if (gl.byteSize() != expectedSize) {
219             throw new IllegalArgumentException("Layout '" + gl + "' has unexpected size: "
220                     + gl.byteSize() + " != " + expectedSize);
221         }
222     }
223 
224     // checks both that there is no excess padding between 'memberLayout' and
225     // the previous layout
226     private static void checkMemberOffset(StructLayout parent, MemoryLayout memberLayout,
227                                           long lastUnpaddedOffset, long offset) {
228         long expectedOffset = Utils.alignUp(lastUnpaddedOffset, memberLayout.byteAlignment());
229         if (expectedOffset != offset) {
230             throw new IllegalArgumentException("Member layout '" + memberLayout + "', of '" + parent + "'" +
231                     " found at unexpected offset: " + offset + " != " + expectedOffset);
232         }
233     }
234 
235     private static void checkSupported(ValueLayout valueLayout) {
236         valueLayout = valueLayout.withoutName();
237         if (valueLayout instanceof AddressLayout addressLayout) {
238             valueLayout = addressLayout.withoutTargetLayout();
239         }
240         if (!SUPPORTED_LAYOUTS.contains(valueLayout.withoutName())) {
241             throw new IllegalArgumentException("Unsupported layout: " + valueLayout);
242         }
243     }
244 
245     private static void checkHasNaturalAlignment(MemoryLayout layout) {
246         if (!((AbstractLayout<?>) layout).hasNaturalAlignment()) {
247             throw new IllegalArgumentException("Layout alignment must be natural alignment: " + layout);
248         }
249     }
250 
251     private static MemoryLayout stripNames(MemoryLayout ml) {
252         // we don't care about transferring alignment and byte order here
253         // since the linker already restricts those such that they will always be the same
254         return switch (ml) {
255             case StructLayout sl -> MemoryLayout.structLayout(stripNames(sl.memberLayouts()));
256             case UnionLayout ul -> MemoryLayout.unionLayout(stripNames(ul.memberLayouts()));
257             case SequenceLayout sl -> MemoryLayout.sequenceLayout(sl.elementCount(), stripNames(sl.elementLayout()));
258             case AddressLayout al -> al.targetLayout()
259                     .map(tl -> al.withoutName().withTargetLayout(stripNames(tl)))
260                     .orElseGet(al::withoutName);
261             default -> ml.withoutName(); // ValueLayout and PaddingLayout
262         };
263     }
264 
265     private static MemoryLayout[] stripNames(List<MemoryLayout> layouts) {
266         return layouts.stream()
267                 .map(AbstractLinker::stripNames)
268                 .toArray(MemoryLayout[]::new);
269     }
270 
271     private static FunctionDescriptor stripNames(FunctionDescriptor function) {
272         return function.returnLayout()
273                 .map(rl -> FunctionDescriptor.of(stripNames(rl), stripNames(function.argumentLayouts())))
274                 .orElseGet(() -> FunctionDescriptor.ofVoid(stripNames(function.argumentLayouts())));
275     }
276 
277     private static final Set<MemoryLayout> SUPPORTED_LAYOUTS = Set.of(
278             ValueLayout.JAVA_BOOLEAN,
279             ValueLayout.JAVA_BYTE,
280             ValueLayout.JAVA_CHAR,
281             ValueLayout.JAVA_SHORT,
282             ValueLayout.JAVA_INT,
283             ValueLayout.JAVA_FLOAT,
284             ValueLayout.JAVA_LONG,
285             ValueLayout.JAVA_DOUBLE,
286             ValueLayout.ADDRESS
287     );
288 }

 37 import jdk.internal.foreign.abi.x64.sysv.SysVx64Linker;
 38 import jdk.internal.foreign.abi.x64.windows.Windowsx64Linker;
 39 import jdk.internal.foreign.layout.AbstractLayout;
 40 import jdk.internal.reflect.CallerSensitive;
 41 import jdk.internal.reflect.Reflection;
 42 
 43 import java.lang.foreign.AddressLayout;
 44 import java.lang.foreign.GroupLayout;
 45 import java.lang.foreign.MemoryLayout;
 46 import java.lang.foreign.Arena;
 47 import java.lang.foreign.FunctionDescriptor;
 48 import java.lang.foreign.Linker;
 49 import java.lang.foreign.MemorySegment;
 50 import java.lang.foreign.PaddingLayout;
 51 import java.lang.foreign.SequenceLayout;
 52 import java.lang.foreign.StructLayout;
 53 import java.lang.foreign.UnionLayout;
 54 import java.lang.foreign.ValueLayout;
 55 import java.lang.invoke.MethodHandle;
 56 import java.lang.invoke.MethodType;
 57 import java.util.HashSet;
 58 import java.util.List;
 59 import java.nio.ByteOrder;
 60 import java.util.Objects;
 61 import java.util.Set;
 62 
 63 public abstract sealed class AbstractLinker implements Linker permits LinuxAArch64Linker, MacOsAArch64Linker,
 64                                                                       SysVx64Linker, WindowsAArch64Linker,
 65                                                                       Windowsx64Linker,
 66                                                                       LinuxPPC64Linker, LinuxPPC64leLinker,
 67                                                                       LinuxRISCV64Linker, LinuxS390Linker,
 68                                                                       FallbackLinker {
 69 
 70     public interface UpcallStubFactory {
 71         MemorySegment makeStub(MethodHandle target, Arena arena);
 72     }
 73 
 74     private record LinkRequest(FunctionDescriptor descriptor, LinkerOptions options) {}
 75     private final SoftReferenceCache<LinkRequest, MethodHandle> DOWNCALL_CACHE = new SoftReferenceCache<>();
 76     private final SoftReferenceCache<LinkRequest, UpcallStubFactory> UPCALL_CACHE = new SoftReferenceCache<>();
 77     private final Set<MemoryLayout> CANONICAL_LAYOUTS_CACHE = new HashSet<>(canonicalLayouts().values());
 78 
 79     @Override
 80     @CallerSensitive
 81     public final MethodHandle downcallHandle(MemorySegment symbol, FunctionDescriptor function, Option... options) {
 82         Reflection.ensureNativeAccess(Reflection.getCallerClass(), Linker.class, "downcallHandle");
 83         SharedUtils.checkSymbol(symbol);
 84         return downcallHandle0(function, options).bindTo(symbol);
 85     }
 86 
 87     @Override
 88     @CallerSensitive
 89     public final MethodHandle downcallHandle(FunctionDescriptor function, Option... options) {
 90         Reflection.ensureNativeAccess(Reflection.getCallerClass(), Linker.class, "downcallHandle");
 91         return downcallHandle0(function, options);
 92     }
 93 
 94     private MethodHandle downcallHandle0(FunctionDescriptor function, Option... options) {
 95         Objects.requireNonNull(function);
 96         Objects.requireNonNull(options);
 97         checkLayouts(function);
 98         function = stripNames(function);
 99         LinkerOptions optionSet = LinkerOptions.forDowncall(function, options);
100         validateVariadicLayouts(function, optionSet);
101 
102         return DOWNCALL_CACHE.get(new LinkRequest(function, optionSet), linkRequest ->  {
103             FunctionDescriptor fd = linkRequest.descriptor();
104             MethodType type = fd.toMethodType();
105             MethodHandle handle = arrangeDowncall(type, fd, linkRequest.options());
106             handle = SharedUtils.maybeCheckCaptureSegment(handle, linkRequest.options());
107             handle = SharedUtils.maybeInsertAllocator(fd, handle);
108             return handle;
109         });
110     }
111 
112     protected abstract MethodHandle arrangeDowncall(MethodType inferredMethodType, FunctionDescriptor function, LinkerOptions options);
113 
114     @Override

198                 }
199             }
200             checkGroupSize(sl, lastUnpaddedOffset);
201         } else if (layout instanceof UnionLayout ul) {
202             checkHasNaturalAlignment(layout);
203             long maxUnpaddedLayout = 0;
204             for (MemoryLayout member : ul.memberLayouts()) {
205                 checkLayoutRecursive(member);
206                 if (!(member instanceof PaddingLayout)) {
207                     maxUnpaddedLayout = Long.max(maxUnpaddedLayout, member.byteSize());
208                 }
209             }
210             checkGroupSize(ul, maxUnpaddedLayout);
211         } else if (layout instanceof SequenceLayout sl) {
212             checkHasNaturalAlignment(layout);
213             checkLayoutRecursive(sl.elementLayout());
214         }
215     }
216 
217     // check for trailing padding
218     private void checkGroupSize(GroupLayout gl, long maxUnpaddedOffset) {
219         long expectedSize = Utils.alignUp(maxUnpaddedOffset, gl.byteAlignment());
220         if (gl.byteSize() != expectedSize) {
221             throw new IllegalArgumentException("Layout '" + gl + "' has unexpected size: "
222                     + gl.byteSize() + " != " + expectedSize);
223         }
224     }
225 
226     // checks both that there is no excess padding between 'memberLayout' and
227     // the previous layout
228     private void checkMemberOffset(StructLayout parent, MemoryLayout memberLayout,
229                                           long lastUnpaddedOffset, long offset) {
230         long expectedOffset = Utils.alignUp(lastUnpaddedOffset, memberLayout.byteAlignment());
231         if (expectedOffset != offset) {
232             throw new IllegalArgumentException("Member layout '" + memberLayout + "', of '" + parent + "'" +
233                     " found at unexpected offset: " + offset + " != " + expectedOffset);
234         }
235     }
236 
237     private void checkSupported(ValueLayout valueLayout) {
238         valueLayout = valueLayout.withoutName();
239         if (valueLayout instanceof AddressLayout addressLayout) {
240             valueLayout = addressLayout.withoutTargetLayout();
241         }
242         if (!CANONICAL_LAYOUTS_CACHE.contains(valueLayout.withoutName())) {
243             throw new IllegalArgumentException("Unsupported layout: " + valueLayout);
244         }
245     }
246 
247     private void checkHasNaturalAlignment(MemoryLayout layout) {
248         if (!((AbstractLayout<?>) layout).hasNaturalAlignment()) {
249             throw new IllegalArgumentException("Layout alignment must be natural alignment: " + layout);
250         }
251     }
252 
253     private static MemoryLayout stripNames(MemoryLayout ml) {
254         // we don't care about transferring alignment and byte order here
255         // since the linker already restricts those such that they will always be the same
256         return switch (ml) {
257             case StructLayout sl -> MemoryLayout.structLayout(stripNames(sl.memberLayouts()));
258             case UnionLayout ul -> MemoryLayout.unionLayout(stripNames(ul.memberLayouts()));
259             case SequenceLayout sl -> MemoryLayout.sequenceLayout(sl.elementCount(), stripNames(sl.elementLayout()));
260             case AddressLayout al -> al.targetLayout()
261                     .map(tl -> al.withoutName().withTargetLayout(stripNames(tl)))
262                     .orElseGet(al::withoutName);
263             default -> ml.withoutName(); // ValueLayout and PaddingLayout
264         };
265     }
266 
267     private static MemoryLayout[] stripNames(List<MemoryLayout> layouts) {
268         return layouts.stream()
269                 .map(AbstractLinker::stripNames)
270                 .toArray(MemoryLayout[]::new);
271     }
272 
273     private static FunctionDescriptor stripNames(FunctionDescriptor function) {
274         return function.returnLayout()
275                 .map(rl -> FunctionDescriptor.of(stripNames(rl), stripNames(function.argumentLayouts())))
276                 .orElseGet(() -> FunctionDescriptor.ofVoid(stripNames(function.argumentLayouts())));
277     }












278 }
< prev index next >