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