java7 invokedynamic学习笔记

来源:互联网 发布:学日语 报班 知乎 编辑:程序博客网 时间:2024/05/21 08:01

概述

jvm中方法调用指令有:

invokeinterface:调用接口方法;

invokespecial:专门用来调用父类方法、私有方法和初始化方法;

invokestatic:调用静态方法;

invokevirtual:调用对象的一般方法。

这四个指令所对应的类、调用的方法在编译时几乎是固定的:invokestatic所对应的类为静态方法所在的类,方法为静态方法本身;invokespecial所对应的类为当前对象,方法是固定的;invokeinterface和invokevirtual所对应的类也为当前对象,方法可以因为继承和实现进行选择,但也仅限于整个继承体系中选择(比如:一个类的equals方法有重写,则调用当前对象的equals方法,否则就调用Object的equals方法,选择的余地不大)。


invokedynamic

在java7 JVM中增加了一个新的指令invokedynamic,用于支持动态语言,即允许方法调用可以在运行时指定类和方法,不必在编译的时候确定。字节码中每条invokedynamic指令出现的位置称为一个动态调用点,invokedynamic指令后面会跟一个指向常量池的调用点限定符,这个限定符会被解析为一个动态调用点。解析和调用过程如下:

1、根据invokedynamic指令后面的限定符#n,找到调用点限定符在常量池中的位置,调用点限定符的符号引用为CONSTANT_InvokeDynamic_info结构:

CONSTANT_InvokeDynamic_info{u1 tag;u2 bootstrap_method_attr_index; u2 name_and_type_index;}

2、通过CONSTANT_InvokeDynamic_info结构,找到引导方法,引导方法返回值必须是java.lang.invoke.CallSite类型

3、调用引导方法。和调用普通方法一样

动态调用点限定符的符号引用解析时出现了异常、或者引导方法执行出现异常、或者引导方法的返回值不匹配、MethodHandle方法描述不一致等都会抛出BootstrapMethodError异常。

4、执行完引导方法之后,动态调用点会返回一个调用点对象(CallSite)、此对象将会与动态调用点永久绑定,随后调用点对象的MethodHandle将会被调用,即调用invoke、invokeExact等方法。

实例

本实例通过asm 5.0.4来生成带invokedynamic的字节码。

1、引导方法
package invokedynamic.demo;import java.lang.invoke.*;public class Bootstrap {    private static void hello() {        System.out.println("Hello!");    }    public static CallSite bootstrap(MethodHandles.Lookup caller, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {        MethodHandles.Lookup lookup = MethodHandles.lookup();        Class thisClass = lookup.lookupClass();        MethodHandle mh = lookup.findStatic(thisClass, "hello", MethodType.methodType(void.class));        return new ConstantCallSite(mh.asType(type));    }}
Bootstrap类中包含引导方法bootstrap,返回值为CallSite且有固定的参数。引导方法中创建了一个MethodHandle,对引导方法的调用会调用MethodHandle底层的方法(Bootstrap.hello())。
2、invokedynamic字节码生成
public byte[] generate(String dynamicInvokeClassName, String dynamicLinkageClassName, String bootstrapMethodName, String methodDescriptor)throws Exception {ClassWriter cw = new ClassWriter(0);MethodVisitor mv;cw.visit(V1_7, ACC_PUBLIC + ACC_SUPER, dynamicInvokeClassName, null, "java/lang/Object", null);{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());mv.visitInvokeDynamicInsn("dynamicInvoke", methodDescriptor, bootstrap);mv.visitInsn(RETURN);mv.visitMaxs(0, 1);mv.visitEnd();}cw.visitEnd();return cw.toByteArray();}
public static void main(String[] args) throws IOException, Exception {        String dynamicClass = "invokedynamic/demo/DynamicInvoker";        FileOutputStream fos = new FileOutputStream(new File("d:/code/java7/out/production/java7/" + dynamicClass + ".class"));        fos.write(new DynamicInvokerGenerator().generate(dynamicClass, "invokedynamic/demo/Bootstrap", "bootstrap", "()V"));}
重点看这句:mv.visitInvokeDynamicInsn("dynamicInvoke", methodDescriptor, bootstrap) 在字节代码中生成invokedynamic指令,在调用的时候传入了方法的名称dynamicInvoke和对应的启动方法bootstrap。
执行main函数后生成了DynamicInvoker.class文件,用javap命令查看字节码如下:
public class invokedynamic.demo.DynamicInvoker  BootstrapMethods:    0: #13 invokestatic invokedynamic/demo/Bootstrap.bootstrap:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;      Method arguments:  minor version: 0  major version: 51  flags: ACC_PUBLIC, ACC_SUPERConstant pool:   #1 = Utf8               invokedynamic/demo/DynamicInvoker   #2 = Class              #1             //  invokedynamic/demo/DynamicInvoker   #3 = Utf8               java/lang/Object   #4 = Class              #3             //  java/lang/Object   #5 = Utf8               main   #6 = Utf8               ([Ljava/lang/String;)V   #7 = Utf8               invokedynamic/demo/Bootstrap   #8 = Class              #7             //  invokedynamic/demo/Bootstrap   #9 = Utf8               bootstrap  #10 = Utf8               (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;  #11 = NameAndType        #9:#10         //  bootstrap:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;  #12 = Methodref          #8.#11         //  invokedynamic/demo/Bootstrap.bootstrap:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;  #13 = MethodHandle       #6:#12         //  invokestatic invokedynamic/demo/Bootstrap.bootstrap:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/  #14 = Utf8               dynamicInvoke  #15 = Utf8               ()V  #16 = NameAndType        #14:#15        //  dynamicInvoke:()V  #17 = InvokeDynamic      #0:#16         //  #0:dynamicInvoke:()V  #18 = Utf8               Code  #19 = Utf8               BootstrapMethods{  public static void main(java.lang.String[]);    flags: ACC_PUBLIC, ACC_STATIC    Code:      stack=0, locals=1, args_size=1         0: invokedynamic #17,  0             // InvokeDynamic #0:dynamicInvoke:()V         5: return}
第33行生成了ynvokedynamic指定,动态调用点在常量池#17,也就是25行,第3行是对引导方法的描述。
用java命令执行这个class文件,打印出Hello!
D:\code\java7\out\production\java7>java invokedynamic.demo.DynamicInvokerHello!

示例代码下载地址:http://download.csdn.net/detail/aesop_wubo/9154407
0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 手机百度云和谐怎么办 服务器连接不上怎么办 微粒贷请求失败怎么办 房子里手机信号不好怎么办 屋里上网没信号怎么办 屋子里面没信号怎么办 crm服务器关机了怎么办 日本代金券诈骗怎么办 发票已认证 作废怎么办 淘宝不发发票怎么办 ipd密码忘记了怎么办 apple id闪退怎么办 信用卡持卡人死亡欠款怎么办 信用卡名字错了怎么办 ios超出手机内存怎么办 app id停用了怎么办 相机储存空间不足怎么办 苹果icloud8满了怎么办 红米云空间已满怎么办 忘记手机密码怎么办oppo oppo云相册丢失怎么办 oppoa79密码忘了怎么办 云存储空间满了怎么办 云备份空间不足怎么办 安卓没有中文怎么办 燃气表显示异常怎么办 is语音登录不了怎么办 is语音禁止登录怎么办 淘宝竞争不过同行怎么办 碰到比价的顾客怎么办 淘宝同行恶意捣乱怎么办 怀孕吃了打虫药怎么办 阿迪鞋微信中签不能取怎么办 康乃馨花叶长斑怎么办 杜鹃花叶长斑怎么办 青苹果竹芋烂根怎么办 朱槿花叶子发黄怎么办 猫眼叶子卷了怎么办 鞋底氧化变黄怎么办 白色旅游鞋变黄怎么办 如意皇后不张新叶片怎么办