jaroslav@1644: /** jaroslav@1644: * Back 2 Browser Bytecode Translator jaroslav@1644: * Copyright (C) 2012 Jaroslav Tulach jaroslav@1644: * jaroslav@1644: * This program is free software: you can redistribute it and/or modify jaroslav@1644: * it under the terms of the GNU General Public License as published by jaroslav@1644: * the Free Software Foundation, version 2 of the License. jaroslav@1644: * jaroslav@1644: * This program is distributed in the hope that it will be useful, jaroslav@1644: * but WITHOUT ANY WARRANTY; without even the implied warranty of jaroslav@1644: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the jaroslav@1644: * GNU General Public License for more details. jaroslav@1644: * jaroslav@1644: * You should have received a copy of the GNU General Public License jaroslav@1644: * along with this program. Look for COPYING file in the top folder. jaroslav@1644: * If not, see http://opensource.org/licenses/GPL-2.0. jaroslav@1644: */ jaroslav@1644: package org.apidesign.vm4brwsr; jaroslav@1644: jaroslav@1644: import java.io.InputStream; jaroslav@1644: import java.lang.invoke.CallSite; jaroslav@1644: import java.lang.invoke.MethodHandles; jaroslav@1644: import java.lang.invoke.MethodType; jaroslav@1644: import java.lang.reflect.Method; jaroslav@1644: import org.objectweb.asm.ClassReader; jaroslav@1644: import org.objectweb.asm.ClassVisitor; jaroslav@1644: import org.objectweb.asm.ClassWriter; jaroslav@1644: import org.objectweb.asm.Handle; jaroslav@1644: import org.objectweb.asm.MethodVisitor; jaroslav@1644: import org.objectweb.asm.Opcodes; jaroslav@1644: import static org.objectweb.asm.Opcodes.ASM4; jaroslav@1644: import static org.objectweb.asm.Opcodes.INVOKESTATIC; jaroslav@1644: import static org.testng.Assert.*; jaroslav@1644: import org.testng.annotations.BeforeClass; jaroslav@1644: import org.testng.annotations.Test; jaroslav@1644: jaroslav@1644: /** jaroslav@1644: * jaroslav@1644: * @author Jaroslav Tulach jaroslav@1644: */ jaroslav@1644: public class InvokeDynamicTest { jaroslav@1644: private static Class invokeDynamicClass; jaroslav@1644: jaroslav@1644: @Test public void simpleDynamicInJava() throws Exception { jaroslav@1644: Method m = invokeDynamicClass.getMethod("dynamicSay"); jaroslav@1644: Object ret = m.invoke(m); jaroslav@1644: assertEquals(ret, "Hello from Dynamic!"); jaroslav@1644: } jaroslav@1644: jaroslav@1644: jaroslav@1644: /* jaroslav@1644: private static TestVM code; jaroslav@1644: jaroslav@1644: @BeforeClass jaroslav@1644: public void compileTheCode() throws Exception { jaroslav@1644: code = TestVM.compileClass(InvokeDynamic.class.getName()); jaroslav@1644: } jaroslav@1644: jaroslav@1644: @AfterClass jaroslav@1644: public static void releaseTheCode() { jaroslav@1644: code = null; jaroslav@1644: } jaroslav@1644: jaroslav@1644: private void assertExec( jaroslav@1644: String msg, Class clazz, String method, Object expRes, Object... args jaroslav@1644: ) throws Exception { jaroslav@1644: code.assertExec(msg, clazz, method, expRes, args); jaroslav@1644: } jaroslav@1644: */ jaroslav@1644: jaroslav@1644: // jaroslav@1644: // the following code is inspired by jaroslav@1644: // https://code.google.com/p/indy-maven-plugin/ jaroslav@1644: // which I don't want to use, as it is not in a public repository jaroslav@1644: // jaroslav@1644: @BeforeClass jaroslav@1644: public static void prepareClass() throws Exception { jaroslav@1644: InputStream input = InvokeDynamic.class.getResourceAsStream("InvokeDynamic.class"); jaroslav@1644: assertNotNull(input, "Class found"); jaroslav@1644: jaroslav@1644: ClassReader reader = new ClassReader(input); jaroslav@1644: ClassWriter writer = new ClassWriter(reader, 0); jaroslav@1644: jaroslav@1644: reader.accept( jaroslav@1644: new ClassVisitor(ASM4, writer) { jaroslav@1644: @Override jaroslav@1644: public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions jaroslav@1644: ) { jaroslav@1644: MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions); jaroslav@1644: return new InvokeDynamicProcessor(mv); jaroslav@1644: } jaroslav@1644: }, jaroslav@1644: 0); jaroslav@1644: input.close(); jaroslav@1644: final byte[] invokeDynamicBytes = writer.toByteArray(); jaroslav@1644: ClassLoader l = new ClassLoader() { jaroslav@1644: @Override jaroslav@1644: public Class loadClass(String name) throws ClassNotFoundException { jaroslav@1644: if (name.equals(InvokeDynamic.class.getName())) { jaroslav@1644: return defineClass(name, invokeDynamicBytes, 0, invokeDynamicBytes.length); jaroslav@1644: } jaroslav@1644: return super.loadClass(name); jaroslav@1644: } jaroslav@1644: }; jaroslav@1644: invokeDynamicClass = l.loadClass(InvokeDynamic.class.getName()); jaroslav@1644: } jaroslav@1644: jaroslav@1644: jaroslav@1644: private static class InvokeDynamicProcessor extends MethodVisitor { jaroslav@1644: InvokeDynamicProcessor(MethodVisitor mv) { jaroslav@1644: super(ASM4, mv); jaroslav@1644: } jaroslav@1644: jaroslav@1644: @Override jaroslav@1644: public void visitMethodInsn(int opcode, String owner, String name, String desc) { jaroslav@1644: if (opcode == INVOKESTATIC) { jaroslav@1644: if (name.startsWith("TEST_dynamic_")) { jaroslav@1644: final String shortName = name.substring(13); jaroslav@1644: Handle mh = new Handle( jaroslav@1644: Opcodes.H_INVOKESTATIC, owner, shortName, jaroslav@1644: MethodType.methodType( jaroslav@1644: CallSite.class, jaroslav@1644: MethodHandles.Lookup.class, jaroslav@1644: String.class, jaroslav@1644: MethodType.class jaroslav@1644: ).toMethodDescriptorString() jaroslav@1644: ); jaroslav@1644: super.visitInvokeDynamicInsn(shortName, desc, mh); jaroslav@1644: return; jaroslav@1644: } jaroslav@1644: } jaroslav@1644: super.visitMethodInsn(opcode, owner, name, desc); jaroslav@1644: } jaroslav@1644: } jaroslav@1644: jaroslav@1644: jaroslav@1644: }