openjdk底层(hotspot)汇编指令调用(四)——发送指令到内存

内存分类

冯诺依曼结构计算机的内存是一整块,其内部分为数据区和指令区,也称数据段和代码段。由于JVM是用软件模拟计算机行为,所以JVM内部也会用C++表示一段代码段内存。代码段内的数据都是计算机指令。

如何发送

指令编码完成后,需要将该指令发送到代码段以供后续CPU执行。那么JVM是如何实现将指令发送到代码段中的呢?

回到assembler_aarch64.hpp文件中的add函数定义

void add(Register Rd, Register Rn, Register Rm, enum shift_kind kind, unsigned shift = 0) { 
    Instruction_aarch64 do_not_use(this); 
    set_current(&do_not_use); 
    f(0, 21); ; 
    zrf(Rd, 0), zrf(Rn, 5), zrf(Rm, 16); 
    op_shifted_reg(0b01011, kind, shift, 1, 0b000); 
}

这里有一个Instruction_aarch64类对象do_not_use,参数是this

我们看看这个类的定义

class Instruction_aarch64 {
  unsigned insn;
  Assembler *assem;

public:

  Instruction_aarch64(class Assembler *as) {
    insn = 0;
    assem = as;
  }

  inline ~Instruction_aarch64();

  unsigned &get_insn() { return insn; }

这个类有2个成员变量,一个是insn,该变量保存汇编指令的机器码,即add函数内部生成的值;另一个Assembler类对象assem,该对象关联与架构相关的汇编器。

add函数中,do_not_use对象在{之后调用构造函数,在}之前调用析构函数

我们来看看构造函数实现了什么功能?

在源码中

Instruction_aarch64 do_not_use(this); 

构造函数传递了一个this参数,即当前的汇编器类对象(class Assembler : public AbstractAssembler {)。

然后在add函数中执行如下代码,将do_not_use对象赋值给汇编器当前指令对象(current)

set_current(&do_not_use); 

在析构函数中实现了

Instruction_aarch64::~Instruction_aarch64() {
  assem->emit();
}

即,在析构函数中调用了当前的汇编器对象(assem)的emit函数

void emit() {
    emit_long(current->get_insn());//获得当前指令对象的机器码值,并将其发送到代码段
  }

emit_long函数的实现如下

void emit_long(jint x) {
    ...
    AbstractAssembler::emit_int32(x);
  }
void emit_int32(  int32_t x) { code_section()->emit_int32(  x); }

由于AArch64RISC指令,其指令长度为32位固定长度,这里可以看到emit_int32函数实现是将32位整型值放入代码段(code_section())中。这里先不要纠结code_section是哪里来的,后面在将JVM指令内存结构时会讲到。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值