本应该是类变量解析的,但我寻思字节对齐不是C++基础吗?
对Java主函数而言,在CallStub例程里会调用entry_point例程, 在entry_point例程里完成主函数的栈帧创建,找到Java主函数所对应的第一个字节码指令并进入执行.在entry_point例程中会涉及method对象
JVM内部可以调用各种不同的方法类型,JNI,Java的静态方法,成员方法.调用不同种类的方法,触发不同的entry_point,创建相应的堆栈,而Java方法的运行必定经过解释器Interpreter
void TemplateInterpreter::initialize(){
//...
{
ResourceMark rm;
TraceTime timer("Interpreter generation", TraceStartupTime);
int code_size = InterpreterCodeSize;
NOT_PRODUCT(code_size *= 4);
_code = new StubQueue(new InterpreterCodeletInterface, code_size, NULL,"Interpreter");
InterpreterGenerator g(_code);//生成解释器
}
//...
}
在hotspot内部有三种解释器,字节码解释器,C++解释器和模版解释器.模版解释器将字节码指令直接翻译成了机器指令,由人工手动优化.为默认的解释器.
解释器有一个对应的解释器生成器,模版解释器对应为TemplateInterpreterGenerator
以生成zerolocals 的entry_point为例
address InterpreterGenerator::generate_normal_entry(bool synchronized){
//...
address entry_point();//对应机器码的入口地址
//定义寄存器变量
const Address size_of_parameters(rbx, methodOopDesc::size_of_parameters_offset());
const Address size_of_locals(rbx, methodOopDesc::size_of_locals_offset() +
InvocationCounter::counter_offset());
//...
//获取Java方法参数数量,max_locals,slot数量
___ load_unsigned_short(rcx, size_of_parameters);
//...
//获取返回地址
___ pop(rax);
//计算java方法第一个参数在堆栈中的地址
___ lea(rdi, Address(rsp,rcx,Interpreter::stackElementScale(), - wordSize));
//为局部变量slot分配空间
{
Label exit, loop;
___ testl(rdx, rdx);
___ jcc(Assembler::lessEqual, exit);
//...
}
//创建栈帧
generate_fixed_frame(false);
//...
//开始执行java方法第一条字节码
___ dispatch_next(vtos);
return entry_point;
}
generate_normal_entry() 在JVM中会想JVM的代码缓存区写入对应的机器码,当JVM调用一个Java方法是,会根据java方法对应的entry_point类型找到相应的入口.而CallStub例程所进去的entry_point就是方法入口.
在entry_point里使用constMethod,method来定位java函数对应的字节码位置
- method对象的constMethod指针在oop对象头后面
- constMethod内部存储java函数对应的字节码指令
- method对象存储java函数的参数数量等
各参数偏移表省略