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 }
|