Skip to content

Commit e676c9d

Browse files
committed
8357258: x86: Improve receiver type profiling reliability
Reviewed-by: kvn, vlivanov
1 parent 1630382 commit e676c9d

File tree

8 files changed

+221
-216
lines changed

8 files changed

+221
-216
lines changed

src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp

Lines changed: 11 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1261,29 +1261,9 @@ void LIR_Assembler::emit_alloc_array(LIR_OpAllocArray* op) {
12611261

12621262
void LIR_Assembler::type_profile_helper(Register mdo,
12631263
ciMethodData *md, ciProfileData *data,
1264-
Register recv, Label* update_done) {
1265-
for (uint i = 0; i < ReceiverTypeData::row_limit(); i++) {
1266-
Label next_test;
1267-
// See if the receiver is receiver[n].
1268-
__ cmpptr(recv, Address(mdo, md->byte_offset_of_slot(data, ReceiverTypeData::receiver_offset(i))));
1269-
__ jccb(Assembler::notEqual, next_test);
1270-
Address data_addr(mdo, md->byte_offset_of_slot(data, ReceiverTypeData::receiver_count_offset(i)));
1271-
__ addptr(data_addr, DataLayout::counter_increment);
1272-
__ jmp(*update_done);
1273-
__ bind(next_test);
1274-
}
1275-
1276-
// Didn't find receiver; find next empty slot and fill it in
1277-
for (uint i = 0; i < ReceiverTypeData::row_limit(); i++) {
1278-
Label next_test;
1279-
Address recv_addr(mdo, md->byte_offset_of_slot(data, ReceiverTypeData::receiver_offset(i)));
1280-
__ cmpptr(recv_addr, NULL_WORD);
1281-
__ jccb(Assembler::notEqual, next_test);
1282-
__ movptr(recv_addr, recv);
1283-
__ movptr(Address(mdo, md->byte_offset_of_slot(data, ReceiverTypeData::receiver_count_offset(i))), DataLayout::counter_increment);
1284-
__ jmp(*update_done);
1285-
__ bind(next_test);
1286-
}
1264+
Register recv) {
1265+
int mdp_offset = md->byte_offset_of_slot(data, in_ByteSize(0));
1266+
__ profile_receiver_type(recv, mdo, mdp_offset);
12871267
}
12881268

12891269
void LIR_Assembler::emit_typecheck_helper(LIR_OpTypeCheck *op, Label* success, Label* failure, Label* obj_is_null) {
@@ -1341,15 +1321,9 @@ void LIR_Assembler::emit_typecheck_helper(LIR_OpTypeCheck *op, Label* success, L
13411321
__ jmp(*obj_is_null);
13421322
__ bind(not_null);
13431323

1344-
Label update_done;
13451324
Register recv = k_RInfo;
13461325
__ load_klass(recv, obj, tmp_load_klass);
1347-
type_profile_helper(mdo, md, data, recv, &update_done);
1348-
1349-
Address nonprofiled_receiver_count_addr(mdo, md->byte_offset_of_slot(data, CounterData::count_offset()));
1350-
__ addptr(nonprofiled_receiver_count_addr, DataLayout::counter_increment);
1351-
1352-
__ bind(update_done);
1326+
type_profile_helper(mdo, md, data, recv);
13531327
} else {
13541328
__ jcc(Assembler::equal, *obj_is_null);
13551329
}
@@ -1461,14 +1435,9 @@ void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) {
14611435
__ jmp(done);
14621436
__ bind(not_null);
14631437

1464-
Label update_done;
14651438
Register recv = k_RInfo;
14661439
__ load_klass(recv, value, tmp_load_klass);
1467-
type_profile_helper(mdo, md, data, recv, &update_done);
1468-
1469-
Address counter_addr(mdo, md->byte_offset_of_slot(data, CounterData::count_offset()));
1470-
__ addptr(counter_addr, DataLayout::counter_increment);
1471-
__ bind(update_done);
1440+
type_profile_helper(mdo, md, data, recv);
14721441
} else {
14731442
__ jcc(Assembler::equal, done);
14741443
}
@@ -2791,46 +2760,23 @@ void LIR_Assembler::emit_profile_call(LIR_OpProfileCall* op) {
27912760
if (C1OptimizeVirtualCallProfiling && known_klass != nullptr) {
27922761
// We know the type that will be seen at this call site; we can
27932762
// statically update the MethodData* rather than needing to do
2794-
// dynamic tests on the receiver type
2795-
2796-
// NOTE: we should probably put a lock around this search to
2797-
// avoid collisions by concurrent compilations
2763+
// dynamic tests on the receiver type.
27982764
ciVirtualCallData* vc_data = (ciVirtualCallData*) data;
2799-
uint i;
2800-
for (i = 0; i < VirtualCallData::row_limit(); i++) {
2765+
for (uint i = 0; i < VirtualCallData::row_limit(); i++) {
28012766
ciKlass* receiver = vc_data->receiver(i);
28022767
if (known_klass->equals(receiver)) {
28032768
Address data_addr(mdo, md->byte_offset_of_slot(data, VirtualCallData::receiver_count_offset(i)));
28042769
__ addptr(data_addr, DataLayout::counter_increment);
28052770
return;
28062771
}
28072772
}
2808-
2809-
// Receiver type not found in profile data; select an empty slot
2810-
2811-
// Note that this is less efficient than it should be because it
2812-
// always does a write to the receiver part of the
2813-
// VirtualCallData rather than just the first time
2814-
for (i = 0; i < VirtualCallData::row_limit(); i++) {
2815-
ciKlass* receiver = vc_data->receiver(i);
2816-
if (receiver == nullptr) {
2817-
Address recv_addr(mdo, md->byte_offset_of_slot(data, VirtualCallData::receiver_offset(i)));
2818-
__ mov_metadata(recv_addr, known_klass->constant_encoding(), rscratch1);
2819-
Address data_addr(mdo, md->byte_offset_of_slot(data, VirtualCallData::receiver_count_offset(i)));
2820-
__ addptr(data_addr, DataLayout::counter_increment);
2821-
return;
2822-
}
2823-
}
2773+
// Receiver type is not found in profile data.
2774+
// Fall back to runtime helper to handle the rest at runtime.
2775+
__ mov_metadata(recv, known_klass->constant_encoding());
28242776
} else {
28252777
__ load_klass(recv, recv, tmp_load_klass);
2826-
Label update_done;
2827-
type_profile_helper(mdo, md, data, recv, &update_done);
2828-
// Receiver did not match any saved receiver and there is no empty row for it.
2829-
// Increment total counter to indicate polymorphic case.
2830-
__ addptr(counter_addr, DataLayout::counter_increment);
2831-
2832-
__ bind(update_done);
28332778
}
2779+
type_profile_helper(mdo, md, data, recv);
28342780
} else {
28352781
// Static call
28362782
__ addptr(counter_addr, DataLayout::counter_increment);

src/hotspot/cpu/x86/c1_LIRAssembler_x86.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
// Record the type of the receiver in ReceiverTypeData
4444
void type_profile_helper(Register mdo,
4545
ciMethodData *md, ciProfileData *data,
46-
Register recv, Label* update_done);
46+
Register recv);
4747

4848
enum {
4949
_call_stub_size = 28,

src/hotspot/cpu/x86/interp_masm_x86.cpp

Lines changed: 5 additions & 136 deletions
Original file line numberDiff line numberDiff line change
@@ -580,17 +580,16 @@ void InterpreterMacroAssembler::load_resolved_klass_at_index(Register klass,
580580
// Rsub_klass: subklass
581581
//
582582
// Kills:
583-
// rcx, rdi
583+
// rcx
584584
void InterpreterMacroAssembler::gen_subtype_check(Register Rsub_klass,
585585
Label& ok_is_subtype) {
586586
assert(Rsub_klass != rax, "rax holds superklass");
587587
assert(Rsub_klass != r14, "r14 holds locals");
588588
assert(Rsub_klass != r13, "r13 holds bcp");
589589
assert(Rsub_klass != rcx, "rcx holds 2ndary super array length");
590-
assert(Rsub_klass != rdi, "rdi holds 2ndary super array scan ptr");
591590

592591
// Profile the not-null value's klass.
593-
profile_typecheck(rcx, Rsub_klass, rdi); // blows rcx, reloads rdi
592+
profile_typecheck(rcx, Rsub_klass); // blows rcx
594593

595594
// Do the check.
596595
check_klass_subtype(Rsub_klass, rax, rcx, ok_is_subtype); // blows rcx
@@ -1394,7 +1393,6 @@ void InterpreterMacroAssembler::profile_final_call(Register mdp) {
13941393

13951394
void InterpreterMacroAssembler::profile_virtual_call(Register receiver,
13961395
Register mdp,
1397-
Register reg2,
13981396
bool receiver_can_be_null) {
13991397
if (ProfileInterpreter) {
14001398
Label profile_continue;
@@ -1414,7 +1412,7 @@ void InterpreterMacroAssembler::profile_virtual_call(Register receiver,
14141412
}
14151413

14161414
// Record the receiver type.
1417-
record_klass_in_profile(receiver, mdp, reg2, true);
1415+
profile_receiver_type(receiver, mdp, 0);
14181416
bind(skip_receiver_profile);
14191417

14201418
// The method data pointer needs to be updated to reflect the new target.
@@ -1423,135 +1421,6 @@ void InterpreterMacroAssembler::profile_virtual_call(Register receiver,
14231421
}
14241422
}
14251423

1426-
// This routine creates a state machine for updating the multi-row
1427-
// type profile at a virtual call site (or other type-sensitive bytecode).
1428-
// The machine visits each row (of receiver/count) until the receiver type
1429-
// is found, or until it runs out of rows. At the same time, it remembers
1430-
// the location of the first empty row. (An empty row records null for its
1431-
// receiver, and can be allocated for a newly-observed receiver type.)
1432-
// Because there are two degrees of freedom in the state, a simple linear
1433-
// search will not work; it must be a decision tree. Hence this helper
1434-
// function is recursive, to generate the required tree structured code.
1435-
// It's the interpreter, so we are trading off code space for speed.
1436-
// See below for example code.
1437-
void InterpreterMacroAssembler::record_klass_in_profile_helper(
1438-
Register receiver, Register mdp,
1439-
Register reg2, int start_row,
1440-
Label& done, bool is_virtual_call) {
1441-
if (TypeProfileWidth == 0) {
1442-
increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset()));
1443-
} else {
1444-
record_item_in_profile_helper(receiver, mdp, reg2, 0, done, TypeProfileWidth,
1445-
&VirtualCallData::receiver_offset, &VirtualCallData::receiver_count_offset);
1446-
}
1447-
}
1448-
1449-
void InterpreterMacroAssembler::record_item_in_profile_helper(Register item, Register mdp, Register reg2, int start_row,
1450-
Label& done, int total_rows,
1451-
OffsetFunction item_offset_fn,
1452-
OffsetFunction item_count_offset_fn) {
1453-
int last_row = total_rows - 1;
1454-
assert(start_row <= last_row, "must be work left to do");
1455-
// Test this row for both the item and for null.
1456-
// Take any of three different outcomes:
1457-
// 1. found item => increment count and goto done
1458-
// 2. found null => keep looking for case 1, maybe allocate this cell
1459-
// 3. found something else => keep looking for cases 1 and 2
1460-
// Case 3 is handled by a recursive call.
1461-
for (int row = start_row; row <= last_row; row++) {
1462-
Label next_test;
1463-
bool test_for_null_also = (row == start_row);
1464-
1465-
// See if the item is item[n].
1466-
int item_offset = in_bytes(item_offset_fn(row));
1467-
test_mdp_data_at(mdp, item_offset, item,
1468-
(test_for_null_also ? reg2 : noreg),
1469-
next_test);
1470-
// (Reg2 now contains the item from the CallData.)
1471-
1472-
// The item is item[n]. Increment count[n].
1473-
int count_offset = in_bytes(item_count_offset_fn(row));
1474-
increment_mdp_data_at(mdp, count_offset);
1475-
jmp(done);
1476-
bind(next_test);
1477-
1478-
if (test_for_null_also) {
1479-
// Failed the equality check on item[n]... Test for null.
1480-
testptr(reg2, reg2);
1481-
if (start_row == last_row) {
1482-
// The only thing left to do is handle the null case.
1483-
Label found_null;
1484-
jccb(Assembler::zero, found_null);
1485-
// Item did not match any saved item and there is no empty row for it.
1486-
// Increment total counter to indicate polymorphic case.
1487-
increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset()));
1488-
jmp(done);
1489-
bind(found_null);
1490-
break;
1491-
}
1492-
Label found_null;
1493-
// Since null is rare, make it be the branch-taken case.
1494-
jcc(Assembler::zero, found_null);
1495-
1496-
// Put all the "Case 3" tests here.
1497-
record_item_in_profile_helper(item, mdp, reg2, start_row + 1, done, total_rows,
1498-
item_offset_fn, item_count_offset_fn);
1499-
1500-
// Found a null. Keep searching for a matching item,
1501-
// but remember that this is an empty (unused) slot.
1502-
bind(found_null);
1503-
}
1504-
}
1505-
1506-
// In the fall-through case, we found no matching item, but we
1507-
// observed the item[start_row] is null.
1508-
1509-
// Fill in the item field and increment the count.
1510-
int item_offset = in_bytes(item_offset_fn(start_row));
1511-
set_mdp_data_at(mdp, item_offset, item);
1512-
int count_offset = in_bytes(item_count_offset_fn(start_row));
1513-
movl(reg2, DataLayout::counter_increment);
1514-
set_mdp_data_at(mdp, count_offset, reg2);
1515-
if (start_row > 0) {
1516-
jmp(done);
1517-
}
1518-
}
1519-
1520-
// Example state machine code for three profile rows:
1521-
// // main copy of decision tree, rooted at row[1]
1522-
// if (row[0].rec == rec) { row[0].incr(); goto done; }
1523-
// if (row[0].rec != nullptr) {
1524-
// // inner copy of decision tree, rooted at row[1]
1525-
// if (row[1].rec == rec) { row[1].incr(); goto done; }
1526-
// if (row[1].rec != nullptr) {
1527-
// // degenerate decision tree, rooted at row[2]
1528-
// if (row[2].rec == rec) { row[2].incr(); goto done; }
1529-
// if (row[2].rec != nullptr) { count.incr(); goto done; } // overflow
1530-
// row[2].init(rec); goto done;
1531-
// } else {
1532-
// // remember row[1] is empty
1533-
// if (row[2].rec == rec) { row[2].incr(); goto done; }
1534-
// row[1].init(rec); goto done;
1535-
// }
1536-
// } else {
1537-
// // remember row[0] is empty
1538-
// if (row[1].rec == rec) { row[1].incr(); goto done; }
1539-
// if (row[2].rec == rec) { row[2].incr(); goto done; }
1540-
// row[0].init(rec); goto done;
1541-
// }
1542-
// done:
1543-
1544-
void InterpreterMacroAssembler::record_klass_in_profile(Register receiver,
1545-
Register mdp, Register reg2,
1546-
bool is_virtual_call) {
1547-
assert(ProfileInterpreter, "must be profiling");
1548-
Label done;
1549-
1550-
record_klass_in_profile_helper(receiver, mdp, reg2, 0, done, is_virtual_call);
1551-
1552-
bind (done);
1553-
}
1554-
15551424
void InterpreterMacroAssembler::profile_ret(Register return_bci,
15561425
Register mdp) {
15571426
if (ProfileInterpreter) {
@@ -1611,7 +1480,7 @@ void InterpreterMacroAssembler::profile_null_seen(Register mdp) {
16111480
}
16121481

16131482

1614-
void InterpreterMacroAssembler::profile_typecheck(Register mdp, Register klass, Register reg2) {
1483+
void InterpreterMacroAssembler::profile_typecheck(Register mdp, Register klass) {
16151484
if (ProfileInterpreter) {
16161485
Label profile_continue;
16171486

@@ -1624,7 +1493,7 @@ void InterpreterMacroAssembler::profile_typecheck(Register mdp, Register klass,
16241493
mdp_delta = in_bytes(VirtualCallData::virtual_call_data_size());
16251494

16261495
// Record the object type.
1627-
record_klass_in_profile(klass, mdp, reg2, false);
1496+
profile_receiver_type(klass, mdp, 0);
16281497
}
16291498
update_mdp_by_constant(mdp, mdp_delta);
16301499

src/hotspot/cpu/x86/interp_masm_x86.hpp

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -234,16 +234,6 @@ class InterpreterMacroAssembler: public MacroAssembler {
234234
Register test_value_out,
235235
Label& not_equal_continue);
236236

237-
void record_klass_in_profile(Register receiver, Register mdp,
238-
Register reg2, bool is_virtual_call);
239-
void record_klass_in_profile_helper(Register receiver, Register mdp,
240-
Register reg2, int start_row,
241-
Label& done, bool is_virtual_call);
242-
void record_item_in_profile_helper(Register item, Register mdp, Register reg2, int start_row,
243-
Label& done, int total_rows,
244-
OffsetFunction item_offset_fn,
245-
OffsetFunction item_count_offset_fn);
246-
247237
void update_mdp_by_offset(Register mdp_in, int offset_of_offset);
248238
void update_mdp_by_offset(Register mdp_in, Register reg, int offset_of_disp);
249239
void update_mdp_by_constant(Register mdp_in, int constant);
@@ -254,11 +244,10 @@ class InterpreterMacroAssembler: public MacroAssembler {
254244
void profile_call(Register mdp);
255245
void profile_final_call(Register mdp);
256246
void profile_virtual_call(Register receiver, Register mdp,
257-
Register scratch2,
258247
bool receiver_can_be_null = false);
259248
void profile_ret(Register return_bci, Register mdp);
260249
void profile_null_seen(Register mdp);
261-
void profile_typecheck(Register mdp, Register klass, Register scratch);
250+
void profile_typecheck(Register mdp, Register klass);
262251

263252
void profile_switch_default(Register mdp);
264253
void profile_switch_case(Register index_in_scratch, Register mdp,

0 commit comments

Comments
 (0)