51
52 public AsmCodeFactory(HeaderFile header) {
53 logger.info(() -> "Instantiate AsmCodeFactory for " + header.path);
54 owner = header;
55 internal_name = Utils.toInternalName(owner.pkgName, owner.clsName);
56 global_cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
57 types = new HashMap<>();
58 init();
59 }
60
61 private void init() {
62 global_cw.visit(V1_8, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE,
63 internal_name,
64 null, "java/lang/Object", null);
65 AnnotationVisitor av = global_cw.visitAnnotation(
66 "Ljava/nicl/metadata/Header;", true);
67 av.visit("path", owner.path.toAbsolutePath().toString());
68 av.visitEnd();
69 }
70
71 private void annotateC(ClassVisitor cw, Cursor dcl) {
72 AnnotationVisitor av = cw.visitAnnotation(
73 "Ljava/nicl/metadata/C;", true);
74 SourceLocation src = dcl.getSourceLocation();
75 SourceLocation.Location loc = src.getFileLocation();
76 Path p = loc.path();
77 av.visit("file", p == null ? "builtin" : p.toAbsolutePath().toString());
78 av.visit("line", loc.line());
79 av.visit("column", loc.column());
80 av.visit("USR", dcl.USR());
81 av.visitEnd();
82 }
83
84 private void writeClassFile(final ClassWriter cw, String clsName)
85 throws IOException {
86 cw.visitEnd();
87 byte[] bytecodes = cw.toByteArray();
88 types.put(clsName, bytecodes);
89 }
90
186 "java/lang/Object", new String[] {"java/nicl/types/Reference"});
187 annotateC(cw, cursor);
188 AnnotationVisitor av = cw.visitAnnotation(
189 "Ljava/nicl/metadata/NativeType;", true);
190 av.visit("layout", Utils.getLayout(t));
191 av.visit("ctype", t.spelling());
192 av.visit("size", t.size());
193 av.visit("isRecordType", true);
194 av.visitEnd();
195 cw.visitInnerClass(name, internal_name, intf, ACC_PUBLIC | ACC_STATIC | ACC_ABSTRACT | ACC_INTERFACE);
196
197 // fields
198 Printer dbg = new Printer();
199 cursor.stream()
200 .filter(cx -> cx.kind() == CursorKind.FieldDecl)
201 .forEachOrdered(cx -> addField(cw, cx, cursor.type()));
202 // Write class
203 try {
204 writeClassFile(cw, owner.clsName + "$" + intf);
205 } catch (IOException ex) {
206 ex.printStackTrace(System.err);
207 }
208 }
209
210 private void createEnum(Cursor cursor) {
211 String nativeName = Utils.getIdentifier(cursor);
212 logger.fine(() -> "create enum: " + nativeName);
213
214 String intf = Utils.toClassName(nativeName);
215 String name = internal_name + "$" + intf;
216
217 logger.fine(() -> "Define class " + name + " for native type " + nativeName);
218 global_cw.visitInnerClass(name, internal_name, intf,
219 ACC_PUBLIC | ACC_STATIC | ACC_ABSTRACT | ACC_INTERFACE | ACC_ANNOTATION);
220 ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
221 String[] superAnno = { "java/lang/annotation/Annotation" };
222 cw.visit(V1_8, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE | ACC_ANNOTATION,
223 name, null, "java/lang/Object", superAnno);
224 annotateC(cw, cursor);
225 AnnotationVisitor av = cw.visitAnnotation(
226 "Ljava/nicl/metadata/NativeType;", true);
229 av.visit("ctype", t.spelling());
230 av.visit("size", t.size());
231 av.visitEnd();
232
233 av = cw.visitAnnotation("Ljava/lang/annotation/Target;", true);
234 av.visitEnum("value", "Ljava/lang/annotation/ElementType;", "TYPE_USE");
235 av.visitEnd();
236 av = cw.visitAnnotation("Ljava/lang/annotation/Retention;", true);
237 av.visitEnum("value", "Ljava/lang/annotation/RetentionPolicy;", "RUNTIME");
238 av.visitEnd();
239 cw.visitInnerClass(name, internal_name, intf,
240 ACC_PUBLIC | ACC_STATIC | ACC_ABSTRACT | ACC_INTERFACE | ACC_ANNOTATION);
241 // constants
242 cursor.stream()
243 .filter(cx -> cx.kind() == CursorKind.EnumConstantDecl)
244 .forEachOrdered(cx -> addConstant(cw, cx));
245 // Write class
246 try {
247 writeClassFile(cw, owner.clsName + "$" + intf);
248 } catch (IOException ex) {
249 ex.printStackTrace(System.err);
250 }
251 }
252
253 private void createAnnotationCls(Cursor dcl) {
254 String nativeName = Utils.getIdentifier(dcl);
255 logger.fine(() -> "Create annotation for: " + nativeName);
256
257 String intf = Utils.toClassName(nativeName);
258 String name = internal_name + "$" + intf;
259
260 logger.fine(() -> "Define class " + name + " for native type " + nativeName);
261 global_cw.visitInnerClass(name, internal_name, intf,
262 ACC_PUBLIC | ACC_STATIC | ACC_ABSTRACT | ACC_INTERFACE | ACC_ANNOTATION);
263 ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
264 String[] superAnno = { "java/lang/annotation/Annotation" };
265 cw.visit(V1_8, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE | ACC_ANNOTATION,
266 name, null, "java/lang/Object", superAnno);
267 annotateC(cw, dcl);
268 Type t = dcl.type().canonicalType();
269 AnnotationVisitor av = cw.visitAnnotation(
270 "Ljava/nicl/metadata/NativeType;", true);
271 av.visit("layout", Utils.getLayout(t));
272 av.visit("ctype", t.spelling());
273 av.visit("size", t.size());
274 av.visitEnd();
275
276 av = cw.visitAnnotation("Ljava/lang/annotation/Target;", true);
277 av.visitEnum("value", "Ljava/lang/annotation/ElementType;", "TYPE_USE");
278 av.visitEnd();
279 av = cw.visitAnnotation("Ljava/lang/annotation/Retention;", true);
280 av.visitEnum("value", "Ljava/lang/annotation/RetentionPolicy;", "RUNTIME");
281 av.visitEnd();
282 cw.visitInnerClass(name, internal_name, intf,
283 ACC_PUBLIC | ACC_STATIC | ACC_ABSTRACT | ACC_INTERFACE | ACC_ANNOTATION);
284 // Write class
285 try {
286 writeClassFile(cw, owner.clsName + "$" + intf);
287 } catch (IOException ex) {
288 ex.printStackTrace(System.err);
289 }
290 }
291
292 private void createFunctionalInterface(JType2 jt2) {
293 JType.FnIf fnif = (JType.FnIf) jt2.getDelegate();
294 JType.Function fn = fnif.getFunction();
295 String intf = ((JType.InnerType) fnif.type).getName();
296 logger.fine(() -> "Create FunctionalInterface " + intf);
297 String nDesc = jt2.getNativeDescriptor();
298
299 final String name = internal_name + "$" + intf;
300
301 logger.fine(() -> "Define class " + name + " for anonymous function " + nDesc);
302 global_cw.visitInnerClass(name, internal_name, intf, ACC_PUBLIC | ACC_STATIC | ACC_ABSTRACT | ACC_INTERFACE);
303 ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
304 cw.visit(V1_8, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE,
305 name, null, "java/lang/Object", null);
306 AnnotationVisitor av = cw.visitAnnotation(
307 "Ljava/lang/FunctionalInterface;", true);
308 av.visitEnd();
311 // add the method
312 MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_ABSTRACT, "fn",
313 fn.getDescriptor(), fn.getSignature(), null);
314 av = mv.visitAnnotation(
315 "Ljava/nicl/metadata/NativeType;", true);
316 av.visit("layout", nDesc);
317 av.visit("ctype", "N/A");
318 av.visit("size", -1);
319 av.visitEnd();
320 // FIXME: We need calling convention
321 av = mv.visitAnnotation(
322 "Ljava/nicl/metadata/CallingConvention;", true);
323 av.visit("value", jt2.getCallingConvention());
324 av.visitEnd();
325
326 mv.visitEnd();
327 // Write class
328 try {
329 writeClassFile(cw, owner.clsName + "$" + intf);
330 } catch (IOException ex) {
331 ex.printStackTrace(System.err);
332 }
333 }
334
335 private void createFunctionalInterface(Cursor dcl, JType.FnIf fnif) {
336 JType.Function fn = fnif.getFunction();
337 String intf;
338 String nativeName;
339 if (dcl == null) {
340 intf = ((JType.InnerType) fnif.type).getName();
341 nativeName = "N/A";
342 } else {
343 nativeName = Utils.getIdentifier(dcl);
344 intf = Utils.toClassName(nativeName);
345 }
346 logger.fine(() -> "Create FunctionalInterface " + intf);
347
348 final String name = internal_name + "$" + intf;
349
350 logger.fine(() -> "Define class " + name + " for native type " + nativeName);
351 global_cw.visitInnerClass(name, internal_name, intf, ACC_PUBLIC | ACC_STATIC | ACC_ABSTRACT | ACC_INTERFACE);
364 MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_ABSTRACT, "fn",
365 fn.getDescriptor(), fn.getSignature(), null);
366 if (dcl != null) {
367 av = mv.visitAnnotation(
368 "Ljava/nicl/metadata/NativeType;", true);
369 Type t = dcl.type().canonicalType();
370 av.visit("layout", Utils.getLayout(t));
371 av.visit("ctype", t.spelling());
372 av.visit("size", t.size());
373 av.visitEnd();
374 av = mv.visitAnnotation(
375 "Ljava/nicl/metadata/CallingConvention;", true);
376 av.visit("value", t.getCallingConvention().value());
377 av.visitEnd();
378 }
379 mv.visitEnd();
380 // Write class
381 try {
382 writeClassFile(cw, owner.clsName + "$" + intf);
383 } catch (IOException ex) {
384 ex.printStackTrace(System.err);
385 }
386 }
387
388 private void defineType(Cursor dcl, TypeAlias alias) {
389 if (alias.getAnnotationDescriptor() != null) {
390 createAnnotationCls(dcl);
391 } else {
392 JType real = alias.canonicalType();
393 if (real instanceof JType.FnIf) {
394 createFunctionalInterface(dcl, (JType.FnIf) real);
395 }
396 // Otherwise, type alias is a same named stuct
397 }
398 }
399
400 private void addMethod(Cursor dcl, JType.Function fn) {
401 logger.fine(() -> "Add method: " + fn.getSignature());
402 int flags = ACC_PUBLIC | ACC_ABSTRACT;
403 if (fn.isVarArgs) {
404 flags |= ACC_VARARGS;
455 TypeAlias alias = (TypeAlias) fn.returnType;
456 logger.finest(() -> " return type is an alias " + alias);
457 if (alias.getAnnotationDescriptor() != null) {
458 mv.visitTypeAnnotation(
459 TypeReference.newTypeReference(TypeReference.METHOD_RETURN).getValue(),
460 null, alias.getAnnotationDescriptor(), true)
461 .visitEnd();
462 }
463 }
464 mv.visitEnd();
465 }
466
467 @Override
468 protected CodeFactory addType(JType jt, Cursor cursor) {
469 JType2 jt2 = null;
470 if (jt instanceof JType2) {
471 jt2 = (JType2) jt;
472 jt = jt2.getDelegate();
473 } else {
474 logger.warning(() -> "Should have JType2 in addType");
475 new Throwable().printStackTrace(System.err);
476 }
477 if (cursor == null) {
478 assert (jt2 != null);
479 if (jt instanceof JType.FnIf) {
480 createFunctionalInterface(jt2);
481 }
482 return this;
483 }
484
485 try {
486 logger.fine(() -> "Process cursor " + cursor.spelling());
487 switch (cursor.kind()) {
488 case StructDecl:
489 createStruct(cursor);
490 break;
491 case FunctionDecl:
492 assert (jt instanceof JType.Function);
493 addMethod(cursor, (JType.Function) jt);
494 break;
495 case EnumDecl:
496 createEnum(cursor);
497 break;
498 case TypedefDecl:
499 // anonymous typedef struct {} xxx will not get TypeAlias
500 if (jt instanceof TypeAlias) {
501 defineType(cursor, (TypeAlias) jt);
502 }
503 break;
504 case VarDecl:
505 addField(global_cw, cursor, null);
506 break;
507 default:
508 logger.warning(() -> "Unsupported declaration Cursor:");
509 logger.fine(() -> Printer.Stringifier(p -> p.dumpCursor(cursor, true)));
510 break;
511 }
512 } catch (Exception ex) {
513 ex.printStackTrace(System.err);
514 logger.warning("Cursor causing above exception is: " + cursor.spelling());
515 logger.fine(() -> Printer.Stringifier(p -> p.dumpCursor(cursor, true)));
516 }
517 return this;
518 }
519
520 private static class Literal {
521 private enum Type {
522 INT(int.class),
523 LONG(long.class),
524 STRING(String.class);
525
526 private Class<?> c;
527
528 Type(Class<?> c) {
529 this.c = c;
530 }
531
532 Class<?> getTypeClass() {
533 return c;
677 case LONG:
678 mv.visitInsn(LRETURN);
679 break;
680 case STRING:
681 mv.visitInsn(ARETURN);
682 break;
683 }
684 mv.visitMaxs(0, 0);
685 mv.visitEnd();
686
687 handledMacros.add(macroName);
688
689 return this;
690 }
691
692 @Override
693 protected void produce() {
694 try {
695 writeClassFile(global_cw, owner.clsName);
696 } catch (IOException ex) {
697 ex.printStackTrace(System.err);
698 }
699 }
700
701 @Override
702 protected Map<String, byte[]> collect() {
703 // Ensure classes are produced
704 produce();
705 HashMap<String, byte[]> rv = new HashMap<>();
706 // Not copying byte[] for efficiency, perhaps not a safe idea though
707 if (owner.pkgName.isEmpty()) {
708 types.forEach((clsName, bytecodes) -> {
709 rv.put(clsName, bytecodes);
710 });
711 } else {
712 types.forEach((clsName, bytecodes) -> {
713 rv.put(owner.pkgName + "." + clsName, bytecodes);
714 });
715 }
716 return Collections.unmodifiableMap(rv);
717 }
|
51
52 public AsmCodeFactory(HeaderFile header) {
53 logger.info(() -> "Instantiate AsmCodeFactory for " + header.path);
54 owner = header;
55 internal_name = Utils.toInternalName(owner.pkgName, owner.clsName);
56 global_cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
57 types = new HashMap<>();
58 init();
59 }
60
61 private void init() {
62 global_cw.visit(V1_8, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE,
63 internal_name,
64 null, "java/lang/Object", null);
65 AnnotationVisitor av = global_cw.visitAnnotation(
66 "Ljava/nicl/metadata/Header;", true);
67 av.visit("path", owner.path.toAbsolutePath().toString());
68 av.visitEnd();
69 }
70
71 private void handleException(Exception ex) {
72 System.err.println(Main.format("cannot.write.class.file", owner.pkgName + "." + owner.clsName, ex));
73 if (Main.DEBUG) {
74 ex.printStackTrace(System.err);
75 }
76 }
77
78 private void annotateC(ClassVisitor cw, Cursor dcl) {
79 AnnotationVisitor av = cw.visitAnnotation(
80 "Ljava/nicl/metadata/C;", true);
81 SourceLocation src = dcl.getSourceLocation();
82 SourceLocation.Location loc = src.getFileLocation();
83 Path p = loc.path();
84 av.visit("file", p == null ? "builtin" : p.toAbsolutePath().toString());
85 av.visit("line", loc.line());
86 av.visit("column", loc.column());
87 av.visit("USR", dcl.USR());
88 av.visitEnd();
89 }
90
91 private void writeClassFile(final ClassWriter cw, String clsName)
92 throws IOException {
93 cw.visitEnd();
94 byte[] bytecodes = cw.toByteArray();
95 types.put(clsName, bytecodes);
96 }
97
193 "java/lang/Object", new String[] {"java/nicl/types/Reference"});
194 annotateC(cw, cursor);
195 AnnotationVisitor av = cw.visitAnnotation(
196 "Ljava/nicl/metadata/NativeType;", true);
197 av.visit("layout", Utils.getLayout(t));
198 av.visit("ctype", t.spelling());
199 av.visit("size", t.size());
200 av.visit("isRecordType", true);
201 av.visitEnd();
202 cw.visitInnerClass(name, internal_name, intf, ACC_PUBLIC | ACC_STATIC | ACC_ABSTRACT | ACC_INTERFACE);
203
204 // fields
205 Printer dbg = new Printer();
206 cursor.stream()
207 .filter(cx -> cx.kind() == CursorKind.FieldDecl)
208 .forEachOrdered(cx -> addField(cw, cx, cursor.type()));
209 // Write class
210 try {
211 writeClassFile(cw, owner.clsName + "$" + intf);
212 } catch (IOException ex) {
213 handleException(ex);
214 }
215 }
216
217 private void createEnum(Cursor cursor) {
218 String nativeName = Utils.getIdentifier(cursor);
219 logger.fine(() -> "create enum: " + nativeName);
220
221 String intf = Utils.toClassName(nativeName);
222 String name = internal_name + "$" + intf;
223
224 logger.fine(() -> "Define class " + name + " for native type " + nativeName);
225 global_cw.visitInnerClass(name, internal_name, intf,
226 ACC_PUBLIC | ACC_STATIC | ACC_ABSTRACT | ACC_INTERFACE | ACC_ANNOTATION);
227 ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
228 String[] superAnno = { "java/lang/annotation/Annotation" };
229 cw.visit(V1_8, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE | ACC_ANNOTATION,
230 name, null, "java/lang/Object", superAnno);
231 annotateC(cw, cursor);
232 AnnotationVisitor av = cw.visitAnnotation(
233 "Ljava/nicl/metadata/NativeType;", true);
236 av.visit("ctype", t.spelling());
237 av.visit("size", t.size());
238 av.visitEnd();
239
240 av = cw.visitAnnotation("Ljava/lang/annotation/Target;", true);
241 av.visitEnum("value", "Ljava/lang/annotation/ElementType;", "TYPE_USE");
242 av.visitEnd();
243 av = cw.visitAnnotation("Ljava/lang/annotation/Retention;", true);
244 av.visitEnum("value", "Ljava/lang/annotation/RetentionPolicy;", "RUNTIME");
245 av.visitEnd();
246 cw.visitInnerClass(name, internal_name, intf,
247 ACC_PUBLIC | ACC_STATIC | ACC_ABSTRACT | ACC_INTERFACE | ACC_ANNOTATION);
248 // constants
249 cursor.stream()
250 .filter(cx -> cx.kind() == CursorKind.EnumConstantDecl)
251 .forEachOrdered(cx -> addConstant(cw, cx));
252 // Write class
253 try {
254 writeClassFile(cw, owner.clsName + "$" + intf);
255 } catch (IOException ex) {
256 handleException(ex);
257 }
258 }
259
260 private void createAnnotationCls(Cursor dcl) {
261 String nativeName = Utils.getIdentifier(dcl);
262 logger.fine(() -> "Create annotation for: " + nativeName);
263
264 String intf = Utils.toClassName(nativeName);
265 String name = internal_name + "$" + intf;
266
267 logger.fine(() -> "Define class " + name + " for native type " + nativeName);
268 global_cw.visitInnerClass(name, internal_name, intf,
269 ACC_PUBLIC | ACC_STATIC | ACC_ABSTRACT | ACC_INTERFACE | ACC_ANNOTATION);
270 ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
271 String[] superAnno = { "java/lang/annotation/Annotation" };
272 cw.visit(V1_8, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE | ACC_ANNOTATION,
273 name, null, "java/lang/Object", superAnno);
274 annotateC(cw, dcl);
275 Type t = dcl.type().canonicalType();
276 AnnotationVisitor av = cw.visitAnnotation(
277 "Ljava/nicl/metadata/NativeType;", true);
278 av.visit("layout", Utils.getLayout(t));
279 av.visit("ctype", t.spelling());
280 av.visit("size", t.size());
281 av.visitEnd();
282
283 av = cw.visitAnnotation("Ljava/lang/annotation/Target;", true);
284 av.visitEnum("value", "Ljava/lang/annotation/ElementType;", "TYPE_USE");
285 av.visitEnd();
286 av = cw.visitAnnotation("Ljava/lang/annotation/Retention;", true);
287 av.visitEnum("value", "Ljava/lang/annotation/RetentionPolicy;", "RUNTIME");
288 av.visitEnd();
289 cw.visitInnerClass(name, internal_name, intf,
290 ACC_PUBLIC | ACC_STATIC | ACC_ABSTRACT | ACC_INTERFACE | ACC_ANNOTATION);
291 // Write class
292 try {
293 writeClassFile(cw, owner.clsName + "$" + intf);
294 } catch (IOException ex) {
295 handleException(ex);
296 }
297 }
298
299 private void createFunctionalInterface(JType2 jt2) {
300 JType.FnIf fnif = (JType.FnIf) jt2.getDelegate();
301 JType.Function fn = fnif.getFunction();
302 String intf = ((JType.InnerType) fnif.type).getName();
303 logger.fine(() -> "Create FunctionalInterface " + intf);
304 String nDesc = jt2.getNativeDescriptor();
305
306 final String name = internal_name + "$" + intf;
307
308 logger.fine(() -> "Define class " + name + " for anonymous function " + nDesc);
309 global_cw.visitInnerClass(name, internal_name, intf, ACC_PUBLIC | ACC_STATIC | ACC_ABSTRACT | ACC_INTERFACE);
310 ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
311 cw.visit(V1_8, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE,
312 name, null, "java/lang/Object", null);
313 AnnotationVisitor av = cw.visitAnnotation(
314 "Ljava/lang/FunctionalInterface;", true);
315 av.visitEnd();
318 // add the method
319 MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_ABSTRACT, "fn",
320 fn.getDescriptor(), fn.getSignature(), null);
321 av = mv.visitAnnotation(
322 "Ljava/nicl/metadata/NativeType;", true);
323 av.visit("layout", nDesc);
324 av.visit("ctype", "N/A");
325 av.visit("size", -1);
326 av.visitEnd();
327 // FIXME: We need calling convention
328 av = mv.visitAnnotation(
329 "Ljava/nicl/metadata/CallingConvention;", true);
330 av.visit("value", jt2.getCallingConvention());
331 av.visitEnd();
332
333 mv.visitEnd();
334 // Write class
335 try {
336 writeClassFile(cw, owner.clsName + "$" + intf);
337 } catch (IOException ex) {
338 handleException(ex);
339 }
340 }
341
342 private void createFunctionalInterface(Cursor dcl, JType.FnIf fnif) {
343 JType.Function fn = fnif.getFunction();
344 String intf;
345 String nativeName;
346 if (dcl == null) {
347 intf = ((JType.InnerType) fnif.type).getName();
348 nativeName = "N/A";
349 } else {
350 nativeName = Utils.getIdentifier(dcl);
351 intf = Utils.toClassName(nativeName);
352 }
353 logger.fine(() -> "Create FunctionalInterface " + intf);
354
355 final String name = internal_name + "$" + intf;
356
357 logger.fine(() -> "Define class " + name + " for native type " + nativeName);
358 global_cw.visitInnerClass(name, internal_name, intf, ACC_PUBLIC | ACC_STATIC | ACC_ABSTRACT | ACC_INTERFACE);
371 MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_ABSTRACT, "fn",
372 fn.getDescriptor(), fn.getSignature(), null);
373 if (dcl != null) {
374 av = mv.visitAnnotation(
375 "Ljava/nicl/metadata/NativeType;", true);
376 Type t = dcl.type().canonicalType();
377 av.visit("layout", Utils.getLayout(t));
378 av.visit("ctype", t.spelling());
379 av.visit("size", t.size());
380 av.visitEnd();
381 av = mv.visitAnnotation(
382 "Ljava/nicl/metadata/CallingConvention;", true);
383 av.visit("value", t.getCallingConvention().value());
384 av.visitEnd();
385 }
386 mv.visitEnd();
387 // Write class
388 try {
389 writeClassFile(cw, owner.clsName + "$" + intf);
390 } catch (IOException ex) {
391 handleException(ex);
392 }
393 }
394
395 private void defineType(Cursor dcl, TypeAlias alias) {
396 if (alias.getAnnotationDescriptor() != null) {
397 createAnnotationCls(dcl);
398 } else {
399 JType real = alias.canonicalType();
400 if (real instanceof JType.FnIf) {
401 createFunctionalInterface(dcl, (JType.FnIf) real);
402 }
403 // Otherwise, type alias is a same named stuct
404 }
405 }
406
407 private void addMethod(Cursor dcl, JType.Function fn) {
408 logger.fine(() -> "Add method: " + fn.getSignature());
409 int flags = ACC_PUBLIC | ACC_ABSTRACT;
410 if (fn.isVarArgs) {
411 flags |= ACC_VARARGS;
462 TypeAlias alias = (TypeAlias) fn.returnType;
463 logger.finest(() -> " return type is an alias " + alias);
464 if (alias.getAnnotationDescriptor() != null) {
465 mv.visitTypeAnnotation(
466 TypeReference.newTypeReference(TypeReference.METHOD_RETURN).getValue(),
467 null, alias.getAnnotationDescriptor(), true)
468 .visitEnd();
469 }
470 }
471 mv.visitEnd();
472 }
473
474 @Override
475 protected CodeFactory addType(JType jt, Cursor cursor) {
476 JType2 jt2 = null;
477 if (jt instanceof JType2) {
478 jt2 = (JType2) jt;
479 jt = jt2.getDelegate();
480 } else {
481 logger.warning(() -> "Should have JType2 in addType");
482 if (Main.DEBUG) {
483 new Throwable().printStackTrace(System.err);
484 }
485 }
486 if (cursor == null) {
487 assert (jt2 != null);
488 if (jt instanceof JType.FnIf) {
489 createFunctionalInterface(jt2);
490 }
491 return this;
492 }
493
494 try {
495 logger.fine(() -> "Process cursor " + cursor.spelling());
496 switch (cursor.kind()) {
497 case StructDecl:
498 createStruct(cursor);
499 break;
500 case FunctionDecl:
501 assert (jt instanceof JType.Function);
502 addMethod(cursor, (JType.Function) jt);
503 break;
504 case EnumDecl:
505 createEnum(cursor);
506 break;
507 case TypedefDecl:
508 // anonymous typedef struct {} xxx will not get TypeAlias
509 if (jt instanceof TypeAlias) {
510 defineType(cursor, (TypeAlias) jt);
511 }
512 break;
513 case VarDecl:
514 addField(global_cw, cursor, null);
515 break;
516 default:
517 logger.warning(() -> "Unsupported declaration Cursor:");
518 logger.fine(() -> Printer.Stringifier(p -> p.dumpCursor(cursor, true)));
519 break;
520 }
521 } catch (Exception ex) {
522 handleException(ex);
523 logger.warning("Cursor causing above exception is: " + cursor.spelling());
524 logger.fine(() -> Printer.Stringifier(p -> p.dumpCursor(cursor, true)));
525 }
526 return this;
527 }
528
529 private static class Literal {
530 private enum Type {
531 INT(int.class),
532 LONG(long.class),
533 STRING(String.class);
534
535 private Class<?> c;
536
537 Type(Class<?> c) {
538 this.c = c;
539 }
540
541 Class<?> getTypeClass() {
542 return c;
686 case LONG:
687 mv.visitInsn(LRETURN);
688 break;
689 case STRING:
690 mv.visitInsn(ARETURN);
691 break;
692 }
693 mv.visitMaxs(0, 0);
694 mv.visitEnd();
695
696 handledMacros.add(macroName);
697
698 return this;
699 }
700
701 @Override
702 protected void produce() {
703 try {
704 writeClassFile(global_cw, owner.clsName);
705 } catch (IOException ex) {
706 handleException(ex);
707 }
708 }
709
710 @Override
711 protected Map<String, byte[]> collect() {
712 // Ensure classes are produced
713 produce();
714 HashMap<String, byte[]> rv = new HashMap<>();
715 // Not copying byte[] for efficiency, perhaps not a safe idea though
716 if (owner.pkgName.isEmpty()) {
717 types.forEach((clsName, bytecodes) -> {
718 rv.put(clsName, bytecodes);
719 });
720 } else {
721 types.forEach((clsName, bytecodes) -> {
722 rv.put(owner.pkgName + "." + clsName, bytecodes);
723 });
724 }
725 return Collections.unmodifiableMap(rv);
726 }
|