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

Sat, 16 Oct 2010 17:12:19 -0400

author
tonyp
date
Sat, 16 Oct 2010 17:12:19 -0400
changeset 2241
72a161e62cc4
parent 2239
9f4848ebbabd
child 2314
f95d63e2154a
permissions
-rw-r--r--

6991377: G1: race between concurrent refinement and humongous object allocation
Summary: There is a race between the concurrent refinement threads and the humongous object allocation that can cause the concurrent refinement threads to corrupt the part of the BOT that it is being initialized by the humongous object allocation operation. The solution is to do the humongous object allocation in careful steps to ensure that the concurrent refinement threads always have a consistent view over the BOT, region contents, and top. The fix includes some very minor tidying up in sparsePRT.
Reviewed-by: jcoomes, johnc, ysr

ysr@777 1 /*
trims@1907 2 * Copyright (c) 2001, 2009, 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
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
apetrusenko@984 35 class SparsePRTEntry: public CHeapObj {
ysr@777 36 public:
ysr@777 37 enum SomePublicConstants {
iveresov@1696 38 NullEntry = -1,
iveresov@1696 39 UnrollFactor = 4
ysr@777 40 };
ysr@777 41 private:
johnc@1242 42 RegionIdx_t _region_ind;
johnc@1242 43 int _next_index;
iveresov@1696 44 CardIdx_t _cards[1];
iveresov@1696 45 // WARNING: Don't put any data members beyond this line. Card array has, in fact, variable length.
iveresov@1696 46 // It should always be the last data member.
ysr@777 47 public:
iveresov@1696 48 // Returns the size of the entry, used for entry allocation.
iveresov@1696 49 static size_t size() { return sizeof(SparsePRTEntry) + sizeof(CardIdx_t) * (cards_num() - 1); }
iveresov@1696 50 // Returns the size of the card array.
iveresov@1696 51 static int cards_num() {
iveresov@1696 52 // The number of cards should be a multiple of 4, because that's our current
iveresov@1696 53 // unrolling factor.
iveresov@1696 54 static const int s = MAX2<int>(G1RSetSparseRegionEntries & ~(UnrollFactor - 1), UnrollFactor);
iveresov@1696 55 return s;
iveresov@1696 56 }
ysr@777 57
ysr@777 58 // Set the region_ind to the given value, and delete all cards.
johnc@1242 59 inline void init(RegionIdx_t region_ind);
ysr@777 60
johnc@1242 61 RegionIdx_t r_ind() const { return _region_ind; }
ysr@777 62 bool valid_entry() const { return r_ind() >= 0; }
johnc@1242 63 void set_r_ind(RegionIdx_t rind) { _region_ind = rind; }
ysr@777 64
johnc@1242 65 int next_index() const { return _next_index; }
johnc@1242 66 int* next_index_addr() { return &_next_index; }
johnc@1242 67 void set_next_index(int ni) { _next_index = ni; }
ysr@777 68
ysr@777 69 // Returns "true" iff the entry contains the given card index.
johnc@1242 70 inline bool contains_card(CardIdx_t card_index) const;
ysr@777 71
ysr@777 72 // Returns the number of non-NULL card entries.
ysr@777 73 inline int num_valid_cards() const;
ysr@777 74
ysr@777 75 // Requires that the entry not contain the given card index. If there is
ysr@777 76 // space available, add the given card index to the entry and return
ysr@777 77 // "true"; otherwise, return "false" to indicate that the entry is full.
ysr@777 78 enum AddCardResult {
ysr@777 79 overflow,
ysr@777 80 found,
ysr@777 81 added
ysr@777 82 };
johnc@1242 83 inline AddCardResult add_card(CardIdx_t card_index);
ysr@777 84
ysr@777 85 // Copy the current entry's cards into "cards".
johnc@1242 86 inline void copy_cards(CardIdx_t* cards) const;
ysr@777 87 // Copy the current entry's cards into the "_card" array of "e."
ysr@777 88 inline void copy_cards(SparsePRTEntry* e) const;
ysr@777 89
johnc@1242 90 inline CardIdx_t card(int i) const { return _cards[i]; }
ysr@777 91 };
ysr@777 92
ysr@777 93
ysr@777 94 class RSHashTable : public CHeapObj {
ysr@777 95
ysr@777 96 friend class RSHashTableIter;
ysr@777 97
ysr@777 98 enum SomePrivateConstants {
ysr@777 99 NullEntry = -1
ysr@777 100 };
ysr@777 101
ysr@777 102 size_t _capacity;
ysr@777 103 size_t _capacity_mask;
ysr@777 104 size_t _occupied_entries;
ysr@777 105 size_t _occupied_cards;
ysr@777 106
ysr@777 107 SparsePRTEntry* _entries;
johnc@1242 108 int* _buckets;
johnc@1242 109 int _free_region;
johnc@1242 110 int _free_list;
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);
iveresov@1696 144
johnc@1242 145 bool delete_entry(RegionIdx_t region_id);
ysr@777 146
johnc@1242 147 bool contains_card(RegionIdx_t region_id, CardIdx_t card_index) const;
ysr@777 148
ysr@777 149 void add_entry(SparsePRTEntry* e);
ysr@777 150
iveresov@1696 151 SparsePRTEntry* get_entry(RegionIdx_t region_id);
iveresov@1696 152
ysr@777 153 void clear();
ysr@777 154
ysr@777 155 size_t capacity() const { return _capacity; }
ysr@777 156 size_t capacity_mask() const { return _capacity_mask; }
ysr@777 157 size_t occupied_entries() const { return _occupied_entries; }
ysr@777 158 size_t occupied_cards() const { return _occupied_cards; }
ysr@777 159 size_t mem_size() const;
ysr@777 160
iveresov@1696 161 SparsePRTEntry* entry(int i) const { return (SparsePRTEntry*)((char*)_entries + SparsePRTEntry::size() * i); }
ysr@777 162
ysr@777 163 void print();
ysr@777 164 };
ysr@777 165
johnc@1242 166 // ValueObj because will be embedded in HRRS iterator.
apetrusenko@984 167 class RSHashTableIter VALUE_OBJ_CLASS_SPEC {
johnc@1242 168 int _tbl_ind; // [-1, 0.._rsht->_capacity)
johnc@1242 169 int _bl_ind; // [-1, 0.._rsht->_capacity)
iveresov@1696 170 short _card_ind; // [0..SparsePRTEntry::cards_num())
johnc@1242 171 RSHashTable* _rsht;
ysr@777 172
johnc@1242 173 // If the bucket list pointed to by _bl_ind contains a card, sets
johnc@1242 174 // _bl_ind to the index of that entry, and returns the card.
johnc@1242 175 // Otherwise, returns SparseEntry::NullEntry.
johnc@1242 176 CardIdx_t find_first_card_in_list();
ysr@777 177
johnc@1242 178 // Computes the proper card index for the card whose offset in the
johnc@1242 179 // current region (as indicated by _bl_ind) is "ci".
johnc@1242 180 // This is subject to errors when there is iteration concurrent with
johnc@1242 181 // modification, but these errors should be benign.
johnc@1242 182 size_t compute_card_ind(CardIdx_t ci);
ysr@777 183
johnc@1242 184 public:
tonyp@2239 185 RSHashTableIter() :
johnc@1242 186 _tbl_ind(RSHashTable::NullEntry),
johnc@1242 187 _bl_ind(RSHashTable::NullEntry),
iveresov@1696 188 _card_ind((SparsePRTEntry::cards_num() - 1)),
tonyp@2239 189 _rsht(NULL) {}
ysr@777 190
johnc@1242 191 void init(RSHashTable* rsht) {
johnc@1242 192 _rsht = rsht;
johnc@1242 193 _tbl_ind = -1; // So that first increment gets to 0.
johnc@1242 194 _bl_ind = RSHashTable::NullEntry;
iveresov@1696 195 _card_ind = (SparsePRTEntry::cards_num() - 1);
johnc@1242 196 }
ysr@777 197
johnc@1242 198 bool has_next(size_t& card_index);
johnc@1242 199 };
ysr@777 200
ysr@777 201 // Concurrent accesss to a SparsePRT must be serialized by some external
ysr@777 202 // mutex.
ysr@777 203
ysr@777 204 class SparsePRTIter;
ysr@777 205
apetrusenko@984 206 class SparsePRT VALUE_OBJ_CLASS_SPEC {
ysr@777 207 // Iterations are done on the _cur hash table, since they only need to
ysr@777 208 // see entries visible at the start of a collection pause.
ysr@777 209 // All other operations are done using the _next hash table.
ysr@777 210 RSHashTable* _cur;
ysr@777 211 RSHashTable* _next;
ysr@777 212
ysr@777 213 HeapRegion* _hr;
ysr@777 214
ysr@777 215 enum SomeAdditionalPrivateConstants {
ysr@777 216 InitialCapacity = 16
ysr@777 217 };
ysr@777 218
ysr@777 219 void expand();
ysr@777 220
ysr@777 221 bool _expanded;
ysr@777 222
ysr@777 223 bool expanded() { return _expanded; }
ysr@777 224 void set_expanded(bool b) { _expanded = b; }
ysr@777 225
ysr@777 226 SparsePRT* _next_expanded;
ysr@777 227
ysr@777 228 SparsePRT* next_expanded() { return _next_expanded; }
ysr@777 229 void set_next_expanded(SparsePRT* nxt) { _next_expanded = nxt; }
ysr@777 230
ysr@777 231 static SparsePRT* _head_expanded_list;
ysr@777 232
ysr@777 233 public:
ysr@777 234 SparsePRT(HeapRegion* hr);
ysr@777 235
ysr@777 236 ~SparsePRT();
ysr@777 237
ysr@777 238 size_t occupied() const { return _next->occupied_cards(); }
ysr@777 239 size_t mem_size() const;
ysr@777 240
ysr@777 241 // Attempts to ensure that the given card_index in the given region is in
ysr@777 242 // the sparse table. If successful (because the card was already
ysr@777 243 // present, or because it was successfullly added) returns "true".
ysr@777 244 // Otherwise, returns "false" to indicate that the addition would
ysr@777 245 // overflow the entry for the region. The caller must transfer these
ysr@777 246 // entries to a larger-capacity representation.
johnc@1242 247 bool add_card(RegionIdx_t region_id, CardIdx_t card_index);
ysr@777 248
ysr@777 249 // If the table hold an entry for "region_ind", Copies its
ysr@777 250 // cards into "cards", which must be an array of length at least
iveresov@1696 251 // "SparePRTEntry::cards_num()", and returns "true"; otherwise,
iveresov@1696 252 // returns "false".
johnc@1242 253 bool get_cards(RegionIdx_t region_ind, CardIdx_t* cards);
ysr@777 254
iveresov@1696 255 // Return the pointer to the entry associated with the given region.
iveresov@1696 256 SparsePRTEntry* get_entry(RegionIdx_t region_ind);
iveresov@1696 257
ysr@777 258 // If there is an entry for "region_ind", removes it and return "true";
ysr@777 259 // otherwise returns "false."
johnc@1242 260 bool delete_entry(RegionIdx_t region_ind);
ysr@777 261
ysr@777 262 // Clear the table, and reinitialize to initial capacity.
ysr@777 263 void clear();
ysr@777 264
ysr@777 265 // Ensure that "_cur" and "_next" point to the same table.
ysr@777 266 void cleanup();
ysr@777 267
ysr@777 268 // Clean up all tables on the expanded list. Called single threaded.
ysr@777 269 static void cleanup_all();
tonyp@1052 270 RSHashTable* cur() const { return _cur; }
ysr@777 271
ysr@777 272 void init_iterator(SparsePRTIter* sprt_iter);
ysr@777 273
ysr@777 274 static void add_to_expanded_list(SparsePRT* sprt);
ysr@777 275 static SparsePRT* get_from_expanded_list();
ysr@777 276
johnc@1242 277 bool contains_card(RegionIdx_t region_id, CardIdx_t card_index) const {
ysr@777 278 return _next->contains_card(region_id, card_index);
ysr@777 279 }
ysr@777 280 };
ysr@777 281
ysr@777 282
tonyp@2239 283 class SparsePRTIter: public RSHashTableIter {
ysr@777 284 public:
ysr@777 285 void init(const SparsePRT* sprt) {
tonyp@1052 286 RSHashTableIter::init(sprt->cur());
ysr@777 287 }
ysr@777 288 bool has_next(size_t& card_index) {
ysr@777 289 return RSHashTableIter::has_next(card_index);
ysr@777 290 }
ysr@777 291 };

mercurial