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 | // Sparse remembered set for a heap region (the "owning" region). Maps |
37 | // indices of other regions to short sequences of cards in the other region |
38 | // that might contain pointers into the owner region. |
39 | |
40 | class SparsePRTEntry: public CHeapObj<mtGC> { |
41 | private: |
42 | // The type of a card entry. |
43 | typedef uint16_t card_elem_t; |
44 | |
45 | // We need to make sizeof(SparsePRTEntry) an even multiple of maximum member size, |
46 | // in order to force correct alignment that could otherwise cause SIGBUS errors |
47 | // when reading the member variables. This calculates the minimum number of card |
48 | // array elements required to get that alignment. |
49 | static const size_t card_array_alignment = sizeof(int) / sizeof(card_elem_t); |
50 | |
51 | RegionIdx_t _region_ind; |
52 | int _next_index; |
53 | int _next_null; |
54 | // The actual cards stored in this array. |
55 | // WARNING: Don't put any data members beyond this line. Card array has, in fact, variable length. |
56 | // It should always be the last data member. |
57 | card_elem_t _cards[card_array_alignment]; |
58 | |
59 | // Copy the current entry's cards into "cards". |
60 | inline void copy_cards(card_elem_t* cards) const; |
61 | public: |
62 | // Returns the size of the entry, used for entry allocation. |
63 | static size_t size() { return sizeof(SparsePRTEntry) + sizeof(card_elem_t) * (cards_num() - card_array_alignment); } |
64 | // Returns the size of the card array. |
65 | static int cards_num() { |
66 | return align_up((int)G1RSetSparseRegionEntries, (int)card_array_alignment); |
67 | } |
68 | |
69 | // Set the region_ind to the given value, and delete all cards. |
70 | inline void init(RegionIdx_t region_ind); |
71 | |
72 | RegionIdx_t r_ind() const { return _region_ind; } |
73 | bool valid_entry() const { return r_ind() >= 0; } |
74 | void set_r_ind(RegionIdx_t rind) { _region_ind = rind; } |
75 | |
76 | int next_index() const { return _next_index; } |
77 | int* next_index_addr() { return &_next_index; } |
78 | void set_next_index(int ni) { _next_index = ni; } |
79 | |
80 | // Returns "true" iff the entry contains the given card index. |
81 | inline bool contains_card(CardIdx_t card_index) const; |
82 | |
83 | // Returns the number of non-NULL card entries. |
84 | inline int num_valid_cards() const { return _next_null; } |
85 | |
86 | // Requires that the entry not contain the given card index. If there is |
87 | // space available, add the given card index to the entry and return |
88 | // "true"; otherwise, return "false" to indicate that the entry is full. |
89 | enum AddCardResult { |
90 | overflow, |
91 | found, |
92 | added |
93 | }; |
94 | inline AddCardResult add_card(CardIdx_t card_index); |
95 | |
96 | // Copy the current entry's cards into the "_card" array of "e." |
97 | inline void copy_cards(SparsePRTEntry* e) const; |
98 | |
99 | inline CardIdx_t card(int i) const { |
100 | assert(i >= 0, "must be nonnegative" ); |
101 | assert(i < cards_num(), "range checking" ); |
102 | return (CardIdx_t)_cards[i]; |
103 | } |
104 | }; |
105 | |
106 | class RSHashTable : public CHeapObj<mtGC> { |
107 | |
108 | friend class RSHashTableIter; |
109 | |
110 | |
111 | // Inverse maximum hash table occupancy used. |
112 | static float TableOccupancyFactor; |
113 | |
114 | size_t _num_entries; |
115 | |
116 | size_t _capacity; |
117 | size_t _capacity_mask; |
118 | size_t _occupied_entries; |
119 | size_t _occupied_cards; |
120 | |
121 | SparsePRTEntry* _entries; |
122 | int* _buckets; |
123 | int _free_region; |
124 | int _free_list; |
125 | |
126 | // Requires that the caller hold a lock preventing parallel modifying |
127 | // operations, and that the the table be less than completely full. If |
128 | // an entry for "region_ind" is already in the table, finds it and |
129 | // returns its address; otherwise allocates, initializes, inserts and |
130 | // returns a new entry for "region_ind". |
131 | SparsePRTEntry* entry_for_region_ind_create(RegionIdx_t region_ind); |
132 | |
133 | // Returns the index of the next free entry in "_entries". |
134 | int alloc_entry(); |
135 | // Declares the entry "fi" to be free. (It must have already been |
136 | // deleted from any bucket lists. |
137 | void free_entry(int fi); |
138 | |
139 | public: |
140 | RSHashTable(size_t capacity); |
141 | ~RSHashTable(); |
142 | |
143 | static const int NullEntry = -1; |
144 | |
145 | bool should_expand() const { return _occupied_entries == _num_entries; } |
146 | |
147 | // Attempts to ensure that the given card_index in the given region is in |
148 | // the sparse table. If successful (because the card was already |
149 | // present, or because it was successfully added) returns "true". |
150 | // Otherwise, returns "false" to indicate that the addition would |
151 | // overflow the entry for the region. The caller must transfer these |
152 | // entries to a larger-capacity representation. |
153 | bool add_card(RegionIdx_t region_id, CardIdx_t card_index); |
154 | |
155 | bool delete_entry(RegionIdx_t region_id); |
156 | |
157 | bool contains_card(RegionIdx_t region_id, CardIdx_t card_index) const; |
158 | |
159 | void add_entry(SparsePRTEntry* e); |
160 | |
161 | SparsePRTEntry* get_entry(RegionIdx_t region_id) const; |
162 | |
163 | void clear(); |
164 | |
165 | size_t capacity() const { return _capacity; } |
166 | size_t capacity_mask() const { return _capacity_mask; } |
167 | size_t occupied_entries() const { return _occupied_entries; } |
168 | size_t occupied_cards() const { return _occupied_cards; } |
169 | size_t mem_size() const; |
170 | // The number of SparsePRTEntry instances available. |
171 | size_t num_entries() const { return _num_entries; } |
172 | |
173 | SparsePRTEntry* entry(int i) const { |
174 | assert(i >= 0 && (size_t)i < _num_entries, "precondition" ); |
175 | return (SparsePRTEntry*)((char*)_entries + SparsePRTEntry::size() * i); |
176 | } |
177 | |
178 | void print(); |
179 | }; |
180 | |
181 | // This is embedded in HRRS iterator. |
182 | class RSHashTableIter { |
183 | // Return value indicating "invalid/no card". |
184 | static const int NoCardFound = -1; |
185 | |
186 | int _tbl_ind; // [-1, 0.._rsht->_capacity) |
187 | int _bl_ind; // [-1, 0.._rsht->_capacity) |
188 | short _card_ind; // [0..SparsePRTEntry::cards_num()) |
189 | RSHashTable* _rsht; |
190 | |
191 | // If the bucket list pointed to by _bl_ind contains a card, sets |
192 | // _bl_ind to the index of that entry, |
193 | // Returns the card found if there is, otherwise returns InvalidCard. |
194 | CardIdx_t find_first_card_in_list(); |
195 | |
196 | // Computes the proper card index for the card whose offset in the |
197 | // current region (as indicated by _bl_ind) is "ci". |
198 | // This is subject to errors when there is iteration concurrent with |
199 | // modification, but these errors should be benign. |
200 | size_t compute_card_ind(CardIdx_t ci); |
201 | |
202 | public: |
203 | RSHashTableIter(RSHashTable* rsht) : |
204 | _tbl_ind(RSHashTable::NullEntry), // So that first increment gets to 0. |
205 | _bl_ind(RSHashTable::NullEntry), |
206 | _card_ind((SparsePRTEntry::cards_num() - 1)), |
207 | _rsht(rsht) {} |
208 | |
209 | bool has_next(size_t& card_index); |
210 | }; |
211 | |
212 | // Concurrent access to a SparsePRT must be serialized by some external mutex. |
213 | |
214 | class SparsePRTIter; |
215 | |
216 | class SparsePRT { |
217 | friend class SparsePRTIter; |
218 | |
219 | RSHashTable* _table; |
220 | |
221 | static const size_t InitialCapacity = 8; |
222 | |
223 | void expand(); |
224 | |
225 | public: |
226 | SparsePRT(); |
227 | ~SparsePRT(); |
228 | |
229 | size_t occupied() const { return _table->occupied_cards(); } |
230 | size_t mem_size() const; |
231 | |
232 | // Attempts to ensure that the given card_index in the given region is in |
233 | // the sparse table. If successful (because the card was already |
234 | // present, or because it was successfully added) returns "true". |
235 | // Otherwise, returns "false" to indicate that the addition would |
236 | // overflow the entry for the region. The caller must transfer these |
237 | // entries to a larger-capacity representation. |
238 | bool add_card(RegionIdx_t region_id, CardIdx_t card_index); |
239 | |
240 | // Return the pointer to the entry associated with the given region. |
241 | SparsePRTEntry* get_entry(RegionIdx_t region_ind); |
242 | |
243 | // If there is an entry for "region_ind", removes it and return "true"; |
244 | // otherwise returns "false." |
245 | bool delete_entry(RegionIdx_t region_ind); |
246 | |
247 | // Clear the table, and reinitialize to initial capacity. |
248 | void clear(); |
249 | |
250 | bool contains_card(RegionIdx_t region_id, CardIdx_t card_index) const { |
251 | return _table->contains_card(region_id, card_index); |
252 | } |
253 | }; |
254 | |
255 | class SparsePRTIter: public RSHashTableIter { |
256 | public: |
257 | SparsePRTIter(const SparsePRT* sprt) : |
258 | RSHashTableIter(sprt->_table) { } |
259 | |
260 | bool has_next(size_t& card_index) { |
261 | return RSHashTableIter::has_next(card_index); |
262 | } |
263 | }; |
264 | |
265 | #endif // SHARE_GC_G1_SPARSEPRT_HPP |
266 | |