// clean (by dirty->clean before) ==> cur_younger_gen // dirty ==> cur_youngergen_and_prev_nonclean_card // precleaned ==> cur_youngergen_and_prev_nonclean_card // prev-younger-gen ==> cur_youngergen_and_prev_nonclean_card // cur-younger-gen ==> cur_younger_gen // cur_youngergen_and_prev_nonclean_card ==> no change. void CardTableRS::write_ref_field_gc_par(void* field, oop new_val) { jbyte* entry = ct_bs()->byte_for(field); do { jbyte entry_val = *entry; // We put this first because it's probably the most common case. if (entry_val == clean_card_val()) { // No threat of contention with cleaning threads. *entry = cur_youngergen_card_val(); return; } else if (card_is_dirty_wrt_gen_iter(entry_val) || is_prev_youngergen_card_val(entry_val)) { // Mark it as both cur and prev youngergen; card cleaning thread will // eventually remove the previous stuff. jbyte new_val = cur_youngergen_and_prev_nonclean_card; jbyte res = Atomic::cmpxchg(new_val, entry, entry_val); // Did the CAS succeed? if (res == entry_val) return; // Otherwise, retry, to see the new value. continue; } else { assert(entry_val == cur_youngergen_and_prev_nonclean_card || entry_val == cur_youngergen_card_val(), "should be only possibilities."); return; } } while (true); }
void CardTableRS::verify_space(Space* s, HeapWord* gen_boundary) { // We don't need to do young-gen spaces. if (s->end() <= gen_boundary) return; MemRegion used = s->used_region(); jbyte* cur_entry = byte_for(used.start()); jbyte* limit = byte_after(used.last()); while (cur_entry < limit) { if (*cur_entry == CardTableModRefBS::clean_card) { jbyte* first_dirty = cur_entry+1; while (first_dirty < limit && *first_dirty == CardTableModRefBS::clean_card) first_dirty++; // If the first object is a regular object, and it has a // young-to-old field, that would mark the previous card. HeapWord* boundary = addr_for(cur_entry); HeapWord* end = addr_for(first_dirty); HeapWord* boundary_block = s->block_start(boundary); HeapWord* begin = boundary; // Until proven otherwise. HeapWord* start_block = boundary_block; // Until proven otherwise. if (boundary_block < boundary) { if (s->block_is_obj(boundary_block)) { oop boundary_obj = oop(boundary_block); if (!boundary_obj->is_objArray() && !boundary_obj->is_typeArray()) { guarantee(cur_entry > byte_for(used.start()), "else boundary would be boundary_block"); if (*byte_for(boundary_block) != CardTableModRefBS::clean_card) { begin = boundary_block + s->block_size(boundary_block); start_block = begin; } } } } // Now traverse objects until end. HeapWord* cur = start_block; VerifyCleanCardClosure verify_blk(gen_boundary, begin, end); while (cur < end) { if (s->block_is_obj(cur)) { oop(cur)->oop_iterate(&verify_blk); } cur += s->block_size(cur); } cur_entry = first_dirty; } else { guarantee(*cur_entry != cur_youngergen_and_prev_nonclean_card, "Illegal CT value"); // If we're in the parallel case, the cur and prev values are // different, and we can't have left a prev in the table. guarantee(cur_youngergen_card_val() == youngergen_card || !is_prev_youngergen_card_val(*cur_entry), "Illegal CT value"); cur_entry++; } } }