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