comparison src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp @ 845:df6caf649ff7

6700789: G1: Enable use of compressed oops with G1 heaps Summary: Modifications to G1 so as to allow the use of compressed oops. Reviewed-by: apetrusenko, coleenp, jmasa, kvn, never, phh, tonyp
author ysr
date Tue, 14 Jul 2009 15:40:39 -0700
parents 0316eac49d5a
children 42d84bbbecf4
comparison
equal deleted inserted replaced
839:bb18957ad21e 845:df6caf649ff7
54 # define IF_G1_DETAILED_STATS(code) code 54 # define IF_G1_DETAILED_STATS(code) code
55 #else 55 #else
56 # define IF_G1_DETAILED_STATS(code) 56 # define IF_G1_DETAILED_STATS(code)
57 #endif 57 #endif
58 58
59 typedef GenericTaskQueue<oop*> RefToScanQueue; 59 typedef GenericTaskQueue<StarTask> RefToScanQueue;
60 typedef GenericTaskQueueSet<oop*> RefToScanQueueSet; 60 typedef GenericTaskQueueSet<StarTask> RefToScanQueueSet;
61 61
62 typedef int RegionIdx_t; // needs to hold [ 0..max_regions() ) 62 typedef int RegionIdx_t; // needs to hold [ 0..max_regions() )
63 typedef int CardIdx_t; // needs to hold [ 0..CardsPerRegion ) 63 typedef int CardIdx_t; // needs to hold [ 0..CardsPerRegion )
64 64
65 enum G1GCThreadGroups { 65 enum G1GCThreadGroups {
1269 // to catch such places (as well as searching for calls to this...) 1269 // to catch such places (as well as searching for calls to this...)
1270 static void g1_unimplemented(); 1270 static void g1_unimplemented();
1271 1271
1272 }; 1272 };
1273 1273
1274 // Local Variables: *** 1274 #define use_local_bitmaps 1
1275 // c-indentation-style: gnu *** 1275 #define verify_local_bitmaps 0
1276 // End: *** 1276 #define oop_buffer_length 256
1277
1278 #ifndef PRODUCT
1279 class GCLabBitMap;
1280 class GCLabBitMapClosure: public BitMapClosure {
1281 private:
1282 ConcurrentMark* _cm;
1283 GCLabBitMap* _bitmap;
1284
1285 public:
1286 GCLabBitMapClosure(ConcurrentMark* cm,
1287 GCLabBitMap* bitmap) {
1288 _cm = cm;
1289 _bitmap = bitmap;
1290 }
1291
1292 virtual bool do_bit(size_t offset);
1293 };
1294 #endif // !PRODUCT
1295
1296 class GCLabBitMap: public BitMap {
1297 private:
1298 ConcurrentMark* _cm;
1299
1300 int _shifter;
1301 size_t _bitmap_word_covers_words;
1302
1303 // beginning of the heap
1304 HeapWord* _heap_start;
1305
1306 // this is the actual start of the GCLab
1307 HeapWord* _real_start_word;
1308
1309 // this is the actual end of the GCLab
1310 HeapWord* _real_end_word;
1311
1312 // this is the first word, possibly located before the actual start
1313 // of the GCLab, that corresponds to the first bit of the bitmap
1314 HeapWord* _start_word;
1315
1316 // size of a GCLab in words
1317 size_t _gclab_word_size;
1318
1319 static int shifter() {
1320 return MinObjAlignment - 1;
1321 }
1322
1323 // how many heap words does a single bitmap word corresponds to?
1324 static size_t bitmap_word_covers_words() {
1325 return BitsPerWord << shifter();
1326 }
1327
1328 static size_t gclab_word_size() {
1329 return G1ParallelGCAllocBufferSize / HeapWordSize;
1330 }
1331
1332 static size_t bitmap_size_in_bits() {
1333 size_t bits_in_bitmap = gclab_word_size() >> shifter();
1334 // We are going to ensure that the beginning of a word in this
1335 // bitmap also corresponds to the beginning of a word in the
1336 // global marking bitmap. To handle the case where a GCLab
1337 // starts from the middle of the bitmap, we need to add enough
1338 // space (i.e. up to a bitmap word) to ensure that we have
1339 // enough bits in the bitmap.
1340 return bits_in_bitmap + BitsPerWord - 1;
1341 }
1342 public:
1343 GCLabBitMap(HeapWord* heap_start)
1344 : BitMap(bitmap_size_in_bits()),
1345 _cm(G1CollectedHeap::heap()->concurrent_mark()),
1346 _shifter(shifter()),
1347 _bitmap_word_covers_words(bitmap_word_covers_words()),
1348 _heap_start(heap_start),
1349 _gclab_word_size(gclab_word_size()),
1350 _real_start_word(NULL),
1351 _real_end_word(NULL),
1352 _start_word(NULL)
1353 {
1354 guarantee( size_in_words() >= bitmap_size_in_words(),
1355 "just making sure");
1356 }
1357
1358 inline unsigned heapWordToOffset(HeapWord* addr) {
1359 unsigned offset = (unsigned) pointer_delta(addr, _start_word) >> _shifter;
1360 assert(offset < size(), "offset should be within bounds");
1361 return offset;
1362 }
1363
1364 inline HeapWord* offsetToHeapWord(size_t offset) {
1365 HeapWord* addr = _start_word + (offset << _shifter);
1366 assert(_real_start_word <= addr && addr < _real_end_word, "invariant");
1367 return addr;
1368 }
1369
1370 bool fields_well_formed() {
1371 bool ret1 = (_real_start_word == NULL) &&
1372 (_real_end_word == NULL) &&
1373 (_start_word == NULL);
1374 if (ret1)
1375 return true;
1376
1377 bool ret2 = _real_start_word >= _start_word &&
1378 _start_word < _real_end_word &&
1379 (_real_start_word + _gclab_word_size) == _real_end_word &&
1380 (_start_word + _gclab_word_size + _bitmap_word_covers_words)
1381 > _real_end_word;
1382 return ret2;
1383 }
1384
1385 inline bool mark(HeapWord* addr) {
1386 guarantee(use_local_bitmaps, "invariant");
1387 assert(fields_well_formed(), "invariant");
1388
1389 if (addr >= _real_start_word && addr < _real_end_word) {
1390 assert(!isMarked(addr), "should not have already been marked");
1391
1392 // first mark it on the bitmap
1393 at_put(heapWordToOffset(addr), true);
1394
1395 return true;
1396 } else {
1397 return false;
1398 }
1399 }
1400
1401 inline bool isMarked(HeapWord* addr) {
1402 guarantee(use_local_bitmaps, "invariant");
1403 assert(fields_well_formed(), "invariant");
1404
1405 return at(heapWordToOffset(addr));
1406 }
1407
1408 void set_buffer(HeapWord* start) {
1409 guarantee(use_local_bitmaps, "invariant");
1410 clear();
1411
1412 assert(start != NULL, "invariant");
1413 _real_start_word = start;
1414 _real_end_word = start + _gclab_word_size;
1415
1416 size_t diff =
1417 pointer_delta(start, _heap_start) % _bitmap_word_covers_words;
1418 _start_word = start - diff;
1419
1420 assert(fields_well_formed(), "invariant");
1421 }
1422
1423 #ifndef PRODUCT
1424 void verify() {
1425 // verify that the marks have been propagated
1426 GCLabBitMapClosure cl(_cm, this);
1427 iterate(&cl);
1428 }
1429 #endif // PRODUCT
1430
1431 void retire() {
1432 guarantee(use_local_bitmaps, "invariant");
1433 assert(fields_well_formed(), "invariant");
1434
1435 if (_start_word != NULL) {
1436 CMBitMap* mark_bitmap = _cm->nextMarkBitMap();
1437
1438 // this means that the bitmap was set up for the GCLab
1439 assert(_real_start_word != NULL && _real_end_word != NULL, "invariant");
1440
1441 mark_bitmap->mostly_disjoint_range_union(this,
1442 0, // always start from the start of the bitmap
1443 _start_word,
1444 size_in_words());
1445 _cm->grayRegionIfNecessary(MemRegion(_real_start_word, _real_end_word));
1446
1447 #ifndef PRODUCT
1448 if (use_local_bitmaps && verify_local_bitmaps)
1449 verify();
1450 #endif // PRODUCT
1451 } else {
1452 assert(_real_start_word == NULL && _real_end_word == NULL, "invariant");
1453 }
1454 }
1455
1456 static size_t bitmap_size_in_words() {
1457 return (bitmap_size_in_bits() + BitsPerWord - 1) / BitsPerWord;
1458 }
1459 };
1460
1461 class G1ParGCAllocBuffer: public ParGCAllocBuffer {
1462 private:
1463 bool _retired;
1464 bool _during_marking;
1465 GCLabBitMap _bitmap;
1466
1467 public:
1468 G1ParGCAllocBuffer() :
1469 ParGCAllocBuffer(G1ParallelGCAllocBufferSize / HeapWordSize),
1470 _during_marking(G1CollectedHeap::heap()->mark_in_progress()),
1471 _bitmap(G1CollectedHeap::heap()->reserved_region().start()),
1472 _retired(false)
1473 { }
1474
1475 inline bool mark(HeapWord* addr) {
1476 guarantee(use_local_bitmaps, "invariant");
1477 assert(_during_marking, "invariant");
1478 return _bitmap.mark(addr);
1479 }
1480
1481 inline void set_buf(HeapWord* buf) {
1482 if (use_local_bitmaps && _during_marking)
1483 _bitmap.set_buffer(buf);
1484 ParGCAllocBuffer::set_buf(buf);
1485 _retired = false;
1486 }
1487
1488 inline void retire(bool end_of_gc, bool retain) {
1489 if (_retired)
1490 return;
1491 if (use_local_bitmaps && _during_marking) {
1492 _bitmap.retire();
1493 }
1494 ParGCAllocBuffer::retire(end_of_gc, retain);
1495 _retired = true;
1496 }
1497 };
1498
1499 class G1ParScanThreadState : public StackObj {
1500 protected:
1501 G1CollectedHeap* _g1h;
1502 RefToScanQueue* _refs;
1503 DirtyCardQueue _dcq;
1504 CardTableModRefBS* _ct_bs;
1505 G1RemSet* _g1_rem;
1506
1507 typedef GrowableArray<StarTask> OverflowQueue;
1508 OverflowQueue* _overflowed_refs;
1509
1510 G1ParGCAllocBuffer _alloc_buffers[GCAllocPurposeCount];
1511 ageTable _age_table;
1512
1513 size_t _alloc_buffer_waste;
1514 size_t _undo_waste;
1515
1516 OopsInHeapRegionClosure* _evac_failure_cl;
1517 G1ParScanHeapEvacClosure* _evac_cl;
1518 G1ParScanPartialArrayClosure* _partial_scan_cl;
1519
1520 int _hash_seed;
1521 int _queue_num;
1522
1523 int _term_attempts;
1524 #if G1_DETAILED_STATS
1525 int _pushes, _pops, _steals, _steal_attempts;
1526 int _overflow_pushes;
1527 #endif
1528
1529 double _start;
1530 double _start_strong_roots;
1531 double _strong_roots_time;
1532 double _start_term;
1533 double _term_time;
1534
1535 // Map from young-age-index (0 == not young, 1 is youngest) to
1536 // surviving words. base is what we get back from the malloc call
1537 size_t* _surviving_young_words_base;
1538 // this points into the array, as we use the first few entries for padding
1539 size_t* _surviving_young_words;
1540
1541 #define PADDING_ELEM_NUM (64 / sizeof(size_t))
1542
1543 void add_to_alloc_buffer_waste(size_t waste) { _alloc_buffer_waste += waste; }
1544
1545 void add_to_undo_waste(size_t waste) { _undo_waste += waste; }
1546
1547 DirtyCardQueue& dirty_card_queue() { return _dcq; }
1548 CardTableModRefBS* ctbs() { return _ct_bs; }
1549
1550 template <class T> void immediate_rs_update(HeapRegion* from, T* p, int tid) {
1551 if (!from->is_survivor()) {
1552 _g1_rem->par_write_ref(from, p, tid);
1553 }
1554 }
1555
1556 template <class T> void deferred_rs_update(HeapRegion* from, T* p, int tid) {
1557 // If the new value of the field points to the same region or
1558 // is the to-space, we don't need to include it in the Rset updates.
1559 if (!from->is_in_reserved(oopDesc::load_decode_heap_oop(p)) && !from->is_survivor()) {
1560 size_t card_index = ctbs()->index_for(p);
1561 // If the card hasn't been added to the buffer, do it.
1562 if (ctbs()->mark_card_deferred(card_index)) {
1563 dirty_card_queue().enqueue((jbyte*)ctbs()->byte_for_index(card_index));
1564 }
1565 }
1566 }
1567
1568 public:
1569 G1ParScanThreadState(G1CollectedHeap* g1h, int queue_num);
1570
1571 ~G1ParScanThreadState() {
1572 FREE_C_HEAP_ARRAY(size_t, _surviving_young_words_base);
1573 }
1574
1575 RefToScanQueue* refs() { return _refs; }
1576 OverflowQueue* overflowed_refs() { return _overflowed_refs; }
1577 ageTable* age_table() { return &_age_table; }
1578
1579 G1ParGCAllocBuffer* alloc_buffer(GCAllocPurpose purpose) {
1580 return &_alloc_buffers[purpose];
1581 }
1582
1583 size_t alloc_buffer_waste() { return _alloc_buffer_waste; }
1584 size_t undo_waste() { return _undo_waste; }
1585
1586 template <class T> void push_on_queue(T* ref) {
1587 assert(ref != NULL, "invariant");
1588 assert(has_partial_array_mask(ref) ||
1589 _g1h->obj_in_cs(oopDesc::load_decode_heap_oop(ref)), "invariant");
1590 #ifdef ASSERT
1591 if (has_partial_array_mask(ref)) {
1592 oop p = clear_partial_array_mask(ref);
1593 // Verify that we point into the CS
1594 assert(_g1h->obj_in_cs(p), "Should be in CS");
1595 }
1596 #endif
1597 if (!refs()->push(ref)) {
1598 overflowed_refs()->push(ref);
1599 IF_G1_DETAILED_STATS(note_overflow_push());
1600 } else {
1601 IF_G1_DETAILED_STATS(note_push());
1602 }
1603 }
1604
1605 void pop_from_queue(StarTask& ref) {
1606 if (refs()->pop_local(ref)) {
1607 assert((oop*)ref != NULL, "pop_local() returned true");
1608 assert(UseCompressedOops || !ref.is_narrow(), "Error");
1609 assert(has_partial_array_mask((oop*)ref) ||
1610 _g1h->obj_in_cs(ref.is_narrow() ? oopDesc::load_decode_heap_oop((narrowOop*)ref)
1611 : oopDesc::load_decode_heap_oop((oop*)ref)),
1612 "invariant");
1613 IF_G1_DETAILED_STATS(note_pop());
1614 } else {
1615 StarTask null_task;
1616 ref = null_task;
1617 }
1618 }
1619
1620 void pop_from_overflow_queue(StarTask& ref) {
1621 StarTask new_ref = overflowed_refs()->pop();
1622 assert((oop*)new_ref != NULL, "pop() from a local non-empty stack");
1623 assert(UseCompressedOops || !new_ref.is_narrow(), "Error");
1624 assert(has_partial_array_mask((oop*)new_ref) ||
1625 _g1h->obj_in_cs(new_ref.is_narrow() ? oopDesc::load_decode_heap_oop((narrowOop*)new_ref)
1626 : oopDesc::load_decode_heap_oop((oop*)new_ref)),
1627 "invariant");
1628 ref = new_ref;
1629 }
1630
1631 int refs_to_scan() { return refs()->size(); }
1632 int overflowed_refs_to_scan() { return overflowed_refs()->length(); }
1633
1634 template <class T> void update_rs(HeapRegion* from, T* p, int tid) {
1635 if (G1DeferredRSUpdate) {
1636 deferred_rs_update(from, p, tid);
1637 } else {
1638 immediate_rs_update(from, p, tid);
1639 }
1640 }
1641
1642 HeapWord* allocate_slow(GCAllocPurpose purpose, size_t word_sz) {
1643
1644 HeapWord* obj = NULL;
1645 if (word_sz * 100 <
1646 (size_t)(G1ParallelGCAllocBufferSize / HeapWordSize) *
1647 ParallelGCBufferWastePct) {
1648 G1ParGCAllocBuffer* alloc_buf = alloc_buffer(purpose);
1649 add_to_alloc_buffer_waste(alloc_buf->words_remaining());
1650 alloc_buf->retire(false, false);
1651
1652 HeapWord* buf =
1653 _g1h->par_allocate_during_gc(purpose, G1ParallelGCAllocBufferSize / HeapWordSize);
1654 if (buf == NULL) return NULL; // Let caller handle allocation failure.
1655 // Otherwise.
1656 alloc_buf->set_buf(buf);
1657
1658 obj = alloc_buf->allocate(word_sz);
1659 assert(obj != NULL, "buffer was definitely big enough...");
1660 } else {
1661 obj = _g1h->par_allocate_during_gc(purpose, word_sz);
1662 }
1663 return obj;
1664 }
1665
1666 HeapWord* allocate(GCAllocPurpose purpose, size_t word_sz) {
1667 HeapWord* obj = alloc_buffer(purpose)->allocate(word_sz);
1668 if (obj != NULL) return obj;
1669 return allocate_slow(purpose, word_sz);
1670 }
1671
1672 void undo_allocation(GCAllocPurpose purpose, HeapWord* obj, size_t word_sz) {
1673 if (alloc_buffer(purpose)->contains(obj)) {
1674 assert(alloc_buffer(purpose)->contains(obj + word_sz - 1),
1675 "should contain whole object");
1676 alloc_buffer(purpose)->undo_allocation(obj, word_sz);
1677 } else {
1678 CollectedHeap::fill_with_object(obj, word_sz);
1679 add_to_undo_waste(word_sz);
1680 }
1681 }
1682
1683 void set_evac_failure_closure(OopsInHeapRegionClosure* evac_failure_cl) {
1684 _evac_failure_cl = evac_failure_cl;
1685 }
1686 OopsInHeapRegionClosure* evac_failure_closure() {
1687 return _evac_failure_cl;
1688 }
1689
1690 void set_evac_closure(G1ParScanHeapEvacClosure* evac_cl) {
1691 _evac_cl = evac_cl;
1692 }
1693
1694 void set_partial_scan_closure(G1ParScanPartialArrayClosure* partial_scan_cl) {
1695 _partial_scan_cl = partial_scan_cl;
1696 }
1697
1698 int* hash_seed() { return &_hash_seed; }
1699 int queue_num() { return _queue_num; }
1700
1701 int term_attempts() { return _term_attempts; }
1702 void note_term_attempt() { _term_attempts++; }
1703
1704 #if G1_DETAILED_STATS
1705 int pushes() { return _pushes; }
1706 int pops() { return _pops; }
1707 int steals() { return _steals; }
1708 int steal_attempts() { return _steal_attempts; }
1709 int overflow_pushes() { return _overflow_pushes; }
1710
1711 void note_push() { _pushes++; }
1712 void note_pop() { _pops++; }
1713 void note_steal() { _steals++; }
1714 void note_steal_attempt() { _steal_attempts++; }
1715 void note_overflow_push() { _overflow_pushes++; }
1716 #endif
1717
1718 void start_strong_roots() {
1719 _start_strong_roots = os::elapsedTime();
1720 }
1721 void end_strong_roots() {
1722 _strong_roots_time += (os::elapsedTime() - _start_strong_roots);
1723 }
1724 double strong_roots_time() { return _strong_roots_time; }
1725
1726 void start_term_time() {
1727 note_term_attempt();
1728 _start_term = os::elapsedTime();
1729 }
1730 void end_term_time() {
1731 _term_time += (os::elapsedTime() - _start_term);
1732 }
1733 double term_time() { return _term_time; }
1734
1735 double elapsed() {
1736 return os::elapsedTime() - _start;
1737 }
1738
1739 size_t* surviving_young_words() {
1740 // We add on to hide entry 0 which accumulates surviving words for
1741 // age -1 regions (i.e. non-young ones)
1742 return _surviving_young_words;
1743 }
1744
1745 void retire_alloc_buffers() {
1746 for (int ap = 0; ap < GCAllocPurposeCount; ++ap) {
1747 size_t waste = _alloc_buffers[ap].words_remaining();
1748 add_to_alloc_buffer_waste(waste);
1749 _alloc_buffers[ap].retire(true, false);
1750 }
1751 }
1752
1753 private:
1754 template <class T> void deal_with_reference(T* ref_to_scan) {
1755 if (has_partial_array_mask(ref_to_scan)) {
1756 _partial_scan_cl->do_oop_nv(ref_to_scan);
1757 } else {
1758 // Note: we can use "raw" versions of "region_containing" because
1759 // "obj_to_scan" is definitely in the heap, and is not in a
1760 // humongous region.
1761 HeapRegion* r = _g1h->heap_region_containing_raw(ref_to_scan);
1762 _evac_cl->set_region(r);
1763 _evac_cl->do_oop_nv(ref_to_scan);
1764 }
1765 }
1766
1767 public:
1768 void trim_queue() {
1769 // I've replicated the loop twice, first to drain the overflow
1770 // queue, second to drain the task queue. This is better than
1771 // having a single loop, which checks both conditions and, inside
1772 // it, either pops the overflow queue or the task queue, as each
1773 // loop is tighter. Also, the decision to drain the overflow queue
1774 // first is not arbitrary, as the overflow queue is not visible
1775 // to the other workers, whereas the task queue is. So, we want to
1776 // drain the "invisible" entries first, while allowing the other
1777 // workers to potentially steal the "visible" entries.
1778
1779 while (refs_to_scan() > 0 || overflowed_refs_to_scan() > 0) {
1780 while (overflowed_refs_to_scan() > 0) {
1781 StarTask ref_to_scan;
1782 assert((oop*)ref_to_scan == NULL, "Constructed above");
1783 pop_from_overflow_queue(ref_to_scan);
1784 // We shouldn't have pushed it on the queue if it was not
1785 // pointing into the CSet.
1786 assert((oop*)ref_to_scan != NULL, "Follows from inner loop invariant");
1787 if (ref_to_scan.is_narrow()) {
1788 assert(UseCompressedOops, "Error");
1789 narrowOop* p = (narrowOop*)ref_to_scan;
1790 assert(!has_partial_array_mask(p) &&
1791 _g1h->obj_in_cs(oopDesc::load_decode_heap_oop(p)), "sanity");
1792 deal_with_reference(p);
1793 } else {
1794 oop* p = (oop*)ref_to_scan;
1795 assert((has_partial_array_mask(p) && _g1h->obj_in_cs(clear_partial_array_mask(p))) ||
1796 _g1h->obj_in_cs(oopDesc::load_decode_heap_oop(p)), "sanity");
1797 deal_with_reference(p);
1798 }
1799 }
1800
1801 while (refs_to_scan() > 0) {
1802 StarTask ref_to_scan;
1803 assert((oop*)ref_to_scan == NULL, "Constructed above");
1804 pop_from_queue(ref_to_scan);
1805 if ((oop*)ref_to_scan != NULL) {
1806 if (ref_to_scan.is_narrow()) {
1807 assert(UseCompressedOops, "Error");
1808 narrowOop* p = (narrowOop*)ref_to_scan;
1809 assert(!has_partial_array_mask(p) &&
1810 _g1h->obj_in_cs(oopDesc::load_decode_heap_oop(p)), "sanity");
1811 deal_with_reference(p);
1812 } else {
1813 oop* p = (oop*)ref_to_scan;
1814 assert((has_partial_array_mask(p) && _g1h->obj_in_cs(clear_partial_array_mask(p))) ||
1815 _g1h->obj_in_cs(oopDesc::load_decode_heap_oop(p)), "sanity");
1816 deal_with_reference(p);
1817 }
1818 }
1819 }
1820 }
1821 }
1822 };