< prev index next >

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

Print this page

        

@@ -20,12 +20,12 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
 package com.sun.tools.jextract;
 
-import java.io.IOException;
 import java.foreign.layout.Layout;
+import java.io.PrintWriter;
 import java.nio.file.Path;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;

@@ -74,69 +74,80 @@
     private static final String NATIVE_CALLBACK = ANNOTATION_PKG_PREFIX + "NativeCallback;";
     private static final String NATIVE_HEADER = ANNOTATION_PKG_PREFIX + "NativeHeader;";
     private static final String NATIVE_LOCATION = ANNOTATION_PKG_PREFIX + "NativeLocation;";
     private static final String NATIVE_STRUCT = ANNOTATION_PKG_PREFIX + "NativeStruct;";
 
-    private final Context ctx;
     private final ClassWriter global_cw;
     // to avoid duplicate generation of methods, field accessors, macros
     private final Set<String> global_methods = new HashSet<>();
     private final Set<String> global_fields = new HashSet<>();
     private final Set<String> global_macros = new HashSet<>();
     private final List<String> headerDeclarations = new ArrayList<>();
-    private transient boolean built = false;
     protected final String headerClassName;
     protected final HeaderFile headerFile;
-    protected final TypeDictionary dict;
     protected final Map<String, byte[]> types;
+    protected final List<String> libraryNames;
+    protected final List<String> libraryPaths;
+    protected final PrintWriter err;
+    protected final boolean noNativeLocations;
     protected final Logger logger = Logger.getLogger(getClass().getPackage().getName());
 
     AsmCodeFactory(Context ctx, HeaderFile header) {
-        this.ctx = ctx;
         logger.info(() -> "Instantiate AsmCodeFactory for " + header.path);
         this.headerFile = header;
         this.headerClassName = Utils.toInternalName(headerFile.pkgName, headerFile.clsName);
         this.global_cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
         this.types = new HashMap<>();
-        this.dict = headerFile.dictionary();
+        this.libraryNames = ctx.libraryNames;
+        this.libraryPaths = ctx.libraryPaths;
+        this.err = ctx.err;
+        this.noNativeLocations = ctx.noNativeLocations;
         global_cw.visit(V1_8, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE,
                 headerClassName,
                 null, "java/lang/Object", null);
     }
 
-    private void generateNativeHeader() {
+    public Map<String, byte[]> generateNativeHeader(List<Tree> decls) {
+        //generate all decls
+        decls.forEach(this::generateDecl);
+        //generate functional interfaces
+        headerFile.dictionary().functionalInterfaces()
+                .forEach(fi -> createFunctionalInterface((JType.FunctionalInterfaceType)fi));
+
+        //generate header intf
         AnnotationVisitor av = global_cw.visitAnnotation(NATIVE_HEADER, true);
         av.visit("path", headerFile.path.toAbsolutePath().toString());
-        if (headerFile.libraries != null && !headerFile.libraries.isEmpty()) {
+        if (!libraryNames.isEmpty()) {
             AnnotationVisitor libNames = av.visitArray("libraries");
-            for (String name : headerFile.libraries) {
+            for (String name : libraryNames) {
                 libNames.visit(null, name);
             }
             libNames.visitEnd();
-            if (headerFile.libraryPaths != null && !headerFile.libraryPaths.isEmpty()) {
+            if (!libraryPaths.isEmpty()) {
                 AnnotationVisitor libPaths = av.visitArray("libraryPaths");
-                for (String path : headerFile.libraryPaths) {
+                for (String path : libraryPaths) {
                     libPaths.visit(null, path);
                 }
                 libPaths.visitEnd();
             }
         }
         av.visit("declarations", String.join(" ", headerDeclarations));
         av.visitEnd();
-        //generate functional interfaces
-        dict.functionalInterfaces().forEach(fi -> createFunctionalInterface((JType.FunctionalInterfaceType)fi));
+        global_cw.visitEnd();
+        addClassIfNeeded(headerClassName, global_cw.toByteArray());
+        return Collections.unmodifiableMap(types);
     }
 
     private void handleException(Exception ex) {
-        ctx.err.println(Main.format("cannot.write.class.file", headerFile.pkgName + "." + headerFile.clsName, ex));
+        err.println(Main.format("cannot.write.class.file", headerFile.pkgName + "." + headerFile.clsName, ex));
         if (Main.DEBUG) {
-            ex.printStackTrace(ctx.err);
+            ex.printStackTrace(err);
         }
     }
 
     private void annotateNativeLocation(ClassVisitor cw, Tree tree) {
-        if (! ctx.getNoNativeLocations()) {
+        if (! noNativeLocations) {
             AnnotationVisitor av = cw.visitAnnotation(NATIVE_LOCATION, true);
             SourceLocation src = tree.location();
             SourceLocation.Location loc = src.getFileLocation();
             Path p = loc.path();
             av.visit("file", p == null ? "builtin" : p.toAbsolutePath().toString());

@@ -144,16 +155,13 @@
             av.visit("column", loc.column());
             av.visitEnd();
         }
     }
 
-    private void writeClassFile(final ClassWriter cw, String clsName)
-            throws IOException {
-        cw.visitEnd();
-        byte[] bytecodes = cw.toByteArray();
-        if (null != types.put(clsName, bytecodes)) {
-            logger.warning("Class " + clsName + " definition is overwritten");
+    private void addClassIfNeeded(String clsName, byte[] bytes) {
+        if (null != types.put(clsName, bytes)) {
+            err.println(Main.format("warn.class.overwritten", clsName));
         }
     }
 
     private static boolean isBitField(Tree tree) {
         return tree instanceof FieldTree && ((FieldTree)tree).isBitField();

@@ -167,22 +175,22 @@
      */
     private boolean addField(ClassVisitor cw, Tree tree, Type parentType) {
         String fieldName = tree.name();
         assert !fieldName.isEmpty();
         Type type = tree.type();
-        JType jt = dict.lookup(type);
+        JType jt = headerFile.dictionary().lookup(type);
         assert (jt != null);
         if (cw == global_cw) {
             String uniqueName = fieldName + "." + jt.getDescriptor();
             if (! global_fields.add(uniqueName)) {
                 return false; // added already
             }
         }
         MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_ABSTRACT, fieldName + "$get",
                 "()" + jt.getDescriptor(), "()" + jt.getSignature(false), null);
 
-        if (! ctx.getNoNativeLocations()) {
+        if (! noNativeLocations) {
             AnnotationVisitor av = mv.visitAnnotation(NATIVE_LOCATION, true);
             SourceLocation src = tree.location();
             SourceLocation.Location loc = src.getFileLocation();
             Path p = loc.path();
             av.visit("file", p == null ? "builtin" : p.toAbsolutePath().toString());

@@ -223,11 +231,11 @@
     }
 
     private void addConstant(ClassWriter cw, FieldTree fieldTree) {
         assert (fieldTree.isEnumConstant());
         String name = fieldTree.name();
-        String desc = dict.lookup(fieldTree.type()).getDescriptor();
+        String desc = headerFile.dictionary().lookup(fieldTree.type()).getDescriptor();
         MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, name, "()" + desc, null, null);
         mv.visitCode();
         if (desc.length() != 1) {
             throw new AssertionError("expected single char descriptor: " + desc);
         }

@@ -249,10 +257,17 @@
         mv.visitEnd();
     }
 
     @Override
     public Boolean visitStruct(StructTree structTree, JType jt) {
+        //generate nested structs recursively
+        structTree.nestedTypes().forEach(this::generateDecl);
+
+        if (structTree.isAnonymous()) {
+            //skip anonymous
+            return false;
+        }
         String nativeName = structTree.name();
         Type type = structTree.type();
         logger.fine(() -> "Create struct: " + nativeName);
 
         String intf = Utils.toClassName(nativeName);

@@ -276,15 +291,12 @@
         cw.visitInnerClass(name, headerClassName, intf, ACC_PUBLIC | ACC_STATIC | ACC_ABSTRACT | ACC_INTERFACE);
 
         // fields
         structTree.fields().forEach(fieldTree -> addField(cw, fieldTree, type));
         // Write class
-        try {
-            writeClassFile(cw, headerFile.clsName + "$" + intf);
-        } catch (IOException ex) {
-            handleException(ex);
-        }
+        cw.visitEnd();
+        addClassIfNeeded(headerClassName + "$" + intf, cw.toByteArray());
         return true;
     }
 
     Layout addGetterSetterName(Layout layout, String accessorName) {
         return layout

@@ -343,15 +355,12 @@
         av.visitEnum("value", "Ljava/lang/annotation/RetentionPolicy;", "RUNTIME");
         av.visitEnd();
         cw.visitInnerClass(name, headerClassName, intf,
                 ACC_PUBLIC | ACC_STATIC | ACC_ABSTRACT | ACC_INTERFACE | ACC_ANNOTATION);
         // Write class
-        try {
-            writeClassFile(cw, headerFile.clsName + "$" + intf);
-        } catch (IOException ex) {
-            handleException(ex);
-        }
+        cw.visitEnd();
+        addClassIfNeeded(headerClassName + "$" + intf, cw.toByteArray());
     }
 
     private void createFunctionalInterface(JType.FunctionalInterfaceType fnif) {
         JType.Function fn = fnif.getFunction();
         String intf;

@@ -385,15 +394,12 @@
         }
         MethodVisitor mv = cw.visitMethod(flags, "fn",
                 fn.getDescriptor(), fn.getSignature(false), null);
         mv.visitEnd();
         // Write class
-        try {
-            writeClassFile(cw, headerFile.clsName + "$" + intf);
-        } catch (IOException ex) {
-            handleException(ex);
-        }
+        cw.visitEnd();
+        addClassIfNeeded(headerClassName + "$" + intf, cw.toByteArray());
     }
 
     @Override
     public Boolean visitTypedef(TypedefTree typedefTree, JType jt) {
         createAnnotationCls(typedefTree);

@@ -428,11 +434,11 @@
             final int tmp = i;
             logger.finer(() -> "  arg " + tmp + ": " + name);
             mv.visitParameter(name, 0);
         }
 
-        if (! ctx.getNoNativeLocations()) {
+        if (! noNativeLocations) {
             AnnotationVisitor av = mv.visitAnnotation(NATIVE_LOCATION, true);
             SourceLocation src = funcTree.location();
             SourceLocation.Location loc = src.getFileLocation();
             Path p = loc.path();
             av.visit("file", p == null ? "builtin" : p.toAbsolutePath().toString());

@@ -447,14 +453,14 @@
 
         mv.visitEnd();
         return true;
     }
 
-    protected AsmCodeFactory addType(JType jt, Tree tree) {
+    private AsmCodeFactory generateDecl(Tree tree) {
         try {
             logger.fine(() -> "Process tree " + tree.name());
-            tree.accept(this, jt);
+            tree.accept(this, tree.isPreprocessing() ? null : headerFile.dictionary().lookup(tree.type()));
         } catch (Exception ex) {
             handleException(ex);
             logger.warning("Tree causing above exception is: " + tree.name());
             logger.warning(() -> tree.toString());
         }

@@ -476,11 +482,11 @@
         Class<?> macroType = Utils.unboxIfNeeded(value.getClass());
 
         String sig = jdk.internal.org.objectweb.asm.Type.getMethodDescriptor(jdk.internal.org.objectweb.asm.Type.getType(macroType));
         MethodVisitor mv = global_cw.visitMethod(ACC_PUBLIC, name, sig, sig, null);
 
-        if (! ctx.getNoNativeLocations()) {
+        if (! noNativeLocations) {
             AnnotationVisitor av = mv.visitAnnotation(NATIVE_LOCATION, true);
             SourceLocation src = macroTree.location();
             SourceLocation.Location loc = src.getFileLocation();
             Path p = loc.path();
             av.visit("file", p == null ? "builtin" : p.toAbsolutePath().toString());

@@ -508,36 +514,6 @@
         }
         mv.visitMaxs(0, 0);
         mv.visitEnd();
         return true;
     }
-
-    protected synchronized void produce() {
-        if (built) {
-            throw new IllegalStateException("Produce is called multiple times");
-        }
-        built = true;
-        generateNativeHeader();
-        try {
-            writeClassFile(global_cw, headerFile.clsName);
-        } catch (IOException ex) {
-            handleException(ex);
-        }
-    }
-
-    protected Map<String, byte[]> collect() {
-        // Ensure classes are produced
-        if (!built) produce();
-        HashMap<String, byte[]> rv = new HashMap<>();
-        // Not copying byte[] for efficiency, perhaps not a safe idea though
-        if (headerFile.pkgName.isEmpty()) {
-            types.forEach((clsName, bytecodes) -> {
-                rv.put(clsName, bytecodes);
-            });
-        } else {
-            types.forEach((clsName, bytecodes) -> {
-                rv.put(headerFile.pkgName + "." + clsName, bytecodes);
-            });
-        }
-        return Collections.unmodifiableMap(rv);
-    }
 }
< prev index next >