src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp

Mon, 18 May 2009 11:52:46 -0700

author
iveresov
date
Mon, 18 May 2009 11:52:46 -0700
changeset 1230
215f81b4d9b3
parent 1229
315a5d70b295
child 1242
d44bdab1c03d
permissions
-rw-r--r--

6841831: G1: assert(contains_reference(from),"We just added it!") fires
Summary: During parallel rset updating we have to make sure that the worker ids of the refinement threads do not intersect with the worker ids that can be claimed by the mutator threads.
Reviewed-by: tonyp

ysr@777 1 /*
xdono@1014 2 * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved.
ysr@777 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
ysr@777 4 *
ysr@777 5 * This code is free software; you can redistribute it and/or modify it
ysr@777 6 * under the terms of the GNU General Public License version 2 only, as
ysr@777 7 * published by the Free Software Foundation.
ysr@777 8 *
ysr@777 9 * This code is distributed in the hope that it will be useful, but WITHOUT
ysr@777 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
ysr@777 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
ysr@777 12 * version 2 for more details (a copy is included in the LICENSE file that
ysr@777 13 * accompanied this code).
ysr@777 14 *
ysr@777 15 * You should have received a copy of the GNU General Public License version
ysr@777 16 * 2 along with this work; if not, write to the Free Software Foundation,
ysr@777 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
ysr@777 18 *
ysr@777 19 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
ysr@777 20 * CA 95054 USA or visit www.sun.com if you need additional information or
ysr@777 21 * have any questions.
ysr@777 22 *
ysr@777 23 */
ysr@777 24
ysr@777 25 #include "incls/_precompiled.incl"
ysr@777 26 #include "incls/_heapRegionRemSet.cpp.incl"
ysr@777 27
ysr@777 28 #define HRRS_VERBOSE 0
ysr@777 29
ysr@777 30 #define PRT_COUNT_OCCUPIED 1
ysr@777 31
ysr@777 32 // OtherRegionsTable
ysr@777 33
ysr@777 34 class PerRegionTable: public CHeapObj {
ysr@777 35 friend class OtherRegionsTable;
ysr@777 36 friend class HeapRegionRemSetIterator;
ysr@777 37
ysr@777 38 HeapRegion* _hr;
ysr@777 39 BitMap _bm;
ysr@777 40 #if PRT_COUNT_OCCUPIED
ysr@777 41 jint _occupied;
ysr@777 42 #endif
ysr@777 43 PerRegionTable* _next_free;
ysr@777 44
ysr@777 45 PerRegionTable* next_free() { return _next_free; }
ysr@777 46 void set_next_free(PerRegionTable* prt) { _next_free = prt; }
ysr@777 47
ysr@777 48
ysr@777 49 static PerRegionTable* _free_list;
ysr@777 50
ysr@777 51 #ifdef _MSC_VER
ysr@777 52 // For some reason even though the classes are marked as friend they are unable
ysr@777 53 // to access CardsPerRegion when private/protected. Only the windows c++ compiler
ysr@777 54 // says this Sun CC and linux gcc don't have a problem with access when private
ysr@777 55
ysr@777 56 public:
ysr@777 57
ysr@777 58 #endif // _MSC_VER
ysr@777 59
ysr@777 60 enum SomePrivateConstants {
ysr@777 61 CardsPerRegion = HeapRegion::GrainBytes >> CardTableModRefBS::card_shift
ysr@777 62 };
ysr@777 63
ysr@777 64 protected:
ysr@777 65 // We need access in order to union things into the base table.
ysr@777 66 BitMap* bm() { return &_bm; }
ysr@777 67
apetrusenko@980 68 #if PRT_COUNT_OCCUPIED
ysr@777 69 void recount_occupied() {
ysr@777 70 _occupied = (jint) bm()->count_one_bits();
ysr@777 71 }
apetrusenko@980 72 #endif
ysr@777 73
ysr@777 74 PerRegionTable(HeapRegion* hr) :
ysr@777 75 _hr(hr),
ysr@777 76 #if PRT_COUNT_OCCUPIED
ysr@777 77 _occupied(0),
ysr@777 78 #endif
ysr@777 79 _bm(CardsPerRegion, false /* in-resource-area */)
ysr@777 80 {}
ysr@777 81
ysr@777 82 static void free(PerRegionTable* prt) {
ysr@777 83 while (true) {
ysr@777 84 PerRegionTable* fl = _free_list;
ysr@777 85 prt->set_next_free(fl);
ysr@777 86 PerRegionTable* res =
ysr@777 87 (PerRegionTable*)
ysr@777 88 Atomic::cmpxchg_ptr(prt, &_free_list, fl);
ysr@777 89 if (res == fl) return;
ysr@777 90 }
ysr@777 91 ShouldNotReachHere();
ysr@777 92 }
ysr@777 93
ysr@777 94 static PerRegionTable* alloc(HeapRegion* hr) {
ysr@777 95 PerRegionTable* fl = _free_list;
ysr@777 96 while (fl != NULL) {
ysr@777 97 PerRegionTable* nxt = fl->next_free();
ysr@777 98 PerRegionTable* res =
ysr@777 99 (PerRegionTable*)
ysr@777 100 Atomic::cmpxchg_ptr(nxt, &_free_list, fl);
ysr@777 101 if (res == fl) {
ysr@777 102 fl->init(hr);
ysr@777 103 return fl;
ysr@777 104 } else {
ysr@777 105 fl = _free_list;
ysr@777 106 }
ysr@777 107 }
ysr@777 108 assert(fl == NULL, "Loop condition.");
ysr@777 109 return new PerRegionTable(hr);
ysr@777 110 }
ysr@777 111
ysr@777 112 void add_card_work(short from_card, bool par) {
ysr@777 113 if (!_bm.at(from_card)) {
ysr@777 114 if (par) {
ysr@777 115 if (_bm.par_at_put(from_card, 1)) {
ysr@777 116 #if PRT_COUNT_OCCUPIED
ysr@777 117 Atomic::inc(&_occupied);
ysr@777 118 #endif
ysr@777 119 }
ysr@777 120 } else {
ysr@777 121 _bm.at_put(from_card, 1);
ysr@777 122 #if PRT_COUNT_OCCUPIED
ysr@777 123 _occupied++;
ysr@777 124 #endif
ysr@777 125 }
ysr@777 126 }
ysr@777 127 }
ysr@777 128
ysr@777 129 void add_reference_work(oop* from, bool par) {
ysr@777 130 // Must make this robust in case "from" is not in "_hr", because of
ysr@777 131 // concurrency.
ysr@777 132
ysr@777 133 #if HRRS_VERBOSE
ysr@777 134 gclog_or_tty->print_cr(" PRT::Add_reference_work(" PTR_FORMAT "->" PTR_FORMAT").",
ysr@777 135 from, *from);
ysr@777 136 #endif
ysr@777 137
ysr@777 138 HeapRegion* loc_hr = hr();
ysr@777 139 // If the test below fails, then this table was reused concurrently
ysr@777 140 // with this operation. This is OK, since the old table was coarsened,
ysr@777 141 // and adding a bit to the new table is never incorrect.
ysr@777 142 if (loc_hr->is_in_reserved(from)) {
ysr@777 143 size_t hw_offset = pointer_delta((HeapWord*)from, loc_hr->bottom());
ysr@777 144 size_t from_card =
ysr@777 145 hw_offset >>
ysr@777 146 (CardTableModRefBS::card_shift - LogHeapWordSize);
ysr@777 147
ysr@777 148 add_card_work((short) from_card, par);
ysr@777 149 }
ysr@777 150 }
ysr@777 151
ysr@777 152 public:
ysr@777 153
ysr@777 154 HeapRegion* hr() const { return _hr; }
ysr@777 155
ysr@777 156 #if PRT_COUNT_OCCUPIED
ysr@777 157 jint occupied() const {
ysr@777 158 // Overkill, but if we ever need it...
ysr@777 159 // guarantee(_occupied == _bm.count_one_bits(), "Check");
ysr@777 160 return _occupied;
ysr@777 161 }
ysr@777 162 #else
ysr@777 163 jint occupied() const {
ysr@777 164 return _bm.count_one_bits();
ysr@777 165 }
ysr@777 166 #endif
ysr@777 167
ysr@777 168 void init(HeapRegion* hr) {
ysr@777 169 _hr = hr;
ysr@777 170 #if PRT_COUNT_OCCUPIED
ysr@777 171 _occupied = 0;
ysr@777 172 #endif
ysr@777 173 _bm.clear();
ysr@777 174 }
ysr@777 175
ysr@777 176 void add_reference(oop* from) {
ysr@777 177 add_reference_work(from, /*parallel*/ true);
ysr@777 178 }
ysr@777 179
ysr@777 180 void seq_add_reference(oop* from) {
ysr@777 181 add_reference_work(from, /*parallel*/ false);
ysr@777 182 }
ysr@777 183
ysr@777 184 void scrub(CardTableModRefBS* ctbs, BitMap* card_bm) {
ysr@777 185 HeapWord* hr_bot = hr()->bottom();
swamyv@924 186 size_t hr_first_card_index = ctbs->index_for(hr_bot);
ysr@777 187 bm()->set_intersection_at_offset(*card_bm, hr_first_card_index);
ysr@777 188 #if PRT_COUNT_OCCUPIED
ysr@777 189 recount_occupied();
ysr@777 190 #endif
ysr@777 191 }
ysr@777 192
ysr@777 193 void add_card(short from_card_index) {
ysr@777 194 add_card_work(from_card_index, /*parallel*/ true);
ysr@777 195 }
ysr@777 196
ysr@777 197 void seq_add_card(short from_card_index) {
ysr@777 198 add_card_work(from_card_index, /*parallel*/ false);
ysr@777 199 }
ysr@777 200
ysr@777 201 // (Destructively) union the bitmap of the current table into the given
ysr@777 202 // bitmap (which is assumed to be of the same size.)
ysr@777 203 void union_bitmap_into(BitMap* bm) {
ysr@777 204 bm->set_union(_bm);
ysr@777 205 }
ysr@777 206
ysr@777 207 // Mem size in bytes.
ysr@777 208 size_t mem_size() const {
ysr@777 209 return sizeof(this) + _bm.size_in_words() * HeapWordSize;
ysr@777 210 }
ysr@777 211
ysr@777 212 static size_t fl_mem_size() {
ysr@777 213 PerRegionTable* cur = _free_list;
ysr@777 214 size_t res = 0;
ysr@777 215 while (cur != NULL) {
ysr@777 216 res += sizeof(PerRegionTable);
ysr@777 217 cur = cur->next_free();
ysr@777 218 }
ysr@777 219 return res;
ysr@777 220 }
ysr@777 221
ysr@777 222 // Requires "from" to be in "hr()".
ysr@777 223 bool contains_reference(oop* from) const {
ysr@777 224 assert(hr()->is_in_reserved(from), "Precondition.");
ysr@777 225 size_t card_ind = pointer_delta(from, hr()->bottom(),
ysr@777 226 CardTableModRefBS::card_size);
ysr@777 227 return _bm.at(card_ind);
ysr@777 228 }
ysr@777 229 };
ysr@777 230
ysr@777 231 PerRegionTable* PerRegionTable::_free_list = NULL;
ysr@777 232
ysr@777 233
ysr@777 234 #define COUNT_PAR_EXPANDS 0
ysr@777 235
ysr@777 236 #if COUNT_PAR_EXPANDS
ysr@777 237 static jint n_par_expands = 0;
ysr@777 238 static jint n_par_contracts = 0;
ysr@777 239 static jint par_expand_list_len = 0;
ysr@777 240 static jint max_par_expand_list_len = 0;
ysr@777 241
ysr@777 242 static void print_par_expand() {
ysr@777 243 Atomic::inc(&n_par_expands);
ysr@777 244 Atomic::inc(&par_expand_list_len);
ysr@777 245 if (par_expand_list_len > max_par_expand_list_len) {
ysr@777 246 max_par_expand_list_len = par_expand_list_len;
ysr@777 247 }
ysr@777 248 if ((n_par_expands % 10) == 0) {
ysr@777 249 gclog_or_tty->print_cr("\n\n%d par expands: %d contracts, "
ysr@777 250 "len = %d, max_len = %d\n.",
ysr@777 251 n_par_expands, n_par_contracts, par_expand_list_len,
ysr@777 252 max_par_expand_list_len);
ysr@777 253 }
ysr@777 254 }
ysr@777 255 #endif
ysr@777 256
ysr@777 257 class PosParPRT: public PerRegionTable {
ysr@777 258 PerRegionTable** _par_tables;
ysr@777 259
ysr@777 260 enum SomePrivateConstants {
ysr@777 261 ReserveParTableExpansion = 1
ysr@777 262 };
ysr@777 263
ysr@777 264 void par_expand() {
ysr@777 265 int n = HeapRegionRemSet::num_par_rem_sets()-1;
ysr@777 266 if (n <= 0) return;
ysr@777 267 if (_par_tables == NULL) {
ysr@777 268 PerRegionTable* res =
ysr@777 269 (PerRegionTable*)
ysr@777 270 Atomic::cmpxchg_ptr((PerRegionTable*)ReserveParTableExpansion,
ysr@777 271 &_par_tables, NULL);
ysr@777 272 if (res != NULL) return;
ysr@777 273 // Otherwise, we reserved the right to do the expansion.
ysr@777 274
ysr@777 275 PerRegionTable** ptables = NEW_C_HEAP_ARRAY(PerRegionTable*, n);
ysr@777 276 for (int i = 0; i < n; i++) {
ysr@777 277 PerRegionTable* ptable = PerRegionTable::alloc(hr());
ysr@777 278 ptables[i] = ptable;
ysr@777 279 }
ysr@777 280 // Here we do not need an atomic.
ysr@777 281 _par_tables = ptables;
ysr@777 282 #if COUNT_PAR_EXPANDS
ysr@777 283 print_par_expand();
ysr@777 284 #endif
ysr@777 285 // We must put this table on the expanded list.
ysr@777 286 PosParPRT* exp_head = _par_expanded_list;
ysr@777 287 while (true) {
ysr@777 288 set_next_par_expanded(exp_head);
ysr@777 289 PosParPRT* res =
ysr@777 290 (PosParPRT*)
ysr@777 291 Atomic::cmpxchg_ptr(this, &_par_expanded_list, exp_head);
ysr@777 292 if (res == exp_head) return;
ysr@777 293 // Otherwise.
ysr@777 294 exp_head = res;
ysr@777 295 }
ysr@777 296 ShouldNotReachHere();
ysr@777 297 }
ysr@777 298 }
ysr@777 299
ysr@777 300 void par_contract() {
ysr@777 301 assert(_par_tables != NULL, "Precondition.");
ysr@777 302 int n = HeapRegionRemSet::num_par_rem_sets()-1;
ysr@777 303 for (int i = 0; i < n; i++) {
ysr@777 304 _par_tables[i]->union_bitmap_into(bm());
ysr@777 305 PerRegionTable::free(_par_tables[i]);
ysr@777 306 _par_tables[i] = NULL;
ysr@777 307 }
ysr@777 308 #if PRT_COUNT_OCCUPIED
ysr@777 309 // We must recount the "occupied."
ysr@777 310 recount_occupied();
ysr@777 311 #endif
ysr@777 312 FREE_C_HEAP_ARRAY(PerRegionTable*, _par_tables);
ysr@777 313 _par_tables = NULL;
ysr@777 314 #if COUNT_PAR_EXPANDS
ysr@777 315 Atomic::inc(&n_par_contracts);
ysr@777 316 Atomic::dec(&par_expand_list_len);
ysr@777 317 #endif
ysr@777 318 }
ysr@777 319
ysr@777 320 static PerRegionTable** _par_table_fl;
ysr@777 321
ysr@777 322 PosParPRT* _next;
ysr@777 323
ysr@777 324 static PosParPRT* _free_list;
ysr@777 325
ysr@777 326 PerRegionTable** par_tables() const {
ysr@777 327 assert(uintptr_t(NULL) == 0, "Assumption.");
ysr@777 328 if (uintptr_t(_par_tables) <= ReserveParTableExpansion)
ysr@777 329 return NULL;
ysr@777 330 else
ysr@777 331 return _par_tables;
ysr@777 332 }
ysr@777 333
ysr@777 334 PosParPRT* _next_par_expanded;
ysr@777 335 PosParPRT* next_par_expanded() { return _next_par_expanded; }
ysr@777 336 void set_next_par_expanded(PosParPRT* ppprt) { _next_par_expanded = ppprt; }
ysr@777 337 static PosParPRT* _par_expanded_list;
ysr@777 338
ysr@777 339 public:
ysr@777 340
ysr@777 341 PosParPRT(HeapRegion* hr) : PerRegionTable(hr), _par_tables(NULL) {}
ysr@777 342
ysr@777 343 jint occupied() const {
ysr@777 344 jint res = PerRegionTable::occupied();
ysr@777 345 if (par_tables() != NULL) {
ysr@777 346 for (int i = 0; i < HeapRegionRemSet::num_par_rem_sets()-1; i++) {
ysr@777 347 res += par_tables()[i]->occupied();
ysr@777 348 }
ysr@777 349 }
ysr@777 350 return res;
ysr@777 351 }
ysr@777 352
ysr@777 353 void init(HeapRegion* hr) {
ysr@777 354 PerRegionTable::init(hr);
ysr@777 355 _next = NULL;
ysr@777 356 if (par_tables() != NULL) {
ysr@777 357 for (int i = 0; i < HeapRegionRemSet::num_par_rem_sets()-1; i++) {
ysr@777 358 par_tables()[i]->init(hr);
ysr@777 359 }
ysr@777 360 }
ysr@777 361 }
ysr@777 362
ysr@777 363 static void free(PosParPRT* prt) {
ysr@777 364 while (true) {
ysr@777 365 PosParPRT* fl = _free_list;
ysr@777 366 prt->set_next(fl);
ysr@777 367 PosParPRT* res =
ysr@777 368 (PosParPRT*)
ysr@777 369 Atomic::cmpxchg_ptr(prt, &_free_list, fl);
ysr@777 370 if (res == fl) return;
ysr@777 371 }
ysr@777 372 ShouldNotReachHere();
ysr@777 373 }
ysr@777 374
ysr@777 375 static PosParPRT* alloc(HeapRegion* hr) {
ysr@777 376 PosParPRT* fl = _free_list;
ysr@777 377 while (fl != NULL) {
ysr@777 378 PosParPRT* nxt = fl->next();
ysr@777 379 PosParPRT* res =
ysr@777 380 (PosParPRT*)
ysr@777 381 Atomic::cmpxchg_ptr(nxt, &_free_list, fl);
ysr@777 382 if (res == fl) {
ysr@777 383 fl->init(hr);
ysr@777 384 return fl;
ysr@777 385 } else {
ysr@777 386 fl = _free_list;
ysr@777 387 }
ysr@777 388 }
ysr@777 389 assert(fl == NULL, "Loop condition.");
ysr@777 390 return new PosParPRT(hr);
ysr@777 391 }
ysr@777 392
ysr@777 393 PosParPRT* next() const { return _next; }
ysr@777 394 void set_next(PosParPRT* nxt) { _next = nxt; }
ysr@777 395 PosParPRT** next_addr() { return &_next; }
ysr@777 396
ysr@777 397 void add_reference(oop* from, int tid) {
ysr@777 398 // Expand if necessary.
ysr@777 399 PerRegionTable** pt = par_tables();
ysr@777 400 if (par_tables() == NULL && tid > 0 && hr()->is_gc_alloc_region()) {
ysr@777 401 par_expand();
ysr@777 402 pt = par_tables();
ysr@777 403 }
ysr@777 404 if (pt != NULL) {
ysr@777 405 // We always have to assume that mods to table 0 are in parallel,
ysr@777 406 // because of the claiming scheme in parallel expansion. A thread
ysr@777 407 // with tid != 0 that finds the table to be NULL, but doesn't succeed
ysr@777 408 // in claiming the right of expanding it, will end up in the else
ysr@777 409 // clause of the above if test. That thread could be delayed, and a
ysr@777 410 // thread 0 add reference could see the table expanded, and come
ysr@777 411 // here. Both threads would be adding in parallel. But we get to
ysr@777 412 // not use atomics for tids > 0.
ysr@777 413 if (tid == 0) {
ysr@777 414 PerRegionTable::add_reference(from);
ysr@777 415 } else {
ysr@777 416 pt[tid-1]->seq_add_reference(from);
ysr@777 417 }
ysr@777 418 } else {
ysr@777 419 // Not expanded -- add to the base table.
ysr@777 420 PerRegionTable::add_reference(from);
ysr@777 421 }
ysr@777 422 }
ysr@777 423
ysr@777 424 void scrub(CardTableModRefBS* ctbs, BitMap* card_bm) {
ysr@777 425 assert(_par_tables == NULL, "Precondition");
ysr@777 426 PerRegionTable::scrub(ctbs, card_bm);
ysr@777 427 }
ysr@777 428
ysr@777 429 size_t mem_size() const {
ysr@777 430 size_t res =
ysr@777 431 PerRegionTable::mem_size() + sizeof(this) - sizeof(PerRegionTable);
ysr@777 432 if (_par_tables != NULL) {
ysr@777 433 for (int i = 0; i < HeapRegionRemSet::num_par_rem_sets()-1; i++) {
ysr@777 434 res += _par_tables[i]->mem_size();
ysr@777 435 }
ysr@777 436 }
ysr@777 437 return res;
ysr@777 438 }
ysr@777 439
ysr@777 440 static size_t fl_mem_size() {
ysr@777 441 PosParPRT* cur = _free_list;
ysr@777 442 size_t res = 0;
ysr@777 443 while (cur != NULL) {
ysr@777 444 res += sizeof(PosParPRT);
ysr@777 445 cur = cur->next();
ysr@777 446 }
ysr@777 447 return res;
ysr@777 448 }
ysr@777 449
ysr@777 450 bool contains_reference(oop* from) const {
ysr@777 451 if (PerRegionTable::contains_reference(from)) return true;
ysr@777 452 if (_par_tables != NULL) {
ysr@777 453 for (int i = 0; i < HeapRegionRemSet::num_par_rem_sets()-1; i++) {
ysr@777 454 if (_par_tables[i]->contains_reference(from)) return true;
ysr@777 455 }
ysr@777 456 }
ysr@777 457 return false;
ysr@777 458 }
ysr@777 459
ysr@777 460 static void par_contract_all();
ysr@777 461
ysr@777 462 };
ysr@777 463
ysr@777 464 void PosParPRT::par_contract_all() {
ysr@777 465 PosParPRT* hd = _par_expanded_list;
ysr@777 466 while (hd != NULL) {
ysr@777 467 PosParPRT* nxt = hd->next_par_expanded();
ysr@777 468 PosParPRT* res =
ysr@777 469 (PosParPRT*)
ysr@777 470 Atomic::cmpxchg_ptr(nxt, &_par_expanded_list, hd);
ysr@777 471 if (res == hd) {
ysr@777 472 // We claimed the right to contract this table.
ysr@777 473 hd->set_next_par_expanded(NULL);
ysr@777 474 hd->par_contract();
ysr@777 475 hd = _par_expanded_list;
ysr@777 476 } else {
ysr@777 477 hd = res;
ysr@777 478 }
ysr@777 479 }
ysr@777 480 }
ysr@777 481
ysr@777 482 PosParPRT* PosParPRT::_free_list = NULL;
ysr@777 483 PosParPRT* PosParPRT::_par_expanded_list = NULL;
ysr@777 484
ysr@777 485 jint OtherRegionsTable::_cache_probes = 0;
ysr@777 486 jint OtherRegionsTable::_cache_hits = 0;
ysr@777 487
ysr@777 488 size_t OtherRegionsTable::_max_fine_entries = 0;
ysr@777 489 size_t OtherRegionsTable::_mod_max_fine_entries_mask = 0;
ysr@777 490 #if SAMPLE_FOR_EVICTION
ysr@777 491 size_t OtherRegionsTable::_fine_eviction_stride = 0;
ysr@777 492 size_t OtherRegionsTable::_fine_eviction_sample_size = 0;
ysr@777 493 #endif
ysr@777 494
ysr@777 495 OtherRegionsTable::OtherRegionsTable(HeapRegion* hr) :
ysr@777 496 _g1h(G1CollectedHeap::heap()),
ysr@777 497 _m(Mutex::leaf, "An OtherRegionsTable lock", true),
ysr@777 498 _hr(hr),
ysr@777 499 _coarse_map(G1CollectedHeap::heap()->max_regions(),
ysr@777 500 false /* in-resource-area */),
ysr@777 501 _fine_grain_regions(NULL),
ysr@777 502 _n_fine_entries(0), _n_coarse_entries(0),
ysr@777 503 #if SAMPLE_FOR_EVICTION
ysr@777 504 _fine_eviction_start(0),
ysr@777 505 #endif
ysr@777 506 _sparse_table(hr)
ysr@777 507 {
ysr@777 508 typedef PosParPRT* PosParPRTPtr;
ysr@777 509 if (_max_fine_entries == 0) {
ysr@777 510 assert(_mod_max_fine_entries_mask == 0, "Both or none.");
kvn@1080 511 _max_fine_entries = (size_t)(1 << G1LogRSRegionEntries);
ysr@777 512 _mod_max_fine_entries_mask = _max_fine_entries - 1;
ysr@777 513 #if SAMPLE_FOR_EVICTION
ysr@777 514 assert(_fine_eviction_sample_size == 0
ysr@777 515 && _fine_eviction_stride == 0, "All init at same time.");
ysr@777 516 _fine_eviction_sample_size = MAX2((size_t)4, (size_t)G1LogRSRegionEntries);
ysr@777 517 _fine_eviction_stride = _max_fine_entries / _fine_eviction_sample_size;
ysr@777 518 #endif
ysr@777 519 }
ysr@777 520 _fine_grain_regions = new PosParPRTPtr[_max_fine_entries];
ysr@777 521 if (_fine_grain_regions == NULL)
ysr@777 522 vm_exit_out_of_memory(sizeof(void*)*_max_fine_entries,
ysr@777 523 "Failed to allocate _fine_grain_entries.");
ysr@777 524 for (size_t i = 0; i < _max_fine_entries; i++) {
ysr@777 525 _fine_grain_regions[i] = NULL;
ysr@777 526 }
ysr@777 527 }
ysr@777 528
ysr@777 529 int** OtherRegionsTable::_from_card_cache = NULL;
ysr@777 530 size_t OtherRegionsTable::_from_card_cache_max_regions = 0;
ysr@777 531 size_t OtherRegionsTable::_from_card_cache_mem_size = 0;
ysr@777 532
ysr@777 533 void OtherRegionsTable::init_from_card_cache(size_t max_regions) {
ysr@777 534 _from_card_cache_max_regions = max_regions;
ysr@777 535
ysr@777 536 int n_par_rs = HeapRegionRemSet::num_par_rem_sets();
ysr@777 537 _from_card_cache = NEW_C_HEAP_ARRAY(int*, n_par_rs);
ysr@777 538 for (int i = 0; i < n_par_rs; i++) {
ysr@777 539 _from_card_cache[i] = NEW_C_HEAP_ARRAY(int, max_regions);
ysr@777 540 for (size_t j = 0; j < max_regions; j++) {
ysr@777 541 _from_card_cache[i][j] = -1; // An invalid value.
ysr@777 542 }
ysr@777 543 }
ysr@777 544 _from_card_cache_mem_size = n_par_rs * max_regions * sizeof(int);
ysr@777 545 }
ysr@777 546
ysr@777 547 void OtherRegionsTable::shrink_from_card_cache(size_t new_n_regs) {
ysr@777 548 for (int i = 0; i < HeapRegionRemSet::num_par_rem_sets(); i++) {
ysr@777 549 assert(new_n_regs <= _from_card_cache_max_regions, "Must be within max.");
ysr@777 550 for (size_t j = new_n_regs; j < _from_card_cache_max_regions; j++) {
ysr@777 551 _from_card_cache[i][j] = -1; // An invalid value.
ysr@777 552 }
ysr@777 553 }
ysr@777 554 }
ysr@777 555
ysr@777 556 #ifndef PRODUCT
ysr@777 557 void OtherRegionsTable::print_from_card_cache() {
ysr@777 558 for (int i = 0; i < HeapRegionRemSet::num_par_rem_sets(); i++) {
ysr@777 559 for (size_t j = 0; j < _from_card_cache_max_regions; j++) {
ysr@777 560 gclog_or_tty->print_cr("_from_card_cache[%d][%d] = %d.",
ysr@777 561 i, j, _from_card_cache[i][j]);
ysr@777 562 }
ysr@777 563 }
ysr@777 564 }
ysr@777 565 #endif
ysr@777 566
ysr@777 567 void OtherRegionsTable::add_reference(oop* from, int tid) {
ysr@777 568 size_t cur_hrs_ind = hr()->hrs_index();
ysr@777 569
ysr@777 570 #if HRRS_VERBOSE
ysr@777 571 gclog_or_tty->print_cr("ORT::add_reference_work(" PTR_FORMAT "->" PTR_FORMAT ").",
ysr@777 572 from, *from);
ysr@777 573 #endif
ysr@777 574
ysr@777 575 int from_card = (int)(uintptr_t(from) >> CardTableModRefBS::card_shift);
ysr@777 576
ysr@777 577 #if HRRS_VERBOSE
ysr@777 578 gclog_or_tty->print_cr("Table for [" PTR_FORMAT "...): card %d (cache = %d)",
ysr@777 579 hr()->bottom(), from_card,
ysr@777 580 _from_card_cache[tid][cur_hrs_ind]);
ysr@777 581 #endif
ysr@777 582
ysr@777 583 #define COUNT_CACHE 0
ysr@777 584 #if COUNT_CACHE
ysr@777 585 jint p = Atomic::add(1, &_cache_probes);
ysr@777 586 if ((p % 10000) == 0) {
ysr@777 587 jint hits = _cache_hits;
ysr@777 588 gclog_or_tty->print_cr("%d/%d = %5.2f%% RS cache hits.",
ysr@777 589 _cache_hits, p, 100.0* (float)hits/(float)p);
ysr@777 590 }
ysr@777 591 #endif
ysr@777 592 if (from_card == _from_card_cache[tid][cur_hrs_ind]) {
ysr@777 593 #if HRRS_VERBOSE
ysr@777 594 gclog_or_tty->print_cr(" from-card cache hit.");
ysr@777 595 #endif
ysr@777 596 #if COUNT_CACHE
ysr@777 597 Atomic::inc(&_cache_hits);
ysr@777 598 #endif
ysr@777 599 assert(contains_reference(from), "We just added it!");
ysr@777 600 return;
ysr@777 601 } else {
ysr@777 602 _from_card_cache[tid][cur_hrs_ind] = from_card;
ysr@777 603 }
ysr@777 604
ysr@777 605 // Note that this may be a continued H region.
ysr@777 606 HeapRegion* from_hr = _g1h->heap_region_containing_raw(from);
ysr@777 607 size_t from_hrs_ind = (size_t)from_hr->hrs_index();
ysr@777 608
ysr@777 609 // If the region is already coarsened, return.
ysr@777 610 if (_coarse_map.at(from_hrs_ind)) {
ysr@777 611 #if HRRS_VERBOSE
ysr@777 612 gclog_or_tty->print_cr(" coarse map hit.");
ysr@777 613 #endif
ysr@777 614 assert(contains_reference(from), "We just added it!");
ysr@777 615 return;
ysr@777 616 }
ysr@777 617
ysr@777 618 // Otherwise find a per-region table to add it to.
ysr@777 619 size_t ind = from_hrs_ind & _mod_max_fine_entries_mask;
ysr@777 620 PosParPRT* prt = find_region_table(ind, from_hr);
ysr@777 621 if (prt == NULL) {
ysr@777 622 MutexLockerEx x(&_m, Mutex::_no_safepoint_check_flag);
ysr@777 623 // Confirm that it's really not there...
ysr@777 624 prt = find_region_table(ind, from_hr);
ysr@777 625 if (prt == NULL) {
ysr@777 626
ysr@777 627 uintptr_t from_hr_bot_card_index =
ysr@777 628 uintptr_t(from_hr->bottom())
ysr@777 629 >> CardTableModRefBS::card_shift;
ysr@777 630 int card_index = from_card - from_hr_bot_card_index;
ysr@777 631 assert(0 <= card_index && card_index < PosParPRT::CardsPerRegion,
ysr@777 632 "Must be in range.");
ysr@777 633 if (G1HRRSUseSparseTable &&
ysr@777 634 _sparse_table.add_card((short) from_hrs_ind, card_index)) {
ysr@777 635 if (G1RecordHRRSOops) {
ysr@777 636 HeapRegionRemSet::record(hr(), from);
ysr@777 637 #if HRRS_VERBOSE
ysr@777 638 gclog_or_tty->print(" Added card " PTR_FORMAT " to region "
ysr@777 639 "[" PTR_FORMAT "...) for ref " PTR_FORMAT ".\n",
ysr@777 640 align_size_down(uintptr_t(from),
ysr@777 641 CardTableModRefBS::card_size),
ysr@777 642 hr()->bottom(), from);
ysr@777 643 #endif
ysr@777 644 }
ysr@777 645 #if HRRS_VERBOSE
ysr@777 646 gclog_or_tty->print_cr(" added card to sparse table.");
ysr@777 647 #endif
ysr@777 648 assert(contains_reference_locked(from), "We just added it!");
ysr@777 649 return;
ysr@777 650 } else {
ysr@777 651 #if HRRS_VERBOSE
ysr@777 652 gclog_or_tty->print_cr(" [tid %d] sparse table entry "
ysr@777 653 "overflow(f: %d, t: %d)",
ysr@777 654 tid, from_hrs_ind, cur_hrs_ind);
ysr@777 655 #endif
ysr@777 656 }
ysr@777 657
ysr@777 658 // Otherwise, transfer from sparse to fine-grain.
ysr@777 659 short cards[SparsePRTEntry::CardsPerEntry];
ysr@777 660 if (G1HRRSUseSparseTable) {
ysr@777 661 bool res = _sparse_table.get_cards((short) from_hrs_ind, &cards[0]);
ysr@777 662 assert(res, "There should have been an entry");
ysr@777 663 }
ysr@777 664
ysr@777 665 if (_n_fine_entries == _max_fine_entries) {
ysr@777 666 prt = delete_region_table();
ysr@777 667 } else {
ysr@777 668 prt = PosParPRT::alloc(from_hr);
ysr@777 669 }
ysr@777 670 prt->init(from_hr);
ysr@777 671 // Record the outgoing pointer in the from_region's outgoing bitmap.
ysr@777 672 from_hr->rem_set()->add_outgoing_reference(hr());
ysr@777 673
ysr@777 674 PosParPRT* first_prt = _fine_grain_regions[ind];
ysr@777 675 prt->set_next(first_prt); // XXX Maybe move to init?
ysr@777 676 _fine_grain_regions[ind] = prt;
ysr@777 677 _n_fine_entries++;
ysr@777 678
ysr@777 679 // Add in the cards from the sparse table.
ysr@777 680 if (G1HRRSUseSparseTable) {
ysr@777 681 for (int i = 0; i < SparsePRTEntry::CardsPerEntry; i++) {
ysr@777 682 short c = cards[i];
ysr@777 683 if (c != SparsePRTEntry::NullEntry) {
ysr@777 684 prt->add_card(c);
ysr@777 685 }
ysr@777 686 }
ysr@777 687 // Now we can delete the sparse entry.
ysr@777 688 bool res = _sparse_table.delete_entry((short) from_hrs_ind);
ysr@777 689 assert(res, "It should have been there.");
ysr@777 690 }
ysr@777 691 }
ysr@777 692 assert(prt != NULL && prt->hr() == from_hr, "consequence");
ysr@777 693 }
ysr@777 694 // Note that we can't assert "prt->hr() == from_hr", because of the
ysr@777 695 // possibility of concurrent reuse. But see head comment of
ysr@777 696 // OtherRegionsTable for why this is OK.
ysr@777 697 assert(prt != NULL, "Inv");
ysr@777 698
ysr@777 699 prt->add_reference(from, tid);
ysr@777 700 if (G1RecordHRRSOops) {
ysr@777 701 HeapRegionRemSet::record(hr(), from);
ysr@777 702 #if HRRS_VERBOSE
ysr@777 703 gclog_or_tty->print("Added card " PTR_FORMAT " to region "
ysr@777 704 "[" PTR_FORMAT "...) for ref " PTR_FORMAT ".\n",
ysr@777 705 align_size_down(uintptr_t(from),
ysr@777 706 CardTableModRefBS::card_size),
ysr@777 707 hr()->bottom(), from);
ysr@777 708 #endif
ysr@777 709 }
ysr@777 710 assert(contains_reference(from), "We just added it!");
ysr@777 711 }
ysr@777 712
ysr@777 713 PosParPRT*
ysr@777 714 OtherRegionsTable::find_region_table(size_t ind, HeapRegion* hr) const {
ysr@777 715 assert(0 <= ind && ind < _max_fine_entries, "Preconditions.");
ysr@777 716 PosParPRT* prt = _fine_grain_regions[ind];
ysr@777 717 while (prt != NULL && prt->hr() != hr) {
ysr@777 718 prt = prt->next();
ysr@777 719 }
ysr@777 720 // Loop postcondition is the method postcondition.
ysr@777 721 return prt;
ysr@777 722 }
ysr@777 723
ysr@777 724
ysr@777 725 #define DRT_CENSUS 0
ysr@777 726
ysr@777 727 #if DRT_CENSUS
ysr@777 728 static const int HistoSize = 6;
ysr@777 729 static int global_histo[HistoSize] = { 0, 0, 0, 0, 0, 0 };
ysr@777 730 static int coarsenings = 0;
ysr@777 731 static int occ_sum = 0;
ysr@777 732 #endif
ysr@777 733
ysr@777 734 jint OtherRegionsTable::_n_coarsenings = 0;
ysr@777 735
ysr@777 736 PosParPRT* OtherRegionsTable::delete_region_table() {
ysr@777 737 #if DRT_CENSUS
ysr@777 738 int histo[HistoSize] = { 0, 0, 0, 0, 0, 0 };
ysr@777 739 const int histo_limits[] = { 1, 4, 16, 64, 256, 2048 };
ysr@777 740 #endif
ysr@777 741
ysr@777 742 assert(_m.owned_by_self(), "Precondition");
ysr@777 743 assert(_n_fine_entries == _max_fine_entries, "Precondition");
ysr@777 744 PosParPRT* max = NULL;
ysr@777 745 jint max_occ = 0;
ysr@777 746 PosParPRT** max_prev;
ysr@777 747 size_t max_ind;
ysr@777 748
ysr@777 749 #if SAMPLE_FOR_EVICTION
ysr@777 750 size_t i = _fine_eviction_start;
ysr@777 751 for (size_t k = 0; k < _fine_eviction_sample_size; k++) {
ysr@777 752 size_t ii = i;
ysr@777 753 // Make sure we get a non-NULL sample.
ysr@777 754 while (_fine_grain_regions[ii] == NULL) {
ysr@777 755 ii++;
ysr@777 756 if (ii == _max_fine_entries) ii = 0;
ysr@777 757 guarantee(ii != i, "We must find one.");
ysr@777 758 }
ysr@777 759 PosParPRT** prev = &_fine_grain_regions[ii];
ysr@777 760 PosParPRT* cur = *prev;
ysr@777 761 while (cur != NULL) {
ysr@777 762 jint cur_occ = cur->occupied();
ysr@777 763 if (max == NULL || cur_occ > max_occ) {
ysr@777 764 max = cur;
ysr@777 765 max_prev = prev;
ysr@777 766 max_ind = i;
ysr@777 767 max_occ = cur_occ;
ysr@777 768 }
ysr@777 769 prev = cur->next_addr();
ysr@777 770 cur = cur->next();
ysr@777 771 }
ysr@777 772 i = i + _fine_eviction_stride;
ysr@777 773 if (i >= _n_fine_entries) i = i - _n_fine_entries;
ysr@777 774 }
ysr@777 775 _fine_eviction_start++;
ysr@777 776 if (_fine_eviction_start >= _n_fine_entries)
ysr@777 777 _fine_eviction_start -= _n_fine_entries;
ysr@777 778 #else
ysr@777 779 for (int i = 0; i < _max_fine_entries; i++) {
ysr@777 780 PosParPRT** prev = &_fine_grain_regions[i];
ysr@777 781 PosParPRT* cur = *prev;
ysr@777 782 while (cur != NULL) {
ysr@777 783 jint cur_occ = cur->occupied();
ysr@777 784 #if DRT_CENSUS
ysr@777 785 for (int k = 0; k < HistoSize; k++) {
ysr@777 786 if (cur_occ <= histo_limits[k]) {
ysr@777 787 histo[k]++; global_histo[k]++; break;
ysr@777 788 }
ysr@777 789 }
ysr@777 790 #endif
ysr@777 791 if (max == NULL || cur_occ > max_occ) {
ysr@777 792 max = cur;
ysr@777 793 max_prev = prev;
ysr@777 794 max_ind = i;
ysr@777 795 max_occ = cur_occ;
ysr@777 796 }
ysr@777 797 prev = cur->next_addr();
ysr@777 798 cur = cur->next();
ysr@777 799 }
ysr@777 800 }
ysr@777 801 #endif
ysr@777 802 // XXX
ysr@777 803 guarantee(max != NULL, "Since _n_fine_entries > 0");
ysr@777 804 #if DRT_CENSUS
ysr@777 805 gclog_or_tty->print_cr("In a coarsening: histo of occs:");
ysr@777 806 for (int k = 0; k < HistoSize; k++) {
ysr@777 807 gclog_or_tty->print_cr(" <= %4d: %5d.", histo_limits[k], histo[k]);
ysr@777 808 }
ysr@777 809 coarsenings++;
ysr@777 810 occ_sum += max_occ;
ysr@777 811 if ((coarsenings % 100) == 0) {
ysr@777 812 gclog_or_tty->print_cr("\ncoarsenings = %d; global summary:", coarsenings);
ysr@777 813 for (int k = 0; k < HistoSize; k++) {
ysr@777 814 gclog_or_tty->print_cr(" <= %4d: %5d.", histo_limits[k], global_histo[k]);
ysr@777 815 }
ysr@777 816 gclog_or_tty->print_cr("Avg occ of deleted region = %6.2f.",
ysr@777 817 (float)occ_sum/(float)coarsenings);
ysr@777 818 }
ysr@777 819 #endif
ysr@777 820
ysr@777 821 // Set the corresponding coarse bit.
ysr@777 822 int max_hrs_index = max->hr()->hrs_index();
ysr@777 823 if (!_coarse_map.at(max_hrs_index)) {
ysr@777 824 _coarse_map.at_put(max_hrs_index, true);
ysr@777 825 _n_coarse_entries++;
ysr@777 826 #if 0
ysr@777 827 gclog_or_tty->print("Coarsened entry in region [" PTR_FORMAT "...] "
ysr@777 828 "for region [" PTR_FORMAT "...] (%d coarse entries).\n",
ysr@777 829 hr()->bottom(),
ysr@777 830 max->hr()->bottom(),
ysr@777 831 _n_coarse_entries);
ysr@777 832 #endif
ysr@777 833 }
ysr@777 834
ysr@777 835 // Unsplice.
ysr@777 836 *max_prev = max->next();
ysr@777 837 Atomic::inc(&_n_coarsenings);
ysr@777 838 _n_fine_entries--;
ysr@777 839 return max;
ysr@777 840 }
ysr@777 841
ysr@777 842
ysr@777 843 // At present, this must be called stop-world single-threaded.
ysr@777 844 void OtherRegionsTable::scrub(CardTableModRefBS* ctbs,
ysr@777 845 BitMap* region_bm, BitMap* card_bm) {
ysr@777 846 // First eliminated garbage regions from the coarse map.
ysr@777 847 if (G1RSScrubVerbose)
ysr@777 848 gclog_or_tty->print_cr("Scrubbing region %d:", hr()->hrs_index());
ysr@777 849
ysr@777 850 assert(_coarse_map.size() == region_bm->size(), "Precondition");
ysr@777 851 if (G1RSScrubVerbose)
ysr@777 852 gclog_or_tty->print(" Coarse map: before = %d...", _n_coarse_entries);
ysr@777 853 _coarse_map.set_intersection(*region_bm);
ysr@777 854 _n_coarse_entries = _coarse_map.count_one_bits();
ysr@777 855 if (G1RSScrubVerbose)
ysr@777 856 gclog_or_tty->print_cr(" after = %d.", _n_coarse_entries);
ysr@777 857
ysr@777 858 // Now do the fine-grained maps.
ysr@777 859 for (size_t i = 0; i < _max_fine_entries; i++) {
ysr@777 860 PosParPRT* cur = _fine_grain_regions[i];
ysr@777 861 PosParPRT** prev = &_fine_grain_regions[i];
ysr@777 862 while (cur != NULL) {
ysr@777 863 PosParPRT* nxt = cur->next();
ysr@777 864 // If the entire region is dead, eliminate.
ysr@777 865 if (G1RSScrubVerbose)
ysr@777 866 gclog_or_tty->print_cr(" For other region %d:", cur->hr()->hrs_index());
ysr@777 867 if (!region_bm->at(cur->hr()->hrs_index())) {
ysr@777 868 *prev = nxt;
ysr@777 869 cur->set_next(NULL);
ysr@777 870 _n_fine_entries--;
ysr@777 871 if (G1RSScrubVerbose)
ysr@777 872 gclog_or_tty->print_cr(" deleted via region map.");
ysr@777 873 PosParPRT::free(cur);
ysr@777 874 } else {
ysr@777 875 // Do fine-grain elimination.
ysr@777 876 if (G1RSScrubVerbose)
ysr@777 877 gclog_or_tty->print(" occ: before = %4d.", cur->occupied());
ysr@777 878 cur->scrub(ctbs, card_bm);
ysr@777 879 if (G1RSScrubVerbose)
ysr@777 880 gclog_or_tty->print_cr(" after = %4d.", cur->occupied());
ysr@777 881 // Did that empty the table completely?
ysr@777 882 if (cur->occupied() == 0) {
ysr@777 883 *prev = nxt;
ysr@777 884 cur->set_next(NULL);
ysr@777 885 _n_fine_entries--;
ysr@777 886 PosParPRT::free(cur);
ysr@777 887 } else {
ysr@777 888 prev = cur->next_addr();
ysr@777 889 }
ysr@777 890 }
ysr@777 891 cur = nxt;
ysr@777 892 }
ysr@777 893 }
ysr@777 894 // Since we may have deleted a from_card_cache entry from the RS, clear
ysr@777 895 // the FCC.
ysr@777 896 clear_fcc();
ysr@777 897 }
ysr@777 898
ysr@777 899
ysr@777 900 size_t OtherRegionsTable::occupied() const {
ysr@777 901 // Cast away const in this case.
ysr@777 902 MutexLockerEx x((Mutex*)&_m, Mutex::_no_safepoint_check_flag);
ysr@777 903 size_t sum = occ_fine();
ysr@777 904 sum += occ_sparse();
ysr@777 905 sum += occ_coarse();
ysr@777 906 return sum;
ysr@777 907 }
ysr@777 908
ysr@777 909 size_t OtherRegionsTable::occ_fine() const {
ysr@777 910 size_t sum = 0;
ysr@777 911 for (size_t i = 0; i < _max_fine_entries; i++) {
ysr@777 912 PosParPRT* cur = _fine_grain_regions[i];
ysr@777 913 while (cur != NULL) {
ysr@777 914 sum += cur->occupied();
ysr@777 915 cur = cur->next();
ysr@777 916 }
ysr@777 917 }
ysr@777 918 return sum;
ysr@777 919 }
ysr@777 920
ysr@777 921 size_t OtherRegionsTable::occ_coarse() const {
ysr@777 922 return (_n_coarse_entries * PosParPRT::CardsPerRegion);
ysr@777 923 }
ysr@777 924
ysr@777 925 size_t OtherRegionsTable::occ_sparse() const {
ysr@777 926 return _sparse_table.occupied();
ysr@777 927 }
ysr@777 928
ysr@777 929 size_t OtherRegionsTable::mem_size() const {
ysr@777 930 // Cast away const in this case.
ysr@777 931 MutexLockerEx x((Mutex*)&_m, Mutex::_no_safepoint_check_flag);
ysr@777 932 size_t sum = 0;
ysr@777 933 for (size_t i = 0; i < _max_fine_entries; i++) {
ysr@777 934 PosParPRT* cur = _fine_grain_regions[i];
ysr@777 935 while (cur != NULL) {
ysr@777 936 sum += cur->mem_size();
ysr@777 937 cur = cur->next();
ysr@777 938 }
ysr@777 939 }
ysr@777 940 sum += (sizeof(PosParPRT*) * _max_fine_entries);
ysr@777 941 sum += (_coarse_map.size_in_words() * HeapWordSize);
ysr@777 942 sum += (_sparse_table.mem_size());
ysr@777 943 sum += sizeof(*this) - sizeof(_sparse_table); // Avoid double counting above.
ysr@777 944 return sum;
ysr@777 945 }
ysr@777 946
ysr@777 947 size_t OtherRegionsTable::static_mem_size() {
ysr@777 948 return _from_card_cache_mem_size;
ysr@777 949 }
ysr@777 950
ysr@777 951 size_t OtherRegionsTable::fl_mem_size() {
ysr@777 952 return PerRegionTable::fl_mem_size() + PosParPRT::fl_mem_size();
ysr@777 953 }
ysr@777 954
ysr@777 955 void OtherRegionsTable::clear_fcc() {
ysr@777 956 for (int i = 0; i < HeapRegionRemSet::num_par_rem_sets(); i++) {
ysr@777 957 _from_card_cache[i][hr()->hrs_index()] = -1;
ysr@777 958 }
ysr@777 959 }
ysr@777 960
ysr@777 961 void OtherRegionsTable::clear() {
ysr@777 962 MutexLockerEx x(&_m, Mutex::_no_safepoint_check_flag);
ysr@777 963 for (size_t i = 0; i < _max_fine_entries; i++) {
ysr@777 964 PosParPRT* cur = _fine_grain_regions[i];
ysr@777 965 while (cur != NULL) {
ysr@777 966 PosParPRT* nxt = cur->next();
ysr@777 967 PosParPRT::free(cur);
ysr@777 968 cur = nxt;
ysr@777 969 }
ysr@777 970 _fine_grain_regions[i] = NULL;
ysr@777 971 }
ysr@777 972 _sparse_table.clear();
ysr@777 973 _coarse_map.clear();
ysr@777 974 _n_fine_entries = 0;
ysr@777 975 _n_coarse_entries = 0;
ysr@777 976
ysr@777 977 clear_fcc();
ysr@777 978 }
ysr@777 979
ysr@777 980 void OtherRegionsTable::clear_incoming_entry(HeapRegion* from_hr) {
ysr@777 981 MutexLockerEx x(&_m, Mutex::_no_safepoint_check_flag);
ysr@777 982 size_t hrs_ind = (size_t)from_hr->hrs_index();
ysr@777 983 size_t ind = hrs_ind & _mod_max_fine_entries_mask;
ysr@777 984 if (del_single_region_table(ind, from_hr)) {
ysr@777 985 assert(!_coarse_map.at(hrs_ind), "Inv");
ysr@777 986 } else {
ysr@777 987 _coarse_map.par_at_put(hrs_ind, 0);
ysr@777 988 }
ysr@777 989 // Check to see if any of the fcc entries come from here.
ysr@777 990 int hr_ind = hr()->hrs_index();
ysr@777 991 for (int tid = 0; tid < HeapRegionRemSet::num_par_rem_sets(); tid++) {
ysr@777 992 int fcc_ent = _from_card_cache[tid][hr_ind];
ysr@777 993 if (fcc_ent != -1) {
ysr@777 994 HeapWord* card_addr = (HeapWord*)
ysr@777 995 (uintptr_t(fcc_ent) << CardTableModRefBS::card_shift);
ysr@777 996 if (hr()->is_in_reserved(card_addr)) {
ysr@777 997 // Clear the from card cache.
ysr@777 998 _from_card_cache[tid][hr_ind] = -1;
ysr@777 999 }
ysr@777 1000 }
ysr@777 1001 }
ysr@777 1002 }
ysr@777 1003
ysr@777 1004 bool OtherRegionsTable::del_single_region_table(size_t ind,
ysr@777 1005 HeapRegion* hr) {
ysr@777 1006 assert(0 <= ind && ind < _max_fine_entries, "Preconditions.");
ysr@777 1007 PosParPRT** prev_addr = &_fine_grain_regions[ind];
ysr@777 1008 PosParPRT* prt = *prev_addr;
ysr@777 1009 while (prt != NULL && prt->hr() != hr) {
ysr@777 1010 prev_addr = prt->next_addr();
ysr@777 1011 prt = prt->next();
ysr@777 1012 }
ysr@777 1013 if (prt != NULL) {
ysr@777 1014 assert(prt->hr() == hr, "Loop postcondition.");
ysr@777 1015 *prev_addr = prt->next();
ysr@777 1016 PosParPRT::free(prt);
ysr@777 1017 _n_fine_entries--;
ysr@777 1018 return true;
ysr@777 1019 } else {
ysr@777 1020 return false;
ysr@777 1021 }
ysr@777 1022 }
ysr@777 1023
ysr@777 1024 bool OtherRegionsTable::contains_reference(oop* from) const {
ysr@777 1025 // Cast away const in this case.
ysr@777 1026 MutexLockerEx x((Mutex*)&_m, Mutex::_no_safepoint_check_flag);
ysr@777 1027 return contains_reference_locked(from);
ysr@777 1028 }
ysr@777 1029
ysr@777 1030 bool OtherRegionsTable::contains_reference_locked(oop* from) const {
ysr@777 1031 HeapRegion* hr = _g1h->heap_region_containing_raw(from);
ysr@777 1032 if (hr == NULL) return false;
ysr@777 1033 size_t hr_ind = hr->hrs_index();
ysr@777 1034 // Is this region in the coarse map?
ysr@777 1035 if (_coarse_map.at(hr_ind)) return true;
ysr@777 1036
ysr@777 1037 PosParPRT* prt = find_region_table(hr_ind & _mod_max_fine_entries_mask,
ysr@777 1038 hr);
ysr@777 1039 if (prt != NULL) {
ysr@777 1040 return prt->contains_reference(from);
ysr@777 1041
ysr@777 1042 } else {
ysr@777 1043 uintptr_t from_card =
ysr@777 1044 (uintptr_t(from) >> CardTableModRefBS::card_shift);
ysr@777 1045 uintptr_t hr_bot_card_index =
ysr@777 1046 uintptr_t(hr->bottom()) >> CardTableModRefBS::card_shift;
ysr@777 1047 assert(from_card >= hr_bot_card_index, "Inv");
ysr@777 1048 int card_index = from_card - hr_bot_card_index;
ysr@777 1049 return _sparse_table.contains_card((short)hr_ind, card_index);
ysr@777 1050 }
ysr@777 1051
ysr@777 1052
ysr@777 1053 }
ysr@777 1054
iveresov@1230 1055 // Determines how many threads can add records to an rset in parallel.
iveresov@1230 1056 // This can be done by either mutator threads together with the
iveresov@1230 1057 // concurrent refinement threads or GC threads.
ysr@777 1058 int HeapRegionRemSet::num_par_rem_sets() {
iveresov@1230 1059 return (int)MAX2(DirtyCardQueueSet::num_par_ids() + ConcurrentG1Refine::thread_num(), ParallelGCThreads);
ysr@777 1060 }
ysr@777 1061
ysr@777 1062 HeapRegionRemSet::HeapRegionRemSet(G1BlockOffsetSharedArray* bosa,
ysr@777 1063 HeapRegion* hr)
ysr@777 1064 : _bosa(bosa), _other_regions(hr),
ysr@777 1065 _outgoing_region_map(G1CollectedHeap::heap()->max_regions(),
ysr@777 1066 false /* in-resource-area */),
ysr@777 1067 _iter_state(Unclaimed)
ysr@777 1068 {}
ysr@777 1069
ysr@777 1070
ysr@777 1071 void HeapRegionRemSet::init_for_par_iteration() {
ysr@777 1072 _iter_state = Unclaimed;
ysr@777 1073 }
ysr@777 1074
ysr@777 1075 bool HeapRegionRemSet::claim_iter() {
ysr@777 1076 if (_iter_state != Unclaimed) return false;
ysr@777 1077 jint res = Atomic::cmpxchg(Claimed, (jint*)(&_iter_state), Unclaimed);
ysr@777 1078 return (res == Unclaimed);
ysr@777 1079 }
ysr@777 1080
ysr@777 1081 void HeapRegionRemSet::set_iter_complete() {
ysr@777 1082 _iter_state = Complete;
ysr@777 1083 }
ysr@777 1084
ysr@777 1085 bool HeapRegionRemSet::iter_is_complete() {
ysr@777 1086 return _iter_state == Complete;
ysr@777 1087 }
ysr@777 1088
ysr@777 1089
ysr@777 1090 void HeapRegionRemSet::init_iterator(HeapRegionRemSetIterator* iter) const {
ysr@777 1091 iter->initialize(this);
ysr@777 1092 }
ysr@777 1093
ysr@777 1094 #ifndef PRODUCT
ysr@777 1095 void HeapRegionRemSet::print() const {
ysr@777 1096 HeapRegionRemSetIterator iter;
ysr@777 1097 init_iterator(&iter);
ysr@777 1098 size_t card_index;
ysr@777 1099 while (iter.has_next(card_index)) {
ysr@777 1100 HeapWord* card_start =
ysr@777 1101 G1CollectedHeap::heap()->bot_shared()->address_for_index(card_index);
ysr@777 1102 gclog_or_tty->print_cr(" Card " PTR_FORMAT ".", card_start);
ysr@777 1103 }
ysr@777 1104 // XXX
ysr@777 1105 if (iter.n_yielded() != occupied()) {
ysr@777 1106 gclog_or_tty->print_cr("Yielded disagrees with occupied:");
ysr@777 1107 gclog_or_tty->print_cr(" %6d yielded (%6d coarse, %6d fine).",
ysr@777 1108 iter.n_yielded(),
ysr@777 1109 iter.n_yielded_coarse(), iter.n_yielded_fine());
ysr@777 1110 gclog_or_tty->print_cr(" %6d occ (%6d coarse, %6d fine).",
ysr@777 1111 occupied(), occ_coarse(), occ_fine());
ysr@777 1112 }
ysr@777 1113 guarantee(iter.n_yielded() == occupied(),
ysr@777 1114 "We should have yielded all the represented cards.");
ysr@777 1115 }
ysr@777 1116 #endif
ysr@777 1117
ysr@777 1118 void HeapRegionRemSet::cleanup() {
ysr@777 1119 SparsePRT::cleanup_all();
ysr@777 1120 }
ysr@777 1121
ysr@777 1122 void HeapRegionRemSet::par_cleanup() {
ysr@777 1123 PosParPRT::par_contract_all();
ysr@777 1124 }
ysr@777 1125
ysr@777 1126 void HeapRegionRemSet::add_outgoing_reference(HeapRegion* to_hr) {
ysr@777 1127 _outgoing_region_map.par_at_put(to_hr->hrs_index(), 1);
ysr@777 1128 }
ysr@777 1129
ysr@777 1130 void HeapRegionRemSet::clear() {
ysr@777 1131 clear_outgoing_entries();
ysr@777 1132 _outgoing_region_map.clear();
ysr@777 1133 _other_regions.clear();
ysr@777 1134 assert(occupied() == 0, "Should be clear.");
ysr@777 1135 }
ysr@777 1136
ysr@777 1137 void HeapRegionRemSet::clear_outgoing_entries() {
ysr@777 1138 G1CollectedHeap* g1h = G1CollectedHeap::heap();
ysr@777 1139 size_t i = _outgoing_region_map.get_next_one_offset(0);
ysr@777 1140 while (i < _outgoing_region_map.size()) {
ysr@777 1141 HeapRegion* to_region = g1h->region_at(i);
apetrusenko@980 1142 if (!to_region->in_collection_set()) {
apetrusenko@980 1143 to_region->rem_set()->clear_incoming_entry(hr());
apetrusenko@980 1144 }
ysr@777 1145 i = _outgoing_region_map.get_next_one_offset(i+1);
ysr@777 1146 }
ysr@777 1147 }
ysr@777 1148
ysr@777 1149
ysr@777 1150 void HeapRegionRemSet::scrub(CardTableModRefBS* ctbs,
ysr@777 1151 BitMap* region_bm, BitMap* card_bm) {
ysr@777 1152 _other_regions.scrub(ctbs, region_bm, card_bm);
ysr@777 1153 }
ysr@777 1154
ysr@777 1155 //-------------------- Iteration --------------------
ysr@777 1156
ysr@777 1157 HeapRegionRemSetIterator::
ysr@777 1158 HeapRegionRemSetIterator() :
ysr@777 1159 _hrrs(NULL),
ysr@777 1160 _g1h(G1CollectedHeap::heap()),
ysr@777 1161 _bosa(NULL),
ysr@777 1162 _sparse_iter(size_t(G1CollectedHeap::heap()->reserved_region().start())
ysr@777 1163 >> CardTableModRefBS::card_shift)
ysr@777 1164 {}
ysr@777 1165
ysr@777 1166 void HeapRegionRemSetIterator::initialize(const HeapRegionRemSet* hrrs) {
ysr@777 1167 _hrrs = hrrs;
ysr@777 1168 _coarse_map = &_hrrs->_other_regions._coarse_map;
ysr@777 1169 _fine_grain_regions = _hrrs->_other_regions._fine_grain_regions;
ysr@777 1170 _bosa = _hrrs->bosa();
ysr@777 1171
ysr@777 1172 _is = Sparse;
ysr@777 1173 // Set these values so that we increment to the first region.
ysr@777 1174 _coarse_cur_region_index = -1;
ysr@777 1175 _coarse_cur_region_cur_card = (PosParPRT::CardsPerRegion-1);;
ysr@777 1176
ysr@777 1177 _cur_region_cur_card = 0;
ysr@777 1178
ysr@777 1179 _fine_array_index = -1;
ysr@777 1180 _fine_cur_prt = NULL;
ysr@777 1181
ysr@777 1182 _n_yielded_coarse = 0;
ysr@777 1183 _n_yielded_fine = 0;
ysr@777 1184 _n_yielded_sparse = 0;
ysr@777 1185
ysr@777 1186 _sparse_iter.init(&hrrs->_other_regions._sparse_table);
ysr@777 1187 }
ysr@777 1188
ysr@777 1189 bool HeapRegionRemSetIterator::coarse_has_next(size_t& card_index) {
ysr@777 1190 if (_hrrs->_other_regions._n_coarse_entries == 0) return false;
ysr@777 1191 // Go to the next card.
ysr@777 1192 _coarse_cur_region_cur_card++;
ysr@777 1193 // Was the last the last card in the current region?
ysr@777 1194 if (_coarse_cur_region_cur_card == PosParPRT::CardsPerRegion) {
ysr@777 1195 // Yes: find the next region. This may leave _coarse_cur_region_index
ysr@777 1196 // Set to the last index, in which case there are no more coarse
ysr@777 1197 // regions.
ysr@777 1198 _coarse_cur_region_index =
ysr@777 1199 (int) _coarse_map->get_next_one_offset(_coarse_cur_region_index + 1);
ysr@777 1200 if ((size_t)_coarse_cur_region_index < _coarse_map->size()) {
ysr@777 1201 _coarse_cur_region_cur_card = 0;
ysr@777 1202 HeapWord* r_bot =
ysr@777 1203 _g1h->region_at(_coarse_cur_region_index)->bottom();
ysr@777 1204 _cur_region_card_offset = _bosa->index_for(r_bot);
ysr@777 1205 } else {
ysr@777 1206 return false;
ysr@777 1207 }
ysr@777 1208 }
ysr@777 1209 // If we didn't return false above, then we can yield a card.
ysr@777 1210 card_index = _cur_region_card_offset + _coarse_cur_region_cur_card;
ysr@777 1211 return true;
ysr@777 1212 }
ysr@777 1213
ysr@777 1214 void HeapRegionRemSetIterator::fine_find_next_non_null_prt() {
ysr@777 1215 // Otherwise, find the next bucket list in the array.
ysr@777 1216 _fine_array_index++;
ysr@777 1217 while (_fine_array_index < (int) OtherRegionsTable::_max_fine_entries) {
ysr@777 1218 _fine_cur_prt = _fine_grain_regions[_fine_array_index];
ysr@777 1219 if (_fine_cur_prt != NULL) return;
ysr@777 1220 else _fine_array_index++;
ysr@777 1221 }
ysr@777 1222 assert(_fine_cur_prt == NULL, "Loop post");
ysr@777 1223 }
ysr@777 1224
ysr@777 1225 bool HeapRegionRemSetIterator::fine_has_next(size_t& card_index) {
ysr@777 1226 if (fine_has_next()) {
ysr@777 1227 _cur_region_cur_card =
ysr@777 1228 _fine_cur_prt->_bm.get_next_one_offset(_cur_region_cur_card + 1);
ysr@777 1229 }
ysr@777 1230 while (!fine_has_next()) {
ysr@777 1231 if (_cur_region_cur_card == PosParPRT::CardsPerRegion) {
ysr@777 1232 _cur_region_cur_card = 0;
ysr@777 1233 _fine_cur_prt = _fine_cur_prt->next();
ysr@777 1234 }
ysr@777 1235 if (_fine_cur_prt == NULL) {
ysr@777 1236 fine_find_next_non_null_prt();
ysr@777 1237 if (_fine_cur_prt == NULL) return false;
ysr@777 1238 }
ysr@777 1239 assert(_fine_cur_prt != NULL && _cur_region_cur_card == 0,
ysr@777 1240 "inv.");
ysr@777 1241 HeapWord* r_bot =
ysr@777 1242 _fine_cur_prt->hr()->bottom();
ysr@777 1243 _cur_region_card_offset = _bosa->index_for(r_bot);
ysr@777 1244 _cur_region_cur_card = _fine_cur_prt->_bm.get_next_one_offset(0);
ysr@777 1245 }
ysr@777 1246 assert(fine_has_next(), "Or else we exited the loop via the return.");
ysr@777 1247 card_index = _cur_region_card_offset + _cur_region_cur_card;
ysr@777 1248 return true;
ysr@777 1249 }
ysr@777 1250
ysr@777 1251 bool HeapRegionRemSetIterator::fine_has_next() {
ysr@777 1252 return
ysr@777 1253 _fine_cur_prt != NULL &&
ysr@777 1254 _cur_region_cur_card < PosParPRT::CardsPerRegion;
ysr@777 1255 }
ysr@777 1256
ysr@777 1257 bool HeapRegionRemSetIterator::has_next(size_t& card_index) {
ysr@777 1258 switch (_is) {
ysr@777 1259 case Sparse:
ysr@777 1260 if (_sparse_iter.has_next(card_index)) {
ysr@777 1261 _n_yielded_sparse++;
ysr@777 1262 return true;
ysr@777 1263 }
ysr@777 1264 // Otherwise, deliberate fall-through
ysr@777 1265 _is = Fine;
ysr@777 1266 case Fine:
ysr@777 1267 if (fine_has_next(card_index)) {
ysr@777 1268 _n_yielded_fine++;
ysr@777 1269 return true;
ysr@777 1270 }
ysr@777 1271 // Otherwise, deliberate fall-through
ysr@777 1272 _is = Coarse;
ysr@777 1273 case Coarse:
ysr@777 1274 if (coarse_has_next(card_index)) {
ysr@777 1275 _n_yielded_coarse++;
ysr@777 1276 return true;
ysr@777 1277 }
ysr@777 1278 // Otherwise...
ysr@777 1279 break;
ysr@777 1280 }
ysr@777 1281 assert(ParallelGCThreads > 1 ||
ysr@777 1282 n_yielded() == _hrrs->occupied(),
ysr@777 1283 "Should have yielded all the cards in the rem set "
ysr@777 1284 "(in the non-par case).");
ysr@777 1285 return false;
ysr@777 1286 }
ysr@777 1287
ysr@777 1288
ysr@777 1289
ysr@777 1290 oop** HeapRegionRemSet::_recorded_oops = NULL;
ysr@777 1291 HeapWord** HeapRegionRemSet::_recorded_cards = NULL;
ysr@777 1292 HeapRegion** HeapRegionRemSet::_recorded_regions = NULL;
ysr@777 1293 int HeapRegionRemSet::_n_recorded = 0;
ysr@777 1294
ysr@777 1295 HeapRegionRemSet::Event* HeapRegionRemSet::_recorded_events = NULL;
ysr@777 1296 int* HeapRegionRemSet::_recorded_event_index = NULL;
ysr@777 1297 int HeapRegionRemSet::_n_recorded_events = 0;
ysr@777 1298
ysr@777 1299 void HeapRegionRemSet::record(HeapRegion* hr, oop* f) {
ysr@777 1300 if (_recorded_oops == NULL) {
ysr@777 1301 assert(_n_recorded == 0
ysr@777 1302 && _recorded_cards == NULL
ysr@777 1303 && _recorded_regions == NULL,
ysr@777 1304 "Inv");
ysr@777 1305 _recorded_oops = NEW_C_HEAP_ARRAY(oop*, MaxRecorded);
ysr@777 1306 _recorded_cards = NEW_C_HEAP_ARRAY(HeapWord*, MaxRecorded);
ysr@777 1307 _recorded_regions = NEW_C_HEAP_ARRAY(HeapRegion*, MaxRecorded);
ysr@777 1308 }
ysr@777 1309 if (_n_recorded == MaxRecorded) {
ysr@777 1310 gclog_or_tty->print_cr("Filled up 'recorded' (%d).", MaxRecorded);
ysr@777 1311 } else {
ysr@777 1312 _recorded_cards[_n_recorded] =
ysr@777 1313 (HeapWord*)align_size_down(uintptr_t(f),
ysr@777 1314 CardTableModRefBS::card_size);
ysr@777 1315 _recorded_oops[_n_recorded] = f;
ysr@777 1316 _recorded_regions[_n_recorded] = hr;
ysr@777 1317 _n_recorded++;
ysr@777 1318 }
ysr@777 1319 }
ysr@777 1320
ysr@777 1321 void HeapRegionRemSet::record_event(Event evnt) {
ysr@777 1322 if (!G1RecordHRRSEvents) return;
ysr@777 1323
ysr@777 1324 if (_recorded_events == NULL) {
ysr@777 1325 assert(_n_recorded_events == 0
ysr@777 1326 && _recorded_event_index == NULL,
ysr@777 1327 "Inv");
ysr@777 1328 _recorded_events = NEW_C_HEAP_ARRAY(Event, MaxRecordedEvents);
ysr@777 1329 _recorded_event_index = NEW_C_HEAP_ARRAY(int, MaxRecordedEvents);
ysr@777 1330 }
ysr@777 1331 if (_n_recorded_events == MaxRecordedEvents) {
ysr@777 1332 gclog_or_tty->print_cr("Filled up 'recorded_events' (%d).", MaxRecordedEvents);
ysr@777 1333 } else {
ysr@777 1334 _recorded_events[_n_recorded_events] = evnt;
ysr@777 1335 _recorded_event_index[_n_recorded_events] = _n_recorded;
ysr@777 1336 _n_recorded_events++;
ysr@777 1337 }
ysr@777 1338 }
ysr@777 1339
ysr@777 1340 void HeapRegionRemSet::print_event(outputStream* str, Event evnt) {
ysr@777 1341 switch (evnt) {
ysr@777 1342 case Event_EvacStart:
ysr@777 1343 str->print("Evac Start");
ysr@777 1344 break;
ysr@777 1345 case Event_EvacEnd:
ysr@777 1346 str->print("Evac End");
ysr@777 1347 break;
ysr@777 1348 case Event_RSUpdateEnd:
ysr@777 1349 str->print("RS Update End");
ysr@777 1350 break;
ysr@777 1351 }
ysr@777 1352 }
ysr@777 1353
ysr@777 1354 void HeapRegionRemSet::print_recorded() {
ysr@777 1355 int cur_evnt = 0;
ysr@777 1356 Event cur_evnt_kind;
ysr@777 1357 int cur_evnt_ind = 0;
ysr@777 1358 if (_n_recorded_events > 0) {
ysr@777 1359 cur_evnt_kind = _recorded_events[cur_evnt];
ysr@777 1360 cur_evnt_ind = _recorded_event_index[cur_evnt];
ysr@777 1361 }
ysr@777 1362
ysr@777 1363 for (int i = 0; i < _n_recorded; i++) {
ysr@777 1364 while (cur_evnt < _n_recorded_events && i == cur_evnt_ind) {
ysr@777 1365 gclog_or_tty->print("Event: ");
ysr@777 1366 print_event(gclog_or_tty, cur_evnt_kind);
ysr@777 1367 gclog_or_tty->print_cr("");
ysr@777 1368 cur_evnt++;
ysr@777 1369 if (cur_evnt < MaxRecordedEvents) {
ysr@777 1370 cur_evnt_kind = _recorded_events[cur_evnt];
ysr@777 1371 cur_evnt_ind = _recorded_event_index[cur_evnt];
ysr@777 1372 }
ysr@777 1373 }
ysr@777 1374 gclog_or_tty->print("Added card " PTR_FORMAT " to region [" PTR_FORMAT "...]"
ysr@777 1375 " for ref " PTR_FORMAT ".\n",
ysr@777 1376 _recorded_cards[i], _recorded_regions[i]->bottom(),
ysr@777 1377 _recorded_oops[i]);
ysr@777 1378 }
ysr@777 1379 }
ysr@777 1380
ysr@777 1381 #ifndef PRODUCT
ysr@777 1382 void HeapRegionRemSet::test() {
ysr@777 1383 os::sleep(Thread::current(), (jlong)5000, false);
ysr@777 1384 G1CollectedHeap* g1h = G1CollectedHeap::heap();
ysr@777 1385
ysr@777 1386 // Run with "-XX:G1LogRSRegionEntries=2", so that 1 and 5 end up in same
ysr@777 1387 // hash bucket.
ysr@777 1388 HeapRegion* hr0 = g1h->region_at(0);
ysr@777 1389 HeapRegion* hr1 = g1h->region_at(1);
ysr@777 1390 HeapRegion* hr2 = g1h->region_at(5);
ysr@777 1391 HeapRegion* hr3 = g1h->region_at(6);
ysr@777 1392 HeapRegion* hr4 = g1h->region_at(7);
ysr@777 1393 HeapRegion* hr5 = g1h->region_at(8);
ysr@777 1394
ysr@777 1395 HeapWord* hr1_start = hr1->bottom();
ysr@777 1396 HeapWord* hr1_mid = hr1_start + HeapRegion::GrainWords/2;
ysr@777 1397 HeapWord* hr1_last = hr1->end() - 1;
ysr@777 1398
ysr@777 1399 HeapWord* hr2_start = hr2->bottom();
ysr@777 1400 HeapWord* hr2_mid = hr2_start + HeapRegion::GrainWords/2;
ysr@777 1401 HeapWord* hr2_last = hr2->end() - 1;
ysr@777 1402
ysr@777 1403 HeapWord* hr3_start = hr3->bottom();
ysr@777 1404 HeapWord* hr3_mid = hr3_start + HeapRegion::GrainWords/2;
ysr@777 1405 HeapWord* hr3_last = hr3->end() - 1;
ysr@777 1406
ysr@777 1407 HeapRegionRemSet* hrrs = hr0->rem_set();
ysr@777 1408
ysr@777 1409 // Make three references from region 0x101...
ysr@777 1410 hrrs->add_reference((oop*)hr1_start);
ysr@777 1411 hrrs->add_reference((oop*)hr1_mid);
ysr@777 1412 hrrs->add_reference((oop*)hr1_last);
ysr@777 1413
ysr@777 1414 hrrs->add_reference((oop*)hr2_start);
ysr@777 1415 hrrs->add_reference((oop*)hr2_mid);
ysr@777 1416 hrrs->add_reference((oop*)hr2_last);
ysr@777 1417
ysr@777 1418 hrrs->add_reference((oop*)hr3_start);
ysr@777 1419 hrrs->add_reference((oop*)hr3_mid);
ysr@777 1420 hrrs->add_reference((oop*)hr3_last);
ysr@777 1421
ysr@777 1422 // Now cause a coarsening.
ysr@777 1423 hrrs->add_reference((oop*)hr4->bottom());
ysr@777 1424 hrrs->add_reference((oop*)hr5->bottom());
ysr@777 1425
ysr@777 1426 // Now, does iteration yield these three?
ysr@777 1427 HeapRegionRemSetIterator iter;
ysr@777 1428 hrrs->init_iterator(&iter);
ysr@777 1429 size_t sum = 0;
ysr@777 1430 size_t card_index;
ysr@777 1431 while (iter.has_next(card_index)) {
ysr@777 1432 HeapWord* card_start =
ysr@777 1433 G1CollectedHeap::heap()->bot_shared()->address_for_index(card_index);
ysr@777 1434 gclog_or_tty->print_cr(" Card " PTR_FORMAT ".", card_start);
ysr@777 1435 sum++;
ysr@777 1436 }
ysr@777 1437 guarantee(sum == 11 - 3 + 2048, "Failure");
ysr@777 1438 guarantee(sum == hrrs->occupied(), "Failure");
ysr@777 1439 }
ysr@777 1440 #endif

mercurial