1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package constmethodhandle; 18 19 import java.io.FileInputStream; 20 import java.io.FileOutputStream; 21 import java.io.IOException; 22 import java.lang.invoke.CallSite; 23 import java.lang.invoke.MethodHandle; 24 import java.lang.invoke.MethodHandles; 25 import java.lang.invoke.MethodType; 26 import java.nio.file.OpenOption; 27 import java.nio.file.Path; 28 import java.nio.file.Paths; 29 import org.objectweb.asm.ClassReader; 30 import org.objectweb.asm.ClassVisitor; 31 import org.objectweb.asm.ClassWriter; 32 import org.objectweb.asm.Handle; 33 import org.objectweb.asm.MethodVisitor; 34 import org.objectweb.asm.Opcodes; 35 import org.objectweb.asm.Type; 36 37 public class TestGenerator { 38 39 private final Path classNamePath; 40 41 public static void main(String[] args) throws IOException { 42 assert args.length == 1; 43 TestGenerator testGenerator = new TestGenerator(Paths.get(args[0], 44 TestGenerator.class.getPackage().getName(), ConstTest.class.getSimpleName() + ".class")); 45 testGenerator.generateTests(); 46 } 47 48 public TestGenerator(Path classNamePath) { 49 this.classNamePath = classNamePath; 50 } 51 52 private void generateTests() throws IOException { 53 ClassReader cr = new ClassReader(new FileInputStream(classNamePath.toFile())); 54 ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES); 55 cr.accept( 56 new ClassVisitor(Opcodes.ASM5, cw) { 57 @Override 58 public void visitEnd() { 59 generateMethodTest1(cw); 60 generateMethodTest2(cw); 61 generateMethodMain(cw); 62 super.visitEnd(); 63 } 64 }, 0); 65 new FileOutputStream(classNamePath.toFile()).write(cw.toByteArray()); 66 } 67 68 /* generate main method that only call all test methods. */ 69 private void generateMethodMain(ClassVisitor cv) { 70 MethodVisitor mv = cv.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, 71 "main", "([Ljava/lang/String;)V", null, null); 72 String internalName = Type.getInternalName(ConstTest.class); 73 mv.visitMethodInsn(Opcodes.INVOKESTATIC, internalName, "test1", 74 "()Ljava/lang/invoke/MethodHandle;", false); 75 mv.visitMethodInsn(Opcodes.INVOKESTATIC, internalName, 76 "displayMethodHandle", "(Ljava/lang/invoke/MethodHandle;)V", false); 77 mv.visitMethodInsn(Opcodes.INVOKESTATIC, internalName, "test2", 78 "()Ljava/lang/invoke/MethodType;", false); 79 mv.visitMethodInsn(Opcodes.INVOKESTATIC, internalName, "displayMethodType", 80 "(Ljava/lang/invoke/MethodType;)V", false); 81 mv.visitInsn(Opcodes.RETURN); 82 mv.visitMaxs(-1, -1); 83 } 84 85 /** 86 * Generate a test that returns a constant method handle. 87 */ 88 private void generateMethodTest1(ClassVisitor cv) { 89 MethodVisitor mv = cv.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "test1", 90 "()Ljava/lang/invoke/MethodHandle;", null, null); 91 MethodType mt = MethodType.methodType(Class.class); 92 Handle mh = new Handle(Opcodes.H_INVOKEVIRTUAL, Type.getInternalName(Object.class), 93 "getClass", mt.toMethodDescriptorString(), false); 94 mv.visitLdcInsn(mh); 95 mv.visitInsn(Opcodes.ARETURN); 96 mv.visitMaxs(-1, -1); 97 } 98 99 /** 100 * Generate a test that returns a constant method type. 101 */ 102 private void generateMethodTest2(ClassVisitor cv) { 103 MethodVisitor mv = cv.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "test2", 104 "()Ljava/lang/invoke/MethodType;", null, null); 105 Type mt = Type.getMethodType(Type.getType(boolean.class), Type.getType(char.class), 106 Type.getType(short.class), Type.getType(int.class), 107 Type.getType(long.class), Type.getType(float.class), 108 Type.getType(double.class), Type.getType(Object.class)); 109 mv.visitLdcInsn(mt); 110 mv.visitInsn(Opcodes.ARETURN); 111 mv.visitMaxs(-1, -1); 112 } 113 } 114