Skip to content

Commit a5765a9

Browse files
author
Anjian Wen
committed
8377225: RISC-V: Improve receiver type profiling reliability
Reviewed-by: shade, fjiang, fyang
1 parent d10ddb8 commit a5765a9

File tree

7 files changed

+176
-227
lines changed

7 files changed

+176
-227
lines changed

src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp

Lines changed: 10 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1041,31 +1041,10 @@ void LIR_Assembler::emit_alloc_array(LIR_OpAllocArray* op) {
10411041
__ bind(*op->stub()->continuation());
10421042
}
10431043

1044-
void LIR_Assembler::type_profile_helper(Register mdo, ciMethodData *md, ciProfileData *data,
1045-
Register recv, Label* update_done) {
1046-
for (uint i = 0; i < ReceiverTypeData::row_limit(); i++) {
1047-
Label next_test;
1048-
// See if the receiver is receiver[n].
1049-
__ ld(t1, Address(mdo, md->byte_offset_of_slot(data, ReceiverTypeData::receiver_offset(i))));
1050-
__ bne(recv, t1, next_test);
1051-
Address data_addr(mdo, md->byte_offset_of_slot(data, ReceiverTypeData::receiver_count_offset(i)));
1052-
__ increment(data_addr, DataLayout::counter_increment);
1053-
__ j(*update_done);
1054-
__ bind(next_test);
1055-
}
1056-
1057-
// Didn't find receiver; find next empty slot and fill it in
1058-
for (uint i = 0; i < ReceiverTypeData::row_limit(); i++) {
1059-
Label next_test;
1060-
Address recv_addr(mdo, md->byte_offset_of_slot(data, ReceiverTypeData::receiver_offset(i)));
1061-
__ ld(t1, recv_addr);
1062-
__ bnez(t1, next_test);
1063-
__ sd(recv, recv_addr);
1064-
__ mv(t1, DataLayout::counter_increment);
1065-
__ sd(t1, Address(mdo, md->byte_offset_of_slot(data, ReceiverTypeData::receiver_count_offset(i))));
1066-
__ j(*update_done);
1067-
__ bind(next_test);
1068-
}
1044+
void LIR_Assembler::type_profile_helper(Register mdo, ciMethodData *md,
1045+
ciProfileData *data, Register recv) {
1046+
int mdp_offset = md->byte_offset_of_slot(data, in_ByteSize(0));
1047+
__ profile_receiver_type(recv, mdo, mdp_offset);
10691048
}
10701049

10711050
void LIR_Assembler::data_check(LIR_OpTypeCheck *op, ciMethodData **md, ciProfileData **data) {
@@ -1139,14 +1118,9 @@ void LIR_Assembler::profile_object(ciMethodData* md, ciProfileData* data, Regist
11391118
__ j(*obj_is_null);
11401119
__ bind(not_null);
11411120

1142-
Label update_done;
11431121
Register recv = k_RInfo;
11441122
__ load_klass(recv, obj);
1145-
type_profile_helper(mdo, md, data, recv, &update_done);
1146-
Address counter_addr(mdo, md->byte_offset_of_slot(data, CounterData::count_offset()));
1147-
__ increment(counter_addr, DataLayout::counter_increment);
1148-
1149-
__ bind(update_done);
1123+
type_profile_helper(mdo, md, data, recv);
11501124
}
11511125

11521126
void LIR_Assembler::typecheck_loaded(LIR_OpTypeCheck *op, ciKlass* k, Register k_RInfo) {
@@ -1554,44 +1528,22 @@ void LIR_Assembler::emit_profile_call(LIR_OpProfileCall* op) {
15541528
// We know the type that will be seen at this call site; we can
15551529
// statically update the MethodData* rather than needing to do
15561530
// dynamic tests on the receiver type
1557-
// NOTE: we should probably put a lock around this search to
1558-
// avoid collisions by concurrent compilations
15591531
ciVirtualCallData* vc_data = (ciVirtualCallData*) data;
1560-
uint i;
1561-
for (i = 0; i < VirtualCallData::row_limit(); i++) {
1532+
for (uint i = 0; i < VirtualCallData::row_limit(); i++) {
15621533
ciKlass* receiver = vc_data->receiver(i);
15631534
if (known_klass->equals(receiver)) {
15641535
Address data_addr(mdo, md->byte_offset_of_slot(data, VirtualCallData::receiver_count_offset(i)));
15651536
__ increment(data_addr, DataLayout::counter_increment);
15661537
return;
15671538
}
15681539
}
1569-
1570-
// Receiver type not found in profile data; select an empty slot
1571-
// Note that this is less efficient than it should be because it
1572-
// always does a write to the receiver part of the
1573-
// VirtualCallData rather than just the first time
1574-
for (i = 0; i < VirtualCallData::row_limit(); i++) {
1575-
ciKlass* receiver = vc_data->receiver(i);
1576-
if (receiver == nullptr) {
1577-
Address recv_addr(mdo, md->byte_offset_of_slot(data, VirtualCallData::receiver_offset(i)));
1578-
__ mov_metadata(t1, known_klass->constant_encoding());
1579-
__ sd(t1, recv_addr);
1580-
Address data_addr(mdo, md->byte_offset_of_slot(data, VirtualCallData::receiver_count_offset(i)));
1581-
__ increment(data_addr, DataLayout::counter_increment);
1582-
return;
1583-
}
1584-
}
1540+
// Receiver type is not found in profile data.
1541+
// Fall back to runtime helper to handle the rest at runtime.
1542+
__ mov_metadata(recv, known_klass->constant_encoding());
15851543
} else {
15861544
__ load_klass(recv, recv);
1587-
Label update_done;
1588-
type_profile_helper(mdo, md, data, recv, &update_done);
1589-
// Receiver did not match any saved receiver and there is no empty row for it.
1590-
// Increment total counter to indicate polymorphic case.
1591-
__ increment(counter_addr, DataLayout::counter_increment);
1592-
1593-
__ bind(update_done);
15941545
}
1546+
type_profile_helper(mdo, md, data, recv);
15951547
} else {
15961548
// Static call
15971549
__ increment(counter_addr, DataLayout::counter_increment);

src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.hpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,8 @@ friend class ArrayCopyStub;
5454
Address stack_slot_address(int index, uint shift, int adjust = 0);
5555

5656
// Record the type of the receiver in ReceiverTypeData
57-
void type_profile_helper(Register mdo,
58-
ciMethodData *md, ciProfileData *data,
59-
Register recv, Label* update_done);
57+
void type_profile_helper(Register mdo, ciMethodData *md,
58+
ciProfileData *data, Register recv);
6059

6160
void casw(Register addr, Register newval, Register cmpval);
6261
void caswu(Register addr, Register newval, Register cmpval);

src/hotspot/cpu/riscv/interp_masm_riscv.cpp

Lines changed: 5 additions & 154 deletions
Original file line numberDiff line numberDiff line change
@@ -237,15 +237,14 @@ void InterpreterMacroAssembler::load_resolved_klass_at_offset(
237237
// Rsub_klass: subklass
238238
//
239239
// Kills:
240-
// x12, x15
240+
// x12
241241
void InterpreterMacroAssembler::gen_subtype_check(Register Rsub_klass,
242242
Label& ok_is_subtype) {
243243
assert(Rsub_klass != x10, "x10 holds superklass");
244244
assert(Rsub_klass != x12, "x12 holds 2ndary super array length");
245-
assert(Rsub_klass != x15, "x15 holds 2ndary super array scan ptr");
246245

247246
// Profile the not-null value's klass.
248-
profile_typecheck(x12, Rsub_klass, x15); // blows x12, reloads x15
247+
profile_typecheck(x12, Rsub_klass); // blows x12
249248

250249
// Do the check.
251250
check_klass_subtype(Rsub_klass, x10, x12, ok_is_subtype); // blows x12
@@ -1042,7 +1041,6 @@ void InterpreterMacroAssembler::profile_final_call(Register mdp) {
10421041

10431042
void InterpreterMacroAssembler::profile_virtual_call(Register receiver,
10441043
Register mdp,
1045-
Register reg2,
10461044
bool receiver_can_be_null) {
10471045
if (ProfileInterpreter) {
10481046
Label profile_continue;
@@ -1060,7 +1058,7 @@ void InterpreterMacroAssembler::profile_virtual_call(Register receiver,
10601058
}
10611059

10621060
// Record the receiver type.
1063-
record_klass_in_profile(receiver, mdp, reg2);
1061+
profile_receiver_type(receiver, mdp, 0);
10641062
bind(skip_receiver_profile);
10651063

10661064
// The method data pointer needs to be updated to reflect the new target.
@@ -1072,153 +1070,6 @@ void InterpreterMacroAssembler::profile_virtual_call(Register receiver,
10721070
}
10731071
}
10741072

1075-
// This routine creates a state machine for updating the multi-row
1076-
// type profile at a virtual call site (or other type-sensitive bytecode).
1077-
// The machine visits each row (of receiver/count) until the receiver type
1078-
// is found, or until it runs out of rows. At the same time, it remembers
1079-
// the location of the first empty row. (An empty row records null for its
1080-
// receiver, and can be allocated for a newly-observed receiver type.)
1081-
// Because there are two degrees of freedom in the state, a simple linear
1082-
// search will not work; it must be a decision tree. Hence this helper
1083-
// function is recursive, to generate the required tree structured code.
1084-
// It's the interpreter, so we are trading off code space for speed.
1085-
// See below for example code.
1086-
void InterpreterMacroAssembler::record_klass_in_profile_helper(
1087-
Register receiver, Register mdp,
1088-
Register reg2, Label& done) {
1089-
if (TypeProfileWidth == 0) {
1090-
increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset()));
1091-
} else {
1092-
record_item_in_profile_helper(receiver, mdp, reg2, 0, done, TypeProfileWidth,
1093-
&VirtualCallData::receiver_offset, &VirtualCallData::receiver_count_offset);
1094-
}
1095-
}
1096-
1097-
void InterpreterMacroAssembler::record_item_in_profile_helper(Register item, Register mdp,
1098-
Register reg2, int start_row, Label& done, int total_rows,
1099-
OffsetFunction item_offset_fn, OffsetFunction item_count_offset_fn) {
1100-
int last_row = total_rows - 1;
1101-
assert(start_row <= last_row, "must be work left to do");
1102-
// Test this row for both the item and for null.
1103-
// Take any of three different outcomes:
1104-
// 1. found item => increment count and goto done
1105-
// 2. found null => keep looking for case 1, maybe allocate this cell
1106-
// 3. found something else => keep looking for cases 1 and 2
1107-
// Case 3 is handled by a recursive call.
1108-
for (int row = start_row; row <= last_row; row++) {
1109-
Label next_test;
1110-
bool test_for_null_also = (row == start_row);
1111-
1112-
// See if the item is item[n].
1113-
int item_offset = in_bytes(item_offset_fn(row));
1114-
test_mdp_data_at(mdp, item_offset, item,
1115-
(test_for_null_also ? reg2 : noreg),
1116-
next_test);
1117-
// (Reg2 now contains the item from the CallData.)
1118-
1119-
// The item is item[n]. Increment count[n].
1120-
int count_offset = in_bytes(item_count_offset_fn(row));
1121-
increment_mdp_data_at(mdp, count_offset);
1122-
j(done);
1123-
bind(next_test);
1124-
1125-
if (test_for_null_also) {
1126-
Label found_null;
1127-
// Failed the equality check on item[n]... Test for null.
1128-
if (start_row == last_row) {
1129-
// The only thing left to do is handle the null case.
1130-
beqz(reg2, found_null);
1131-
// Item did not match any saved item and there is no empty row for it.
1132-
// Increment total counter to indicate polymorphic case.
1133-
increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset()));
1134-
j(done);
1135-
bind(found_null);
1136-
break;
1137-
}
1138-
// Since null is rare, make it be the branch-taken case.
1139-
beqz(reg2, found_null);
1140-
1141-
// Put all the "Case 3" tests here.
1142-
record_item_in_profile_helper(item, mdp, reg2, start_row + 1, done, total_rows,
1143-
item_offset_fn, item_count_offset_fn);
1144-
1145-
// Found a null. Keep searching for a matching item,
1146-
// but remember that this is an empty (unused) slot.
1147-
bind(found_null);
1148-
}
1149-
}
1150-
1151-
// In the fall-through case, we found no matching item, but we
1152-
// observed the item[start_row] is null.
1153-
// Fill in the item field and increment the count.
1154-
int item_offset = in_bytes(item_offset_fn(start_row));
1155-
set_mdp_data_at(mdp, item_offset, item);
1156-
int count_offset = in_bytes(item_count_offset_fn(start_row));
1157-
mv(reg2, DataLayout::counter_increment);
1158-
set_mdp_data_at(mdp, count_offset, reg2);
1159-
if (start_row > 0) {
1160-
j(done);
1161-
}
1162-
}
1163-
1164-
// Example state machine code for three profile rows:
1165-
// # main copy of decision tree, rooted at row[1]
1166-
// if (row[0].rec == rec) then [
1167-
// row[0].incr()
1168-
// goto done
1169-
// ]
1170-
// if (row[0].rec != nullptr) then [
1171-
// # inner copy of decision tree, rooted at row[1]
1172-
// if (row[1].rec == rec) then [
1173-
// row[1].incr()
1174-
// goto done
1175-
// ]
1176-
// if (row[1].rec != nullptr) then [
1177-
// # degenerate decision tree, rooted at row[2]
1178-
// if (row[2].rec == rec) then [
1179-
// row[2].incr()
1180-
// goto done
1181-
// ]
1182-
// if (row[2].rec != nullptr) then [
1183-
// count.incr()
1184-
// goto done
1185-
// ] # overflow
1186-
// row[2].init(rec)
1187-
// goto done
1188-
// ] else [
1189-
// # remember row[1] is empty
1190-
// if (row[2].rec == rec) then [
1191-
// row[2].incr()
1192-
// goto done
1193-
// ]
1194-
// row[1].init(rec)
1195-
// goto done
1196-
// ]
1197-
// else [
1198-
// # remember row[0] is empty
1199-
// if (row[1].rec == rec) then [
1200-
// row[1].incr()
1201-
// goto done
1202-
// ]
1203-
// if (row[2].rec == rec) then [
1204-
// row[2].incr()
1205-
// goto done
1206-
// ]
1207-
// row[0].init(rec)
1208-
// goto done
1209-
// ]
1210-
// done:
1211-
1212-
void InterpreterMacroAssembler::record_klass_in_profile(Register receiver,
1213-
Register mdp, Register reg2) {
1214-
assert(ProfileInterpreter, "must be profiling");
1215-
Label done;
1216-
1217-
record_klass_in_profile_helper(receiver, mdp, reg2, done);
1218-
1219-
bind(done);
1220-
}
1221-
12221073
void InterpreterMacroAssembler::profile_ret(Register return_bci, Register mdp) {
12231074
if (ProfileInterpreter) {
12241075
Label profile_continue;
@@ -1274,7 +1125,7 @@ void InterpreterMacroAssembler::profile_null_seen(Register mdp) {
12741125
}
12751126
}
12761127

1277-
void InterpreterMacroAssembler::profile_typecheck(Register mdp, Register klass, Register reg2) {
1128+
void InterpreterMacroAssembler::profile_typecheck(Register mdp, Register klass) {
12781129
if (ProfileInterpreter) {
12791130
Label profile_continue;
12801131

@@ -1287,7 +1138,7 @@ void InterpreterMacroAssembler::profile_typecheck(Register mdp, Register klass,
12871138
mdp_delta = in_bytes(VirtualCallData::virtual_call_data_size());
12881139

12891140
// Record the object type.
1290-
record_klass_in_profile(klass, mdp, reg2);
1141+
profile_receiver_type(klass, mdp, 0);
12911142
}
12921143
update_mdp_by_constant(mdp, mdp_delta);
12931144

src/hotspot/cpu/riscv/interp_masm_riscv.hpp

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -262,14 +262,6 @@ class InterpreterMacroAssembler: public MacroAssembler {
262262
Register test_value_out,
263263
Label& not_equal_continue);
264264

265-
void record_klass_in_profile(Register receiver, Register mdp,
266-
Register reg2);
267-
void record_klass_in_profile_helper(Register receiver, Register mdp,
268-
Register reg2, Label& done);
269-
void record_item_in_profile_helper(Register item, Register mdp,
270-
Register reg2, int start_row, Label& done, int total_rows,
271-
OffsetFunction item_offset_fn, OffsetFunction item_count_offset_fn);
272-
273265
void update_mdp_by_offset(Register mdp_in, int offset_of_offset);
274266
void update_mdp_by_offset(Register mdp_in, Register reg, int offset_of_disp);
275267
void update_mdp_by_constant(Register mdp_in, int constant);
@@ -283,11 +275,10 @@ class InterpreterMacroAssembler: public MacroAssembler {
283275
void profile_call(Register mdp);
284276
void profile_final_call(Register mdp);
285277
void profile_virtual_call(Register receiver, Register mdp,
286-
Register t1,
287278
bool receiver_can_be_null = false);
288279
void profile_ret(Register return_bci, Register mdp);
289280
void profile_null_seen(Register mdp);
290-
void profile_typecheck(Register mdp, Register klass, Register temp);
281+
void profile_typecheck(Register mdp, Register klass);
291282
void profile_typecheck_failed(Register mdp);
292283
void profile_switch_default(Register mdp);
293284
void profile_switch_case(Register index_in_scratch, Register mdp,

0 commit comments

Comments
 (0)