1 /*
2  * Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  *
23  */
24 
25 #ifndef SHARE_GC_G1_SPARSEPRT_HPP
26 #define SHARE_GC_G1_SPARSEPRT_HPP
27 
28 #include "gc/g1/g1CollectedHeap.hpp"
29 #include "gc/g1/heapRegion.hpp"
30 #include "gc/shared/cardTableBarrierSet.hpp"
31 #include "memory/allocation.hpp"
32 #include "runtime/mutex.hpp"
33 #include "utilities/align.hpp"
34 #include "utilities/globalDefinitions.hpp"
35 
36 class RSHashTable;
37 class SparsePRTEntry;
38 class SparsePRTIter;
39 
40 // Sparse remembered set for a heap region (the "owning" region).  Maps
41 // indices of other regions to short sequences of cards in the other region
42 // that might contain pointers into the owner region.
43 // Concurrent access to a SparsePRT must be serialized by some external mutex.
44 class SparsePRT {
45   friend class SparsePRTIter;
46   friend class SparsePRTBucketIter;
47 
48   RSHashTable* _table;
49 
50   static const size_t InitialCapacity = 8;
51 
52   void expand();
53 
54 public:
55   SparsePRT();
56   ~SparsePRT();
57 
58   size_t mem_size() const;
59 
60   enum AddCardResult {
61     overflow, // The table is full, could not add the card to the table.
62     found,    // The card is already in the PRT.
63     added     // The card has been added.
64   };
65 
66   // Attempts to ensure that the given card_index in the given region is in
67   // the sparse table.  If successful (because the card was already
68   // present, or because it was successfully added) returns "true".
69   // Otherwise, returns "false" to indicate that the addition would
70   // overflow the entry for the region.  The caller must transfer these
71   // entries to a larger-capacity representation.
72   AddCardResult add_card(RegionIdx_t region_id, CardIdx_t card_index);
73 
74   // Return the pointer to the entry associated with the given region.
75   SparsePRTEntry* get_entry(RegionIdx_t region_ind);
76 
77   // If there is an entry for "region_ind", removes it and return "true";
78   // otherwise returns "false."
79   bool delete_entry(RegionIdx_t region_ind);
80 
81   // Clear the table, and reinitialize to initial capacity.
82   void clear();
83 
84   bool contains_card(RegionIdx_t region_id, CardIdx_t card_index) const;
85 };
86 
87 class SparsePRTEntry: public CHeapObj<mtGC> {
88 public:
89   // The type of a card entry.
90   typedef uint16_t card_elem_t;
91 
92 private:
93   // We need to make sizeof(SparsePRTEntry) an even multiple of maximum member size,
94   // in order to force correct alignment that could otherwise cause SIGBUS errors
95   // when reading the member variables. This calculates the minimum number of card
96   // array elements required to get that alignment.
97   static const size_t card_array_alignment = sizeof(int) / sizeof(card_elem_t);
98 
99   RegionIdx_t _region_ind;
100   int         _next_index;
101   int         _next_null;
102   // The actual cards stored in this array.
103   // WARNING: Don't put any data members beyond this line. Card array has, in fact, variable length.
104   // It should always be the last data member.
105   card_elem_t _cards[card_array_alignment];
106 
107   // Copy the current entry's cards into "cards".
108   inline void copy_cards(card_elem_t* cards) const;
109 public:
110   // Returns the size of the entry, used for entry allocation.
size()111   static size_t size() { return sizeof(SparsePRTEntry) + sizeof(card_elem_t) * (cards_num() - card_array_alignment); }
112   // Returns the size of the card array.
cards_num()113   static int cards_num() {
114     return align_up((int)G1RSetSparseRegionEntries, (int)card_array_alignment);
115   }
116 
117   // Set the region_ind to the given value, and delete all cards.
118   inline void init(RegionIdx_t region_ind);
119 
r_ind() const120   RegionIdx_t r_ind() const { return _region_ind; }
valid_entry() const121   bool valid_entry() const { return r_ind() >= 0; }
set_r_ind(RegionIdx_t rind)122   void set_r_ind(RegionIdx_t rind) { _region_ind = rind; }
123 
next_index() const124   int next_index() const { return _next_index; }
next_index_addr()125   int* next_index_addr() { return &_next_index; }
set_next_index(int ni)126   void set_next_index(int ni) { _next_index = ni; }
127 
128   // Returns "true" iff the entry contains the given card index.
129   inline bool contains_card(CardIdx_t card_index) const;
130 
131   // Returns the number of non-NULL card entries.
num_valid_cards() const132   inline int num_valid_cards() const { return _next_null; }
133 
134   inline SparsePRT::AddCardResult add_card(CardIdx_t card_index);
135 
136   // Copy the current entry's cards into the "_card" array of "e."
137   inline void copy_cards(SparsePRTEntry* e) const;
138 
cards()139   card_elem_t* cards() { return _cards; }
140 
card(int i) const141   inline CardIdx_t card(int i) const {
142     assert(i >= 0, "must be nonnegative");
143     assert(i < cards_num(), "range checking");
144     return (CardIdx_t)_cards[i];
145   }
146 };
147 
148 class RSHashTable : public CHeapObj<mtGC> {
149 
150   friend class RSHashTableIter;
151   friend class RSHashTableBucketIter;
152 
153   // Inverse maximum hash table occupancy used.
154   static float TableOccupancyFactor;
155 
156   size_t _num_entries;
157 
158   size_t _capacity;
159   size_t _capacity_mask;
160   size_t _occupied_entries;
161   size_t _occupied_cards;
162 
163   SparsePRTEntry* _entries;
164   int* _buckets;
165   int  _free_region;
166   int  _free_list;
167 
168   // Requires that the caller hold a lock preventing parallel modifying
169   // operations, and that the the table be less than completely full.  If
170   // an entry for "region_ind" is already in the table, finds it and
171   // returns its address; otherwise allocates, initializes, inserts and
172   // returns a new entry for "region_ind".
173   SparsePRTEntry* entry_for_region_ind_create(RegionIdx_t region_ind);
174 
175   // Returns the index of the next free entry in "_entries".
176   int alloc_entry();
177   // Declares the entry "fi" to be free.  (It must have already been
178   // deleted from any bucket lists.
179   void free_entry(int fi);
180 
181 public:
182   RSHashTable(size_t capacity);
183   ~RSHashTable();
184 
185   static const int NullEntry = -1;
186 
should_expand() const187   bool should_expand() const { return _occupied_entries == _num_entries; }
188 
189   // Attempts to ensure that the given card_index in the given region is in
190   // the sparse table.  If successful (because the card was already
191   // present, or because it was successfully added) returns "true".
192   // Otherwise, returns "false" to indicate that the addition would
193   // overflow the entry for the region.  The caller must transfer these
194   // entries to a larger-capacity representation.
195   SparsePRT::AddCardResult add_card(RegionIdx_t region_id, CardIdx_t card_index);
196 
197   bool delete_entry(RegionIdx_t region_id);
198 
199   bool contains_card(RegionIdx_t region_id, CardIdx_t card_index) const;
200 
201   void add_entry(SparsePRTEntry* e);
202 
203   SparsePRTEntry* get_entry(RegionIdx_t region_id) const;
204 
205   void clear();
206 
capacity() const207   size_t capacity() const      { return _capacity; }
capacity_mask() const208   size_t capacity_mask() const { return _capacity_mask;  }
occupied_entries() const209   size_t occupied_entries() const { return _occupied_entries; }
210   size_t mem_size() const;
211   // The number of SparsePRTEntry instances available.
num_entries() const212   size_t num_entries() const { return _num_entries; }
213 
entry(int i) const214   SparsePRTEntry* entry(int i) const {
215     assert(i >= 0 && (size_t)i < _num_entries, "precondition");
216     return (SparsePRTEntry*)((char*)_entries + SparsePRTEntry::size() * i);
217   }
218 
219   void print();
220 };
221 
222 // This is embedded in HRRS iterator.
223 class RSHashTableIter {
224   // Return value indicating "invalid/no card".
225   static const int NoCardFound = -1;
226 
227   int _tbl_ind;         // [-1, 0.._rsht->_capacity)
228   int _bl_ind;          // [-1, 0.._rsht->_capacity)
229   short _card_ind;      // [0..SparsePRTEntry::cards_num())
230   RSHashTable* _rsht;
231 
232   // If the bucket list pointed to by _bl_ind contains a card, sets
233   // _bl_ind to the index of that entry,
234   // Returns the card found if there is, otherwise returns InvalidCard.
235   CardIdx_t find_first_card_in_list();
236 
237   // Computes the proper card index for the card whose offset in the
238   // current region (as indicated by _bl_ind) is "ci".
239   // This is subject to errors when there is iteration concurrent with
240   // modification, but these errors should be benign.
241   size_t compute_card_ind(CardIdx_t ci);
242 
243 public:
RSHashTableIter(RSHashTable * rsht)244   RSHashTableIter(RSHashTable* rsht) :
245     _tbl_ind(RSHashTable::NullEntry), // So that first increment gets to 0.
246     _bl_ind(RSHashTable::NullEntry),
247     _card_ind((SparsePRTEntry::cards_num() - 1)),
248     _rsht(rsht) {}
249 
250   bool has_next(size_t& card_index);
251 };
252 
253 // This is embedded in HRRS iterator.
254 class RSHashTableBucketIter {
255   int _tbl_ind;         // [-1, 0.._rsht->_capacity)
256   int _bl_ind;          // [-1, 0.._rsht->_capacity)
257 
258   RSHashTable* _rsht;
259 
260 public:
RSHashTableBucketIter(RSHashTable * rsht)261   RSHashTableBucketIter(RSHashTable* rsht) :
262     _tbl_ind(0),
263     _bl_ind(rsht->_buckets[_tbl_ind]),
264     _rsht(rsht) { }
265 
266   bool has_next(SparsePRTEntry*& entry);
267 };
268 
269 class SparsePRTIter: public RSHashTableIter {
270 public:
SparsePRTIter(const SparsePRT * sprt)271   SparsePRTIter(const SparsePRT* sprt) :
272     RSHashTableIter(sprt->_table) { }
273 
has_next(size_t & card_index)274   bool has_next(size_t& card_index) {
275     return RSHashTableIter::has_next(card_index);
276   }
277 };
278 
279 class SparsePRTBucketIter: public RSHashTableBucketIter {
280 public:
SparsePRTBucketIter(const SparsePRT * sprt)281   SparsePRTBucketIter(const SparsePRT* sprt) :
282     RSHashTableBucketIter(sprt->_table) {}
283 
has_next(SparsePRTEntry * & entry)284   bool has_next(SparsePRTEntry*& entry) {
285     return RSHashTableBucketIter::has_next(entry);
286   }
287 };
288 
289 #endif // SHARE_GC_G1_SPARSEPRT_HPP
290