Hotspot 方法调用之StubGenerator 源码解析

   目录

        一、StubGenerator

1、StubGenerator_generate

2、定义

3、generate_atomic_xchg和generate_disjoint_byte_copy

4、generate_call_stub

5、栈帧的演变

二、StubCodeGenerator

三、StubCodeDesc

四、StubCodeMark

五、MacroAssembler

1、定义

2、实现原理

六、ICache

1、ICache

2、ICacheStubGenerator


上篇《Hotspot 方法调用之StubRoutines 源码解析》中讲解了StubRoutines初始化相关的类,这篇文章就顺着其中StubGenerator_generate方法的实现来深入了解下JVM解释器相关类的使用。

一、StubGenerator

1、StubGenerator_generate

      查看StubGenerator_generate方法的实现时,eclipse弹框如下图,即存在不同CPU架构的实现,我们重点关注x86_64的实现,这是后端CentOS服务器的常用的CPU架构。

       那么编译器编译的时候怎么知道使用哪个文件的实现了?可以全局搜索包含stubGenerator_x86_64.cpp的文件,结果如下图:

    点开这个configurations.xml,如下图:

 其外层的xml的配置如下图:

   即 configurations.xml指定了编译Linux-64版本时应该包含哪些文件。

    StubGenerator_generate的源码实现如下,下面的几节会逐一讲解相关类的用途。

generate_initial和generate_all两个方法都是给StubRoutines中的static public的函数调用地址赋值,即生成stub,如下图:

2、定义

      StubGenerator顾名思义就是用来生成Stub的,这里的Stub实际是一段可执行的汇编代码,具体来说就是生成StubRoutines中定义的多个public static的函数调用点,调用方可以将其作为一个经过优化后的函数直接使用。其类继承关系如下:

     StubGenerator继承自StubCodeGenerator,但是没有添加任何新的属性,其对外的public方法只有一个构造方法,参考上节的StubGenerator_generate方法的源码。其他的都是用来生成单个Stub的私有方法,这些私有方法通过generate_initial和generate_all调用,如下图:

3、generate_atomic_xchg和generate_disjoint_byte_copy

     generate_atomic_xchg生成的函数相当于jint atomic::xchg(jint exchange_value, volatile jint* dest),即原子的将exchange_value设置到dest指向的内存中,如果设置成功则返回原来的值。generate_disjoint_byte_copy用于来复制int或者byte数组。以这两个为例说明StubGenerator生成stub的实现。

generate_atomic_xchg的源码说明如下:

  // Support for jint atomic::xchg(jint exchange_value, volatile jint* dest)
  //
  // Arguments :
  //    c_rarg0: exchange_value
  //    c_rarg1: dest
  //
  // Result:
  //    *dest <- ex, return (orig *dest)
  address generate_atomic_xchg() {
    //通过StubCodeMark的构造和析构函数来执行必要的资源初始化和销毁
    StubCodeMark mark(this, "StubRoutines", "atomic_xchg");
    //__是_masm->的别名,masm是StubCodeGenerator中的属性,MacroAssembler*,表示汇编代码的生成器
    //pc()是MacroAssembler的方法,返回MacroAssembler绑定的CodeSection的end地址
    address start = __ pc();
    //movl()也是MacroAssembler的方法,对应movl汇编指令,其入参是两个Register,即寄存器
    //rax和c_rarg0分别对应rax寄存器和通常用于保存第一个参数的rdi寄存器
    //这里是将rdi寄存器中的数据拷贝到rax中
    __ movl(rax, c_rarg0); // Copy to eax we need a return value anyhow
    //将rax中的值同c_rarg1寄存器即rsi寄存器中保存的地址上的值原子的交换,如果交换成功,rax中的值就是原来dest的值
    //可以先读取dest的值,然后再执行原子交换,如果交换的结果是之前读取的dest的值说明当前线程加锁成功
    __ xchgl(rax, Address(c_rarg1, 0)); // automatic LOCK
    //ret表示调用结束,返回
    __ ret(0);

    return start;
  }

  #define __ _masm->

  generate_disjoint_byte_copy的源码说明如下:

  // 本方法的参数:
  //   aligned - true => 如果为true,则表示输入输出都已经按照8字节对齐了
  //   name    - stub的名字
  //   entry   - 就是address*,无特别意义
  //
  // 调用此stub的参数:
  //   c_rarg0   - 原数组的地址
  //   c_rarg1   - 目标数组的地址
  //   c_rarg2   - 元素个数
  //
  // If 'from' and/or 'to' are aligned on 4-, 2-, or 1-byte boundaries,
  // we let the hardware handle it.  The one to eight bytes within words,
  // dwords or qwords that span cache line boundaries will still be loaded
  // and stored atomically.
  //
  // Side Effects:
  //   disjoint_byte_copy_entry is set to the no-overlap entry point
  //   used by generate_conjoint_byte_copy().
  //
  address generate_disjoint_byte_copy(bool aligned, address* entry, const char *name) {
    //让Assamber关联的CodeSection按指定的内存大小对齐
    __ align(CodeEntryAlignment);
    //通过StubCodeMark的构造和析构函数执行初始化和善后处理工作
    StubCodeMark mark(this, "StubRoutines", name);
    //获取Assamber关联的CodeSection的end属性,即汇编代码写入的起始地址
    address start = __ pc();

    //Label表示跳转指令用到的标签
    Label L_copy_bytes, L_copy_8_bytes, L_copy_4_bytes, L_copy_2_bytes;
    Label L_copy_byte, L_exit;
    //Register表示寄存器
    const Register from        = rdi;  // 原数组地址
    const Register to          = rsi;  // 目标数组地址
    const Register count       = rdx;  // 元素个数
    const Register byte_count  = rcx;
    const Register qword_count = count;
    const Register end_from    = from; // source array end address
    const Register end_to      = to;   // destination array end address
    // End pointers are inclusive, and if count is not zero they point
    // to the last unit copied:  end_to[0] := end_from[0]

    __ enter(); // 往下移动rbp,开启一个新的栈帧
    assert_clean_int(c_rarg2, rax);    // 验证rdx寄存器中保存的数值是一个32位的int

    if (entry != NULL) {
      //将end属性赋值给entry
      *entry = __ pc();
       // 添加注释
      BLOCK_COMMENT("Entry:");
    }
    //window下将r9和r10寄存器中的数据拷贝到rdi和rsi寄存器中,从而与Linux等保持一致
    setup_arg_regs(); // from => rdi, to => rsi, count => rdx
                      // r9 and r10 may be used to save non-volatile registers

    // 'from', 'to' and 'count' are now valid
    //将count对应的rdx寄存器的值拷贝到byte_count对应的寄存器rcx中
    __ movptr(byte_count, count);
    //shr是逻辑右移指令,即将count的值右移3位
    __ shrptr(count, 3); // count => qword_count

    // Copy from low to high addresses.  Use 'to' as scratch.
    //lea指令用来加载有效地址到指定的寄存器
    __ lea(end_from, Address(from, qword_count, Address::times_8, -8));
    __ lea(end_to,   Address(to,   qword_count, Address::times_8, -8));
    //neg指令用来对操作数取补,qword_count变成count的负数
    __ negptr(qword_count); // make the count negative
    //jmp指令用来跳转到指定的地址
    __ jmp(L_copy_bytes);

    // Copy trailing qwords
  __ BIND(L_copy_8_bytes);
    __ movq(rax, Address(end_from, qword_count, Address::times_8, 8));
    __ movq(Address(end_to, qword_count, Address::times_8, 8), rax);
    __ increment(qword_count);
    __ jcc(Assembler::notZero, L_copy_8_bytes);

    // Check for and copy trailing dword
  __ BIND(L_copy_4_bytes);
    __ testl(byte_count, 4);
    __ jccb(A
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值