diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index 8f516f38e7d..82a4df29326 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -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 . +// 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 void MacroAssembler::lookup_virtual_method(Register recv_klass, RegisterOrConstant vtable_index, diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp index 1a8271166a9..8308ea255c7 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp @@ -254,6 +254,15 @@ class MacroAssembler: public Assembler { Label& no_such_interface, 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 // n.n. x86 allows RegisterOrConstant for vtable_index void lookup_virtual_method(Register recv_klass, diff --git a/src/hotspot/cpu/riscv/vtableStubs_riscv.cpp b/src/hotspot/cpu/riscv/vtableStubs_riscv.cpp index 6ab3a262323..9d08796681f 100644 --- a/src/hotspot/cpu/riscv/vtableStubs_riscv.cpp +++ b/src/hotspot/cpu/riscv/vtableStubs_riscv.cpp @@ -178,7 +178,7 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) { // so all registers except arguments are free at this point. const Register recv_klass_reg = x18; 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_reg2 = x29; const Register icholder_reg = t1; @@ -195,28 +195,13 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) { __ load_klass(recv_klass_reg, j_rarg0); // 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 - __ lookup_interface_method(// inputs: rec. class, interface, itable index - recv_klass_reg, holder_klass_reg, itable_index, - // outputs: method, scan temp. reg - xmethod, temp_reg, - L_no_such_interface); - - const ptrdiff_t lookupSize = __ pc() - start_pc; + __ lookup_interface_method_stub(recv_klass_reg, holder_klass_reg, resolved_klass_reg, xmethod, + temp_reg, temp_reg2, itable_index, L_no_such_interface); // Reduce "estimate" such that "padding" does not drop below 8. const ptrdiff_t estimate = 256; - const ptrdiff_t codesize = typecheckSize + lookupSize; + const ptrdiff_t codesize = __ pc() - start_pc; slop_delta = (int)(estimate - codesize); 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);