JVM中generate_fixed_frame生成Java方法的固定栈帧

1,093 阅读3分钟

紧接着上一篇文章介绍generate_fixed_frame是生成java方法的栈帧固定栈帧部分,也即是JVM定义的动态链接的部分,在此之前JVM规范的本地变量表已经初始化完成了.

void TemplateInterpreterGenerator::generate_fixed_frame(bool native_call) {
  // initialize fixed part of activation frame
  __ push(rax);    // save return address
  __ enter();   // save old & set new rbp,

  __ push(rsi);   // set sender sp
  __ push((int32_t)NULL_WORD);                        // leave last_sp as null
  __ movptr(rsi, Address(rbx,Method::const_offset())); // get ConstMethod*
  __ lea(rsi, Address(rsi,ConstMethod::codes_offset())); // get codebase
  __ push(rbx);            // save Method*
  if (ProfileInterpreter) {
    Label method_data_continue;
    __ movptr(rdx, Address(rbx, in_bytes(Method::method_data_offset())));
    __ testptr(rdx, rdx);
    __ jcc(Assembler::zero, method_data_continue);
    __ addptr(rdx, in_bytes(MethodData::data_offset()));
    __ bind(method_data_continue);
    __ push(rdx);                                       // set the mdp (method data pointer)
  } else {
    __ push(0);
  }
  __ movptr(rdx, Address(rbx, Method::const_offset()));
  __ movptr(rdx, Address(rdx, ConstMethod::constants_offset()));
  __ movptr(rdx, Address(rdx, ConstantPool::cache_offset_in_bytes()));
  __ push(rdx);     // set constant pool cache
  __ push(rdi);      // set locals pointer
  if (native_call) {
    __ push(0);       // no bcp
  } else {
    __ push(rsi);  、    // set bcp
    }
  __ push(0);                                         // reserve word for pointer to expression stack bottom
  __ movptr(Address(rsp, 0), rsp);       // set expression stack bottom
}
  1. 将栈上的返回地址保存到rax寄存器中.
 __ push(rax);    // save return address
  1. enter方法会执行两条指令,
    push(rbp); 保存当前rbp的栈基地址到栈中
    mov(rbp, rsp);将当前rsp的值赋值给rbp寄存器,开辟一个新的栈帧\
  __ enter();  
  1. 保存rsi寄存器的值到栈上,rsi的值是调用者rsp栈顶。
  __ push(rsi); 
  1. 获取method的ConstMethod指针地址。
 __ movptr(rsi, Address(rbx,Method::const_offset())); // get ConstMethod*
  1. 从ConstMethod取出字节码指令的偏移地址,从下面ConstMthod的codes_offset方法可以看出,ConstMethod将字节码指令放在ConstMethod对象的末尾。
 __ lea(rsi, Address(rsi,ConstMethod::codes_offset())); // get codebase
  // ConstMethod的方法
  static ByteSize codes_offset(){
     return in_ByteSize(sizeof(ConstMethod));
   }
  1. 保存Method的指针地址到rbx寄存器.
  __ push(rbx);              // save Method*
  1. 是否开启解释器的性能统计数据,默认是false,这里暂时不展开讲了. 此段代码就会走else中代码,将往栈push一个0
  if (ProfileInterpreter) {
    Label method_data_continue;
    __ movptr(rdx, Address(rbx, in_bytes(Method::method_data_offset())));
    __ testptr(rdx, rdx);
    __ jcc(Assembler::zero, method_data_continue);
    __ addptr(rdx, in_bytes(MethodData::data_offset()));
    __ bind(method_data_continue);
    __ push(rdx);    // set the mdp (method data pointer)
  } else {
    __ push(0);
  }
  1. 将Method的ConstMethod的的地址移动到rdx寄存器.
__ movptr(rdx, Address(rbx, Method::const_offset()));
 // Method的const_offset方法
  static ByteSize const_offset(){ return byte_offset_of(Method, _constMethod  ); }
  1. 将ConstMethod的ConstantPool的指针地址移动到rdx寄存器.
 __ movptr(rdx, Address(rdx, ConstMethod::constants_offset()));
  //ConstMethod的constants_offset方法
   static ByteSize constants_offset()
   { return byte_offset_of(ConstMethod, _constants); }
  1. 将ConstantPool的ConstantPoolCache偏移地址移动到rdx寄存器.
  __ movptr(rdx, Address(rdx, ConstantPool::cache_offset_in_bytes()));
   // ConstantPool的cache_offset_in_bytes
  static int cache_offset_in_bytes()        { return offset_of(ConstantPool, _cache); }
  1. 保存rdx寄存器保存的是ConstantPoolCache的地址、rdi的寄存器保存的是第一个参数位置。
 __ push(rdx);     // set constant pool cache
 __ push(rdi);      // set locals pointer
  1. 这里先判断是否本地调用,如果不是,则表示是java调用,则保存byte code pointer(字节码指针)到栈顶,如果是本地方法是没有字节码指令,则直接保存一个0到栈顶.
if (native_call) {
    __ push(0);       // no bcp
  } else {
    __ push(rsi);    // set bcp
  }
  1. 再保存一个0到栈顶,作为保留字段,然后保存表达式栈的底部的值,
  __ push(0);  //  reserve word for pointer to expression stack bottom
  __ movptr(Address(rsp, 0), rsp); // set expression stack bottom

经过上面的步骤java的栈帧状态如下:

image.png 总结
本文主要分析了java生成固定栈帧的部分汇编指令逻辑,这样JVM规范定义的三部分中动态链接的栈帧也分析完了,还剩下操作数栈,hotspot中也称表达式栈,这个在接下来的一篇分析.