/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package constmethodhandle;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.invoke.CallSite;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.nio.file.OpenOption;
import java.nio.file.Path;
import java.nio.file.Paths;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Handle;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
public class TestGenerator {
private final Path classNamePath;
public static void main(String[] args) throws IOException {
assert args.length == 1;
TestGenerator testGenerator = new TestGenerator(Paths.get(args[0],
TestGenerator.class.getPackage().getName(), ConstTest.class.getSimpleName() + ".class"));
testGenerator.generateTests();
}
public TestGenerator(Path classNamePath) {
this.classNamePath = classNamePath;
}
private void generateTests() throws IOException {
ClassReader cr = new ClassReader(new FileInputStream(classNamePath.toFile()));
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
cr.accept(
new ClassVisitor(Opcodes.ASM5, cw) {
@Override
public void visitEnd() {
generateMethodTest1(cw);
generateMethodTest2(cw);
generateMethodMain(cw);
super.visitEnd();
}
}, 0);
new FileOutputStream(classNamePath.toFile()).write(cw.toByteArray());
}
/* generate main method that only call all test methods. */
private void generateMethodMain(ClassVisitor cv) {
MethodVisitor mv = cv.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC,
"main", "([Ljava/lang/String;)V", null, null);
String internalName = Type.getInternalName(ConstTest.class);
mv.visitMethodInsn(Opcodes.INVOKESTATIC, internalName, "test1",
"()Ljava/lang/invoke/MethodHandle;", false);
mv.visitMethodInsn(Opcodes.INVOKESTATIC, internalName,
"displayMethodHandle", "(Ljava/lang/invoke/MethodHandle;)V", false);
mv.visitMethodInsn(Opcodes.INVOKESTATIC, internalName, "test2",
"()Ljava/lang/invoke/MethodType;", false);
mv.visitMethodInsn(Opcodes.INVOKESTATIC, internalName, "displayMethodType",
"(Ljava/lang/invoke/MethodType;)V", false);
mv.visitInsn(Opcodes.RETURN);
mv.visitMaxs(-1, -1);
}
/**
* Generate a test that returns a constant method handle.
*/
private void generateMethodTest1(ClassVisitor cv) {
MethodVisitor mv = cv.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "test1",
"()Ljava/lang/invoke/MethodHandle;", null, null);
MethodType mt = MethodType.methodType(Class.class);
Handle mh = new Handle(Opcodes.H_INVOKEVIRTUAL, Type.getInternalName(Object.class),
"getClass", mt.toMethodDescriptorString(), false);
mv.visitLdcInsn(mh);
mv.visitInsn(Opcodes.ARETURN);
mv.visitMaxs(-1, -1);
}
/**
* Generate a test that returns a constant method type.
*/
private void generateMethodTest2(ClassVisitor cv) {
MethodVisitor mv = cv.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "test2",
"()Ljava/lang/invoke/MethodType;", null, null);
Type mt = Type.getMethodType(Type.getType(boolean.class), Type.getType(char.class),
Type.getType(short.class), Type.getType(int.class),
Type.getType(long.class), Type.getType(float.class),
Type.getType(double.class), Type.getType(Object.class));
mv.visitLdcInsn(mt);
mv.visitInsn(Opcodes.ARETURN);
mv.visitMaxs(-1, -1);
}
}