目录
一、AbstractInterpreter
二、TemplateInterpreter
1、定义
2、initialize
3、interpreter_init
三、TemplateTable
1、定义
2、Template
3、initialize
4、aaload和aastore指令实现
四、InterpreterGenerator
五、AbstractInterpreterGenerator
六、TemplateInterpreterGenerator
1、generate_all
2、set_entry_points_for_all_bytes
在上一篇《Hotspot 方法调用之Interpreter 源码解析》中讲到Interpreter通过宏可以继承自CppInterpreter或者TemplateInterpreter,前者称为C++解释器,每个指令都对应一段C++代码,通过switch/case的方式处理字节码,后者称为模板解释器,每个指令对应一段汇编指令,通过指令模板的方式处理字节码,JVM默认使用模板解释器。下面我们就详细探讨下TemplateInterpreter的相关类及其实现。
AbstractInterpreter的定义位于hotspot src/share/vm/interpreter/abstractInterpreter.hpp中,是CppInterpreter和TemplateInterpreter共同的基类,用来抽象平台独立的解释器相关的属性和方法。AbstractInterpreter定义的属性都是protected,如下:
AbstractInterpreter定义了一个表示方法类型的枚举MethodKind,每个类型都对应_entry_table中一个数组元素,即一个处理该类型方法的方法调用的入口地址,如下图:
枚举number_of_result_handlers的定义如下:
AbstractInterpreter定义的public方法可以分为以下几种:
重点关注其initialize方法的实现,源码说明如下:
void AbstractInterpreter::initialize() {
//避免二次初始化
if (_code != NULL) return;
// make sure 'imported' classes are initialized
//BytecodeCounter统计字节码总的执行次数
if (CountBytecodes || TraceBytecodes || StopInterpreterAt) BytecodeCounter::reset();
//BytecodeHistogram统计每个字节码的执行次数
if (PrintBytecodeHistogram) BytecodeHistogram::reset();
//BytecodePairHistogram统计字节码对的执行次数,字节码对是指两个连续的字节码
if (PrintBytecodePairHistogram) BytecodePairHistogram::reset();
//InvocationCounters用于保存方法调用的次数,当次数达到某个阈值时会触发某个动作执行
InvocationCounter::reinitialize(DelayCompilationDuringStartup);
}
其调用链如下:
TemplateInterpreter继承自AbstractInterpreter,其定义在同目录下的templateInterpreter.hpp中。TemplateInterpreter在此基础上增加了很多的完成特定功能的函数的调用入口,如下图:
EntryPoint就是一个address的数组的包装类,如下图所示:
其中number_of_states是枚举TosState中表示state个数的枚举值,如下图:
TosState枚举用来表示字节码指令执行前后栈顶的值的类型,栈顶的值可能保存在一个或者多个CPU寄存器中,需要通过值类型正确的读取值,将栈顶的值保存到一个或者多个寄存器中的技术就称为栈顶缓存技术,默认情况下栈顶的值保存在rax寄存器中。如果TosState为vtos则表示未使用栈顶缓存。
DispatchTable是一个address二维数组的包装类,其定义如下:
其中BitsPerByte表示一个字节多少位,固定值8。
TemplateInterpreter新增的方法主要有以下几种:
TemplateInterpreter中定义的都是平台无关的部分,跟平台相关的部分通过宏的方式引入,如下图:
templateInterpreter_x86.hpp也比较简单,主要添加了InterpreterCodeSize常量的定义,如下图:
重点关注TemplateInterpreter initialize方法的实现,源码说明如下 :
void TemplateInterpreter::initialize() {
if (_code != NULL) return;
//校验字节码的个数必须小于等于DispatchTable的长度
assert((int)Bytecodes::number_of_codes <= (int)DispatchTable::length,
"dispatch table too small");
//初始化
AbstractInterpreter::initialize();
TemplateTable::initialize();
// generate interpreter
{ ResourceMark rm;
TraceTime timer("Interpreter generation", TraceStartupTime);
//InterpreterCodeSize是在平台相关的templateInterpreter_x86.hpp中定义的,64位下是256 * 1024
int code_size = InterpreterCodeSize;
NOT_PRODUCT(code_size *= 4;) // debug uses extra interpreter code space
//创建一个StubQueue
_code = new StubQueue(new InterpreterCodeletInterface, code_size, NULL,
"Interpreter");
//初始化InterpreterGenerator,初始化的时候会生成所有的调用函数
InterpreterGenerator g(_code);
if (PrintInterpreter) print();
}
// 将_normal_table标记为激活的
_active_table = _normal_table;
}
其调用链如下:
其中interpreter_init和 universe_post_init方法都是通过Interpreter::initialize()方法调用的,因为Interpreter没有提供该方法的实现,所以默认采用其父类TemplateInterpreter的实现。universe_post_init的调用如下:
interpreter_init方法的实现在同目录的interpreter.cpp中,其源码说明如下:
void interpreter_init() {
//初始化解释器
Interpreter::initialize();
//通知libcollector stub已经生成并装载完成
Forte::register_stub(
"Interpreter",
AbstractInterpreter::code()->code_start(),
AbstractInterpreter::code()->code_end()
);
// 发布JVMTI事件
if (JvmtiExport::should_post_dynamic_code_generated()) {
JvmtiExport::post_dynamic_code_generated("Interpreter",
AbstractInterpreter::code()->code_start(),
AbstractInterpreter::code()->code_end());
}
}
TemplateTable的定义位于同目录的templateTable.hpp中,表示字节码指令的模板类,定义了所有指令的指令模板,并提供了获取给定字节码指令的模板的方法。TemplateTable定义的属性如下:
上述属性都是静态属性,除_masm是public外,其他的都是私有属性
TemplateTable定义的方法也都是静态的,其中私有方法大部分都是跟指令对应的方法,如下图:
对外public static方法就4个,如下图:
跟平台相关的方法定义通过宏的方式引入,如下图:
templateTable_x86_64.hpp定义的方法不多,同样是public static方法,如下图:
Template的定义位于templateTable.hpp中,用来描述一个字节码模板的属性,并提供一个用来生成字节码模板的函数。其定义的私有属性如下:
Template定义的方法中除属性相关的如uses_bcp外,就三个方法,各方法实现的源码说明如下:
void Template::initialize(int flags, TosState tos_in, TosState tos_out, generator gen, int arg) {
_flags = flags;
_tos_in = tos_in;
_tos_out = tos_out;
_gen = gen;
_arg = arg;
}
Bytecodes::Code Template::bytecode() const {
//通过当前Template的地址在_template_table中的位置反算出对应的字节码
int i = this - TemplateTable::_template_table;
if (i < 0 || i >= Bytecodes::number_of_codes) i = this - TemplateTable::_template_table_wide;
return Bytecodes::cast(i);
}
void Template::generate(InterpreterMacroAssembler* masm) {
// parameter passing
TemplateTable::_desc = this;
TemplateTable::_masm = masm;
//调用gen生成字节码模板
_gen(_arg);
//刷新指令缓存
masm->flush();
}
其中initialize的调用链如下:
generate方法的调用链如下:
initialize方法的源码如下:
void TemplateTable::initialize() {
//如果已经初始化则返回
if (_is_initialized) return;
// Initialize table
TraceTime timer("TemplateTable initialization", TraceStartupTime);
//设置bs
_bs = Universe::heap()->barrier_set();
// For better readability
const char _ = ' ';
const int ____ = 0;
const int ubcp = 1 << Template::uses_bcp_bit;
const int disp = 1 << Template::does_dispatch_bit;
const int clvm = 1 << Template::calls_vm_bit;
const int iswd = 1 << Template::wide_bit;
//nop等是TemplateTable的静态私有方法,in表示字节码执行前栈顶值的类型,out表示字节码执行后栈顶值的类型
//generator表示生成字节码方法的函数,argument表示生成字节码模板的参数
//初始化_template_table数组和_template_table_wide中的Template元素
// 具体哪个字节码 字节码模板属性 in out generator argument
def(Bytecodes::_nop , ____|____|____|____, vtos, vtos, nop , _ );
def(Bytecodes::_aconst_null , ____|____|____|____, vtos, atos, aconst_null , _ );
def(Bytecodes::_iconst_m1 , ____|____|____|____, vtos, itos, iconst , -1 );
def(Bytecodes::_iconst_0 , ____|____|____|____, vtos, itos, iconst , 0 );
def(Bytecodes::_iconst_1 , ____|____|____|____, vtos, itos, iconst , 1 );
//包含Bytecodes定义所有的指令,不同的指令调用不同的def重载版本
// platform specific bytecodes
pd_initialize();
_is_initialized = true;
}
void TemplateTable::def(Bytecodes::Code code, int flags, TosState in, TosState out, void (*gen)(), char filler) {
//校验filter为' '
assert(filler == ' ', "just checkin'");
def(code, flags, in, out, (Template::generator)gen, 0);
}
void TemplateTable::def(Bytecodes::Code code, int flags, TosState in, TosState out, void (*gen)(Operation op), Operation op) {
def(code, flags, in, out, (Template::generator)gen, (int)op);
}
void TemplateTable::def(Bytecodes::Code code, int flags, TosState in, TosState out, void (*gen)(bool arg ), bool arg) {
def(code, flags, in, out, (Template::generator)gen, (int)arg);
}
void TemplateTable::def(Bytecodes::Code code, int flags, TosState in, TosState out, void (*gen)(TosState tos), TosState tos) {
def(code, flags, in, out, (Template::generator)gen, (int)tos);
}
void TemplateTable::def(Bytecodes::Code code, int flags, TosState in, TosState out, void (*gen)(Condition cc), Condition cc) {
def(code, flags, in, out, (Template::generator)gen, (int)cc);
}
void TemplateTable::def(Bytecodes::Code code, int flags, TosState in, TosState out, void (*gen)(int arg), int arg) {
// should factor out these constants
const int ubcp = 1 << Template::uses_bcp_bit;
const int disp = 1 << Template::does_dispatch_bit;
const int clvm = 1 << Template::calls_vm_bit;
const int iswd = 1 << Template::wide_bit;
// 判断是否是宽字节指令
bool is_wide = (flags & iswd) != 0;
assert(in == vtos || !is_wide, "wide instructions have vtos entry point only");
Template* t = is_wide ? template_for_wide(code) : template_for(code);
// setup entry
t->initialize(flags, in, out, gen, arg);
assert(t->bytecode() == code, "just checkin'");
}
//先检查是否是非宽字节指令,如果是则返回对应的Template
static Template* template_for (Bytecodes::Code code) { Bytecodes::check (code); return &_template_table [code]; }
static Template* template_for_wide(Bytecodes::Code code) { Bytecodes::wide_check(code); return &_template_table_wide[code]; }
void TemplateTable::pd_initialize() {
// No amd64 specific initialization
}
点击生成字节码指令模板的函数时,弹框如下:
即字节码指令的实现跟CPU架构相关,我们重点关注x86_64下的实现。全局搜索该文件名,结果如下:
即通过configurations.xml文件来引入特定CPU架构的实现文件。
以aaload指令和aastore指令为例说明字节码指令的实现方式,其源码说明如下:
void TemplateTable::aaload() {
//校验当前Template的itos与atos与指令配置是否相符
//aaload指令的栈顶是int类型的,表示待加载的数组索引,对应这里的itos
//aaload指令执行完成后栈顶的值是一个对象引用,表示读取的数组元素,对应这里的atos
transition(itos, atos);
//pop_ptr表示把当前栈帧栈顶的值pop出来放到rdx中,因为操作数栈的栈顶在栈顶缓存下就是rax中的值
//所以当前栈帧栈顶的值就是一个数组引用
__ pop_ptr(rdx);
// eax: index
// rdx: array
//根据数组引用,读取对应的数组长度,判断index是否在小于数组长度,如果否则抛出异常
index_check(rdx, rax); // kills rbx
//根据数组索引,数组引用计算目标元素的位置,然后加载特定内存位置的值到rax中
__ load_heap_oop(rax, Address(rdx, rax,
UseCompressedOops ? Address::times_4 : Address::times_8,
arrayOopDesc::base_offset_in_bytes(T_OBJECT)));
}
void TemplateTable::aastore() {
Label is_null, ok_is_subtype, done;
//校验当前Template的itos与atos与指令配置是否相符
transition(vtos, vtos);
// stack: ..., array, index, value
//将栈顶的三个元素复制到寄存器中
__ movptr(rax, at_tos()); // value
__ movl(rcx, at_tos_p1()); // index
__ movptr(rdx, at_tos_p2()); // array
//获取指定索引的数组元素的内存位置
Address element_address(rdx, rcx,
UseCompressedOops? Address::times_4 : Address::times_8,
arrayOopDesc::base_offset_in_bytes(T_OBJECT));
//校验数组索引是否超过数组长度
index_check(rdx, rcx); // kills rbx
//rax中的值非空校验,校验失败跳转到is_null标签
__ testptr(rax, rax);
__ jcc(Assembler::zero, is_null);
// 获取rax中的对象的Klass,将其引用放到rbx中
__ load_klass(rbx, rax);
// 将rdx中的数组对应的Klass的引用放到rax中
__ load_klass(rax, rdx);
//将数组klass的数组元素的klass的引用放到rax中
__ movptr(rax, Address(rax,
ObjArrayKlass::element_klass_offset()));
//将element_address的内存地址放到rdx中
__ lea(rdx, element_address);
//检查value对应的klass,即rax中的klass引用,是否是数组元素klass即rax中的klass引用的子类型
//如果检查通过则跳转到ok_is_subtype
__ gen_subtype_check(rbx, ok_is_subtype);
//检查失败,抛出异常
__ jump(ExternalAddress(Interpreter::_throw_ArrayStoreException_entry));
// 检查成功
__ bind(ok_is_subtype);
// 将栈顶的值即目标value再次拷贝到rax中
__ movptr(rax, at_tos());
// Now store using the appropriate barrier
//rdx中保存的是存入数组的内存位置,将rax中的值写入到对应的内存位置,会根据不同的BarrierSet类型执行不同操作
do_oop_store(_masm, Address(rdx, 0), rax, _bs->kind(), true);
//完成
__ jmp(done);
//保存NULL到数组中
__ bind(is_null);
__ profile_null_seen(rbx);
do_oop_store(_masm, element_address, noreg, _bs->kind(), true);
//操作结束
__ bind(done);
//将rsp向高地址方向移动,即pop掉三个栈顶元素
__ addptr(rsp, 3 * Interpreter::stackElementSize);
}
//返回栈顶元素的内存地址
static inline Address at_tos () {
//rsp寄存器保存栈顶地址,expr_offset_in_bytes方法返回偏移量
return Address(rsp, Interpreter::expr_offset_in_bytes(0));
}
//返回栈顶第二个元素的内存地址
static inline Address at_tos_p1() {
return Address(rsp, Interpreter::expr_offset_in_bytes(1));
}
//返回栈顶第三个元素的内存地址
static inline Address at_tos_p2() {
return Address(rsp, Interpreter::expr_offset_in_bytes(2));
}
static int expr_offset_in_bytes(int i) { return stackElementSize * i; }
InterpreterGenerator的定义在同目录下的interpreterGenerator.hpp中,表示一个解释器生成器。其实现跟Interpreter类似,只是一个统一的门面而已,通过宏决定其继承的子类是CppInterpreterGenerator或者TemplateInterpreterGenerator,如下图:
默认是继承TemplateInterpreterGenerator,此时类继承关系如下:
跟平台相关的部分通过图中的宏定义引入,interpreterGenerator_x86.hpp中定义的都是私有方法,如下图:
重点关注其构造方法实现,如下:
其核心就是调用父类的generate_all方法。
AbstractInterpreterGenerator的定义位于同目录下的abstractInterpreterGenerator.hpp中,只有一个属性InterpreterMacroAssembler* _masm,即用来生成字节码的Assembler实例。AbstractInterpreterGenerator定义的方法都是protected方法,如下图:
重点关注其构造方法和generate_all方法的实现,源码说明如下:
AbstractInterpreterGenerator::AbstractInterpreterGenerator(StubQueue* _code) {
_masm = NULL;
}
void AbstractInterpreterGenerator::generate_all() {
//在CodeletMark中申请一个新的保存汇编代码的Stub和一个与之关联的InterpreterMacroAssembler实例
//CodeletMark销毁后自动销毁掉InterpreterMacroAssembler
{ CodeletMark cm(_masm, "slow signature handler");
//generate_slow_signature_handler方法最终调用InterpreterRuntime::slow_signature_handler方法实现
Interpreter::_slow_signature_handler = generate_slow_signature_handler();
}
}
TemplateInterpreterGenerator的定义位于同目录的templateInterpreterGenerator.hpp中,在AbstractInterpreterGenerator的基础上主要添加了一些protected方法,如下图:
generate_all方法用于生成Interpreter中定义的各种调用入口地址,源码说明如下:
TemplateInterpreterGenerator::TemplateInterpreterGenerator(StubQueue* _code): AbstractInterpreterGenerator(_code) {
_unimplemented_bytecode = NULL;
_illegal_bytecode_sequence = NULL;
}
void TemplateInterpreterGenerator::generate_all() {
AbstractInterpreterGenerator::generate_all();
{ CodeletMark cm(_masm, "error exits");
//生成包含错误提示的退出函数
_unimplemented_bytecode = generate_error_exit("unimplemented bytecode");
_illegal_bytecode_sequence = generate_error_exit("illegal bytecode sequence - method not verified");
}
{ CodeletMark cm(_masm, "return entry points");
const int index_size = sizeof(u2);
//初始化Interpreter::_return_entry数组
for (int i = 0; i < Interpreter::number_of_return_entries; i++) {
Interpreter::_return_entry[i] =
EntryPoint(
generate_return_entry_for(itos, i, index_size),
generate_return_entry_for(itos, i, index_size),
generate_return_entry_for(itos, i, index_size),
generate_return_entry_for(itos, i, index_size),
generate_return_entry_for(atos, i, index_size),
generate_return_entry_for(itos, i, index_size),
generate_return_entry_for(ltos, i, index_size),
generate_return_entry_for(ftos, i, index_size),
generate_return_entry_for(dtos, i, index_size),
generate_return_entry_for(vtos, i, index_size)
);
}
}
{ CodeletMark cm(_masm, "invoke return entry points");
//btos/ztos/ctos/stos这四种栈顶值类型都会转换成int,所以states将其替换成itos
const TosState states[] = {itos, itos, itos, itos, itos, ltos, ftos, dtos, atos, vtos, ilgl};
//获取三个指令的指令长度
const int invoke_length = Bytecodes::length_for(Bytecodes::_invokestatic);
const int invokeinterface_length = Bytecodes::length_for(Bytecodes::_invokeinterface);
const int invokedynamic_length = Bytecodes::length_for(Bytecodes::_invokedynamic);
//逐一初始化_invoke_return_entry,_invokeinterface_return_entry,_invokedynamic_return_entry
for (int i = 0; i < Interpreter::number_of_return_addrs; i++) {
TosState state = states[i];
assert(state != ilgl, "states array is wrong above");
Interpreter::_invoke_return_entry[i] = generate_return_entry_for(state, invoke_length, sizeof(u2));
Interpreter::_invokeinterface_return_entry[i] = generate_return_entry_for(state, invokeinterface_length, sizeof(u2));
Interpreter::_invokedynamic_return_entry[i] = generate_return_entry_for(state, invokedynamic_length, sizeof(u4));
}
}
//省略其他属性的初始化代码。。。。。。
//初始化_entry_table
#define method_entry(kind) \
{ CodeletMark cm(_masm, "method entry point (kind = " #kind ")"); \
Interpreter::_entry_table[Interpreter::kind] = generate_method_entry(Interpreter::kind); \
}
// all non-native method kinds
method_entry(zerolocals)
method_entry(zerolocals_synchronized)
method_entry(empty)
method_entry(accessor)
method_entry(abstract)
method_entry(java_lang_math_sin )
method_entry(java_lang_math_cos )
method_entry(java_lang_math_tan )
method_entry(java_lang_math_abs )
method_entry(java_lang_math_sqrt )
method_entry(java_lang_math_log )
method_entry(java_lang_math_log10)
method_entry(java_lang_math_exp )
method_entry(java_lang_math_pow )
method_entry(java_lang_ref_reference_get)
if (UseCRC32Intrinsics) {
method_entry(java_util_zip_CRC32_update)
method_entry(java_util_zip_CRC32_updateBytes)
method_entry(java_util_zip_CRC32_updateByteBuffer)
}
initialize_method_handle_entries();
// all native method kinds (must be one contiguous block)
Interpreter::_native_entry_begin = Interpreter::code()->code_end();
method_entry(native)
method_entry(native_synchronized)
Interpreter::_native_entry_end = Interpreter::code()->code_end();
#undef method_entry
//生成所有字节码对应的汇编指令
set_entry_points_for_all_bytes();
set_safepoints_for_all_bytes();
}
set_entry_points_for_all_bytes方法给所有的字节码生成对应的汇编指令,源码说明如下:
void TemplateInterpreterGenerator::set_entry_points_for_all_bytes() {
//逐一遍历所有的字节码
for (int i = 0; i < DispatchTable::length; i++) {
Bytecodes::Code code = (Bytecodes::Code)i;
//如果定义了这个字节码
if (Bytecodes::is_defined(code)) {
//生成对应字节码的汇编指令
set_entry_points(code);
} else {
//将其标记成未实现
set_unimplemented(i);
}
}
}
void TemplateInterpreterGenerator::set_entry_points(Bytecodes::Code code) {
CodeletMark cm(_masm, Bytecodes::name(code), code);
// 初始化 entry points
assert(_unimplemented_bytecode != NULL, "should have been generated before");
assert(_illegal_bytecode_sequence != NULL, "should have been generated before");
address bep = _illegal_bytecode_sequence;
address zep = _illegal_bytecode_sequence;
address cep = _illegal_bytecode_sequence;
address sep = _illegal_bytecode_sequence;
address aep = _illegal_bytecode_sequence;
address iep = _illegal_bytecode_sequence;
address lep = _illegal_bytecode_sequence;
address fep = _illegal_bytecode_sequence;
address dep = _illegal_bytecode_sequence;
address vep = _unimplemented_bytecode;
address wep = _unimplemented_bytecode;
//如果定义了字节码
if (Bytecodes::is_defined(code)) {
//获取该字节码对应的Template
Template* t = TemplateTable::template_for(code);
assert(t->is_valid(), "just checking");
//生成汇编代码,最终调用Template::generate方法生成
set_short_entry_points(t, bep, cep, sep, aep, iep, lep, fep, dep, vep);
}
//如果是宽字节
if (Bytecodes::wide_is_defined(code)) {
//获取该字节码对应的Template
Template* t = TemplateTable::template_for_wide(code);
assert(t->is_valid(), "just checking");
//生成汇编代码,最终调用Template::generate方法生成
set_wide_entry_point(t, wep);
}
// 将生成的 entry points放入_normal_table中
EntryPoint entry(bep, zep, cep, sep, aep, iep, lep, fep, dep, vep);
Interpreter::_normal_table.set_entry(code, entry);
Interpreter::_wentry_point[code] = wep;
}
void TemplateInterpreterGenerator::set_unimplemented(int i) {
address e = _unimplemented_bytecode;
EntryPoint entry(e, e, e, e, e, e, e, e, e, e);
Interpreter::_normal_table.set_entry(i, entry);
Interpreter::_wentry_point[i] = _unimplemented_bytecode;
}
最终调用Template::generate(InterpreterMacroAssembler* masm)方法生成汇编代码,其调用链如下: