// 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++;
    }
  }
}