8318159: RISC-V: Improve itable_stub
Reviewed-by: fyang, rehn
This commit is contained in:
parent
06f040ba3a
commit
6d79e0aa3c
@ -2519,6 +2519,109 @@ void MacroAssembler::lookup_interface_method(Register recv_klass,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Look up the method for a megamorphic invokeinterface call in a single pass over itable:
|
||||||
|
// - check recv_klass (actual object class) is a subtype of resolved_klass from CompiledICHolder
|
||||||
|
// - find a holder_klass (class that implements the method) vtable offset and get the method from vtable by index
|
||||||
|
// The target method is determined by <holder_klass, itable_index>.
|
||||||
|
// The receiver klass is in recv_klass.
|
||||||
|
// On success, the result will be in method_result, and execution falls through.
|
||||||
|
// On failure, execution transfers to the given label.
|
||||||
|
void MacroAssembler::lookup_interface_method_stub(Register recv_klass,
|
||||||
|
Register holder_klass,
|
||||||
|
Register resolved_klass,
|
||||||
|
Register method_result,
|
||||||
|
Register temp_itbl_klass,
|
||||||
|
Register scan_temp,
|
||||||
|
int itable_index,
|
||||||
|
Label& L_no_such_interface) {
|
||||||
|
// 'method_result' is only used as output register at the very end of this method.
|
||||||
|
// Until then we can reuse it as 'holder_offset'.
|
||||||
|
Register holder_offset = method_result;
|
||||||
|
assert_different_registers(resolved_klass, recv_klass, holder_klass, temp_itbl_klass, scan_temp, holder_offset);
|
||||||
|
|
||||||
|
int vtable_start_offset_bytes = in_bytes(Klass::vtable_start_offset());
|
||||||
|
int scan_step = itableOffsetEntry::size() * wordSize;
|
||||||
|
int ioffset_bytes = in_bytes(itableOffsetEntry::interface_offset());
|
||||||
|
int ooffset_bytes = in_bytes(itableOffsetEntry::offset_offset());
|
||||||
|
int itmentry_off_bytes = in_bytes(itableMethodEntry::method_offset());
|
||||||
|
const int vte_scale = exact_log2(vtableEntry::size_in_bytes());
|
||||||
|
|
||||||
|
Label L_loop_search_resolved_entry, L_resolved_found, L_holder_found;
|
||||||
|
|
||||||
|
lwu(scan_temp, Address(recv_klass, Klass::vtable_length_offset()));
|
||||||
|
add(recv_klass, recv_klass, vtable_start_offset_bytes + ioffset_bytes);
|
||||||
|
// itableOffsetEntry[] itable = recv_klass + Klass::vtable_start_offset()
|
||||||
|
// + sizeof(vtableEntry) * (recv_klass->_vtable_len);
|
||||||
|
// scan_temp = &(itable[0]._interface)
|
||||||
|
// temp_itbl_klass = itable[0]._interface;
|
||||||
|
shadd(scan_temp, scan_temp, recv_klass, scan_temp, vte_scale);
|
||||||
|
ld(temp_itbl_klass, Address(scan_temp));
|
||||||
|
mv(holder_offset, zr);
|
||||||
|
|
||||||
|
// Initial checks:
|
||||||
|
// - if (holder_klass != resolved_klass), go to "scan for resolved"
|
||||||
|
// - if (itable[0] == holder_klass), shortcut to "holder found"
|
||||||
|
// - if (itable[0] == 0), no such interface
|
||||||
|
bne(resolved_klass, holder_klass, L_loop_search_resolved_entry);
|
||||||
|
beq(holder_klass, temp_itbl_klass, L_holder_found);
|
||||||
|
beqz(temp_itbl_klass, L_no_such_interface);
|
||||||
|
|
||||||
|
// Loop: Look for holder_klass record in itable
|
||||||
|
// do {
|
||||||
|
// temp_itbl_klass = *(scan_temp += scan_step);
|
||||||
|
// if (temp_itbl_klass == holder_klass) {
|
||||||
|
// goto L_holder_found; // Found!
|
||||||
|
// }
|
||||||
|
// } while (temp_itbl_klass != 0);
|
||||||
|
// goto L_no_such_interface // Not found.
|
||||||
|
Label L_search_holder;
|
||||||
|
bind(L_search_holder);
|
||||||
|
add(scan_temp, scan_temp, scan_step);
|
||||||
|
ld(temp_itbl_klass, Address(scan_temp));
|
||||||
|
beq(holder_klass, temp_itbl_klass, L_holder_found);
|
||||||
|
bnez(temp_itbl_klass, L_search_holder);
|
||||||
|
|
||||||
|
j(L_no_such_interface);
|
||||||
|
|
||||||
|
// Loop: Look for resolved_class record in itable
|
||||||
|
// while (true) {
|
||||||
|
// temp_itbl_klass = *(scan_temp += scan_step);
|
||||||
|
// if (temp_itbl_klass == 0) {
|
||||||
|
// goto L_no_such_interface;
|
||||||
|
// }
|
||||||
|
// if (temp_itbl_klass == resolved_klass) {
|
||||||
|
// goto L_resolved_found; // Found!
|
||||||
|
// }
|
||||||
|
// if (temp_itbl_klass == holder_klass) {
|
||||||
|
// holder_offset = scan_temp;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
Label L_loop_search_resolved;
|
||||||
|
bind(L_loop_search_resolved);
|
||||||
|
add(scan_temp, scan_temp, scan_step);
|
||||||
|
ld(temp_itbl_klass, Address(scan_temp));
|
||||||
|
bind(L_loop_search_resolved_entry);
|
||||||
|
beqz(temp_itbl_klass, L_no_such_interface);
|
||||||
|
beq(resolved_klass, temp_itbl_klass, L_resolved_found);
|
||||||
|
bne(holder_klass, temp_itbl_klass, L_loop_search_resolved);
|
||||||
|
mv(holder_offset, scan_temp);
|
||||||
|
j(L_loop_search_resolved);
|
||||||
|
|
||||||
|
// See if we already have a holder klass. If not, go and scan for it.
|
||||||
|
bind(L_resolved_found);
|
||||||
|
beqz(holder_offset, L_search_holder);
|
||||||
|
mv(scan_temp, holder_offset);
|
||||||
|
|
||||||
|
// Finally, scan_temp contains holder_klass vtable offset
|
||||||
|
bind(L_holder_found);
|
||||||
|
lwu(method_result, Address(scan_temp, ooffset_bytes - ioffset_bytes));
|
||||||
|
add(recv_klass, recv_klass, itable_index * wordSize + itmentry_off_bytes
|
||||||
|
- vtable_start_offset_bytes - ioffset_bytes); // substract offsets to restore the original value of recv_klass
|
||||||
|
add(method_result, recv_klass, method_result);
|
||||||
|
ld(method_result, Address(method_result));
|
||||||
|
}
|
||||||
|
|
||||||
// virtual method calling
|
// virtual method calling
|
||||||
void MacroAssembler::lookup_virtual_method(Register recv_klass,
|
void MacroAssembler::lookup_virtual_method(Register recv_klass,
|
||||||
RegisterOrConstant vtable_index,
|
RegisterOrConstant vtable_index,
|
||||||
|
@ -254,6 +254,15 @@ class MacroAssembler: public Assembler {
|
|||||||
Label& no_such_interface,
|
Label& no_such_interface,
|
||||||
bool return_method = true);
|
bool return_method = true);
|
||||||
|
|
||||||
|
void lookup_interface_method_stub(Register recv_klass,
|
||||||
|
Register holder_klass,
|
||||||
|
Register resolved_klass,
|
||||||
|
Register method_result,
|
||||||
|
Register temp_reg,
|
||||||
|
Register temp_reg2,
|
||||||
|
int itable_index,
|
||||||
|
Label& L_no_such_interface);
|
||||||
|
|
||||||
// virtual method calling
|
// virtual method calling
|
||||||
// n.n. x86 allows RegisterOrConstant for vtable_index
|
// n.n. x86 allows RegisterOrConstant for vtable_index
|
||||||
void lookup_virtual_method(Register recv_klass,
|
void lookup_virtual_method(Register recv_klass,
|
||||||
|
@ -178,7 +178,7 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) {
|
|||||||
// so all registers except arguments are free at this point.
|
// so all registers except arguments are free at this point.
|
||||||
const Register recv_klass_reg = x18;
|
const Register recv_klass_reg = x18;
|
||||||
const Register holder_klass_reg = x19; // declaring interface klass (DECC)
|
const Register holder_klass_reg = x19; // declaring interface klass (DECC)
|
||||||
const Register resolved_klass_reg = xmethod; // resolved interface klass (REFC)
|
const Register resolved_klass_reg = x30; // resolved interface klass (REFC)
|
||||||
const Register temp_reg = x28;
|
const Register temp_reg = x28;
|
||||||
const Register temp_reg2 = x29;
|
const Register temp_reg2 = x29;
|
||||||
const Register icholder_reg = t1;
|
const Register icholder_reg = t1;
|
||||||
@ -195,28 +195,13 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) {
|
|||||||
__ load_klass(recv_klass_reg, j_rarg0);
|
__ load_klass(recv_klass_reg, j_rarg0);
|
||||||
|
|
||||||
// Receiver subtype check against REFC.
|
// Receiver subtype check against REFC.
|
||||||
__ lookup_interface_method(// inputs: rec. class, interface
|
|
||||||
recv_klass_reg, resolved_klass_reg, noreg,
|
|
||||||
// outputs: scan temp. reg1, scan temp. reg2
|
|
||||||
temp_reg2, temp_reg,
|
|
||||||
L_no_such_interface,
|
|
||||||
/*return_method=*/false);
|
|
||||||
|
|
||||||
const ptrdiff_t typecheckSize = __ pc() - start_pc;
|
|
||||||
start_pc = __ pc();
|
|
||||||
|
|
||||||
// Get selected method from declaring class and itable index
|
// Get selected method from declaring class and itable index
|
||||||
__ lookup_interface_method(// inputs: rec. class, interface, itable index
|
__ lookup_interface_method_stub(recv_klass_reg, holder_klass_reg, resolved_klass_reg, xmethod,
|
||||||
recv_klass_reg, holder_klass_reg, itable_index,
|
temp_reg, temp_reg2, itable_index, L_no_such_interface);
|
||||||
// outputs: method, scan temp. reg
|
|
||||||
xmethod, temp_reg,
|
|
||||||
L_no_such_interface);
|
|
||||||
|
|
||||||
const ptrdiff_t lookupSize = __ pc() - start_pc;
|
|
||||||
|
|
||||||
// Reduce "estimate" such that "padding" does not drop below 8.
|
// Reduce "estimate" such that "padding" does not drop below 8.
|
||||||
const ptrdiff_t estimate = 256;
|
const ptrdiff_t estimate = 256;
|
||||||
const ptrdiff_t codesize = typecheckSize + lookupSize;
|
const ptrdiff_t codesize = __ pc() - start_pc;
|
||||||
slop_delta = (int)(estimate - codesize);
|
slop_delta = (int)(estimate - codesize);
|
||||||
slop_bytes += slop_delta;
|
slop_bytes += slop_delta;
|
||||||
assert(slop_delta >= 0, "itable #%d: Code size estimate (%d) for lookup_interface_method too small, required: %d", itable_index, (int)estimate, (int)codesize);
|
assert(slop_delta >= 0, "itable #%d: Code size estimate (%d) for lookup_interface_method too small, required: %d", itable_index, (int)estimate, (int)codesize);
|
||||||
|
Loading…
Reference in New Issue
Block a user