Path: blob/aarch64-shenandoah-jdk8u272-b10/hotspot/src/share/vm/memory/cardTableRS.cpp
32285 views
/*1* Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*22*/2324#include "precompiled.hpp"25#include "memory/allocation.inline.hpp"26#include "memory/cardTableRS.hpp"27#include "memory/genCollectedHeap.hpp"28#include "memory/generation.hpp"29#include "memory/space.hpp"30#include "oops/oop.inline.hpp"31#include "runtime/java.hpp"32#include "runtime/os.hpp"33#include "utilities/macros.hpp"34#if INCLUDE_ALL_GCS35#include "gc_implementation/g1/concurrentMark.hpp"36#include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp"37#endif // INCLUDE_ALL_GCS3839CardTableRS::CardTableRS(MemRegion whole_heap,40int max_covered_regions) :41GenRemSet(),42_cur_youngergen_card_val(youngergenP1_card),43_regions_to_iterate(max_covered_regions - 1)44{45#if INCLUDE_ALL_GCS46if (UseG1GC) {47_ct_bs = new G1SATBCardTableLoggingModRefBS(whole_heap,48max_covered_regions);49} else {50_ct_bs = new CardTableModRefBSForCTRS(whole_heap, max_covered_regions);51}52#else53_ct_bs = new CardTableModRefBSForCTRS(whole_heap, max_covered_regions);54#endif55_ct_bs->initialize();56set_bs(_ct_bs);57_last_cur_val_in_gen = NEW_C_HEAP_ARRAY3(jbyte, GenCollectedHeap::max_gens + 1,58mtGC, CURRENT_PC, AllocFailStrategy::RETURN_NULL);59if (_last_cur_val_in_gen == NULL) {60vm_exit_during_initialization("Could not create last_cur_val_in_gen array.");61}62for (int i = 0; i < GenCollectedHeap::max_gens + 1; i++) {63_last_cur_val_in_gen[i] = clean_card_val();64}65_ct_bs->set_CTRS(this);66}6768CardTableRS::~CardTableRS() {69if (_ct_bs) {70delete _ct_bs;71_ct_bs = NULL;72}73if (_last_cur_val_in_gen) {74FREE_C_HEAP_ARRAY(jbyte, _last_cur_val_in_gen, mtInternal);75}76}7778void CardTableRS::resize_covered_region(MemRegion new_region) {79_ct_bs->resize_covered_region(new_region);80}8182jbyte CardTableRS::find_unused_youngergenP_card_value() {83for (jbyte v = youngergenP1_card;84v < cur_youngergen_and_prev_nonclean_card;85v++) {86bool seen = false;87for (int g = 0; g < _regions_to_iterate; g++) {88if (_last_cur_val_in_gen[g] == v) {89seen = true;90break;91}92}93if (!seen) return v;94}95ShouldNotReachHere();96return 0;97}9899void CardTableRS::prepare_for_younger_refs_iterate(bool parallel) {100// Parallel or sequential, we must always set the prev to equal the101// last one written.102if (parallel) {103// Find a parallel value to be used next.104jbyte next_val = find_unused_youngergenP_card_value();105set_cur_youngergen_card_val(next_val);106107} else {108// In an sequential traversal we will always write youngergen, so that109// the inline barrier is correct.110set_cur_youngergen_card_val(youngergen_card);111}112}113114void CardTableRS::younger_refs_iterate(Generation* g,115OopsInGenClosure* blk) {116_last_cur_val_in_gen[g->level()+1] = cur_youngergen_card_val();117g->younger_refs_iterate(blk);118}119120inline bool ClearNoncleanCardWrapper::clear_card(jbyte* entry) {121if (_is_par) {122return clear_card_parallel(entry);123} else {124return clear_card_serial(entry);125}126}127128inline bool ClearNoncleanCardWrapper::clear_card_parallel(jbyte* entry) {129while (true) {130// In the parallel case, we may have to do this several times.131jbyte entry_val = *entry;132assert(entry_val != CardTableRS::clean_card_val(),133"We shouldn't be looking at clean cards, and this should "134"be the only place they get cleaned.");135if (CardTableRS::card_is_dirty_wrt_gen_iter(entry_val)136|| _ct->is_prev_youngergen_card_val(entry_val)) {137jbyte res =138Atomic::cmpxchg(CardTableRS::clean_card_val(), entry, entry_val);139if (res == entry_val) {140break;141} else {142assert(res == CardTableRS::cur_youngergen_and_prev_nonclean_card,143"The CAS above should only fail if another thread did "144"a GC write barrier.");145}146} else if (entry_val ==147CardTableRS::cur_youngergen_and_prev_nonclean_card) {148// Parallelism shouldn't matter in this case. Only the thread149// assigned to scan the card should change this value.150*entry = _ct->cur_youngergen_card_val();151break;152} else {153assert(entry_val == _ct->cur_youngergen_card_val(),154"Should be the only possibility.");155// In this case, the card was clean before, and become156// cur_youngergen only because of processing of a promoted object.157// We don't have to look at the card.158return false;159}160}161return true;162}163164165inline bool ClearNoncleanCardWrapper::clear_card_serial(jbyte* entry) {166jbyte entry_val = *entry;167assert(entry_val != CardTableRS::clean_card_val(),168"We shouldn't be looking at clean cards, and this should "169"be the only place they get cleaned.");170assert(entry_val != CardTableRS::cur_youngergen_and_prev_nonclean_card,171"This should be possible in the sequential case.");172*entry = CardTableRS::clean_card_val();173return true;174}175176ClearNoncleanCardWrapper::ClearNoncleanCardWrapper(177DirtyCardToOopClosure* dirty_card_closure, CardTableRS* ct) :178_dirty_card_closure(dirty_card_closure), _ct(ct) {179// Cannot yet substitute active_workers for n_par_threads180// in the case where parallelism is being turned off by181// setting n_par_threads to 0.182_is_par = (SharedHeap::heap()->n_par_threads() > 0);183assert(!_is_par ||184(SharedHeap::heap()->n_par_threads() ==185SharedHeap::heap()->workers()->active_workers()), "Mismatch");186}187188bool ClearNoncleanCardWrapper::is_word_aligned(jbyte* entry) {189return (((intptr_t)entry) & (BytesPerWord-1)) == 0;190}191192void ClearNoncleanCardWrapper::do_MemRegion(MemRegion mr) {193assert(mr.word_size() > 0, "Error");194assert(_ct->is_aligned(mr.start()), "mr.start() should be card aligned");195// mr.end() may not necessarily be card aligned.196jbyte* cur_entry = _ct->byte_for(mr.last());197const jbyte* limit = _ct->byte_for(mr.start());198HeapWord* end_of_non_clean = mr.end();199HeapWord* start_of_non_clean = end_of_non_clean;200while (cur_entry >= limit) {201HeapWord* cur_hw = _ct->addr_for(cur_entry);202if ((*cur_entry != CardTableRS::clean_card_val()) && clear_card(cur_entry)) {203// Continue the dirty range by opening the204// dirty window one card to the left.205start_of_non_clean = cur_hw;206} else {207// We hit a "clean" card; process any non-empty208// "dirty" range accumulated so far.209if (start_of_non_clean < end_of_non_clean) {210const MemRegion mrd(start_of_non_clean, end_of_non_clean);211_dirty_card_closure->do_MemRegion(mrd);212}213214// fast forward through potential continuous whole-word range of clean cards beginning at a word-boundary215if (is_word_aligned(cur_entry)) {216jbyte* cur_row = cur_entry - BytesPerWord;217while (cur_row >= limit && *((intptr_t*)cur_row) == CardTableRS::clean_card_row()) {218cur_row -= BytesPerWord;219}220cur_entry = cur_row + BytesPerWord;221cur_hw = _ct->addr_for(cur_entry);222}223224// Reset the dirty window, while continuing to look225// for the next dirty card that will start a226// new dirty window.227end_of_non_clean = cur_hw;228start_of_non_clean = cur_hw;229}230// Note that "cur_entry" leads "start_of_non_clean" in231// its leftward excursion after this point232// in the loop and, when we hit the left end of "mr",233// will point off of the left end of the card-table234// for "mr".235cur_entry--;236}237// If the first card of "mr" was dirty, we will have238// been left with a dirty window, co-initial with "mr",239// which we now process.240if (start_of_non_clean < end_of_non_clean) {241const MemRegion mrd(start_of_non_clean, end_of_non_clean);242_dirty_card_closure->do_MemRegion(mrd);243}244}245246// clean (by dirty->clean before) ==> cur_younger_gen247// dirty ==> cur_youngergen_and_prev_nonclean_card248// precleaned ==> cur_youngergen_and_prev_nonclean_card249// prev-younger-gen ==> cur_youngergen_and_prev_nonclean_card250// cur-younger-gen ==> cur_younger_gen251// cur_youngergen_and_prev_nonclean_card ==> no change.252void CardTableRS::write_ref_field_gc_par(void* field, oop new_val) {253jbyte* entry = ct_bs()->byte_for(field);254do {255jbyte entry_val = *entry;256// We put this first because it's probably the most common case.257if (entry_val == clean_card_val()) {258// No threat of contention with cleaning threads.259*entry = cur_youngergen_card_val();260return;261} else if (card_is_dirty_wrt_gen_iter(entry_val)262|| is_prev_youngergen_card_val(entry_val)) {263// Mark it as both cur and prev youngergen; card cleaning thread will264// eventually remove the previous stuff.265jbyte new_val = cur_youngergen_and_prev_nonclean_card;266jbyte res = Atomic::cmpxchg(new_val, entry, entry_val);267// Did the CAS succeed?268if (res == entry_val) return;269// Otherwise, retry, to see the new value.270continue;271} else {272assert(entry_val == cur_youngergen_and_prev_nonclean_card273|| entry_val == cur_youngergen_card_val(),274"should be only possibilities.");275return;276}277} while (true);278}279280void CardTableRS::younger_refs_in_space_iterate(Space* sp,281OopsInGenClosure* cl) {282const MemRegion urasm = sp->used_region_at_save_marks();283#ifdef ASSERT284// Convert the assertion check to a warning if we are running285// CMS+ParNew until related bug is fixed.286MemRegion ur = sp->used_region();287assert(ur.contains(urasm) || (UseConcMarkSweepGC && UseParNewGC),288err_msg("Did you forget to call save_marks()? "289"[" PTR_FORMAT ", " PTR_FORMAT ") is not contained in "290"[" PTR_FORMAT ", " PTR_FORMAT ")",291p2i(urasm.start()), p2i(urasm.end()), p2i(ur.start()), p2i(ur.end())));292// In the case of CMS+ParNew, issue a warning293if (!ur.contains(urasm)) {294assert(UseConcMarkSweepGC && UseParNewGC, "Tautology: see assert above");295warning("CMS+ParNew: Did you forget to call save_marks()? "296"[" PTR_FORMAT ", " PTR_FORMAT ") is not contained in "297"[" PTR_FORMAT ", " PTR_FORMAT ")",298p2i(urasm.start()), p2i(urasm.end()), p2i(ur.start()), p2i(ur.end()));299MemRegion ur2 = sp->used_region();300MemRegion urasm2 = sp->used_region_at_save_marks();301if (!ur.equals(ur2)) {302warning("CMS+ParNew: Flickering used_region()!!");303}304if (!urasm.equals(urasm2)) {305warning("CMS+ParNew: Flickering used_region_at_save_marks()!!");306}307ShouldNotReachHere();308}309#endif310_ct_bs->non_clean_card_iterate_possibly_parallel(sp, urasm, cl, this);311}312313void CardTableRS::clear_into_younger(Generation* old_gen) {314assert(old_gen->level() == 1, "Should only be called for the old generation");315// The card tables for the youngest gen need never be cleared.316// There's a bit of subtlety in the clear() and invalidate()317// methods that we exploit here and in invalidate_or_clear()318// below to avoid missing cards at the fringes. If clear() or319// invalidate() are changed in the future, this code should320// be revisited. 20040107.ysr321clear(old_gen->prev_used_region());322}323324void CardTableRS::invalidate_or_clear(Generation* old_gen) {325assert(old_gen->level() == 1, "Should only be called for the old generation");326// Invalidate the cards for the currently occupied part of327// the old generation and clear the cards for the328// unoccupied part of the generation (if any, making use329// of that generation's prev_used_region to determine that330// region). No need to do anything for the youngest331// generation. Also see note#20040107.ysr above.332MemRegion used_mr = old_gen->used_region();333MemRegion to_be_cleared_mr = old_gen->prev_used_region().minus(used_mr);334if (!to_be_cleared_mr.is_empty()) {335clear(to_be_cleared_mr);336}337invalidate(used_mr);338}339340341class VerifyCleanCardClosure: public OopClosure {342private:343HeapWord* _boundary;344HeapWord* _begin;345HeapWord* _end;346protected:347template <class T> void do_oop_work(T* p) {348HeapWord* jp = (HeapWord*)p;349assert(jp >= _begin && jp < _end,350err_msg("Error: jp " PTR_FORMAT " should be within "351"[_begin, _end) = [" PTR_FORMAT "," PTR_FORMAT ")",352p2i(jp), p2i(_begin), p2i(_end)));353oop obj = oopDesc::load_decode_heap_oop(p);354guarantee(obj == NULL || (HeapWord*)obj >= _boundary,355err_msg("pointer " PTR_FORMAT " at " PTR_FORMAT " on "356"clean card crosses boundary" PTR_FORMAT,357p2i((HeapWord*)obj), p2i(jp), p2i(_boundary)));358}359360public:361VerifyCleanCardClosure(HeapWord* b, HeapWord* begin, HeapWord* end) :362_boundary(b), _begin(begin), _end(end) {363assert(b <= begin,364err_msg("Error: boundary " PTR_FORMAT " should be at or below begin " PTR_FORMAT,365p2i(b), p2i(begin)));366assert(begin <= end,367err_msg("Error: begin " PTR_FORMAT " should be strictly below end " PTR_FORMAT,368p2i(begin), p2i(end)));369}370371virtual void do_oop(oop* p) { VerifyCleanCardClosure::do_oop_work(p); }372virtual void do_oop(narrowOop* p) { VerifyCleanCardClosure::do_oop_work(p); }373};374375class VerifyCTSpaceClosure: public SpaceClosure {376private:377CardTableRS* _ct;378HeapWord* _boundary;379public:380VerifyCTSpaceClosure(CardTableRS* ct, HeapWord* boundary) :381_ct(ct), _boundary(boundary) {}382virtual void do_space(Space* s) { _ct->verify_space(s, _boundary); }383};384385class VerifyCTGenClosure: public GenCollectedHeap::GenClosure {386CardTableRS* _ct;387public:388VerifyCTGenClosure(CardTableRS* ct) : _ct(ct) {}389void do_generation(Generation* gen) {390// Skip the youngest generation.391if (gen->level() == 0) return;392// Normally, we're interested in pointers to younger generations.393VerifyCTSpaceClosure blk(_ct, gen->reserved().start());394gen->space_iterate(&blk, true);395}396};397398void CardTableRS::verify_space(Space* s, HeapWord* gen_boundary) {399// We don't need to do young-gen spaces.400if (s->end() <= gen_boundary) return;401MemRegion used = s->used_region();402403jbyte* cur_entry = byte_for(used.start());404jbyte* limit = byte_after(used.last());405while (cur_entry < limit) {406if (*cur_entry == CardTableModRefBS::clean_card) {407jbyte* first_dirty = cur_entry+1;408while (first_dirty < limit &&409*first_dirty == CardTableModRefBS::clean_card) {410first_dirty++;411}412// If the first object is a regular object, and it has a413// young-to-old field, that would mark the previous card.414HeapWord* boundary = addr_for(cur_entry);415HeapWord* end = (first_dirty >= limit) ? used.end() : addr_for(first_dirty);416HeapWord* boundary_block = s->block_start(boundary);417HeapWord* begin = boundary; // Until proven otherwise.418HeapWord* start_block = boundary_block; // Until proven otherwise.419if (boundary_block < boundary) {420if (s->block_is_obj(boundary_block) && s->obj_is_alive(boundary_block)) {421oop boundary_obj = oop(boundary_block);422if (!boundary_obj->is_objArray() &&423!boundary_obj->is_typeArray()) {424guarantee(cur_entry > byte_for(used.start()),425"else boundary would be boundary_block");426if (*byte_for(boundary_block) != CardTableModRefBS::clean_card) {427begin = boundary_block + s->block_size(boundary_block);428start_block = begin;429}430}431}432}433// Now traverse objects until end.434if (begin < end) {435MemRegion mr(begin, end);436VerifyCleanCardClosure verify_blk(gen_boundary, begin, end);437for (HeapWord* cur = start_block; cur < end; cur += s->block_size(cur)) {438if (s->block_is_obj(cur) && s->obj_is_alive(cur)) {439oop(cur)->oop_iterate_no_header(&verify_blk, mr);440}441}442}443cur_entry = first_dirty;444} else {445// We'd normally expect that cur_youngergen_and_prev_nonclean_card446// is a transient value, that cannot be in the card table447// except during GC, and thus assert that:448// guarantee(*cur_entry != cur_youngergen_and_prev_nonclean_card,449// "Illegal CT value");450// That however, need not hold, as will become clear in the451// following...452453// We'd normally expect that if we are in the parallel case,454// we can't have left a prev value (which would be different455// from the current value) in the card table, and so we'd like to456// assert that:457// guarantee(cur_youngergen_card_val() == youngergen_card458// || !is_prev_youngergen_card_val(*cur_entry),459// "Illegal CT value");460// That, however, may not hold occasionally, because of461// CMS or MSC in the old gen. To wit, consider the462// following two simple illustrative scenarios:463// (a) CMS: Consider the case where a large object L464// spanning several cards is allocated in the old465// gen, and has a young gen reference stored in it, dirtying466// some interior cards. A young collection scans the card,467// finds a young ref and installs a youngergenP_n value.468// L then goes dead. Now a CMS collection starts,469// finds L dead and sweeps it up. Assume that L is470// abutting _unallocated_blk, so _unallocated_blk is471// adjusted down to (below) L. Assume further that472// no young collection intervenes during this CMS cycle.473// The next young gen cycle will not get to look at this474// youngergenP_n card since it lies in the unoccupied475// part of the space.476// Some young collections later the blocks on this477// card can be re-allocated either due to direct allocation478// or due to absorbing promotions. At this time, the479// before-gc verification will fail the above assert.480// (b) MSC: In this case, an object L with a young reference481// is on a card that (therefore) holds a youngergen_n value.482// Suppose also that L lies towards the end of the used483// the used space before GC. An MSC collection484// occurs that compacts to such an extent that this485// card is no longer in the occupied part of the space.486// Since current code in MSC does not always clear cards487// in the unused part of old gen, this stale youngergen_n488// value is left behind and can later be covered by489// an object when promotion or direct allocation490// re-allocates that part of the heap.491//492// Fortunately, the presence of such stale card values is493// "only" a minor annoyance in that subsequent young collections494// might needlessly scan such cards, but would still never corrupt495// the heap as a result. However, it's likely not to be a significant496// performance inhibitor in practice. For instance,497// some recent measurements with unoccupied cards eagerly cleared498// out to maintain this invariant, showed next to no499// change in young collection times; of course one can construct500// degenerate examples where the cost can be significant.)501// Note, in particular, that if the "stale" card is modified502// after re-allocation, it would be dirty, not "stale". Thus,503// we can never have a younger ref in such a card and it is504// safe not to scan that card in any collection. [As we see505// below, we do some unnecessary scanning506// in some cases in the current parallel scanning algorithm.]507//508// The main point below is that the parallel card scanning code509// deals correctly with these stale card values. There are two main510// cases to consider where we have a stale "younger gen" value and a511// "derivative" case to consider, where we have a stale512// "cur_younger_gen_and_prev_non_clean" value, as will become513// apparent in the case analysis below.514// o Case 1. If the stale value corresponds to a younger_gen_n515// value other than the cur_younger_gen value then the code516// treats this as being tantamount to a prev_younger_gen517// card. This means that the card may be unnecessarily scanned.518// There are two sub-cases to consider:519// o Case 1a. Let us say that the card is in the occupied part520// of the generation at the time the collection begins. In521// that case the card will be either cleared when it is scanned522// for young pointers, or will be set to cur_younger_gen as a523// result of promotion. (We have elided the normal case where524// the scanning thread and the promoting thread interleave525// possibly resulting in a transient526// cur_younger_gen_and_prev_non_clean value before settling527// to cur_younger_gen. [End Case 1a.]528// o Case 1b. Consider now the case when the card is in the unoccupied529// part of the space which becomes occupied because of promotions530// into it during the current young GC. In this case the card531// will never be scanned for young references. The current532// code will set the card value to either533// cur_younger_gen_and_prev_non_clean or leave534// it with its stale value -- because the promotions didn't535// result in any younger refs on that card. Of these two536// cases, the latter will be covered in Case 1a during537// a subsequent scan. To deal with the former case, we need538// to further consider how we deal with a stale value of539// cur_younger_gen_and_prev_non_clean in our case analysis540// below. This we do in Case 3 below. [End Case 1b]541// [End Case 1]542// o Case 2. If the stale value corresponds to cur_younger_gen being543// a value not necessarily written by a current promotion, the544// card will not be scanned by the younger refs scanning code.545// (This is OK since as we argued above such cards cannot contain546// any younger refs.) The result is that this value will be547// treated as a prev_younger_gen value in a subsequent collection,548// which is addressed in Case 1 above. [End Case 2]549// o Case 3. We here consider the "derivative" case from Case 1b. above550// because of which we may find a stale551// cur_younger_gen_and_prev_non_clean card value in the table.552// Once again, as in Case 1, we consider two subcases, depending553// on whether the card lies in the occupied or unoccupied part554// of the space at the start of the young collection.555// o Case 3a. Let us say the card is in the occupied part of556// the old gen at the start of the young collection. In that557// case, the card will be scanned by the younger refs scanning558// code which will set it to cur_younger_gen. In a subsequent559// scan, the card will be considered again and get its final560// correct value. [End Case 3a]561// o Case 3b. Now consider the case where the card is in the562// unoccupied part of the old gen, and is occupied as a result563// of promotions during thus young gc. In that case,564// the card will not be scanned for younger refs. The presence565// of newly promoted objects on the card will then result in566// its keeping the value cur_younger_gen_and_prev_non_clean567// value, which we have dealt with in Case 3 here. [End Case 3b]568// [End Case 3]569//570// (Please refer to the code in the helper class571// ClearNonCleanCardWrapper and in CardTableModRefBS for details.)572//573// The informal arguments above can be tightened into a formal574// correctness proof and it behooves us to write up such a proof,575// or to use model checking to prove that there are no lingering576// concerns.577//578// Clearly because of Case 3b one cannot bound the time for579// which a card will retain what we have called a "stale" value.580// However, one can obtain a Loose upper bound on the redundant581// work as a result of such stale values. Note first that any582// time a stale card lies in the occupied part of the space at583// the start of the collection, it is scanned by younger refs584// code and we can define a rank function on card values that585// declines when this is so. Note also that when a card does not586// lie in the occupied part of the space at the beginning of a587// young collection, its rank can either decline or stay unchanged.588// In this case, no extra work is done in terms of redundant589// younger refs scanning of that card.590// Then, the case analysis above reveals that, in the worst case,591// any such stale card will be scanned unnecessarily at most twice.592//593// It is nonethelss advisable to try and get rid of some of this594// redundant work in a subsequent (low priority) re-design of595// the card-scanning code, if only to simplify the underlying596// state machine analysis/proof. ysr 1/28/2002. XXX597cur_entry++;598}599}600}601602void CardTableRS::verify() {603// At present, we only know how to verify the card table RS for604// generational heaps.605VerifyCTGenClosure blk(this);606CollectedHeap* ch = Universe::heap();607608if (ch->kind() == CollectedHeap::GenCollectedHeap) {609GenCollectedHeap::heap()->generation_iterate(&blk, false);610_ct_bs->verify();611}612}613614615void CardTableRS::verify_aligned_region_empty(MemRegion mr) {616if (!mr.is_empty()) {617jbyte* cur_entry = byte_for(mr.start());618jbyte* limit = byte_after(mr.last());619// The region mr may not start on a card boundary so620// the first card may reflect a write to the space621// just prior to mr.622if (!is_aligned(mr.start())) {623cur_entry++;624}625for (;cur_entry < limit; cur_entry++) {626guarantee(*cur_entry == CardTableModRefBS::clean_card,627"Unexpected dirty card found");628}629}630}631632633