最近在研究JVM字节码,发现在对字节码反编译后出现了 StackMapTable 这样一个结构,因此这里研究一下这个到底是做什么用的。
首先说下栈图这个东西在哪里,这是我最近在学习java 字节码的时候发现的一个东西。当我在 Idea 中使用反编译选项对 java.util.HashMap类进行反编译时,读取到了这样的字节码:
如图frame APPEND、frame SAME这样的代码并不是标准的字节码指令,因此有可能是 Idea 的反编译器为了代码的可读性,自动给我们增加的内容。从字面意义上解读的话应该是字节码运行到这里的时候,在帧中追加变量 java.util.HashMap&Node 但由于没有给出变量的地址,因此又好像不是。为了验证,这里做了一番研究。
首先,如果我们直接使用 javap反编译相同的代码时,相同位置并没有类似的字节码。可以肯定这部分的确是 Idea 反编译器加上去的。
栈图(StackMapTable)栈图是 JDK1.6 之后引入的一个JVM特性,主要用于提高 JVM 在加载类时对局部变量表中的类型验证效率。栈图结构位于 Code 的属性表结构中(attributes table) 。位于 JVM 规范的 JSR202文档中,里面描述了一种新的字节码校验算法,“类型检查”,在此之前使用的是 “类型推导"的算法。下图为字节码校验的阶段:
为了支持新算法,class 文件从版本 50 开始添加了一个新的属性表,叫做 StackMapTable,里面记录了一个方法中操作数栈与局部变量区的类型在一些特定位置的状态。
上图为 java.util.HashMap 类中 treeifyBin 方法的栈映射帧,从 JDK6 开始,如果方法的字节码中没有该属性,则会默认为其分配一个相关属性。可以看到栈映射帧中存在 frameAppend、frameSame等类型指的是 StackMapframe,这个 frame 与 Java 方法调用栈的栈帧不同。而是拥有表述该调用栈状态的一种数据结构,会在 class 文件加载时利用该属性进行校验。注意这里所谓的 frameAppend ,frameChop 都是对同一个方法的栈帧而言的,并不是说 “添加栈帧”、“减少栈帧"或者"压入栈帧”,弹出"栈帧”,而是指栈桢的内容(局部变量表)在数量上有所变化。
bytecode viewer介绍
jclasslib
Java JVM 栈帧(Stack frame)
栈帧
JVM的StackMapTable的前世今生
StackMapTable属性说明
StackMapTable属性的运作原理



