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