--- old/src/jdk.jextract/share/classes/com/sun/tools/jextract/AsmCodeFactoryExt.java 2019-04-25 08:51:41.000000000 +0530 +++ /dev/null 2019-04-25 08:51:41.000000000 +0530 @@ -1,366 +0,0 @@ -/* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.tools.jextract; - -import java.foreign.Libraries; -import java.foreign.Scope; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodHandles.Lookup; -import java.lang.invoke.MethodType; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.function.Consumer; -import java.util.logging.Level; - -import com.sun.tools.jextract.parser.MacroParser; -import com.sun.tools.jextract.tree.Tree; -import jdk.internal.org.objectweb.asm.FieldVisitor; -import jdk.internal.org.objectweb.asm.ClassWriter; -import jdk.internal.org.objectweb.asm.MethodVisitor; -import jdk.internal.org.objectweb.asm.Type; -import com.sun.tools.jextract.tree.EnumTree; -import com.sun.tools.jextract.tree.FieldTree; -import com.sun.tools.jextract.tree.FunctionTree; -import com.sun.tools.jextract.tree.MacroTree; -import com.sun.tools.jextract.tree.VarTree; - -import static jdk.internal.org.objectweb.asm.Opcodes.ACC_ABSTRACT; -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.ARETURN; -import static jdk.internal.org.objectweb.asm.Opcodes.ACC_VARARGS; -import static jdk.internal.org.objectweb.asm.Opcodes.CHECKCAST; -import static jdk.internal.org.objectweb.asm.Opcodes.GETSTATIC; -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.PUTSTATIC; -import static jdk.internal.org.objectweb.asm.Opcodes.RETURN; -import static jdk.internal.org.objectweb.asm.Opcodes.V1_8; - -/** - * This extended factory generates a class with only static methods and fields. A native - * library interface instance (of the given header file) is kept as a static private field. - * One static method is generated for every library interface method. Enum and macro constants - * are mapped to static final fields. By importing the "static forwarder" class, the user code - * looks more or less like C code. Libraries.bind and header interface usage is hidden. - */ -final class AsmCodeFactoryExt extends AsmCodeFactory { - private final String headerClassNameDesc; - private final String forwarderClassName; - private final ClassWriter cw; - // suffix for static forwarder class name - // field name for the header interface instance. - private static final String STATICS_LIBRARY_FIELD_NAME = "_theLibrary"; - - private final List> constantInitializers = new ArrayList<>(); - private final List enumFactories = new ArrayList<>(); - - AsmCodeFactoryExt(Context ctx, HeaderFile header) { - super(ctx, header); - log.print(Level.INFO, () -> "Instantiate StaticForwarderGenerator for " + header.path); - this.headerClassNameDesc = "L" + headerClassName + ";"; - this.forwarderClassName = Utils.toInternalName(header.pkgName, header.staticForwarderClsName); - this.cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); - this.cw.visit(V1_8, ACC_PUBLIC | ACC_FINAL, getClassName(), - null, "java/lang/Object", null); - scopeAccessor(); - } - - private class EnumFactory { - private final EnumTree enumTree; - private final String enumClassName; - - EnumFactory(EnumTree enumTree) { - log.print(Level.INFO, () -> "Instantiate EnumFactory for " + enumTree.name()); - this.enumTree = enumTree; - this.enumClassName = AsmCodeFactoryExt.this.getClassName() + "$" + enumTree.name(); - - } - - String getEnumName() { - return enumTree.name(); - } - - String getClassName() { - return enumClassName; - } - - byte[] getClassBytes() { - return generate(); - } - - private byte[] generate() { - ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); - cw.visit(V1_8, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE, enumClassName, - null, "java/lang/Object", null); - cw.visitInnerClass(enumClassName, AsmCodeFactoryExt.this.getClassName(), enumTree.name(), ACC_PUBLIC | ACC_FINAL); - enumTree.constants().forEach(constant -> { - String name = constant.name(); - JType type = headerFile.dictionary().lookup(constant.type()); - Object constantValue = makeConstantValue(type, constant.enumConstant().get()); - FieldVisitor fv = cw.visitField(ACC_PUBLIC | ACC_STATIC | ACC_FINAL, name, type.getDescriptor(), - type.getSignature(false), constantValue); - fv.visitEnd(); - }); - - cw.visitEnd(); - return cw.toByteArray(); - } - } - - @Override - public Boolean visitVar(VarTree varTree, JType jt) { - if (super.visitVar(varTree, jt)) { - String fieldName = varTree.name(); - assert !fieldName.isEmpty(); - - emitStaticForwarder(fieldName + "$get", - "()" + jt.getDescriptor(), "()" + jt.getSignature(false), false); - jt.visitInner(cw); - - emitStaticForwarder(fieldName + "$set", - "(" + jt.getDescriptor() + ")V", - "(" + jt.getSignature(true) + ")V", false); - JType ptrType = JType.GenericType.ofPointer(jt); - emitStaticForwarder(fieldName + "$ptr", - "()" + ptrType.getDescriptor(), "()" + ptrType.getSignature(false), false); - ptrType.visitInner(cw); - - return true; - } else { - return false; - } - } - - @Override - public Boolean visitEnum(EnumTree enumTree, JType jt) { - if (super.visitEnum(enumTree, jt)) { - if (enumTree.name().isEmpty()) { - enumTree.constants().forEach(constant -> addConstant(constant.name(), - headerFile.dictionary().lookup(constant.type()), - constant.enumConstant().get())); - } else { - EnumFactory ef = new EnumFactory(enumTree); - enumFactories.add(ef); - cw.visitInnerClass(ef.getClassName(), getClassName(), ef.getEnumName(), - ACC_PUBLIC | ACC_STATIC | ACC_ABSTRACT | ACC_INTERFACE); - } - return true; - } else { - return false; - } - } - - @Override - public Boolean visitFunction(FunctionTree funcTree, JType jt) { - if (super.visitFunction(funcTree, jt)) { - assert (jt instanceof JType.Function); - JType.Function fn = (JType.Function)jt; - log.print(Level.FINE, () -> "Add method: " + fn.getSignature(false)); - emitStaticForwarder(funcTree.name(), fn.getDescriptor(), fn.getSignature(false), fn.isVarArgs); - fn.visitInner(cw); - return true; - } else { - return false; - } - } - - @Override - public Boolean visitMacro(MacroTree macroTree, JType jt) { - if (super.visitMacro(macroTree, jt)) { - String name = macroTree.name(); - MacroParser.Macro macro = macroTree.macro().get(); - log.print(Level.FINE, () -> "Adding macro " + name); - addConstant(Utils.toMacroName(name), macro.type(), macro.value()); - return true; - } else { - return false; - } - } - - private void addConstant(String name, JType type, Object value) { - Object constantValue = makeConstantValue(type, value); - FieldVisitor fv = cw.visitField(ACC_PUBLIC | ACC_STATIC | ACC_FINAL, name, type.getDescriptor(), - type.getSignature(false), constantValue); - fv.visitEnd(); - if (constantValue == null) { - constantInitializers.add(mv -> { - // load library interface (static) field - String desc = type.getDescriptor(); - mv.visitFieldInsn(GETSTATIC, getClassName(), - STATICS_LIBRARY_FIELD_NAME, headerClassNameDesc); - mv.visitMethodInsn(INVOKEINTERFACE, headerClassName, name, "()" + desc, true); - mv.visitFieldInsn(PUTSTATIC, getClassName(), name, desc); - }); - } - } - - private Object makeConstantValue(JType type, Object value) { - switch (type.getDescriptor()) { - case "Z": - return ((long)value) != 0; - case "C": - return (char)(long)value; - case "B": - return (byte)(long)value; - case "S": - return (short)(long)value; - case "I": - return (int)(long)value; - case "F": - return (float)(double)value; - case "J": case "D": - return value; - default: - return null; - } - } - - @Override - public Map generateNativeHeader(List decls) { - Map results = new HashMap<>(); - results.putAll(super.generateNativeHeader(decls)); - staticsInitializer(); - results.put(getClassName(), getClassBytes()); - for (EnumFactory ef : enumFactories) { - results.put(ef.getClassName(), ef.getClassBytes()); - } - return Collections.unmodifiableMap(results); - } - - // Internals only below this point - - private String getClassName() { - return forwarderClassName; - } - - // return the generated static forwarder class bytes - private byte[] getClassBytes() { - cw.visitEnd(); - return cw.toByteArray(); - } - - // emit library interface static field and initializer for that field - private void staticsInitializer() { - // library interface field - FieldVisitor fv = cw.visitField(ACC_PRIVATE|ACC_STATIC|ACC_FINAL, - STATICS_LIBRARY_FIELD_NAME, headerClassNameDesc, null, null); - fv.visitEnd(); - - // to bind library interface field - MethodVisitor mv = cw.visitMethod(ACC_STATIC, - "", "()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, - Type.getInternalName(MethodHandles.class), "lookup", - Type.getMethodDescriptor(lookupMethod), false); - - // ldc library-interface-class - mv.visitLdcInsn(Type.getObjectType(headerClassName)); - - // 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, - Type.getInternalName(Libraries.class), "bind", - Type.getMethodDescriptor(bindMethod), false); - - // store it in library interface field - mv.visitTypeInsn(CHECKCAST, headerClassName); - mv.visitFieldInsn(PUTSTATIC, getClassName(), - STATICS_LIBRARY_FIELD_NAME, headerClassNameDesc); - - constantInitializers.forEach(init -> init.accept(mv)); - - mv.visitInsn(RETURN); - mv.visitMaxs(0, 0); - mv.visitEnd(); - } - - private void scopeAccessor() { - String scopeAccessorDesc = MethodType.methodType(Scope.class).descriptorString(); - MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "scope", scopeAccessorDesc, null, null); - mv.visitCode(); - - // load library interface (static) field - mv.visitFieldInsn(GETSTATIC, getClassName(), - STATICS_LIBRARY_FIELD_NAME, headerClassNameDesc); - - String libraryScopeDesc = MethodType.methodType(Scope.class, Object.class).descriptorString(); - mv.visitMethodInsn(INVOKESTATIC, Type.getInternalName(Libraries.class), "libraryScope", libraryScopeDesc, false); - mv.visitInsn(ARETURN); - mv.visitMaxs(1,1); - mv.visitEnd(); - } - - // emit static forwarder method for a specific library interface method - private void emitStaticForwarder(String name, String desc, String signature, boolean isVarArgs) { - int accessFlags = ACC_PUBLIC | ACC_STATIC; - if (isVarArgs) { - accessFlags |= ACC_VARARGS; - } - - MethodVisitor mv = cw.visitMethod(accessFlags, name, desc, signature, null); - mv.visitCode(); - - // load library interface (static) field - mv.visitFieldInsn(GETSTATIC, getClassName(), - STATICS_LIBRARY_FIELD_NAME, headerClassNameDesc); - - // forward the call to the interface - Type[] argTypes = Type.getArgumentTypes(desc); - Type retType = Type.getReturnType(desc); - - int loadIdx = 0; - for (int i = 0; i < argTypes.length; i++) { - mv.visitVarInsn(argTypes[i].getOpcode(ILOAD), loadIdx); - loadIdx += argTypes[i].getSize(); - } - mv.visitMethodInsn(INVOKEINTERFACE, headerClassName, name, desc, true); - mv.visitInsn(retType.getOpcode(IRETURN)); - - mv.visitMaxs(0, 0); - mv.visitEnd(); - } -}