< prev index next >

src/java.base/share/classes/jdk/internal/foreign/abi/fallback/FFIType.java

Print this page

 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.fallback;
 26 
 27 import jdk.internal.foreign.Utils;
 28 
 29 import java.lang.foreign.Arena;
 30 import java.lang.foreign.GroupLayout;
 31 import java.lang.foreign.MemoryLayout;
 32 import java.lang.foreign.MemorySegment;
 33 import java.lang.foreign.PaddingLayout;
 34 import java.lang.foreign.SequenceLayout;
 35 import java.lang.foreign.StructLayout;
 36 import java.lang.foreign.UnionLayout;
 37 import java.lang.foreign.ValueLayout;
 38 import java.lang.invoke.VarHandle;
 39 import java.util.Collections;
 40 import java.util.Comparator;
 41 import java.util.List;
 42 import java.util.Map;
 43 import java.util.Objects;
 44 import java.util.function.Predicate;
 45 
 46 import static java.lang.foreign.ValueLayout.ADDRESS;

 47 import static java.lang.foreign.ValueLayout.JAVA_INT;
 48 import static java.lang.foreign.ValueLayout.JAVA_LONG;
 49 import static java.lang.foreign.ValueLayout.JAVA_SHORT;
 50 
 51 /**
 52  * typedef struct _ffi_type
 53  * {
 54  *   size_t size;
 55  *   unsigned short alignment;
 56  *   unsigned short type;
 57  *   struct _ffi_type **elements;
 58  * } ffi_type;
 59  */
 60 class FFIType {
 61     private static final ValueLayout SIZE_T = switch ((int) ADDRESS.byteSize()) {
 62             case 8 -> JAVA_LONG;
 63             case 4 -> JAVA_INT;
 64             default -> throw new IllegalStateException("Address size not supported: " + ADDRESS.byteSize());
 65         };
 66     private static final ValueLayout UNSIGNED_SHORT = JAVA_SHORT;
 67     private static final StructLayout LAYOUT = Utils.computePaddedStructLayout(
 68             SIZE_T, UNSIGNED_SHORT, UNSIGNED_SHORT.withName("type"), ADDRESS.withName("elements"));
 69 
 70     private static final VarHandle VH_TYPE = LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("type"));
 71     private static final VarHandle VH_ELEMENTS = LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("elements"));
 72     private static final VarHandle VH_SIZE_T_ARRAY = SIZE_T.arrayElementVarHandle();
 73 
 74     private static MemorySegment make(List<MemoryLayout> elements, FFIABI abi, Arena scope) {
 75         MemorySegment elementsSeg = scope.allocate((elements.size() + 1) * ADDRESS.byteSize());
 76         int i = 0;
 77         for (; i < elements.size(); i++) {
 78             MemoryLayout elementLayout = elements.get(i);
 79             MemorySegment elementType = toFFIType(elementLayout, abi, scope);
 80             elementsSeg.setAtIndex(ADDRESS, i, elementType);
 81         }
 82         // elements array is null-terminated
 83         elementsSeg.setAtIndex(ADDRESS, i, MemorySegment.NULL);
 84 
 85         MemorySegment ffiType = scope.allocate(LAYOUT);
 86         VH_TYPE.set(ffiType, LibFallback.structTag());
 87         VH_ELEMENTS.set(ffiType, elementsSeg);
 88 
 89         return ffiType;
 90     }
 91 
 92     private static final Map<Class<?>, MemorySegment> CARRIER_TO_TYPE = Map.of(
 93         boolean.class, LibFallback.uint8Type(),
 94         byte.class, LibFallback.sint8Type(),
 95         short.class, LibFallback.sint16Type(),
 96         char.class, LibFallback.uint16Type(),
 97         int.class, LibFallback.sint32Type(),
 98         long.class, LibFallback.sint64Type(),
 99         float.class, LibFallback.floatType(),
100         double.class, LibFallback.doubleType(),
101         MemorySegment.class, LibFallback.pointerType()
102     );
103 
104     static MemorySegment toFFIType(MemoryLayout layout, FFIABI abi, Arena scope) {
105         if (layout instanceof GroupLayout grpl) {
106             if (grpl instanceof StructLayout strl) {
107                 // libffi doesn't want our padding

115             assert grpl instanceof UnionLayout;
116             // JDK-8301800
117             throw new IllegalArgumentException("Fallback linker does not support by-value unions: " + grpl);
118         } else if (layout instanceof SequenceLayout sl) {
119             List<MemoryLayout> elements = Collections.nCopies(Math.toIntExact(sl.elementCount()), sl.elementLayout());
120             return make(elements, abi, scope);
121         }
122         return Objects.requireNonNull(CARRIER_TO_TYPE.get(((ValueLayout) layout).carrier()));
123     }
124 
125     // verify layout against what libffi sets
126     private static void verifyStructType(StructLayout structLayout, List<MemoryLayout> filteredLayouts, MemorySegment structType,
127                                          FFIABI abi) {
128         try (Arena verifyArena = Arena.ofConfined()) {
129             MemorySegment offsetsOut = verifyArena.allocate(SIZE_T.byteSize() * filteredLayouts.size());
130             LibFallback.getStructOffsets(structType, offsetsOut, abi);
131             long expectedOffset = 0;
132             int offsetIdx = 0;
133             for (MemoryLayout element : structLayout.memberLayouts()) {
134                 if (!(element instanceof PaddingLayout)) {
135                     long ffiOffset = (long) VH_SIZE_T_ARRAY.get(offsetsOut, offsetIdx++);
136                     if (ffiOffset != expectedOffset) {
137                         throw new IllegalArgumentException("Invalid group layout." +
138                                 " Offset of '" + element.name().orElse("<unnamed>")
139                                 + "': " + expectedOffset + " != " + ffiOffset);
140                     }
141                 }
142                 expectedOffset += element.byteSize();
143             }
144         }
145     }



















146 }

 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.fallback;
 26 
 27 import jdk.internal.foreign.Utils;
 28 
 29 import java.lang.foreign.Arena;
 30 import java.lang.foreign.GroupLayout;
 31 import java.lang.foreign.MemoryLayout;
 32 import java.lang.foreign.MemorySegment;
 33 import java.lang.foreign.PaddingLayout;
 34 import java.lang.foreign.SequenceLayout;
 35 import java.lang.foreign.StructLayout;
 36 import java.lang.foreign.UnionLayout;
 37 import java.lang.foreign.ValueLayout;
 38 import java.lang.invoke.VarHandle;
 39 import java.util.Collections;

 40 import java.util.List;
 41 import java.util.Map;
 42 import java.util.Objects;
 43 import java.util.function.Predicate;
 44 
 45 import static java.lang.foreign.ValueLayout.ADDRESS;
 46 import static java.lang.foreign.ValueLayout.JAVA_BYTE;
 47 import static java.lang.foreign.ValueLayout.JAVA_INT;
 48 import static java.lang.foreign.ValueLayout.JAVA_LONG;
 49 import static java.lang.foreign.ValueLayout.JAVA_SHORT;
 50 
 51 /**
 52  * typedef struct _ffi_type
 53  * {
 54  *   size_t size;
 55  *   unsigned short alignment;
 56  *   unsigned short type;
 57  *   struct _ffi_type **elements;
 58  * } ffi_type;
 59  */
 60 class FFIType {
 61     static final ValueLayout SIZE_T = layoutFor((int)ADDRESS.byteSize());




 62     private static final ValueLayout UNSIGNED_SHORT = JAVA_SHORT;
 63     private static final StructLayout LAYOUT = Utils.computePaddedStructLayout(
 64             SIZE_T, UNSIGNED_SHORT, UNSIGNED_SHORT.withName("type"), ADDRESS.withName("elements"));
 65 
 66     private static final VarHandle VH_TYPE = LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("type"));
 67     private static final VarHandle VH_ELEMENTS = LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("elements"));
 68     private static final VarHandle VH_SIZE_T = SIZE_T.varHandle();
 69 
 70     private static MemorySegment make(List<MemoryLayout> elements, FFIABI abi, Arena scope) {
 71         MemorySegment elementsSeg = scope.allocate((elements.size() + 1) * ADDRESS.byteSize());
 72         int i = 0;
 73         for (; i < elements.size(); i++) {
 74             MemoryLayout elementLayout = elements.get(i);
 75             MemorySegment elementType = toFFIType(elementLayout, abi, scope);
 76             elementsSeg.setAtIndex(ADDRESS, i, elementType);
 77         }
 78         // elements array is null-terminated
 79         elementsSeg.setAtIndex(ADDRESS, i, MemorySegment.NULL);
 80 
 81         MemorySegment ffiType = scope.allocate(LAYOUT);
 82         VH_TYPE.set(ffiType, 0L, LibFallback.structTag());
 83         VH_ELEMENTS.set(ffiType, 0L, elementsSeg);
 84 
 85         return ffiType;
 86     }
 87 
 88     private static final Map<Class<?>, MemorySegment> CARRIER_TO_TYPE = Map.of(
 89         boolean.class, LibFallback.uint8Type(),
 90         byte.class, LibFallback.sint8Type(),
 91         short.class, LibFallback.sint16Type(),
 92         char.class, LibFallback.uint16Type(),
 93         int.class, LibFallback.sint32Type(),
 94         long.class, LibFallback.sint64Type(),
 95         float.class, LibFallback.floatType(),
 96         double.class, LibFallback.doubleType(),
 97         MemorySegment.class, LibFallback.pointerType()
 98     );
 99 
100     static MemorySegment toFFIType(MemoryLayout layout, FFIABI abi, Arena scope) {
101         if (layout instanceof GroupLayout grpl) {
102             if (grpl instanceof StructLayout strl) {
103                 // libffi doesn't want our padding

111             assert grpl instanceof UnionLayout;
112             // JDK-8301800
113             throw new IllegalArgumentException("Fallback linker does not support by-value unions: " + grpl);
114         } else if (layout instanceof SequenceLayout sl) {
115             List<MemoryLayout> elements = Collections.nCopies(Math.toIntExact(sl.elementCount()), sl.elementLayout());
116             return make(elements, abi, scope);
117         }
118         return Objects.requireNonNull(CARRIER_TO_TYPE.get(((ValueLayout) layout).carrier()));
119     }
120 
121     // verify layout against what libffi sets
122     private static void verifyStructType(StructLayout structLayout, List<MemoryLayout> filteredLayouts, MemorySegment structType,
123                                          FFIABI abi) {
124         try (Arena verifyArena = Arena.ofConfined()) {
125             MemorySegment offsetsOut = verifyArena.allocate(SIZE_T.byteSize() * filteredLayouts.size());
126             LibFallback.getStructOffsets(structType, offsetsOut, abi);
127             long expectedOffset = 0;
128             int offsetIdx = 0;
129             for (MemoryLayout element : structLayout.memberLayouts()) {
130                 if (!(element instanceof PaddingLayout)) {
131                     long ffiOffset = sizeTAtIndex(offsetsOut, offsetIdx++);
132                     if (ffiOffset != expectedOffset) {
133                         throw new IllegalArgumentException("Invalid group layout." +
134                                 " Offset of '" + element.name().orElse("<unnamed>")
135                                 + "': " + expectedOffset + " != " + ffiOffset);
136                     }
137                 }
138                 expectedOffset += element.byteSize();
139             }
140         }
141     }
142 
143     static ValueLayout layoutFor(int byteSize) {
144         return switch (byteSize) {
145             case 1 -> JAVA_BYTE;
146             case 2 -> JAVA_SHORT;
147             case 4 -> JAVA_INT;
148             case 8 -> JAVA_LONG;
149             default -> throw new IllegalStateException("Unsupported size: " + byteSize);
150         };
151     }
152 
153     private static long sizeTAtIndex(MemorySegment segment, int index) {
154         long offset = SIZE_T.scale(0, index);
155         if (VH_SIZE_T.varType() == long.class) {
156             return (long) VH_SIZE_T.get(segment, offset);
157         } else {
158             return (int) VH_SIZE_T.get(segment, offset); // 'erase' to long
159         }
160     }
161 }
< prev index next >