2.5.2 Code属性
在众多属性中,笔者将重点介绍和Code相关的属性。因为一个函数的内容(也就是这个函数的源码转换后得到的Java字节码)就存储在Code属性中。图2-7所示为Code属性的数据结构伪代码。
图2-7中Code_attribute各成员变量的说明如下。
·attribute_name_index指向内容为"Code"的Utf8_info常量项。attribute_length表示接下来内容的长度。
·max_stack:JVM执行一个指令的时候,该指令的操作数存储在一个名叫“操作数栈(operand stack)”的地方,每一个操作数占用一个或两个(long、double类型的操作数)栈项。stack就是一块只能进行先入后出的内存。max_stack用于说明这个函数在执行过程中,需要最深多少栈空间(也就是多少栈项)。max_locals表示该函数包括最多几个局部变量。注意,max_stack和max_locals都和JVM如何执行一个函数有关。根据JVM官方规范,每一个函数执行的时候都会分配一个操作数栈和局部变量数组。所以Code_attribute需要包含这些内容,这样JVM在执行函数前就可以分配相应的空间。
·code_length和code:函数对应的指令内容也就是这个函数的源码经过编译器转换后得到的Java指令码存储在code数组中,其长度由code_length表明。
·exception_table_length和exception_table:一个函数可以包含多个try/catch语句,一个try/catch语句对应exception_table数组中的一项。
图2-7 Code_attribute数据结构
介绍exception_table之前需要先了解pc(program counter)的概念。JVM执行的时候,会维护一个变量来指向当前要执行的指令,这个变量就叫pc。有了pc的概念,exception_table中各成员变量的含义就比较容易理解了。其中:
·start_pc描述try/cath语句从哪条指令开始。注意,这个table中的各个pc变量的取值必须位于代表整个函数内容的Java字节码code[code_length]数组中。
·end_pc表示这个try语句到哪条指令结束。注意,只包括try语句,不包括catch。
·handler_pc表示catch语句的内容从哪条指令开始。
·catch_type表示catch中截获的Exception或Error的名字,指向Utf8_info常量项。如果catch_type取值为0,则表示它是final{}语句块。
另外,图2-7中表明Code_atrribute还能包含其他属性,Code_attribute里常见的属性有:
·LineNumberTable用于调试,比如指明哪条指令。对应于源码哪一行。
·LocalVariableTable用于调试,调试时可以用于计算本地变量的值。
·LocalVariableTypeTable,功能和LocalVariableTable类似。
·StackMapTable为Java 1.6以上才支持的属性。JVM加载Class文件的时候,将利用该属性的内容对函数进行类型校验(Type Checking)。
关于Code_attribute携带的属性,本章将简单介绍"LineNumberTable"和"LocalVariableTable"。