149 throws IOException {
150 cw.visitEnd();
151 byte[] bytecodes = cw.toByteArray();
152 if (null != types.put(clsName, bytecodes)) {
153 logger.warning("Class " + clsName + " definition is overwritten");
154 }
155 }
156
157 private static boolean isBitField(Tree tree) {
158 return tree instanceof FieldTree && ((FieldTree)tree).isBitField();
159 }
160
161 /**
162 *
163 * @param cw ClassWriter for the struct
164 * @param tree The Tree
165 * @param parentType The struct type
166 */
167 private void addField(ClassVisitor cw, Tree tree, Type parentType) {
168 String fieldName = tree.name();
169 if (fieldName.isEmpty()) {
170 //skip anon fields
171 return;
172 }
173 Type type = tree.type();
174 JType jt = owner.globalLookup(type);
175 assert (jt != null);
176 if (cw == global_cw) {
177 String uniqueName = fieldName + "." + jt.getDescriptor();
178 if (! global_fields.add(uniqueName)) {
179 return; // added already
180 }
181 }
182 MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_ABSTRACT, fieldName + "$get",
183 "()" + jt.getDescriptor(), "()" + jt.getSignature(), null);
184
185 AnnotationVisitor av = mv.visitAnnotation(NATIVE_LOCATION, true);
186 SourceLocation src = tree.location();
187 SourceLocation.Location loc = src.getFileLocation();
188 Path p = loc.path();
189 av.visit("file", p == null ? "builtin" : p.toAbsolutePath().toString());
190 av.visit("line", loc.line());
191 av.visit("column", loc.column());
192 av.visit("USR", tree.USR());
217 }
218
219 private void addConstant(ClassVisitor cw, FieldTree fieldTree) {
220 assert (fieldTree.isEnumConstant());
221 String name = fieldTree.name();
222 String desc = owner.globalLookup(fieldTree.type()).getDescriptor();
223 Object value = null;
224 switch (desc) {
225 case "J":
226 value = fieldTree.enumConstant().get();
227 break;
228 case "I":
229 value = fieldTree.enumConstant().get().intValue();
230 break;
231 }
232 cw.visitField(ACC_PUBLIC | ACC_FINAL | ACC_STATIC, name, desc, null, value);
233 }
234
235 @Override
236 public Void visitStruct(StructTree structTree, JType jt) {
237 String nativeName = structTree.identifier();
238 Type type = structTree.type();
239 logger.fine(() -> "Create struct: " + nativeName);
240
241 String intf = Utils.toClassName(nativeName);
242 String name = internal_name + "$" + intf;
243
244 logger.fine(() -> "Define class " + name + " for native type " + nativeName);
245 /* FIXME: Member interface is implicit static, also ASM.CheckClassAdapter is not
246 * taking static as a valid flag, so comment this out during development.
247 */
248 global_cw.visitInnerClass(name, internal_name, intf, ACC_PUBLIC | ACC_STATIC | ACC_ABSTRACT | ACC_INTERFACE);
249 ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
250 cw.visit(V1_8, ACC_PUBLIC /*| ACC_STATIC*/ | ACC_INTERFACE | ACC_ABSTRACT,
251 name, "Ljava/lang/Object;Ljava/foreign/memory/Struct<L" + name + ";>;",
252 "java/lang/Object", new String[] {"java/foreign/memory/Struct"});
253 annotateNativeLocation(cw, structTree);
254
255 AnnotationVisitor av = cw.visitAnnotation(NATIVE_STRUCT, true);
256 Layout structLayout = structTree.layout(this::decorateAsAccessor);
257 av.visit("value", structLayout.toString());
288 }
289 return layout;
290 }
291
292 @Override
293 public Void visitEnum(EnumTree enumTree, JType jt) {
294 // define enum constants in global_cw
295 enumTree.constants().forEach(constant -> addConstant(global_cw, constant));
296
297 if (enumTree.name().isEmpty()) {
298 // We are done with anonymous enum
299 return null;
300 }
301
302 // generate annotation class for named enum
303 createAnnotationCls(enumTree);
304 return null;
305 }
306
307 private void createAnnotationCls(Tree tree) {
308 String nativeName = tree.identifier();
309 logger.fine(() -> "Create annotation for: " + nativeName);
310
311 String intf = Utils.toClassName(nativeName);
312 String name = internal_name + "$" + intf;
313
314 logger.fine(() -> "Define class " + name + " for native type " + nativeName);
315 global_cw.visitInnerClass(name, internal_name, intf,
316 ACC_PUBLIC | ACC_STATIC | ACC_ABSTRACT | ACC_INTERFACE | ACC_ANNOTATION);
317 ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
318 String[] superAnno = { "java/lang/annotation/Annotation" };
319 cw.visit(V1_8, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE | ACC_ANNOTATION,
320 name, null, "java/lang/Object", superAnno);
321 annotateNativeLocation(cw, tree);
322 Type type = tree.type().canonicalType();
323 AnnotationVisitor av = cw.visitAnnotation("Ljava/lang/annotation/Target;", true);
324 av.visitEnum("value", "Ljava/lang/annotation/ElementType;", "TYPE_USE");
325 av.visitEnd();
326 av = cw.visitAnnotation("Ljava/lang/annotation/Retention;", true);
327 av.visitEnum("value", "Ljava/lang/annotation/RetentionPolicy;", "RUNTIME");
328 av.visitEnd();
329 cw.visitInnerClass(name, internal_name, intf,
330 ACC_PUBLIC | ACC_STATIC | ACC_ABSTRACT | ACC_INTERFACE | ACC_ANNOTATION);
331 // Write class
332 try {
333 writeClassFile(cw, owner.clsName + "$" + intf);
334 } catch (IOException ex) {
335 handleException(ex);
336 }
337 }
338
339 private void createFunctionalInterface(Tree tree, JType.FnIf fnif) {
340 JType.Function fn = fnif.getFunction();
341 String intf;
342 String nativeName;
343 String nDesc = fnif.getFunction().getNativeDescriptor();
344 if (tree == null) {
345 intf = ((JType.InnerType) fnif.type).getName();
346 nativeName = "anonymous function";
347 } else {
348 nativeName = tree.identifier();
349 intf = Utils.toClassName(nativeName);
350 }
351 logger.fine(() -> "Create FunctionalInterface " + intf);
352
353 final String name = internal_name + "$" + intf;
354
355 logger.fine(() -> "Define class " + name + " for native type " + nativeName + nDesc);
356 global_cw.visitInnerClass(name, internal_name, intf, ACC_PUBLIC | ACC_STATIC | ACC_ABSTRACT | ACC_INTERFACE);
357 ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
358 cw.visit(V1_8, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE,
359 name, "Ljava/lang/Object;",
360 "java/lang/Object", new String[0]);
361 if (tree != null) {
362 annotateNativeLocation(cw, tree);
363 }
364 AnnotationVisitor av = cw.visitAnnotation(
365 "Ljava/lang/FunctionalInterface;", true);
366 av.visitEnd();
367 av = cw.visitAnnotation(NATIVE_CALLBACK, true);
368 av.visit("value", nDesc);
371
372 // add the method
373
374 int flags = ACC_PUBLIC | ACC_ABSTRACT;
375 if (fn.isVarArgs) {
376 flags |= ACC_VARARGS;
377 }
378 MethodVisitor mv = cw.visitMethod(flags, "fn",
379 fn.getDescriptor(), fn.getSignature(), null);
380 mv.visitEnd();
381 // Write class
382 try {
383 writeClassFile(cw, owner.clsName + "$" + intf);
384 } catch (IOException ex) {
385 handleException(ex);
386 }
387 }
388
389 @Override
390 public Void visitTypedef(TypedefTree typedefTree, JType jt) {
391 Type t = typedefTree.type();
392 if (t.canonicalType().kind() == TypeKind.Enum &&
393 t.spelling().equals(t.canonicalType().getDeclarationCursor().spelling())) {
394 logger.fine("Skip redundant typedef " + t.spelling());
395 return null;
396 }
397
398 // anonymous typedef struct {} xxx will not get TypeAlias
399 if (jt instanceof TypeAlias) {
400 TypeAlias alias = (TypeAlias) jt;
401 if (alias.getAnnotationDescriptor() != null) {
402 createAnnotationCls(typedefTree);
403 } else {
404 JType real = alias.canonicalType();
405 if (real instanceof JType.FnIf) {
406 createFunctionalInterface(typedefTree, (JType.FnIf) real);
407 }
408 // Otherwise, type alias is a same named stuct
409 }
410 }
411 return null;
412 }
413
414 @Override
415 public Void visitTree(Tree tree, JType jt) {
416 logger.warning(() -> "Unsupported declaration tree:");
417 logger.warning(() -> tree.toString());
|
149 throws IOException {
150 cw.visitEnd();
151 byte[] bytecodes = cw.toByteArray();
152 if (null != types.put(clsName, bytecodes)) {
153 logger.warning("Class " + clsName + " definition is overwritten");
154 }
155 }
156
157 private static boolean isBitField(Tree tree) {
158 return tree instanceof FieldTree && ((FieldTree)tree).isBitField();
159 }
160
161 /**
162 *
163 * @param cw ClassWriter for the struct
164 * @param tree The Tree
165 * @param parentType The struct type
166 */
167 private void addField(ClassVisitor cw, Tree tree, Type parentType) {
168 String fieldName = tree.name();
169 assert !fieldName.isEmpty();
170 Type type = tree.type();
171 JType jt = owner.globalLookup(type);
172 assert (jt != null);
173 if (cw == global_cw) {
174 String uniqueName = fieldName + "." + jt.getDescriptor();
175 if (! global_fields.add(uniqueName)) {
176 return; // added already
177 }
178 }
179 MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_ABSTRACT, fieldName + "$get",
180 "()" + jt.getDescriptor(), "()" + jt.getSignature(), null);
181
182 AnnotationVisitor av = mv.visitAnnotation(NATIVE_LOCATION, true);
183 SourceLocation src = tree.location();
184 SourceLocation.Location loc = src.getFileLocation();
185 Path p = loc.path();
186 av.visit("file", p == null ? "builtin" : p.toAbsolutePath().toString());
187 av.visit("line", loc.line());
188 av.visit("column", loc.column());
189 av.visit("USR", tree.USR());
214 }
215
216 private void addConstant(ClassVisitor cw, FieldTree fieldTree) {
217 assert (fieldTree.isEnumConstant());
218 String name = fieldTree.name();
219 String desc = owner.globalLookup(fieldTree.type()).getDescriptor();
220 Object value = null;
221 switch (desc) {
222 case "J":
223 value = fieldTree.enumConstant().get();
224 break;
225 case "I":
226 value = fieldTree.enumConstant().get().intValue();
227 break;
228 }
229 cw.visitField(ACC_PUBLIC | ACC_FINAL | ACC_STATIC, name, desc, null, value);
230 }
231
232 @Override
233 public Void visitStruct(StructTree structTree, JType jt) {
234 String nativeName = structTree.name();
235 Type type = structTree.type();
236 logger.fine(() -> "Create struct: " + nativeName);
237
238 String intf = Utils.toClassName(nativeName);
239 String name = internal_name + "$" + intf;
240
241 logger.fine(() -> "Define class " + name + " for native type " + nativeName);
242 /* FIXME: Member interface is implicit static, also ASM.CheckClassAdapter is not
243 * taking static as a valid flag, so comment this out during development.
244 */
245 global_cw.visitInnerClass(name, internal_name, intf, ACC_PUBLIC | ACC_STATIC | ACC_ABSTRACT | ACC_INTERFACE);
246 ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
247 cw.visit(V1_8, ACC_PUBLIC /*| ACC_STATIC*/ | ACC_INTERFACE | ACC_ABSTRACT,
248 name, "Ljava/lang/Object;Ljava/foreign/memory/Struct<L" + name + ";>;",
249 "java/lang/Object", new String[] {"java/foreign/memory/Struct"});
250 annotateNativeLocation(cw, structTree);
251
252 AnnotationVisitor av = cw.visitAnnotation(NATIVE_STRUCT, true);
253 Layout structLayout = structTree.layout(this::decorateAsAccessor);
254 av.visit("value", structLayout.toString());
285 }
286 return layout;
287 }
288
289 @Override
290 public Void visitEnum(EnumTree enumTree, JType jt) {
291 // define enum constants in global_cw
292 enumTree.constants().forEach(constant -> addConstant(global_cw, constant));
293
294 if (enumTree.name().isEmpty()) {
295 // We are done with anonymous enum
296 return null;
297 }
298
299 // generate annotation class for named enum
300 createAnnotationCls(enumTree);
301 return null;
302 }
303
304 private void createAnnotationCls(Tree tree) {
305 String nativeName = tree.name();
306 logger.fine(() -> "Create annotation for: " + nativeName);
307
308 String intf = Utils.toClassName(nativeName);
309 String name = internal_name + "$" + intf;
310
311 logger.fine(() -> "Define class " + name + " for native type " + nativeName);
312 global_cw.visitInnerClass(name, internal_name, intf,
313 ACC_PUBLIC | ACC_STATIC | ACC_ABSTRACT | ACC_INTERFACE | ACC_ANNOTATION);
314 ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
315 String[] superAnno = { "java/lang/annotation/Annotation" };
316 cw.visit(V1_8, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE | ACC_ANNOTATION,
317 name, null, "java/lang/Object", superAnno);
318 annotateNativeLocation(cw, tree);
319 Type type = tree.type().canonicalType();
320 AnnotationVisitor av = cw.visitAnnotation("Ljava/lang/annotation/Target;", true);
321 av.visitEnum("value", "Ljava/lang/annotation/ElementType;", "TYPE_USE");
322 av.visitEnd();
323 av = cw.visitAnnotation("Ljava/lang/annotation/Retention;", true);
324 av.visitEnum("value", "Ljava/lang/annotation/RetentionPolicy;", "RUNTIME");
325 av.visitEnd();
326 cw.visitInnerClass(name, internal_name, intf,
327 ACC_PUBLIC | ACC_STATIC | ACC_ABSTRACT | ACC_INTERFACE | ACC_ANNOTATION);
328 // Write class
329 try {
330 writeClassFile(cw, owner.clsName + "$" + intf);
331 } catch (IOException ex) {
332 handleException(ex);
333 }
334 }
335
336 private void createFunctionalInterface(Tree tree, JType.FnIf fnif) {
337 JType.Function fn = fnif.getFunction();
338 String intf;
339 String nativeName;
340 String nDesc = fnif.getFunction().getNativeDescriptor();
341 if (tree == null) {
342 intf = ((JType.InnerType) fnif.type).getName();
343 nativeName = "anonymous function";
344 } else {
345 nativeName = tree.name();
346 intf = Utils.toClassName(nativeName);
347 }
348 logger.fine(() -> "Create FunctionalInterface " + intf);
349
350 final String name = internal_name + "$" + intf;
351
352 logger.fine(() -> "Define class " + name + " for native type " + nativeName + nDesc);
353 global_cw.visitInnerClass(name, internal_name, intf, ACC_PUBLIC | ACC_STATIC | ACC_ABSTRACT | ACC_INTERFACE);
354 ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
355 cw.visit(V1_8, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE,
356 name, "Ljava/lang/Object;",
357 "java/lang/Object", new String[0]);
358 if (tree != null) {
359 annotateNativeLocation(cw, tree);
360 }
361 AnnotationVisitor av = cw.visitAnnotation(
362 "Ljava/lang/FunctionalInterface;", true);
363 av.visitEnd();
364 av = cw.visitAnnotation(NATIVE_CALLBACK, true);
365 av.visit("value", nDesc);
368
369 // add the method
370
371 int flags = ACC_PUBLIC | ACC_ABSTRACT;
372 if (fn.isVarArgs) {
373 flags |= ACC_VARARGS;
374 }
375 MethodVisitor mv = cw.visitMethod(flags, "fn",
376 fn.getDescriptor(), fn.getSignature(), null);
377 mv.visitEnd();
378 // Write class
379 try {
380 writeClassFile(cw, owner.clsName + "$" + intf);
381 } catch (IOException ex) {
382 handleException(ex);
383 }
384 }
385
386 @Override
387 public Void visitTypedef(TypedefTree typedefTree, JType jt) {
388 // anonymous typedef struct {} xxx will not get TypeAlias
389 if (jt instanceof TypeAlias) {
390 TypeAlias alias = (TypeAlias) jt;
391 if (alias.getAnnotationDescriptor() != null) {
392 createAnnotationCls(typedefTree);
393 } else {
394 JType real = alias.canonicalType();
395 if (real instanceof JType.FnIf) {
396 createFunctionalInterface(typedefTree, (JType.FnIf) real);
397 }
398 // Otherwise, type alias is a same named stuct
399 }
400 }
401 return null;
402 }
403
404 @Override
405 public Void visitTree(Tree tree, JType jt) {
406 logger.warning(() -> "Unsupported declaration tree:");
407 logger.warning(() -> tree.toString());
|