32 import java.foreign.layout.Unresolved;
33 import java.foreign.layout.Value;
34 import java.util.ArrayList;
35 import java.util.List;
36 import java.util.function.BiFunction;
37 import java.util.stream.Collectors;
38 import java.util.stream.Stream;
39 import jdk.internal.clang.Cursor;
40 import jdk.internal.clang.CursorKind;
41 import jdk.internal.clang.SourceLocation;
42 import jdk.internal.clang.Type;
43 import jdk.internal.clang.TypeKind;
44 import jdk.internal.foreign.memory.Types;
45
46 /**
47 * General Layout utility functions
48 */
49 public final class LayoutUtils {
50 private LayoutUtils() {}
51
52 public static String getIdentifier(Type type) {
53 Cursor c = type.getDeclarationCursor();
54 if (c.isInvalid()) {
55 return type.spelling();
56 }
57 return getIdentifier(c);
58 }
59
60 static String getIdentifier(Cursor cursor) {
61 // Use cursor name instead of type name, this way we don't have struct
62 // or enum prefix
63 String nativeName = cursor.spelling();
64 if (nativeName.isEmpty()) {
65 // This happens when a typedef an anonymous struct, i.e., typedef struct {} type;
66 Type t = cursor.type();
67 nativeName = t.spelling();
68 if (nativeName.contains("::")) {
69 SourceLocation.Location loc = cursor.getSourceLocation().getFileLocation();
70 return "anon$"
71 + loc.path().getFileName().toString().replaceAll("\\.", "_")
72 + "$" + loc.offset();
73 }
74 }
75
76 return nativeName;
77 }
78
79 private static boolean isFunction(Type clang_type) {
80 switch (clang_type.kind()) {
81 case Unexposed:
82 case Typedef:
83 case Elaborated:
84 return isFunction(clang_type.canonicalType());
85 case FunctionProto:
86 case FunctionNoProto:
87 return true;
88 default:
179
180 private static Address parsePointerInternal(Type pointeeType) {
181 switch (pointeeType.kind()) {
182 case Unexposed:
183 case Typedef:
184 case Elaborated:
185 return parsePointerInternal(pointeeType.canonicalType());
186 case FunctionProto:
187 case FunctionNoProto:
188 return Address.ofFunction(64, parseFunctionInternal(pointeeType));
189 case Void:
190 return Address.ofVoid(64);
191 default:
192 return Address.ofLayout(64, getLayout(pointeeType));
193 }
194 }
195
196 private static Layout getRecordReferenceLayout(Type t) {
197 //symbolic reference
198 return Unresolved.of()
199 .withAnnotation(Layout.NAME, getIdentifier(t.canonicalType()));
200 }
201
202 static Layout getRecordLayout(Type t, BiFunction<Cursor, Layout, Layout> fieldMapper) {
203 return getRecordLayoutInternal(0, t, t, fieldMapper);
204 }
205
206 private static Layout getRecordLayoutInternal(long offset, Type parent, Type t, BiFunction<Cursor, Layout, Layout> fieldMapper) {
207 Cursor cu = t.getDeclarationCursor().getDefinition();
208 if (cu.isInvalid()) {
209 return getRecordReferenceLayout(t);
210 }
211 final boolean isUnion = cu.kind() == CursorKind.UnionDecl;
212 Stream<Cursor> fieldTypes = cu.children()
213 .filter(cx -> cx.isAnonymousStruct() || cx.kind() == CursorKind.FieldDecl);
214 List<Layout> fieldLayouts = new ArrayList<>();
215 int pendingBitfieldStart = -1;
216 long actualSize = 0L;
217 for (Cursor c : fieldTypes.collect(Collectors.toList())) {
218 boolean isBitfield = c.isBitField();
219 if (isBitfield && c.getBitFieldWidth() == 0) continue;
240 fieldLayouts.add(fieldLayout);
241 long size = fieldSize(isUnion, c);
242 if (isUnion) {
243 actualSize = Math.max(actualSize, size);
244 } else {
245 offset += size;
246 actualSize += size;
247 }
248 }
249 long expectedSize = t.size() * 8;
250 if (actualSize < expectedSize) {
251 fieldLayouts.add(Padding.of(expectedSize - actualSize));
252 }
253 if (pendingBitfieldStart >= 0) {
254 //emit/replace bitfields
255 replaceBitfields(fieldLayouts, pendingBitfieldStart);
256 }
257 Layout[] fields = fieldLayouts.toArray(new Layout[0]);
258 Group g = isUnion ?
259 Group.union(fields) : Group.struct(fields);
260 return g.withAnnotation(Layout.NAME, getIdentifier(cu));
261 }
262
263 private static Layout fieldLayout(boolean isUnion, Cursor c, BiFunction<Cursor, Layout, Layout> fieldMapper) {
264 Layout layout = getLayout(c.type());
265 if (c.isBitField()) {
266 boolean isSigned = ((Value)layout).kind() == Value.Kind.INTEGRAL_SIGNED;
267 Layout sublayout = isSigned ?
268 Value.ofSignedInt(c.getBitFieldWidth()) :
269 Value.ofUnsignedInt(c.getBitFieldWidth());
270 sublayout = fieldMapper.apply(c, sublayout);
271 return isUnion ?
272 bitfield((Value)layout, List.of(sublayout)) :
273 sublayout;
274 } else {
275 return fieldMapper.apply(c, layout);
276 }
277 }
278
279 private static long fieldSize(boolean isUnion, Cursor c) {
280 if (!c.isBitField() || isUnion) {
|
32 import java.foreign.layout.Unresolved;
33 import java.foreign.layout.Value;
34 import java.util.ArrayList;
35 import java.util.List;
36 import java.util.function.BiFunction;
37 import java.util.stream.Collectors;
38 import java.util.stream.Stream;
39 import jdk.internal.clang.Cursor;
40 import jdk.internal.clang.CursorKind;
41 import jdk.internal.clang.SourceLocation;
42 import jdk.internal.clang.Type;
43 import jdk.internal.clang.TypeKind;
44 import jdk.internal.foreign.memory.Types;
45
46 /**
47 * General Layout utility functions
48 */
49 public final class LayoutUtils {
50 private LayoutUtils() {}
51
52 public static String getName(Type type) {
53 Cursor c = type.getDeclarationCursor();
54 if (c.isInvalid()) {
55 return type.spelling();
56 }
57 return getName(c);
58 }
59
60 public static String getName(Tree tree) {
61 String name = tree.name();
62 return name.isEmpty()? getName(tree.cursor()) : name;
63 }
64
65 private static String getName(Cursor cursor) {
66 // Use cursor name instead of type name, this way we don't have struct
67 // or enum prefix
68 String nativeName = cursor.spelling();
69 if (nativeName.isEmpty()) {
70 Type t = cursor.type();
71 nativeName = t.spelling();
72 if (nativeName.contains("::") || nativeName.contains(" ")) {
73 SourceLocation.Location loc = cursor.getSourceLocation().getFileLocation();
74 return "anon$"
75 + loc.path().getFileName().toString().replaceAll("\\.", "_")
76 + "$" + loc.offset();
77 }
78 }
79
80 return nativeName;
81 }
82
83 private static boolean isFunction(Type clang_type) {
84 switch (clang_type.kind()) {
85 case Unexposed:
86 case Typedef:
87 case Elaborated:
88 return isFunction(clang_type.canonicalType());
89 case FunctionProto:
90 case FunctionNoProto:
91 return true;
92 default:
183
184 private static Address parsePointerInternal(Type pointeeType) {
185 switch (pointeeType.kind()) {
186 case Unexposed:
187 case Typedef:
188 case Elaborated:
189 return parsePointerInternal(pointeeType.canonicalType());
190 case FunctionProto:
191 case FunctionNoProto:
192 return Address.ofFunction(64, parseFunctionInternal(pointeeType));
193 case Void:
194 return Address.ofVoid(64);
195 default:
196 return Address.ofLayout(64, getLayout(pointeeType));
197 }
198 }
199
200 private static Layout getRecordReferenceLayout(Type t) {
201 //symbolic reference
202 return Unresolved.of()
203 .withAnnotation(Layout.NAME, getName(t.canonicalType()));
204 }
205
206 static Layout getRecordLayout(Type t, BiFunction<Cursor, Layout, Layout> fieldMapper) {
207 return getRecordLayoutInternal(0, t, t, fieldMapper);
208 }
209
210 private static Layout getRecordLayoutInternal(long offset, Type parent, Type t, BiFunction<Cursor, Layout, Layout> fieldMapper) {
211 Cursor cu = t.getDeclarationCursor().getDefinition();
212 if (cu.isInvalid()) {
213 return getRecordReferenceLayout(t);
214 }
215 final boolean isUnion = cu.kind() == CursorKind.UnionDecl;
216 Stream<Cursor> fieldTypes = cu.children()
217 .filter(cx -> cx.isAnonymousStruct() || cx.kind() == CursorKind.FieldDecl);
218 List<Layout> fieldLayouts = new ArrayList<>();
219 int pendingBitfieldStart = -1;
220 long actualSize = 0L;
221 for (Cursor c : fieldTypes.collect(Collectors.toList())) {
222 boolean isBitfield = c.isBitField();
223 if (isBitfield && c.getBitFieldWidth() == 0) continue;
244 fieldLayouts.add(fieldLayout);
245 long size = fieldSize(isUnion, c);
246 if (isUnion) {
247 actualSize = Math.max(actualSize, size);
248 } else {
249 offset += size;
250 actualSize += size;
251 }
252 }
253 long expectedSize = t.size() * 8;
254 if (actualSize < expectedSize) {
255 fieldLayouts.add(Padding.of(expectedSize - actualSize));
256 }
257 if (pendingBitfieldStart >= 0) {
258 //emit/replace bitfields
259 replaceBitfields(fieldLayouts, pendingBitfieldStart);
260 }
261 Layout[] fields = fieldLayouts.toArray(new Layout[0]);
262 Group g = isUnion ?
263 Group.union(fields) : Group.struct(fields);
264 return g.withAnnotation(Layout.NAME, getName(cu));
265 }
266
267 private static Layout fieldLayout(boolean isUnion, Cursor c, BiFunction<Cursor, Layout, Layout> fieldMapper) {
268 Layout layout = getLayout(c.type());
269 if (c.isBitField()) {
270 boolean isSigned = ((Value)layout).kind() == Value.Kind.INTEGRAL_SIGNED;
271 Layout sublayout = isSigned ?
272 Value.ofSignedInt(c.getBitFieldWidth()) :
273 Value.ofUnsignedInt(c.getBitFieldWidth());
274 sublayout = fieldMapper.apply(c, sublayout);
275 return isUnion ?
276 bitfield((Value)layout, List.of(sublayout)) :
277 sublayout;
278 } else {
279 return fieldMapper.apply(c, layout);
280 }
281 }
282
283 private static long fieldSize(boolean isUnion, Cursor c) {
284 if (!c.isBitField() || isUnion) {
|