JVM: 字节码-模板解释汇编 映射 / 栈上替换
JVM 在解释模式下使用的比较多的是模板解释器,该解释器将每个字节码都用一段汇编代码表示,并且给出这段汇编代码的入口地址
实际上字节码在JVM中可执行的对等表示即 这段汇编。字节码是从C++层面的Method对象的ConstMethod对象中的code内存段(字节码内存段)
获取的,Class文件解析之后会把字节码保存在ConstMethod对象的末尾一段额外开辟的内存区域,也就是字节码内存段。
执行的时候把字节码的地址(此时字节码在堆上)放在 r13 寄存器中,然后取字节码的值,解析出汇编代码的起始地址,然后执行这一段
汇编代码,这个过程称为dispatch,也即字节码派分。生成这一段代码需要依赖 InterpreterGenerator,实际保存字节码到汇编映射的是 Interpreter
Interpreter 保存有一个DispatchTable,起始就是对数组的一个包装,数组 _table[ a ] [ b ] , 第一维表示栈顶缓存类型,第二纬表示字节码
栈顶缓存类型一般用 xtos 表示,x可以是 a (引用类型) ,i (整形),d (浮点数) ... , tos 意思是 top of stack - Caching , 也就是栈顶缓存
一个字节码能操作的操作数是固定的,比如 istore_0 , 他的作用是把栈顶的int类型放到本地变量表的 0号变量中,那么栈顶就应该是 int 类型的,为什么还有其他类型呢?
要知道的是在模板解析执行的情况下,因为使用了栈顶缓存,所以字节码的汇编代码直接操作的是栈顶缓存的值,所谓栈顶缓存无非是为了减少存取内存的次数,因为
栈是在内存中的,CPU访问寄存器会比访问内存快几个数量级,所以把栈顶的元素缓存在寄存器中,字节码指令直接操作寄存器的值,一般缓存在rax寄存器。当栈顶缓存
,也就是寄存器的值,和当前的值不匹配的时候,比如说 需要的是 itos, 栈顶缓存是 vtos,那么就需要把栈中的内容 pop 到寄存器中,这个过程是栈顶缓存的填充。可不
可能是 atos呢?不可能,因为字节码是根据java代码生成的,并且被检验过,大概率不会出现类型不匹配的情况。那为什么会是vtos呢? 可能是因为栈顶缓存被push回栈中。
同理,如果当前需要vtos,而栈顶缓存不是vots, 那么需要把栈顶缓存 push 回栈中,这里的栈顶缓存是上一个指令留下来的缓存。
所以一个字节码可以对应不同的 vtos,所以 _table 数组有 一,二 纬之分。
实际编译汇编代码的是Template,保存有 Template 数组的是TemplateTable,InterpreterGenerator只是将 Template 产生的内容放到 Interpreter 中。