Java 虚拟机程序员

【Java 虚拟机笔记】字节码执行引擎相关整理

2019-04-08  本文已影响11人  58bc06151329

文前说明

作为码农中的一员,需要不断的学习,我工作之余将一些分析总结和学习笔记写成博客与大家一起交流,也希望采用这种方式记录自己的学习之旅。

本文仅供学习交流使用,侵权必删。
不用于商业目的,转载请注明出处。

1. 概述

2. 栈帧

3. 方法调用

3.1 解析调用

指令 说明
invokestatic 调用静态方法。
invokespecial 调用实例构造器 <init> 方法、私有方法和父类方法。
invokevirtual 调用所有的虚方法。
invokeinterface 调用接口方法,会在运行时再确定一个实现此接口的对象。
invokedynamic 动态解析要调用的方法。

3.2 分派调用

静态分派

动态分派

单分派和多分派

public class Test {

    static class QQ {
    }

    static class _360 {
    }

    public static class Father {
        public void hardChoice(QQ arg) {
            System.out.println("father choose QQ");
        }

        public void hardChoice(_360 arg) {
            System.out.println("father choose 360");
        }
    }

    public static class Son extends Father {
        public void hardChoice(QQ arg) {
            System.out.println("son choose QQ");
        }

        public void hardChoice(_360 arg) {
            System.out.println("son choose 360");
        }
    }

    public static void main(String[] args) {
        Father father = new Father();
        Father son = new Son();
        father.hardChoice(new _360());
        son.hardChoice(new QQ());
    }

}
/*print
father choose 360
son choose QQ
*/

3.3 动态分派的实现

虚方法表实现

3.4 动态类型语言支持

public class MethodHandleTest {
      static class ClassA{
        public  void println(String s){
            System.out.println(s);
        }
      }
       public static void main(String[] args) throws Throwable{
           Object obj=System.currentTimeMillis()%2==0?System.out  : new ClassA();
           getPrintlnMH(obj).invokeExact("icyfenix");
           
       }
    private static MethodHandle getPrintlnMH(Object reveiver) throws Throwable {
       //MethodType代表“方法类型”,包含了方法的返回值(第一个参数)和具体参数(第二个参数)
       MethodType mt=MethodType.methodType(void.class.String.class);
       //lookup()方法来自于MethodHandles.lookup,这句话的作用是在指定类中查找符合给定的方法名称、方法类型,并且符合调用权限的方法句柄
       //因为这里调用的是一个虚方法,按照java语言的规则,方法第一个参数是隐式的,代表该方法的接受者,也即是this指向的对象,这个参数以前是放在参数列表中进行传递的,现在提供了bindTo()方法
       return lloup().findVirtual(reveiver.getClass(),"println",mt).bindTo(reveiver);
    }
}
public class Test {

    class GrandFather {
        void thinking() {
            System.out.println("i am grandfather.");
        }
    }

    class Father extends GrandFather {
        void thinking() {
            System.out.println("i am father.");
        }
    }

    class Son extends Father {
        void thinking() {
            try {
                MethodType mt = MethodType.methodType(void.class);
                Field IMPL_LOOKUP = MethodHandles.Lookup.class.getDeclaredField("IMPL_LOOKUP");
                IMPL_LOOKUP.setAccessible(true);
                MethodHandles.Lookup lookup = (MethodHandles.Lookup) IMPL_LOOKUP.get(null);
                MethodHandle mh = lookup.findSpecial(GrandFather.class, "thinking", mt, Father.class);
                mh.invoke(this);
            } catch (Throwable e) {
            }
        }
    }

    public static void main(String[] args) {
        Test t = new Test();
        (t.new Son()).thinking();
    }
}
/*print
i am grandfather.
*/

//lookup.findSpecial
public MethodHandle findSpecial(Class<?> refc, String name, MethodType type, Class<?> specialCaller) throws NoSuchMethodException, IllegalAccessException {
    this.checkSpecialCaller(specialCaller);
    MethodHandles.Lookup specialLookup = this.in(specialCaller);
    MemberName method = specialLookup.resolveOrFail(7, refc, name, (MethodType)type);
    this.checkSecurityManager(refc, method);
    return specialLookup.getDirectMethod(7, refc, method, this.findBoundCallerClass(method));
}

//allowedModes = -1 可以绕开检查
private void checkSpecialCaller(Class<?> specialCaller) throws IllegalAccessException {
    int allowedModes = this.allowedModes;
    if(allowedModes != -1) {
        if((allowedModes & 2) == 0 || specialCaller != this.lookupClass()) {
            throw (new MemberName(specialCaller)).makeAccessException("no private access for invokespecial", this);
        }
    }
}

4. 基于栈的字节码解释执行引擎

4.1 解释执行

编译原理

4.2 基于栈的指令集和基于寄存器的指令集

4.3 基于栈的解释器执行过程

public class Test {

    public static int cal() {
        int a = 100;
        int b = 200;
        int c = 300;
        return a + b + c;
    }

    public static void main(String[] args) {
        System.out.println(cal());
    }

}
public static int cal();
    descriptor: ()I
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=3, args_size=0
         0: bipush        100
         2: istore_0
         3: sipush        200
         6: istore_1
         7: sipush        300
        10: istore_2
        11: iload_0
        12: iload_1
        13: iadd
        14: iload_2
        15: iadd
        16: ireturn
      LineNumberTable:
        line 6: 0
        line 7: 3
        line 8: 7
        line 9: 11
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            3      14     0     a   I
            7      10     1     b   I
           11       6     2     c   I

操作 1 操作 2 操作 3 操作 4 操作 5 操作 6 操作 7

参考资料

https://blog.csdn.net/it_gjw/article/details/80627661
https://www.cnblogs.com/royi123/p/3569511.html
https://blog.csdn.net/suifeng629/article/details/82349784
https://www.cnblogs.com/wxw7blog/p/7264475.html

上一篇 下一篇

猜你喜欢

热点阅读