< prev index next >

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

Print this page

        

*** 20,31 **** * 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.nio.file.Path; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; --- 20,31 ---- * or visit www.oracle.com if you need additional information or have any * questions. */ package com.sun.tools.jextract; 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,142 **** 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 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(); global_cw.visit(V1_8, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE, headerClassName, null, "java/lang/Object", null); } ! private void generateNativeHeader() { AnnotationVisitor av = global_cw.visitAnnotation(NATIVE_HEADER, true); av.visit("path", headerFile.path.toAbsolutePath().toString()); ! if (headerFile.libraries != null && !headerFile.libraries.isEmpty()) { AnnotationVisitor libNames = av.visitArray("libraries"); ! for (String name : headerFile.libraries) { libNames.visit(null, name); } libNames.visitEnd(); ! if (headerFile.libraryPaths != null && !headerFile.libraryPaths.isEmpty()) { AnnotationVisitor libPaths = av.visitArray("libraryPaths"); ! for (String path : headerFile.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)); } private void handleException(Exception ex) { ! ctx.err.println(Main.format("cannot.write.class.file", headerFile.pkgName + "." + headerFile.clsName, ex)); if (Main.DEBUG) { ! ex.printStackTrace(ctx.err); } } private void annotateNativeLocation(ClassVisitor cw, Tree tree) { ! if (! ctx.getNoNativeLocations()) { 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()); --- 74,153 ---- 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 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<>(); protected final String headerClassName; protected final HeaderFile headerFile; 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) { 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.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); } ! 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 (!libraryNames.isEmpty()) { AnnotationVisitor libNames = av.visitArray("libraries"); ! for (String name : libraryNames) { libNames.visit(null, name); } libNames.visitEnd(); ! if (!libraryPaths.isEmpty()) { AnnotationVisitor libPaths = av.visitArray("libraryPaths"); ! for (String path : libraryPaths) { libPaths.visit(null, path); } libPaths.visitEnd(); } } av.visit("declarations", String.join(" ", headerDeclarations)); av.visitEnd(); ! global_cw.visitEnd(); ! addClassIfNeeded(headerClassName, global_cw.toByteArray()); ! return Collections.unmodifiableMap(types); } private void handleException(Exception ex) { ! err.println(Main.format("cannot.write.class.file", headerFile.pkgName + "." + headerFile.clsName, ex)); if (Main.DEBUG) { ! ex.printStackTrace(err); } } private void annotateNativeLocation(ClassVisitor cw, Tree tree) { ! 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,159 **** 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 static boolean isBitField(Tree tree) { return tree instanceof FieldTree && ((FieldTree)tree).isBitField(); --- 155,167 ---- av.visit("column", loc.column()); av.visitEnd(); } } ! 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,188 **** */ 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); 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()) { 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()); --- 175,196 ---- */ private boolean addField(ClassVisitor cw, Tree tree, Type parentType) { String fieldName = tree.name(); assert !fieldName.isEmpty(); Type type = tree.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 (! 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,233 **** } private void addConstant(ClassWriter cw, FieldTree fieldTree) { assert (fieldTree.isEnumConstant()); String name = fieldTree.name(); ! String desc = dict.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); } --- 231,241 ---- } private void addConstant(ClassWriter cw, FieldTree fieldTree) { assert (fieldTree.isEnumConstant()); String name = fieldTree.name(); ! 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,258 **** --- 257,273 ---- 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,290 **** 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); ! } return true; } Layout addGetterSetterName(Layout layout, String accessorName) { return layout --- 291,302 ---- cw.visitInnerClass(name, headerClassName, intf, ACC_PUBLIC | ACC_STATIC | ACC_ABSTRACT | ACC_INTERFACE); // fields structTree.fields().forEach(fieldTree -> addField(cw, fieldTree, type)); // Write class ! cw.visitEnd(); ! addClassIfNeeded(headerClassName + "$" + intf, cw.toByteArray()); return true; } Layout addGetterSetterName(Layout layout, String accessorName) { return layout
*** 343,357 **** 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); ! } } private void createFunctionalInterface(JType.FunctionalInterfaceType fnif) { JType.Function fn = fnif.getFunction(); String intf; --- 355,366 ---- 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 ! cw.visitEnd(); ! addClassIfNeeded(headerClassName + "$" + intf, cw.toByteArray()); } private void createFunctionalInterface(JType.FunctionalInterfaceType fnif) { JType.Function fn = fnif.getFunction(); String intf;
*** 385,399 **** } 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); ! } } @Override public Boolean visitTypedef(TypedefTree typedefTree, JType jt) { createAnnotationCls(typedefTree); --- 394,405 ---- } MethodVisitor mv = cw.visitMethod(flags, "fn", fn.getDescriptor(), fn.getSignature(false), null); mv.visitEnd(); // Write class ! cw.visitEnd(); ! addClassIfNeeded(headerClassName + "$" + intf, cw.toByteArray()); } @Override public Boolean visitTypedef(TypedefTree typedefTree, JType jt) { createAnnotationCls(typedefTree);
*** 428,438 **** final int tmp = i; logger.finer(() -> " arg " + tmp + ": " + name); mv.visitParameter(name, 0); } ! if (! ctx.getNoNativeLocations()) { 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()); --- 434,444 ---- final int tmp = i; logger.finer(() -> " arg " + tmp + ": " + name); mv.visitParameter(name, 0); } ! 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,460 **** mv.visitEnd(); return true; } ! protected AsmCodeFactory addType(JType jt, Tree tree) { try { logger.fine(() -> "Process tree " + tree.name()); ! tree.accept(this, jt); } catch (Exception ex) { handleException(ex); logger.warning("Tree causing above exception is: " + tree.name()); logger.warning(() -> tree.toString()); } --- 453,466 ---- mv.visitEnd(); return true; } ! private AsmCodeFactory generateDecl(Tree tree) { try { logger.fine(() -> "Process tree " + tree.name()); ! 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,486 **** 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()) { 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()); --- 482,492 ---- 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 (! 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,543 **** } 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); - } } --- 514,519 ----
< prev index next >