openjdk底层汇编指令调用(二)——寄存器定义

在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是一个宏定义,RegisterRegisterImpl*的别名。

typedef RegisterImpl* Register;

上述宏定义的展开如下

const Register r0 = ((Register)r0_RegisterEnumValue)

如果将上述的宏展开式中的RegisterRegisterImpl*进行替换可发现

const RegisterImpl* r0 = ((RegisterImpl*)r0_RegisterEnumValue)

即在内存中声明了一个RegisterImpl对象只读对象(不可被修改),其中r0等于r0_RegisterEnumValue的值,并将其转换为(RegisterImpl*)指针。

这里要注意以下几个点:

  1. r0是一个64位的整型值且不能被修改。源码中r0是一个指针。在C++中,无论是什么类型的指针都指向内存中的地址,即r0对应一个地址的值。在64位系统中,地址是一个64位的整型值,即,r0就是一个64位的整型值。
  2. r0的值等于r0_RegisterEnumValue,而这个值在register_aarch64.hpp中被定义。
  3. 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的值
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值