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 27 package jdk.internal.jextract.impl; 28 29 30 import java.nio.ByteOrder; 31 import java.util.ArrayList; 32 import java.util.ConcurrentModificationException; 33 import java.util.HashMap; 34 import java.util.List; 35 import java.util.Map; 36 import java.util.Objects; 37 import java.util.function.Supplier; 38 import java.util.stream.Collectors; 39 40 import jdk.incubator.foreign.MemoryLayout; 41 import jdk.incubator.jextract.Declaration; 42 import jdk.incubator.jextract.Type; 43 import jdk.incubator.jextract.Type.Delegated; 44 import jdk.incubator.jextract.Type.Primitive; 45 import jdk.internal.clang.Cursor; 46 import jdk.internal.clang.TypeKind; 47 48 class TypeMaker { 49 50 TreeMaker treeMaker; 51 private final Map<jdk.internal.clang.Type, Type> typeCache = new HashMap<>(); 52 private List<ClangTypeReference> unresolved = new ArrayList<>(); 53 54 private class ClangTypeReference implements Supplier<Type> { 55 jdk.internal.clang.Type origin; 56 Type derived; 57 58 private ClangTypeReference(jdk.internal.clang.Type origin) { 59 this.origin = origin; 60 derived = typeCache.get(origin); 61 } 62 63 public boolean isUnresolved() { 64 return null == derived; 65 } 66 67 public void resolve() { 68 derived = makeType(origin); 69 Objects.requireNonNull(derived, "Clang type cannot be resolved: " + origin.spelling()); 70 } 71 72 public Type get() { 73 Objects.requireNonNull(derived, "Type is not yet resolved."); 74 return derived; 75 } 76 } 77 78 private ClangTypeReference reference(jdk.internal.clang.Type type) { 79 ClangTypeReference ref = new ClangTypeReference(type); 80 if (ref.isUnresolved()) { 81 unresolved.add(ref); 82 } 83 return ref; 84 } 85 86 public TypeMaker(TreeMaker treeMaker) { 87 this.treeMaker = treeMaker; 88 } 89 90 /** 91 * Resolve all type references. This method should be called before discard clang cursors/types 92 */ 93 void resolveTypeReferences() { 94 List<ClangTypeReference> resolving = unresolved; 95 unresolved = new ArrayList<>(); 96 while (! resolving.isEmpty()) { 97 resolving.forEach(ClangTypeReference::resolve); 98 resolving = unresolved; 99 unresolved = new ArrayList<>(); 100 } 101 } 102 103 Type makeType(jdk.internal.clang.Type t) { 104 Type rv = typeCache.get(t); 105 if (rv != null) { 106 return rv; 107 } 108 rv = makeTypeInternal(t); 109 if (null != rv && typeCache.put(t, rv) != null) { 110 throw new ConcurrentModificationException(); 111 } 112 return rv; 113 } 114 115 static class TypeException extends RuntimeException { 116 static final long serialVersionUID = 1L; 117 118 TypeException(String msg) { 119 super(msg); 120 } 121 } 122 123 Type makeTypeInternal(jdk.internal.clang.Type t) { 124 switch(t.kind()) { 125 case Auto: 126 return makeType(t.canonicalType()); 127 case Void: 128 return Type.void_(); 129 case Char_S: 130 case Char_U: 131 return Type.primitive(Primitive.Kind.Char); 132 case Short: 133 return Type.primitive(Primitive.Kind.Short); 134 case Int: 135 return Type.primitive(Primitive.Kind.Int); 136 case Long: 137 return Type.primitive(Primitive.Kind.Long); 138 case LongLong: 139 return Type.primitive(Primitive.Kind.LongLong); 140 case SChar: { 141 Type chType = Type.primitive(Primitive.Kind.Char); 142 return Type.qualified(Delegated.Kind.SIGNED, chType); 143 } 144 case UShort: { 145 Type chType = Type.primitive(Primitive.Kind.Short); 146 return Type.qualified(Delegated.Kind.UNSIGNED, chType); 147 } 148 case UInt: { 149 Type chType = Type.primitive(Primitive.Kind.Int); 150 return Type.qualified(Delegated.Kind.UNSIGNED, chType); 151 } 152 case ULong: { 153 Type chType = Type.primitive(Primitive.Kind.Long); 154 return Type.qualified(Delegated.Kind.UNSIGNED, chType); 155 } 156 case ULongLong: { 157 Type chType = Type.primitive(Primitive.Kind.LongLong); 158 return Type.qualified(Delegated.Kind.UNSIGNED, chType); 159 } 160 case UChar: { 161 Type chType = Type.primitive(Primitive.Kind.Char); 162 return Type.qualified(Delegated.Kind.UNSIGNED, chType); 163 } 164 165 case Bool: 166 return Type.primitive(Primitive.Kind.Bool); 167 case Double: 168 return Type.primitive(Primitive.Kind.Double); 169 case Float: 170 return Type.primitive(Primitive.Kind.Float); 171 case Unexposed: 172 case Elaborated: 173 jdk.internal.clang.Type canonical = t.canonicalType(); 174 if (canonical.equalType(t)) { 175 throw new TypeException("Unknown type with same canonical type: " + t.spelling()); 176 } 177 return makeType(canonical); 178 case ConstantArray: { 179 Type elem = makeType(t.getElementType()); 180 return Type.array(t.getNumberOfElements(), elem); 181 } 182 case IncompleteArray: { 183 Type elem = makeType(t.getElementType()); 184 return Type.array(elem); 185 } 186 case FunctionProto: 187 case FunctionNoProto: { 188 List<Type> args = new ArrayList<>(); 189 for (int i = 0; i < t.numberOfArgs(); i++) { 190 // argument could be function pointer declared locally 191 args.add(lowerFunctionType(t.argType(i))); 192 } 193 return Type.function(t.isVariadic(), lowerFunctionType(t.resultType()), args.toArray(new Type[0])); 194 } 195 case Enum: 196 case Record: { 197 return Type.declared((Declaration.Scoped) treeMaker.createTree(t.getDeclarationCursor())); 198 } 199 case BlockPointer: 200 case Pointer: { 201 // TODO: We can always erase type for macro evaluation, should we? 202 if (t.getPointeeType().kind() == TypeKind.FunctionProto) { 203 return new TypeImpl.PointerImpl(makeType(t.getPointeeType())); 204 } else { 205 return new TypeImpl.PointerImpl(reference(t.getPointeeType())); 206 } 207 } 208 case Typedef: { 209 Type __type = makeType(t.canonicalType()); 210 return Type.typedef(t.spelling(), __type); 211 } 212 case Complex: { 213 Type __type = makeType(t.getElementType()); 214 return Type.qualified(Delegated.Kind.COMPLEX, __type); 215 } 216 case Vector: { 217 Type __type = makeType(t.getElementType()); 218 return Type.vector(t.getNumberOfElements(), __type); 219 } 220 case WChar: //unsupported 221 return Type.primitive(Primitive.Kind.WChar); 222 case Char16: //unsupported 223 return Type.primitive(Primitive.Kind.Char16); 224 case Half: //unsupported 225 return Type.primitive(Primitive.Kind.HalfFloat); 226 case Int128: //unsupported 227 return Type.primitive(Primitive.Kind.Int128); 228 case LongDouble: //unsupported 229 return Type.primitive(Primitive.Kind.LongDouble); 230 case UInt128: { //unsupported 231 Type iType = Type.primitive(Primitive.Kind.Int128); 232 return Type.qualified(Delegated.Kind.UNSIGNED, iType); 233 } 234 default: 235 return TypeImpl.ERROR; 236 } 237 } 238 239 private Type lowerFunctionType(jdk.internal.clang.Type t) { 240 Type t2 = makeType(t); 241 return t2.accept(lowerFunctionType, null); 242 } 243 244 private Type.Visitor<Type, Void> lowerFunctionType = new Type.Visitor<>() { 245 @Override 246 public Type visitArray(Type.Array t, Void aVoid) { 247 return Type.pointer(t.elementType()); 248 } 249 250 @Override 251 public Type visitDelegated(Type.Delegated t, Void aVoid) { 252 if (t.kind() == Delegated.Kind.TYPEDEF && t.type() instanceof Type.Array) { 253 return visitArray((Type.Array)t.type(), aVoid); 254 } 255 return visitType(t, aVoid); 256 } 257 258 @Override 259 public Type visitType(Type t, Void aVoid) { 260 return t; 261 } 262 }; 263 264 public static Primitive.Kind valueLayoutForSize(long size) { 265 return switch ((int) size) { 266 case 8 -> Primitive.Kind.Char; 267 case 16 -> Primitive.Kind.Short; 268 case 32 -> Primitive.Kind.Int; 269 case 64 -> Primitive.Kind.LongLong; 270 default -> throw new IllegalStateException("Cannot infer container layout"); 271 }; 272 } 273 }