< prev index next >

src/jdk.jextract/share/classes/com/sun/tools/jextract/TypeDictionary.java

Print this page




  33 import java.math.BigDecimal;
  34 import java.math.BigInteger;
  35 import java.nicl.metadata.NativeType;
  36 import java.nio.file.Files;
  37 import java.nio.file.Path;
  38 import java.util.HashMap;
  39 import java.util.Map;
  40 import java.util.concurrent.atomic.AtomicInteger;
  41 import java.util.function.Function;
  42 import java.util.jar.JarEntry;
  43 import java.util.jar.JarInputStream;
  44 import java.util.logging.Logger;
  45 import java.util.stream.Stream;
  46 
  47 import static java.nio.file.StandardOpenOption.READ;
  48 
  49 /**
  50  * A dictionary that find Java type for a given native type.
  51  * Each instance of TypeDictionary presents types for a given java package.
  52  */
  53 public final class TypeDictionary {
  54     // package name to TypeDictionary
  55     final static Map<String, TypeDictionary> tdMap;
  56     final Logger logger = Logger.getLogger(getClass().getPackage().getName());
  57 
  58     final String pkgName;
  59     // clang.Type.spelling() to java type
  60     final Map<String, JType> typeMap;
  61 
  62     static {
  63         tdMap = new HashMap<>();
  64     }
  65 
  66     final AtomicInteger serialNo;
  67 
  68     private int serialNo() {
  69         return serialNo.incrementAndGet();
  70     }
  71 
  72     private TypeDictionary(String pkg) {
  73         pkgName = pkg;
  74         typeMap = new HashMap<>();
  75         serialNo = new AtomicInteger();

  76     }
  77 
  78     public static TypeDictionary of(String pkg) {
  79         return tdMap.computeIfAbsent(pkg, TypeDictionary::new);
  80     }
  81 /*
  82     public static boolean addType(Type t, Class<?> cls) {
  83         if (cls.isAnnotation() || cls.isArray()) {
  84             throw new IllegalArgumentException();
  85         }
  86 
  87         String pkg = cls.getPackage().getName();
  88         TypeDictionary dict = TypeDictionary.of(pkg);
  89 
  90         String type = t.spelling();
  91         return dict.addWithClass(type, cls);
  92     }
  93 
  94     boolean addType(String type, Class<?> cls) {
  95         String pkg = cls.getPackage().getName();
  96         // Class must be in this or sub packages
  97         if (! pkg.startsWith(pkgName)) {
  98             return false;
  99         }
 100         return addWithClass(type, cls);
 101     }
 102 
 103     private boolean addWithClass(String type, Class<?> cls) {
 104         assert(! cls.isArray());
 105         assert(! cls.isAnnotation());
 106 
 107         return (null == typeMap.putIfAbsent(type, JType.of(cls)));
 108     }
 109 */
 110 
 111     static class JarClassStreamer extends ClassLoader {

 112         private final HashMap<String, byte[]> bytecodes = new HashMap<>();
 113 
 114         JarClassStreamer(Path jar) {

 115             try (JarInputStream jis = new JarInputStream(Files.newInputStream(jar, READ))) {
 116                 // List all classes in the jar
 117                 for (JarEntry e = jis.getNextJarEntry(); e != null; e = jis.getNextJarEntry()) {
 118                     if (e.isDirectory()) {
 119                         jis.closeEntry();
 120                         continue;
 121                     }
 122                     String name = e.getName();
 123                     if (! name.endsWith(".class")) {
 124                         // Should not have file not class files
 125                         Context.getInstance().err.println("Warning: unexpected file " + name);
 126                     }
 127                     name = name.substring(0, name.length() - 6);
 128                     byte[] buf = new byte[4096];
 129                     ByteArrayOutputStream bos = new ByteArrayOutputStream();
 130                     int n;
 131                     while ((n = jis.read(buf)) > -1) {
 132                         bos.write(buf, 0, n);
 133                     }
 134                     bytecodes.put(name.replace(File.separatorChar, '.'), bos.toByteArray());
 135                 }
 136             } catch (IOException ioe) {
 137                 Context.getInstance().err.println("Failed to load types from jar file: " + jar.toString());
 138             }
 139         }
 140 
 141         public Stream<Class<?>> stream() {
 142             return bytecodes.entrySet().stream()
 143                     .map(e -> {
 144                         byte[] bytecode = e.getValue();
 145                         return defineClass(e.getKey(), bytecode, 0, bytecode.length);
 146                     });
 147         }
 148     }
 149 
 150     public static void loadJar(Path jar) {
 151         JarClassStreamer cl = new JarClassStreamer(jar);
 152         cl.stream().forEach(cls -> {
 153             Package pkg = cls.getPackage();
 154             TypeDictionary dict = TypeDictionary.of(pkg.getName());
 155             NativeType nt = cls.getAnnotation(NativeType.class);
 156             dict.typeMap.putIfAbsent(nt.ctype(), JType.of(cls));
 157         });
 158     }
 159 
 160     private static JType checkPrimitive(Type t) {
 161         switch (t.kind()) {
 162             case Void:
 163                 return JType.Void;
 164             // signed integer
 165             case Char_S:
 166             case SChar:
 167             case Short:
 168             case Int:
 169             case Long:
 170             case LongLong:
 171             case Int128:
 172             // unsigned integer, size-compatible at groveller level
 173             // accomodate value-range needed at civilizer level
 174             case UShort:


 200             case Float:
 201                 return JType.Float;
 202             case LongDouble:
 203                 return JType.of(BigDecimal.class);
 204         }
 205         return null;
 206     }
 207 
 208     private JType exist(Type t) {
 209         JType jt = checkPrimitive(t);
 210         if (jt == null) {
 211             jt = typeMap.get(t.spelling());
 212         }
 213         return jt;
 214     }
 215 
 216     /**
 217      * @param t
 218      * @return
 219      */
 220     public final JType get(Type t) {
 221         JType jt;
 222 
 223         switch(t.kind()) {
 224             case Unexposed:
 225                 // Always look at canonical type
 226                 jt = get(t.canonicalType());
 227                 break;
 228             case ConstantArray:
 229                 // Array of element type
 230                 jt = get(t.getElementType());
 231                 if (jt != null) {
 232                     jt = new JType.Array(jt);
 233                 }
 234                 break;
 235             case IncompleteArray:
 236                 jt = get(t.getElementType());
 237                 if (jt != null) {
 238                     jt = new PointerType(jt);
 239                 }
 240                 break;


 260                     case 32:
 261                     case 64:
 262                     default:
 263                         throw new UnsupportedOperationException("Support for vector size: " + t.size());
 264                 }
 265                 break;
 266             default:
 267                 jt = exist(t);
 268         }
 269 
 270         if (null == jt) {
 271             logger.fine(() -> "Cannot find type for " + t.spelling());
 272         } else {
 273             final JType finalJt = jt;
 274             logger.fine(() -> "Found type " + finalJt.getDescriptor() + " for " + t.spelling());
 275             jt = (jt instanceof JType2) ? jt : JType2.bind(jt, t, t.getDeclarationCursor());
 276         }
 277         return jt;
 278     }
 279 
 280     public final JType computeIfAbsent(Type t, Function<Type, JType> fn) {
 281         JType jt = get(t);
 282         if (jt != null) {
 283             return jt;
 284         }
 285 
 286         // avoid nested call of computeAbsent as fn is likely to define a type
 287         jt = fn.apply(t);
 288         JType rv = typeMap.putIfAbsent(t.spelling(), jt);
 289         // should we be alert in this situation?
 290         return (rv == null) ? jt : rv;
 291     }
 292 
 293     /**
 294      * Look up a type in this instance first, if cannot find it, try to
 295      * look into the origin(declaring) TypeDictionary.
 296      * @param t
 297      * @return
 298      * @throws com.sun.tools.jextract.TypeDictionary.NotDeclaredException
 299      */
 300     public final JType lookup(Type t) throws NotDeclaredException {
 301         JType jt = get(t);
 302         if (jt == null && t.kind() != TypeKind.Pointer) {
 303             // Pointer type need to check with pointee type, as the declaration
 304             // might still be in same TypeDictionary
 305             Cursor c = t.getDeclarationCursor();
 306             if (c.isInvalid()) {
 307                 logger.info(() -> "Type " + t.spelling() + " has invalid declaration cursor.");
 308                 logger.fine(() -> Printer.Stringifier(p -> p.dumpType(t)));
 309                 throw new NotDeclaredException(t);
 310             }
 311             jt = Context.getInstance().getJType(t.getDeclarationCursor());
 312         }
 313         return jt;
 314     }
 315 
 316     static class NotDeclaredException extends RuntimeException {
 317         private static final long serialVersionUID = -1L;
 318 
 319         private final Type type;
 320 
 321         public NotDeclaredException(Type t) {
 322             type = t;
 323         }
 324 
 325         public final Type getType() { return type; }
 326     }
 327 }


  33 import java.math.BigDecimal;
  34 import java.math.BigInteger;
  35 import java.nicl.metadata.NativeType;
  36 import java.nio.file.Files;
  37 import java.nio.file.Path;
  38 import java.util.HashMap;
  39 import java.util.Map;
  40 import java.util.concurrent.atomic.AtomicInteger;
  41 import java.util.function.Function;
  42 import java.util.jar.JarEntry;
  43 import java.util.jar.JarInputStream;
  44 import java.util.logging.Logger;
  45 import java.util.stream.Stream;
  46 
  47 import static java.nio.file.StandardOpenOption.READ;
  48 
  49 /**
  50  * A dictionary that find Java type for a given native type.
  51  * Each instance of TypeDictionary presents types for a given java package.
  52  */
  53 final class TypeDictionary {
  54     private final Logger logger = Logger.getLogger(getClass().getPackage().getName());
  55     private Context ctx;
  56     private final String pkgName;


  57     // clang.Type.spelling() to java type
  58     private final Map<String, JType> typeMap;
  59     private final AtomicInteger serialNo;





  60 
  61     private int serialNo() {
  62         return serialNo.incrementAndGet();
  63     }
  64 
  65     TypeDictionary(Context ctx, String pkg) {
  66         this.ctx = ctx;
  67         this.pkgName = pkg;
  68         this.typeMap = new HashMap<>();
  69         this.serialNo = new AtomicInteger();
  70     }
  71 



  72 /*
  73     public static boolean addType(Context ctx, Type t, Class<?> cls) {
  74         if (cls.isAnnotation() || cls.isArray()) {
  75             throw new IllegalArgumentException();
  76         }
  77 
  78         String pkg = cls.getPackage().getName();
  79         TypeDictionary dict = ctx.typeDictionaryFor(pkg);
  80 
  81         String type = t.spelling();
  82         return dict.addWithClass(type, cls);
  83     }
  84 
  85     boolean addType(String type, Class<?> cls) {
  86         String pkg = cls.getPackage().getName();
  87         // Class must be in this or sub packages
  88         if (! pkg.startsWith(pkgName)) {
  89             return false;
  90         }
  91         return addWithClass(type, cls);
  92     }
  93 
  94     private boolean addWithClass(String type, Class<?> cls) {
  95         assert(! cls.isArray());
  96         assert(! cls.isAnnotation());
  97 
  98         return (null == typeMap.putIfAbsent(type, JType.of(cls)));
  99     }
 100 */
 101 
 102     static class JarClassStreamer extends ClassLoader {
 103         private final Context ctx;
 104         private final HashMap<String, byte[]> bytecodes = new HashMap<>();
 105 
 106         JarClassStreamer(Context ctx, Path jar) {
 107             this.ctx = ctx;
 108             try (JarInputStream jis = new JarInputStream(Files.newInputStream(jar, READ))) {
 109                 // List all classes in the jar
 110                 for (JarEntry e = jis.getNextJarEntry(); e != null; e = jis.getNextJarEntry()) {
 111                     if (e.isDirectory()) {
 112                         jis.closeEntry();
 113                         continue;
 114                     }
 115                     String name = e.getName();
 116                     if (! name.endsWith(".class")) {
 117                         // Should not have file not class files
 118                         ctx.err.println("Warning: unexpected file " + name);
 119                     }
 120                     name = name.substring(0, name.length() - 6);
 121                     byte[] buf = new byte[4096];
 122                     ByteArrayOutputStream bos = new ByteArrayOutputStream();
 123                     int n;
 124                     while ((n = jis.read(buf)) > -1) {
 125                         bos.write(buf, 0, n);
 126                     }
 127                     bytecodes.put(name.replace(File.separatorChar, '.'), bos.toByteArray());
 128                 }
 129             } catch (IOException ioe) {
 130                 ctx.err.println("Failed to load types from jar file: " + jar.toString());
 131             }
 132         }
 133 
 134         public Stream<Class<?>> stream() {
 135             return bytecodes.entrySet().stream()
 136                     .map(e -> {
 137                         byte[] bytecode = e.getValue();
 138                         return defineClass(e.getKey(), bytecode, 0, bytecode.length);
 139                     });
 140         }
 141     }
 142 
 143     void loadJar(Path jar) {
 144         JarClassStreamer cl = new JarClassStreamer(ctx, jar);
 145         cl.stream().forEach(cls -> {
 146             Package pkg = cls.getPackage();
 147             TypeDictionary dict = ctx.typeDictionaryFor(pkg.getName());
 148             NativeType nt = cls.getAnnotation(NativeType.class);
 149             dict.typeMap.putIfAbsent(nt.ctype(), JType.of(cls));
 150         });
 151     }
 152 
 153     private static JType checkPrimitive(Type t) {
 154         switch (t.kind()) {
 155             case Void:
 156                 return JType.Void;
 157             // signed integer
 158             case Char_S:
 159             case SChar:
 160             case Short:
 161             case Int:
 162             case Long:
 163             case LongLong:
 164             case Int128:
 165             // unsigned integer, size-compatible at groveller level
 166             // accomodate value-range needed at civilizer level
 167             case UShort:


 193             case Float:
 194                 return JType.Float;
 195             case LongDouble:
 196                 return JType.of(BigDecimal.class);
 197         }
 198         return null;
 199     }
 200 
 201     private JType exist(Type t) {
 202         JType jt = checkPrimitive(t);
 203         if (jt == null) {
 204             jt = typeMap.get(t.spelling());
 205         }
 206         return jt;
 207     }
 208 
 209     /**
 210      * @param t
 211      * @return
 212      */
 213     final JType get(Type t) {
 214         JType jt;
 215 
 216         switch(t.kind()) {
 217             case Unexposed:
 218                 // Always look at canonical type
 219                 jt = get(t.canonicalType());
 220                 break;
 221             case ConstantArray:
 222                 // Array of element type
 223                 jt = get(t.getElementType());
 224                 if (jt != null) {
 225                     jt = new JType.Array(jt);
 226                 }
 227                 break;
 228             case IncompleteArray:
 229                 jt = get(t.getElementType());
 230                 if (jt != null) {
 231                     jt = new PointerType(jt);
 232                 }
 233                 break;


 253                     case 32:
 254                     case 64:
 255                     default:
 256                         throw new UnsupportedOperationException("Support for vector size: " + t.size());
 257                 }
 258                 break;
 259             default:
 260                 jt = exist(t);
 261         }
 262 
 263         if (null == jt) {
 264             logger.fine(() -> "Cannot find type for " + t.spelling());
 265         } else {
 266             final JType finalJt = jt;
 267             logger.fine(() -> "Found type " + finalJt.getDescriptor() + " for " + t.spelling());
 268             jt = (jt instanceof JType2) ? jt : JType2.bind(jt, t, t.getDeclarationCursor());
 269         }
 270         return jt;
 271     }
 272 
 273     final JType computeIfAbsent(Type t, Function<Type, JType> fn) {
 274         JType jt = get(t);
 275         if (jt != null) {
 276             return jt;
 277         }
 278 
 279         // avoid nested call of computeAbsent as fn is likely to define a type
 280         jt = fn.apply(t);
 281         JType rv = typeMap.putIfAbsent(t.spelling(), jt);
 282         // should we be alert in this situation?
 283         return (rv == null) ? jt : rv;
 284     }
 285 
 286     /**
 287      * Look up a type in this instance first, if cannot find it, try to
 288      * look into the origin(declaring) TypeDictionary.
 289      * @param t
 290      * @return
 291      * @throws com.sun.tools.jextract.TypeDictionary.NotDeclaredException
 292      */
 293     final JType lookup(Type t) throws NotDeclaredException {
 294         JType jt = get(t);
 295         if (jt == null && t.kind() != TypeKind.Pointer) {
 296             // Pointer type need to check with pointee type, as the declaration
 297             // might still be in same TypeDictionary
 298             Cursor c = t.getDeclarationCursor();
 299             if (c.isInvalid()) {
 300                 logger.info(() -> "Type " + t.spelling() + " has invalid declaration cursor.");
 301                 logger.fine(() -> Printer.Stringifier(p -> p.dumpType(t)));
 302                 throw new NotDeclaredException(t);
 303             }
 304             jt = ctx.getJType(t.getDeclarationCursor());
 305         }
 306         return jt;
 307     }
 308 
 309     static class NotDeclaredException extends RuntimeException {
 310         private static final long serialVersionUID = -1L;
 311 
 312         private final Type type;
 313 
 314         public NotDeclaredException(Type t) {
 315             type = t;
 316         }
 317 
 318         public final Type getType() { return type; }
 319     }
 320 }
< prev index next >