blob: 7ee4bdc0b5cf0fd915562d48f63421eafdd4ee0c [file] [log] [blame]
Mikaël Peltier7b7b53a2017-10-09 13:33:21 +02001// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4package invokecustom;
5
Rico Windc0016d12017-10-26 13:39:32 +02006
Mikaël Peltier7b7b53a2017-10-09 13:33:21 +02007import java.io.IOException;
Rico Windc0016d12017-10-26 13:39:32 +02008import java.io.InputStream;
9import java.io.OutputStream;
Mikaël Peltier7b7b53a2017-10-09 13:33:21 +020010import java.lang.invoke.CallSite;
Mikaël Peltier7b7b53a2017-10-09 13:33:21 +020011import java.lang.invoke.MethodHandles;
12import java.lang.invoke.MethodType;
Rico Windc0016d12017-10-26 13:39:32 +020013import java.nio.file.Files;
Mikaël Peltier7b7b53a2017-10-09 13:33:21 +020014import java.nio.file.Path;
15import java.nio.file.Paths;
16import org.objectweb.asm.ClassReader;
17import org.objectweb.asm.ClassVisitor;
18import org.objectweb.asm.ClassWriter;
19import org.objectweb.asm.Handle;
20import org.objectweb.asm.MethodVisitor;
21import org.objectweb.asm.Opcodes;
22import org.objectweb.asm.Type;
23
24public class TestGenerator {
25
26 private final Path classNamePath;
27
28 public static void main(String[] args) throws IOException {
29 assert args.length == 1;
30 TestGenerator testGenerator = new TestGenerator(Paths.get(args[0],
31 TestGenerator.class.getPackage().getName(), InvokeCustom.class.getSimpleName() + ".class"));
32 testGenerator.generateTests();
33 }
34
35 public TestGenerator(Path classNamePath) {
36 this.classNamePath = classNamePath;
37 }
38
39 private void generateTests() throws IOException {
Rico Windc0016d12017-10-26 13:39:32 +020040 try (InputStream inputStream = Files.newInputStream(classNamePath)) {
41 ClassReader cr = new ClassReader(inputStream);
42 ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
43 cr.accept(
44 new ClassVisitor(Opcodes.ASM6, cw) {
45 @Override
46 public void visitEnd() {
47 generateMethodTest1(cw);
48 generateMethodTest2(cw);
49 generateMethodMain(cw);
50 super.visitEnd();
51 }
52 }, 0);
53 try (OutputStream output = Files.newOutputStream(classNamePath)) {
54 output.write(cw.toByteArray());
55 }
56 }
Mikaël Peltier7b7b53a2017-10-09 13:33:21 +020057 }
58
59 /* Generate main method that only call all test methods. */
60 private void generateMethodMain(ClassVisitor cv) {
61 MethodVisitor mv = cv.visitMethod(
62 Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "main", "([Ljava/lang/String;)V", null, null);
63 mv.visitMethodInsn(
64 Opcodes.INVOKESTATIC, Type.getInternalName(InvokeCustom.class), "test1", "()V", false);
Mikaël Peltiercfd6dac2017-10-10 13:45:55 +020065 mv.visitMethodInsn(
66 Opcodes.INVOKESTATIC, Type.getInternalName(InvokeCustom.class), "test2", "()V", false);
Mikaël Peltier7b7b53a2017-10-09 13:33:21 +020067 mv.visitInsn(Opcodes.RETURN);
68 mv.visitMaxs(-1, -1);
69 }
70
71 /**
72 * Generate test with an invokedynamic, a static bootstrap method without extra args and
73 * args to the target method.
74 */
75 private void generateMethodTest1(ClassVisitor cv) {
76 MethodVisitor mv = cv.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "test1", "()V",
77 null, null);
78 MethodType mt = MethodType.methodType(
79 CallSite.class, MethodHandles.Lookup.class, String.class, MethodType.class);
80 Handle bootstrap = new Handle( Opcodes.H_INVOKESTATIC, Type.getInternalName(InvokeCustom.class),
81 "bsmLookupStatic", mt.toMethodDescriptorString(), false);
82 mv.visitLdcInsn(new Handle(Opcodes.H_INVOKESTATIC, Type.getInternalName(InvokeCustom.class),
83 "targetMethodTest1", "()V", false));
84 mv.visitLdcInsn(new Handle(Opcodes.H_GETSTATIC, Type.getInternalName(InvokeCustom.class),
85 "staticField1", "Ljava/lang/String;", false));
86 mv.visitInvokeDynamicInsn("targetMethodTest2",
87 "(Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;)V",
88 bootstrap);
89 mv.visitInsn(Opcodes.RETURN);
90 mv.visitMaxs(-1, -1);
91 }
Mikaël Peltiercfd6dac2017-10-10 13:45:55 +020092
93 /**
94 * Generate test with an invokedynamic, a static bootstrap method without extra args and
95 * args to the target method.
96 */
97 private void generateMethodTest2(ClassVisitor cv) {
98 MethodVisitor mv = cv.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "test2", "()V",
99 null, null);
100 MethodType mt = MethodType.methodType(
101 CallSite.class, MethodHandles.Lookup.class, String.class, MethodType.class);
102 Handle bootstrap = new Handle( Opcodes.H_INVOKESTATIC, Type.getInternalName(InvokeCustom.class),
103 "bsmLookupStatic", mt.toMethodDescriptorString(), false);
104 mv.visitLdcInsn(Type.getMethodType("(ZBSCIFJDLjava/lang/String;)Ljava/lang/Object;"));
105 mv.visitInvokeDynamicInsn("targetMethodTest3", "(Ljava/lang/invoke/MethodType;)V",
106 bootstrap);
107 mv.visitInsn(Opcodes.RETURN);
108 mv.visitMaxs(-1, -1);
109 }
Mikaël Peltier7b7b53a2017-10-09 13:33:21 +0200110}