Repository navigation
runtime interp invokevirtual
ceragon 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
// rdx: 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
load_invoke_cp_cache_entry(byte_no, method, index, flags, is_invokevirtual, false, is_invokedynamic);
if (load_receiver) {
__ movl(recv, flags);
__ 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
Address recv_addr = __ argument_address(recv, no_return_pc_pushed_yet + receiver_is_at_end);
__ movptr(recv, recv_addr);
__ verify_oop(recv);
}
if (save_flags) {
__ movl(rbcp, flags);
}
__ shrl(flags, ConstantPoolCacheEntry::tos_state_shift);
{
const address table_addr = (address) Interpreter::invoke_return_entry_table_for(code);
ExternalAddress table(table_addr);
__ lea(rscratch1, table);
__ movptr(flags, Address(rscratch1, flags, Address::times_ptr));
}
__ push(flags);
if (save_flags) {
__ movl(flags, rbcp);
__ 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));
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()));
__ 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());
__ 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;
// index_size: u2
__ get_cache_and_index_and_bytecode_at_bcp(Rcache, index, temp, byte_no, 1, index_size);
__ cmpl(temp, code);
__ jcc(Assembler::equal, resolved);
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) {
get_cache_and_index_at_bcp(cache, index, bcp_offset, index_size);
movl(bytecode, Address(cache, index, Address::times_ptr, ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::indices_offset()));
const int shift_count = (1 + byte_no) * BitsPerByte;
shrl(bytecode, shift_count);
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) {
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));
}
}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));
}
}void TemplateTable::invokevirtual_helper(Register index,
Register recv,
Register flags) {
Label notFinal;
__ movl(rax, flags);
__ andl(rax, (1 << ConstantPoolCacheEntry::is_vfinal_shift));
__ jcc(Assembler::zero, notFinal);
const Register method = index; // method must be rbx
__ null_check(recv);
__ profile_final_call(rax);
__ profile_arguments_type(rax, method, rbcp, true);
__ jump_from_interpreted(method, rax);
__ bind(notFinal);
// get receiver klass
__ null_check(recv, oopDesc::klass_offset_in_bytes());
__ 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 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 || bytecode == Bytecodes::_invokeinterface ||
bytecode == Bytecodes::_invokespecial) {
methodHandle m (thread, last_frame.method());
Bytecode_invoke call(m, last_frame.bci());
Symbol* signature = call.signature();
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;
}
}