74 75 private final Context ctx; 76 private final ClassWriter global_cw; 77 // to avoid duplicate generation of methods, field accessors 78 private final Set<String> global_methods = new HashSet<>(); 79 private final Set<String> global_fields = new HashSet<>(); 80 private final String internal_name; 81 private final HeaderFile owner; 82 private final Map<String, byte[]> types; 83 private final Logger logger = Logger.getLogger(getClass().getPackage().getName()); 84 private final List<String> headerDeclarations = new ArrayList<>(); 85 private transient boolean built = false; 86 87 AsmCodeFactory(Context ctx, HeaderFile header) { 88 this.ctx = ctx; 89 logger.info(() -> "Instantiate AsmCodeFactory for " + header.path); 90 this.owner = header; 91 this.internal_name = Utils.toInternalName(owner.pkgName, owner.clsName); 92 this.global_cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); 93 this.types = new HashMap<>(); 94 global_cw.visit(V1_8, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE, 95 internal_name, 96 null, "java/lang/Object", null); 97 } 98 99 private void generateNativeHeader() { 100 generateMacros(); 101 AnnotationVisitor av = global_cw.visitAnnotation(NATIVE_HEADER, true); 102 av.visit("path", owner.path.toAbsolutePath().toString()); 103 if (owner.libraries != null && !owner.libraries.isEmpty()) { 104 AnnotationVisitor libNames = av.visitArray("libraries"); 105 for (String name : owner.libraries) { 106 libNames.visit(null, name); 107 } 108 libNames.visitEnd(); 109 if (owner.libraryPaths != null && !owner.libraryPaths.isEmpty()) { 110 AnnotationVisitor libPaths = av.visitArray("libraryPaths"); 111 for (String path : owner.libraryPaths) { 112 libPaths.visit(null, path); 113 } 114 libPaths.visitEnd(); 115 } 116 } 540 } else if (macroType.equals(double.class)) { 541 mv.visitInsn(DRETURN); 542 } else if (macroType.equals(String.class)) { 543 mv.visitInsn(ARETURN); 544 } 545 mv.visitMaxs(0, 0); 546 mv.visitEnd(); 547 } else { 548 logger.fine(() -> "Skipping unrecognized object-like macro " + macro.name()); 549 } 550 } 551 552 return this; 553 } 554 555 protected synchronized void produce() { 556 if (built) { 557 throw new IllegalStateException("Produce is called multiple times"); 558 } 559 built = true; 560 generateNativeHeader(); 561 try { 562 writeClassFile(global_cw, owner.clsName); 563 } catch (IOException ex) { 564 handleException(ex); 565 } 566 } 567 568 protected Map<String, byte[]> collect() { 569 // Ensure classes are produced 570 if (!built) produce(); 571 HashMap<String, byte[]> rv = new HashMap<>(); 572 // Not copying byte[] for efficiency, perhaps not a safe idea though 573 if (owner.pkgName.isEmpty()) { 574 types.forEach((clsName, bytecodes) -> { 575 rv.put(clsName, bytecodes); 576 }); 577 } else { 578 types.forEach((clsName, bytecodes) -> { 579 rv.put(owner.pkgName + "." + clsName, bytecodes); | 74 75 private final Context ctx; 76 private final ClassWriter global_cw; 77 // to avoid duplicate generation of methods, field accessors 78 private final Set<String> global_methods = new HashSet<>(); 79 private final Set<String> global_fields = new HashSet<>(); 80 private final String internal_name; 81 private final HeaderFile owner; 82 private final Map<String, byte[]> types; 83 private final Logger logger = Logger.getLogger(getClass().getPackage().getName()); 84 private final List<String> headerDeclarations = new ArrayList<>(); 85 private transient boolean built = false; 86 87 AsmCodeFactory(Context ctx, HeaderFile header) { 88 this.ctx = ctx; 89 logger.info(() -> "Instantiate AsmCodeFactory for " + header.path); 90 this.owner = header; 91 this.internal_name = Utils.toInternalName(owner.pkgName, owner.clsName); 92 this.global_cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); 93 this.types = new HashMap<>(); 94 } 95 96 private String[] getSuperInterfaces() { 97 String[] interfaces = owner.getIncludedFiles(). 98 map(hf -> Utils.toInternalName(hf.pkgName, hf.clsName)). 99 toArray(String[]::new); 100 return interfaces.length != 0 ? interfaces : null; 101 } 102 103 private void generateNativeHeader() { 104 generateMacros(); 105 AnnotationVisitor av = global_cw.visitAnnotation(NATIVE_HEADER, true); 106 av.visit("path", owner.path.toAbsolutePath().toString()); 107 if (owner.libraries != null && !owner.libraries.isEmpty()) { 108 AnnotationVisitor libNames = av.visitArray("libraries"); 109 for (String name : owner.libraries) { 110 libNames.visit(null, name); 111 } 112 libNames.visitEnd(); 113 if (owner.libraryPaths != null && !owner.libraryPaths.isEmpty()) { 114 AnnotationVisitor libPaths = av.visitArray("libraryPaths"); 115 for (String path : owner.libraryPaths) { 116 libPaths.visit(null, path); 117 } 118 libPaths.visitEnd(); 119 } 120 } 544 } else if (macroType.equals(double.class)) { 545 mv.visitInsn(DRETURN); 546 } else if (macroType.equals(String.class)) { 547 mv.visitInsn(ARETURN); 548 } 549 mv.visitMaxs(0, 0); 550 mv.visitEnd(); 551 } else { 552 logger.fine(() -> "Skipping unrecognized object-like macro " + macro.name()); 553 } 554 } 555 556 return this; 557 } 558 559 protected synchronized void produce() { 560 if (built) { 561 throw new IllegalStateException("Produce is called multiple times"); 562 } 563 built = true; 564 global_cw.visit(V1_8, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE, 565 internal_name, 566 null, "java/lang/Object", getSuperInterfaces()); 567 generateNativeHeader(); 568 try { 569 writeClassFile(global_cw, owner.clsName); 570 } catch (IOException ex) { 571 handleException(ex); 572 } 573 } 574 575 protected Map<String, byte[]> collect() { 576 // Ensure classes are produced 577 if (!built) produce(); 578 HashMap<String, byte[]> rv = new HashMap<>(); 579 // Not copying byte[] for efficiency, perhaps not a safe idea though 580 if (owner.pkgName.isEmpty()) { 581 types.forEach((clsName, bytecodes) -> { 582 rv.put(clsName, bytecodes); 583 }); 584 } else { 585 types.forEach((clsName, bytecodes) -> { 586 rv.put(owner.pkgName + "." + clsName, bytecodes); |