自制Java 虚拟机(一)解析class文件
一、认识class文件结构
一个.java
后缀的java源文件,经过javac
编译之后的字节码文件,结构如下:(摘自jvm虚拟机规范 version8)
ClassFile {
u4 magic; // 魔数,值为 0xCAFEBABE,表示这是一个java class文件
u2 minor_version; // 次版本号
u2 major_version; // 主版本号
u2 constant_pool_count; // 等于constant_pool表中条目的数量+1
cp_info constant_pool[constant_pool_count-1]; // 常量池表,下标从1开始
u2 access_flags; // 该类或接口的访问限制标志
u2 this_class; // 表示该class文件定义的类或者接口,其值是常量池表中的索引,对应一个CONSTANT_Class_info结构
u2 super_class; // 表示该class文件定义的类/接口的父类/父接口,其值是常量池表中的索引,是一个CONSTANT_Class_info结构。特殊情况下,其值是0,表示该类没有父类(java.lang.Object)
u2 interfaces_count; // 该类/接口的父类/接口的数量
u2 interfaces[interfaces_count]; // 该数组中的每一个值都是常量池中的索引, 对应一个CONSTANT_Class_info结构
u2 fields_count; // 该数值表示fields表中field_info的总数(由该类/接口声明的字段),包括类变量和实例变量
field_info fields[fields_count]; // 每个fields表中的一项是一个field_info结构,含有该字段完整的描述信息,不包括从父类或者父接口中继承而来的字段
u2 methods_count; // 该数值表示methods表中method_info的总数
method_info methods[methods_count]; // 每个methods中的一项是一个method_info结构,含有该阿方法的完整描述信息,如果该方法不是ACC_NATIVE或者ACC_ABSTRACT,还包含JVM指令(就是方法的代码)
u2 attributes_count; // 该class文件表示的类/接口的attributes表中包含多少个attribute_info
attribute_info attributes[attributes_count];
}
其中u1、u2、u4分别表示1个字节、2个字节、4个字节。看了以上结构,很自然地想到可以用一个结构体来表示一个class文件,u1可以用unsigned char
类型,u2用unsigned short
类型,u4用unsigned int
类型。
不过由于cp_info、field_info、method_info、attribute_info是复合类型,光以上信息还不能够确定如何用C语言中的结构表示一个class文件,所以我们还得继续往下看:
1. 常量池中的主要结构
常量池是个关键,很多java指令都以索引的形式引用常量池中的符号信息。
一个常量池中的项目有如下通用结构:
cp_info {
u1 tag; // 一个字节,表示常量的类型。
u1 info[]; // 该内容因tag的不同而不同
}
表1:不同tag对应的常量池类型 摘自jvm虚拟机规范 version8
常量池类型 | tag |
---|---|
CONSTANT_Class | 7 |
CONSTANT_Fieldref | 9 |
CONSTANT_Methodref | 10 |
CONSTANT_InterfaceMethodref | 11 |
CONSTANT_String | 8 |
CONSTANT_Integer | 3 |
CONSTANT_Float | 4 |
CONSTANT_Long | 5 |
CONSTANT_Double | 6 |
CONSTANT_NameAndType | 12 |
CONSTANT_Utf8 | 1 |
CONSTANT_MethodHandle | 15 |
CONSTANT_MethodType | 16 |
CONSTANT_InvokeDynamic | 18 |
很自然,我们可以用define来定义这些常量
#define CONSTANT_Class 7
#define CONSTANT_Fieldref 9
...
#define CONSTANT_InvokeDynamic 18
1.1 CONSTANT_Class_info类型
CONSTANT_Class_info表示一个类或接口(interface):
CONSTANT_Class_info {
u1 tag; // 固定为7,即 CONSTANT_Class
u2 name_index; // 其值是常量池中的一个索引,对应一个CONSTANT_Utf8_info结构
}
自然,我们可以用C语言定义一个结构体来表示:
typedef struct _CONSTANT_Class_info {
uchar tag; // 为了方便,已经 typedef unsigned char uchar;
ushort name_index; // 为了方便,已经 typedef unsigned short ushort;
}
1.2 CONSTANT_Fieldref_info,CONSTANT_Methodref_info,CONSTANT_InterfaceMethodref_info 类型
这三种类型有相似的结构:
.... {
u1 tag; //
u2 class_index; // 其值是常量池中的一个索引,对应一个 CONSTANT_Class_info结构。
u2 name_and_type_index; // 其值是常量池中的一个索引,对应一个CONSTANT_NameAndType_info结构
}
于是我们可以用C语言定义如下结构:
typedef struct _CONSTANT_Fieldref_inf