1 /* 2 * Copyright (c) 2020, 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 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 */ 26 package jdk.internal.jextract.impl; 27 28 import java.lang.constant.Constable; 29 import java.nio.file.Path; 30 import java.util.ArrayList; 31 import java.util.List; 32 import java.util.Map; 33 import java.util.Objects; 34 import java.util.stream.Collectors; 35 36 import jdk.incubator.foreign.MemoryLayout; 37 import jdk.incubator.jextract.Declaration; 38 import jdk.incubator.jextract.Position; 39 import jdk.incubator.jextract.Type; 40 import jdk.internal.clang.Cursor; 41 import jdk.internal.clang.CursorKind; 42 import jdk.internal.clang.CursorLanguage; 43 import jdk.internal.clang.SourceLocation; 44 45 class TreeMaker { 46 public TreeMaker() {} 47 48 TypeMaker typeMaker = new TypeMaker(this); 49 50 public void freeze() { 51 typeMaker.resolveTypeReferences(); 52 } 53 54 interface ScopedFactoryLayout { 55 Declaration.Scoped make(Position pos, String name, MemoryLayout layout, Declaration... decls); 56 } 57 58 interface ScopedFactoryNoLayout { 59 Declaration.Scoped make(Position pos, String name, Declaration... decls); 60 } 61 62 interface VarFactoryNoLayout { 63 Declaration.Variable make(Position pos, String name, Type type); 64 } 65 66 Map<String, List<Constable>> collectAttributes(Cursor c) { 67 return c.children().filter(Cursor::isAttribute) 68 .collect(Collectors.groupingBy( 69 attr -> attr.kind().name(), 70 Collectors.mapping(Cursor::spelling, Collectors.toList()) 71 )); 72 } 73 74 public Declaration createTree(Cursor c) { 75 Objects.requireNonNull(c); 76 CursorLanguage lang = c.language(); 77 if (lang != CursorLanguage.C && lang != CursorLanguage.Invalid) { 78 throw new RuntimeException("Unsupported language: " + c.language()); 79 } 80 var rv = (DeclarationImpl) createTreeInternal(c); 81 return (rv == null) ? null : rv.withAttributes(collectAttributes(c)); 82 } 83 84 private Declaration createTreeInternal(Cursor c) { 85 switch (c.kind()) { 86 case EnumDecl: 87 return createEnum(c, Declaration::enum_, Declaration::enum_); 88 case EnumConstantDecl: 89 return createEnumConstant(c); 90 case FieldDecl: 91 return createVar(c.isBitField() ? 92 Declaration.Variable.Kind.BITFIELD : Declaration.Variable.Kind.FIELD, c, Declaration::field); 93 case ParmDecl: 94 return createVar(Declaration.Variable.Kind.PARAMETER, c, Declaration::parameter); 95 case FunctionDecl: 96 return createFunction(c); 97 case StructDecl: 98 return createRecord(c, Declaration.Scoped.Kind.STRUCT, Declaration::struct, Declaration::struct); 99 case UnionDecl: 100 return createRecord(c, Declaration.Scoped.Kind.UNION, Declaration::union, Declaration::union); 101 case TypedefDecl: { 102 return createTypedef(c); 103 } 104 case VarDecl: 105 return createVar(Declaration.Variable.Kind.GLOBAL, c, Declaration::globalVariable); 106 default: 107 return null; 108 } 109 } 110 111 static class CursorPosition implements Position { 112 private final Cursor cursor; 113 private final Path path; 114 private final int line; 115 private final int column; 116 117 private CursorPosition(Cursor cursor) { 118 this.cursor = cursor; 119 SourceLocation.Location loc = cursor.getSourceLocation().getFileLocation(); 120 this.path = loc.path(); 121 this.line = loc.line(); 122 this.column = loc.column(); 123 } 124 125 static Position of(Cursor cursor) { 126 SourceLocation loc = cursor.getSourceLocation(); 127 if (loc == null) { 128 return NO_POSITION; 129 } 130 SourceLocation.Location sloc = loc.getFileLocation(); 131 if (sloc == null) { 132 return NO_POSITION; 133 } 134 return new CursorPosition(cursor); 135 } 136 137 @Override 138 public Path path() { 139 return path; 140 } 141 142 @Override 143 public int line() { 144 return line; 145 } 146 147 @Override 148 public int col() { 149 return column; 150 } 151 152 public Cursor cursor() { 153 return cursor; 154 } 155 156 @Override 157 public String toString() { 158 return PrettyPrinter.position(this); 159 } 160 } 161 162 public Declaration.Function createFunction(Cursor c) { 163 checkCursor(c, CursorKind.FunctionDecl); 164 List<Declaration.Variable> params = new ArrayList<>(); 165 for (int i = 0 ; i < c.numberOfArgs() ; i++) { 166 params.add((Declaration.Variable)createTree(c.getArgument(i))); 167 } 168 Type type = toType(c); 169 Type funcType = canonicalType(type); 170 return Declaration.function(CursorPosition.of(c), c.spelling(), (Type.Function)funcType, 171 params.toArray(new Declaration.Variable[0])); 172 } 173 174 public Declaration.Constant createMacro(Cursor c, String name, Type type, Object value) { 175 checkCursorAny(c, CursorKind.MacroDefinition); 176 return Declaration.constant(CursorPosition.of(c), name, value, type); 177 } 178 179 public Declaration.Constant createEnumConstant(Cursor c) { 180 return Declaration.constant(CursorPosition.of(c), c.spelling(), c.getEnumConstantValue(), typeMaker.makeType(c.type())); 181 } 182 183 public Declaration.Scoped createHeader(Cursor c, List<Declaration> decls) { 184 return Declaration.toplevel(CursorPosition.of(c), filterNestedDeclarations(decls).toArray(new Declaration[0])); 185 } 186 187 public Declaration.Scoped createRecord(Cursor c, Declaration.Scoped.Kind scopeKind, ScopedFactoryLayout factoryLayout, ScopedFactoryNoLayout factoryNoLayout) { 188 Type.Declared t = (Type.Declared)RecordLayoutComputer.compute(typeMaker, 0, c.type(), c.type()); 189 List<Declaration> decls = filterNestedDeclarations(t.tree().members()); 190 if (c.isDefinition()) { 191 //just a declaration AND definition, we have a layout 192 return factoryLayout.make(CursorPosition.of(c), c.spelling(), t.tree().layout().get(), decls.toArray(new Declaration[0])); 193 } else { 194 //just a declaration 195 if (scopeKind == Declaration.Scoped.Kind.STRUCT || 196 scopeKind == Declaration.Scoped.Kind.UNION || 197 scopeKind == Declaration.Scoped.Kind.CLASS) { 198 //if there's a real definition somewhere else, skip this redundant declaration 199 if (!c.getDefinition().isInvalid()) { 200 return null; 201 } 202 } 203 return factoryNoLayout.make(CursorPosition.of(c), c.spelling(), decls.toArray(new Declaration[0])); 204 } 205 } 206 207 public Declaration.Scoped createEnum(Cursor c, ScopedFactoryLayout factoryLayout, ScopedFactoryNoLayout factoryNoLayout) { 208 List<Declaration> decls = filterNestedDeclarations(c.children() 209 .filter(fc -> { 210 if (fc.isBitField()) { 211 // only non-empty and named bit fields are generated 212 return fc.getBitFieldWidth() != 0 && !fc.spelling().isEmpty(); 213 } 214 return true; 215 }) 216 .map(this::createTree).collect(Collectors.toList())); 217 if (c.isDefinition()) { 218 //just a declaration AND definition, we have a layout 219 MemoryLayout layout = TypeMaker.valueLayoutForSize(c.type().size() * 8).layout().orElseThrow(); 220 return factoryLayout.make(CursorPosition.of(c), c.spelling(), layout, decls.toArray(new Declaration[0])); 221 } else { 222 //just a declaration 223 //if there's a real definition somewhere else, skip this redundant declaration 224 if (!c.getDefinition().isInvalid()) { 225 return null; 226 } 227 return factoryNoLayout.make(CursorPosition.of(c), c.spelling(), decls.toArray(new Declaration[0])); 228 } 229 } 230 231 private static boolean isEnum(Declaration d) { 232 return d instanceof Declaration.Scoped && ((Declaration.Scoped)d).kind() == Declaration.Scoped.Kind.ENUM; 233 } 234 235 private static boolean isBitfield(Declaration d) { 236 return d instanceof Declaration.Scoped && ((Declaration.Scoped)d).kind() == Declaration.Scoped.Kind.BITFIELDS; 237 } 238 239 private static boolean isAnonymousStruct(Declaration declaration) { 240 return ((CursorPosition)declaration.pos()).cursor.isAnonymousStruct(); 241 } 242 243 private List<Declaration> filterNestedDeclarations(List<Declaration> declarations) { 244 return declarations.stream() 245 .filter(Objects::nonNull) 246 .filter(d -> isEnum(d) || !d.name().isEmpty() || isAnonymousStruct(d) || isBitfield(d)) 247 .collect(Collectors.toList()); 248 } 249 250 private Declaration.Typedef createTypedef(Cursor c) { 251 Type cursorType = toType(c); 252 Type canonicalType = canonicalType(cursorType); 253 if (canonicalType instanceof Type.Declared) { 254 Declaration.Scoped s = ((Type.Declared) canonicalType).tree(); 255 if (s.name().equals(c.spelling())) { 256 // typedef record with the same name, no need to present twice 257 return null; 258 } 259 } 260 Type.Function funcType = null; 261 boolean isFuncPtrType = false; 262 if (canonicalType instanceof Type.Function) { 263 funcType = (Type.Function)canonicalType; 264 } else if (Utils.isPointerType(canonicalType)) { 265 Type pointeeType = null; 266 try { 267 pointeeType = ((Type.Delegated)canonicalType).type(); 268 } catch (NullPointerException npe) { 269 // exception thrown for unresolved pointee type. Ignore if we hit that case. 270 } 271 if (pointeeType instanceof Type.Function) { 272 funcType = (Type.Function)pointeeType; 273 isFuncPtrType = true; 274 } 275 } 276 if (funcType != null) { 277 List<String> params = c.children(). 278 filter(ch -> ch.kind() == CursorKind.ParmDecl). 279 map(this::createTree). 280 map(Declaration.Variable.class::cast). 281 map(Declaration::name). 282 collect(Collectors.toList()); 283 if (!params.isEmpty()) { 284 canonicalType = funcType.withParameterNames(params); 285 if (isFuncPtrType) { 286 canonicalType = new TypeImpl.PointerImpl(canonicalType); 287 } 288 } 289 } 290 return Declaration.typedef(CursorPosition.of(c), c.spelling(), canonicalType); 291 } 292 293 private Type canonicalType(Type t) { 294 if (t instanceof Type.Delegated delegated && 295 delegated.kind() == Type.Delegated.Kind.TYPEDEF) { 296 return delegated.type(); 297 } else { 298 return t; 299 } 300 } 301 302 private Declaration.Variable createVar(Declaration.Variable.Kind kind, Cursor c, VarFactoryNoLayout varFactory) { 303 checkCursorAny(c, CursorKind.VarDecl, CursorKind.FieldDecl, CursorKind.ParmDecl); 304 if (c.isBitField()) { 305 return Declaration.bitfield(CursorPosition.of(c), c.spelling(), toType(c), 306 MemoryLayout.paddingLayout(c.getBitFieldWidth())); 307 } else { 308 Type type = null; 309 try { 310 type = toType(c); 311 } catch (TypeMaker.TypeException ex) { 312 System.err.println(ex); 313 System.err.println("WARNING: ignoring variable: " + c.spelling()); 314 return null; 315 } 316 return varFactory.make(CursorPosition.of(c), c.spelling(), type); 317 } 318 } 319 320 private Type toType(Cursor c) { 321 return typeMaker.makeType(c.type()); 322 } 323 324 private void checkCursor(Cursor c, CursorKind k) { 325 if (c.kind() != k) { 326 throw new IllegalArgumentException("Invalid cursor kind"); 327 } 328 } 329 330 private void checkCursorAny(Cursor c, CursorKind... kinds) { 331 CursorKind expected = Objects.requireNonNull(c.kind()); 332 for (CursorKind k : kinds) { 333 if (k == expected) { 334 return; 335 } 336 } 337 throw new IllegalArgumentException("Invalid cursor kind"); 338 } 339 }