src/share/vm/gc_implementation/g1/sparsePRT.hpp

Thu, 11 Jun 2009 17:19:33 -0700

author
johnc
date
Thu, 11 Jun 2009 17:19:33 -0700
changeset 1242
d44bdab1c03d
parent 1063
7bb995fbd3c0
child 1377
2c79770d1f6e
permissions
-rw-r--r--

6843694: G1: assert(index < _vs.committed_size(),"bad index"), g1BlockOffsetTable.inline.hpp:55
Summary: For heaps larger than 32Gb, the number of heap regions overflows the data type used to hold the region index in the SparsePRT structure. Changed the region indexes, card indexes, and RSet hash table buckets to ints and added some size overflow guarantees.
Reviewed-by: ysr, 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 // Sparse remembered set for a heap region (the "owning" region). Maps
ysr@777 26 // indices of other regions to short sequences of cards in the other region
ysr@777 27 // that might contain pointers into the owner region.
ysr@777 28
ysr@777 29 // These tables only expand while they are accessed in parallel --
ysr@777 30 // deletions may be done in single-threaded code. This allows us to allow
ysr@777 31 // unsynchronized reads/iterations, as long as expansions caused by
ysr@777 32 // insertions only enqueue old versions for deletions, but do not delete
ysr@777 33 // old versions synchronously.
ysr@777 34
ysr@777 35
apetrusenko@984 36 class SparsePRTEntry: public CHeapObj {
ysr@777 37 public:
johnc@1242 38
ysr@777 39 enum SomePublicConstants {
johnc@1242 40 CardsPerEntry = 4,
johnc@1242 41 NullEntry = -1
ysr@777 42 };
ysr@777 43
ysr@777 44 private:
johnc@1242 45 RegionIdx_t _region_ind;
johnc@1242 46 int _next_index;
johnc@1242 47 CardIdx_t _cards[CardsPerEntry];
ysr@777 48
ysr@777 49 public:
ysr@777 50
ysr@777 51 // Set the region_ind to the given value, and delete all cards.
johnc@1242 52 inline void init(RegionIdx_t region_ind);
ysr@777 53
johnc@1242 54 RegionIdx_t r_ind() const { return _region_ind; }
ysr@777 55 bool valid_entry() const { return r_ind() >= 0; }
johnc@1242 56 void set_r_ind(RegionIdx_t rind) { _region_ind = rind; }
ysr@777 57
johnc@1242 58 int next_index() const { return _next_index; }
johnc@1242 59 int* next_index_addr() { return &_next_index; }
johnc@1242 60 void set_next_index(int ni) { _next_index = ni; }
ysr@777 61
ysr@777 62 // Returns "true" iff the entry contains the given card index.
johnc@1242 63 inline bool contains_card(CardIdx_t card_index) const;
ysr@777 64
ysr@777 65 // Returns the number of non-NULL card entries.
ysr@777 66 inline int num_valid_cards() const;
ysr@777 67
ysr@777 68 // Requires that the entry not contain the given card index. If there is
ysr@777 69 // space available, add the given card index to the entry and return
ysr@777 70 // "true"; otherwise, return "false" to indicate that the entry is full.
ysr@777 71 enum AddCardResult {
ysr@777 72 overflow,
ysr@777 73 found,
ysr@777 74 added
ysr@777 75 };
johnc@1242 76 inline AddCardResult add_card(CardIdx_t card_index);
ysr@777 77
ysr@777 78 // Copy the current entry's cards into "cards".
johnc@1242 79 inline void copy_cards(CardIdx_t* cards) const;
ysr@777 80 // Copy the current entry's cards into the "_card" array of "e."
ysr@777 81 inline void copy_cards(SparsePRTEntry* e) const;
ysr@777 82
johnc@1242 83 inline CardIdx_t card(int i) const { return _cards[i]; }
ysr@777 84 };
ysr@777 85
ysr@777 86
ysr@777 87 class RSHashTable : public CHeapObj {
ysr@777 88
ysr@777 89 friend class RSHashTableIter;
ysr@777 90
ysr@777 91 enum SomePrivateConstants {
ysr@777 92 NullEntry = -1
ysr@777 93 };
ysr@777 94
ysr@777 95 size_t _capacity;
ysr@777 96 size_t _capacity_mask;
ysr@777 97 size_t _occupied_entries;
ysr@777 98 size_t _occupied_cards;
ysr@777 99
ysr@777 100 SparsePRTEntry* _entries;
johnc@1242 101 int* _buckets;
johnc@1242 102 int _free_region;
johnc@1242 103 int _free_list;
ysr@777 104
ysr@777 105 static RSHashTable* _head_deleted_list;
ysr@777 106 RSHashTable* _next_deleted;
ysr@777 107 RSHashTable* next_deleted() { return _next_deleted; }
ysr@777 108 void set_next_deleted(RSHashTable* rsht) { _next_deleted = rsht; }
ysr@777 109 bool _deleted;
ysr@777 110 void set_deleted(bool b) { _deleted = b; }
ysr@777 111
ysr@777 112 // Requires that the caller hold a lock preventing parallel modifying
ysr@777 113 // operations, and that the the table be less than completely full. If
ysr@777 114 // an entry for "region_ind" is already in the table, finds it and
ysr@777 115 // returns its address; otherwise returns "NULL."
johnc@1242 116 SparsePRTEntry* entry_for_region_ind(RegionIdx_t region_ind) const;
ysr@777 117
ysr@777 118 // Requires that the caller hold a lock preventing parallel modifying
ysr@777 119 // operations, and that the the table be less than completely full. If
ysr@777 120 // an entry for "region_ind" is already in the table, finds it and
ysr@777 121 // returns its address; otherwise allocates, initializes, inserts and
ysr@777 122 // returns a new entry for "region_ind".
johnc@1242 123 SparsePRTEntry* entry_for_region_ind_create(RegionIdx_t region_ind);
ysr@777 124
ysr@777 125 // Returns the index of the next free entry in "_entries".
johnc@1242 126 int alloc_entry();
ysr@777 127 // Declares the entry "fi" to be free. (It must have already been
ysr@777 128 // deleted from any bucket lists.
johnc@1242 129 void free_entry(int fi);
ysr@777 130
ysr@777 131 public:
ysr@777 132 RSHashTable(size_t capacity);
ysr@777 133 ~RSHashTable();
ysr@777 134
ysr@777 135 // Attempts to ensure that the given card_index in the given region is in
ysr@777 136 // the sparse table. If successful (because the card was already
ysr@777 137 // present, or because it was successfullly added) returns "true".
ysr@777 138 // Otherwise, returns "false" to indicate that the addition would
ysr@777 139 // overflow the entry for the region. The caller must transfer these
ysr@777 140 // entries to a larger-capacity representation.
johnc@1242 141 bool add_card(RegionIdx_t region_id, CardIdx_t card_index);
ysr@777 142
johnc@1242 143 bool get_cards(RegionIdx_t region_id, CardIdx_t* cards);
johnc@1242 144 bool delete_entry(RegionIdx_t region_id);
ysr@777 145
johnc@1242 146 bool contains_card(RegionIdx_t region_id, CardIdx_t card_index) const;
ysr@777 147
ysr@777 148 void add_entry(SparsePRTEntry* e);
ysr@777 149
ysr@777 150 void clear();
ysr@777 151
ysr@777 152 size_t capacity() const { return _capacity; }
ysr@777 153 size_t capacity_mask() const { return _capacity_mask; }
ysr@777 154 size_t occupied_entries() const { return _occupied_entries; }
ysr@777 155 size_t occupied_cards() const { return _occupied_cards; }
ysr@777 156 size_t mem_size() const;
ysr@777 157 bool deleted() { return _deleted; }
ysr@777 158
ysr@777 159 SparsePRTEntry* entry(int i) const { return &_entries[i]; }
ysr@777 160
ysr@777 161 void print();
ysr@777 162
ysr@777 163 static void add_to_deleted_list(RSHashTable* rsht);
ysr@777 164 static RSHashTable* get_from_deleted_list();
ysr@777 165 };
ysr@777 166
johnc@1242 167 // ValueObj because will be embedded in HRRS iterator.
apetrusenko@984 168 class RSHashTableIter VALUE_OBJ_CLASS_SPEC {
johnc@1242 169 int _tbl_ind; // [-1, 0.._rsht->_capacity)
johnc@1242 170 int _bl_ind; // [-1, 0.._rsht->_capacity)
johnc@1242 171 short _card_ind; // [0..CardsPerEntry)
johnc@1242 172 RSHashTable* _rsht;
johnc@1242 173 size_t _heap_bot_card_ind;
ysr@777 174
johnc@1242 175 enum SomePrivateConstants {
johnc@1242 176 CardsPerRegion = HeapRegion::GrainBytes >> CardTableModRefBS::card_shift
johnc@1242 177 };
ysr@777 178
johnc@1242 179 // If the bucket list pointed to by _bl_ind contains a card, sets
johnc@1242 180 // _bl_ind to the index of that entry, and returns the card.
johnc@1242 181 // Otherwise, returns SparseEntry::NullEntry.
johnc@1242 182 CardIdx_t find_first_card_in_list();
ysr@777 183
johnc@1242 184 // Computes the proper card index for the card whose offset in the
johnc@1242 185 // current region (as indicated by _bl_ind) is "ci".
johnc@1242 186 // This is subject to errors when there is iteration concurrent with
johnc@1242 187 // modification, but these errors should be benign.
johnc@1242 188 size_t compute_card_ind(CardIdx_t ci);
ysr@777 189
johnc@1242 190 public:
johnc@1242 191 RSHashTableIter(size_t heap_bot_card_ind) :
johnc@1242 192 _tbl_ind(RSHashTable::NullEntry),
johnc@1242 193 _bl_ind(RSHashTable::NullEntry),
johnc@1242 194 _card_ind((SparsePRTEntry::CardsPerEntry-1)),
johnc@1242 195 _rsht(NULL),
johnc@1242 196 _heap_bot_card_ind(heap_bot_card_ind)
johnc@1242 197 {}
ysr@777 198
johnc@1242 199 void init(RSHashTable* rsht) {
johnc@1242 200 _rsht = rsht;
johnc@1242 201 _tbl_ind = -1; // So that first increment gets to 0.
johnc@1242 202 _bl_ind = RSHashTable::NullEntry;
johnc@1242 203 _card_ind = (SparsePRTEntry::CardsPerEntry-1);
johnc@1242 204 }
ysr@777 205
johnc@1242 206 bool has_next(size_t& card_index);
johnc@1242 207 };
ysr@777 208
ysr@777 209 // Concurrent accesss to a SparsePRT must be serialized by some external
ysr@777 210 // mutex.
ysr@777 211
ysr@777 212 class SparsePRTIter;
ysr@777 213
apetrusenko@984 214 class SparsePRT VALUE_OBJ_CLASS_SPEC {
ysr@777 215 // Iterations are done on the _cur hash table, since they only need to
ysr@777 216 // see entries visible at the start of a collection pause.
ysr@777 217 // All other operations are done using the _next hash table.
ysr@777 218 RSHashTable* _cur;
ysr@777 219 RSHashTable* _next;
ysr@777 220
ysr@777 221 HeapRegion* _hr;
ysr@777 222
ysr@777 223 enum SomeAdditionalPrivateConstants {
ysr@777 224 InitialCapacity = 16
ysr@777 225 };
ysr@777 226
ysr@777 227 void expand();
ysr@777 228
ysr@777 229 bool _expanded;
ysr@777 230
ysr@777 231 bool expanded() { return _expanded; }
ysr@777 232 void set_expanded(bool b) { _expanded = b; }
ysr@777 233
ysr@777 234 SparsePRT* _next_expanded;
ysr@777 235
ysr@777 236 SparsePRT* next_expanded() { return _next_expanded; }
ysr@777 237 void set_next_expanded(SparsePRT* nxt) { _next_expanded = nxt; }
ysr@777 238
ysr@777 239 static SparsePRT* _head_expanded_list;
ysr@777 240
ysr@777 241 public:
ysr@777 242 SparsePRT(HeapRegion* hr);
ysr@777 243
ysr@777 244 ~SparsePRT();
ysr@777 245
ysr@777 246 size_t occupied() const { return _next->occupied_cards(); }
ysr@777 247 size_t mem_size() const;
ysr@777 248
ysr@777 249 // Attempts to ensure that the given card_index in the given region is in
ysr@777 250 // the sparse table. If successful (because the card was already
ysr@777 251 // present, or because it was successfullly added) returns "true".
ysr@777 252 // Otherwise, returns "false" to indicate that the addition would
ysr@777 253 // overflow the entry for the region. The caller must transfer these
ysr@777 254 // entries to a larger-capacity representation.
johnc@1242 255 bool add_card(RegionIdx_t region_id, CardIdx_t card_index);
ysr@777 256
ysr@777 257 // If the table hold an entry for "region_ind", Copies its
ysr@777 258 // cards into "cards", which must be an array of length at least
ysr@777 259 // "CardsPerEntry", and returns "true"; otherwise, returns "false".
johnc@1242 260 bool get_cards(RegionIdx_t region_ind, CardIdx_t* cards);
ysr@777 261
ysr@777 262 // If there is an entry for "region_ind", removes it and return "true";
ysr@777 263 // otherwise returns "false."
johnc@1242 264 bool delete_entry(RegionIdx_t region_ind);
ysr@777 265
ysr@777 266 // Clear the table, and reinitialize to initial capacity.
ysr@777 267 void clear();
ysr@777 268
ysr@777 269 // Ensure that "_cur" and "_next" point to the same table.
ysr@777 270 void cleanup();
ysr@777 271
ysr@777 272 // Clean up all tables on the expanded list. Called single threaded.
ysr@777 273 static void cleanup_all();
tonyp@1052 274 RSHashTable* cur() const { return _cur; }
ysr@777 275
ysr@777 276 void init_iterator(SparsePRTIter* sprt_iter);
ysr@777 277
ysr@777 278 static void add_to_expanded_list(SparsePRT* sprt);
ysr@777 279 static SparsePRT* get_from_expanded_list();
ysr@777 280
johnc@1242 281 bool contains_card(RegionIdx_t region_id, CardIdx_t card_index) const {
ysr@777 282 return _next->contains_card(region_id, card_index);
ysr@777 283 }
ysr@777 284
ysr@777 285 #if 0
ysr@777 286 void verify_is_cleared();
ysr@777 287 void print();
ysr@777 288 #endif
ysr@777 289 };
ysr@777 290
ysr@777 291
ysr@777 292 class SparsePRTIter: public /* RSHashTable:: */RSHashTableIter {
ysr@777 293 public:
ysr@777 294 SparsePRTIter(size_t heap_bot_card_ind) :
ysr@777 295 /* RSHashTable:: */RSHashTableIter(heap_bot_card_ind)
ysr@777 296 {}
ysr@777 297
ysr@777 298 void init(const SparsePRT* sprt) {
tonyp@1052 299 RSHashTableIter::init(sprt->cur());
ysr@777 300 }
ysr@777 301 bool has_next(size_t& card_index) {
ysr@777 302 return RSHashTableIter::has_next(card_index);
ysr@777 303 }
ysr@777 304 };

mercurial