自制Java 虚拟机(一)解析class文件

自制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
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值