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; 25 26 import java.foreign.memory.DoubleComplex; 27 import java.foreign.memory.FloatComplex; 28 import java.foreign.memory.LongDoubleComplex; 29 import java.math.BigInteger; 30 import java.nio.file.Path; 31 import java.util.HashSet; 32 import java.util.Optional; 33 import java.util.Set; 34 import java.util.function.Function; 35 import java.util.HashMap; 36 import java.util.Map; 37 import java.util.logging.Logger; 38 import java.util.stream.Stream; 39 40 import jdk.internal.clang.Type; 41 import jdk.internal.clang.TypeKind; 42 43 /** 44 * A dictionary that find Java type for a given native type. 45 * Each instance of TypeDictionary presents types for a given java package. 46 */ 47 public final class TypeDictionary { 48 private HeaderResolver resolver; 49 private final HeaderFile headerFile; 50 private final Map<String, JType> functionalTypes; 51 private final Set<String> resolutionRoots; 52 private int serialNo; 53 54 public TypeDictionary(HeaderResolver resolver, HeaderFile headerFile) { 55 this.resolver = resolver; 56 this.headerFile = headerFile; 57 functionalTypes = new HashMap<>(); 58 resolutionRoots = new HashSet<>(); 59 } 60 61 private int serialNo() { 62 return ++serialNo; 63 } 64 65 private String recordOwnerClass(Type t) { 66 try { 67 //try resolve globally 68 Path p = t.getDeclarationCursor().getSourceLocation().getFileLocation().path(); 69 HeaderFile hf = resolver.headerFor(p); 70 return Utils.toInternalName(hf.pkgName, hf.headerClsName); 71 } catch (Throwable ex) { 72 //fallback: resolve locally. This can happen for two reasons: (i) the symbol to be resolved is a builtin 73 //symbol (e.g. no header file has its definition), or (ii) when the declaration cursor points to an header file 74 //not previously seen by Context. 75 return headerClass(); 76 } 77 } 78 79 private String headerClass() { 80 return Utils.toInternalName(headerFile.pkgName, headerFile.headerClsName); 81 } 82 83 public Stream<JType> functionalInterfaces() { 84 return functionalTypes.entrySet().stream() 85 .map(Map.Entry::getValue); 86 } 87 88 public Stream<JType.ClassType> resolutionRoots() { 89 return resolutionRoots.stream() 90 .filter(root -> !root.equals(headerClass())) 91 .map(JType.ClassType::new); 92 } 93 94 /** 95 * @param t 96 * @return 97 */ 98 private JType getInternal(Type t, Function<JType.Function, JType> funcResolver) { 99 switch(t.kind()) { 100 case Void: 101 return JType.Void; 102 // signed integer 103 case Char_S: 104 case SChar: 105 case Short: 106 case Int: 107 case Long: 108 case LongLong: 109 case Int128: 110 // unsigned integer, size-compatible at groveller level 111 // accomodate value-range needed at civilizer level 112 case UShort: 113 case UInt: 114 case UInt128: 115 case ULong: 116 case ULongLong: 117 case Char_U: 118 case UChar: 119 long size = t.size(); 120 if (size <= 1) { 121 return JType.Byte; 122 } else if (size <= 2) { 123 return JType.Short; 124 } else if (size <= 4) { 125 return JType.Int; 126 } else if (size <= 8) { 127 return JType.Long; 128 } else { 129 return JType.of(BigInteger.class); 130 } 131 case WChar: 132 case Char16: 133 return JType.Char; 134 case Bool: 135 return JType.Bool; 136 case Double: 137 case LongDouble: 138 return JType.Double; 139 case Float: 140 return JType.Float; 141 case Unexposed: 142 case Elaborated: 143 return getInternal(t.canonicalType(), funcResolver); 144 case ConstantArray: 145 case IncompleteArray: 146 return new JType.ArrayType(getInternal(t.getElementType(), funcResolver)); 147 case FunctionProto: 148 case FunctionNoProto: 149 JType[] args = new JType[t.numberOfArgs()]; 150 for (int i = 0; i < args.length; i++) { 151 // argument could be function pointer declared locally 152 JType arg = getInternal(t.argType(i), funcResolver); 153 if(arg instanceof JType.Function) { 154 // interpret function types in parameters as function pointers 155 arg = JType.GenericType.ofCallback(funcResolver.apply((JType.Function) arg)); 156 } 157 args[i] = arg; 158 } 159 return new JType.Function(Utils.getFunction(t), t.isVariadic(), getInternal(t.resultType(), funcResolver), args); 160 case Enum: { 161 return JType.Int; 162 } 163 case Invalid: 164 throw new IllegalArgumentException("Invalid type"); 165 case Record: { 166 String name = Utils.toClassName(Utils.getName(t)); 167 String owner = recordOwnerClass(t); 168 resolutionRoots.add(owner); 169 return new JType.ClassType(owner, name); 170 } 171 case Pointer: { 172 JType jt = getInternal(t.getPointeeType().canonicalType(), funcResolver); 173 if (jt instanceof JType.Function) { 174 jt = funcResolver.apply((JType.Function) jt); 175 return JType.GenericType.ofCallback(jt); 176 } else { 177 return JType.GenericType.ofPointer(jt); 178 } 179 } 180 case Typedef: { 181 Type truetype = t.canonicalType(); 182 return getInternal(truetype, funcResolver); 183 } 184 case BlockPointer: 185 // FIXME: what is BlockPointer? A FunctionalPointer as this is closure 186 JType jt = getInternal(t.getPointeeType(), funcResolver); 187 jt = funcResolver.apply((JType.Function)jt); 188 return JType.GenericType.ofCallback(jt); 189 case Complex: 190 TypeKind ek = t.getElementType().kind(); 191 if (ek == TypeKind.Float) { 192 return JType.of(FloatComplex.class); 193 } else if (ek == TypeKind.Double) { 194 return JType.of(DoubleComplex.class); 195 } else if (ek == TypeKind.LongDouble) { 196 return JType.of(LongDoubleComplex.class); 197 } else { 198 throw new UnsupportedOperationException("_Complex kind " + ek + " not supported"); 199 } 200 case Vector: 201 switch ((int) t.size()) { 202 case 8: 203 return JType.Long; 204 case 16: 205 case 32: 206 case 64: 207 default: 208 throw new UnsupportedOperationException("Support for vector size: " + t.size()); 209 } 210 default: 211 throw new IllegalStateException("Unexpected type:" + t.kind()); 212 } 213 } 214 215 public JType enterIfAbsent(Type t) { 216 return getInternal(t, this::enterFunctionIfNeeded); 217 } 218 219 //where 220 private JType enterFunctionIfNeeded(JType.Function f) { 221 return functionalTypes.computeIfAbsent(f.getNativeDescriptor(), _unused -> 222 new JType.FunctionalInterfaceType(headerClass(), "FI" + serialNo(), f)); 223 } 224 225 public JType lookup(Type t) { 226 return getInternal(t, this::lookupFunction); 227 } 228 229 //where 230 private JType lookupFunction(JType.Function f) { 231 return Optional.ofNullable(functionalTypes.get(f.getNativeDescriptor())) 232 .orElseThrow(IllegalStateException::new); 233 } 234 }