< prev index next >

src/jdk.jextract/share/classes/com/sun/tools/jextract/AsmCodeFactory.java

Print this page




   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 package com.sun.tools.jextract;
  24 
  25 import java.io.IOException;




  26 import java.foreign.layout.Layout;
  27 import java.nio.file.Path;
  28 import java.nio.file.Paths;
  29 import java.util.ArrayList;
  30 import java.util.Collections;
  31 import java.util.HashMap;
  32 import java.util.HashSet;
  33 import java.util.List;
  34 import java.util.Map;
  35 import java.util.Set;
  36 import java.util.logging.Logger;
  37 import java.util.stream.Stream;
  38 import jdk.internal.clang.SourceLocation;
  39 import jdk.internal.clang.Type;
  40 import jdk.internal.clang.TypeKind;
  41 import jdk.internal.org.objectweb.asm.AnnotationVisitor;

  42 import jdk.internal.org.objectweb.asm.ClassVisitor;
  43 import jdk.internal.org.objectweb.asm.ClassWriter;
  44 import jdk.internal.org.objectweb.asm.MethodVisitor;
  45 import jdk.internal.org.objectweb.asm.TypeReference;
  46 import com.sun.tools.jextract.tree.EnumTree;
  47 import com.sun.tools.jextract.tree.FieldTree;
  48 import com.sun.tools.jextract.tree.FunctionTree;
  49 import com.sun.tools.jextract.tree.MacroTree;
  50 import com.sun.tools.jextract.tree.SimpleTreeVisitor;
  51 import com.sun.tools.jextract.tree.StructTree;
  52 import com.sun.tools.jextract.tree.Tree;
  53 import com.sun.tools.jextract.tree.TypedefTree;
  54 import com.sun.tools.jextract.tree.VarTree;
  55 
  56 import static jdk.internal.org.objectweb.asm.Opcodes.ACC_ABSTRACT;
  57 import static jdk.internal.org.objectweb.asm.Opcodes.ACC_ANNOTATION;
  58 import static jdk.internal.org.objectweb.asm.Opcodes.ACC_FINAL;
  59 import static jdk.internal.org.objectweb.asm.Opcodes.ACC_INTERFACE;
  60 import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PUBLIC;

  61 import static jdk.internal.org.objectweb.asm.Opcodes.ACC_STATIC;
  62 import static jdk.internal.org.objectweb.asm.Opcodes.ACC_VARARGS;
  63 import static jdk.internal.org.objectweb.asm.Opcodes.ARETURN;

  64 import static jdk.internal.org.objectweb.asm.Opcodes.DRETURN;
  65 import static jdk.internal.org.objectweb.asm.Opcodes.FRETURN;

  66 import static jdk.internal.org.objectweb.asm.Opcodes.I2C;



  67 import static jdk.internal.org.objectweb.asm.Opcodes.IRETURN;
  68 import static jdk.internal.org.objectweb.asm.Opcodes.LRETURN;


  69 import static jdk.internal.org.objectweb.asm.Opcodes.V1_8;
  70 
  71 /**
  72  * Scan a header file and generate classes for entities defined in that header
  73  * file.
  74  */
  75 final class AsmCodeFactory extends SimpleTreeVisitor<Void, JType> {
  76     private static final String ANNOTATION_PKG_PREFIX = "Ljava/foreign/annotations/";
  77     private static final String NATIVE_CALLBACK = ANNOTATION_PKG_PREFIX + "NativeCallback;";
  78     private static final String NATIVE_HEADER = ANNOTATION_PKG_PREFIX + "NativeHeader;";
  79     private static final String NATIVE_LOCATION = ANNOTATION_PKG_PREFIX + "NativeLocation;";
  80     private static final String NATIVE_STRUCT = ANNOTATION_PKG_PREFIX + "NativeStruct;";
  81 
  82     private final Context ctx;


  83     private final ClassWriter global_cw;
  84     // to avoid duplicate generation of methods, field accessors, macros
  85     private final Set<String> global_methods = new HashSet<>();
  86     private final Set<String> global_fields = new HashSet<>();
  87     private final Set<String> global_macros = new HashSet<>();
  88     private final String internal_name;

  89     private final HeaderFile owner;
  90     private final Map<String, byte[]> types;
  91     private final Logger logger = Logger.getLogger(getClass().getPackage().getName());
  92     private final List<String> headerDeclarations = new ArrayList<>();
  93     private transient boolean built = false;
  94 




  95     AsmCodeFactory(Context ctx, HeaderFile header) {
  96         this.ctx = ctx;
  97         logger.info(() -> "Instantiate AsmCodeFactory for " + header.path);
  98         this.owner = header;
  99         this.internal_name = Utils.toInternalName(owner.pkgName, owner.clsName);

 100         this.global_cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
 101         this.types = new HashMap<>();
 102         global_cw.visit(V1_8, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE,
 103                 internal_name,
 104                 null, "java/lang/Object", null);






























































 105     }
 106 
 107     private void generateNativeHeader() {
 108         AnnotationVisitor av = global_cw.visitAnnotation(NATIVE_HEADER, true);
 109         av.visit("path", owner.path.toAbsolutePath().toString());
 110         if (owner.libraries != null && !owner.libraries.isEmpty()) {
 111             AnnotationVisitor libNames = av.visitArray("libraries");
 112             for (String name : owner.libraries) {
 113                 libNames.visit(null, name);
 114             }
 115             libNames.visitEnd();
 116             if (owner.libraryPaths != null && !owner.libraryPaths.isEmpty()) {
 117                 AnnotationVisitor libPaths = av.visitArray("libraryPaths");
 118                 for (String path : owner.libraryPaths) {
 119                     libPaths.visit(null, path);
 120                 }
 121                 libPaths.visitEnd();
 122             }
 123         }
 124         av.visit("declarations", String.join(" ", headerDeclarations));
 125         av.visitEnd();
 126     }
 127 
 128     private void handleException(Exception ex) {
 129         ctx.err.println(Main.format("cannot.write.class.file", owner.pkgName + "." + owner.clsName, ex));
 130         if (Main.DEBUG) {


 220         mv.visitCode();
 221         if (desc.length() != 1) {
 222             throw new AssertionError("expected single char descriptor: " + desc);
 223         }
 224         switch (desc.charAt(0)) {
 225             case 'J':
 226                 long lvalue = fieldTree.enumConstant().get();
 227                 mv.visitLdcInsn(lvalue);
 228                 mv.visitInsn(LRETURN);
 229                 break;
 230             case 'I':
 231                 int ivalue = fieldTree.enumConstant().get().intValue();
 232                 mv.visitLdcInsn(ivalue);
 233                 mv.visitInsn(IRETURN);
 234                 break;
 235             default:
 236                 throw new AssertionError("should not reach here");
 237         }
 238         mv.visitMaxs(1, 1);
 239         mv.visitEnd();


 240     }
 241 
 242     @Override
 243     public Void visitStruct(StructTree structTree, JType jt) {
 244         String nativeName = structTree.name();
 245         Type type = structTree.type();
 246         logger.fine(() -> "Create struct: " + nativeName);
 247 
 248         String intf = Utils.toClassName(nativeName);
 249         String name = internal_name + "$" + intf;
 250 
 251         logger.fine(() -> "Define class " + name + " for native type " + nativeName);
 252         /* FIXME: Member interface is implicit static, also ASM.CheckClassAdapter is not
 253          * taking static as a valid flag, so comment this out during development.
 254          */
 255         global_cw.visitInnerClass(name, internal_name, intf, ACC_PUBLIC | ACC_STATIC | ACC_ABSTRACT | ACC_INTERFACE);
 256         ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
 257         cw.visit(V1_8, ACC_PUBLIC /*| ACC_STATIC*/ | ACC_INTERFACE | ACC_ABSTRACT,
 258                 name, "Ljava/lang/Object;Ljava/foreign/memory/Struct<L" + name + ";>;",
 259                 "java/lang/Object", new String[] {"java/foreign/memory/Struct"});


 463                     mv.visitTypeAnnotation(
 464                             TypeReference.newFormalParameterReference(idx).getValue(),
 465                             null, alias.getAnnotationDescriptor(), true)
 466                       .visitEnd();
 467                 }
 468             }
 469             idx++;
 470         }
 471 
 472         if (fn.returnType instanceof TypeAlias) {
 473             TypeAlias alias = (TypeAlias) fn.returnType;
 474             logger.finest(() -> "  return type is an alias " + alias);
 475             if (alias.getAnnotationDescriptor() != null) {
 476                 mv.visitTypeAnnotation(
 477                         TypeReference.newTypeReference(TypeReference.METHOD_RETURN).getValue(),
 478                         null, alias.getAnnotationDescriptor(), true)
 479                   .visitEnd();
 480             }
 481         }
 482         mv.visitEnd();

 483         return null;
 484     }
 485 





























 486     protected AsmCodeFactory addType(JType jt, Tree tree) {
 487         JType2 jt2 = null;
 488         if (jt instanceof JType2) {
 489             jt2 = (JType2) jt;
 490             jt = jt2.getDelegate();
 491         } else {
 492             logger.warning(() -> "Should have JType2 in addType");
 493             if (Main.DEBUG) {
 494                 new Throwable().printStackTrace(ctx.err);
 495             }
 496         }
 497         if (tree == null) {
 498             assert (jt2 != null);
 499             if (jt instanceof JType.FnIf) {
 500                 createFunctionalInterface(null, (JType.FnIf) jt);
 501             }
 502             return this;
 503         }
 504         /*
 505         // FIXME: what is this?


 549 
 550         mv.visitCode();
 551 
 552         mv.visitLdcInsn(value);
 553         if (macroType.equals(char.class)) {
 554             mv.visitInsn(I2C);
 555             mv.visitInsn(IRETURN);
 556         } else if (macroType.equals(int.class)) {
 557             mv.visitInsn(IRETURN);
 558         } else if (macroType.equals(float.class)) {
 559             mv.visitInsn(FRETURN);
 560         } else if (macroType.equals(long.class)) {
 561             mv.visitInsn(LRETURN);
 562         } else if (macroType.equals(double.class)) {
 563             mv.visitInsn(DRETURN);
 564         } else if (macroType.equals(String.class)) {
 565             mv.visitInsn(ARETURN);
 566         }
 567         mv.visitMaxs(0, 0);
 568         mv.visitEnd();


 569         return null;
 570     }
 571 
 572     protected synchronized void produce() {
 573         if (built) {
 574             throw new IllegalStateException("Produce is called multiple times");
 575         }
 576         built = true;
 577         generateNativeHeader();
 578         try {
 579             writeClassFile(global_cw, owner.clsName);



 580         } catch (IOException ex) {
 581             handleException(ex);
 582         }
 583     }
 584 
 585     protected Map<String, byte[]> collect() {
 586         // Ensure classes are produced
 587         if (!built) produce();
 588         HashMap<String, byte[]> rv = new HashMap<>();
 589         // Not copying byte[] for efficiency, perhaps not a safe idea though
 590         if (owner.pkgName.isEmpty()) {
 591             types.forEach((clsName, bytecodes) -> {
 592                 rv.put(clsName, bytecodes);
 593             });
 594         } else {
 595             types.forEach((clsName, bytecodes) -> {
 596                 rv.put(owner.pkgName + "." + clsName, bytecodes);
 597             });
 598         }
 599         return Collections.unmodifiableMap(rv);


   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 package com.sun.tools.jextract;
  24 
  25 import java.io.IOException;
  26 import java.foreign.Libraries;
  27 import java.lang.invoke.MethodHandles;
  28 import java.lang.invoke.MethodHandles.Lookup;
  29 import java.lang.reflect.Method;
  30 import java.foreign.layout.Layout;
  31 import java.nio.file.Path;
  32 import java.nio.file.Paths;
  33 import java.util.ArrayList;
  34 import java.util.Collections;
  35 import java.util.HashMap;
  36 import java.util.HashSet;
  37 import java.util.List;
  38 import java.util.Map;
  39 import java.util.Set;
  40 import java.util.logging.Logger;
  41 import java.util.stream.Stream;
  42 import jdk.internal.clang.SourceLocation;
  43 import jdk.internal.clang.Type;
  44 import jdk.internal.clang.TypeKind;
  45 import jdk.internal.org.objectweb.asm.AnnotationVisitor;
  46 import jdk.internal.org.objectweb.asm.FieldVisitor;
  47 import jdk.internal.org.objectweb.asm.ClassVisitor;
  48 import jdk.internal.org.objectweb.asm.ClassWriter;
  49 import jdk.internal.org.objectweb.asm.MethodVisitor;
  50 import jdk.internal.org.objectweb.asm.TypeReference;
  51 import com.sun.tools.jextract.tree.EnumTree;
  52 import com.sun.tools.jextract.tree.FieldTree;
  53 import com.sun.tools.jextract.tree.FunctionTree;
  54 import com.sun.tools.jextract.tree.MacroTree;
  55 import com.sun.tools.jextract.tree.SimpleTreeVisitor;
  56 import com.sun.tools.jextract.tree.StructTree;
  57 import com.sun.tools.jextract.tree.Tree;
  58 import com.sun.tools.jextract.tree.TypedefTree;
  59 import com.sun.tools.jextract.tree.VarTree;
  60 
  61 import static jdk.internal.org.objectweb.asm.Opcodes.ACC_ABSTRACT;
  62 import static jdk.internal.org.objectweb.asm.Opcodes.ACC_ANNOTATION;
  63 import static jdk.internal.org.objectweb.asm.Opcodes.ACC_FINAL;
  64 import static jdk.internal.org.objectweb.asm.Opcodes.ACC_INTERFACE;
  65 import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PUBLIC;
  66 import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PRIVATE;
  67 import static jdk.internal.org.objectweb.asm.Opcodes.ACC_STATIC;
  68 import static jdk.internal.org.objectweb.asm.Opcodes.ACC_VARARGS;
  69 import static jdk.internal.org.objectweb.asm.Opcodes.ARETURN;
  70 import static jdk.internal.org.objectweb.asm.Opcodes.CHECKCAST;
  71 import static jdk.internal.org.objectweb.asm.Opcodes.DRETURN;
  72 import static jdk.internal.org.objectweb.asm.Opcodes.FRETURN;
  73 import static jdk.internal.org.objectweb.asm.Opcodes.GETSTATIC;
  74 import static jdk.internal.org.objectweb.asm.Opcodes.I2C;
  75 import static jdk.internal.org.objectweb.asm.Opcodes.ILOAD;
  76 import static jdk.internal.org.objectweb.asm.Opcodes.INVOKEINTERFACE;
  77 import static jdk.internal.org.objectweb.asm.Opcodes.INVOKESTATIC;
  78 import static jdk.internal.org.objectweb.asm.Opcodes.IRETURN;
  79 import static jdk.internal.org.objectweb.asm.Opcodes.LRETURN;
  80 import static jdk.internal.org.objectweb.asm.Opcodes.PUTSTATIC;
  81 import static jdk.internal.org.objectweb.asm.Opcodes.RETURN;
  82 import static jdk.internal.org.objectweb.asm.Opcodes.V1_8;
  83 
  84 /**
  85  * Scan a header file and generate classes for entities defined in that header
  86  * file.
  87  */
  88 final class AsmCodeFactory extends SimpleTreeVisitor<Void, JType> {
  89     private static final String ANNOTATION_PKG_PREFIX = "Ljava/foreign/annotations/";
  90     private static final String NATIVE_CALLBACK = ANNOTATION_PKG_PREFIX + "NativeCallback;";
  91     private static final String NATIVE_HEADER = ANNOTATION_PKG_PREFIX + "NativeHeader;";
  92     private static final String NATIVE_LOCATION = ANNOTATION_PKG_PREFIX + "NativeLocation;";
  93     private static final String NATIVE_STRUCT = ANNOTATION_PKG_PREFIX + "NativeStruct;";
  94 
  95     private final Context ctx;
  96     // static methods forwards for this header file
  97     private final ClassWriter statics_cw;
  98     private final ClassWriter global_cw;
  99     // to avoid duplicate generation of methods, field accessors, macros
 100     private final Set<String> global_methods = new HashSet<>();
 101     private final Set<String> global_fields = new HashSet<>();
 102     private final Set<String> global_macros = new HashSet<>();
 103     private final String internal_name;
 104     private final String internal_name_desc;
 105     private final HeaderFile owner;
 106     private final Map<String, byte[]> types;
 107     private final Logger logger = Logger.getLogger(getClass().getPackage().getName());
 108     private final List<String> headerDeclarations = new ArrayList<>();
 109     private transient boolean built = false;
 110 
 111     // constants used by static forwarder class
 112     private static final String STATICS_CLASS_NAME_SUFFIX = "_h";
 113     private static final String STATICS_LIBRARY_FIELD_NAME = "_theLibrary";
 114 
 115     AsmCodeFactory(Context ctx, HeaderFile header) {
 116         this.ctx = ctx;
 117         logger.info(() -> "Instantiate AsmCodeFactory for " + header.path);
 118         this.owner = header;
 119         this.internal_name = Utils.toInternalName(owner.pkgName, owner.clsName);
 120         this.internal_name_desc = "L" + internal_name + ";";
 121         this.global_cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
 122         this.types = new HashMap<>();
 123         global_cw.visit(V1_8, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE,
 124                 internal_name,
 125                 null, "java/lang/Object", null);
 126         // if there is no -l option specified, we cannot do Libraries.bind(Lookup, Class).
 127         // so, don't generate statics forwarder.
 128         if (librariesSpecified()) {
 129             this.statics_cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
 130             this.statics_cw.visit(V1_8, ACC_PUBLIC | ACC_FINAL,
 131                 internal_name + STATICS_CLASS_NAME_SUFFIX,
 132                 null, "java/lang/Object", null);
 133             staticsInitializer();
 134         } else {
 135             this.statics_cw = null;
 136         }
 137     }
 138 
 139     // emit library interface static field and <clinit> initializer for that field
 140     private void staticsInitializer() {
 141         // library interface field
 142         FieldVisitor fv = statics_cw.visitField(ACC_PRIVATE|ACC_STATIC|ACC_FINAL,
 143             STATICS_LIBRARY_FIELD_NAME, internal_name_desc, null, null);
 144         fv.visitEnd();
 145 
 146         // <clinit> to bind library interface field
 147         MethodVisitor mv = statics_cw.visitMethod(ACC_STATIC,
 148             "<clinit>", "()V", null, null);
 149         mv.visitCode();
 150 
 151         // MethodHandles.lookup()
 152         Method lookupMethod = null;
 153         try {
 154             lookupMethod = MethodHandles.class.getMethod("lookup");
 155         } catch (NoSuchMethodException nsme) {
 156             throw new RuntimeException(nsme);
 157         }
 158         mv.visitMethodInsn(INVOKESTATIC,
 159             jdk.internal.org.objectweb.asm.Type.getInternalName(MethodHandles.class), "lookup",
 160             jdk.internal.org.objectweb.asm.Type.getMethodDescriptor(lookupMethod), false);
 161 
 162         // ldc library-interface-class
 163         mv.visitLdcInsn(jdk.internal.org.objectweb.asm.Type.getObjectType(internal_name));
 164 
 165         // Libraries.bind(lookup, class);
 166         Method bindMethod = null;
 167         try {
 168             bindMethod = Libraries.class.getMethod("bind", Lookup.class, Class.class);
 169         } catch (NoSuchMethodException nsme) {
 170             throw new RuntimeException(nsme);
 171         }
 172         mv.visitMethodInsn(INVOKESTATIC,
 173             jdk.internal.org.objectweb.asm.Type.getInternalName(Libraries.class), "bind",
 174             jdk.internal.org.objectweb.asm.Type.getMethodDescriptor(bindMethod), false);
 175 
 176         // store it in library interface field
 177         mv.visitTypeInsn(CHECKCAST, internal_name);
 178         mv.visitFieldInsn(PUTSTATIC, internal_name + STATICS_CLASS_NAME_SUFFIX,
 179             STATICS_LIBRARY_FIELD_NAME, internal_name_desc);
 180 
 181         mv.visitInsn(RETURN);
 182         mv.visitMaxs(0, 0);
 183         mv.visitEnd();
 184     }
 185 
 186     private boolean librariesSpecified() {
 187         return owner.libraries != null && !owner.libraries.isEmpty();
 188     }
 189 
 190     private void generateNativeHeader() {
 191         AnnotationVisitor av = global_cw.visitAnnotation(NATIVE_HEADER, true);
 192         av.visit("path", owner.path.toAbsolutePath().toString());
 193         if (librariesSpecified()) {
 194             AnnotationVisitor libNames = av.visitArray("libraries");
 195             for (String name : owner.libraries) {
 196                 libNames.visit(null, name);
 197             }
 198             libNames.visitEnd();
 199             if (owner.libraryPaths != null && !owner.libraryPaths.isEmpty()) {
 200                 AnnotationVisitor libPaths = av.visitArray("libraryPaths");
 201                 for (String path : owner.libraryPaths) {
 202                     libPaths.visit(null, path);
 203                 }
 204                 libPaths.visitEnd();
 205             }
 206         }
 207         av.visit("declarations", String.join(" ", headerDeclarations));
 208         av.visitEnd();
 209     }
 210 
 211     private void handleException(Exception ex) {
 212         ctx.err.println(Main.format("cannot.write.class.file", owner.pkgName + "." + owner.clsName, ex));
 213         if (Main.DEBUG) {


 303         mv.visitCode();
 304         if (desc.length() != 1) {
 305             throw new AssertionError("expected single char descriptor: " + desc);
 306         }
 307         switch (desc.charAt(0)) {
 308             case 'J':
 309                 long lvalue = fieldTree.enumConstant().get();
 310                 mv.visitLdcInsn(lvalue);
 311                 mv.visitInsn(LRETURN);
 312                 break;
 313             case 'I':
 314                 int ivalue = fieldTree.enumConstant().get().intValue();
 315                 mv.visitLdcInsn(ivalue);
 316                 mv.visitInsn(IRETURN);
 317                 break;
 318             default:
 319                 throw new AssertionError("should not reach here");
 320         }
 321         mv.visitMaxs(1, 1);
 322         mv.visitEnd();
 323         // static forwarder method for this enum constant
 324         emitStaticsForwarder(name, "()" + desc, null);
 325     }
 326 
 327     @Override
 328     public Void visitStruct(StructTree structTree, JType jt) {
 329         String nativeName = structTree.name();
 330         Type type = structTree.type();
 331         logger.fine(() -> "Create struct: " + nativeName);
 332 
 333         String intf = Utils.toClassName(nativeName);
 334         String name = internal_name + "$" + intf;
 335 
 336         logger.fine(() -> "Define class " + name + " for native type " + nativeName);
 337         /* FIXME: Member interface is implicit static, also ASM.CheckClassAdapter is not
 338          * taking static as a valid flag, so comment this out during development.
 339          */
 340         global_cw.visitInnerClass(name, internal_name, intf, ACC_PUBLIC | ACC_STATIC | ACC_ABSTRACT | ACC_INTERFACE);
 341         ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
 342         cw.visit(V1_8, ACC_PUBLIC /*| ACC_STATIC*/ | ACC_INTERFACE | ACC_ABSTRACT,
 343                 name, "Ljava/lang/Object;Ljava/foreign/memory/Struct<L" + name + ";>;",
 344                 "java/lang/Object", new String[] {"java/foreign/memory/Struct"});


 548                     mv.visitTypeAnnotation(
 549                             TypeReference.newFormalParameterReference(idx).getValue(),
 550                             null, alias.getAnnotationDescriptor(), true)
 551                       .visitEnd();
 552                 }
 553             }
 554             idx++;
 555         }
 556 
 557         if (fn.returnType instanceof TypeAlias) {
 558             TypeAlias alias = (TypeAlias) fn.returnType;
 559             logger.finest(() -> "  return type is an alias " + alias);
 560             if (alias.getAnnotationDescriptor() != null) {
 561                 mv.visitTypeAnnotation(
 562                         TypeReference.newTypeReference(TypeReference.METHOD_RETURN).getValue(),
 563                         null, alias.getAnnotationDescriptor(), true)
 564                   .visitEnd();
 565             }
 566         }
 567         mv.visitEnd();
 568         emitStaticsForwarder(funcTree.name(), fn.getDescriptor(), fn.getSignature());
 569         return null;
 570     }
 571 
 572     // emit static forwarder method for a specific library interface method
 573     private void emitStaticsForwarder(String name, String desc, String signature) {
 574         if (statics_cw == null) {
 575             return;
 576         }
 577         MethodVisitor statics_mv = statics_cw.visitMethod(ACC_PUBLIC | ACC_STATIC,
 578             name, desc, signature, null);
 579         statics_mv.visitCode();
 580 
 581         // load library interface (static) field
 582         statics_mv.visitFieldInsn(GETSTATIC, internal_name + STATICS_CLASS_NAME_SUFFIX,
 583             STATICS_LIBRARY_FIELD_NAME, internal_name_desc);
 584 
 585         // forward the call to the interface
 586         jdk.internal.org.objectweb.asm.Type[] argTypes = jdk.internal.org.objectweb.asm.Type.getArgumentTypes(desc);
 587         jdk.internal.org.objectweb.asm.Type retType = jdk.internal.org.objectweb.asm.Type.getReturnType(desc);
 588 
 589         int loadIdx = 0;
 590         for (int i = 0; i < argTypes.length; i++) {
 591             statics_mv.visitVarInsn(argTypes[i].getOpcode(ILOAD), loadIdx);
 592             loadIdx += argTypes[i].getSize();
 593         }
 594         statics_mv.visitMethodInsn(INVOKEINTERFACE, internal_name, name, desc, true);
 595         statics_mv.visitInsn(retType.getOpcode(IRETURN));
 596 
 597         statics_mv.visitMaxs(0, 0);
 598         statics_mv.visitEnd();
 599     }
 600 
 601     protected AsmCodeFactory addType(JType jt, Tree tree) {
 602         JType2 jt2 = null;
 603         if (jt instanceof JType2) {
 604             jt2 = (JType2) jt;
 605             jt = jt2.getDelegate();
 606         } else {
 607             logger.warning(() -> "Should have JType2 in addType");
 608             if (Main.DEBUG) {
 609                 new Throwable().printStackTrace(ctx.err);
 610             }
 611         }
 612         if (tree == null) {
 613             assert (jt2 != null);
 614             if (jt instanceof JType.FnIf) {
 615                 createFunctionalInterface(null, (JType.FnIf) jt);
 616             }
 617             return this;
 618         }
 619         /*
 620         // FIXME: what is this?


 664 
 665         mv.visitCode();
 666 
 667         mv.visitLdcInsn(value);
 668         if (macroType.equals(char.class)) {
 669             mv.visitInsn(I2C);
 670             mv.visitInsn(IRETURN);
 671         } else if (macroType.equals(int.class)) {
 672             mv.visitInsn(IRETURN);
 673         } else if (macroType.equals(float.class)) {
 674             mv.visitInsn(FRETURN);
 675         } else if (macroType.equals(long.class)) {
 676             mv.visitInsn(LRETURN);
 677         } else if (macroType.equals(double.class)) {
 678             mv.visitInsn(DRETURN);
 679         } else if (macroType.equals(String.class)) {
 680             mv.visitInsn(ARETURN);
 681         }
 682         mv.visitMaxs(0, 0);
 683         mv.visitEnd();
 684         // static forwarder method for this macro
 685         emitStaticsForwarder(name, sig, sig);
 686         return null;
 687     }
 688 
 689     protected synchronized void produce() {
 690         if (built) {
 691             throw new IllegalStateException("Produce is called multiple times");
 692         }
 693         built = true;
 694         generateNativeHeader();
 695         try {
 696             writeClassFile(global_cw, owner.clsName);
 697             if (statics_cw != null) {
 698                 writeClassFile(statics_cw, owner.clsName + STATICS_CLASS_NAME_SUFFIX);
 699             }
 700         } catch (IOException ex) {
 701             handleException(ex);
 702         }
 703     }
 704 
 705     protected Map<String, byte[]> collect() {
 706         // Ensure classes are produced
 707         if (!built) produce();
 708         HashMap<String, byte[]> rv = new HashMap<>();
 709         // Not copying byte[] for efficiency, perhaps not a safe idea though
 710         if (owner.pkgName.isEmpty()) {
 711             types.forEach((clsName, bytecodes) -> {
 712                 rv.put(clsName, bytecodes);
 713             });
 714         } else {
 715             types.forEach((clsName, bytecodes) -> {
 716                 rv.put(owner.pkgName + "." + clsName, bytecodes);
 717             });
 718         }
 719         return Collections.unmodifiableMap(rv);
< prev index next >