Mercurial > hg > truffle
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 }; |