在openjdk中,当JVM(java虚拟机)加载字节码后,也需要将字节码的操作转换为对应平台的指令执行方可实现Java程序的行为。那么,在何处实现这些汇编指令的编码呢?假设在AArch64架构的机器上运行JVM
目录位置
openjdk
|--src
|--hotspot
|--cpu
|--aarch64
在aarch64
目录下的以下文件涉及指令编码
register_aarch64.hpp
assembler_aarch64.hpp
根据面向对象的编程思想,我们可以定义寄存器类和汇编器类。寄存器类用于定义寄存器的名称和值,汇编器类用于定义汇编语言的助记符和编码规则。
除此之外,由于openjdk支持多种平台,因此在寄存器和汇编器之上应该抽象出寄存器和汇编器的抽象类。
其目录位置
openjdk
|--share
|--asm
|--assembler.hpp
|--register.hpp
寄存器定义
其中寄存器的类图如下
其中,value()
函数用于获得当前寄存器的编号。
那么,如何给寄存器进行编号赋值呢?在register_aarch64.hpp
中使用了一种比较巧妙的方法。这里以0号寄存器为例进行说明。
首先需要声明一个r0
的寄存器表示0号寄存器
REGISTER_DEFINITION(Register, r0);
其中,REGISTER_DEFINITION
是一个宏定义,Register
是RegisterImpl*
的别名。
typedef RegisterImpl* Register;
上述宏定义的展开如下
const Register r0 = ((Register)r0_RegisterEnumValue)
如果将上述的宏展开式中的Register
用RegisterImpl*
进行替换可发现
const RegisterImpl* r0 = ((RegisterImpl*)r0_RegisterEnumValue)
即在内存中声明了一个RegisterImpl
对象只读对象(不可被修改),其中r0
等于r0_RegisterEnumValue
的值,并将其转换为(RegisterImpl*)
指针。
这里要注意以下几个点:
r0
是一个64位的整型值且不能被修改。源码中r0
是一个指针。在C++
中,无论是什么类型的指针都指向内存中的地址,即r0
对应一个地址的值。在64位系统中,地址是一个64位的整型值,即,r0
就是一个64位的整型值。r0
的值等于r0_RegisterEnumValue
,而这个值在register_aarch64.hpp
中被定义。r0
地址内的值无法被访问,可以避免错误读取或赋值。因为0号地址是不可被访问的保护区域,即使用*r0
会报错。
CONSTANT_REGISTER_DECLARATION(Register, r0, (0));
将上述宏定义展开可得
extern const Register r0; enum { r0_RegisterEnumValue = ((0)) }
现在就很清晰了,r0_RegisterEnumValue
就是一个整型值,值为0。
总而言之,如果在openjdk
中见到如下定义
Register r0
即可认为是aarch64
中的x0
或者w0
寄存器。因为x0
以及w0
的寄存器编号为0
同理也可找到浮点寄存器以及向量寄存器的定义,这里不再赘述。
寄存器别名定义
在实际使用过程中,为了能方便记忆各寄存器的用途,JVM
将上述定义的部分寄存器定义了其他的别名。例如,在assembler_aarch64.hpp中
// locals on stack
REGISTER_DECLARATION(Register, rlocals, r24);
宏定义展开如下
extern const Register rlocals; enum { rlocals_RegisterEnumValue = r24_RegisterEnumValue }
可以看出,这里定义24号寄存器的别名是rlocals
。在实际使用过程中,rlocals
用于记录局部变量表的基地址.
除此之外,在该文件中还有其他的别名定义,这里只需了解上述宏定义是为寄存器定义别名。
好处
上述定义寄存器带来的有点是程序员在编写与寄存器相关的程序时可将寄存器实例化。比如,我在x86中想执行一个压栈操作,那么可以直接用C++代码写成下面的形式。
Register rbx;
push(rbx);
这里可以抽象地认为rbx
是一个寄存器。因为rbx
是一个Register
对象,而非是整型值。
实际push
函数的实现是
void push(Register r){
long inst_value = 0x50+r;
emit(inst_value);//往内存的指令区域中写入inst_value的值
}