Repository navigation
runtime interp invokevirtual
wangkaiwu edited this page Jun 13, 2022
·
7 revisions
void TemplateTable::invokevirtual(int byte_no) {
prepare_invoke(byte_no,
rbx, // method or vtable index
noreg, // unused itable index
rcx, rdx); // recv, flags
// rbx: index, 调用方法的基址
// rcx: receiver, 调用者对象的 this 指针
// rdx: flags, 调用方法的 flags 参数
invokevirtual_helper(rbx, rcx, rdx);
}void TemplateTable::prepare_invoke(int byte_no,
Register method, // linked method (or i-klass)
Register index, // itable index, MethodType, etc.
Register recv, // if caller wants to see it
Register flags // if caller wants to test it
) {
const bool is_invokevirtual = code == Bytecodes::_invokevirtual;
// recv: rcx
const bool load_receiver = (recv != noreg);
// flags: rdx
const bool save_flags = (flags != noreg);
// 保存当前字节码指令的首地址到栈上
__ save_bcp();
// index: noreg
// method: rbx, 方法的基址
// flags: rdx, 方法的参数(private, final 等)
load_invoke_cp_cache_entry(byte_no, method, index, flags, is_invokevirtual, false, is_invokedynamic);
if (load_receiver) {
// recv: rcx
// flags: rdx
__ movl(recv, flags);
// parameter_size_mask: 0b1111_1111
// recv: 得到方法的参数数量
__ andl(recv, ConstantPoolCacheEntry::parameter_size_mask);
const int no_return_pc_pushed_yet = -1; // argument slot correction before we push return address
const int receiver_is_at_end = -1; // back off one slot to get receiver
// 假设有一个方法 public void sayHello(String word);
// 调用该方法之前,需要先把 this 压栈,再把 word 压栈
// recv_addr: 最终会得到 this 参数的地址
Address recv_addr = __ argument_address(recv, no_return_pc_pushed_yet + receiver_is_at_end);
// recv: rcx,存储了 this 对象的地址
__ movptr(recv, recv_addr);
// 检查对象非空
__ verify_oop(recv);
}
if (save_flags) {
// rbcp: r13
__ movl(rbcp, flags);
}
// compute return type
__ shrl(flags, ConstantPoolCacheEntry::tos_state_shift);
{
// return entry table 的地址
const address table_addr = (address) Interpreter::invoke_return_entry_table_for(code);
ExternalAddress table(table_addr);
// rscratch1: r10
// 将返回地址表保存到 rscratch1
__ lea(rscratch1, table);
// return 代码的地址到 rdx 中
__ movptr(flags, Address(rscratch1, flags, Address::times_ptr));
}
// 返回地址压栈
__ push(flags);
if (save_flags) {
// 还原 flags 的值, rdx
__ movl(flags, rbcp);
// 还原当前字节码的首地址到 r13 中
__ restore_bcp();
}
}void TemplateTable::load_invoke_cp_cache_entry(int byte_no,
Register method,
Register itable_index,
Register flags,
bool is_invokevirtual,
bool is_invokevfinal, /*unused*/
bool is_invokedynamic) {
const Register cache = rcx;
const Register index = rdx;
// index_size = u2,也就是 short
size_t index_size = (is_invokedynamic ? sizeof(u4) : sizeof(u2));
// byte_no: u2
// cache: 常量池的基址
// index: Methodref 的索引
resolve_cache_and_index(byte_no, cache, index, index_size);
const int method_offset = in_bytes(
ConstantPoolCache::base_offset() +
((byte_no == f2_byte)
? ConstantPoolCacheEntry::f2_offset()
: ConstantPoolCacheEntry::f1_offset()));
// method: rbx
// 根据 index 获取对应方法在常量池中的基址
__ movptr(method, Address(cache, index, Address::times_ptr, method_offset));
// itable_index = noreg
if (itable_index != noreg) {
// 不执行
}
const int flags_offset = in_bytes(ConstantPoolCache::base_offset() +
ConstantPoolCacheEntry::flags_offset());
// 获取方法的 flags 值(例如 private, final 等)
__ movl(flags, Address(cache, index, Address::times_ptr, flags_offset));
}void TemplateTable::resolve_cache_and_index(int byte_no,
Register Rcache,
Register index,
size_t index_size) {
// Rcache: rcx
// index: rdx
const Register temp = rbx;
Bytecodes::Code code = bytecode();
// index_size: u2
__ get_cache_and_index_and_bytecode_at_bcp(Rcache, index, temp, byte_no, 1, index_size);
// Rcache: 常量池的基址
// index: Methodref 常量的索引
// temp: 如果 index 对应的类已经完成了解析,那么某些标志位会变成字节码的值
// 判断 temp 是否是 invokevirtual
__ cmpl(temp, code);
// 相等的话跳转到 resolved
__ jcc(Assembler::equal, resolved);
// TODO: 解析类
address entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_from_cache);
__ movl(temp, code);
__ call_VM(noreg, entry, temp);
__ get_cache_and_index_at_bcp(Rcache, index, 1, index_size);
__ bind(resolved);
}void InterpreterMacroAssembler::get_cache_and_index_and_bytecode_at_bcp(Register cache,
Register index,
Register bytecode,
int byte_no,
int bcp_offset,
size_t index_size) {
// #6 = Methodref #4.#38 // javap/Test.testHello:()V
// cache: rcx
// index: rdx
// bcp_offset: 1
// index_size: u2
get_cache_and_index_at_bcp(cache, index, bcp_offset, index_size);
// bytecode: rbx
// cache: 常量池的基址
// index: 常量表的索引,例如 #6
// times_ptr: 值是3
// 将 index 对应的那个方法在常量池中的基址赋值到 rbx 中
movl(bytecode, Address(cache, index, Address::times_ptr,
ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::indices_offset()));
// 偏移数量, BitsPerByte == 0b1000 == 8;
// byte_no: f2_byte = 2
// shift_count = (1 + 2) * 8 = 24;
const int shift_count = (1 + byte_no) * BitsPerByte;
// 将地址右移 24位,
shrl(bytecode, shift_count);
// bytecode_1_mask: 0xFF
// bytecode: 应该是 #4 的值
andl(bytecode, ConstantPoolCacheEntry::bytecode_1_mask);
}
void InterpreterMacroAssembler::get_cache_and_index_at_bcp(Register cache,
Register index,
int bcp_offset,
size_t index_size) {
// index: rdx
// bcp_offset: 1
// index_size: u2
// 调用之后,index 将变成一个常量表的索引 (实际是上调用方法的常量信息)
get_cache_index_at_bcp(index, bcp_offset, index_size);
// 从栈上获取常量池的基址
movptr(cache, Address(rbp, frame::interpreter_frame_cache_offset * wordSize));
// index的值左移两位
shll(index, 2);
}
void InterpreterMacroAssembler::get_cache_index_at_bcp(Register index,
int bcp_offset,
size_t index_size) {
if (index_size == sizeof(u2)) {
// index: rdx
// _bcp_register: 当前字节码的首地址
// bcp_offset: 字节码第一个参数的偏移量
// 取出第一个参数,使用 load 是因为希望取出的值是无符号的 short,但是要放入一个8字节的寄存器里,于是高位需要补0
load_unsigned_short(index, Address(_bcp_register, bcp_offset));
}
}void InterpreterMacroAssembler::get_cache_and_index_at_bcp(Register cache,
Register index,
int bcp_offset,
size_t index_size) {
get_cache_index_at_bcp(index, bcp_offset, index_size);
movptr(cache, Address(rbp, frame::interpreter_frame_cache_offset * wordSize));
shll(index, 2);
}
void InterpreterMacroAssembler::get_cache_index_at_bcp(Register index,
int bcp_offset,
size_t index_size) {
if (index_size == sizeof(u2)) {
load_unsigned_short(index, Address(_bcp_register, bcp_offset));
}
}Address MacroAssembler::argument_address(RegisterOrConstant arg_slot,
int extra_slot_offset) {
Register scale_reg = noreg;
Address::ScaleFactor scale_factor = Address::no_scale;
scale_reg = arg_slot.as_register();
// stackElementSize: 8 字节
int stackElementSize = Interpreter::stackElementSize;
// scale_factor: 3,表示 2的3次方
scale_factor = Address::times(stackElementSize);
// extra_slot_offset: -2
// offset = 8 * -2 = -16
int offset = Interpreter::expr_offset_in_bytes(extra_slot_offset+0);
// offset += 8 == -8
offset += wordSize;
// scale_reg: 参数数量
// scale_factor: 3
// offset: -8
return Address(rsp, scale_reg, scale_factor, offset);
}address* TemplateInterpreter::invoke_return_entry_table_for(Bytecodes::Code code) {
switch (code) {
case Bytecodes::_invokevirtual:
return Interpreter::invoke_return_entry_table();
}
}
class TemplateInterpreter: public AbstractInterpreter {
static address _invoke_return_entry[number_of_return_addrs];
static address* invoke_return_entry_table() {
return _invoke_return_entry;
}
};void TemplateTable::invokevirtual_helper(Register index,
Register recv,
Register flags) {
Label notFinal;
// 方法的flags 保存到 rax 中 (也就是操作数栈顶)
__ movl(rax, flags);
// flags 中有没有 final 标记
__ andl(rax, (1 << ConstantPoolCacheEntry::is_vfinal_shift));
// 没有说明不是 final 方法
__ jcc(Assembler::zero, notFinal);
// 说明以下是 final 的方法流程
const Register method = index; // method must be rbx
// 调用者的 this 指针
__ null_check(recv);
// 先跳过 profile
__ profile_final_call(rax);
__ profile_arguments_type(rax, method, rbcp, true);
// 跳转到方法入口执行
__ jump_from_interpreted(method, rax);
// 不是 final 的方法
__ bind(notFinal);
// get receiver klass
__ null_check(recv, oopDesc::klass_offset_in_bytes());
// this 对象的 class 信息地址保存到 rax 中
__ load_klass(rax, recv);
// profile this call
__ profile_virtual_call(rax, rlocals, rdx);
// get target Method* & entry point
__ lookup_virtual_method(rax, index, method);
__ profile_called_method(method, rdx, rbcp);
__ profile_arguments_type(rdx, method, rbcp, true);
__ jump_from_interpreted(method, rdx);
}void InterpreterMacroAssembler::jump_from_interpreted(Register method, Register temp) {
prepare_to_jump_from_interpreted();
jmp(Address(method, Method::from_interpreted_offset()));
}void MacroAssembler::load_klass(Register dst, Register src) {
// src: 调用者 this 指针
// 对象的 8字节偏移处存储的是对象的 class 信息地址
movptr(dst, Address(src, oopDesc::klass_offset_in_bytes()));
}class InstanceKlass: public Klass {
static int header_size() {
return sizeof(InstanceKlass)/wordSize;
}
};
ByteSize Klass::vtable_start_offset() {
return in_ByteSize(InstanceKlass::header_size() * wordSize);
}class vtableEntry {
Method* _method;
static int method_offset_in_bytes() {
return offset_of(vtableEntry, _method);
}
};void MacroAssembler::lookup_virtual_method(Register recv_klass,
RegisterOrConstant vtable_index,
Register method_result) {
// recv_klass: rax, this 的 class 信息地址
// vtable_index: rbx, 目标虚方法的地址
// method_result: rbx, 真正的方法地址
// InstanceKlass 的大小
const int base = in_bytes(Klass::vtable_start_offset());
// recv_klass: this 对象的 class 地址
// vtable_index: 虚拟表的索引
Address vtable_entry_addr(recv_klass,
vtable_index, Address::times_ptr,
base + vtableEntry::method_offset_in_bytes());
// method_result: 目标方法的地址
movptr(method_result, vtable_entry_addr);
}void InterpreterRuntime::resolve_from_cache(JavaThread* thread, Bytecodes::Code bytecode) {
switch (bytecode) {
case Bytecodes::_invokevirtual:
resolve_invoke(thread, bytecode);
break;
}
}
void InterpreterRuntime::resolve_invoke(JavaThread* thread, Bytecodes::Code bytecode) {
Thread* THREAD = thread;
// 线程最后一帧的信息
LastFrameAccessor last_frame(thread);
Handle receiver(thread, NULL);
if (bytecode == Bytecodes::_invokevirtual) {
// 保存最后一帧的方法信息
methodHandle m(thread, last_frame.method());
// bci 方法中字节码的首地址
Bytecode_invoke call(m, last_frame.bci());
Symbol* signature = call.signature();
// receiver 调用者信息
receiver = Handle(thread, last_frame.callee_receiver(signature));
}
CallInfo info;
constantPoolHandle pool(thread, last_frame.method()->constants());
{
LinkResolver::resolve_invoke(info, receiver, pool,
last_frame.get_index_u2_cpcache(bytecode), bytecode, CHECK);
}
ConstantPoolCacheEntry* cp_cache_entry = last_frame.cache_entry();
if (cp_cache_entry->is_resolved(bytecode)) return;
switch (info.call_kind()) {
case CallInfo::direct_call:
cp_cache_entry->set_direct_call(
bytecode,
info.resolved_method(),
sender->is_interface());
break;
case CallInfo::vtable_call:
cp_cache_entry->set_vtable_call(
bytecode,
info.resolved_method(),
info.vtable_index());
break;
case CallInfo::itable_call:
cp_cache_entry->set_itable_call(
bytecode,
info.resolved_klass(),
info.resolved_method(),
info.itable_index());
break;
}
}void LinkResolver::resolve_invoke(CallInfo& result, Handle recv, const constantPoolHandle& pool, int index, Bytecodes::Code byte, TRAPS) {
switch (byte) {
case Bytecodes::_invokevirtual:
// result: CallInfo info
// recv: Handle receiver
// pool: constantPoolHandle pool
// index: 盲猜是常量池的索引
resolve_invokevirtual(result, recv, pool, index, CHECK);
break;
}
}
void LinkResolver::resolve_invokevirtual(CallInfo& result, Handle recv,
const constantPoolHandle& pool, int index,
TRAPS) {
LinkInfo link_info(pool, index, CHECK);
Klass* recvrKlass = recv.is_null() ? (Klass*)NULL : recv->klass();
resolve_virtual_call(result, recv, recvrKlass, link_info, /*check_null_or_abstract*/true, CHECK);
}
void LinkResolver::runtime_resolve_virtual_method(CallInfo& result,
const methodHandle& resolved_method,
Klass* resolved_klass,
Handle recv,
Klass* recv_klass,
bool check_null_and_abstract,
TRAPS) {
int vtable_index = Method::invalid_vtable_index;
if (resolved_method->method_holder()->is_interface()) {
selected_method = methodHandle(THREAD, recv_klass->method_at_vtable(vtable_index));
} else {
vtable_index = resolved_method->vtable_index();
if (vtable_index == Method::nonvirtual_vtable_index) {
selected_method = resolved_method;
} else {
selected_method = methodHandle(THREAD, recv_klass->method_at_vtable(vtable_index));
}
}
result.set_virtual(resolved_klass, recv_klass, resolved_method, selected_method, vtable_index, CHECK);
}class vtableEntry {
Method* _method;
void set(Method* method) {
_method = method;
}
};class klassVtable {
Klass* _klass;
int _tableOffset;
vtableEntry* table() const {
return (vtableEntry*)(address(_klass) + _tableOffset);
}
};
void klassVtable::put_method_at(Method* m, int index) {
table()[index].set(m);
}
void klassVtable::initialize_vtable(bool checkconstraints, TRAPS) {
Klass* super = _klass->java_super();
int super_vtable_len = initialize_from_super(super);
if (_klass->is_array_klass()) {
} else {
Array<Method*>* methods = ik()->methods();
int len = methods->length();
int initialized = super_vtable_len;
for (int i = 0; i < len; i++) {
bool needs_new_entry = update_inherited_vtable(ik(), mh, super_vtable_len, -1, checkconstraints, CHECK);
if (needs_new_entry) {
put_method_at(mh(), initialized);
mh()->set_vtable_index(initialized);
initialized++;
}
}
}
}bool InstanceKlass::link_class_impl(bool throw_verifyerror, TRAPS) {
}