1485 1486 // If no method data exists, go to profile_continue. 1487 test_method_data_pointer(mdp, profile_continue); 1488 1489 Label skip_receiver_profile; 1490 if (receiver_can_be_null) { 1491 Label not_null; 1492 testptr(receiver, receiver); 1493 jccb(Assembler::notZero, not_null); 1494 // We are making a call. Increment the count for null receiver. 1495 increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); 1496 jmp(skip_receiver_profile); 1497 bind(not_null); 1498 } 1499 1500 // Record the receiver type. 1501 record_klass_in_profile(receiver, mdp, reg2, true); 1502 bind(skip_receiver_profile); 1503 1504 // The method data pointer needs to be updated to reflect the new target. 1505 update_mdp_by_constant(mdp, 1506 in_bytes(VirtualCallData:: 1507 virtual_call_data_size())); 1508 bind(profile_continue); 1509 } 1510 } 1511 1512 // This routine creates a state machine for updating the multi-row 1513 // type profile at a virtual call site (or other type-sensitive bytecode). 1514 // The machine visits each row (of receiver/count) until the receiver type 1515 // is found, or until it runs out of rows. At the same time, it remembers 1516 // the location of the first empty row. (An empty row records null for its 1517 // receiver, and can be allocated for a newly-observed receiver type.) 1518 // Because there are two degrees of freedom in the state, a simple linear 1519 // search will not work; it must be a decision tree. Hence this helper 1520 // function is recursive, to generate the required tree structured code. 1521 // It's the interpreter, so we are trading off code space for speed. 1522 // See below for example code. 1523 void InterpreterMacroAssembler::record_klass_in_profile_helper( 1524 Register receiver, Register mdp, 1525 Register reg2, int start_row, 1526 Label& done, bool is_virtual_call) { 1527 if (TypeProfileWidth == 0) { 1528 if (is_virtual_call) { 1529 increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); 1530 } 1531 return; 1532 } 1533 1534 int last_row = VirtualCallData::row_limit() - 1; 1535 assert(start_row <= last_row, "must be work left to do"); 1536 // Test this row for both the receiver and for null. 1537 // Take any of three different outcomes: 1538 // 1. found receiver => increment count and goto done 1539 // 2. found null => keep looking for case 1, maybe allocate this cell 1540 // 3. found something else => keep looking for cases 1 and 2 1541 // Case 3 is handled by a recursive call. 1542 for (int row = start_row; row <= last_row; row++) { 1543 Label next_test; 1544 bool test_for_null_also = (row == start_row); 1545 1546 // See if the receiver is receiver[n]. 1547 int recvr_offset = in_bytes(VirtualCallData::receiver_offset(row)); 1548 test_mdp_data_at(mdp, recvr_offset, receiver, 1549 (test_for_null_also ? reg2 : noreg), 1550 next_test); 1551 // (Reg2 now contains the receiver from the CallData.) 1552 1553 // The receiver is receiver[n]. Increment count[n]. 1554 int count_offset = in_bytes(VirtualCallData::receiver_count_offset(row)); 1555 increment_mdp_data_at(mdp, count_offset); 1556 jmp(done); 1557 bind(next_test); 1558 1559 if (test_for_null_also) { 1560 Label found_null; 1561 // Failed the equality check on receiver[n]... Test for null. 1562 testptr(reg2, reg2); 1563 if (start_row == last_row) { 1564 // The only thing left to do is handle the null case. 1565 if (is_virtual_call) { 1566 jccb(Assembler::zero, found_null); 1567 // Receiver did not match any saved receiver and there is no empty row for it. 1568 // Increment total counter to indicate polymorphic case. 1569 increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); 1570 jmp(done); 1571 bind(found_null); 1572 } else { 1573 jcc(Assembler::notZero, done); 1574 } 1575 break; 1576 } 1577 // Since null is rare, make it be the branch-taken case. 1578 jcc(Assembler::zero, found_null); 1579 1580 // Put all the "Case 3" tests here. 1581 record_klass_in_profile_helper(receiver, mdp, reg2, start_row + 1, done, is_virtual_call); 1582 1583 // Found a null. Keep searching for a matching receiver, 1584 // but remember that this is an empty (unused) slot. 1585 bind(found_null); 1586 } 1587 } 1588 1589 // In the fall-through case, we found no matching receiver, but we 1590 // observed the receiver[start_row] is NULL. 1591 1592 // Fill in the receiver field and increment the count. 1593 int recvr_offset = in_bytes(VirtualCallData::receiver_offset(start_row)); 1594 set_mdp_data_at(mdp, recvr_offset, receiver); 1595 int count_offset = in_bytes(VirtualCallData::receiver_count_offset(start_row)); 1596 movl(reg2, DataLayout::counter_increment); 1597 set_mdp_data_at(mdp, count_offset, reg2); 1598 if (start_row > 0) { 1599 jmp(done); 1600 } 1601 } 1602 1603 // Example state machine code for three profile rows: 1604 // // main copy of decision tree, rooted at row[1] 1605 // if (row[0].rec == rec) { row[0].incr(); goto done; } 1606 // if (row[0].rec != NULL) { 1607 // // inner copy of decision tree, rooted at row[1] 1608 // if (row[1].rec == rec) { row[1].incr(); goto done; } 1609 // if (row[1].rec != NULL) { 1610 // // degenerate decision tree, rooted at row[2] 1611 // if (row[2].rec == rec) { row[2].incr(); goto done; } 1612 // if (row[2].rec != NULL) { count.incr(); goto done; } // overflow 1613 // row[2].init(rec); goto done; 1614 // } else { 1615 // // remember row[1] is empty | 1485 1486 // If no method data exists, go to profile_continue. 1487 test_method_data_pointer(mdp, profile_continue); 1488 1489 Label skip_receiver_profile; 1490 if (receiver_can_be_null) { 1491 Label not_null; 1492 testptr(receiver, receiver); 1493 jccb(Assembler::notZero, not_null); 1494 // We are making a call. Increment the count for null receiver. 1495 increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); 1496 jmp(skip_receiver_profile); 1497 bind(not_null); 1498 } 1499 1500 // Record the receiver type. 1501 record_klass_in_profile(receiver, mdp, reg2, true); 1502 bind(skip_receiver_profile); 1503 1504 // The method data pointer needs to be updated to reflect the new target. 1505 #if INCLUDE_JVMCI 1506 if (MethodProfileWidth == 0) { 1507 update_mdp_by_constant(mdp, in_bytes(VirtualCallData::virtual_call_data_size())); 1508 } 1509 #else // INCLUDE_JVMCI 1510 update_mdp_by_constant(mdp, 1511 in_bytes(VirtualCallData:: 1512 virtual_call_data_size())); 1513 #endif // INCLUDE_JVMCI 1514 bind(profile_continue); 1515 } 1516 } 1517 1518 #if INCLUDE_JVMCI 1519 void InterpreterMacroAssembler::profile_called_method(Register method, Register mdp, Register reg2) { 1520 assert_different_registers(method, mdp, reg2); 1521 if (ProfileInterpreter && MethodProfileWidth > 0) { 1522 Label profile_continue; 1523 1524 // If no method data exists, go to profile_continue. 1525 test_method_data_pointer(mdp, profile_continue); 1526 1527 Label done; 1528 record_item_in_profile_helper(method, mdp, reg2, 0, done, MethodProfileWidth, 1529 &VirtualCallData::method_offset, &VirtualCallData::method_count_offset, in_bytes(VirtualCallData::nonprofiled_receiver_count_offset())); 1530 bind(done); 1531 1532 update_mdp_by_constant(mdp, in_bytes(VirtualCallData::virtual_call_data_size())); 1533 bind(profile_continue); 1534 } 1535 } 1536 #endif // INCLUDE_JVMCI 1537 1538 // This routine creates a state machine for updating the multi-row 1539 // type profile at a virtual call site (or other type-sensitive bytecode). 1540 // The machine visits each row (of receiver/count) until the receiver type 1541 // is found, or until it runs out of rows. At the same time, it remembers 1542 // the location of the first empty row. (An empty row records null for its 1543 // receiver, and can be allocated for a newly-observed receiver type.) 1544 // Because there are two degrees of freedom in the state, a simple linear 1545 // search will not work; it must be a decision tree. Hence this helper 1546 // function is recursive, to generate the required tree structured code. 1547 // It's the interpreter, so we are trading off code space for speed. 1548 // See below for example code. 1549 void InterpreterMacroAssembler::record_klass_in_profile_helper( 1550 Register receiver, Register mdp, 1551 Register reg2, int start_row, 1552 Label& done, bool is_virtual_call) { 1553 if (TypeProfileWidth == 0) { 1554 if (is_virtual_call) { 1555 increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); 1556 } 1557 #if INCLUDE_JVMCI 1558 else if (EnableJVMCI) { 1559 increment_mdp_data_at(mdp, in_bytes(ReceiverTypeData::nonprofiled_receiver_count_offset())); 1560 } 1561 #endif // INCLUDE_JVMCI 1562 } else { 1563 int non_profiled_offset = -1; 1564 if (is_virtual_call) { 1565 non_profiled_offset = in_bytes(CounterData::count_offset()); 1566 } 1567 #if INCLUDE_JVMCI 1568 else if (EnableJVMCI) { 1569 non_profiled_offset = in_bytes(ReceiverTypeData::nonprofiled_receiver_count_offset()); 1570 } 1571 #endif // INCLUDE_JVMCI 1572 1573 record_item_in_profile_helper(receiver, mdp, reg2, 0, done, TypeProfileWidth, 1574 &VirtualCallData::receiver_offset, &VirtualCallData::receiver_count_offset, non_profiled_offset); 1575 } 1576 } 1577 1578 void InterpreterMacroAssembler::record_item_in_profile_helper(Register item, Register mdp, 1579 Register reg2, int start_row, Label& done, int total_rows, 1580 OffsetFunction item_offset_fn, OffsetFunction item_count_offset_fn, 1581 int non_profiled_offset) { 1582 int last_row = total_rows - 1; 1583 assert(start_row <= last_row, "must be work left to do"); 1584 // Test this row for both the item and for null. 1585 // Take any of three different outcomes: 1586 // 1. found item => increment count and goto done 1587 // 2. found null => keep looking for case 1, maybe allocate this cell 1588 // 3. found something else => keep looking for cases 1 and 2 1589 // Case 3 is handled by a recursive call. 1590 for (int row = start_row; row <= last_row; row++) { 1591 Label next_test; 1592 bool test_for_null_also = (row == start_row); 1593 1594 // See if the item is item[n]. 1595 int item_offset = in_bytes(item_offset_fn(row)); 1596 test_mdp_data_at(mdp, item_offset, item, 1597 (test_for_null_also ? reg2 : noreg), 1598 next_test); 1599 // (Reg2 now contains the item from the CallData.) 1600 1601 // The item is item[n]. Increment count[n]. 1602 int count_offset = in_bytes(item_count_offset_fn(row)); 1603 increment_mdp_data_at(mdp, count_offset); 1604 jmp(done); 1605 bind(next_test); 1606 1607 if (test_for_null_also) { 1608 Label found_null; 1609 // Failed the equality check on item[n]... Test for null. 1610 testptr(reg2, reg2); 1611 if (start_row == last_row) { 1612 // The only thing left to do is handle the null case. 1613 if (non_profiled_offset >= 0) { 1614 jccb(Assembler::zero, found_null); 1615 // Item did not match any saved item and there is no empty row for it. 1616 // Increment total counter to indicate polymorphic case. 1617 increment_mdp_data_at(mdp, non_profiled_offset); 1618 jmp(done); 1619 bind(found_null); 1620 } else { 1621 jcc(Assembler::notZero, done); 1622 } 1623 break; 1624 } 1625 // Since null is rare, make it be the branch-taken case. 1626 jcc(Assembler::zero, found_null); 1627 1628 // Put all the "Case 3" tests here. 1629 record_item_in_profile_helper(item, mdp, reg2, start_row + 1, done, total_rows, 1630 item_offset_fn, item_count_offset_fn, non_profiled_offset); 1631 1632 // Found a null. Keep searching for a matching item, 1633 // but remember that this is an empty (unused) slot. 1634 bind(found_null); 1635 } 1636 } 1637 1638 // In the fall-through case, we found no matching item, but we 1639 // observed the item[start_row] is NULL. 1640 1641 // Fill in the item field and increment the count. 1642 int item_offset = in_bytes(item_offset_fn(start_row)); 1643 set_mdp_data_at(mdp, item_offset, item); 1644 int count_offset = in_bytes(item_count_offset_fn(start_row)); 1645 movl(reg2, DataLayout::counter_increment); 1646 set_mdp_data_at(mdp, count_offset, reg2); 1647 if (start_row > 0) { 1648 jmp(done); 1649 } 1650 } 1651 1652 // Example state machine code for three profile rows: 1653 // // main copy of decision tree, rooted at row[1] 1654 // if (row[0].rec == rec) { row[0].incr(); goto done; } 1655 // if (row[0].rec != NULL) { 1656 // // inner copy of decision tree, rooted at row[1] 1657 // if (row[1].rec == rec) { row[1].incr(); goto done; } 1658 // if (row[1].rec != NULL) { 1659 // // degenerate decision tree, rooted at row[2] 1660 // if (row[2].rec == rec) { row[2].incr(); goto done; } 1661 // if (row[2].rec != NULL) { count.incr(); goto done; } // overflow 1662 // row[2].init(rec); goto done; 1663 // } else { 1664 // // remember row[1] is empty |