< 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 >