Skip to content

Commit c664f1c

Browse files
author
Boris Ulasevich
committedSep 8, 2023
8307352: AARCH64: Improve itable_stub
Reviewed-by: simonis, eastigeevich, aph
1 parent 8ddf9ea commit c664f1c

File tree

4 files changed

+118
-20
lines changed

4 files changed

+118
-20
lines changed
 

‎src/hotspot/cpu/aarch64/assembler_aarch64.hpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -574,7 +574,7 @@ class Address {
574574
if (size == 0) // It's a byte
575575
i->f(ext().shift() >= 0, 12);
576576
else {
577-
assert(ext().shift() <= 0 || ext().shift() == (int)size, "bad shift");
577+
guarantee(ext().shift() <= 0 || ext().shift() == (int)size, "bad shift");
578578
i->f(ext().shift() > 0, 12);
579579
}
580580
i->f(0b10, 11, 10);

‎src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp

+104
Original file line numberDiff line numberDiff line change
@@ -1196,6 +1196,110 @@ void MacroAssembler::lookup_interface_method(Register recv_klass,
11961196
}
11971197
}
11981198

1199+
// Look up the method for a megamorphic invokeinterface call in a single pass over itable:
1200+
// - check recv_klass (actual object class) is a subtype of resolved_klass from CompiledICHolder
1201+
// - find a holder_klass (class that implements the method) vtable offset and get the method from vtable by index
1202+
// The target method is determined by <holder_klass, itable_index>.
1203+
// The receiver klass is in recv_klass.
1204+
// On success, the result will be in method_result, and execution falls through.
1205+
// On failure, execution transfers to the given label.
1206+
void MacroAssembler::lookup_interface_method_stub(Register recv_klass,
1207+
Register holder_klass,
1208+
Register resolved_klass,
1209+
Register method_result,
1210+
Register temp_itbl_klass,
1211+
Register scan_temp,
1212+
int itable_index,
1213+
Label& L_no_such_interface) {
1214+
// 'method_result' is only used as output register at the very end of this method.
1215+
// Until then we can reuse it as 'holder_offset'.
1216+
Register holder_offset = method_result;
1217+
assert_different_registers(resolved_klass, recv_klass, holder_klass, temp_itbl_klass, scan_temp, holder_offset);
1218+
1219+
int vtable_start_offset = in_bytes(Klass::vtable_start_offset());
1220+
int itable_offset_entry_size = itableOffsetEntry::size() * wordSize;
1221+
int ioffset = in_bytes(itableOffsetEntry::interface_offset());
1222+
int ooffset = in_bytes(itableOffsetEntry::offset_offset());
1223+
1224+
Label L_loop_search_resolved_entry, L_resolved_found, L_holder_found;
1225+
1226+
ldrw(scan_temp, Address(recv_klass, Klass::vtable_length_offset()));
1227+
add(recv_klass, recv_klass, vtable_start_offset + ioffset);
1228+
// itableOffsetEntry[] itable = recv_klass + Klass::vtable_start_offset() + sizeof(vtableEntry) * recv_klass->_vtable_len;
1229+
// temp_itbl_klass = itable[0]._interface;
1230+
int vtblEntrySize = vtableEntry::size_in_bytes();
1231+
assert(vtblEntrySize == wordSize, "ldr lsl shift amount must be 3");
1232+
ldr(temp_itbl_klass, Address(recv_klass, scan_temp, Address::lsl(exact_log2(vtblEntrySize))));
1233+
mov(holder_offset, zr);
1234+
// scan_temp = &(itable[0]._interface)
1235+
lea(scan_temp, Address(recv_klass, scan_temp, Address::lsl(exact_log2(vtblEntrySize))));
1236+
1237+
// Initial checks:
1238+
// - if (holder_klass != resolved_klass), go to "scan for resolved"
1239+
// - if (itable[0] == holder_klass), shortcut to "holder found"
1240+
// - if (itable[0] == 0), no such interface
1241+
cmp(resolved_klass, holder_klass);
1242+
br(Assembler::NE, L_loop_search_resolved_entry);
1243+
cmp(holder_klass, temp_itbl_klass);
1244+
br(Assembler::EQ, L_holder_found);
1245+
cbz(temp_itbl_klass, L_no_such_interface);
1246+
1247+
// Loop: Look for holder_klass record in itable
1248+
// do {
1249+
// temp_itbl_klass = *(scan_temp += itable_offset_entry_size);
1250+
// if (temp_itbl_klass == holder_klass) {
1251+
// goto L_holder_found; // Found!
1252+
// }
1253+
// } while (temp_itbl_klass != 0);
1254+
// goto L_no_such_interface // Not found.
1255+
Label L_search_holder;
1256+
bind(L_search_holder);
1257+
ldr(temp_itbl_klass, Address(pre(scan_temp, itable_offset_entry_size)));
1258+
cmp(holder_klass, temp_itbl_klass);
1259+
br(Assembler::EQ, L_holder_found);
1260+
cbnz(temp_itbl_klass, L_search_holder);
1261+
1262+
b(L_no_such_interface);
1263+
1264+
// Loop: Look for resolved_class record in itable
1265+
// while (true) {
1266+
// temp_itbl_klass = *(scan_temp += itable_offset_entry_size);
1267+
// if (temp_itbl_klass == 0) {
1268+
// goto L_no_such_interface;
1269+
// }
1270+
// if (temp_itbl_klass == resolved_klass) {
1271+
// goto L_resolved_found; // Found!
1272+
// }
1273+
// if (temp_itbl_klass == holder_klass) {
1274+
// holder_offset = scan_temp;
1275+
// }
1276+
// }
1277+
//
1278+
Label L_loop_search_resolved;
1279+
bind(L_loop_search_resolved);
1280+
ldr(temp_itbl_klass, Address(pre(scan_temp, itable_offset_entry_size)));
1281+
bind(L_loop_search_resolved_entry);
1282+
cbz(temp_itbl_klass, L_no_such_interface);
1283+
cmp(resolved_klass, temp_itbl_klass);
1284+
br(Assembler::EQ, L_resolved_found);
1285+
cmp(holder_klass, temp_itbl_klass);
1286+
br(Assembler::NE, L_loop_search_resolved);
1287+
mov(holder_offset, scan_temp);
1288+
b(L_loop_search_resolved);
1289+
1290+
// See if we already have a holder klass. If not, go and scan for it.
1291+
bind(L_resolved_found);
1292+
cbz(holder_offset, L_search_holder);
1293+
mov(scan_temp, holder_offset);
1294+
1295+
// Finally, scan_temp contains holder_klass vtable offset
1296+
bind(L_holder_found);
1297+
ldrw(method_result, Address(scan_temp, ooffset - ioffset));
1298+
add(recv_klass, recv_klass, itable_index * wordSize + in_bytes(itableMethodEntry::method_offset())
1299+
- vtable_start_offset - ioffset); // substract offsets to restore the original value of recv_klass
1300+
ldr(method_result, Address(recv_klass, method_result, Address::uxtw(0)));
1301+
}
1302+
11991303
// virtual method calling
12001304
void MacroAssembler::lookup_virtual_method(Register recv_klass,
12011305
RegisterOrConstant vtable_index,

‎src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp

+9
Original file line numberDiff line numberDiff line change
@@ -943,6 +943,15 @@ class MacroAssembler: public Assembler {
943943
Label& no_such_interface,
944944
bool return_method = true);
945945

946+
void lookup_interface_method_stub(Register recv_klass,
947+
Register holder_klass,
948+
Register resolved_klass,
949+
Register method_result,
950+
Register temp_reg,
951+
Register temp_reg2,
952+
int itable_index,
953+
Label& L_no_such_interface);
954+
946955
// virtual method calling
947956
// n.b. x86 allows RegisterOrConstant for vtable_index
948957
void lookup_virtual_method(Register recv_klass,

‎src/hotspot/cpu/aarch64/vtableStubs_aarch64.cpp

+4-19
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) {
175175
// so all registers except arguments are free at this point.
176176
const Register recv_klass_reg = r10;
177177
const Register holder_klass_reg = r16; // declaring interface klass (DECC)
178-
const Register resolved_klass_reg = rmethod; // resolved interface klass (REFC)
178+
const Register resolved_klass_reg = r17; // resolved interface klass (REFC)
179179
const Register temp_reg = r11;
180180
const Register temp_reg2 = r15;
181181
const Register icholder_reg = rscratch2;
@@ -192,28 +192,13 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) {
192192
__ load_klass(recv_klass_reg, j_rarg0);
193193

194194
// Receiver subtype check against REFC.
195-
__ lookup_interface_method(// inputs: rec. class, interface
196-
recv_klass_reg, resolved_klass_reg, noreg,
197-
// outputs: scan temp. reg1, scan temp. reg2
198-
temp_reg2, temp_reg,
199-
L_no_such_interface,
200-
/*return_method=*/false);
201-
202-
const ptrdiff_t typecheckSize = __ pc() - start_pc;
203-
start_pc = __ pc();
204-
205195
// Get selected method from declaring class and itable index
206-
__ lookup_interface_method(// inputs: rec. class, interface, itable index
207-
recv_klass_reg, holder_klass_reg, itable_index,
208-
// outputs: method, scan temp. reg
209-
rmethod, temp_reg,
210-
L_no_such_interface);
211-
212-
const ptrdiff_t lookupSize = __ pc() - start_pc;
196+
__ lookup_interface_method_stub(recv_klass_reg, holder_klass_reg, resolved_klass_reg, rmethod,
197+
temp_reg, temp_reg2, itable_index, L_no_such_interface);
213198

214199
// Reduce "estimate" such that "padding" does not drop below 8.
215200
const ptrdiff_t estimate = 124;
216-
const ptrdiff_t codesize = typecheckSize + lookupSize;
201+
const ptrdiff_t codesize = __ pc() - start_pc;
217202
slop_delta = (int)(estimate - codesize);
218203
slop_bytes += slop_delta;
219204
assert(slop_delta >= 0, "itable #%d: Code size estimate (%d) for lookup_interface_method too small, required: %d", itable_index, (int)estimate, (int)codesize);

0 commit comments

Comments
 (0)
Please sign in to comment.