Thu, 21 Aug 2014 16:44:41 +0200
8055098: WB API should be extended to provide information about size and age of object.
Summary: Extend the WhiteBox API to provide information about the size and age of objects. Further add a mechanism to trigger a young GC.
Reviewed-by: tschatzl, sjohanss
Contributed-by: Leonid Mesnik <leonid.mesnik@oracle.com>
ysr@777 | 1 | /* |
mikael@6198 | 2 | * Copyright (c) 2001, 2013, 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/heapRegion.hpp" |
stefank@2314 | 27 | #include "gc_implementation/g1/heapRegionRemSet.hpp" |
stefank@2314 | 28 | #include "gc_implementation/g1/sparsePRT.hpp" |
stefank@2314 | 29 | #include "memory/allocation.inline.hpp" |
stefank@2314 | 30 | #include "memory/cardTableModRefBS.hpp" |
stefank@2314 | 31 | #include "memory/space.inline.hpp" |
stefank@2314 | 32 | #include "runtime/mutexLocker.hpp" |
ysr@777 | 33 | |
ysr@777 | 34 | #define SPARSE_PRT_VERBOSE 0 |
ysr@777 | 35 | |
iveresov@1696 | 36 | #define UNROLL_CARD_LOOPS 1 |
ysr@777 | 37 | |
johnc@1242 | 38 | void SparsePRTEntry::init(RegionIdx_t region_ind) { |
ysr@777 | 39 | _region_ind = region_ind; |
ysr@777 | 40 | _next_index = NullEntry; |
iveresov@1696 | 41 | |
ysr@777 | 42 | #if UNROLL_CARD_LOOPS |
iveresov@1696 | 43 | assert((cards_num() & (UnrollFactor - 1)) == 0, "Invalid number of cards in the entry"); |
iveresov@1696 | 44 | for (int i = 0; i < cards_num(); i += UnrollFactor) { |
iveresov@1696 | 45 | _cards[i] = NullEntry; |
iveresov@1696 | 46 | _cards[i + 1] = NullEntry; |
iveresov@1696 | 47 | _cards[i + 2] = NullEntry; |
iveresov@1696 | 48 | _cards[i + 3] = NullEntry; |
iveresov@1696 | 49 | } |
ysr@777 | 50 | #else |
iveresov@1696 | 51 | for (int i = 0; i < cards_num(); i++) |
johnc@1242 | 52 | _cards[i] = NullEntry; |
ysr@777 | 53 | #endif |
ysr@777 | 54 | } |
ysr@777 | 55 | |
johnc@1242 | 56 | bool SparsePRTEntry::contains_card(CardIdx_t card_index) const { |
ysr@777 | 57 | #if UNROLL_CARD_LOOPS |
iveresov@1696 | 58 | assert((cards_num() & (UnrollFactor - 1)) == 0, "Invalid number of cards in the entry"); |
iveresov@1696 | 59 | for (int i = 0; i < cards_num(); i += UnrollFactor) { |
iveresov@1696 | 60 | if (_cards[i] == card_index || |
iveresov@1696 | 61 | _cards[i + 1] == card_index || |
iveresov@1696 | 62 | _cards[i + 2] == card_index || |
iveresov@1696 | 63 | _cards[i + 3] == card_index) return true; |
iveresov@1696 | 64 | } |
ysr@777 | 65 | #else |
iveresov@1696 | 66 | for (int i = 0; i < cards_num(); i++) { |
ysr@777 | 67 | if (_cards[i] == card_index) return true; |
ysr@777 | 68 | } |
ysr@777 | 69 | #endif |
ysr@777 | 70 | // Otherwise, we're full. |
ysr@777 | 71 | return false; |
ysr@777 | 72 | } |
ysr@777 | 73 | |
ysr@777 | 74 | int SparsePRTEntry::num_valid_cards() const { |
ysr@777 | 75 | int sum = 0; |
ysr@777 | 76 | #if UNROLL_CARD_LOOPS |
iveresov@1696 | 77 | assert((cards_num() & (UnrollFactor - 1)) == 0, "Invalid number of cards in the entry"); |
iveresov@1696 | 78 | for (int i = 0; i < cards_num(); i += UnrollFactor) { |
iveresov@1696 | 79 | sum += (_cards[i] != NullEntry); |
iveresov@1696 | 80 | sum += (_cards[i + 1] != NullEntry); |
iveresov@1696 | 81 | sum += (_cards[i + 2] != NullEntry); |
iveresov@1696 | 82 | sum += (_cards[i + 3] != NullEntry); |
iveresov@1696 | 83 | } |
ysr@777 | 84 | #else |
iveresov@1696 | 85 | for (int i = 0; i < cards_num(); i++) { |
iveresov@1696 | 86 | sum += (_cards[i] != NullEntry); |
ysr@777 | 87 | } |
ysr@777 | 88 | #endif |
ysr@777 | 89 | // Otherwise, we're full. |
ysr@777 | 90 | return sum; |
ysr@777 | 91 | } |
ysr@777 | 92 | |
johnc@1242 | 93 | SparsePRTEntry::AddCardResult SparsePRTEntry::add_card(CardIdx_t card_index) { |
ysr@777 | 94 | #if UNROLL_CARD_LOOPS |
iveresov@1696 | 95 | assert((cards_num() & (UnrollFactor - 1)) == 0, "Invalid number of cards in the entry"); |
iveresov@1696 | 96 | CardIdx_t c; |
iveresov@1696 | 97 | for (int i = 0; i < cards_num(); i += UnrollFactor) { |
iveresov@1696 | 98 | c = _cards[i]; |
iveresov@1696 | 99 | if (c == card_index) return found; |
iveresov@1696 | 100 | if (c == NullEntry) { _cards[i] = card_index; return added; } |
iveresov@1696 | 101 | c = _cards[i + 1]; |
iveresov@1696 | 102 | if (c == card_index) return found; |
iveresov@1696 | 103 | if (c == NullEntry) { _cards[i + 1] = card_index; return added; } |
iveresov@1696 | 104 | c = _cards[i + 2]; |
iveresov@1696 | 105 | if (c == card_index) return found; |
iveresov@1696 | 106 | if (c == NullEntry) { _cards[i + 2] = card_index; return added; } |
iveresov@1696 | 107 | c = _cards[i + 3]; |
iveresov@1696 | 108 | if (c == card_index) return found; |
iveresov@1696 | 109 | if (c == NullEntry) { _cards[i + 3] = card_index; return added; } |
iveresov@1696 | 110 | } |
ysr@777 | 111 | #else |
iveresov@1696 | 112 | for (int i = 0; i < cards_num(); i++) { |
johnc@1242 | 113 | CardIdx_t c = _cards[i]; |
ysr@777 | 114 | if (c == card_index) return found; |
iveresov@1696 | 115 | if (c == NullEntry) { _cards[i] = card_index; return added; } |
ysr@777 | 116 | } |
ysr@777 | 117 | #endif |
ysr@777 | 118 | // Otherwise, we're full. |
ysr@777 | 119 | return overflow; |
ysr@777 | 120 | } |
ysr@777 | 121 | |
johnc@1242 | 122 | void SparsePRTEntry::copy_cards(CardIdx_t* cards) const { |
ysr@777 | 123 | #if UNROLL_CARD_LOOPS |
iveresov@1696 | 124 | assert((cards_num() & (UnrollFactor - 1)) == 0, "Invalid number of cards in the entry"); |
iveresov@1696 | 125 | for (int i = 0; i < cards_num(); i += UnrollFactor) { |
iveresov@1696 | 126 | cards[i] = _cards[i]; |
iveresov@1696 | 127 | cards[i + 1] = _cards[i + 1]; |
iveresov@1696 | 128 | cards[i + 2] = _cards[i + 2]; |
iveresov@1696 | 129 | cards[i + 3] = _cards[i + 3]; |
iveresov@1696 | 130 | } |
ysr@777 | 131 | #else |
iveresov@1696 | 132 | for (int i = 0; i < cards_num(); i++) { |
ysr@777 | 133 | cards[i] = _cards[i]; |
ysr@777 | 134 | } |
ysr@777 | 135 | #endif |
ysr@777 | 136 | } |
ysr@777 | 137 | |
ysr@777 | 138 | void SparsePRTEntry::copy_cards(SparsePRTEntry* e) const { |
ysr@777 | 139 | copy_cards(&e->_cards[0]); |
ysr@777 | 140 | } |
ysr@777 | 141 | |
ysr@777 | 142 | // ---------------------------------------------------------------------- |
ysr@777 | 143 | |
ysr@777 | 144 | RSHashTable::RSHashTable(size_t capacity) : |
ysr@777 | 145 | _capacity(capacity), _capacity_mask(capacity-1), |
ysr@777 | 146 | _occupied_entries(0), _occupied_cards(0), |
zgu@3900 | 147 | _entries((SparsePRTEntry*)NEW_C_HEAP_ARRAY(char, SparsePRTEntry::size() * capacity, mtGC)), |
zgu@3900 | 148 | _buckets(NEW_C_HEAP_ARRAY(int, capacity, mtGC)), |
ysr@777 | 149 | _free_list(NullEntry), _free_region(0) |
ysr@777 | 150 | { |
ysr@777 | 151 | clear(); |
ysr@777 | 152 | } |
ysr@777 | 153 | |
ysr@777 | 154 | RSHashTable::~RSHashTable() { |
ysr@777 | 155 | if (_entries != NULL) { |
zgu@3900 | 156 | FREE_C_HEAP_ARRAY(SparsePRTEntry, _entries, mtGC); |
ysr@777 | 157 | _entries = NULL; |
ysr@777 | 158 | } |
ysr@777 | 159 | if (_buckets != NULL) { |
zgu@3900 | 160 | FREE_C_HEAP_ARRAY(int, _buckets, mtGC); |
ysr@777 | 161 | _buckets = NULL; |
ysr@777 | 162 | } |
ysr@777 | 163 | } |
ysr@777 | 164 | |
ysr@777 | 165 | void RSHashTable::clear() { |
ysr@777 | 166 | _occupied_entries = 0; |
ysr@777 | 167 | _occupied_cards = 0; |
ysr@777 | 168 | guarantee(_entries != NULL, "INV"); |
ysr@777 | 169 | guarantee(_buckets != NULL, "INV"); |
johnc@1242 | 170 | |
johnc@1242 | 171 | guarantee(_capacity <= ((size_t)1 << (sizeof(int)*BitsPerByte-1)) - 1, |
johnc@1242 | 172 | "_capacity too large"); |
johnc@1242 | 173 | |
ysr@777 | 174 | // This will put -1 == NullEntry in the key field of all entries. |
iveresov@1696 | 175 | memset(_entries, NullEntry, _capacity * SparsePRTEntry::size()); |
iveresov@1696 | 176 | memset(_buckets, NullEntry, _capacity * sizeof(int)); |
ysr@777 | 177 | _free_list = NullEntry; |
ysr@777 | 178 | _free_region = 0; |
ysr@777 | 179 | } |
ysr@777 | 180 | |
johnc@1242 | 181 | bool RSHashTable::add_card(RegionIdx_t region_ind, CardIdx_t card_index) { |
ysr@777 | 182 | SparsePRTEntry* e = entry_for_region_ind_create(region_ind); |
ysr@777 | 183 | assert(e != NULL && e->r_ind() == region_ind, |
ysr@777 | 184 | "Postcondition of call above."); |
ysr@777 | 185 | SparsePRTEntry::AddCardResult res = e->add_card(card_index); |
ysr@777 | 186 | if (res == SparsePRTEntry::added) _occupied_cards++; |
ysr@777 | 187 | #if SPARSE_PRT_VERBOSE |
ysr@777 | 188 | gclog_or_tty->print_cr(" after add_card[%d]: valid-cards = %d.", |
iveresov@1696 | 189 | pointer_delta(e, _entries, SparsePRTEntry::size()), |
iveresov@1696 | 190 | e->num_valid_cards()); |
ysr@777 | 191 | #endif |
ysr@777 | 192 | assert(e->num_valid_cards() > 0, "Postcondition"); |
ysr@777 | 193 | return res != SparsePRTEntry::overflow; |
ysr@777 | 194 | } |
ysr@777 | 195 | |
johnc@1242 | 196 | bool RSHashTable::get_cards(RegionIdx_t region_ind, CardIdx_t* cards) { |
johnc@1242 | 197 | int ind = (int) (region_ind & capacity_mask()); |
johnc@1242 | 198 | int cur_ind = _buckets[ind]; |
ysr@777 | 199 | SparsePRTEntry* cur; |
ysr@777 | 200 | while (cur_ind != NullEntry && |
ysr@777 | 201 | (cur = entry(cur_ind))->r_ind() != region_ind) { |
ysr@777 | 202 | cur_ind = cur->next_index(); |
ysr@777 | 203 | } |
ysr@777 | 204 | |
ysr@777 | 205 | if (cur_ind == NullEntry) return false; |
ysr@777 | 206 | // Otherwise... |
ysr@777 | 207 | assert(cur->r_ind() == region_ind, "Postcondition of loop + test above."); |
ysr@777 | 208 | assert(cur->num_valid_cards() > 0, "Inv"); |
ysr@777 | 209 | cur->copy_cards(cards); |
ysr@777 | 210 | return true; |
ysr@777 | 211 | } |
ysr@777 | 212 | |
iveresov@1696 | 213 | SparsePRTEntry* RSHashTable::get_entry(RegionIdx_t region_ind) { |
iveresov@1696 | 214 | int ind = (int) (region_ind & capacity_mask()); |
iveresov@1696 | 215 | int cur_ind = _buckets[ind]; |
iveresov@1696 | 216 | SparsePRTEntry* cur; |
iveresov@1696 | 217 | while (cur_ind != NullEntry && |
iveresov@1696 | 218 | (cur = entry(cur_ind))->r_ind() != region_ind) { |
iveresov@1696 | 219 | cur_ind = cur->next_index(); |
iveresov@1696 | 220 | } |
iveresov@1696 | 221 | |
iveresov@1696 | 222 | if (cur_ind == NullEntry) return NULL; |
iveresov@1696 | 223 | // Otherwise... |
iveresov@1696 | 224 | assert(cur->r_ind() == region_ind, "Postcondition of loop + test above."); |
iveresov@1696 | 225 | assert(cur->num_valid_cards() > 0, "Inv"); |
iveresov@1696 | 226 | return cur; |
iveresov@1696 | 227 | } |
iveresov@1696 | 228 | |
johnc@1242 | 229 | bool RSHashTable::delete_entry(RegionIdx_t region_ind) { |
johnc@1242 | 230 | int ind = (int) (region_ind & capacity_mask()); |
johnc@1242 | 231 | int* prev_loc = &_buckets[ind]; |
johnc@1242 | 232 | int cur_ind = *prev_loc; |
ysr@777 | 233 | SparsePRTEntry* cur; |
ysr@777 | 234 | while (cur_ind != NullEntry && |
ysr@777 | 235 | (cur = entry(cur_ind))->r_ind() != region_ind) { |
ysr@777 | 236 | prev_loc = cur->next_index_addr(); |
ysr@777 | 237 | cur_ind = *prev_loc; |
ysr@777 | 238 | } |
ysr@777 | 239 | |
ysr@777 | 240 | if (cur_ind == NullEntry) return false; |
ysr@777 | 241 | // Otherwise, splice out "cur". |
ysr@777 | 242 | *prev_loc = cur->next_index(); |
ysr@777 | 243 | _occupied_cards -= cur->num_valid_cards(); |
ysr@777 | 244 | free_entry(cur_ind); |
ysr@777 | 245 | _occupied_entries--; |
ysr@777 | 246 | return true; |
ysr@777 | 247 | } |
ysr@777 | 248 | |
johnc@1242 | 249 | SparsePRTEntry* |
johnc@1242 | 250 | RSHashTable::entry_for_region_ind(RegionIdx_t region_ind) const { |
ysr@777 | 251 | assert(occupied_entries() < capacity(), "Precondition"); |
johnc@1242 | 252 | int ind = (int) (region_ind & capacity_mask()); |
johnc@1242 | 253 | int cur_ind = _buckets[ind]; |
ysr@777 | 254 | SparsePRTEntry* cur; |
ysr@777 | 255 | while (cur_ind != NullEntry && |
ysr@777 | 256 | (cur = entry(cur_ind))->r_ind() != region_ind) { |
ysr@777 | 257 | cur_ind = cur->next_index(); |
ysr@777 | 258 | } |
ysr@777 | 259 | |
ysr@777 | 260 | if (cur_ind != NullEntry) { |
ysr@777 | 261 | assert(cur->r_ind() == region_ind, "Loop postcondition + test"); |
ysr@777 | 262 | return cur; |
ysr@777 | 263 | } else { |
ysr@777 | 264 | return NULL; |
ysr@777 | 265 | } |
ysr@777 | 266 | } |
ysr@777 | 267 | |
johnc@1242 | 268 | SparsePRTEntry* |
johnc@1242 | 269 | RSHashTable::entry_for_region_ind_create(RegionIdx_t region_ind) { |
ysr@777 | 270 | SparsePRTEntry* res = entry_for_region_ind(region_ind); |
ysr@777 | 271 | if (res == NULL) { |
johnc@1242 | 272 | int new_ind = alloc_entry(); |
ysr@777 | 273 | assert(0 <= new_ind && (size_t)new_ind < capacity(), "There should be room."); |
ysr@777 | 274 | res = entry(new_ind); |
ysr@777 | 275 | res->init(region_ind); |
ysr@777 | 276 | // Insert at front. |
johnc@1242 | 277 | int ind = (int) (region_ind & capacity_mask()); |
ysr@777 | 278 | res->set_next_index(_buckets[ind]); |
ysr@777 | 279 | _buckets[ind] = new_ind; |
ysr@777 | 280 | _occupied_entries++; |
ysr@777 | 281 | } |
ysr@777 | 282 | return res; |
ysr@777 | 283 | } |
ysr@777 | 284 | |
johnc@1242 | 285 | int RSHashTable::alloc_entry() { |
johnc@1242 | 286 | int res; |
ysr@777 | 287 | if (_free_list != NullEntry) { |
ysr@777 | 288 | res = _free_list; |
ysr@777 | 289 | _free_list = entry(res)->next_index(); |
ysr@777 | 290 | return res; |
ysr@777 | 291 | } else if ((size_t) _free_region+1 < capacity()) { |
ysr@777 | 292 | res = _free_region; |
ysr@777 | 293 | _free_region++; |
ysr@777 | 294 | return res; |
ysr@777 | 295 | } else { |
ysr@777 | 296 | return NullEntry; |
ysr@777 | 297 | } |
ysr@777 | 298 | } |
ysr@777 | 299 | |
johnc@1242 | 300 | void RSHashTable::free_entry(int fi) { |
ysr@777 | 301 | entry(fi)->set_next_index(_free_list); |
ysr@777 | 302 | _free_list = fi; |
ysr@777 | 303 | } |
ysr@777 | 304 | |
ysr@777 | 305 | void RSHashTable::add_entry(SparsePRTEntry* e) { |
ysr@777 | 306 | assert(e->num_valid_cards() > 0, "Precondition."); |
ysr@777 | 307 | SparsePRTEntry* e2 = entry_for_region_ind_create(e->r_ind()); |
ysr@777 | 308 | e->copy_cards(e2); |
ysr@777 | 309 | _occupied_cards += e2->num_valid_cards(); |
ysr@777 | 310 | assert(e2->num_valid_cards() > 0, "Postcondition."); |
ysr@777 | 311 | } |
ysr@777 | 312 | |
tonyp@2241 | 313 | CardIdx_t RSHashTableIter::find_first_card_in_list() { |
johnc@1242 | 314 | CardIdx_t res; |
ysr@777 | 315 | while (_bl_ind != RSHashTable::NullEntry) { |
ysr@777 | 316 | res = _rsht->entry(_bl_ind)->card(0); |
ysr@777 | 317 | if (res != SparsePRTEntry::NullEntry) { |
ysr@777 | 318 | return res; |
ysr@777 | 319 | } else { |
ysr@777 | 320 | _bl_ind = _rsht->entry(_bl_ind)->next_index(); |
ysr@777 | 321 | } |
ysr@777 | 322 | } |
ysr@777 | 323 | // Otherwise, none found: |
ysr@777 | 324 | return SparsePRTEntry::NullEntry; |
ysr@777 | 325 | } |
ysr@777 | 326 | |
tonyp@2241 | 327 | size_t RSHashTableIter::compute_card_ind(CardIdx_t ci) { |
tonyp@2239 | 328 | return (_rsht->entry(_bl_ind)->r_ind() * HeapRegion::CardsPerRegion) + ci; |
ysr@777 | 329 | } |
ysr@777 | 330 | |
tonyp@2241 | 331 | bool RSHashTableIter::has_next(size_t& card_index) { |
ysr@777 | 332 | _card_ind++; |
johnc@1242 | 333 | CardIdx_t ci; |
iveresov@1696 | 334 | if (_card_ind < SparsePRTEntry::cards_num() && |
ysr@777 | 335 | ((ci = _rsht->entry(_bl_ind)->card(_card_ind)) != |
ysr@777 | 336 | SparsePRTEntry::NullEntry)) { |
ysr@777 | 337 | card_index = compute_card_ind(ci); |
ysr@777 | 338 | return true; |
ysr@777 | 339 | } |
ysr@777 | 340 | // Otherwise, must find the next valid entry. |
ysr@777 | 341 | _card_ind = 0; |
ysr@777 | 342 | |
ysr@777 | 343 | if (_bl_ind != RSHashTable::NullEntry) { |
ysr@777 | 344 | _bl_ind = _rsht->entry(_bl_ind)->next_index(); |
ysr@777 | 345 | ci = find_first_card_in_list(); |
ysr@777 | 346 | if (ci != SparsePRTEntry::NullEntry) { |
ysr@777 | 347 | card_index = compute_card_ind(ci); |
ysr@777 | 348 | return true; |
ysr@777 | 349 | } |
ysr@777 | 350 | } |
ysr@777 | 351 | // If we didn't return above, must go to the next non-null table index. |
ysr@777 | 352 | _tbl_ind++; |
ysr@777 | 353 | while ((size_t)_tbl_ind < _rsht->capacity()) { |
ysr@777 | 354 | _bl_ind = _rsht->_buckets[_tbl_ind]; |
ysr@777 | 355 | ci = find_first_card_in_list(); |
ysr@777 | 356 | if (ci != SparsePRTEntry::NullEntry) { |
ysr@777 | 357 | card_index = compute_card_ind(ci); |
ysr@777 | 358 | return true; |
ysr@777 | 359 | } |
ysr@777 | 360 | // Otherwise, try next entry. |
ysr@777 | 361 | _tbl_ind++; |
ysr@777 | 362 | } |
ysr@777 | 363 | // Otherwise, there were no entry. |
ysr@777 | 364 | return false; |
ysr@777 | 365 | } |
ysr@777 | 366 | |
johnc@1242 | 367 | bool RSHashTable::contains_card(RegionIdx_t region_index, CardIdx_t card_index) const { |
ysr@777 | 368 | SparsePRTEntry* e = entry_for_region_ind(region_index); |
ysr@777 | 369 | return (e != NULL && e->contains_card(card_index)); |
ysr@777 | 370 | } |
ysr@777 | 371 | |
ysr@777 | 372 | size_t RSHashTable::mem_size() const { |
tschatzl@6932 | 373 | return sizeof(RSHashTable) + |
iveresov@1696 | 374 | capacity() * (SparsePRTEntry::size() + sizeof(int)); |
ysr@777 | 375 | } |
ysr@777 | 376 | |
ysr@777 | 377 | // ---------------------------------------------------------------------- |
ysr@777 | 378 | |
ysr@777 | 379 | SparsePRT* SparsePRT::_head_expanded_list = NULL; |
ysr@777 | 380 | |
ysr@777 | 381 | void SparsePRT::add_to_expanded_list(SparsePRT* sprt) { |
ysr@777 | 382 | // We could expand multiple times in a pause -- only put on list once. |
ysr@777 | 383 | if (sprt->expanded()) return; |
ysr@777 | 384 | sprt->set_expanded(true); |
ysr@777 | 385 | SparsePRT* hd = _head_expanded_list; |
ysr@777 | 386 | while (true) { |
ysr@777 | 387 | sprt->_next_expanded = hd; |
ysr@777 | 388 | SparsePRT* res = |
ysr@777 | 389 | (SparsePRT*) |
ysr@777 | 390 | Atomic::cmpxchg_ptr(sprt, &_head_expanded_list, hd); |
ysr@777 | 391 | if (res == hd) return; |
ysr@777 | 392 | else hd = res; |
ysr@777 | 393 | } |
ysr@777 | 394 | } |
ysr@777 | 395 | |
johnc@1242 | 396 | |
ysr@777 | 397 | SparsePRT* SparsePRT::get_from_expanded_list() { |
ysr@777 | 398 | SparsePRT* hd = _head_expanded_list; |
ysr@777 | 399 | while (hd != NULL) { |
ysr@777 | 400 | SparsePRT* next = hd->next_expanded(); |
ysr@777 | 401 | SparsePRT* res = |
ysr@777 | 402 | (SparsePRT*) |
ysr@777 | 403 | Atomic::cmpxchg_ptr(next, &_head_expanded_list, hd); |
ysr@777 | 404 | if (res == hd) { |
ysr@777 | 405 | hd->set_next_expanded(NULL); |
ysr@777 | 406 | return hd; |
ysr@777 | 407 | } else { |
ysr@777 | 408 | hd = res; |
ysr@777 | 409 | } |
ysr@777 | 410 | } |
ysr@777 | 411 | return NULL; |
ysr@777 | 412 | } |
ysr@777 | 413 | |
tonyp@2493 | 414 | void SparsePRT::reset_for_cleanup_tasks() { |
tonyp@2493 | 415 | _head_expanded_list = NULL; |
tonyp@2493 | 416 | } |
tonyp@2493 | 417 | |
tonyp@2493 | 418 | void SparsePRT::do_cleanup_work(SparsePRTCleanupTask* sprt_cleanup_task) { |
tonyp@2493 | 419 | if (should_be_on_expanded_list()) { |
tonyp@2493 | 420 | sprt_cleanup_task->add(this); |
tonyp@2493 | 421 | } |
tonyp@2493 | 422 | } |
tonyp@2493 | 423 | |
tonyp@2493 | 424 | void SparsePRT::finish_cleanup_task(SparsePRTCleanupTask* sprt_cleanup_task) { |
tonyp@2493 | 425 | assert(ParGCRareEvent_lock->owned_by_self(), "pre-condition"); |
tonyp@2493 | 426 | SparsePRT* head = sprt_cleanup_task->head(); |
tonyp@2493 | 427 | SparsePRT* tail = sprt_cleanup_task->tail(); |
tonyp@2493 | 428 | if (head != NULL) { |
tonyp@2493 | 429 | assert(tail != NULL, "if head is not NULL, so should tail"); |
tonyp@2493 | 430 | |
tonyp@2493 | 431 | tail->set_next_expanded(_head_expanded_list); |
tonyp@2493 | 432 | _head_expanded_list = head; |
tonyp@2493 | 433 | } else { |
tonyp@2493 | 434 | assert(tail == NULL, "if head is NULL, so should tail"); |
tonyp@2493 | 435 | } |
tonyp@2493 | 436 | } |
tonyp@2493 | 437 | |
tonyp@2493 | 438 | bool SparsePRT::should_be_on_expanded_list() { |
tonyp@2493 | 439 | if (_expanded) { |
tonyp@2493 | 440 | assert(_cur != _next, "if _expanded is true, cur should be != _next"); |
tonyp@2493 | 441 | } else { |
tonyp@2493 | 442 | assert(_cur == _next, "if _expanded is false, cur should be == _next"); |
tonyp@2493 | 443 | } |
tonyp@2493 | 444 | return expanded(); |
tonyp@2493 | 445 | } |
ysr@777 | 446 | |
ysr@777 | 447 | void SparsePRT::cleanup_all() { |
ysr@777 | 448 | // First clean up all expanded tables so they agree on next and cur. |
ysr@777 | 449 | SparsePRT* sprt = get_from_expanded_list(); |
ysr@777 | 450 | while (sprt != NULL) { |
ysr@777 | 451 | sprt->cleanup(); |
ysr@777 | 452 | sprt = get_from_expanded_list(); |
ysr@777 | 453 | } |
ysr@777 | 454 | } |
ysr@777 | 455 | |
ysr@777 | 456 | |
ysr@777 | 457 | SparsePRT::SparsePRT(HeapRegion* hr) : |
johnc@2063 | 458 | _hr(hr), _expanded(false), _next_expanded(NULL) |
ysr@777 | 459 | { |
ysr@777 | 460 | _cur = new RSHashTable(InitialCapacity); |
ysr@777 | 461 | _next = _cur; |
ysr@777 | 462 | } |
ysr@777 | 463 | |
johnc@1242 | 464 | |
ysr@777 | 465 | SparsePRT::~SparsePRT() { |
ysr@777 | 466 | assert(_next != NULL && _cur != NULL, "Inv"); |
ysr@777 | 467 | if (_cur != _next) { delete _cur; } |
ysr@777 | 468 | delete _next; |
ysr@777 | 469 | } |
ysr@777 | 470 | |
ysr@777 | 471 | |
ysr@777 | 472 | size_t SparsePRT::mem_size() const { |
ysr@777 | 473 | // We ignore "_cur" here, because it either = _next, or else it is |
ysr@777 | 474 | // on the deleted list. |
tschatzl@6932 | 475 | return sizeof(SparsePRT) + _next->mem_size(); |
ysr@777 | 476 | } |
ysr@777 | 477 | |
johnc@1242 | 478 | bool SparsePRT::add_card(RegionIdx_t region_id, CardIdx_t card_index) { |
ysr@777 | 479 | #if SPARSE_PRT_VERBOSE |
tonyp@3713 | 480 | gclog_or_tty->print_cr(" Adding card %d from region %d to region %u sparse.", |
tonyp@2963 | 481 | card_index, region_id, _hr->hrs_index()); |
ysr@777 | 482 | #endif |
ysr@777 | 483 | if (_next->occupied_entries() * 2 > _next->capacity()) { |
ysr@777 | 484 | expand(); |
ysr@777 | 485 | } |
ysr@777 | 486 | return _next->add_card(region_id, card_index); |
ysr@777 | 487 | } |
ysr@777 | 488 | |
johnc@1242 | 489 | bool SparsePRT::get_cards(RegionIdx_t region_id, CardIdx_t* cards) { |
ysr@777 | 490 | return _next->get_cards(region_id, cards); |
ysr@777 | 491 | } |
ysr@777 | 492 | |
iveresov@1696 | 493 | SparsePRTEntry* SparsePRT::get_entry(RegionIdx_t region_id) { |
iveresov@1696 | 494 | return _next->get_entry(region_id); |
iveresov@1696 | 495 | } |
iveresov@1696 | 496 | |
johnc@1242 | 497 | bool SparsePRT::delete_entry(RegionIdx_t region_id) { |
ysr@777 | 498 | return _next->delete_entry(region_id); |
ysr@777 | 499 | } |
ysr@777 | 500 | |
ysr@777 | 501 | void SparsePRT::clear() { |
ysr@777 | 502 | // If they differ, _next is bigger then cur, so next has no chance of |
ysr@777 | 503 | // being the initial size. |
ysr@777 | 504 | if (_next != _cur) { |
ysr@777 | 505 | delete _next; |
ysr@777 | 506 | } |
ysr@777 | 507 | |
ysr@777 | 508 | if (_cur->capacity() != InitialCapacity) { |
ysr@777 | 509 | delete _cur; |
ysr@777 | 510 | _cur = new RSHashTable(InitialCapacity); |
ysr@777 | 511 | } else { |
ysr@777 | 512 | _cur->clear(); |
ysr@777 | 513 | } |
ysr@777 | 514 | _next = _cur; |
tonyp@2493 | 515 | _expanded = false; |
ysr@777 | 516 | } |
ysr@777 | 517 | |
ysr@777 | 518 | void SparsePRT::cleanup() { |
apetrusenko@1480 | 519 | // Make sure that the current and next tables agree. |
apetrusenko@1480 | 520 | if (_cur != _next) { |
apetrusenko@1480 | 521 | delete _cur; |
apetrusenko@1480 | 522 | } |
ysr@777 | 523 | _cur = _next; |
tonyp@1052 | 524 | set_expanded(false); |
ysr@777 | 525 | } |
ysr@777 | 526 | |
ysr@777 | 527 | void SparsePRT::expand() { |
ysr@777 | 528 | RSHashTable* last = _next; |
ysr@777 | 529 | _next = new RSHashTable(last->capacity() * 2); |
ysr@777 | 530 | |
ysr@777 | 531 | #if SPARSE_PRT_VERBOSE |
tonyp@3713 | 532 | gclog_or_tty->print_cr(" Expanded sparse table for %u to %d.", |
tonyp@2963 | 533 | _hr->hrs_index(), _next->capacity()); |
ysr@777 | 534 | #endif |
ysr@777 | 535 | for (size_t i = 0; i < last->capacity(); i++) { |
ysr@777 | 536 | SparsePRTEntry* e = last->entry((int)i); |
ysr@777 | 537 | if (e->valid_entry()) { |
ysr@777 | 538 | #if SPARSE_PRT_VERBOSE |
ysr@777 | 539 | gclog_or_tty->print_cr(" During expansion, transferred entry for %d.", |
ysr@777 | 540 | e->r_ind()); |
ysr@777 | 541 | #endif |
ysr@777 | 542 | _next->add_entry(e); |
ysr@777 | 543 | } |
ysr@777 | 544 | } |
apetrusenko@1480 | 545 | if (last != _cur) { |
apetrusenko@1480 | 546 | delete last; |
apetrusenko@1480 | 547 | } |
ysr@777 | 548 | add_to_expanded_list(this); |
ysr@777 | 549 | } |
tonyp@2493 | 550 | |
tonyp@2493 | 551 | void SparsePRTCleanupTask::add(SparsePRT* sprt) { |
tonyp@2493 | 552 | assert(sprt->should_be_on_expanded_list(), "pre-condition"); |
tonyp@2493 | 553 | |
tonyp@2493 | 554 | sprt->set_next_expanded(NULL); |
tonyp@2493 | 555 | if (_tail != NULL) { |
tonyp@2493 | 556 | _tail->set_next_expanded(sprt); |
tonyp@2493 | 557 | } else { |
tonyp@2493 | 558 | _head = sprt; |
tonyp@2493 | 559 | } |
tonyp@2493 | 560 | _tail = sprt; |
tonyp@2493 | 561 | } |