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

Fri, 10 Oct 2014 15:51:58 +0200

author
tschatzl
date
Fri, 10 Oct 2014 15:51:58 +0200
changeset 7257
e7d0505c8a30
parent 7208
7baf47cb97cb
child 7535
7ae4e26cb1e0
child 7828
cbc7c4c9e11c
permissions
-rw-r--r--

8059758: Footprint regressions with JDK-8038423
Summary: Changes in JDK-8038423 always initialize (zero out) virtual memory used for auxiliary data structures. This causes a footprint regression for G1 in startup benchmarks. This is because they do not touch that memory at all, so the operating system does not actually commit these pages. The fix is to, if the initialization value of the data structures matches the default value of just committed memory (=0), do not do anything.
Reviewed-by: jwilhelm, brutisso

ysr@777 1 /*
tschatzl@6402 2 * Copyright (c) 2001, 2014, Oracle and/or its affiliates. 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 *
trims@1907 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
trims@1907 20 * or visit www.oracle.com if you need additional information or have any
trims@1907 21 * questions.
ysr@777 22 *
ysr@777 23 */
ysr@777 24
stefank@2314 25 #include "precompiled.hpp"
stefank@2314 26 #include "gc_implementation/g1/concurrentG1Refine.hpp"
stefank@2314 27 #include "gc_implementation/g1/g1BlockOffsetTable.inline.hpp"
stefank@2314 28 #include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
stefank@2314 29 #include "gc_implementation/g1/heapRegionRemSet.hpp"
tschatzl@7091 30 #include "gc_implementation/g1/heapRegionManager.inline.hpp"
stefank@2314 31 #include "memory/allocation.hpp"
tschatzl@6403 32 #include "memory/padded.inline.hpp"
stefank@2314 33 #include "memory/space.inline.hpp"
johnc@3891 34 #include "oops/oop.inline.hpp"
stefank@2314 35 #include "utilities/bitMap.inline.hpp"
stefank@2314 36 #include "utilities/globalDefinitions.hpp"
johnc@5548 37 #include "utilities/growableArray.hpp"
ysr@777 38
drchase@6680 39 PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC
drchase@6680 40
zgu@3900 41 class PerRegionTable: public CHeapObj<mtGC> {
ysr@777 42 friend class OtherRegionsTable;
ysr@777 43 friend class HeapRegionRemSetIterator;
ysr@777 44
ysr@777 45 HeapRegion* _hr;
ysr@777 46 BitMap _bm;
ysr@777 47 jint _occupied;
ysr@777 48
johnc@3956 49 // next pointer for free/allocated 'all' list
johnc@3891 50 PerRegionTable* _next;
ysr@777 51
johnc@3956 52 // prev pointer for the allocated 'all' list
johnc@3956 53 PerRegionTable* _prev;
johnc@3956 54
johnc@3956 55 // next pointer in collision list
johnc@3956 56 PerRegionTable * _collision_list_next;
johnc@3956 57
johnc@3956 58 // Global free list of PRTs
ysr@777 59 static PerRegionTable* _free_list;
ysr@777 60
ysr@777 61 protected:
ysr@777 62 // We need access in order to union things into the base table.
ysr@777 63 BitMap* bm() { return &_bm; }
ysr@777 64
ysr@777 65 void recount_occupied() {
ysr@777 66 _occupied = (jint) bm()->count_one_bits();
ysr@777 67 }
ysr@777 68
ysr@777 69 PerRegionTable(HeapRegion* hr) :
ysr@777 70 _hr(hr),
ysr@777 71 _occupied(0),
johnc@3956 72 _bm(HeapRegion::CardsPerRegion, false /* in-resource-area */),
johnc@3956 73 _collision_list_next(NULL), _next(NULL), _prev(NULL)
ysr@777 74 {}
ysr@777 75
johnc@1242 76 void add_card_work(CardIdx_t from_card, bool par) {
ysr@777 77 if (!_bm.at(from_card)) {
ysr@777 78 if (par) {
ysr@777 79 if (_bm.par_at_put(from_card, 1)) {
ysr@777 80 Atomic::inc(&_occupied);
ysr@777 81 }
ysr@777 82 } else {
ysr@777 83 _bm.at_put(from_card, 1);
ysr@777 84 _occupied++;
ysr@777 85 }
ysr@777 86 }
ysr@777 87 }
ysr@777 88
ysr@1280 89 void add_reference_work(OopOrNarrowOopStar from, bool par) {
ysr@777 90 // Must make this robust in case "from" is not in "_hr", because of
ysr@777 91 // concurrency.
ysr@777 92
johnc@3891 93 if (G1TraceHeapRegionRememberedSet) {
johnc@3891 94 gclog_or_tty->print_cr(" PRT::Add_reference_work(" PTR_FORMAT "->" PTR_FORMAT").",
johnc@3891 95 from,
johnc@3891 96 UseCompressedOops
hseigel@5784 97 ? (void *)oopDesc::load_decode_heap_oop((narrowOop*)from)
hseigel@5784 98 : (void *)oopDesc::load_decode_heap_oop((oop*)from));
johnc@3891 99 }
ysr@777 100
ysr@777 101 HeapRegion* loc_hr = hr();
ysr@777 102 // If the test below fails, then this table was reused concurrently
ysr@777 103 // with this operation. This is OK, since the old table was coarsened,
ysr@777 104 // and adding a bit to the new table is never incorrect.
brutisso@3216 105 // If the table used to belong to a continues humongous region and is
brutisso@3216 106 // now reused for the corresponding start humongous region, we need to
brutisso@3216 107 // make sure that we detect this. Thus, we call is_in_reserved_raw()
brutisso@3216 108 // instead of just is_in_reserved() here.
brutisso@3216 109 if (loc_hr->is_in_reserved_raw(from)) {
ysr@777 110 size_t hw_offset = pointer_delta((HeapWord*)from, loc_hr->bottom());
johnc@1242 111 CardIdx_t from_card = (CardIdx_t)
johnc@1242 112 hw_offset >> (CardTableModRefBS::card_shift - LogHeapWordSize);
ysr@777 113
johnc@3182 114 assert(0 <= from_card && (size_t)from_card < HeapRegion::CardsPerRegion,
tonyp@1377 115 "Must be in range.");
johnc@1242 116 add_card_work(from_card, par);
ysr@777 117 }
ysr@777 118 }
ysr@777 119
ysr@777 120 public:
ysr@777 121
ysr@777 122 HeapRegion* hr() const { return _hr; }
ysr@777 123
ysr@777 124 jint occupied() const {
ysr@777 125 // Overkill, but if we ever need it...
ysr@777 126 // guarantee(_occupied == _bm.count_one_bits(), "Check");
ysr@777 127 return _occupied;
ysr@777 128 }
ysr@777 129
johnc@3956 130 void init(HeapRegion* hr, bool clear_links_to_all_list) {
johnc@3956 131 if (clear_links_to_all_list) {
johnc@3956 132 set_next(NULL);
johnc@3956 133 set_prev(NULL);
johnc@3956 134 }
ysr@777 135 _hr = hr;
johnc@3956 136 _collision_list_next = NULL;
ysr@777 137 _occupied = 0;
ysr@777 138 _bm.clear();
ysr@777 139 }
ysr@777 140
ysr@1280 141 void add_reference(OopOrNarrowOopStar from) {
ysr@777 142 add_reference_work(from, /*parallel*/ true);
ysr@777 143 }
ysr@777 144
ysr@1280 145 void seq_add_reference(OopOrNarrowOopStar from) {
ysr@777 146 add_reference_work(from, /*parallel*/ false);
ysr@777 147 }
ysr@777 148
ysr@777 149 void scrub(CardTableModRefBS* ctbs, BitMap* card_bm) {
ysr@777 150 HeapWord* hr_bot = hr()->bottom();
swamyv@924 151 size_t hr_first_card_index = ctbs->index_for(hr_bot);
ysr@777 152 bm()->set_intersection_at_offset(*card_bm, hr_first_card_index);
ysr@777 153 recount_occupied();
ysr@777 154 }
ysr@777 155
johnc@1242 156 void add_card(CardIdx_t from_card_index) {
ysr@777 157 add_card_work(from_card_index, /*parallel*/ true);
ysr@777 158 }
ysr@777 159
johnc@1242 160 void seq_add_card(CardIdx_t from_card_index) {
ysr@777 161 add_card_work(from_card_index, /*parallel*/ false);
ysr@777 162 }
ysr@777 163
ysr@777 164 // (Destructively) union the bitmap of the current table into the given
ysr@777 165 // bitmap (which is assumed to be of the same size.)
ysr@777 166 void union_bitmap_into(BitMap* bm) {
ysr@777 167 bm->set_union(_bm);
ysr@777 168 }
ysr@777 169
ysr@777 170 // Mem size in bytes.
ysr@777 171 size_t mem_size() const {
tschatzl@6932 172 return sizeof(PerRegionTable) + _bm.size_in_words() * HeapWordSize;
ysr@777 173 }
ysr@777 174
ysr@777 175 // Requires "from" to be in "hr()".
ysr@1280 176 bool contains_reference(OopOrNarrowOopStar from) const {
ysr@777 177 assert(hr()->is_in_reserved(from), "Precondition.");
ysr@777 178 size_t card_ind = pointer_delta(from, hr()->bottom(),
ysr@777 179 CardTableModRefBS::card_size);
ysr@777 180 return _bm.at(card_ind);
ysr@777 181 }
ysr@777 182
johnc@3956 183 // Bulk-free the PRTs from prt to last, assumes that they are
johnc@3956 184 // linked together using their _next field.
johnc@3956 185 static void bulk_free(PerRegionTable* prt, PerRegionTable* last) {
ysr@777 186 while (true) {
johnc@3891 187 PerRegionTable* fl = _free_list;
johnc@3956 188 last->set_next(fl);
johnc@3956 189 PerRegionTable* res = (PerRegionTable*) Atomic::cmpxchg_ptr(prt, &_free_list, fl);
johnc@3956 190 if (res == fl) {
johnc@3956 191 return;
johnc@3956 192 }
ysr@777 193 }
ysr@777 194 ShouldNotReachHere();
ysr@777 195 }
ysr@777 196
johnc@3956 197 static void free(PerRegionTable* prt) {
johnc@3956 198 bulk_free(prt, prt);
johnc@3956 199 }
johnc@3956 200
johnc@3956 201 // Returns an initialized PerRegionTable instance.
johnc@3891 202 static PerRegionTable* alloc(HeapRegion* hr) {
johnc@3891 203 PerRegionTable* fl = _free_list;
ysr@777 204 while (fl != NULL) {
johnc@3891 205 PerRegionTable* nxt = fl->next();
johnc@3891 206 PerRegionTable* res =
johnc@3891 207 (PerRegionTable*)
ysr@777 208 Atomic::cmpxchg_ptr(nxt, &_free_list, fl);
ysr@777 209 if (res == fl) {
johnc@3956 210 fl->init(hr, true);
ysr@777 211 return fl;
ysr@777 212 } else {
ysr@777 213 fl = _free_list;
ysr@777 214 }
ysr@777 215 }
ysr@777 216 assert(fl == NULL, "Loop condition.");
johnc@3891 217 return new PerRegionTable(hr);
ysr@777 218 }
ysr@777 219
johnc@3956 220 PerRegionTable* next() const { return _next; }
johnc@3956 221 void set_next(PerRegionTable* next) { _next = next; }
johnc@3956 222 PerRegionTable* prev() const { return _prev; }
johnc@3956 223 void set_prev(PerRegionTable* prev) { _prev = prev; }
johnc@3956 224
johnc@3956 225 // Accessor and Modification routines for the pointer for the
johnc@3956 226 // singly linked collision list that links the PRTs within the
johnc@3956 227 // OtherRegionsTable::_fine_grain_regions hash table.
johnc@3956 228 //
johnc@3956 229 // It might be useful to also make the collision list doubly linked
johnc@3956 230 // to avoid iteration over the collisions list during scrubbing/deletion.
johnc@3956 231 // OTOH there might not be many collisions.
johnc@3956 232
johnc@3956 233 PerRegionTable* collision_list_next() const {
johnc@3956 234 return _collision_list_next;
johnc@3956 235 }
johnc@3956 236
johnc@3956 237 void set_collision_list_next(PerRegionTable* next) {
johnc@3956 238 _collision_list_next = next;
johnc@3956 239 }
johnc@3956 240
johnc@3956 241 PerRegionTable** collision_list_next_addr() {
johnc@3956 242 return &_collision_list_next;
johnc@3956 243 }
johnc@3956 244
ysr@777 245 static size_t fl_mem_size() {
johnc@3891 246 PerRegionTable* cur = _free_list;
ysr@777 247 size_t res = 0;
ysr@777 248 while (cur != NULL) {
tschatzl@5165 249 res += cur->mem_size();
ysr@777 250 cur = cur->next();
ysr@777 251 }
ysr@777 252 return res;
ysr@777 253 }
tschatzl@5165 254
tschatzl@5165 255 static void test_fl_mem_size();
ysr@777 256 };
ysr@777 257
johnc@3891 258 PerRegionTable* PerRegionTable::_free_list = NULL;
ysr@777 259
ysr@777 260 size_t OtherRegionsTable::_max_fine_entries = 0;
ysr@777 261 size_t OtherRegionsTable::_mod_max_fine_entries_mask = 0;
ysr@777 262 size_t OtherRegionsTable::_fine_eviction_stride = 0;
ysr@777 263 size_t OtherRegionsTable::_fine_eviction_sample_size = 0;
ysr@777 264
tschatzl@6402 265 OtherRegionsTable::OtherRegionsTable(HeapRegion* hr, Mutex* m) :
ysr@777 266 _g1h(G1CollectedHeap::heap()),
tschatzl@6402 267 _hr(hr), _m(m),
ysr@777 268 _coarse_map(G1CollectedHeap::heap()->max_regions(),
ysr@777 269 false /* in-resource-area */),
ysr@777 270 _fine_grain_regions(NULL),
johnc@3956 271 _first_all_fine_prts(NULL), _last_all_fine_prts(NULL),
ysr@777 272 _n_fine_entries(0), _n_coarse_entries(0),
ysr@777 273 _fine_eviction_start(0),
ysr@777 274 _sparse_table(hr)
ysr@777 275 {
johnc@3891 276 typedef PerRegionTable* PerRegionTablePtr;
johnc@3891 277
ysr@777 278 if (_max_fine_entries == 0) {
ysr@777 279 assert(_mod_max_fine_entries_mask == 0, "Both or none.");
iveresov@1696 280 size_t max_entries_log = (size_t)log2_long((jlong)G1RSetRegionEntries);
brutisso@4061 281 _max_fine_entries = (size_t)1 << max_entries_log;
ysr@777 282 _mod_max_fine_entries_mask = _max_fine_entries - 1;
johnc@3891 283
ysr@777 284 assert(_fine_eviction_sample_size == 0
ysr@777 285 && _fine_eviction_stride == 0, "All init at same time.");
iveresov@1696 286 _fine_eviction_sample_size = MAX2((size_t)4, max_entries_log);
ysr@777 287 _fine_eviction_stride = _max_fine_entries / _fine_eviction_sample_size;
ysr@777 288 }
johnc@3891 289
minqi@5103 290 _fine_grain_regions = NEW_C_HEAP_ARRAY3(PerRegionTablePtr, _max_fine_entries,
zgu@7074 291 mtGC, CURRENT_PC, AllocFailStrategy::RETURN_NULL);
johnc@3891 292
johnc@3891 293 if (_fine_grain_regions == NULL) {
ccheung@4993 294 vm_exit_out_of_memory(sizeof(void*)*_max_fine_entries, OOM_MALLOC_ERROR,
ysr@777 295 "Failed to allocate _fine_grain_entries.");
johnc@3891 296 }
johnc@3891 297
ysr@777 298 for (size_t i = 0; i < _max_fine_entries; i++) {
ysr@777 299 _fine_grain_regions[i] = NULL;
ysr@777 300 }
ysr@777 301 }
ysr@777 302
johnc@3956 303 void OtherRegionsTable::link_to_all(PerRegionTable* prt) {
johnc@3956 304 // We always append to the beginning of the list for convenience;
johnc@3956 305 // the order of entries in this list does not matter.
johnc@3956 306 if (_first_all_fine_prts != NULL) {
johnc@3956 307 assert(_first_all_fine_prts->prev() == NULL, "invariant");
johnc@3956 308 _first_all_fine_prts->set_prev(prt);
johnc@3956 309 prt->set_next(_first_all_fine_prts);
johnc@3956 310 } else {
johnc@3956 311 // this is the first element we insert. Adjust the "last" pointer
johnc@3956 312 _last_all_fine_prts = prt;
johnc@3956 313 assert(prt->next() == NULL, "just checking");
johnc@3956 314 }
johnc@3956 315 // the new element is always the first element without a predecessor
johnc@3956 316 prt->set_prev(NULL);
johnc@3956 317 _first_all_fine_prts = prt;
johnc@3956 318
johnc@3956 319 assert(prt->prev() == NULL, "just checking");
johnc@3956 320 assert(_first_all_fine_prts == prt, "just checking");
johnc@3956 321 assert((_first_all_fine_prts == NULL && _last_all_fine_prts == NULL) ||
johnc@3956 322 (_first_all_fine_prts != NULL && _last_all_fine_prts != NULL),
johnc@3956 323 "just checking");
johnc@3956 324 assert(_last_all_fine_prts == NULL || _last_all_fine_prts->next() == NULL,
johnc@3956 325 "just checking");
johnc@3956 326 assert(_first_all_fine_prts == NULL || _first_all_fine_prts->prev() == NULL,
johnc@3956 327 "just checking");
johnc@3956 328 }
johnc@3956 329
johnc@3956 330 void OtherRegionsTable::unlink_from_all(PerRegionTable* prt) {
johnc@3956 331 if (prt->prev() != NULL) {
johnc@3956 332 assert(_first_all_fine_prts != prt, "just checking");
johnc@3956 333 prt->prev()->set_next(prt->next());
johnc@3956 334 // removing the last element in the list?
johnc@3956 335 if (_last_all_fine_prts == prt) {
johnc@3956 336 _last_all_fine_prts = prt->prev();
johnc@3956 337 }
johnc@3956 338 } else {
johnc@3956 339 assert(_first_all_fine_prts == prt, "just checking");
johnc@3956 340 _first_all_fine_prts = prt->next();
johnc@3956 341 // list is empty now?
johnc@3956 342 if (_first_all_fine_prts == NULL) {
johnc@3956 343 _last_all_fine_prts = NULL;
johnc@3956 344 }
johnc@3956 345 }
johnc@3956 346
johnc@3956 347 if (prt->next() != NULL) {
johnc@3956 348 prt->next()->set_prev(prt->prev());
johnc@3956 349 }
johnc@3956 350
johnc@3956 351 prt->set_next(NULL);
johnc@3956 352 prt->set_prev(NULL);
johnc@3956 353
johnc@3956 354 assert((_first_all_fine_prts == NULL && _last_all_fine_prts == NULL) ||
johnc@3956 355 (_first_all_fine_prts != NULL && _last_all_fine_prts != NULL),
johnc@3956 356 "just checking");
johnc@3956 357 assert(_last_all_fine_prts == NULL || _last_all_fine_prts->next() == NULL,
johnc@3956 358 "just checking");
johnc@3956 359 assert(_first_all_fine_prts == NULL || _first_all_fine_prts->prev() == NULL,
johnc@3956 360 "just checking");
johnc@3956 361 }
johnc@3956 362
tschatzl@6407 363 int** FromCardCache::_cache = NULL;
tschatzl@6407 364 uint FromCardCache::_max_regions = 0;
tschatzl@6407 365 size_t FromCardCache::_static_mem_size = 0;
ysr@777 366
tschatzl@6407 367 void FromCardCache::initialize(uint n_par_rs, uint max_num_regions) {
tschatzl@6407 368 guarantee(_cache == NULL, "Should not call this multiple times");
tschatzl@6403 369
tschatzl@6407 370 _max_regions = max_num_regions;
tschatzl@6407 371 _cache = Padded2DArray<int, mtGC>::create_unfreeable(n_par_rs,
tschatzl@6407 372 _max_regions,
tschatzl@6407 373 &_static_mem_size);
ysr@777 374
tschatzl@7051 375 invalidate(0, _max_regions);
ysr@777 376 }
ysr@777 377
tschatzl@7051 378 void FromCardCache::invalidate(uint start_idx, size_t new_num_regions) {
tschatzl@7051 379 guarantee((size_t)start_idx + new_num_regions <= max_uintx,
tschatzl@7051 380 err_msg("Trying to invalidate beyond maximum region, from %u size "SIZE_FORMAT,
tschatzl@7051 381 start_idx, new_num_regions));
tschatzl@6403 382 for (uint i = 0; i < HeapRegionRemSet::num_par_rem_sets(); i++) {
tschatzl@7051 383 uint end_idx = (start_idx + (uint)new_num_regions);
tschatzl@7051 384 assert(end_idx <= _max_regions, "Must be within max.");
tschatzl@7051 385 for (uint j = start_idx; j < end_idx; j++) {
tschatzl@6407 386 set(i, j, InvalidCard);
ysr@777 387 }
ysr@777 388 }
ysr@777 389 }
ysr@777 390
ysr@777 391 #ifndef PRODUCT
tschatzl@6407 392 void FromCardCache::print(outputStream* out) {
tschatzl@6403 393 for (uint i = 0; i < HeapRegionRemSet::num_par_rem_sets(); i++) {
tschatzl@6407 394 for (uint j = 0; j < _max_regions; j++) {
tschatzl@6407 395 out->print_cr("_from_card_cache["UINT32_FORMAT"]["UINT32_FORMAT"] = "INT32_FORMAT".",
tschatzl@6407 396 i, j, at(i, j));
ysr@777 397 }
ysr@777 398 }
ysr@777 399 }
ysr@777 400 #endif
ysr@777 401
tschatzl@6407 402 void FromCardCache::clear(uint region_idx) {
tschatzl@6407 403 uint num_par_remsets = HeapRegionRemSet::num_par_rem_sets();
tschatzl@6407 404 for (uint i = 0; i < num_par_remsets; i++) {
tschatzl@6407 405 set(i, region_idx, InvalidCard);
tschatzl@6407 406 }
tschatzl@6407 407 }
tschatzl@6407 408
tschatzl@7051 409 void OtherRegionsTable::initialize(uint max_regions) {
tschatzl@6407 410 FromCardCache::initialize(HeapRegionRemSet::num_par_rem_sets(), max_regions);
tschatzl@6407 411 }
tschatzl@6407 412
tschatzl@7051 413 void OtherRegionsTable::invalidate(uint start_idx, size_t num_regions) {
tschatzl@7051 414 FromCardCache::invalidate(start_idx, num_regions);
tschatzl@6407 415 }
tschatzl@6407 416
tschatzl@6407 417 void OtherRegionsTable::print_from_card_cache() {
tschatzl@6407 418 FromCardCache::print();
tschatzl@6407 419 }
tschatzl@6407 420
ysr@1280 421 void OtherRegionsTable::add_reference(OopOrNarrowOopStar from, int tid) {
tschatzl@7091 422 uint cur_hrm_ind = hr()->hrm_index();
ysr@777 423
johnc@3891 424 if (G1TraceHeapRegionRememberedSet) {
johnc@3891 425 gclog_or_tty->print_cr("ORT::add_reference_work(" PTR_FORMAT "->" PTR_FORMAT ").",
johnc@3891 426 from,
johnc@3891 427 UseCompressedOops
hseigel@5784 428 ? (void *)oopDesc::load_decode_heap_oop((narrowOop*)from)
hseigel@5784 429 : (void *)oopDesc::load_decode_heap_oop((oop*)from));
johnc@3891 430 }
ysr@777 431
ysr@777 432 int from_card = (int)(uintptr_t(from) >> CardTableModRefBS::card_shift);
ysr@777 433
johnc@3891 434 if (G1TraceHeapRegionRememberedSet) {
tschatzl@6407 435 gclog_or_tty->print_cr("Table for [" PTR_FORMAT "...): card %d (cache = "INT32_FORMAT")",
johnc@3891 436 hr()->bottom(), from_card,
tschatzl@7091 437 FromCardCache::at((uint)tid, cur_hrm_ind));
johnc@3891 438 }
ysr@777 439
tschatzl@7091 440 if (FromCardCache::contains_or_replace((uint)tid, cur_hrm_ind, from_card)) {
johnc@3891 441 if (G1TraceHeapRegionRememberedSet) {
johnc@3891 442 gclog_or_tty->print_cr(" from-card cache hit.");
johnc@3891 443 }
ysr@777 444 assert(contains_reference(from), "We just added it!");
ysr@777 445 return;
ysr@777 446 }
ysr@777 447
ysr@777 448 // Note that this may be a continued H region.
ysr@777 449 HeapRegion* from_hr = _g1h->heap_region_containing_raw(from);
tschatzl@7106 450 RegionIdx_t from_hrm_ind = (RegionIdx_t) from_hr->hrm_index();
ysr@777 451
ysr@777 452 // If the region is already coarsened, return.
tschatzl@7106 453 if (_coarse_map.at(from_hrm_ind)) {
johnc@3891 454 if (G1TraceHeapRegionRememberedSet) {
johnc@3891 455 gclog_or_tty->print_cr(" coarse map hit.");
johnc@3891 456 }
ysr@777 457 assert(contains_reference(from), "We just added it!");
ysr@777 458 return;
ysr@777 459 }
ysr@777 460
ysr@777 461 // Otherwise find a per-region table to add it to.
tschatzl@7106 462 size_t ind = from_hrm_ind & _mod_max_fine_entries_mask;
johnc@3891 463 PerRegionTable* prt = find_region_table(ind, from_hr);
ysr@777 464 if (prt == NULL) {
tschatzl@6402 465 MutexLockerEx x(_m, Mutex::_no_safepoint_check_flag);
ysr@777 466 // Confirm that it's really not there...
ysr@777 467 prt = find_region_table(ind, from_hr);
ysr@777 468 if (prt == NULL) {
ysr@777 469
ysr@777 470 uintptr_t from_hr_bot_card_index =
ysr@777 471 uintptr_t(from_hr->bottom())
ysr@777 472 >> CardTableModRefBS::card_shift;
johnc@1242 473 CardIdx_t card_index = from_card - from_hr_bot_card_index;
johnc@3182 474 assert(0 <= card_index && (size_t)card_index < HeapRegion::CardsPerRegion,
ysr@777 475 "Must be in range.");
ysr@777 476 if (G1HRRSUseSparseTable &&
tschatzl@7106 477 _sparse_table.add_card(from_hrm_ind, card_index)) {
ysr@777 478 if (G1RecordHRRSOops) {
ysr@777 479 HeapRegionRemSet::record(hr(), from);
johnc@3891 480 if (G1TraceHeapRegionRememberedSet) {
johnc@3891 481 gclog_or_tty->print(" Added card " PTR_FORMAT " to region "
johnc@3891 482 "[" PTR_FORMAT "...) for ref " PTR_FORMAT ".\n",
johnc@3891 483 align_size_down(uintptr_t(from),
johnc@3891 484 CardTableModRefBS::card_size),
johnc@3891 485 hr()->bottom(), from);
johnc@3891 486 }
ysr@777 487 }
johnc@3891 488 if (G1TraceHeapRegionRememberedSet) {
johnc@3891 489 gclog_or_tty->print_cr(" added card to sparse table.");
johnc@3891 490 }
ysr@777 491 assert(contains_reference_locked(from), "We just added it!");
ysr@777 492 return;
ysr@777 493 } else {
johnc@3891 494 if (G1TraceHeapRegionRememberedSet) {
johnc@3891 495 gclog_or_tty->print_cr(" [tid %d] sparse table entry "
tschatzl@7091 496 "overflow(f: %d, t: %u)",
tschatzl@7106 497 tid, from_hrm_ind, cur_hrm_ind);
johnc@3891 498 }
ysr@777 499 }
ysr@777 500
ysr@777 501 if (_n_fine_entries == _max_fine_entries) {
ysr@777 502 prt = delete_region_table();
johnc@3956 503 // There is no need to clear the links to the 'all' list here:
johnc@3956 504 // prt will be reused immediately, i.e. remain in the 'all' list.
johnc@3956 505 prt->init(from_hr, false /* clear_links_to_all_list */);
ysr@777 506 } else {
johnc@3891 507 prt = PerRegionTable::alloc(from_hr);
johnc@3956 508 link_to_all(prt);
ysr@777 509 }
ysr@777 510
johnc@3891 511 PerRegionTable* first_prt = _fine_grain_regions[ind];
johnc@3956 512 prt->set_collision_list_next(first_prt);
ysr@777 513 _fine_grain_regions[ind] = prt;
ysr@777 514 _n_fine_entries++;
ysr@777 515
ysr@777 516 if (G1HRRSUseSparseTable) {
iveresov@1696 517 // Transfer from sparse to fine-grain.
tschatzl@7106 518 SparsePRTEntry *sprt_entry = _sparse_table.get_entry(from_hrm_ind);
iveresov@1696 519 assert(sprt_entry != NULL, "There should have been an entry");
iveresov@1696 520 for (int i = 0; i < SparsePRTEntry::cards_num(); i++) {
iveresov@1696 521 CardIdx_t c = sprt_entry->card(i);
ysr@777 522 if (c != SparsePRTEntry::NullEntry) {
ysr@777 523 prt->add_card(c);
ysr@777 524 }
ysr@777 525 }
ysr@777 526 // Now we can delete the sparse entry.
tschatzl@7106 527 bool res = _sparse_table.delete_entry(from_hrm_ind);
ysr@777 528 assert(res, "It should have been there.");
ysr@777 529 }
ysr@777 530 }
ysr@777 531 assert(prt != NULL && prt->hr() == from_hr, "consequence");
ysr@777 532 }
ysr@777 533 // Note that we can't assert "prt->hr() == from_hr", because of the
ysr@777 534 // possibility of concurrent reuse. But see head comment of
ysr@777 535 // OtherRegionsTable for why this is OK.
ysr@777 536 assert(prt != NULL, "Inv");
ysr@777 537
johnc@3891 538 prt->add_reference(from);
johnc@3891 539
ysr@777 540 if (G1RecordHRRSOops) {
ysr@777 541 HeapRegionRemSet::record(hr(), from);
johnc@3891 542 if (G1TraceHeapRegionRememberedSet) {
johnc@3891 543 gclog_or_tty->print("Added card " PTR_FORMAT " to region "
johnc@3891 544 "[" PTR_FORMAT "...) for ref " PTR_FORMAT ".\n",
johnc@3891 545 align_size_down(uintptr_t(from),
johnc@3891 546 CardTableModRefBS::card_size),
johnc@3891 547 hr()->bottom(), from);
johnc@3891 548 }
ysr@777 549 }
ysr@777 550 assert(contains_reference(from), "We just added it!");
ysr@777 551 }
ysr@777 552
johnc@3891 553 PerRegionTable*
ysr@777 554 OtherRegionsTable::find_region_table(size_t ind, HeapRegion* hr) const {
ysr@777 555 assert(0 <= ind && ind < _max_fine_entries, "Preconditions.");
johnc@3891 556 PerRegionTable* prt = _fine_grain_regions[ind];
ysr@777 557 while (prt != NULL && prt->hr() != hr) {
johnc@3956 558 prt = prt->collision_list_next();
ysr@777 559 }
ysr@777 560 // Loop postcondition is the method postcondition.
ysr@777 561 return prt;
ysr@777 562 }
ysr@777 563
ysr@777 564 jint OtherRegionsTable::_n_coarsenings = 0;
ysr@777 565
johnc@3891 566 PerRegionTable* OtherRegionsTable::delete_region_table() {
tschatzl@6402 567 assert(_m->owned_by_self(), "Precondition");
ysr@777 568 assert(_n_fine_entries == _max_fine_entries, "Precondition");
johnc@3891 569 PerRegionTable* max = NULL;
ysr@777 570 jint max_occ = 0;
johnc@3891 571 PerRegionTable** max_prev;
ysr@777 572 size_t max_ind;
ysr@777 573
ysr@777 574 size_t i = _fine_eviction_start;
ysr@777 575 for (size_t k = 0; k < _fine_eviction_sample_size; k++) {
ysr@777 576 size_t ii = i;
ysr@777 577 // Make sure we get a non-NULL sample.
ysr@777 578 while (_fine_grain_regions[ii] == NULL) {
ysr@777 579 ii++;
ysr@777 580 if (ii == _max_fine_entries) ii = 0;
ysr@777 581 guarantee(ii != i, "We must find one.");
ysr@777 582 }
johnc@3891 583 PerRegionTable** prev = &_fine_grain_regions[ii];
johnc@3891 584 PerRegionTable* cur = *prev;
ysr@777 585 while (cur != NULL) {
ysr@777 586 jint cur_occ = cur->occupied();
ysr@777 587 if (max == NULL || cur_occ > max_occ) {
ysr@777 588 max = cur;
ysr@777 589 max_prev = prev;
ysr@777 590 max_ind = i;
ysr@777 591 max_occ = cur_occ;
ysr@777 592 }
johnc@3956 593 prev = cur->collision_list_next_addr();
johnc@3956 594 cur = cur->collision_list_next();
ysr@777 595 }
ysr@777 596 i = i + _fine_eviction_stride;
ysr@777 597 if (i >= _n_fine_entries) i = i - _n_fine_entries;
ysr@777 598 }
johnc@3891 599
ysr@777 600 _fine_eviction_start++;
johnc@3891 601
johnc@3891 602 if (_fine_eviction_start >= _n_fine_entries) {
ysr@777 603 _fine_eviction_start -= _n_fine_entries;
ysr@777 604 }
johnc@3891 605
ysr@777 606 guarantee(max != NULL, "Since _n_fine_entries > 0");
ysr@777 607
ysr@777 608 // Set the corresponding coarse bit.
tschatzl@7091 609 size_t max_hrm_index = (size_t) max->hr()->hrm_index();
tschatzl@7091 610 if (!_coarse_map.at(max_hrm_index)) {
tschatzl@7091 611 _coarse_map.at_put(max_hrm_index, true);
ysr@777 612 _n_coarse_entries++;
johnc@3891 613 if (G1TraceHeapRegionRememberedSet) {
johnc@3891 614 gclog_or_tty->print("Coarsened entry in region [" PTR_FORMAT "...] "
johnc@3891 615 "for region [" PTR_FORMAT "...] (%d coarse entries).\n",
johnc@3891 616 hr()->bottom(),
johnc@3891 617 max->hr()->bottom(),
johnc@3891 618 _n_coarse_entries);
johnc@3891 619 }
ysr@777 620 }
ysr@777 621
ysr@777 622 // Unsplice.
johnc@3956 623 *max_prev = max->collision_list_next();
ysr@777 624 Atomic::inc(&_n_coarsenings);
ysr@777 625 _n_fine_entries--;
ysr@777 626 return max;
ysr@777 627 }
ysr@777 628
ysr@777 629
ysr@777 630 // At present, this must be called stop-world single-threaded.
ysr@777 631 void OtherRegionsTable::scrub(CardTableModRefBS* ctbs,
ysr@777 632 BitMap* region_bm, BitMap* card_bm) {
ysr@777 633 // First eliminated garbage regions from the coarse map.
tonyp@3713 634 if (G1RSScrubVerbose) {
tschatzl@7091 635 gclog_or_tty->print_cr("Scrubbing region %u:", hr()->hrm_index());
tonyp@3713 636 }
ysr@777 637
ysr@777 638 assert(_coarse_map.size() == region_bm->size(), "Precondition");
tonyp@3713 639 if (G1RSScrubVerbose) {
tonyp@3713 640 gclog_or_tty->print(" Coarse map: before = "SIZE_FORMAT"...",
tonyp@3713 641 _n_coarse_entries);
tonyp@3713 642 }
ysr@777 643 _coarse_map.set_intersection(*region_bm);
ysr@777 644 _n_coarse_entries = _coarse_map.count_one_bits();
tonyp@3713 645 if (G1RSScrubVerbose) {
tonyp@3713 646 gclog_or_tty->print_cr(" after = "SIZE_FORMAT".", _n_coarse_entries);
tonyp@3713 647 }
ysr@777 648
ysr@777 649 // Now do the fine-grained maps.
ysr@777 650 for (size_t i = 0; i < _max_fine_entries; i++) {
johnc@3891 651 PerRegionTable* cur = _fine_grain_regions[i];
johnc@3891 652 PerRegionTable** prev = &_fine_grain_regions[i];
ysr@777 653 while (cur != NULL) {
johnc@3956 654 PerRegionTable* nxt = cur->collision_list_next();
ysr@777 655 // If the entire region is dead, eliminate.
tonyp@3713 656 if (G1RSScrubVerbose) {
tonyp@3713 657 gclog_or_tty->print_cr(" For other region %u:",
tschatzl@7091 658 cur->hr()->hrm_index());
tonyp@3713 659 }
tschatzl@7091 660 if (!region_bm->at((size_t) cur->hr()->hrm_index())) {
ysr@777 661 *prev = nxt;
johnc@3956 662 cur->set_collision_list_next(NULL);
ysr@777 663 _n_fine_entries--;
tonyp@3713 664 if (G1RSScrubVerbose) {
ysr@777 665 gclog_or_tty->print_cr(" deleted via region map.");
tonyp@3713 666 }
johnc@3956 667 unlink_from_all(cur);
johnc@3891 668 PerRegionTable::free(cur);
ysr@777 669 } else {
ysr@777 670 // Do fine-grain elimination.
tonyp@3713 671 if (G1RSScrubVerbose) {
ysr@777 672 gclog_or_tty->print(" occ: before = %4d.", cur->occupied());
tonyp@3713 673 }
ysr@777 674 cur->scrub(ctbs, card_bm);
tonyp@3713 675 if (G1RSScrubVerbose) {
ysr@777 676 gclog_or_tty->print_cr(" after = %4d.", cur->occupied());
tonyp@3713 677 }
ysr@777 678 // Did that empty the table completely?
ysr@777 679 if (cur->occupied() == 0) {
ysr@777 680 *prev = nxt;
johnc@3956 681 cur->set_collision_list_next(NULL);
ysr@777 682 _n_fine_entries--;
johnc@3956 683 unlink_from_all(cur);
johnc@3891 684 PerRegionTable::free(cur);
ysr@777 685 } else {
johnc@3956 686 prev = cur->collision_list_next_addr();
ysr@777 687 }
ysr@777 688 }
ysr@777 689 cur = nxt;
ysr@777 690 }
ysr@777 691 }
ysr@777 692 // Since we may have deleted a from_card_cache entry from the RS, clear
ysr@777 693 // the FCC.
ysr@777 694 clear_fcc();
ysr@777 695 }
ysr@777 696
tschatzl@7010 697 bool OtherRegionsTable::is_empty() const {
tschatzl@7010 698 return occ_sparse() == 0 && occ_coarse() == 0 && _first_all_fine_prts == NULL;
tschatzl@7010 699 }
ysr@777 700
ysr@777 701 size_t OtherRegionsTable::occupied() const {
ysr@777 702 size_t sum = occ_fine();
ysr@777 703 sum += occ_sparse();
ysr@777 704 sum += occ_coarse();
ysr@777 705 return sum;
ysr@777 706 }
ysr@777 707
ysr@777 708 size_t OtherRegionsTable::occ_fine() const {
ysr@777 709 size_t sum = 0;
johnc@3956 710
johnc@3956 711 size_t num = 0;
johnc@3956 712 PerRegionTable * cur = _first_all_fine_prts;
johnc@3956 713 while (cur != NULL) {
johnc@3956 714 sum += cur->occupied();
johnc@3956 715 cur = cur->next();
johnc@3956 716 num++;
ysr@777 717 }
johnc@3956 718 guarantee(num == _n_fine_entries, "just checking");
ysr@777 719 return sum;
ysr@777 720 }
ysr@777 721
ysr@777 722 size_t OtherRegionsTable::occ_coarse() const {
tonyp@1377 723 return (_n_coarse_entries * HeapRegion::CardsPerRegion);
ysr@777 724 }
ysr@777 725
ysr@777 726 size_t OtherRegionsTable::occ_sparse() const {
ysr@777 727 return _sparse_table.occupied();
ysr@777 728 }
ysr@777 729
ysr@777 730 size_t OtherRegionsTable::mem_size() const {
ysr@777 731 size_t sum = 0;
tschatzl@5122 732 // all PRTs are of the same size so it is sufficient to query only one of them.
tschatzl@5122 733 if (_first_all_fine_prts != NULL) {
tschatzl@5122 734 assert(_last_all_fine_prts != NULL &&
tschatzl@5122 735 _first_all_fine_prts->mem_size() == _last_all_fine_prts->mem_size(), "check that mem_size() is constant");
tschatzl@5122 736 sum += _first_all_fine_prts->mem_size() * _n_fine_entries;
ysr@777 737 }
johnc@3891 738 sum += (sizeof(PerRegionTable*) * _max_fine_entries);
ysr@777 739 sum += (_coarse_map.size_in_words() * HeapWordSize);
ysr@777 740 sum += (_sparse_table.mem_size());
tschatzl@6932 741 sum += sizeof(OtherRegionsTable) - sizeof(_sparse_table); // Avoid double counting above.
ysr@777 742 return sum;
ysr@777 743 }
ysr@777 744
ysr@777 745 size_t OtherRegionsTable::static_mem_size() {
tschatzl@6407 746 return FromCardCache::static_mem_size();
ysr@777 747 }
ysr@777 748
ysr@777 749 size_t OtherRegionsTable::fl_mem_size() {
johnc@3891 750 return PerRegionTable::fl_mem_size();
ysr@777 751 }
ysr@777 752
ysr@777 753 void OtherRegionsTable::clear_fcc() {
tschatzl@7091 754 FromCardCache::clear(hr()->hrm_index());
ysr@777 755 }
ysr@777 756
ysr@777 757 void OtherRegionsTable::clear() {
johnc@3956 758 // if there are no entries, skip this step
johnc@3956 759 if (_first_all_fine_prts != NULL) {
johnc@3956 760 guarantee(_first_all_fine_prts != NULL && _last_all_fine_prts != NULL, "just checking");
johnc@3956 761 PerRegionTable::bulk_free(_first_all_fine_prts, _last_all_fine_prts);
johnc@3956 762 memset(_fine_grain_regions, 0, _max_fine_entries * sizeof(_fine_grain_regions[0]));
johnc@3956 763 } else {
johnc@3956 764 guarantee(_first_all_fine_prts == NULL && _last_all_fine_prts == NULL, "just checking");
ysr@777 765 }
johnc@3956 766
johnc@3956 767 _first_all_fine_prts = _last_all_fine_prts = NULL;
ysr@777 768 _sparse_table.clear();
ysr@777 769 _coarse_map.clear();
ysr@777 770 _n_fine_entries = 0;
ysr@777 771 _n_coarse_entries = 0;
ysr@777 772
ysr@777 773 clear_fcc();
ysr@777 774 }
ysr@777 775
ysr@777 776 bool OtherRegionsTable::del_single_region_table(size_t ind,
ysr@777 777 HeapRegion* hr) {
ysr@777 778 assert(0 <= ind && ind < _max_fine_entries, "Preconditions.");
johnc@3891 779 PerRegionTable** prev_addr = &_fine_grain_regions[ind];
johnc@3891 780 PerRegionTable* prt = *prev_addr;
ysr@777 781 while (prt != NULL && prt->hr() != hr) {
johnc@3956 782 prev_addr = prt->collision_list_next_addr();
johnc@3956 783 prt = prt->collision_list_next();
ysr@777 784 }
ysr@777 785 if (prt != NULL) {
ysr@777 786 assert(prt->hr() == hr, "Loop postcondition.");
johnc@3956 787 *prev_addr = prt->collision_list_next();
johnc@3956 788 unlink_from_all(prt);
johnc@3891 789 PerRegionTable::free(prt);
ysr@777 790 _n_fine_entries--;
ysr@777 791 return true;
ysr@777 792 } else {
ysr@777 793 return false;
ysr@777 794 }
ysr@777 795 }
ysr@777 796
ysr@1280 797 bool OtherRegionsTable::contains_reference(OopOrNarrowOopStar from) const {
ysr@777 798 // Cast away const in this case.
tschatzl@6402 799 MutexLockerEx x((Mutex*)_m, Mutex::_no_safepoint_check_flag);
ysr@777 800 return contains_reference_locked(from);
ysr@777 801 }
ysr@777 802
ysr@1280 803 bool OtherRegionsTable::contains_reference_locked(OopOrNarrowOopStar from) const {
ysr@777 804 HeapRegion* hr = _g1h->heap_region_containing_raw(from);
tschatzl@7091 805 RegionIdx_t hr_ind = (RegionIdx_t) hr->hrm_index();
ysr@777 806 // Is this region in the coarse map?
ysr@777 807 if (_coarse_map.at(hr_ind)) return true;
ysr@777 808
johnc@3891 809 PerRegionTable* prt = find_region_table(hr_ind & _mod_max_fine_entries_mask,
ysr@777 810 hr);
ysr@777 811 if (prt != NULL) {
ysr@777 812 return prt->contains_reference(from);
ysr@777 813
ysr@777 814 } else {
ysr@777 815 uintptr_t from_card =
ysr@777 816 (uintptr_t(from) >> CardTableModRefBS::card_shift);
ysr@777 817 uintptr_t hr_bot_card_index =
ysr@777 818 uintptr_t(hr->bottom()) >> CardTableModRefBS::card_shift;
ysr@777 819 assert(from_card >= hr_bot_card_index, "Inv");
johnc@1242 820 CardIdx_t card_index = from_card - hr_bot_card_index;
johnc@3182 821 assert(0 <= card_index && (size_t)card_index < HeapRegion::CardsPerRegion,
tonyp@1377 822 "Must be in range.");
johnc@1242 823 return _sparse_table.contains_card(hr_ind, card_index);
ysr@777 824 }
ysr@777 825 }
ysr@777 826
tonyp@2493 827 void
tonyp@2493 828 OtherRegionsTable::do_cleanup_work(HRRSCleanupTask* hrrs_cleanup_task) {
tonyp@2493 829 _sparse_table.do_cleanup_work(hrrs_cleanup_task);
tonyp@2493 830 }
tonyp@2493 831
iveresov@1230 832 // Determines how many threads can add records to an rset in parallel.
iveresov@1230 833 // This can be done by either mutator threads together with the
iveresov@1230 834 // concurrent refinement threads or GC threads.
tschatzl@6403 835 uint HeapRegionRemSet::num_par_rem_sets() {
vkempik@6552 836 return MAX2(DirtyCardQueueSet::num_par_ids() + ConcurrentG1Refine::thread_num(), (uint)ParallelGCThreads);
ysr@777 837 }
ysr@777 838
ysr@777 839 HeapRegionRemSet::HeapRegionRemSet(G1BlockOffsetSharedArray* bosa,
ysr@777 840 HeapRegion* hr)
tschatzl@6402 841 : _bosa(bosa),
tschatzl@7091 842 _m(Mutex::leaf, FormatBuffer<128>("HeapRegionRemSet lock #%u", hr->hrm_index()), true),
tschatzl@7051 843 _code_roots(), _other_regions(hr, &_m), _iter_state(Unclaimed), _iter_claimed(0) {
tonyp@2974 844 reset_for_par_iteration();
tonyp@2974 845 }
ysr@777 846
iveresov@1696 847 void HeapRegionRemSet::setup_remset_size() {
iveresov@1696 848 // Setup sparse and fine-grain tables sizes.
iveresov@1696 849 // table_size = base * (log(region_size / 1M) + 1)
brutisso@3810 850 const int LOG_M = 20;
brutisso@3810 851 int region_size_log_mb = MAX2(HeapRegion::LogOfHRGrainBytes - LOG_M, 0);
iveresov@1696 852 if (FLAG_IS_DEFAULT(G1RSetSparseRegionEntries)) {
iveresov@1696 853 G1RSetSparseRegionEntries = G1RSetSparseRegionEntriesBase * (region_size_log_mb + 1);
iveresov@1696 854 }
iveresov@1696 855 if (FLAG_IS_DEFAULT(G1RSetRegionEntries)) {
iveresov@1696 856 G1RSetRegionEntries = G1RSetRegionEntriesBase * (region_size_log_mb + 1);
iveresov@1696 857 }
iveresov@1696 858 guarantee(G1RSetSparseRegionEntries > 0 && G1RSetRegionEntries > 0 , "Sanity");
iveresov@1696 859 }
iveresov@1696 860
ysr@777 861 bool HeapRegionRemSet::claim_iter() {
ysr@777 862 if (_iter_state != Unclaimed) return false;
ysr@777 863 jint res = Atomic::cmpxchg(Claimed, (jint*)(&_iter_state), Unclaimed);
ysr@777 864 return (res == Unclaimed);
ysr@777 865 }
ysr@777 866
ysr@777 867 void HeapRegionRemSet::set_iter_complete() {
ysr@777 868 _iter_state = Complete;
ysr@777 869 }
ysr@777 870
ysr@777 871 bool HeapRegionRemSet::iter_is_complete() {
ysr@777 872 return _iter_state == Complete;
ysr@777 873 }
ysr@777 874
ysr@777 875 #ifndef PRODUCT
tschatzl@6402 876 void HeapRegionRemSet::print() {
johnc@5014 877 HeapRegionRemSetIterator iter(this);
ysr@777 878 size_t card_index;
ysr@777 879 while (iter.has_next(card_index)) {
ysr@777 880 HeapWord* card_start =
ysr@777 881 G1CollectedHeap::heap()->bot_shared()->address_for_index(card_index);
tonyp@2974 882 gclog_or_tty->print_cr(" Card " PTR_FORMAT, card_start);
ysr@777 883 }
ysr@777 884 if (iter.n_yielded() != occupied()) {
ysr@777 885 gclog_or_tty->print_cr("Yielded disagrees with occupied:");
ysr@777 886 gclog_or_tty->print_cr(" %6d yielded (%6d coarse, %6d fine).",
ysr@777 887 iter.n_yielded(),
ysr@777 888 iter.n_yielded_coarse(), iter.n_yielded_fine());
ysr@777 889 gclog_or_tty->print_cr(" %6d occ (%6d coarse, %6d fine).",
ysr@777 890 occupied(), occ_coarse(), occ_fine());
ysr@777 891 }
ysr@777 892 guarantee(iter.n_yielded() == occupied(),
ysr@777 893 "We should have yielded all the represented cards.");
ysr@777 894 }
ysr@777 895 #endif
ysr@777 896
ysr@777 897 void HeapRegionRemSet::cleanup() {
ysr@777 898 SparsePRT::cleanup_all();
ysr@777 899 }
ysr@777 900
ysr@777 901 void HeapRegionRemSet::clear() {
tschatzl@6402 902 MutexLockerEx x(&_m, Mutex::_no_safepoint_check_flag);
tschatzl@6402 903 clear_locked();
tschatzl@6402 904 }
johnc@5548 905
tschatzl@6402 906 void HeapRegionRemSet::clear_locked() {
tschatzl@6402 907 _code_roots.clear();
ysr@777 908 _other_regions.clear();
tschatzl@6402 909 assert(occupied_locked() == 0, "Should be clear.");
tonyp@2974 910 reset_for_par_iteration();
tonyp@2974 911 }
tonyp@2974 912
tonyp@2974 913 void HeapRegionRemSet::reset_for_par_iteration() {
tonyp@2974 914 _iter_state = Unclaimed;
tonyp@2974 915 _iter_claimed = 0;
tonyp@2974 916 // It's good to check this to make sure that the two methods are in sync.
tonyp@2974 917 assert(verify_ready_for_par_iteration(), "post-condition");
ysr@777 918 }
ysr@777 919
ysr@777 920 void HeapRegionRemSet::scrub(CardTableModRefBS* ctbs,
ysr@777 921 BitMap* region_bm, BitMap* card_bm) {
ysr@777 922 _other_regions.scrub(ctbs, region_bm, card_bm);
ysr@777 923 }
ysr@777 924
johnc@5548 925 // Code roots support
mgerdin@7208 926 //
mgerdin@7208 927 // The code root set is protected by two separate locking schemes
mgerdin@7208 928 // When at safepoint the per-hrrs lock must be held during modifications
mgerdin@7208 929 // except when doing a full gc.
mgerdin@7208 930 // When not at safepoint the CodeCache_lock must be held during modifications.
mgerdin@7208 931 // When concurrent readers access the contains() function
mgerdin@7208 932 // (during the evacuation phase) no removals are allowed.
johnc@5548 933
johnc@5548 934 void HeapRegionRemSet::add_strong_code_root(nmethod* nm) {
johnc@5548 935 assert(nm != NULL, "sanity");
mgerdin@7208 936 // Optimistic unlocked contains-check
mgerdin@7208 937 if (!_code_roots.contains(nm)) {
mgerdin@7208 938 MutexLockerEx ml(&_m, Mutex::_no_safepoint_check_flag);
mgerdin@7208 939 add_strong_code_root_locked(nm);
mgerdin@7208 940 }
mgerdin@7208 941 }
mgerdin@7208 942
mgerdin@7208 943 void HeapRegionRemSet::add_strong_code_root_locked(nmethod* nm) {
mgerdin@7208 944 assert(nm != NULL, "sanity");
tschatzl@6402 945 _code_roots.add(nm);
johnc@5548 946 }
johnc@5548 947
johnc@5548 948 void HeapRegionRemSet::remove_strong_code_root(nmethod* nm) {
johnc@5548 949 assert(nm != NULL, "sanity");
stefank@6992 950 assert_locked_or_safepoint(CodeCache_lock);
stefank@6992 951
mgerdin@7208 952 MutexLockerEx ml(CodeCache_lock->owned_by_self() ? NULL : &_m, Mutex::_no_safepoint_check_flag);
mgerdin@7208 953 _code_roots.remove(nm);
stefank@6992 954
johnc@5548 955 // Check that there were no duplicates
tschatzl@6402 956 guarantee(!_code_roots.contains(nm), "duplicate entry found");
johnc@5548 957 }
johnc@5548 958
mgerdin@7208 959 void HeapRegionRemSet::strong_code_roots_do(CodeBlobClosure* blk) const {
mgerdin@7208 960 _code_roots.nmethods_do(blk);
johnc@5548 961 }
johnc@5548 962
mgerdin@7208 963 void HeapRegionRemSet::clean_strong_code_roots(HeapRegion* hr) {
mgerdin@7208 964 _code_roots.clean(hr);
johnc@5548 965 }
johnc@5548 966
johnc@5548 967 size_t HeapRegionRemSet::strong_code_roots_mem_size() {
tschatzl@6402 968 return _code_roots.mem_size();
johnc@5548 969 }
johnc@5548 970
tschatzl@6402 971 HeapRegionRemSetIterator:: HeapRegionRemSetIterator(HeapRegionRemSet* hrrs) :
johnc@5014 972 _hrrs(hrrs),
ysr@777 973 _g1h(G1CollectedHeap::heap()),
johnc@5014 974 _coarse_map(&hrrs->_other_regions._coarse_map),
johnc@5014 975 _bosa(hrrs->bosa()),
johnc@5014 976 _is(Sparse),
ysr@777 977 // Set these values so that we increment to the first region.
johnc@5014 978 _coarse_cur_region_index(-1),
johnc@5014 979 _coarse_cur_region_cur_card(HeapRegion::CardsPerRegion-1),
tschatzl@6927 980 _cur_card_in_prt(HeapRegion::CardsPerRegion),
johnc@5014 981 _fine_cur_prt(NULL),
johnc@5014 982 _n_yielded_coarse(0),
johnc@5014 983 _n_yielded_fine(0),
johnc@5014 984 _n_yielded_sparse(0),
johnc@5014 985 _sparse_iter(&hrrs->_other_regions._sparse_table) {}
ysr@777 986
ysr@777 987 bool HeapRegionRemSetIterator::coarse_has_next(size_t& card_index) {
ysr@777 988 if (_hrrs->_other_regions._n_coarse_entries == 0) return false;
ysr@777 989 // Go to the next card.
ysr@777 990 _coarse_cur_region_cur_card++;
ysr@777 991 // Was the last the last card in the current region?
tonyp@1377 992 if (_coarse_cur_region_cur_card == HeapRegion::CardsPerRegion) {
ysr@777 993 // Yes: find the next region. This may leave _coarse_cur_region_index
ysr@777 994 // Set to the last index, in which case there are no more coarse
ysr@777 995 // regions.
ysr@777 996 _coarse_cur_region_index =
ysr@777 997 (int) _coarse_map->get_next_one_offset(_coarse_cur_region_index + 1);
ysr@777 998 if ((size_t)_coarse_cur_region_index < _coarse_map->size()) {
ysr@777 999 _coarse_cur_region_cur_card = 0;
ysr@777 1000 HeapWord* r_bot =
tonyp@3713 1001 _g1h->region_at((uint) _coarse_cur_region_index)->bottom();
ysr@777 1002 _cur_region_card_offset = _bosa->index_for(r_bot);
ysr@777 1003 } else {
ysr@777 1004 return false;
ysr@777 1005 }
ysr@777 1006 }
ysr@777 1007 // If we didn't return false above, then we can yield a card.
ysr@777 1008 card_index = _cur_region_card_offset + _coarse_cur_region_cur_card;
ysr@777 1009 return true;
ysr@777 1010 }
ysr@777 1011
ysr@777 1012 bool HeapRegionRemSetIterator::fine_has_next(size_t& card_index) {
ysr@777 1013 if (fine_has_next()) {
tschatzl@6927 1014 _cur_card_in_prt =
tschatzl@6927 1015 _fine_cur_prt->_bm.get_next_one_offset(_cur_card_in_prt + 1);
ysr@777 1016 }
tschatzl@6927 1017 if (_cur_card_in_prt == HeapRegion::CardsPerRegion) {
tschatzl@6927 1018 // _fine_cur_prt may still be NULL in case if there are not PRTs at all for
tschatzl@6927 1019 // the remembered set.
tschatzl@6927 1020 if (_fine_cur_prt == NULL || _fine_cur_prt->next() == NULL) {
tschatzl@6927 1021 return false;
ysr@777 1022 }
tschatzl@6927 1023 PerRegionTable* next_prt = _fine_cur_prt->next();
tschatzl@6927 1024 switch_to_prt(next_prt);
tschatzl@6927 1025 _cur_card_in_prt = _fine_cur_prt->_bm.get_next_one_offset(_cur_card_in_prt + 1);
ysr@777 1026 }
tschatzl@6927 1027
tschatzl@6927 1028 card_index = _cur_region_card_offset + _cur_card_in_prt;
tschatzl@6927 1029 guarantee(_cur_card_in_prt < HeapRegion::CardsPerRegion,
tschatzl@6927 1030 err_msg("Card index "SIZE_FORMAT" must be within the region", _cur_card_in_prt));
ysr@777 1031 return true;
ysr@777 1032 }
ysr@777 1033
ysr@777 1034 bool HeapRegionRemSetIterator::fine_has_next() {
tschatzl@6927 1035 return _cur_card_in_prt != HeapRegion::CardsPerRegion;
tschatzl@6927 1036 }
tschatzl@6927 1037
tschatzl@6927 1038 void HeapRegionRemSetIterator::switch_to_prt(PerRegionTable* prt) {
tschatzl@6927 1039 assert(prt != NULL, "Cannot switch to NULL prt");
tschatzl@6927 1040 _fine_cur_prt = prt;
tschatzl@6927 1041
tschatzl@6927 1042 HeapWord* r_bot = _fine_cur_prt->hr()->bottom();
tschatzl@6927 1043 _cur_region_card_offset = _bosa->index_for(r_bot);
tschatzl@6927 1044
tschatzl@6927 1045 // The bitmap scan for the PRT always scans from _cur_region_cur_card + 1.
tschatzl@6927 1046 // To avoid special-casing this start case, and not miss the first bitmap
tschatzl@6927 1047 // entry, initialize _cur_region_cur_card with -1 instead of 0.
tschatzl@6927 1048 _cur_card_in_prt = (size_t)-1;
ysr@777 1049 }
ysr@777 1050
ysr@777 1051 bool HeapRegionRemSetIterator::has_next(size_t& card_index) {
ysr@777 1052 switch (_is) {
tschatzl@6927 1053 case Sparse: {
ysr@777 1054 if (_sparse_iter.has_next(card_index)) {
ysr@777 1055 _n_yielded_sparse++;
ysr@777 1056 return true;
ysr@777 1057 }
ysr@777 1058 // Otherwise, deliberate fall-through
ysr@777 1059 _is = Fine;
tschatzl@6927 1060 PerRegionTable* initial_fine_prt = _hrrs->_other_regions._first_all_fine_prts;
tschatzl@6927 1061 if (initial_fine_prt != NULL) {
tschatzl@6927 1062 switch_to_prt(_hrrs->_other_regions._first_all_fine_prts);
tschatzl@6927 1063 }
tschatzl@6927 1064 }
ysr@777 1065 case Fine:
ysr@777 1066 if (fine_has_next(card_index)) {
ysr@777 1067 _n_yielded_fine++;
ysr@777 1068 return true;
ysr@777 1069 }
ysr@777 1070 // Otherwise, deliberate fall-through
ysr@777 1071 _is = Coarse;
ysr@777 1072 case Coarse:
ysr@777 1073 if (coarse_has_next(card_index)) {
ysr@777 1074 _n_yielded_coarse++;
ysr@777 1075 return true;
ysr@777 1076 }
ysr@777 1077 // Otherwise...
ysr@777 1078 break;
ysr@777 1079 }
ysr@777 1080 assert(ParallelGCThreads > 1 ||
ysr@777 1081 n_yielded() == _hrrs->occupied(),
ysr@777 1082 "Should have yielded all the cards in the rem set "
ysr@777 1083 "(in the non-par case).");
ysr@777 1084 return false;
ysr@777 1085 }
ysr@777 1086
ysr@777 1087
ysr@777 1088
ysr@1280 1089 OopOrNarrowOopStar* HeapRegionRemSet::_recorded_oops = NULL;
ysr@1280 1090 HeapWord** HeapRegionRemSet::_recorded_cards = NULL;
ysr@1280 1091 HeapRegion** HeapRegionRemSet::_recorded_regions = NULL;
ysr@1280 1092 int HeapRegionRemSet::_n_recorded = 0;
ysr@777 1093
ysr@777 1094 HeapRegionRemSet::Event* HeapRegionRemSet::_recorded_events = NULL;
ysr@777 1095 int* HeapRegionRemSet::_recorded_event_index = NULL;
ysr@777 1096 int HeapRegionRemSet::_n_recorded_events = 0;
ysr@777 1097
ysr@1280 1098 void HeapRegionRemSet::record(HeapRegion* hr, OopOrNarrowOopStar f) {
ysr@777 1099 if (_recorded_oops == NULL) {
ysr@777 1100 assert(_n_recorded == 0
ysr@777 1101 && _recorded_cards == NULL
ysr@777 1102 && _recorded_regions == NULL,
ysr@777 1103 "Inv");
zgu@3900 1104 _recorded_oops = NEW_C_HEAP_ARRAY(OopOrNarrowOopStar, MaxRecorded, mtGC);
zgu@3900 1105 _recorded_cards = NEW_C_HEAP_ARRAY(HeapWord*, MaxRecorded, mtGC);
zgu@3900 1106 _recorded_regions = NEW_C_HEAP_ARRAY(HeapRegion*, MaxRecorded, mtGC);
ysr@777 1107 }
ysr@777 1108 if (_n_recorded == MaxRecorded) {
ysr@777 1109 gclog_or_tty->print_cr("Filled up 'recorded' (%d).", MaxRecorded);
ysr@777 1110 } else {
ysr@777 1111 _recorded_cards[_n_recorded] =
ysr@777 1112 (HeapWord*)align_size_down(uintptr_t(f),
ysr@777 1113 CardTableModRefBS::card_size);
ysr@777 1114 _recorded_oops[_n_recorded] = f;
ysr@777 1115 _recorded_regions[_n_recorded] = hr;
ysr@777 1116 _n_recorded++;
ysr@777 1117 }
ysr@777 1118 }
ysr@777 1119
ysr@777 1120 void HeapRegionRemSet::record_event(Event evnt) {
ysr@777 1121 if (!G1RecordHRRSEvents) return;
ysr@777 1122
ysr@777 1123 if (_recorded_events == NULL) {
ysr@777 1124 assert(_n_recorded_events == 0
ysr@777 1125 && _recorded_event_index == NULL,
ysr@777 1126 "Inv");
zgu@3900 1127 _recorded_events = NEW_C_HEAP_ARRAY(Event, MaxRecordedEvents, mtGC);
zgu@3900 1128 _recorded_event_index = NEW_C_HEAP_ARRAY(int, MaxRecordedEvents, mtGC);
ysr@777 1129 }
ysr@777 1130 if (_n_recorded_events == MaxRecordedEvents) {
ysr@777 1131 gclog_or_tty->print_cr("Filled up 'recorded_events' (%d).", MaxRecordedEvents);
ysr@777 1132 } else {
ysr@777 1133 _recorded_events[_n_recorded_events] = evnt;
ysr@777 1134 _recorded_event_index[_n_recorded_events] = _n_recorded;
ysr@777 1135 _n_recorded_events++;
ysr@777 1136 }
ysr@777 1137 }
ysr@777 1138
ysr@777 1139 void HeapRegionRemSet::print_event(outputStream* str, Event evnt) {
ysr@777 1140 switch (evnt) {
ysr@777 1141 case Event_EvacStart:
ysr@777 1142 str->print("Evac Start");
ysr@777 1143 break;
ysr@777 1144 case Event_EvacEnd:
ysr@777 1145 str->print("Evac End");
ysr@777 1146 break;
ysr@777 1147 case Event_RSUpdateEnd:
ysr@777 1148 str->print("RS Update End");
ysr@777 1149 break;
ysr@777 1150 }
ysr@777 1151 }
ysr@777 1152
ysr@777 1153 void HeapRegionRemSet::print_recorded() {
ysr@777 1154 int cur_evnt = 0;
ysr@777 1155 Event cur_evnt_kind;
ysr@777 1156 int cur_evnt_ind = 0;
ysr@777 1157 if (_n_recorded_events > 0) {
ysr@777 1158 cur_evnt_kind = _recorded_events[cur_evnt];
ysr@777 1159 cur_evnt_ind = _recorded_event_index[cur_evnt];
ysr@777 1160 }
ysr@777 1161
ysr@777 1162 for (int i = 0; i < _n_recorded; i++) {
ysr@777 1163 while (cur_evnt < _n_recorded_events && i == cur_evnt_ind) {
ysr@777 1164 gclog_or_tty->print("Event: ");
ysr@777 1165 print_event(gclog_or_tty, cur_evnt_kind);
drchase@6680 1166 gclog_or_tty->cr();
ysr@777 1167 cur_evnt++;
ysr@777 1168 if (cur_evnt < MaxRecordedEvents) {
ysr@777 1169 cur_evnt_kind = _recorded_events[cur_evnt];
ysr@777 1170 cur_evnt_ind = _recorded_event_index[cur_evnt];
ysr@777 1171 }
ysr@777 1172 }
ysr@777 1173 gclog_or_tty->print("Added card " PTR_FORMAT " to region [" PTR_FORMAT "...]"
ysr@777 1174 " for ref " PTR_FORMAT ".\n",
ysr@777 1175 _recorded_cards[i], _recorded_regions[i]->bottom(),
ysr@777 1176 _recorded_oops[i]);
ysr@777 1177 }
ysr@777 1178 }
ysr@777 1179
tonyp@2493 1180 void HeapRegionRemSet::reset_for_cleanup_tasks() {
tonyp@2493 1181 SparsePRT::reset_for_cleanup_tasks();
tonyp@2493 1182 }
tonyp@2493 1183
tonyp@2493 1184 void HeapRegionRemSet::do_cleanup_work(HRRSCleanupTask* hrrs_cleanup_task) {
tonyp@2493 1185 _other_regions.do_cleanup_work(hrrs_cleanup_task);
tonyp@2493 1186 }
tonyp@2493 1187
tonyp@2493 1188 void
tonyp@2493 1189 HeapRegionRemSet::finish_cleanup_task(HRRSCleanupTask* hrrs_cleanup_task) {
tonyp@2493 1190 SparsePRT::finish_cleanup_task(hrrs_cleanup_task);
tonyp@2493 1191 }
tonyp@2493 1192
ysr@777 1193 #ifndef PRODUCT
tschatzl@5165 1194 void PerRegionTable::test_fl_mem_size() {
tschatzl@5165 1195 PerRegionTable* dummy = alloc(NULL);
tschatzl@6932 1196
tschatzl@6932 1197 size_t min_prt_size = sizeof(void*) + dummy->bm()->size_in_words() * HeapWordSize;
tschatzl@6932 1198 assert(dummy->mem_size() > min_prt_size,
tschatzl@6932 1199 err_msg("PerRegionTable memory usage is suspiciously small, only has "SIZE_FORMAT" bytes. "
tschatzl@6932 1200 "Should be at least "SIZE_FORMAT" bytes.", dummy->mem_size(), min_prt_size));
tschatzl@5165 1201 free(dummy);
tschatzl@5165 1202 guarantee(dummy->mem_size() == fl_mem_size(), "fl_mem_size() does not return the correct element size");
tschatzl@5165 1203 // try to reset the state
tschatzl@5165 1204 _free_list = NULL;
tschatzl@5165 1205 delete dummy;
tschatzl@5165 1206 }
tschatzl@5165 1207
tschatzl@5165 1208 void HeapRegionRemSet::test_prt() {
tschatzl@5165 1209 PerRegionTable::test_fl_mem_size();
tschatzl@5165 1210 }
tschatzl@5165 1211
ysr@777 1212 void HeapRegionRemSet::test() {
ysr@777 1213 os::sleep(Thread::current(), (jlong)5000, false);
ysr@777 1214 G1CollectedHeap* g1h = G1CollectedHeap::heap();
ysr@777 1215
iveresov@1696 1216 // Run with "-XX:G1LogRSetRegionEntries=2", so that 1 and 5 end up in same
ysr@777 1217 // hash bucket.
ysr@777 1218 HeapRegion* hr0 = g1h->region_at(0);
ysr@777 1219 HeapRegion* hr1 = g1h->region_at(1);
ysr@777 1220 HeapRegion* hr2 = g1h->region_at(5);
ysr@777 1221 HeapRegion* hr3 = g1h->region_at(6);
ysr@777 1222 HeapRegion* hr4 = g1h->region_at(7);
ysr@777 1223 HeapRegion* hr5 = g1h->region_at(8);
ysr@777 1224
ysr@777 1225 HeapWord* hr1_start = hr1->bottom();
ysr@777 1226 HeapWord* hr1_mid = hr1_start + HeapRegion::GrainWords/2;
ysr@777 1227 HeapWord* hr1_last = hr1->end() - 1;
ysr@777 1228
ysr@777 1229 HeapWord* hr2_start = hr2->bottom();
ysr@777 1230 HeapWord* hr2_mid = hr2_start + HeapRegion::GrainWords/2;
ysr@777 1231 HeapWord* hr2_last = hr2->end() - 1;
ysr@777 1232
ysr@777 1233 HeapWord* hr3_start = hr3->bottom();
ysr@777 1234 HeapWord* hr3_mid = hr3_start + HeapRegion::GrainWords/2;
ysr@777 1235 HeapWord* hr3_last = hr3->end() - 1;
ysr@777 1236
ysr@777 1237 HeapRegionRemSet* hrrs = hr0->rem_set();
ysr@777 1238
ysr@777 1239 // Make three references from region 0x101...
ysr@1280 1240 hrrs->add_reference((OopOrNarrowOopStar)hr1_start);
ysr@1280 1241 hrrs->add_reference((OopOrNarrowOopStar)hr1_mid);
ysr@1280 1242 hrrs->add_reference((OopOrNarrowOopStar)hr1_last);
ysr@777 1243
ysr@1280 1244 hrrs->add_reference((OopOrNarrowOopStar)hr2_start);
ysr@1280 1245 hrrs->add_reference((OopOrNarrowOopStar)hr2_mid);
ysr@1280 1246 hrrs->add_reference((OopOrNarrowOopStar)hr2_last);
ysr@777 1247
ysr@1280 1248 hrrs->add_reference((OopOrNarrowOopStar)hr3_start);
ysr@1280 1249 hrrs->add_reference((OopOrNarrowOopStar)hr3_mid);
ysr@1280 1250 hrrs->add_reference((OopOrNarrowOopStar)hr3_last);
ysr@777 1251
ysr@777 1252 // Now cause a coarsening.
ysr@1280 1253 hrrs->add_reference((OopOrNarrowOopStar)hr4->bottom());
ysr@1280 1254 hrrs->add_reference((OopOrNarrowOopStar)hr5->bottom());
ysr@777 1255
ysr@777 1256 // Now, does iteration yield these three?
johnc@5014 1257 HeapRegionRemSetIterator iter(hrrs);
ysr@777 1258 size_t sum = 0;
ysr@777 1259 size_t card_index;
ysr@777 1260 while (iter.has_next(card_index)) {
ysr@777 1261 HeapWord* card_start =
ysr@777 1262 G1CollectedHeap::heap()->bot_shared()->address_for_index(card_index);
ysr@777 1263 gclog_or_tty->print_cr(" Card " PTR_FORMAT ".", card_start);
ysr@777 1264 sum++;
ysr@777 1265 }
ysr@777 1266 guarantee(sum == 11 - 3 + 2048, "Failure");
ysr@777 1267 guarantee(sum == hrrs->occupied(), "Failure");
ysr@777 1268 }
ysr@777 1269 #endif

mercurial