Skip to content

Commit 6d79d5e

Browse files
committed
8253049: Enhance itable_stub for AArch64 and x86_64
1 parent 8777ded commit 6d79d5e

File tree

7 files changed

+311
-48
lines changed

7 files changed

+311
-48
lines changed

src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1035,6 +1035,88 @@ void MacroAssembler::lookup_interface_method(Register recv_klass,
10351035
}
10361036
}
10371037

1038+
void MacroAssembler::lookup_interface_method_in_stub(Register recv_klass,
1039+
Register resolved_klass,
1040+
Register holder_klass,
1041+
int itable_index,
1042+
Register method_result,
1043+
Register scan_temp,
1044+
Register count,
1045+
Label& L_no_such_interface
1046+
) {
1047+
assert_different_registers(recv_klass, resolved_klass, holder_klass);
1048+
assert_different_registers(method_result, scan_temp, count);
1049+
1050+
// Compute start of first itableOffsetEntry (which is at the end of the vtable)
1051+
int vtable_base = in_bytes(Klass::vtable_start_offset());
1052+
int itentry_off = itableMethodEntry::method_offset_in_bytes();
1053+
int scan_step = itableOffsetEntry::size() * wordSize;
1054+
int vte_size = vtableEntry::size_in_bytes();
1055+
assert(vte_size == wordSize, "else adjust times_vte_scale");
1056+
1057+
ldrw(scan_temp, Address(recv_klass, Klass::vtable_length_offset()));
1058+
1059+
// %%% Could store the aligned, prescaled offset in the klassoop.
1060+
lea(scan_temp, Address(recv_klass, scan_temp, Address::lsl(3)));
1061+
add(scan_temp, scan_temp, vtable_base);
1062+
mov(count, -2);
1063+
1064+
// Adjust recv_klass by scaled itable_index, so we can free itable_index.
1065+
assert(itableMethodEntry::size() * wordSize == wordSize, "adjust the scaling in the code below");
1066+
if (itable_index != 0) {
1067+
lea(recv_klass, Address(recv_klass, itable_index, Address::lsl(3)));
1068+
}
1069+
if (itentry_off) {
1070+
add(recv_klass, recv_klass, itentry_off);
1071+
}
1072+
1073+
Label L_fast_loop, L_slow_loop, L_slow_loop_tail, L_exit;
1074+
1075+
cmp(holder_klass, resolved_klass);
1076+
br(Assembler::NE, L_slow_loop);
1077+
1078+
// fast loop, check holder klass only
1079+
bind(L_fast_loop);
1080+
if (itableOffsetEntry::interface_offset_in_bytes() == 0 ) {
1081+
ldr(method_result, Address(post(scan_temp, scan_step)));
1082+
} else {
1083+
ldr(method_result, Address(scan_temp, itableOffsetEntry::interface_offset_in_bytes()));
1084+
add(scan_temp, scan_temp, scan_step);
1085+
}
1086+
cbz(method_result, L_no_such_interface);
1087+
// check holder_klass
1088+
cmp(holder_klass, method_result);
1089+
br(Assembler::NE, L_fast_loop);
1090+
// found, holder_klass can be free for other use
1091+
ldrw(holder_klass, Address(scan_temp, -scan_step + itableOffsetEntry::offset_offset_in_bytes()));
1092+
b(L_exit);
1093+
1094+
// slow loop, search both resolved_klass and holder_klass
1095+
bind(L_slow_loop);
1096+
if (itableOffsetEntry::interface_offset_in_bytes() == 0 ) {
1097+
ldr(method_result, Address(post(scan_temp, scan_step)));
1098+
} else {
1099+
ldr(method_result, Address(scan_temp, itableOffsetEntry::interface_offset_in_bytes()));
1100+
add(scan_temp, scan_temp, scan_step);
1101+
}
1102+
cbz(method_result, L_no_such_interface);
1103+
// check resolved_klass
1104+
cmp(resolved_klass, method_result);
1105+
csinc(count, count, count, Assembler::NE);
1106+
// check holder_klass
1107+
cmp(holder_klass, method_result);
1108+
br(Assembler::NE, L_slow_loop_tail);
1109+
increment(count);
1110+
// holder_klass can be free for other use
1111+
ldrw(holder_klass, Address(scan_temp, -scan_step + itableOffsetEntry::offset_offset_in_bytes()));
1112+
bind(L_slow_loop_tail);
1113+
cbnz(count, L_slow_loop);
1114+
1115+
// Got a hit.
1116+
bind(L_exit);
1117+
ldr(method_result, Address(recv_klass, holder_klass, Address::uxtw(0)));
1118+
}
1119+
10381120
// virtual method calling
10391121
void MacroAssembler::lookup_virtual_method(Register recv_klass,
10401122
RegisterOrConstant vtable_index,

src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -909,6 +909,16 @@ class MacroAssembler: public Assembler {
909909
Label& no_such_interface,
910910
bool return_method = true);
911911

912+
// for itable_stub
913+
void lookup_interface_method_in_stub(Register recv_klass,
914+
Register resolved_klass,
915+
Register holder_klass,
916+
int itable_index,
917+
Register method_result,
918+
Register scan_temp,
919+
Register count,
920+
Label& no_such_interface);
921+
912922
// virtual method calling
913923
// n.b. x86 allows RegisterOrConstant for vtable_index
914924
void lookup_virtual_method(Register recv_klass,

src/hotspot/cpu/aarch64/vtableStubs_aarch64.cpp

Lines changed: 7 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -174,9 +174,9 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) {
174174
// so all registers except arguments are free at this point.
175175
const Register recv_klass_reg = r10;
176176
const Register holder_klass_reg = r16; // declaring interface klass (DECC)
177-
const Register resolved_klass_reg = rmethod; // resolved interface klass (REFC)
177+
const Register resolved_klass_reg = r13; // resolved interface klass (REFC)
178178
const Register temp_reg = r11;
179-
const Register temp_reg2 = r15;
179+
const Register count_reg = r15;
180180
const Register icholder_reg = rscratch2;
181181

182182
Label L_no_such_interface;
@@ -190,29 +190,14 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) {
190190
address npe_addr = __ pc();
191191
__ load_klass(recv_klass_reg, j_rarg0);
192192

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

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

src/hotspot/cpu/x86/macroAssembler_x86.cpp

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3454,6 +3454,73 @@ void MacroAssembler::lookup_interface_method(Register recv_klass,
34543454
}
34553455
}
34563456

3457+
void MacroAssembler::lookup_interface_method_in_stub(Register recv_klass,
3458+
Register holder_klass,
3459+
Register resolved_klass,
3460+
int itable_index,
3461+
Register method_result,
3462+
Register scan_temp,
3463+
Register count,
3464+
Label& L_no_such_interface) {
3465+
assert_different_registers(recv_klass, holder_klass, resolved_klass);
3466+
assert_different_registers(method_result, scan_temp, count);
3467+
3468+
// Compute start of first itableOffsetEntry (which is at the end of the vtable)
3469+
int vtable_base = in_bytes(Klass::vtable_start_offset());
3470+
int itentry_off = itableMethodEntry::method_offset_in_bytes();
3471+
int scan_step = itableOffsetEntry::size() * wordSize;
3472+
int vte_size = vtableEntry::size_in_bytes();
3473+
Address::ScaleFactor times_vte_scale = Address::times_ptr;
3474+
Label L_fast_loop, L_slow_loop, L_next_check, L_slow_loop_tail, L_exit;
3475+
3476+
assert(vte_size == wordSize, "else adjust times_vte_scale");
3477+
3478+
movl(scan_temp, Address(recv_klass, Klass::vtable_length_offset()));
3479+
lea(scan_temp, Address(recv_klass, scan_temp, times_vte_scale, vtable_base));
3480+
3481+
assert(itableMethodEntry::size() * wordSize == wordSize, "adjust the scaling in the code below");
3482+
lea(recv_klass, Address(recv_klass, itable_index, Address::times_ptr, itentry_off));
3483+
movl(count, 2);
3484+
3485+
cmpptr(holder_klass, resolved_klass);
3486+
jcc(Assembler::notEqual, L_slow_loop);
3487+
3488+
// fast loop, check holder_klass only
3489+
bind(L_fast_loop);
3490+
movptr(method_result, Address(scan_temp, itableOffsetEntry::interface_offset_in_bytes()));
3491+
testptr(method_result, method_result);
3492+
jcc(Assembler::zero, L_no_such_interface);
3493+
addptr(scan_temp, scan_step);
3494+
cmpptr(holder_klass, method_result);
3495+
jccb(Assembler::notEqual, L_fast_loop);
3496+
movptr(holder_klass, Address(scan_temp, -scan_step + itableOffsetEntry::offset_offset_in_bytes()));
3497+
jmp(L_exit);
3498+
3499+
// slow loop, search both resolved_klass and holder_klass
3500+
bind(L_slow_loop);
3501+
movptr(method_result, Address(scan_temp, itableOffsetEntry::interface_offset_in_bytes()));
3502+
testptr(method_result, method_result);
3503+
jcc(Assembler::zero, L_no_such_interface);
3504+
3505+
cmpptr(holder_klass, method_result);
3506+
jccb(Assembler::notEqual, L_next_check);
3507+
movptr(holder_klass, Address(scan_temp, itableOffsetEntry::offset_offset_in_bytes()));
3508+
decrement(count);
3509+
3510+
bind(L_next_check);
3511+
cmpptr(resolved_klass, method_result);
3512+
jccb(Assembler::notEqual, L_slow_loop_tail);
3513+
decrement(count);
3514+
3515+
bind(L_slow_loop_tail);
3516+
addptr(scan_temp, scan_step);
3517+
testl(count, count);
3518+
jcc(Assembler::notZero, L_slow_loop);
3519+
3520+
// Got a hit.
3521+
bind(L_exit);
3522+
movptr(method_result, Address(recv_klass, holder_klass, Address::times_1));
3523+
}
34573524

34583525
// virtual method calling
34593526
void MacroAssembler::lookup_virtual_method(Register recv_klass,

src/hotspot/cpu/x86/macroAssembler_x86.hpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -536,6 +536,16 @@ class MacroAssembler: public Assembler {
536536
Label& no_such_interface,
537537
bool return_method = true);
538538

539+
// for itable_stub
540+
void lookup_interface_method_in_stub(Register recv_klass,
541+
Register holder_klass,
542+
Register resolved_klass,
543+
int itable_index,
544+
Register method_result,
545+
Register scan_temp,
546+
Register count,
547+
Label& no_such_interface);
548+
539549
// virtual method calling
540550
void lookup_virtual_method(Register recv_klass,
541551
RegisterOrConstant vtable_index,

src/hotspot/cpu/x86/vtableStubs_x86_64.cpp

Lines changed: 8 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -175,10 +175,13 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) {
175175
// (various calling sequences use r[cd]x, r[sd]i, r[89]; stay away from them)
176176
const Register recv_klass_reg = r10;
177177
const Register holder_klass_reg = rax; // declaring interface klass (DECC)
178-
const Register resolved_klass_reg = rbx; // resolved interface klass (REFC)
178+
const Register resolved_klass_reg = r14; // resolved interface klass (REFC)
179179
const Register temp_reg = r11;
180180

181181
const Register icholder_reg = rax;
182+
const Register method = rbx;
183+
const Register count_reg = r13;
184+
182185
__ movptr(resolved_klass_reg, Address(icholder_reg, CompiledICHolder::holder_klass_offset()));
183186
__ movptr(holder_klass_reg, Address(icholder_reg, CompiledICHolder::holder_metadata_offset()));
184187

@@ -190,35 +193,15 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) {
190193
__ load_klass(recv_klass_reg, j_rarg0, temp_reg);
191194

192195
start_pc = __ pc();
193-
194-
// Receiver subtype check against REFC.
195-
// Destroys recv_klass_reg value.
196-
__ lookup_interface_method(// inputs: rec. class, interface
197-
recv_klass_reg, resolved_klass_reg, noreg,
198-
// outputs: scan temp. reg1, scan temp. reg2
199-
recv_klass_reg, temp_reg,
200-
L_no_such_interface,
201-
/*return_method=*/false);
202-
203-
const ptrdiff_t typecheckSize = __ pc() - start_pc;
204-
start_pc = __ pc();
205-
206-
// Get selected method from declaring class and itable index
207-
const Register method = rbx;
208-
__ load_klass(recv_klass_reg, j_rarg0, temp_reg); // restore recv_klass_reg
209-
__ lookup_interface_method(// inputs: rec. class, interface, itable index
210-
recv_klass_reg, holder_klass_reg, itable_index,
211-
// outputs: method, scan temp. reg
212-
method, temp_reg,
213-
L_no_such_interface);
214-
215-
const ptrdiff_t lookupSize = __ pc() - start_pc;
196+
__ lookup_interface_method_in_stub(recv_klass_reg, holder_klass_reg, resolved_klass_reg, itable_index,
197+
method, temp_reg, count_reg,
198+
L_no_such_interface);
216199

217200
// We expect we need index_dependent_slop extra bytes. Reason:
218201
// The emitted code in lookup_interface_method changes when itable_index exceeds 15.
219202
// For linux, a very narrow estimate would be 112, but Solaris requires some more space (130).
220203
const ptrdiff_t estimate = 136;
221-
const ptrdiff_t codesize = typecheckSize + lookupSize + index_dependent_slop;
204+
const ptrdiff_t codesize = __ pc() - start_pc + index_dependent_slop;
222205
slop_delta = (int)(estimate - codesize);
223206
slop_bytes += slop_delta;
224207
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)