< prev index next >
src/jdk.jextract/share/classes/com/sun/tools/jextract/AsmCodeFactory.java
Print this page
*** 21,30 ****
--- 21,34 ----
* questions.
*/
package com.sun.tools.jextract;
import java.io.IOException;
+ import java.foreign.Libraries;
+ import java.lang.invoke.MethodHandles;
+ import java.lang.invoke.MethodHandles.Lookup;
+ import java.lang.reflect.Method;
import java.foreign.layout.Layout;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
*** 37,46 ****
--- 41,51 ----
import java.util.stream.Stream;
import jdk.internal.clang.SourceLocation;
import jdk.internal.clang.Type;
import jdk.internal.clang.TypeKind;
import jdk.internal.org.objectweb.asm.AnnotationVisitor;
+ import jdk.internal.org.objectweb.asm.FieldVisitor;
import jdk.internal.org.objectweb.asm.ClassVisitor;
import jdk.internal.org.objectweb.asm.ClassWriter;
import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.internal.org.objectweb.asm.TypeReference;
import com.sun.tools.jextract.tree.EnumTree;
*** 56,73 ****
--- 61,86 ----
import static jdk.internal.org.objectweb.asm.Opcodes.ACC_ABSTRACT;
import static jdk.internal.org.objectweb.asm.Opcodes.ACC_ANNOTATION;
import static jdk.internal.org.objectweb.asm.Opcodes.ACC_FINAL;
import static jdk.internal.org.objectweb.asm.Opcodes.ACC_INTERFACE;
import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PUBLIC;
+ import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PRIVATE;
import static jdk.internal.org.objectweb.asm.Opcodes.ACC_STATIC;
import static jdk.internal.org.objectweb.asm.Opcodes.ACC_VARARGS;
import static jdk.internal.org.objectweb.asm.Opcodes.ARETURN;
+ import static jdk.internal.org.objectweb.asm.Opcodes.CHECKCAST;
import static jdk.internal.org.objectweb.asm.Opcodes.DRETURN;
import static jdk.internal.org.objectweb.asm.Opcodes.FRETURN;
+ import static jdk.internal.org.objectweb.asm.Opcodes.GETSTATIC;
import static jdk.internal.org.objectweb.asm.Opcodes.I2C;
+ import static jdk.internal.org.objectweb.asm.Opcodes.ILOAD;
+ import static jdk.internal.org.objectweb.asm.Opcodes.INVOKEINTERFACE;
+ import static jdk.internal.org.objectweb.asm.Opcodes.INVOKESTATIC;
import static jdk.internal.org.objectweb.asm.Opcodes.IRETURN;
import static jdk.internal.org.objectweb.asm.Opcodes.LRETURN;
+ import static jdk.internal.org.objectweb.asm.Opcodes.PUTSTATIC;
+ import static jdk.internal.org.objectweb.asm.Opcodes.RETURN;
import static jdk.internal.org.objectweb.asm.Opcodes.V1_8;
/**
* Scan a header file and generate classes for entities defined in that header
* file.
*** 78,115 ****
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 String internal_name;
private final HeaderFile owner;
private final Map<String, byte[]> types;
private final Logger logger = Logger.getLogger(getClass().getPackage().getName());
private final List<String> headerDeclarations = new ArrayList<>();
private transient boolean built = false;
AsmCodeFactory(Context ctx, HeaderFile header) {
this.ctx = ctx;
logger.info(() -> "Instantiate AsmCodeFactory for " + header.path);
this.owner = header;
this.internal_name = Utils.toInternalName(owner.pkgName, owner.clsName);
this.global_cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
this.types = new HashMap<>();
global_cw.visit(V1_8, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE,
internal_name,
null, "java/lang/Object", null);
}
private void generateNativeHeader() {
AnnotationVisitor av = global_cw.visitAnnotation(NATIVE_HEADER, true);
av.visit("path", owner.path.toAbsolutePath().toString());
! if (owner.libraries != null && !owner.libraries.isEmpty()) {
AnnotationVisitor libNames = av.visitArray("libraries");
for (String name : owner.libraries) {
libNames.visit(null, name);
}
libNames.visitEnd();
--- 91,198 ----
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;
+ // static methods forwards for this header file
+ private final ClassWriter statics_cw;
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 String internal_name;
+ private final String internal_name_desc;
private final HeaderFile owner;
private final Map<String, byte[]> types;
private final Logger logger = Logger.getLogger(getClass().getPackage().getName());
private final List<String> headerDeclarations = new ArrayList<>();
private transient boolean built = false;
+ // constants used by static forwarder class
+ private static final String STATICS_CLASS_NAME_SUFFIX = "_h";
+ private static final String STATICS_LIBRARY_FIELD_NAME = "_theLibrary";
+
AsmCodeFactory(Context ctx, HeaderFile header) {
this.ctx = ctx;
logger.info(() -> "Instantiate AsmCodeFactory for " + header.path);
this.owner = header;
this.internal_name = Utils.toInternalName(owner.pkgName, owner.clsName);
+ this.internal_name_desc = "L" + internal_name + ";";
this.global_cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
this.types = new HashMap<>();
global_cw.visit(V1_8, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE,
internal_name,
null, "java/lang/Object", null);
+ // if there is no -l option specified, we cannot do Libraries.bind(Lookup, Class).
+ // so, don't generate statics forwarder.
+ if (librariesSpecified()) {
+ this.statics_cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
+ this.statics_cw.visit(V1_8, ACC_PUBLIC | ACC_FINAL,
+ internal_name + STATICS_CLASS_NAME_SUFFIX,
+ null, "java/lang/Object", null);
+ staticsInitializer();
+ } else {
+ this.statics_cw = null;
+ }
+ }
+
+ // emit library interface static field and <clinit> initializer for that field
+ private void staticsInitializer() {
+ // library interface field
+ FieldVisitor fv = statics_cw.visitField(ACC_PRIVATE|ACC_STATIC|ACC_FINAL,
+ STATICS_LIBRARY_FIELD_NAME, internal_name_desc, null, null);
+ fv.visitEnd();
+
+ // <clinit> to bind library interface field
+ MethodVisitor mv = statics_cw.visitMethod(ACC_STATIC,
+ "<clinit>", "()V", null, null);
+ mv.visitCode();
+
+ // MethodHandles.lookup()
+ Method lookupMethod = null;
+ try {
+ lookupMethod = MethodHandles.class.getMethod("lookup");
+ } catch (NoSuchMethodException nsme) {
+ throw new RuntimeException(nsme);
+ }
+ mv.visitMethodInsn(INVOKESTATIC,
+ jdk.internal.org.objectweb.asm.Type.getInternalName(MethodHandles.class), "lookup",
+ jdk.internal.org.objectweb.asm.Type.getMethodDescriptor(lookupMethod), false);
+
+ // ldc library-interface-class
+ mv.visitLdcInsn(jdk.internal.org.objectweb.asm.Type.getObjectType(internal_name));
+
+ // Libraries.bind(lookup, class);
+ Method bindMethod = null;
+ try {
+ bindMethod = Libraries.class.getMethod("bind", Lookup.class, Class.class);
+ } catch (NoSuchMethodException nsme) {
+ throw new RuntimeException(nsme);
+ }
+ mv.visitMethodInsn(INVOKESTATIC,
+ jdk.internal.org.objectweb.asm.Type.getInternalName(Libraries.class), "bind",
+ jdk.internal.org.objectweb.asm.Type.getMethodDescriptor(bindMethod), false);
+
+ // store it in library interface field
+ mv.visitTypeInsn(CHECKCAST, internal_name);
+ mv.visitFieldInsn(PUTSTATIC, internal_name + STATICS_CLASS_NAME_SUFFIX,
+ STATICS_LIBRARY_FIELD_NAME, internal_name_desc);
+
+ mv.visitInsn(RETURN);
+ mv.visitMaxs(0, 0);
+ mv.visitEnd();
+ }
+
+ private boolean librariesSpecified() {
+ return owner.libraries != null && !owner.libraries.isEmpty();
}
private void generateNativeHeader() {
AnnotationVisitor av = global_cw.visitAnnotation(NATIVE_HEADER, true);
av.visit("path", owner.path.toAbsolutePath().toString());
! if (librariesSpecified()) {
AnnotationVisitor libNames = av.visitArray("libraries");
for (String name : owner.libraries) {
libNames.visit(null, name);
}
libNames.visitEnd();
*** 235,244 ****
--- 318,329 ----
default:
throw new AssertionError("should not reach here");
}
mv.visitMaxs(1, 1);
mv.visitEnd();
+ // static forwarder method for this enum constant
+ emitStaticsForwarder(name, "()" + desc, null);
}
@Override
public Void visitStruct(StructTree structTree, JType jt) {
String nativeName = structTree.name();
*** 478,490 ****
--- 563,605 ----
null, alias.getAnnotationDescriptor(), true)
.visitEnd();
}
}
mv.visitEnd();
+ emitStaticsForwarder(funcTree.name(), fn.getDescriptor(), fn.getSignature());
return null;
}
+ // emit static forwarder method for a specific library interface method
+ private void emitStaticsForwarder(String name, String desc, String signature) {
+ if (statics_cw == null) {
+ return;
+ }
+ MethodVisitor statics_mv = statics_cw.visitMethod(ACC_PUBLIC | ACC_STATIC,
+ name, desc, signature, null);
+ statics_mv.visitCode();
+
+ // load library interface (static) field
+ statics_mv.visitFieldInsn(GETSTATIC, internal_name + STATICS_CLASS_NAME_SUFFIX,
+ STATICS_LIBRARY_FIELD_NAME, internal_name_desc);
+
+ // forward the call to the interface
+ jdk.internal.org.objectweb.asm.Type[] argTypes = jdk.internal.org.objectweb.asm.Type.getArgumentTypes(desc);
+ jdk.internal.org.objectweb.asm.Type retType = jdk.internal.org.objectweb.asm.Type.getReturnType(desc);
+
+ int loadIdx = 0;
+ for (int i = 0; i < argTypes.length; i++) {
+ statics_mv.visitVarInsn(argTypes[i].getOpcode(ILOAD), loadIdx);
+ loadIdx += argTypes[i].getSize();
+ }
+ statics_mv.visitMethodInsn(INVOKEINTERFACE, internal_name, name, desc, true);
+ statics_mv.visitInsn(retType.getOpcode(IRETURN));
+
+ statics_mv.visitMaxs(0, 0);
+ statics_mv.visitEnd();
+ }
+
protected AsmCodeFactory addType(JType jt, Tree tree) {
JType2 jt2 = null;
if (jt instanceof JType2) {
jt2 = (JType2) jt;
jt = jt2.getDelegate();
*** 564,573 ****
--- 679,690 ----
} else if (macroType.equals(String.class)) {
mv.visitInsn(ARETURN);
}
mv.visitMaxs(0, 0);
mv.visitEnd();
+ // static forwarder method for this macro
+ emitStaticsForwarder(name, sig, sig);
return null;
}
protected synchronized void produce() {
if (built) {
*** 575,584 ****
--- 692,704 ----
}
built = true;
generateNativeHeader();
try {
writeClassFile(global_cw, owner.clsName);
+ if (statics_cw != null) {
+ writeClassFile(statics_cw, owner.clsName + STATICS_CLASS_NAME_SUFFIX);
+ }
} catch (IOException ex) {
handleException(ex);
}
}
< prev index next >