Java中的invokedynamic
来源:互联网 发布:大数据的商品化 编辑:程序博客网 时间:2024/05/21 15:01
invokedynamic字节码不能直接通过Java的编译器来直接生成的,它只有在碰到lambda的时候,会生成。
那么我们如果来测试invokedynamic字节码呢。可以通过asm-all-4.0.jar来自己生成。其实这个命名主要是为了动态语言而生的,
一般只有在写动态语言的解释器来需要用到。
可以看看下面一个例子,来了解一下invokedynamic是如何生成的使用的。
首先写一个生成invokedynamic的抽象类:
package invokedynamic;import java.lang.invoke.CallSite;import java.lang.invoke.MethodHandles;import java.lang.invoke.MethodType;import org.objectweb.asm.AnnotationVisitor;import org.objectweb.asm.ClassWriter;import org.objectweb.asm.FieldVisitor;import org.objectweb.asm.Handle;import org.objectweb.asm.MethodVisitor;import org.objectweb.asm.Opcodes;@SuppressWarnings("unused")public abstract class AbstractDynamicInvokerGenerator implements Opcodes {public byte[] dump(String dynamicInvokerClassName, String dynamicLinkageClassName, String bootstrapMethodName, String targetMethodDescriptor)throws Exception {ClassWriter cw = new ClassWriter(0);FieldVisitor fv;MethodVisitor mv;AnnotationVisitor av0;cw.visit(V1_7, ACC_PUBLIC + ACC_SUPER, dynamicInvokerClassName, null, "java/lang/Object", null);{mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);mv.visitCode();mv.visitVarInsn(ALOAD, 0);mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");mv.visitInsn(RETURN);mv.visitMaxs(1, 1);mv.visitEnd();}{mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "main", "([Ljava/lang/String;)V", null, null);mv.visitCode();MethodType mt = MethodType.methodType(CallSite.class, MethodHandles.Lookup.class, String.class,MethodType.class);Handle bootstrap = new Handle(Opcodes.H_INVOKESTATIC, dynamicLinkageClassName, bootstrapMethodName,mt.toMethodDescriptorString());int maxStackSize = addMethodParameters(mv);mv.visitInvokeDynamicInsn("runCalculation", targetMethodDescriptor, bootstrap); //注意这里mv.visitInsn(RETURN);mv.visitMaxs(maxStackSize, 1);mv.visitEnd();}cw.visitEnd();return cw.toByteArray();}protected abstract int addMethodParameters(MethodVisitor mv);}
asm通过
visitInvokeDynamicInsn命令来生成invokedynamic指令。
然后再实现一个通过invokedynamic来调用SimpleDynamicLinkageExample类bootstrapDynamic方法;
package invokedynamic.generator;import invokedynamic.AbstractDynamicInvokerGenerator;import java.io.File;import java.io.FileOutputStream;import java.io.IOException;import org.objectweb.asm.MethodVisitor;public class SimpleDynamicInvokerGenerator extendsAbstractDynamicInvokerGenerator {@Overrideprotected int addMethodParameters(MethodVisitor mv) {return 0;}public static void main(String[] args) throws IOException, Exception {String dynamicInvokerClassName = "invokedynamic/generator/SimpleDynamicInvoker";FileOutputStream fos = new FileOutputStream(new File("bin/"+ dynamicInvokerClassName + ".class"));fos.write(new SimpleDynamicInvokerGenerator().dump(dynamicInvokerClassName,"invokedynamic/linkageclasses/SimpleDynamicLinkageExample","bootstrapDynamic", "()V"));}}
然后实现SimpleDynamicLinkageExample类:
package invokedynamic.linkageclasses;import java.lang.invoke.CallSite;import java.lang.invoke.ConstantCallSite;import java.lang.invoke.MethodHandle;import java.lang.invoke.MethodHandles;import java.lang.invoke.MethodType;@SuppressWarnings({ "unused", "rawtypes" })public class SimpleDynamicLinkageExample {private static MethodHandle sayHello;private static void sayHello() {System.out.println("There we go!");}public static CallSite bootstrapDynamic(MethodHandles.Lookup caller, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {MethodHandles.Lookup lookup = MethodHandles.lookup();Class thisClass = lookup.lookupClass(); // (who am I?)sayHello = lookup.findStatic(thisClass, "sayHello", MethodType.methodType(void.class));return new ConstantCallSite(sayHello.asType(type));}}
这是需要的类就写完了,需要注意的是,你需要先在Eclipse中运行SimpleDynamicInvokerGenerator,让它生成invokedynamic/generator/SimpleDynamicInvoker.class文件;
这个类是我们的入口类,还需要注意的是,我是在Eclipse中编译这些文件的,如果你的bin目录指定到别的地方,你需要修改SimpleDynamicInvokerGenerator类中的路径;
因为生成的SimpleDynamicInvoker类对Eclipse不可见,所以我们需要在命令行中来执行它;
先cd到你的工程目录下,执行
C:\Users\tmp\workspace_java\SimpleDyn\bin>java -classpath "C:\Users\tmp\workspace_java\SimpleDyn\bin;" invokedynamic.generator.SimpleDynamicInvoker
There we go!
那么只是怎么完成的呢:
看看SimpleDynamicInvokerGenerator的内容就知道了:
// (version 1.7 : 51.0, super bit)public class invokedynamic.generator.SimpleDynamicInvoker { // Method descriptor #6 ()V // Stack: 1, Locals: 1 public SimpleDynamicInvoker(); 0 aload_0 [this] 1 invokespecial java.lang.Object() [8] 4 return // Method descriptor #10 ([Ljava/lang/String;)V // Stack: 0, Locals: 1 public static void main(java.lang.String[] arg0); 0 invokedynamic 0 runCalculation() : void [20] 5 returnBootstrap methods: 0 : # 17 invokestatic invokedynamic/linkageclasses/SimpleDynamicLinkageExample.bootstrapDynamic:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;Method arguments:}
在class中JVM通过invokedynamic来调用runCalculation方法,这个方法是我们通过asm来写入的,可以是任意的名字;
然后我们用通过Bootstrap方法将runCalculation和
SimpleDynamicLinkageExample的
bootstrapDynamic方法关联起来;
在
SimpleDynamicLinkageExample中我们有通过MethodHandle找到其中的sayHello方法,然后调用它,这样就完成了invokedynamic命令和实际的函数关联了起来。
http://niklasschlimm.blogspot.com/2012/02/java-7-complete-invokedynamic-example.html
- Java中的invokedynamic
- Scripting Java #3:Groovy与invokedynamic
- Java语言的动态性-invokedynamic
- JVM规范学习:invokedynamic
- java7 invokedynamic学习笔记
- invokedynamic与lambda表达式
- lambdas in java8 --invokedynamic
- Cause: InvokeDynamic not supported
- java7 invokedynamic命令深入研究
- java7 invokedynamic命令深入研究
- Java8学习笔记(2) -- InvokeDynamic指令
- MethodHandle与反射Method区别,invokedynamic指令
- java7 invokedynamic命令深入研究_0
- 动态类型的语言支持--invokedynamic
- invokevirtual、invokespecial、invokestatic、invokeinterface、invokedynamic介绍
- Reflect与jdk7引进的InvokeDynamic
- 代码模拟invokedynamic指令invokevirtual指令调用方法
- JRuby 1.7 Preview 1发布:默认使用Ruby 1.9,通过Invokedynamic改进了性能
- EtherCAT状态机----Kithara RTS
- jQuery Jcrop 结合后台java实现图像裁剪切图案例
- 64位windows操作系统安装scikit-learn
- 数据结构-线性结构-线性表及其实现
- 通过v$sqlarea,v$sql查询最占用资源的查询
- Java中的invokedynamic
- SMTP协议_454 Authentication failed, please open smtp flag first!
- nginx中rtmp协议的配置
- textarea限制字数
- ExtJs4.2应用:根据指定格式显示列字段信息
- servlet-api.jar和javax.servlet-api.jar、jstl.jar和jstl-api.jar的联系区别
- 图表样式预定义
- Ubuntu 12.04 编辑 /etc/profile 之后登陆界面进不去
- springmvc的foward和redirect跳转简单解析