< prev index next >

src/cpu/x86/vm/interp_masm_x86.cpp

Print this page




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


< prev index next >