1 /* 2 * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 package com.sun.tools.jextract.tree; 25 26 import java.foreign.layout.Address; 27 import java.foreign.layout.Function; 28 import java.foreign.layout.Group; 29 import java.foreign.layout.Layout; 30 import java.foreign.layout.Padding; 31 import java.foreign.layout.Sequence; 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 45 /** 46 * General Layout utility functions 47 */ 48 public final class LayoutUtils { 49 private LayoutUtils() {} 50 51 public static String getName(Type type) { 52 Cursor c = type.getDeclarationCursor(); 53 if (c.isInvalid()) { 54 return type.spelling(); 55 } 56 return getName(c); 57 } 58 59 public static String getName(Tree tree) { 60 String name = tree.name(); 61 return name.isEmpty()? getName(tree.cursor()) : name; 62 } 63 64 private static String getName(Cursor cursor) { 65 // Use cursor name instead of type name, this way we don't have struct 66 // or enum prefix 67 String nativeName = cursor.spelling(); 68 if (nativeName.isEmpty()) { 69 Type t = cursor.type(); 70 nativeName = t.spelling(); 71 if (nativeName.contains("::") || nativeName.contains(" ")) { 72 SourceLocation.Location loc = cursor.getSourceLocation().getFileLocation(); 73 return "anon$" 74 + loc.path().getFileName().toString().replaceAll("\\.", "_") 75 + "$" + loc.offset(); 76 } 77 } 78 79 return nativeName; 80 } 81 82 private static boolean isFunction(Type clang_type) { 83 switch (clang_type.kind()) { 84 case Unexposed: 85 case Typedef: 86 case Elaborated: 87 return isFunction(clang_type.canonicalType()); 88 case FunctionProto: 89 case FunctionNoProto: 90 return true; 91 default: 92 return false; 93 } 94 } 95 96 public static Function getFunction(Type t) { 97 assert isFunction(t) : "not a function type"; 98 switch (t.kind()) { 99 case Unexposed: 100 case Typedef: 101 case Elaborated: 102 return parseFunctionInternal(t.canonicalType()); 103 case FunctionProto: 104 case FunctionNoProto: 105 return parseFunctionInternal(t); 106 default: 107 throw new IllegalArgumentException( 108 "Unsupported type kind: " + t.kind()); 109 } 110 } 111 112 private static Function parseFunctionInternal(Type t) { 113 final int argSize = t.numberOfArgs(); 114 Layout[] args = new Layout[argSize]; 115 for (int i = 0; i < argSize; i++) { 116 Layout l = getLayout(t.argType(i)); 117 args[i] = l instanceof Sequence? Address.ofLayout(64, ((Sequence)l).element()) : l; 118 } 119 if (t.resultType().kind() == TypeKind.Void) { 120 return Function.ofVoid(t.isVariadic(), args); 121 } else { 122 return Function.of(getLayout(t.resultType()), t.isVariadic(), args); 123 } 124 } 125 126 static class Types { 127 public final static Layout BYTE = Value.ofSignedInt(8); 128 public final static Layout SHORT = Value.ofSignedInt(16); 129 public final static Layout INT = Value.ofSignedInt(32); 130 public final static Layout LONG = Value.ofSignedInt(64); 131 public final static Layout LONG_LONG = Value.ofSignedInt(64); 132 public final static Layout FLOAT = Value.ofFloatingPoint(32); 133 public final static Layout DOUBLE = Value.ofFloatingPoint(64); 134 public final static Layout LONG_DOUBLE = Value.ofFloatingPoint(128); 135 public final static Layout CHAR = Value.ofSignedInt(8); 136 public final static Layout BOOLEAN = Value.ofUnsignedInt(8); 137 public final static Layout POINTER = Address.ofVoid(64); 138 public final static Layout INT8 = Value.ofSignedInt(8); 139 public final static Layout INT16 = Value.ofSignedInt(16); 140 public final static Layout INT32 = Value.ofSignedInt(32); 141 public final static Layout INT64 = Value.ofSignedInt(64); 142 public final static Layout INT128 = Value.ofSignedInt(128); 143 public final static Layout VOID = Value.ofUnsignedInt(0); 144 145 public static class UNSIGNED { 146 public final static Layout BYTE = Value.ofUnsignedInt(8); 147 public final static Layout SHORT = Value.ofUnsignedInt(16); 148 public final static Layout INT = Value.ofUnsignedInt(32); 149 public final static Layout LONG = Value.ofUnsignedInt(64); 150 public final static Layout LONG_LONG = Value.ofUnsignedInt(64); 151 public final static Layout INT8 = Value.ofUnsignedInt(8); 152 public final static Layout INT16 = Value.ofUnsignedInt(16); 153 public final static Layout INT32 = Value.ofUnsignedInt(32); 154 public final static Layout INT64 = Value.ofUnsignedInt(64); 155 public final static Layout INT128 = Value.ofUnsignedInt(128); 156 } 157 } 158 159 public static Layout getLayout(Type t) { 160 switch(t.kind()) { 161 case Bool: 162 return Types.BOOLEAN; 163 case Int: 164 return Types.INT; 165 case UInt: 166 return Types.UNSIGNED.INT; 167 case Int128: 168 return Types.INT128; 169 case UInt128: 170 return Types.UNSIGNED.INT128; 171 case Short: 172 return Types.SHORT; 173 case UShort: 174 return Types.UNSIGNED.SHORT; 175 case Long: 176 return Types.LONG; 177 case ULong: 178 return Types.UNSIGNED.LONG; 179 case LongLong: 180 return Types.LONG_LONG; 181 case ULongLong: 182 return Types.UNSIGNED.LONG_LONG; 183 case SChar: 184 return Types.BYTE; 185 case Char_S: 186 case Char_U: 187 case UChar: 188 return Types.UNSIGNED.BYTE; 189 case Float: 190 return Types.FLOAT; 191 case Double: 192 return Types.DOUBLE; 193 case LongDouble: 194 return Types.LONG_DOUBLE; 195 case Record: 196 return getRecordReferenceLayout(t); 197 case Enum: 198 return Types.INT; 199 case ConstantArray: 200 return Sequence.of(t.getNumberOfElements(), getLayout(t.getElementType())); 201 case IncompleteArray: 202 return Sequence.of(0L, getLayout(t.getElementType())); 203 case Unexposed: 204 case Typedef: 205 case Elaborated: 206 return getLayout(t.canonicalType()); 207 case Pointer: 208 case BlockPointer: 209 return parsePointerInternal(t.getPointeeType()); 210 default: 211 throw new IllegalArgumentException( 212 "Unsupported type kind: " + t.kind()); 213 } 214 } 215 216 private static Address parsePointerInternal(Type pointeeType) { 217 switch (pointeeType.kind()) { 218 case Unexposed: 219 case Typedef: 220 case Elaborated: 221 return parsePointerInternal(pointeeType.canonicalType()); 222 case FunctionProto: 223 case FunctionNoProto: 224 return Address.ofFunction(64, parseFunctionInternal(pointeeType)); 225 case Void: 226 return Address.ofVoid(64); 227 default: 228 return Address.ofLayout(64, getLayout(pointeeType)); 229 } 230 } 231 232 private static Layout getRecordReferenceLayout(Type t) { 233 //symbolic reference 234 return Unresolved.of() 235 .withAnnotation(Layout.NAME, getName(t.canonicalType())); 236 } 237 238 static Layout getRecordLayout(Type t, BiFunction<Cursor, Layout, Layout> fieldMapper) { 239 return getRecordLayoutInternal(0, t, t, fieldMapper); 240 } 241 242 private static Layout getRecordLayoutInternal(long offset, Type parent, Type t, BiFunction<Cursor, Layout, Layout> fieldMapper) { 243 Cursor cu = t.getDeclarationCursor().getDefinition(); 244 if (cu.isInvalid()) { 245 return getRecordReferenceLayout(t); 246 } 247 final boolean isUnion = cu.kind() == CursorKind.UnionDecl; 248 Stream<Cursor> fieldTypes = cu.children() 249 .filter(cx -> cx.isAnonymousStruct() || cx.kind() == CursorKind.FieldDecl); 250 List<Layout> fieldLayouts = new ArrayList<>(); 251 int pendingBitfieldStart = -1; 252 long actualSize = 0L; 253 for (Cursor c : fieldTypes.collect(Collectors.toList())) { 254 boolean isBitfield = c.isBitField(); 255 if (isBitfield && c.getBitFieldWidth() == 0) continue; 256 long expectedOffset = offsetOf(parent, c); 257 if (expectedOffset > offset) { 258 if (isUnion) { 259 throw new IllegalStateException("No padding in union elements!"); 260 } 261 fieldLayouts.add(Padding.of(expectedOffset - offset)); 262 actualSize += (expectedOffset - offset); 263 offset = expectedOffset; 264 } 265 if (isBitfield && !isUnion && pendingBitfieldStart == -1) { 266 pendingBitfieldStart = fieldLayouts.size(); 267 } 268 if (!isBitfield && pendingBitfieldStart >= 0) { 269 //emit/replace bitfields 270 replaceBitfields(fieldLayouts, pendingBitfieldStart); 271 pendingBitfieldStart = -1; 272 } 273 Layout fieldLayout = (c.isAnonymousStruct()) ? 274 getRecordLayoutInternal(offset, parent, c.type(), fieldMapper) : 275 fieldLayout(isUnion, c, fieldMapper); 276 fieldLayouts.add(fieldLayout); 277 long size = fieldSize(isUnion, c); 278 if (isUnion) { 279 actualSize = Math.max(actualSize, size); 280 } else { 281 offset += size; 282 actualSize += size; 283 } 284 } 285 long expectedSize = t.size() * 8; 286 if (actualSize < expectedSize) { 287 fieldLayouts.add(Padding.of(expectedSize - actualSize)); 288 } 289 if (pendingBitfieldStart >= 0) { 290 //emit/replace bitfields 291 replaceBitfields(fieldLayouts, pendingBitfieldStart); 292 } 293 Layout[] fields = fieldLayouts.toArray(new Layout[0]); 294 Group g = isUnion ? 295 Group.union(fields) : Group.struct(fields); 296 return g.withAnnotation(Layout.NAME, getName(cu)); 297 } 298 299 private static Layout fieldLayout(boolean isUnion, Cursor c, BiFunction<Cursor, Layout, Layout> fieldMapper) { 300 Layout layout = getLayout(c.type()); 301 if (c.isBitField()) { 302 boolean isSigned = ((Value)layout).kind() == Value.Kind.INTEGRAL_SIGNED; 303 Layout sublayout = isSigned ? 304 Value.ofSignedInt(c.getBitFieldWidth()) : 305 Value.ofUnsignedInt(c.getBitFieldWidth()); 306 sublayout = fieldMapper.apply(c, sublayout); 307 return isUnion ? 308 bitfield((Value)layout, List.of(sublayout)) : 309 sublayout; 310 } else { 311 return fieldMapper.apply(c, layout); 312 } 313 } 314 315 private static long fieldSize(boolean isUnion, Cursor c) { 316 if (!c.isBitField() || isUnion) { 317 return c.type().size() * 8; 318 } else { 319 return c.getBitFieldWidth(); 320 } 321 } 322 323 private static void replaceBitfields(List<Layout> layouts, int pendingBitfieldsStart) { 324 long storageSize = storageSize(layouts); 325 long offset = 0L; 326 List<Layout> newFields = new ArrayList<>(); 327 List<Layout> pendingFields = new ArrayList<>(); 328 while (layouts.size() > pendingBitfieldsStart) { 329 Layout l = layouts.remove(pendingBitfieldsStart); 330 offset += l.bitsSize(); 331 pendingFields.add(l); 332 if (!pendingFields.isEmpty() && 333 offset == storageSize) { 334 //emit new 335 newFields.add(bitfield(Value.ofUnsignedInt(storageSize), pendingFields)); 336 pendingFields.clear(); 337 offset = 0L; 338 } else if (offset > storageSize) { 339 throw new IllegalStateException("Crossing storage unit boundaries"); 340 } 341 } 342 if (!pendingFields.isEmpty()) { 343 throw new IllegalStateException("Partially used storage unit"); 344 } 345 //add back new fields 346 newFields.forEach(layouts::add); 347 } 348 349 private static long storageSize(List<Layout> layouts) { 350 long size = layouts.stream().mapToLong(Layout::bitsSize).sum(); 351 int[] sizes = { 64, 32, 16, 8 }; 352 for (int s : sizes) { 353 if (size % s == 0) { 354 return s; 355 } 356 } 357 throw new IllegalStateException("Cannot infer storage size"); 358 } 359 360 private static Value bitfield(Value v, List<Layout> sublayouts) { 361 return v.withContents(Group.struct(sublayouts.toArray(new Layout[0]))); 362 } 363 364 private static long offsetOf(Type parent, Cursor c) { 365 if (c.kind() == CursorKind.FieldDecl) { 366 return parent.getOffsetOf(c.spelling()); 367 } else { 368 return c.children() 369 .mapToLong(child -> offsetOf(parent, child)) 370 .findFirst().orElseThrow(IllegalStateException::new); 371 } 372 } 373 } --- EOF ---