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