< prev index next >

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

Print this page




  73  * file.
  74  */
  75 final class AsmCodeFactory extends SimpleTreeVisitor<Void, JType> {
  76     private static final String ANNOTATION_PKG_PREFIX = "Ljava/foreign/annotations/";
  77     private static final String NATIVE_CALLBACK = ANNOTATION_PKG_PREFIX + "NativeCallback;";
  78     private static final String NATIVE_HEADER = ANNOTATION_PKG_PREFIX + "NativeHeader;";
  79     private static final String NATIVE_LOCATION = ANNOTATION_PKG_PREFIX + "NativeLocation;";
  80     private static final String NATIVE_STRUCT = ANNOTATION_PKG_PREFIX + "NativeStruct;";
  81 
  82     private final Context ctx;
  83     private final ClassWriter global_cw;
  84     // to avoid duplicate generation of methods, field accessors, macros
  85     private final Set<String> global_methods = new HashSet<>();
  86     private final Set<String> global_fields = new HashSet<>();
  87     private final Set<String> global_macros = new HashSet<>();
  88     private final String internal_name;
  89     private final HeaderFile owner;
  90     private final Map<String, byte[]> types;
  91     private final Logger logger = Logger.getLogger(getClass().getPackage().getName());
  92     private final List<String> headerDeclarations = new ArrayList<>();


  93     private transient boolean built = false;
  94 
  95     AsmCodeFactory(Context ctx, HeaderFile header) {
  96         this.ctx = ctx;
  97         logger.info(() -> "Instantiate AsmCodeFactory for " + header.path);
  98         this.owner = header;
  99         this.internal_name = Utils.toInternalName(owner.pkgName, owner.clsName);
 100         this.global_cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
 101         this.types = new HashMap<>();
 102         global_cw.visit(V1_8, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE,
 103                 internal_name,
 104                 null, "java/lang/Object", null);





 105     }
 106 
 107     private void generateNativeHeader() {
 108         AnnotationVisitor av = global_cw.visitAnnotation(NATIVE_HEADER, true);
 109         av.visit("path", owner.path.toAbsolutePath().toString());
 110         if (owner.libraries != null && !owner.libraries.isEmpty()) {
 111             AnnotationVisitor libNames = av.visitArray("libraries");
 112             for (String name : owner.libraries) {
 113                 libNames.visit(null, name);
 114             }
 115             libNames.visitEnd();
 116             if (owner.libraryPaths != null && !owner.libraryPaths.isEmpty()) {
 117                 AnnotationVisitor libPaths = av.visitArray("libraryPaths");
 118                 for (String path : owner.libraryPaths) {
 119                     libPaths.visit(null, path);
 120                 }
 121                 libPaths.visitEnd();
 122             }
 123         }
 124         av.visit("declarations", String.join(" ", headerDeclarations));


 172         if (cw == global_cw) {
 173             String uniqueName = fieldName + "." + jt.getDescriptor();
 174             if (! global_fields.add(uniqueName)) {
 175                 return; // added already
 176             }
 177         }
 178         MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_ABSTRACT, fieldName + "$get",
 179                 "()" + jt.getDescriptor(), "()" + jt.getSignature(), null);
 180 
 181         AnnotationVisitor av = mv.visitAnnotation(NATIVE_LOCATION, true);
 182         SourceLocation src = tree.location();
 183         SourceLocation.Location loc = src.getFileLocation();
 184         Path p = loc.path();
 185         av.visit("file", p == null ? "builtin" : p.toAbsolutePath().toString());
 186         av.visit("line", loc.line());
 187         av.visit("column", loc.column());
 188         av.visit("USR", tree.USR());
 189         av.visitEnd();
 190 
 191         mv.visitEnd();
 192         cw.visitMethod(ACC_PUBLIC | ACC_ABSTRACT, fieldName + "$set",
 193                 "(" + jt.getDescriptor() + ")V",
 194                 "(" + JType.getPointerVoidAsWildcard(jt) + ")V", null);

 195         if (tree instanceof VarTree || !isBitField(tree)) {
 196             JType ptrType = new PointerType(jt);
 197             cw.visitMethod(ACC_PUBLIC | ACC_ABSTRACT, fieldName + "$ptr",
 198                     "()" + ptrType.getDescriptor(), "()" + ptrType.getSignature(), null);

 199         }
 200     }
 201 
 202     @Override
 203     public Void visitVar(VarTree varTree, JType jt) {
 204         addField(global_cw, varTree, null);
 205         Layout layout = varTree.layout();
 206         String descStr = decorateAsAccessor(varTree, layout).toString();
 207         addHeaderDecl(varTree.name(), descStr);



 208         return null;
 209     }
 210 
 211     private void addHeaderDecl(String symbol, String desc) {
 212         headerDeclarations.add(String.format("%s=%s", symbol, desc));
 213     }
 214 
 215     private void addConstant(ClassWriter cw, FieldTree fieldTree) {
 216         assert (fieldTree.isEnumConstant());
 217         String name = fieldTree.name();
 218         String desc = owner.globalLookup(fieldTree.type()).getDescriptor();
 219         MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, name, "()" + desc, null, null);
 220         mv.visitCode();
 221         if (desc.length() != 1) {
 222             throw new AssertionError("expected single char descriptor: " + desc);
 223         }
 224         switch (desc.charAt(0)) {
 225             case 'J':
 226                 long lvalue = fieldTree.enumConstant().get();
 227                 mv.visitLdcInsn(lvalue);


 291         layout = addGetterSetterName(layout, fieldTree.name());
 292         if (!fieldTree.isBitField()) {
 293             //no pointer accessors for bitfield!
 294             layout = layout.withAnnotation("ptr", fieldTree.name() + "$ptr");
 295         }
 296         return layout;
 297     }
 298 
 299     @Override
 300     public Void visitEnum(EnumTree enumTree, JType jt) {
 301         // define enum constants in global_cw
 302         enumTree.constants().forEach(constant -> addConstant(global_cw, constant));
 303 
 304         if (enumTree.name().isEmpty()) {
 305             // We are done with anonymous enum
 306             return null;
 307         }
 308 
 309         // generate annotation class for named enum
 310         createAnnotationCls(enumTree);



 311         return null;
 312     }
 313 
 314     private void createAnnotationCls(Tree tree) {
 315         String nativeName = tree.name();
 316         logger.fine(() -> "Create annotation for: " + nativeName);
 317 
 318         String intf = Utils.toClassName(nativeName);
 319         String name = internal_name + "$" + intf;
 320 
 321         logger.fine(() -> "Define class " + name + " for native type " + nativeName);
 322         global_cw.visitInnerClass(name, internal_name, intf,
 323                 ACC_PUBLIC | ACC_STATIC | ACC_ABSTRACT | ACC_INTERFACE | ACC_ANNOTATION);
 324         ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
 325         String[] superAnno = { "java/lang/annotation/Annotation" };
 326         cw.visit(V1_8, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE | ACC_ANNOTATION,
 327                 name, null, "java/lang/Object", superAnno);
 328         annotateNativeLocation(cw, tree);
 329         Type type = tree.type().canonicalType();
 330         AnnotationVisitor av = cw.visitAnnotation("Ljava/lang/annotation/Target;", true);


 463                     mv.visitTypeAnnotation(
 464                             TypeReference.newFormalParameterReference(idx).getValue(),
 465                             null, alias.getAnnotationDescriptor(), true)
 466                       .visitEnd();
 467                 }
 468             }
 469             idx++;
 470         }
 471 
 472         if (fn.returnType instanceof TypeAlias) {
 473             TypeAlias alias = (TypeAlias) fn.returnType;
 474             logger.finest(() -> "  return type is an alias " + alias);
 475             if (alias.getAnnotationDescriptor() != null) {
 476                 mv.visitTypeAnnotation(
 477                         TypeReference.newTypeReference(TypeReference.METHOD_RETURN).getValue(),
 478                         null, alias.getAnnotationDescriptor(), true)
 479                   .visitEnd();
 480             }
 481         }
 482         mv.visitEnd();



 483         return null;
 484     }
 485 
 486     protected AsmCodeFactory addType(JType jt, Tree tree) {
 487         JType2 jt2 = null;
 488         if (jt instanceof JType2) {
 489             jt2 = (JType2) jt;
 490             jt = jt2.getDelegate();
 491         } else {
 492             logger.warning(() -> "Should have JType2 in addType");
 493             if (Main.DEBUG) {
 494                 new Throwable().printStackTrace(ctx.err);
 495             }
 496         }
 497         if (tree == null) {
 498             assert (jt2 != null);
 499             if (jt instanceof JType.FnIf) {
 500                 createFunctionalInterface(null, (JType.FnIf) jt);
 501             }
 502             return this;


 549 
 550         mv.visitCode();
 551 
 552         mv.visitLdcInsn(value);
 553         if (macroType.equals(char.class)) {
 554             mv.visitInsn(I2C);
 555             mv.visitInsn(IRETURN);
 556         } else if (macroType.equals(int.class)) {
 557             mv.visitInsn(IRETURN);
 558         } else if (macroType.equals(float.class)) {
 559             mv.visitInsn(FRETURN);
 560         } else if (macroType.equals(long.class)) {
 561             mv.visitInsn(LRETURN);
 562         } else if (macroType.equals(double.class)) {
 563             mv.visitInsn(DRETURN);
 564         } else if (macroType.equals(String.class)) {
 565             mv.visitInsn(ARETURN);
 566         }
 567         mv.visitMaxs(0, 0);
 568         mv.visitEnd();



 569         return null;
 570     }
 571 
 572     protected synchronized void produce() {
 573         if (built) {
 574             throw new IllegalStateException("Produce is called multiple times");
 575         }
 576         built = true;
 577         generateNativeHeader();
 578         try {
 579             writeClassFile(global_cw, owner.clsName);
 580         } catch (IOException ex) {
 581             handleException(ex);
 582         }



 583     }
 584 
 585     protected Map<String, byte[]> collect() {
 586         // Ensure classes are produced
 587         if (!built) produce();
 588         HashMap<String, byte[]> rv = new HashMap<>();
 589         // Not copying byte[] for efficiency, perhaps not a safe idea though
 590         if (owner.pkgName.isEmpty()) {
 591             types.forEach((clsName, bytecodes) -> {
 592                 rv.put(clsName, bytecodes);
 593             });
 594         } else {
 595             types.forEach((clsName, bytecodes) -> {
 596                 rv.put(owner.pkgName + "." + clsName, bytecodes);
 597             });
 598         }
 599         return Collections.unmodifiableMap(rv);
 600     }
 601 }


  73  * file.
  74  */
  75 final class AsmCodeFactory extends SimpleTreeVisitor<Void, JType> {
  76     private static final String ANNOTATION_PKG_PREFIX = "Ljava/foreign/annotations/";
  77     private static final String NATIVE_CALLBACK = ANNOTATION_PKG_PREFIX + "NativeCallback;";
  78     private static final String NATIVE_HEADER = ANNOTATION_PKG_PREFIX + "NativeHeader;";
  79     private static final String NATIVE_LOCATION = ANNOTATION_PKG_PREFIX + "NativeLocation;";
  80     private static final String NATIVE_STRUCT = ANNOTATION_PKG_PREFIX + "NativeStruct;";
  81 
  82     private final Context ctx;
  83     private final ClassWriter global_cw;
  84     // to avoid duplicate generation of methods, field accessors, macros
  85     private final Set<String> global_methods = new HashSet<>();
  86     private final Set<String> global_fields = new HashSet<>();
  87     private final Set<String> global_macros = new HashSet<>();
  88     private final String internal_name;
  89     private final HeaderFile owner;
  90     private final Map<String, byte[]> types;
  91     private final Logger logger = Logger.getLogger(getClass().getPackage().getName());
  92     private final List<String> headerDeclarations = new ArrayList<>();
  93     private final StaticForwarderGenerator staticForwardGen;
  94 
  95     private transient boolean built = false;
  96 
  97     AsmCodeFactory(Context ctx, HeaderFile header) {
  98         this.ctx = ctx;
  99         logger.info(() -> "Instantiate AsmCodeFactory for " + header.path);
 100         this.owner = header;
 101         this.internal_name = Utils.toInternalName(owner.pkgName, owner.clsName);
 102         this.global_cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
 103         this.types = new HashMap<>();
 104         global_cw.visit(V1_8, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE,
 105                 internal_name,
 106                 null, "java/lang/Object", null);
 107         if (ctx.getGenStaticForwarder()) {
 108             this.staticForwardGen = new StaticForwarderGenerator(header);
 109         } else {
 110             this.staticForwardGen = null;
 111         }
 112     }
 113 
 114     private void generateNativeHeader() {
 115         AnnotationVisitor av = global_cw.visitAnnotation(NATIVE_HEADER, true);
 116         av.visit("path", owner.path.toAbsolutePath().toString());
 117         if (owner.libraries != null && !owner.libraries.isEmpty()) {
 118             AnnotationVisitor libNames = av.visitArray("libraries");
 119             for (String name : owner.libraries) {
 120                 libNames.visit(null, name);
 121             }
 122             libNames.visitEnd();
 123             if (owner.libraryPaths != null && !owner.libraryPaths.isEmpty()) {
 124                 AnnotationVisitor libPaths = av.visitArray("libraryPaths");
 125                 for (String path : owner.libraryPaths) {
 126                     libPaths.visit(null, path);
 127                 }
 128                 libPaths.visitEnd();
 129             }
 130         }
 131         av.visit("declarations", String.join(" ", headerDeclarations));


 179         if (cw == global_cw) {
 180             String uniqueName = fieldName + "." + jt.getDescriptor();
 181             if (! global_fields.add(uniqueName)) {
 182                 return; // added already
 183             }
 184         }
 185         MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_ABSTRACT, fieldName + "$get",
 186                 "()" + jt.getDescriptor(), "()" + jt.getSignature(), null);
 187 
 188         AnnotationVisitor av = mv.visitAnnotation(NATIVE_LOCATION, true);
 189         SourceLocation src = tree.location();
 190         SourceLocation.Location loc = src.getFileLocation();
 191         Path p = loc.path();
 192         av.visit("file", p == null ? "builtin" : p.toAbsolutePath().toString());
 193         av.visit("line", loc.line());
 194         av.visit("column", loc.column());
 195         av.visit("USR", tree.USR());
 196         av.visitEnd();
 197 
 198         mv.visitEnd();
 199         mv = cw.visitMethod(ACC_PUBLIC | ACC_ABSTRACT, fieldName + "$set",
 200                 "(" + jt.getDescriptor() + ")V",
 201                 "(" + JType.getPointerVoidAsWildcard(jt) + ")V", null);
 202         mv.visitEnd();
 203         if (tree instanceof VarTree || !isBitField(tree)) {
 204             JType ptrType = new PointerType(jt);
 205             mv = cw.visitMethod(ACC_PUBLIC | ACC_ABSTRACT, fieldName + "$ptr",
 206                     "()" + ptrType.getDescriptor(), "()" + ptrType.getSignature(), null);
 207             mv.visitEnd();
 208         }
 209     }
 210 
 211     @Override
 212     public Void visitVar(VarTree varTree, JType jt) {
 213         addField(global_cw, varTree, null);
 214         Layout layout = varTree.layout();
 215         String descStr = decorateAsAccessor(varTree, layout).toString();
 216         addHeaderDecl(varTree.name(), descStr);
 217         if (staticForwardGen != null) {
 218             staticForwardGen.visitVar(varTree, jt);
 219         }
 220         return null;
 221     }
 222 
 223     private void addHeaderDecl(String symbol, String desc) {
 224         headerDeclarations.add(String.format("%s=%s", symbol, desc));
 225     }
 226 
 227     private void addConstant(ClassWriter cw, FieldTree fieldTree) {
 228         assert (fieldTree.isEnumConstant());
 229         String name = fieldTree.name();
 230         String desc = owner.globalLookup(fieldTree.type()).getDescriptor();
 231         MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, name, "()" + desc, null, null);
 232         mv.visitCode();
 233         if (desc.length() != 1) {
 234             throw new AssertionError("expected single char descriptor: " + desc);
 235         }
 236         switch (desc.charAt(0)) {
 237             case 'J':
 238                 long lvalue = fieldTree.enumConstant().get();
 239                 mv.visitLdcInsn(lvalue);


 303         layout = addGetterSetterName(layout, fieldTree.name());
 304         if (!fieldTree.isBitField()) {
 305             //no pointer accessors for bitfield!
 306             layout = layout.withAnnotation("ptr", fieldTree.name() + "$ptr");
 307         }
 308         return layout;
 309     }
 310 
 311     @Override
 312     public Void visitEnum(EnumTree enumTree, JType jt) {
 313         // define enum constants in global_cw
 314         enumTree.constants().forEach(constant -> addConstant(global_cw, constant));
 315 
 316         if (enumTree.name().isEmpty()) {
 317             // We are done with anonymous enum
 318             return null;
 319         }
 320 
 321         // generate annotation class for named enum
 322         createAnnotationCls(enumTree);
 323         if (staticForwardGen != null) {
 324             staticForwardGen.visitEnum(enumTree, jt);
 325         }
 326         return null;
 327     }
 328 
 329     private void createAnnotationCls(Tree tree) {
 330         String nativeName = tree.name();
 331         logger.fine(() -> "Create annotation for: " + nativeName);
 332 
 333         String intf = Utils.toClassName(nativeName);
 334         String name = internal_name + "$" + intf;
 335 
 336         logger.fine(() -> "Define class " + name + " for native type " + nativeName);
 337         global_cw.visitInnerClass(name, internal_name, intf,
 338                 ACC_PUBLIC | ACC_STATIC | ACC_ABSTRACT | ACC_INTERFACE | ACC_ANNOTATION);
 339         ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
 340         String[] superAnno = { "java/lang/annotation/Annotation" };
 341         cw.visit(V1_8, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE | ACC_ANNOTATION,
 342                 name, null, "java/lang/Object", superAnno);
 343         annotateNativeLocation(cw, tree);
 344         Type type = tree.type().canonicalType();
 345         AnnotationVisitor av = cw.visitAnnotation("Ljava/lang/annotation/Target;", true);


 478                     mv.visitTypeAnnotation(
 479                             TypeReference.newFormalParameterReference(idx).getValue(),
 480                             null, alias.getAnnotationDescriptor(), true)
 481                       .visitEnd();
 482                 }
 483             }
 484             idx++;
 485         }
 486 
 487         if (fn.returnType instanceof TypeAlias) {
 488             TypeAlias alias = (TypeAlias) fn.returnType;
 489             logger.finest(() -> "  return type is an alias " + alias);
 490             if (alias.getAnnotationDescriptor() != null) {
 491                 mv.visitTypeAnnotation(
 492                         TypeReference.newTypeReference(TypeReference.METHOD_RETURN).getValue(),
 493                         null, alias.getAnnotationDescriptor(), true)
 494                   .visitEnd();
 495             }
 496         }
 497         mv.visitEnd();
 498         if (staticForwardGen != null) {
 499             staticForwardGen.visitFunction(funcTree, jt);
 500         }
 501         return null;
 502     }
 503 
 504     protected AsmCodeFactory addType(JType jt, Tree tree) {
 505         JType2 jt2 = null;
 506         if (jt instanceof JType2) {
 507             jt2 = (JType2) jt;
 508             jt = jt2.getDelegate();
 509         } else {
 510             logger.warning(() -> "Should have JType2 in addType");
 511             if (Main.DEBUG) {
 512                 new Throwable().printStackTrace(ctx.err);
 513             }
 514         }
 515         if (tree == null) {
 516             assert (jt2 != null);
 517             if (jt instanceof JType.FnIf) {
 518                 createFunctionalInterface(null, (JType.FnIf) jt);
 519             }
 520             return this;


 567 
 568         mv.visitCode();
 569 
 570         mv.visitLdcInsn(value);
 571         if (macroType.equals(char.class)) {
 572             mv.visitInsn(I2C);
 573             mv.visitInsn(IRETURN);
 574         } else if (macroType.equals(int.class)) {
 575             mv.visitInsn(IRETURN);
 576         } else if (macroType.equals(float.class)) {
 577             mv.visitInsn(FRETURN);
 578         } else if (macroType.equals(long.class)) {
 579             mv.visitInsn(LRETURN);
 580         } else if (macroType.equals(double.class)) {
 581             mv.visitInsn(DRETURN);
 582         } else if (macroType.equals(String.class)) {
 583             mv.visitInsn(ARETURN);
 584         }
 585         mv.visitMaxs(0, 0);
 586         mv.visitEnd();
 587         if (staticForwardGen != null) {
 588             staticForwardGen.visitMacro(macroTree, jt);
 589         }
 590         return null;
 591     }
 592 
 593     protected synchronized void produce() {
 594         if (built) {
 595             throw new IllegalStateException("Produce is called multiple times");
 596         }
 597         built = true;
 598         generateNativeHeader();
 599         try {
 600             writeClassFile(global_cw, owner.clsName);
 601         } catch (IOException ex) {
 602             handleException(ex);
 603         }
 604         if (staticForwardGen != null) {
 605             types.put(staticForwardGen.getSimpleClassName(), staticForwardGen.getClassBytes());
 606         }
 607     }
 608 
 609     protected Map<String, byte[]> collect() {
 610         // Ensure classes are produced
 611         if (!built) produce();
 612         HashMap<String, byte[]> rv = new HashMap<>();
 613         // Not copying byte[] for efficiency, perhaps not a safe idea though
 614         if (owner.pkgName.isEmpty()) {
 615             types.forEach((clsName, bytecodes) -> {
 616                 rv.put(clsName, bytecodes);
 617             });
 618         } else {
 619             types.forEach((clsName, bytecodes) -> {
 620                 rv.put(owner.pkgName + "." + clsName, bytecodes);
 621             });
 622         }
 623         return Collections.unmodifiableMap(rv);
 624     }
 625 }
< prev index next >