File: | jdk/src/hotspot/share/gc/g1/g1CardSet.cpp |
Warning: | line 680, column 3 Undefined or garbage value returned to caller |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* | |||
2 | * Copyright (c) 2021, 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 | #include "precompiled.hpp" | |||
26 | #include "gc/g1/g1CardSet.inline.hpp" | |||
27 | #include "gc/g1/g1CardSetContainers.inline.hpp" | |||
28 | #include "gc/g1/g1CardSetMemory.inline.hpp" | |||
29 | #include "gc/g1/g1FromCardCache.hpp" | |||
30 | #include "gc/g1/heapRegion.inline.hpp" | |||
31 | #include "memory/allocation.inline.hpp" | |||
32 | #include "runtime/atomic.hpp" | |||
33 | #include "runtime/globals_extension.hpp" | |||
34 | #include "runtime/mutex.hpp" | |||
35 | #include "utilities/bitMap.inline.hpp" | |||
36 | #include "utilities/concurrentHashTable.inline.hpp" | |||
37 | #include "utilities/globalDefinitions.hpp" | |||
38 | #include "utilities/lockFreeStack.hpp" | |||
39 | #include "utilities/spinYield.hpp" | |||
40 | ||||
41 | #include "gc/shared/gcLogPrecious.hpp" | |||
42 | #include "gc/shared/gcTraceTime.inline.hpp" | |||
43 | #include "runtime/java.hpp" | |||
44 | ||||
45 | G1CardSet::CardSetPtr G1CardSet::FullCardSet = (G1CardSet::CardSetPtr)-1; | |||
46 | ||||
47 | static uint default_log2_card_region_per_region() { | |||
48 | uint log2_card_regions_per_heap_region = 0; | |||
49 | ||||
50 | const uint card_container_limit = G1CardSetContainer::LogCardsPerRegionLimit; | |||
51 | if (card_container_limit < (uint)HeapRegion::LogCardsPerRegion) { | |||
52 | log2_card_regions_per_heap_region = (uint)HeapRegion::LogCardsPerRegion - card_container_limit; | |||
53 | } | |||
54 | ||||
55 | return log2_card_regions_per_heap_region; | |||
56 | } | |||
57 | ||||
58 | G1CardSetConfiguration::G1CardSetConfiguration() : | |||
59 | G1CardSetConfiguration(HeapRegion::LogCardsPerRegion, /* inline_ptr_bits_per_card */ | |||
60 | G1RemSetArrayOfCardsEntries, /* max_cards_in_array */ | |||
61 | (double)G1RemSetCoarsenHowlBitmapToHowlFullPercent / 100, /* cards_in_bitmap_threshold_percent */ | |||
62 | G1RemSetHowlNumBuckets, /* num_buckets_in_howl */ | |||
63 | (double)G1RemSetCoarsenHowlToFullPercent / 100, /* cards_in_howl_threshold_percent */ | |||
64 | (uint)HeapRegion::CardsPerRegion, /* max_cards_in_cardset */ | |||
65 | default_log2_card_region_per_region()) /* log2_card_region_per_region */ | |||
66 | { | |||
67 | assert((_log2_card_regions_per_heap_region + _log2_cards_per_card_region) == (uint)HeapRegion::LogCardsPerRegion,do { if (!((_log2_card_regions_per_heap_region + _log2_cards_per_card_region ) == (uint)HeapRegion::LogCardsPerRegion)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/gc/g1/g1CardSet.cpp" , 68, "assert(" "(_log2_card_regions_per_heap_region + _log2_cards_per_card_region) == (uint)HeapRegion::LogCardsPerRegion" ") failed", "inconsistent heap region virtualization setup") ; ::breakpoint(); } } while (0) | |||
68 | "inconsistent heap region virtualization setup")do { if (!((_log2_card_regions_per_heap_region + _log2_cards_per_card_region ) == (uint)HeapRegion::LogCardsPerRegion)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/gc/g1/g1CardSet.cpp" , 68, "assert(" "(_log2_card_regions_per_heap_region + _log2_cards_per_card_region) == (uint)HeapRegion::LogCardsPerRegion" ") failed", "inconsistent heap region virtualization setup") ; ::breakpoint(); } } while (0); | |||
69 | } | |||
70 | ||||
71 | G1CardSetConfiguration::G1CardSetConfiguration(uint max_cards_in_array, | |||
72 | double cards_in_bitmap_threshold_percent, | |||
73 | uint max_buckets_in_howl, | |||
74 | double cards_in_howl_threshold_percent, | |||
75 | uint max_cards_in_card_set, | |||
76 | uint log2_card_region_per_region) : | |||
77 | G1CardSetConfiguration(log2i_exact(max_cards_in_card_set), /* inline_ptr_bits_per_card */ | |||
78 | max_cards_in_array, /* max_cards_in_array */ | |||
79 | cards_in_bitmap_threshold_percent, /* cards_in_bitmap_threshold_percent */ | |||
80 | G1CardSetHowl::num_buckets(max_cards_in_card_set, /* num_buckets_in_howl */ | |||
81 | max_cards_in_array, | |||
82 | max_buckets_in_howl), | |||
83 | cards_in_howl_threshold_percent, /* cards_in_howl_threshold_percent */ | |||
84 | max_cards_in_card_set, /* max_cards_in_cardset */ | |||
85 | log2_card_region_per_region) | |||
86 | { } | |||
87 | ||||
88 | G1CardSetConfiguration::G1CardSetConfiguration(uint inline_ptr_bits_per_card, | |||
89 | uint max_cards_in_array, | |||
90 | double cards_in_bitmap_threshold_percent, | |||
91 | uint num_buckets_in_howl, | |||
92 | double cards_in_howl_threshold_percent, | |||
93 | uint max_cards_in_card_set, | |||
94 | uint log2_card_regions_per_heap_region) : | |||
95 | _inline_ptr_bits_per_card(inline_ptr_bits_per_card), | |||
96 | _max_cards_in_array(max_cards_in_array), | |||
97 | _num_buckets_in_howl(num_buckets_in_howl), | |||
98 | _max_cards_in_card_set(max_cards_in_card_set), | |||
99 | _cards_in_howl_threshold(max_cards_in_card_set * cards_in_howl_threshold_percent), | |||
100 | _max_cards_in_howl_bitmap(G1CardSetHowl::bitmap_size(_max_cards_in_card_set, _num_buckets_in_howl)), | |||
101 | _cards_in_howl_bitmap_threshold(_max_cards_in_howl_bitmap * cards_in_bitmap_threshold_percent), | |||
102 | _log2_max_cards_in_howl_bitmap(log2i_exact(_max_cards_in_howl_bitmap)), | |||
103 | _bitmap_hash_mask(~(~(0) << _log2_max_cards_in_howl_bitmap)), | |||
104 | _log2_card_regions_per_heap_region(log2_card_regions_per_heap_region), | |||
105 | _log2_cards_per_card_region(log2i_exact(_max_cards_in_card_set) - _log2_card_regions_per_heap_region) { | |||
106 | ||||
107 | assert(is_power_of_2(_max_cards_in_card_set),do { if (!(is_power_of_2(_max_cards_in_card_set))) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/gc/g1/g1CardSet.cpp" , 108, "assert(" "is_power_of_2(_max_cards_in_card_set)" ") failed" , "max_cards_in_card_set must be a power of 2: %u", _max_cards_in_card_set ); ::breakpoint(); } } while (0) | |||
108 | "max_cards_in_card_set must be a power of 2: %u", _max_cards_in_card_set)do { if (!(is_power_of_2(_max_cards_in_card_set))) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/gc/g1/g1CardSet.cpp" , 108, "assert(" "is_power_of_2(_max_cards_in_card_set)" ") failed" , "max_cards_in_card_set must be a power of 2: %u", _max_cards_in_card_set ); ::breakpoint(); } } while (0); | |||
109 | ||||
110 | init_card_set_alloc_options(); | |||
111 | log_configuration(); | |||
112 | } | |||
113 | ||||
114 | G1CardSetConfiguration::~G1CardSetConfiguration() { | |||
115 | FREE_C_HEAP_ARRAY(size_t, _card_set_alloc_options)FreeHeap((char*)(_card_set_alloc_options)); | |||
116 | } | |||
117 | ||||
118 | void G1CardSetConfiguration::init_card_set_alloc_options() { | |||
119 | _card_set_alloc_options = NEW_C_HEAP_ARRAY(G1CardSetAllocOptions, num_mem_object_types(), mtGC)(G1CardSetAllocOptions*) (AllocateHeap((num_mem_object_types( )) * sizeof(G1CardSetAllocOptions), mtGC)); | |||
120 | new (&_card_set_alloc_options[0]) G1CardSetAllocOptions((uint)CardSetHash::get_node_size()); | |||
121 | new (&_card_set_alloc_options[1]) G1CardSetAllocOptions((uint)G1CardSetArray::size_in_bytes(_max_cards_in_array), 2, 256); | |||
122 | new (&_card_set_alloc_options[2]) G1CardSetAllocOptions((uint)G1CardSetBitMap::size_in_bytes(_max_cards_in_howl_bitmap), 2, 256); | |||
123 | new (&_card_set_alloc_options[3]) G1CardSetAllocOptions((uint)G1CardSetHowl::size_in_bytes(_num_buckets_in_howl), 2, 256); | |||
124 | } | |||
125 | ||||
126 | void G1CardSetConfiguration::log_configuration() { | |||
127 | log_debug_p(gc, remset)GCLogPreciousHandle( LogTargetHandle::create<LogLevel::Debug , (LogTag::_gc), (LogTag::_remset), (LogTag::__NO_TAG), (LogTag ::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG)>() , "/home/daniel/Projects/java/jdk/src/hotspot/share/gc/g1/g1CardSet.cpp" , 127).write("Card Set container configuration: " | |||
128 | "InlinePtr #cards %u size %zu " | |||
129 | "Array Of Cards #cards %u size %zu " | |||
130 | "Howl #buckets %u coarsen threshold %u " | |||
131 | "Howl Bitmap #cards %u size %zu coarsen threshold %u " | |||
132 | "Card regions per heap region %u cards per card region %u", | |||
133 | max_cards_in_inline_ptr(), sizeof(void*), | |||
134 | max_cards_in_array(), G1CardSetArray::size_in_bytes(max_cards_in_array()), | |||
135 | num_buckets_in_howl(), cards_in_howl_threshold(), | |||
136 | max_cards_in_howl_bitmap(), G1CardSetBitMap::size_in_bytes(max_cards_in_howl_bitmap()), cards_in_howl_bitmap_threshold(), | |||
137 | (uint)1 << log2_card_regions_per_heap_region(), | |||
138 | (uint)1 << log2_cards_per_card_region()); | |||
139 | } | |||
140 | ||||
141 | uint G1CardSetConfiguration::max_cards_in_inline_ptr() const { | |||
142 | return max_cards_in_inline_ptr(_inline_ptr_bits_per_card); | |||
143 | } | |||
144 | ||||
145 | uint G1CardSetConfiguration::max_cards_in_inline_ptr(uint bits_per_card) { | |||
146 | return G1CardSetInlinePtr::max_cards_in_inline_ptr(bits_per_card); | |||
147 | } | |||
148 | ||||
149 | const G1CardSetAllocOptions* G1CardSetConfiguration::mem_object_alloc_options(uint idx) { | |||
150 | return &_card_set_alloc_options[idx]; | |||
151 | } | |||
152 | ||||
153 | const char* G1CardSetConfiguration::mem_object_type_name_str(uint index) { | |||
154 | const char* names[] = { "Node", "Array", "Bitmap", "Howl" }; | |||
155 | return names[index]; | |||
156 | } | |||
157 | ||||
158 | void G1CardSetCoarsenStats::reset() { | |||
159 | STATIC_ASSERT(ARRAY_SIZE(_coarsen_from) == ARRAY_SIZE(_coarsen_collision))static_assert((sizeof(array_size_impl(_coarsen_from)) == sizeof (array_size_impl(_coarsen_collision))), "ARRAY_SIZE(_coarsen_from) == ARRAY_SIZE(_coarsen_collision)" ); | |||
160 | for (uint i = 0; i < ARRAY_SIZE(_coarsen_from)sizeof(array_size_impl(_coarsen_from)); i++) { | |||
161 | _coarsen_from[i] = 0; | |||
162 | _coarsen_collision[i] = 0; | |||
163 | } | |||
164 | } | |||
165 | ||||
166 | void G1CardSetCoarsenStats::subtract_from(G1CardSetCoarsenStats& other) { | |||
167 | STATIC_ASSERT(ARRAY_SIZE(_coarsen_from) == ARRAY_SIZE(_coarsen_collision))static_assert((sizeof(array_size_impl(_coarsen_from)) == sizeof (array_size_impl(_coarsen_collision))), "ARRAY_SIZE(_coarsen_from) == ARRAY_SIZE(_coarsen_collision)" ); | |||
168 | for (uint i = 0; i < ARRAY_SIZE(_coarsen_from)sizeof(array_size_impl(_coarsen_from)); i++) { | |||
169 | _coarsen_from[i] = other._coarsen_from[i] - _coarsen_from[i]; | |||
170 | _coarsen_collision[i] = other._coarsen_collision[i] - _coarsen_collision[i]; | |||
171 | } | |||
172 | } | |||
173 | ||||
174 | void G1CardSetCoarsenStats::record_coarsening(uint tag, bool collision) { | |||
175 | assert(tag < ARRAY_SIZE(_coarsen_from), "tag %u out of bounds", tag)do { if (!(tag < sizeof(array_size_impl(_coarsen_from)))) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/gc/g1/g1CardSet.cpp" , 175, "assert(" "tag < sizeof(array_size_impl(_coarsen_from))" ") failed", "tag %u out of bounds", tag); ::breakpoint(); } } while (0); | |||
176 | Atomic::inc(&_coarsen_from[tag], memory_order_relaxed); | |||
177 | if (collision) { | |||
178 | Atomic::inc(&_coarsen_collision[tag], memory_order_relaxed); | |||
179 | } | |||
180 | } | |||
181 | ||||
182 | void G1CardSetCoarsenStats::print_on(outputStream* out) { | |||
183 | out->print_cr("Inline->AoC %zu (%zu) " | |||
184 | "AoC->Howl %zu (%zu) " | |||
185 | "Howl->Full %zu (%zu) " | |||
186 | "Inline->AoC %zu (%zu) " | |||
187 | "AoC->BitMap %zu (%zu) " | |||
188 | "BitMap->Full %zu (%zu) ", | |||
189 | _coarsen_from[0], _coarsen_collision[0], | |||
190 | _coarsen_from[1], _coarsen_collision[1], | |||
191 | // There is no BitMap at the first level so we can't . | |||
192 | _coarsen_from[3], _coarsen_collision[3], | |||
193 | _coarsen_from[4], _coarsen_collision[4], | |||
194 | _coarsen_from[5], _coarsen_collision[5], | |||
195 | _coarsen_from[6], _coarsen_collision[6] | |||
196 | ); | |||
197 | } | |||
198 | ||||
199 | class G1CardSetHashTable : public CHeapObj<mtGCCardSet> { | |||
200 | using CardSetPtr = G1CardSet::CardSetPtr; | |||
201 | ||||
202 | // Did we insert at least one card in the table? | |||
203 | bool volatile _inserted_card; | |||
204 | ||||
205 | G1CardSetMemoryManager* _mm; | |||
206 | CardSetHash _table; | |||
207 | ||||
208 | class G1CardSetHashTableLookUp : public StackObj { | |||
209 | uint _region_idx; | |||
210 | public: | |||
211 | explicit G1CardSetHashTableLookUp(uint region_idx) : _region_idx(region_idx) { } | |||
212 | ||||
213 | uintx get_hash() const { return _region_idx; } | |||
214 | ||||
215 | bool equals(G1CardSetHashTableValue* value, bool* is_dead) { | |||
216 | *is_dead = false; | |||
217 | return value->_region_idx == _region_idx; | |||
218 | } | |||
219 | }; | |||
220 | ||||
221 | class G1CardSetHashTableFound : public StackObj { | |||
222 | G1CardSetHashTableValue* _value; | |||
223 | public: | |||
224 | G1CardSetHashTableFound() : _value(nullptr) { } | |||
225 | ||||
226 | void operator()(G1CardSetHashTableValue* value) { | |||
227 | _value = value; | |||
228 | } | |||
229 | ||||
230 | G1CardSetHashTableValue* value() const { return _value; } | |||
231 | }; | |||
232 | ||||
233 | class G1CardSetHashTableScan : public StackObj { | |||
234 | G1CardSet::CardSetPtrClosure* _scan_f; | |||
235 | public: | |||
236 | explicit G1CardSetHashTableScan(G1CardSet::CardSetPtrClosure* f) : _scan_f(f) { } | |||
237 | ||||
238 | bool operator()(G1CardSetHashTableValue* value) { | |||
239 | _scan_f->do_cardsetptr(value->_region_idx, value->_num_occupied, value->_card_set); | |||
240 | return true; | |||
241 | } | |||
242 | }; | |||
243 | ||||
244 | ||||
245 | public: | |||
246 | static const size_t InitialLogTableSize = 2; | |||
247 | ||||
248 | G1CardSetHashTable(G1CardSetMemoryManager* mm, | |||
249 | size_t initial_log_table_size = InitialLogTableSize) : | |||
250 | _inserted_card(false), | |||
251 | _mm(mm), | |||
252 | _table(mm, initial_log_table_size) { | |||
253 | } | |||
254 | ||||
255 | ~G1CardSetHashTable() { | |||
256 | reset(); | |||
257 | } | |||
258 | ||||
259 | G1CardSetHashTableValue* get_or_add(uint region_idx, bool* should_grow) { | |||
260 | G1CardSetHashTableLookUp lookup(region_idx); | |||
261 | G1CardSetHashTableFound found; | |||
262 | ||||
263 | if (_table.get(Thread::current(), lookup, found)) { | |||
264 | return found.value(); | |||
265 | } | |||
266 | ||||
267 | G1CardSetHashTableValue value(region_idx, G1CardSetInlinePtr()); | |||
268 | bool inserted = _table.insert_get(Thread::current(), lookup, value, found, should_grow); | |||
269 | ||||
270 | if (!_inserted_card && inserted) { | |||
271 | // It does not matter to us who is setting the flag so a regular atomic store | |||
272 | // is sufficient. | |||
273 | Atomic::store(&_inserted_card, true); | |||
274 | } | |||
275 | ||||
276 | return found.value(); | |||
277 | } | |||
278 | ||||
279 | G1CardSetHashTableValue* get(uint region_idx) { | |||
280 | G1CardSetHashTableLookUp lookup(region_idx); | |||
281 | G1CardSetHashTableFound found; | |||
282 | ||||
283 | _table.get(Thread::current(), lookup, found); | |||
284 | return found.value(); | |||
285 | } | |||
286 | ||||
287 | void iterate_safepoint(G1CardSet::CardSetPtrClosure* cl2) { | |||
288 | G1CardSetHashTableScan cl(cl2); | |||
289 | _table.do_safepoint_scan(cl); | |||
290 | } | |||
291 | ||||
292 | void iterate(G1CardSet::CardSetPtrClosure* cl2) { | |||
293 | G1CardSetHashTableScan cl(cl2); | |||
294 | _table.do_scan(Thread::current(), cl); | |||
295 | } | |||
296 | ||||
297 | void reset() { | |||
298 | if (Atomic::load(&_inserted_card)) { | |||
299 | _table.unsafe_reset(InitialLogTableSize); | |||
300 | Atomic::store(&_inserted_card, false); | |||
301 | } | |||
302 | } | |||
303 | ||||
304 | void print(outputStream* os) { | |||
305 | os->print("TBL " PTR_FORMAT"0x%016" "l" "x" " size %zu mem %zu ", p2i(&_table), _table.get_size_log2(Thread::current()), _table.get_mem_size(Thread::current())); | |||
306 | } | |||
307 | ||||
308 | void grow() { | |||
309 | size_t new_limit = _table.get_size_log2(Thread::current()) + 1; | |||
310 | _table.grow(Thread::current(), new_limit); | |||
311 | } | |||
312 | ||||
313 | size_t mem_size() { | |||
314 | return sizeof(*this) + | |||
315 | _table.get_mem_size(Thread::current()) - sizeof(_table); | |||
316 | } | |||
317 | ||||
318 | size_t log_table_size() { return _table.get_size_log2(Thread::current()); } | |||
319 | }; | |||
320 | ||||
321 | void* G1CardSetHashTableConfig::allocate_node(void* context, size_t size, Value const& value) { | |||
322 | G1CardSetMemoryManager* mm = (G1CardSetMemoryManager*)context; | |||
323 | return mm->allocate_node(); | |||
324 | } | |||
325 | ||||
326 | void G1CardSetHashTableConfig::free_node(void* context, void* memory, Value const& value) { | |||
327 | G1CardSetMemoryManager* mm = (G1CardSetMemoryManager*)context; | |||
328 | mm->free_node(memory); | |||
329 | } | |||
330 | ||||
331 | G1CardSetCoarsenStats G1CardSet::_coarsen_stats; | |||
332 | G1CardSetCoarsenStats G1CardSet::_last_coarsen_stats; | |||
333 | ||||
334 | G1CardSet::G1CardSet(G1CardSetConfiguration* config, G1CardSetMemoryManager* mm) : | |||
335 | _mm(mm), | |||
336 | _config(config), | |||
337 | _table(new G1CardSetHashTable(mm)), | |||
338 | _num_occupied(0) { | |||
339 | } | |||
340 | ||||
341 | G1CardSet::~G1CardSet() { | |||
342 | delete _table; | |||
343 | _mm->flush(); | |||
344 | } | |||
345 | ||||
346 | uint G1CardSet::card_set_type_to_mem_object_type(uintptr_t type) const { | |||
347 | assert(type == G1CardSet::CardSetArrayOfCards ||do { if (!(type == G1CardSet::CardSetArrayOfCards || type == G1CardSet ::CardSetBitMap || type == G1CardSet::CardSetHowl)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/gc/g1/g1CardSet.cpp" , 349, "assert(" "type == G1CardSet::CardSetArrayOfCards || type == G1CardSet::CardSetBitMap || type == G1CardSet::CardSetHowl" ") failed", "should not allocate card set type %zu", type); :: breakpoint(); } } while (0) | |||
348 | type == G1CardSet::CardSetBitMap ||do { if (!(type == G1CardSet::CardSetArrayOfCards || type == G1CardSet ::CardSetBitMap || type == G1CardSet::CardSetHowl)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/gc/g1/g1CardSet.cpp" , 349, "assert(" "type == G1CardSet::CardSetArrayOfCards || type == G1CardSet::CardSetBitMap || type == G1CardSet::CardSetHowl" ") failed", "should not allocate card set type %zu", type); :: breakpoint(); } } while (0) | |||
349 | type == G1CardSet::CardSetHowl, "should not allocate card set type %zu", type)do { if (!(type == G1CardSet::CardSetArrayOfCards || type == G1CardSet ::CardSetBitMap || type == G1CardSet::CardSetHowl)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/gc/g1/g1CardSet.cpp" , 349, "assert(" "type == G1CardSet::CardSetArrayOfCards || type == G1CardSet::CardSetBitMap || type == G1CardSet::CardSetHowl" ") failed", "should not allocate card set type %zu", type); :: breakpoint(); } } while (0); | |||
350 | ||||
351 | return (uint)type; | |||
352 | } | |||
353 | ||||
354 | uint8_t* G1CardSet::allocate_mem_object(uintptr_t type) { | |||
355 | return _mm->allocate(card_set_type_to_mem_object_type(type)); | |||
356 | } | |||
357 | ||||
358 | void G1CardSet::free_mem_object(CardSetPtr card_set) { | |||
359 | assert(card_set != G1CardSet::FreeCardSet, "should not free Free card set")do { if (!(card_set != G1CardSet::FreeCardSet)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/gc/g1/g1CardSet.cpp" , 359, "assert(" "card_set != G1CardSet::FreeCardSet" ") failed" , "should not free Free card set"); ::breakpoint(); } } while (0); | |||
360 | assert(card_set != G1CardSet::FullCardSet, "should not free Full card set")do { if (!(card_set != G1CardSet::FullCardSet)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/gc/g1/g1CardSet.cpp" , 360, "assert(" "card_set != G1CardSet::FullCardSet" ") failed" , "should not free Full card set"); ::breakpoint(); } } while (0); | |||
361 | ||||
362 | uintptr_t type = card_set_type(card_set); | |||
363 | void* value = strip_card_set_type(card_set); | |||
364 | ||||
365 | assert(type == G1CardSet::CardSetArrayOfCards ||do { if (!(type == G1CardSet::CardSetArrayOfCards || type == G1CardSet ::CardSetBitMap || type == G1CardSet::CardSetHowl)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/gc/g1/g1CardSet.cpp" , 367, "assert(" "type == G1CardSet::CardSetArrayOfCards || type == G1CardSet::CardSetBitMap || type == G1CardSet::CardSetHowl" ") failed", "should not free card set type %zu", type); ::breakpoint (); } } while (0) | |||
366 | type == G1CardSet::CardSetBitMap ||do { if (!(type == G1CardSet::CardSetArrayOfCards || type == G1CardSet ::CardSetBitMap || type == G1CardSet::CardSetHowl)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/gc/g1/g1CardSet.cpp" , 367, "assert(" "type == G1CardSet::CardSetArrayOfCards || type == G1CardSet::CardSetBitMap || type == G1CardSet::CardSetHowl" ") failed", "should not free card set type %zu", type); ::breakpoint (); } } while (0) | |||
367 | type == G1CardSet::CardSetHowl, "should not free card set type %zu", type)do { if (!(type == G1CardSet::CardSetArrayOfCards || type == G1CardSet ::CardSetBitMap || type == G1CardSet::CardSetHowl)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/gc/g1/g1CardSet.cpp" , 367, "assert(" "type == G1CardSet::CardSetArrayOfCards || type == G1CardSet::CardSetBitMap || type == G1CardSet::CardSetHowl" ") failed", "should not free card set type %zu", type); ::breakpoint (); } } while (0); | |||
368 | ||||
369 | #ifdef ASSERT1 | |||
370 | if (type == G1CardSet::CardSetArrayOfCards || | |||
371 | type == G1CardSet::CardSetBitMap || | |||
372 | type == G1CardSet::CardSetHowl) { | |||
373 | G1CardSetContainer* card_set = (G1CardSetContainer*)value; | |||
374 | assert((card_set->refcount() == 1), "must be")do { if (!((card_set->refcount() == 1))) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/gc/g1/g1CardSet.cpp" , 374, "assert(" "(card_set->refcount() == 1)" ") failed", "must be"); ::breakpoint(); } } while (0); | |||
375 | } | |||
376 | #endif | |||
377 | ||||
378 | _mm->free(card_set_type_to_mem_object_type(type), value); | |||
379 | } | |||
380 | ||||
381 | G1CardSet::CardSetPtr G1CardSet::acquire_card_set(CardSetPtr volatile* card_set_addr) { | |||
382 | // Update reference counts under RCU critical section to avoid a | |||
383 | // use-after-cleapup bug where we increment a reference count for | |||
384 | // an object whose memory has already been cleaned up and reused. | |||
385 | GlobalCounter::CriticalSection cs(Thread::current()); | |||
386 | while (true) { | |||
387 | // Get cardsetptr and increment refcount atomically wrt to memory reuse. | |||
388 | CardSetPtr card_set = Atomic::load_acquire(card_set_addr); | |||
389 | uint cs_type = card_set_type(card_set); | |||
390 | if (card_set == FullCardSet || cs_type == CardSetInlinePtr) { | |||
391 | return card_set; | |||
392 | } | |||
393 | ||||
394 | G1CardSetContainer* card_set_on_heap = (G1CardSetContainer*)strip_card_set_type(card_set); | |||
395 | ||||
396 | if (card_set_on_heap->try_increment_refcount()) { | |||
397 | assert(card_set_on_heap->refcount() >= 3, "Smallest value is 3")do { if (!(card_set_on_heap->refcount() >= 3)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/gc/g1/g1CardSet.cpp" , 397, "assert(" "card_set_on_heap->refcount() >= 3" ") failed" , "Smallest value is 3"); ::breakpoint(); } } while (0); | |||
398 | return card_set; | |||
399 | } | |||
400 | } | |||
401 | } | |||
402 | ||||
403 | bool G1CardSet::release_card_set(CardSetPtr card_set) { | |||
404 | uint cs_type = card_set_type(card_set); | |||
405 | if (card_set == FullCardSet || cs_type == CardSetInlinePtr) { | |||
406 | return false; | |||
407 | } | |||
408 | ||||
409 | G1CardSetContainer* card_set_on_heap = (G1CardSetContainer*)strip_card_set_type(card_set); | |||
410 | return card_set_on_heap->decrement_refcount() == 1; | |||
411 | } | |||
412 | ||||
413 | void G1CardSet::release_and_maybe_free_card_set(CardSetPtr card_set) { | |||
414 | if (release_card_set(card_set)) { | |||
415 | free_mem_object(card_set); | |||
416 | } | |||
417 | } | |||
418 | ||||
419 | void G1CardSet::release_and_must_free_card_set(CardSetPtr card_set) { | |||
420 | bool should_free = release_card_set(card_set); | |||
421 | assert(should_free, "should have been the only one having a reference")do { if (!(should_free)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/gc/g1/g1CardSet.cpp" , 421, "assert(" "should_free" ") failed", "should have been the only one having a reference" ); ::breakpoint(); } } while (0); | |||
422 | free_mem_object(card_set); | |||
423 | } | |||
424 | ||||
425 | class G1ReleaseCardsets : public StackObj { | |||
426 | G1CardSet* _card_set; | |||
427 | using CardSetPtr = G1CardSet::CardSetPtr; | |||
428 | ||||
429 | void coarsen_to_full(CardSetPtr* card_set_addr) { | |||
430 | while (true) { | |||
431 | CardSetPtr cur_card_set = Atomic::load_acquire(card_set_addr); | |||
432 | uint cs_type = G1CardSet::card_set_type(cur_card_set); | |||
433 | if (cur_card_set == G1CardSet::FullCardSet) { | |||
434 | return; | |||
435 | } | |||
436 | ||||
437 | CardSetPtr old_value = Atomic::cmpxchg(card_set_addr, cur_card_set, G1CardSet::FullCardSet); | |||
438 | ||||
439 | if (old_value == cur_card_set) { | |||
440 | _card_set->release_and_maybe_free_card_set(cur_card_set); | |||
441 | return; | |||
442 | } | |||
443 | } | |||
444 | } | |||
445 | ||||
446 | public: | |||
447 | explicit G1ReleaseCardsets(G1CardSet* card_set) : _card_set(card_set) { } | |||
448 | ||||
449 | void operator ()(CardSetPtr* card_set_addr) { | |||
450 | coarsen_to_full(card_set_addr); | |||
451 | } | |||
452 | }; | |||
453 | ||||
454 | G1AddCardResult G1CardSet::add_to_array(CardSetPtr card_set, uint card_in_region) { | |||
455 | G1CardSetArray* array = card_set_ptr<G1CardSetArray>(card_set); | |||
456 | return array->add(card_in_region); | |||
457 | } | |||
458 | ||||
459 | G1AddCardResult G1CardSet::add_to_howl(CardSetPtr parent_card_set, | |||
460 | uint card_region, | |||
461 | uint card_in_region, | |||
462 | bool increment_total) { | |||
463 | G1CardSetHowl* howl = card_set_ptr<G1CardSetHowl>(parent_card_set); | |||
464 | ||||
465 | G1AddCardResult add_result; | |||
466 | CardSetPtr to_transfer = nullptr; | |||
467 | CardSetPtr card_set; | |||
468 | ||||
469 | uint bucket = _config->howl_bucket_index(card_in_region); | |||
470 | volatile CardSetPtr* bucket_entry = howl->get_card_set_addr(bucket); | |||
471 | ||||
472 | while (true) { | |||
473 | if (Atomic::load(&howl->_num_entries) >= _config->cards_in_howl_threshold()) { | |||
474 | return Overflow; | |||
475 | } | |||
476 | ||||
477 | card_set = acquire_card_set(bucket_entry); | |||
478 | add_result = add_to_card_set(bucket_entry, card_set, card_region, card_in_region); | |||
479 | ||||
480 | if (add_result != Overflow) { | |||
481 | break; | |||
482 | } | |||
483 | // Card set has overflown. Coarsen or retry. | |||
484 | bool coarsened = coarsen_card_set(bucket_entry, card_set, card_in_region, true /* within_howl */); | |||
485 | _coarsen_stats.record_coarsening(card_set_type(card_set) + G1CardSetCoarsenStats::CoarsenHowlOffset, !coarsened); | |||
486 | if (coarsened) { | |||
487 | // We have been the one coarsening this card set (and in the process added that card). | |||
488 | add_result = Added; | |||
489 | to_transfer = card_set; | |||
490 | break; | |||
491 | } | |||
492 | // Somebody else beat us to coarsening. Retry. | |||
493 | release_and_maybe_free_card_set(card_set); | |||
494 | } | |||
495 | ||||
496 | if (increment_total && add_result == Added) { | |||
497 | Atomic::inc(&howl->_num_entries, memory_order_relaxed); | |||
498 | } | |||
499 | ||||
500 | if (to_transfer != nullptr) { | |||
501 | transfer_cards_in_howl(parent_card_set, to_transfer, card_region); | |||
502 | } | |||
503 | ||||
504 | release_and_maybe_free_card_set(card_set); | |||
505 | return add_result; | |||
506 | } | |||
507 | ||||
508 | G1AddCardResult G1CardSet::add_to_bitmap(CardSetPtr card_set, uint card_in_region) { | |||
509 | G1CardSetBitMap* bitmap = card_set_ptr<G1CardSetBitMap>(card_set); | |||
510 | uint card_offset = _config->howl_bitmap_offset(card_in_region); | |||
511 | return bitmap->add(card_offset, _config->cards_in_howl_bitmap_threshold(), _config->max_cards_in_howl_bitmap()); | |||
512 | } | |||
513 | ||||
514 | G1AddCardResult G1CardSet::add_to_inline_ptr(CardSetPtr volatile* card_set_addr, CardSetPtr card_set, uint card_in_region) { | |||
515 | G1CardSetInlinePtr value(card_set_addr, card_set); | |||
516 | return value.add(card_in_region, _config->inline_ptr_bits_per_card(), _config->max_cards_in_inline_ptr()); | |||
517 | } | |||
518 | ||||
519 | G1CardSet::CardSetPtr G1CardSet::create_coarsened_array_of_cards(uint card_in_region, bool within_howl) { | |||
520 | uint8_t* data = nullptr; | |||
521 | CardSetPtr new_card_set; | |||
522 | if (within_howl) { | |||
523 | uint const size_in_bits = _config->max_cards_in_howl_bitmap(); | |||
524 | uint card_offset = _config->howl_bitmap_offset(card_in_region); | |||
525 | data = allocate_mem_object(CardSetBitMap); | |||
526 | new (data) G1CardSetBitMap(card_offset, size_in_bits); | |||
527 | new_card_set = make_card_set_ptr(data, CardSetBitMap); | |||
528 | } else { | |||
529 | data = allocate_mem_object(CardSetHowl); | |||
530 | new (data) G1CardSetHowl(card_in_region, _config); | |||
531 | new_card_set = make_card_set_ptr(data, CardSetHowl); | |||
532 | } | |||
533 | return new_card_set; | |||
534 | } | |||
535 | ||||
536 | bool G1CardSet::coarsen_card_set(volatile CardSetPtr* card_set_addr, | |||
537 | CardSetPtr cur_card_set, | |||
538 | uint card_in_region, | |||
539 | bool within_howl) { | |||
540 | CardSetPtr new_card_set = nullptr; | |||
541 | ||||
542 | switch (card_set_type(cur_card_set)) { | |||
543 | case CardSetArrayOfCards : { | |||
544 | new_card_set = create_coarsened_array_of_cards(card_in_region, within_howl); | |||
545 | break; | |||
546 | } | |||
547 | case CardSetBitMap: { | |||
548 | new_card_set = FullCardSet; | |||
549 | break; | |||
550 | } | |||
551 | case CardSetInlinePtr: { | |||
552 | uint const size = _config->max_cards_in_array(); | |||
553 | uint8_t* data = allocate_mem_object(CardSetArrayOfCards); | |||
554 | new (data) G1CardSetArray(card_in_region, size); | |||
555 | new_card_set = make_card_set_ptr(data, CardSetArrayOfCards); | |||
556 | break; | |||
557 | } | |||
558 | case CardSetHowl: { | |||
559 | new_card_set = FullCardSet; // anything will do at this point. | |||
560 | break; | |||
561 | } | |||
562 | default: | |||
563 | ShouldNotReachHere()do { (*g_assert_poison) = 'X';; report_should_not_reach_here( "/home/daniel/Projects/java/jdk/src/hotspot/share/gc/g1/g1CardSet.cpp" , 563); ::breakpoint(); } while (0); | |||
564 | } | |||
565 | ||||
566 | CardSetPtr old_value = Atomic::cmpxchg(card_set_addr, cur_card_set, new_card_set); // Memory order? | |||
567 | if (old_value == cur_card_set) { | |||
568 | // Success. Indicate that the cards from the current card set must be transferred | |||
569 | // by this caller. | |||
570 | // Release the hash table reference to the card. The caller still holds the | |||
571 | // reference to this card set, so it can never be released (and we do not need to | |||
572 | // check its result). | |||
573 | bool should_free = release_card_set(cur_card_set); | |||
574 | assert(!should_free, "must have had more than one reference")do { if (!(!should_free)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/gc/g1/g1CardSet.cpp" , 574, "assert(" "!should_free" ") failed", "must have had more than one reference" ); ::breakpoint(); } } while (0); | |||
575 | // Free containers if cur_card_set is CardSetHowl | |||
576 | if (card_set_type(cur_card_set) == CardSetHowl) { | |||
577 | G1ReleaseCardsets rel(this); | |||
578 | card_set_ptr<G1CardSetHowl>(cur_card_set)->iterate(rel, _config->num_buckets_in_howl()); | |||
579 | } | |||
580 | return true; | |||
581 | } else { | |||
582 | // Somebody else beat us to coarsening that card set. Exit, but clean up first. | |||
583 | if (new_card_set != FullCardSet) { | |||
584 | assert(new_card_set != nullptr, "must not be")do { if (!(new_card_set != nullptr)) { (*g_assert_poison) = 'X' ;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/gc/g1/g1CardSet.cpp" , 584, "assert(" "new_card_set != nullptr" ") failed", "must not be" ); ::breakpoint(); } } while (0); | |||
585 | release_and_must_free_card_set(new_card_set); | |||
586 | } | |||
587 | return false; | |||
588 | } | |||
589 | } | |||
590 | ||||
591 | class G1TransferCard : public StackObj { | |||
592 | G1CardSet* _card_set; | |||
593 | uint _region_idx; | |||
594 | public: | |||
595 | G1TransferCard(G1CardSet* card_set, uint region_idx) : _card_set(card_set), _region_idx(region_idx) { } | |||
596 | ||||
597 | void operator ()(uint card_idx) { | |||
598 | _card_set->add_card(_region_idx, card_idx, false); | |||
599 | } | |||
600 | }; | |||
601 | ||||
602 | void G1CardSet::transfer_cards(G1CardSetHashTableValue* table_entry, CardSetPtr source_card_set, uint card_region) { | |||
603 | assert(source_card_set != FullCardSet, "Should not need to transfer from full")do { if (!(source_card_set != FullCardSet)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/gc/g1/g1CardSet.cpp" , 603, "assert(" "source_card_set != FullCardSet" ") failed", "Should not need to transfer from full"); ::breakpoint(); } } while (0); | |||
604 | // Need to transfer old entries unless there is a Full card set in place now, i.e. | |||
605 | // the old type has been CardSetBitMap. "Full" contains all elements anyway. | |||
606 | if (card_set_type(source_card_set) != CardSetHowl) { | |||
607 | G1TransferCard iter(this, card_region); | |||
608 | iterate_cards_during_transfer(source_card_set, iter); | |||
609 | } else { | |||
610 | assert(card_set_type(source_card_set) == CardSetHowl, "must be")do { if (!(card_set_type(source_card_set) == CardSetHowl)) { ( *g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/gc/g1/g1CardSet.cpp" , 610, "assert(" "card_set_type(source_card_set) == CardSetHowl" ") failed", "must be"); ::breakpoint(); } } while (0); | |||
611 | // Need to correct for that the Full remembered set occupies more cards than the | |||
612 | // AoCS before. | |||
613 | Atomic::add(&_num_occupied, _config->max_cards_in_region() - table_entry->_num_occupied, memory_order_relaxed); | |||
614 | } | |||
615 | } | |||
616 | ||||
617 | void G1CardSet::transfer_cards_in_howl(CardSetPtr parent_card_set, | |||
618 | CardSetPtr source_card_set, | |||
619 | uint card_region) { | |||
620 | assert(card_set_type(parent_card_set) == CardSetHowl, "must be")do { if (!(card_set_type(parent_card_set) == CardSetHowl)) { ( *g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/gc/g1/g1CardSet.cpp" , 620, "assert(" "card_set_type(parent_card_set) == CardSetHowl" ") failed", "must be"); ::breakpoint(); } } while (0); | |||
621 | assert(source_card_set != FullCardSet, "Should not need to transfer from full")do { if (!(source_card_set != FullCardSet)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/gc/g1/g1CardSet.cpp" , 621, "assert(" "source_card_set != FullCardSet" ") failed", "Should not need to transfer from full"); ::breakpoint(); } } while (0); | |||
622 | // Need to transfer old entries unless there is a Full card set in place now, i.e. | |||
623 | // the old type has been CardSetBitMap. | |||
624 | if (card_set_type(source_card_set) != CardSetBitMap) { | |||
625 | // We only need to transfer from anything below CardSetBitMap. | |||
626 | G1TransferCard iter(this, card_region); | |||
627 | iterate_cards_during_transfer(source_card_set, iter); | |||
628 | } else { | |||
629 | uint diff = _config->max_cards_in_howl_bitmap() - card_set_ptr<G1CardSetBitMap>(source_card_set)->num_bits_set(); | |||
630 | ||||
631 | // Need to correct for that the Full remembered set occupies more cards than the | |||
632 | // bitmap before. | |||
633 | // We add 1 card less because the values will be incremented | |||
634 | // in G1CardSet::add_card for the current addition or where already incremented in | |||
635 | // G1CardSet::add_to_howl after coarsening. | |||
636 | diff -= 1; | |||
637 | ||||
638 | G1CardSetHowl* howling_array = card_set_ptr<G1CardSetHowl>(parent_card_set); | |||
639 | Atomic::add(&howling_array->_num_entries, diff, memory_order_relaxed); | |||
640 | ||||
641 | G1CardSetHashTableValue* table_entry = get_card_set(card_region); | |||
642 | assert(table_entry != nullptr, "Table entry not found for transferred cards")do { if (!(table_entry != nullptr)) { (*g_assert_poison) = 'X' ;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/gc/g1/g1CardSet.cpp" , 642, "assert(" "table_entry != nullptr" ") failed", "Table entry not found for transferred cards" ); ::breakpoint(); } } while (0); | |||
643 | ||||
644 | Atomic::add(&table_entry->_num_occupied, diff, memory_order_relaxed); | |||
645 | ||||
646 | Atomic::add(&_num_occupied, diff, memory_order_relaxed); | |||
647 | } | |||
648 | } | |||
649 | ||||
650 | G1AddCardResult G1CardSet::add_to_card_set(volatile CardSetPtr* card_set_addr, CardSetPtr card_set, uint card_region, uint card_in_region, bool increment_total) { | |||
651 | assert(card_set_addr != nullptr, "Cannot add to empty cardset")do { if (!(card_set_addr != nullptr)) { (*g_assert_poison) = 'X' ;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/gc/g1/g1CardSet.cpp" , 651, "assert(" "card_set_addr != nullptr" ") failed", "Cannot add to empty cardset" ); ::breakpoint(); } } while (0); | |||
652 | ||||
653 | G1AddCardResult add_result; | |||
654 | ||||
655 | switch (card_set_type(card_set)) { | |||
656 | case CardSetInlinePtr: { | |||
657 | add_result = add_to_inline_ptr(card_set_addr, card_set, card_in_region); | |||
658 | break; | |||
659 | } | |||
660 | case CardSetArrayOfCards : { | |||
661 | add_result = add_to_array(card_set, card_in_region); | |||
662 | break; | |||
663 | } | |||
664 | case CardSetBitMap: { | |||
665 | add_result = add_to_bitmap(card_set, card_in_region); | |||
666 | break; | |||
667 | } | |||
668 | case CardSetHowl: { | |||
669 | assert(CardSetHowl == card_set_type(FullCardSet), "must be")do { if (!(CardSetHowl == card_set_type(FullCardSet))) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/gc/g1/g1CardSet.cpp" , 669, "assert(" "CardSetHowl == card_set_type(FullCardSet)" ") failed" , "must be"); ::breakpoint(); } } while (0); | |||
670 | if (card_set == FullCardSet) { | |||
671 | return Found; | |||
672 | } | |||
673 | add_result = add_to_howl(card_set, card_region, card_in_region, increment_total); | |||
674 | break; | |||
675 | } | |||
676 | default: | |||
677 | ShouldNotReachHere()do { (*g_assert_poison) = 'X';; report_should_not_reach_here( "/home/daniel/Projects/java/jdk/src/hotspot/share/gc/g1/g1CardSet.cpp" , 677); ::breakpoint(); } while (0); | |||
678 | } | |||
679 | ||||
680 | return add_result; | |||
| ||||
681 | } | |||
682 | ||||
683 | G1CardSetHashTableValue* G1CardSet::get_or_add_card_set(uint card_region, bool* should_grow_table) { | |||
684 | return _table->get_or_add(card_region, should_grow_table); | |||
685 | } | |||
686 | ||||
687 | G1CardSetHashTableValue* G1CardSet::get_card_set(uint card_region) { | |||
688 | return _table->get(card_region); | |||
689 | } | |||
690 | ||||
691 | G1AddCardResult G1CardSet::add_card(uint card_region, uint card_in_region, bool increment_total) { | |||
692 | G1AddCardResult add_result; | |||
693 | CardSetPtr to_transfer = nullptr; | |||
694 | CardSetPtr card_set; | |||
695 | ||||
696 | bool should_grow_table = false; | |||
697 | G1CardSetHashTableValue* table_entry = get_or_add_card_set(card_region, &should_grow_table); | |||
698 | while (true) { | |||
699 | card_set = acquire_card_set(&table_entry->_card_set); | |||
700 | add_result = add_to_card_set(&table_entry->_card_set, card_set, card_region, card_in_region, increment_total); | |||
701 | ||||
702 | if (add_result != Overflow) { | |||
703 | break; | |||
704 | } | |||
705 | // Card set has overflown. Coarsen or retry. | |||
706 | bool coarsened = coarsen_card_set(&table_entry->_card_set, card_set, card_in_region); | |||
707 | _coarsen_stats.record_coarsening(card_set_type(card_set), !coarsened); | |||
708 | if (coarsened) { | |||
709 | // We have been the one coarsening this card set (and in the process added that card). | |||
710 | add_result = Added; | |||
711 | to_transfer = card_set; | |||
712 | break; | |||
713 | } | |||
714 | // Somebody else beat us to coarsening. Retry. | |||
715 | release_and_maybe_free_card_set(card_set); | |||
716 | } | |||
717 | ||||
718 | if (increment_total && add_result == Added) { | |||
719 | Atomic::inc(&table_entry->_num_occupied, memory_order_relaxed); | |||
720 | Atomic::inc(&_num_occupied, memory_order_relaxed); | |||
721 | } | |||
722 | if (should_grow_table) { | |||
723 | _table->grow(); | |||
724 | } | |||
725 | if (to_transfer != nullptr) { | |||
726 | transfer_cards(table_entry, to_transfer, card_region); | |||
727 | } | |||
728 | ||||
729 | release_and_maybe_free_card_set(card_set); | |||
730 | ||||
731 | return add_result; | |||
732 | } | |||
733 | ||||
734 | bool G1CardSet::contains_card(uint card_region, uint card_in_region) { | |||
735 | assert(card_in_region < _config->max_cards_in_region(),do { if (!(card_in_region < _config->max_cards_in_region ())) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/gc/g1/g1CardSet.cpp" , 736, "assert(" "card_in_region < _config->max_cards_in_region()" ") failed", "Card %u is beyond max %u", card_in_region, _config ->max_cards_in_region()); ::breakpoint(); } } while (0) | |||
736 | "Card %u is beyond max %u", card_in_region, _config->max_cards_in_region())do { if (!(card_in_region < _config->max_cards_in_region ())) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/gc/g1/g1CardSet.cpp" , 736, "assert(" "card_in_region < _config->max_cards_in_region()" ") failed", "Card %u is beyond max %u", card_in_region, _config ->max_cards_in_region()); ::breakpoint(); } } while (0); | |||
737 | ||||
738 | // Protect the card set from reclamation. | |||
739 | GlobalCounter::CriticalSection cs(Thread::current()); | |||
740 | G1CardSetHashTableValue* table_entry = get_card_set(card_region); | |||
741 | if (table_entry == nullptr) { | |||
742 | return false; | |||
743 | } | |||
744 | ||||
745 | CardSetPtr card_set = table_entry->_card_set; | |||
746 | if (card_set == FullCardSet) { | |||
747 | // contains_card() is not a performance critical method so we do not hide that | |||
748 | // case in the switch below. | |||
749 | return true; | |||
750 | } | |||
751 | ||||
752 | switch (card_set_type(card_set)) { | |||
753 | case CardSetInlinePtr: { | |||
754 | G1CardSetInlinePtr ptr(card_set); | |||
755 | return ptr.contains(card_in_region, _config->inline_ptr_bits_per_card()); | |||
756 | } | |||
757 | case CardSetArrayOfCards : return card_set_ptr<G1CardSetArray>(card_set)->contains(card_in_region); | |||
758 | case CardSetBitMap: return card_set_ptr<G1CardSetBitMap>(card_set)->contains(card_in_region, _config->max_cards_in_howl_bitmap()); | |||
759 | case CardSetHowl: { | |||
760 | G1CardSetHowl* howling_array = card_set_ptr<G1CardSetHowl>(card_set); | |||
761 | ||||
762 | return howling_array->contains(card_in_region, _config); | |||
763 | } | |||
764 | } | |||
765 | ShouldNotReachHere()do { (*g_assert_poison) = 'X';; report_should_not_reach_here( "/home/daniel/Projects/java/jdk/src/hotspot/share/gc/g1/g1CardSet.cpp" , 765); ::breakpoint(); } while (0); | |||
766 | return false; | |||
767 | } | |||
768 | ||||
769 | void G1CardSet::print_info(outputStream* st, uint card_region, uint card_in_region) { | |||
770 | G1CardSetHashTableValue* table_entry = get_card_set(card_region); | |||
771 | if (table_entry == nullptr) { | |||
772 | st->print("NULL card set"); | |||
773 | return; | |||
774 | } | |||
775 | ||||
776 | CardSetPtr card_set = table_entry->_card_set; | |||
777 | if (card_set == FullCardSet) { | |||
778 | st->print("FULL card set)"); | |||
779 | return; | |||
780 | } | |||
781 | switch (card_set_type(card_set)) { | |||
782 | case CardSetInlinePtr: { | |||
783 | st->print("InlinePtr not containing %u", card_in_region); | |||
784 | break; | |||
785 | } | |||
786 | case CardSetArrayOfCards : { | |||
787 | st->print("AoC not containing %u", card_in_region); | |||
788 | break; | |||
789 | } | |||
790 | case CardSetBitMap: { | |||
791 | st->print("BitMap not containing %u", card_in_region); | |||
792 | break; | |||
793 | } | |||
794 | case CardSetHowl: { | |||
795 | st->print("CardSetHowl not containing %u", card_in_region); | |||
796 | break; | |||
797 | } | |||
798 | default: st->print("Unknown card set type %u", card_set_type(card_set)); ShouldNotReachHere()do { (*g_assert_poison) = 'X';; report_should_not_reach_here( "/home/daniel/Projects/java/jdk/src/hotspot/share/gc/g1/g1CardSet.cpp" , 798); ::breakpoint(); } while (0); break; | |||
799 | } | |||
800 | } | |||
801 | ||||
802 | template <class CardVisitor> | |||
803 | void G1CardSet::iterate_cards_during_transfer(CardSetPtr const card_set, CardVisitor& cl) { | |||
804 | uint type = card_set_type(card_set); | |||
805 | assert(type == CardSetInlinePtr || type == CardSetArrayOfCards,do { if (!(type == CardSetInlinePtr || type == CardSetArrayOfCards )) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/gc/g1/g1CardSet.cpp" , 807, "assert(" "type == CardSetInlinePtr || type == CardSetArrayOfCards" ") failed", "invalid card set type %d to transfer from", card_set_type (card_set)); ::breakpoint(); } } while (0) | |||
| ||||
806 | "invalid card set type %d to transfer from",do { if (!(type == CardSetInlinePtr || type == CardSetArrayOfCards )) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/gc/g1/g1CardSet.cpp" , 807, "assert(" "type == CardSetInlinePtr || type == CardSetArrayOfCards" ") failed", "invalid card set type %d to transfer from", card_set_type (card_set)); ::breakpoint(); } } while (0) | |||
807 | card_set_type(card_set))do { if (!(type == CardSetInlinePtr || type == CardSetArrayOfCards )) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/gc/g1/g1CardSet.cpp" , 807, "assert(" "type == CardSetInlinePtr || type == CardSetArrayOfCards" ") failed", "invalid card set type %d to transfer from", card_set_type (card_set)); ::breakpoint(); } } while (0); | |||
808 | ||||
809 | switch (type) { | |||
810 | case CardSetInlinePtr: { | |||
811 | G1CardSetInlinePtr ptr(card_set); | |||
812 | ptr.iterate(cl, _config->inline_ptr_bits_per_card()); | |||
813 | return; | |||
814 | } | |||
815 | case CardSetArrayOfCards : { | |||
816 | card_set_ptr<G1CardSetArray>(card_set)->iterate(cl); | |||
817 | return; | |||
818 | } | |||
819 | default: | |||
820 | ShouldNotReachHere()do { (*g_assert_poison) = 'X';; report_should_not_reach_here( "/home/daniel/Projects/java/jdk/src/hotspot/share/gc/g1/g1CardSet.cpp" , 820); ::breakpoint(); } while (0); | |||
821 | } | |||
822 | } | |||
823 | ||||
824 | void G1CardSet::iterate_containers(CardSetPtrClosure* cl, bool at_safepoint) { | |||
825 | if (at_safepoint) { | |||
826 | _table->iterate_safepoint(cl); | |||
827 | } else { | |||
828 | _table->iterate(cl); | |||
829 | } | |||
830 | } | |||
831 | ||||
832 | // Applied to all card (ranges) of the containers. | |||
833 | template <typename Closure> | |||
834 | class G1ContainerCardsClosure { | |||
835 | Closure& _cl; | |||
836 | uint _region_idx; | |||
837 | ||||
838 | public: | |||
839 | G1ContainerCardsClosure(Closure& cl, uint region_idx) : _cl(cl), _region_idx(region_idx) { } | |||
840 | ||||
841 | bool start_iterate(uint tag) { return true; } | |||
842 | ||||
843 | void operator()(uint card_idx) { | |||
844 | _cl.do_card(_region_idx, card_idx); | |||
845 | } | |||
846 | ||||
847 | void operator()(uint card_idx, uint length) { | |||
848 | for (uint i = 0; i < length; i++) { | |||
849 | _cl.do_card(_region_idx, card_idx); | |||
850 | } | |||
851 | } | |||
852 | }; | |||
853 | ||||
854 | template <typename Closure, template <typename> class CardOrRanges> | |||
855 | class G1CardSetContainersClosure : public G1CardSet::CardSetPtrClosure { | |||
856 | G1CardSet* _card_set; | |||
857 | Closure& _cl; | |||
858 | ||||
859 | public: | |||
860 | ||||
861 | G1CardSetContainersClosure(G1CardSet* card_set, | |||
862 | Closure& cl) : | |||
863 | _card_set(card_set), | |||
864 | _cl(cl) { } | |||
865 | ||||
866 | void do_cardsetptr(uint region_idx, size_t num_occupied, G1CardSet::CardSetPtr card_set) override { | |||
867 | CardOrRanges<Closure> cl(_cl, region_idx); | |||
868 | _card_set->iterate_cards_or_ranges_in_container(card_set, cl); | |||
869 | } | |||
870 | }; | |||
871 | ||||
872 | void G1CardSet::iterate_cards(CardClosure& cl) { | |||
873 | G1CardSetContainersClosure<CardClosure, G1ContainerCardsClosure> cl2(this, cl); | |||
874 | iterate_containers(&cl2); | |||
875 | } | |||
876 | ||||
877 | bool G1CardSet::occupancy_less_or_equal_to(size_t limit) const { | |||
878 | return occupied() <= limit; | |||
879 | } | |||
880 | ||||
881 | bool G1CardSet::is_empty() const { | |||
882 | return _num_occupied == 0; | |||
883 | } | |||
884 | ||||
885 | size_t G1CardSet::occupied() const { | |||
886 | return _num_occupied; | |||
887 | } | |||
888 | ||||
889 | size_t G1CardSet::num_containers() { | |||
890 | class GetNumberOfContainers : public CardSetPtrClosure { | |||
891 | public: | |||
892 | size_t _count; | |||
893 | ||||
894 | GetNumberOfContainers() : CardSetPtrClosure(), _count(0) { } | |||
895 | ||||
896 | void do_cardsetptr(uint region_idx, size_t num_occupied, CardSetPtr card_set) override { | |||
897 | _count++; | |||
898 | } | |||
899 | } cl; | |||
900 | ||||
901 | iterate_containers(&cl); | |||
902 | return cl._count; | |||
903 | } | |||
904 | ||||
905 | G1CardSetCoarsenStats G1CardSet::coarsen_stats() { | |||
906 | return _coarsen_stats; | |||
907 | } | |||
908 | ||||
909 | void G1CardSet::print_coarsen_stats(outputStream* out) { | |||
910 | _last_coarsen_stats.subtract_from(_coarsen_stats); | |||
911 | out->print("Coarsening (recent): "); | |||
912 | _last_coarsen_stats.print_on(out); | |||
913 | out->print("Coarsening (all): "); | |||
914 | _coarsen_stats.print_on(out); | |||
915 | } | |||
916 | ||||
917 | size_t G1CardSet::mem_size() const { | |||
918 | return sizeof(*this) + | |||
919 | _table->mem_size() + | |||
920 | _mm->mem_size(); | |||
921 | } | |||
922 | ||||
923 | size_t G1CardSet::wasted_mem_size() const { | |||
924 | return _mm->wasted_mem_size(); | |||
925 | } | |||
926 | ||||
927 | size_t G1CardSet::static_mem_size() { | |||
928 | return sizeof(FullCardSet) + sizeof(_coarsen_stats); | |||
929 | } | |||
930 | ||||
931 | void G1CardSet::clear() { | |||
932 | _table->reset(); | |||
933 | _num_occupied = 0; | |||
934 | _mm->flush(); | |||
935 | } | |||
936 | ||||
937 | void G1CardSet::print(outputStream* os) { | |||
938 | _table->print(os); | |||
939 | _mm->print(os); | |||
940 | } |
1 | /* |
2 | * Copyright (c) 2021, 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_G1CARDSETCONTAINERS_INLINE_HPP |
26 | #define SHARE_GC_G1_G1CARDSETCONTAINERS_INLINE_HPP |
27 | |
28 | #include "gc/g1/g1CardSetContainers.hpp" |
29 | #include "gc/g1/g1GCPhaseTimes.hpp" |
30 | #include "utilities/globalDefinitions.hpp" |
31 | |
32 | inline G1CardSetInlinePtr::CardSetPtr G1CardSetInlinePtr::merge(CardSetPtr orig_value, uint card_in_region, uint idx, uint bits_per_card) { |
33 | assert((idx & (SizeFieldMask >> SizeFieldPos)) == idx, "Index %u too large to fit into size field", idx)do { if (!((idx & (SizeFieldMask >> SizeFieldPos)) == idx)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/gc/g1/g1CardSetContainers.inline.hpp" , 33, "assert(" "(idx & (SizeFieldMask >> SizeFieldPos)) == idx" ") failed", "Index %u too large to fit into size field", idx ); ::breakpoint(); } } while (0); |
34 | assert(card_in_region < ((uint)1 << bits_per_card), "Card %u too large to fit into card value field", card_in_region)do { if (!(card_in_region < ((uint)1 << bits_per_card ))) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/gc/g1/g1CardSetContainers.inline.hpp" , 34, "assert(" "card_in_region < ((uint)1 << bits_per_card)" ") failed", "Card %u too large to fit into card value field" , card_in_region); ::breakpoint(); } } while (0); |
35 | |
36 | uint8_t card_pos = card_pos_for(idx, bits_per_card); |
37 | assert(card_pos + bits_per_card < BitsInValue, "Putting card at pos %u with %u bits would extend beyond pointer", card_pos, bits_per_card)do { if (!(card_pos + bits_per_card < BitsInValue)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/gc/g1/g1CardSetContainers.inline.hpp" , 37, "assert(" "card_pos + bits_per_card < BitsInValue" ") failed" , "Putting card at pos %u with %u bits would extend beyond pointer" , card_pos, bits_per_card); ::breakpoint(); } } while (0); |
38 | |
39 | // Check that we do not touch any fields we do not own. |
40 | uintptr_t mask = ((((uintptr_t)1 << bits_per_card) - 1) << card_pos); |
41 | assert(((uintptr_t)orig_value & mask) == 0, "The bits in the new range should be empty; orig_value " PTR_FORMAT " mask " PTR_FORMAT, p2i(orig_value), mask)do { if (!(((uintptr_t)orig_value & mask) == 0)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/gc/g1/g1CardSetContainers.inline.hpp" , 41, "assert(" "((uintptr_t)orig_value & mask) == 0" ") failed" , "The bits in the new range should be empty; orig_value " "0x%016" "l" "x" " mask " "0x%016" "l" "x", p2i(orig_value), mask); :: breakpoint(); } } while (0); |
42 | |
43 | uintptr_t value = ((uintptr_t)(idx + 1) << SizeFieldPos) | ((uintptr_t)card_in_region << card_pos); |
44 | uintptr_t res = (((uintptr_t)orig_value & ~SizeFieldMask) | value); |
45 | return (CardSetPtr)res; |
46 | } |
47 | |
48 | inline G1AddCardResult G1CardSetInlinePtr::add(uint card_idx, uint bits_per_card, uint max_cards_in_inline_ptr) { |
49 | assert(_value_addr != nullptr, "No value address available, cannot add to set.")do { if (!(_value_addr != nullptr)) { (*g_assert_poison) = 'X' ;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/gc/g1/g1CardSetContainers.inline.hpp" , 49, "assert(" "_value_addr != nullptr" ") failed", "No value address available, cannot add to set." ); ::breakpoint(); } } while (0); |
50 | |
51 | uint cur_idx = 0; |
52 | while (true) { |
53 | uint num_cards = num_cards_in(_value); |
54 | if (num_cards > 0) { |
55 | cur_idx = find(card_idx, bits_per_card, cur_idx, num_cards); |
56 | } |
57 | // Check if the card is already stored in the pointer. |
58 | if (cur_idx < num_cards) { |
59 | return Found; |
60 | } |
61 | // Check if there is actually enough space. |
62 | if (num_cards >= max_cards_in_inline_ptr) { |
63 | return Overflow; |
64 | } |
65 | CardSetPtr new_value = merge(_value, card_idx, num_cards, bits_per_card); |
66 | CardSetPtr old_value = Atomic::cmpxchg(_value_addr, _value, new_value, memory_order_relaxed); |
67 | if (_value == old_value) { |
68 | return Added; |
69 | } |
70 | // Update values and retry. |
71 | _value = old_value; |
72 | // The value of the pointer may have changed to something different than |
73 | // an inline card set. Exit then instead of overwriting. |
74 | if (G1CardSet::card_set_type(_value) != G1CardSet::CardSetInlinePtr) { |
75 | return Overflow; |
76 | } |
77 | } |
78 | } |
79 | |
80 | inline uint G1CardSetInlinePtr::find(uint card_idx, uint bits_per_card, uint start_at, uint num_cards) { |
81 | assert(start_at < num_cards, "Precondition!")do { if (!(start_at < num_cards)) { (*g_assert_poison) = 'X' ;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/gc/g1/g1CardSetContainers.inline.hpp" , 81, "assert(" "start_at < num_cards" ") failed", "Precondition!" ); ::breakpoint(); } } while (0); |
82 | |
83 | uintptr_t const card_mask = (1 << bits_per_card) - 1; |
84 | uintptr_t value = ((uintptr_t)_value) >> card_pos_for(start_at, bits_per_card); |
85 | |
86 | // Check if the card is already stored in the pointer. |
87 | for (uint cur_idx = start_at; cur_idx < num_cards; cur_idx++) { |
88 | if ((value & card_mask) == card_idx) { |
89 | return cur_idx; |
90 | } |
91 | value >>= bits_per_card; |
92 | } |
93 | return num_cards; |
94 | } |
95 | |
96 | inline bool G1CardSetInlinePtr::contains(uint card_idx, uint bits_per_card) { |
97 | uint num_cards = num_cards_in(_value); |
98 | if (num_cards == 0) { |
99 | return false; |
100 | } |
101 | uint cur_idx = find(card_idx, bits_per_card, 0, num_cards); |
102 | return cur_idx < num_cards; |
103 | } |
104 | |
105 | template <class CardVisitor> |
106 | inline void G1CardSetInlinePtr::iterate(CardVisitor& found, uint bits_per_card) { |
107 | uint const num_cards = num_cards_in(_value); |
108 | uintptr_t const card_mask = (1 << bits_per_card) - 1; |
109 | |
110 | uintptr_t value = ((uintptr_t)_value) >> card_pos_for(0, bits_per_card); |
111 | for (uint cur_idx = 0; cur_idx < num_cards; cur_idx++) { |
112 | found(value & card_mask); |
113 | value >>= bits_per_card; |
114 | } |
115 | } |
116 | |
117 | inline bool G1CardSetContainer::try_increment_refcount() { |
118 | uintptr_t old_value = refcount(); |
119 | while (true) { |
120 | if (old_value < 3 || (old_value & 0x1) == 0) { // reclaimed, reference counts are odd numbers starting at 3 |
121 | return false; // dead, can't revive. |
122 | } |
123 | |
124 | uintptr_t new_value = old_value + 2; |
125 | uintptr_t ref_count = Atomic::cmpxchg(&_ref_count, old_value, new_value); |
126 | if (ref_count == old_value) { |
127 | return true; |
128 | } |
129 | old_value = ref_count; |
130 | } |
131 | } |
132 | |
133 | inline uintptr_t G1CardSetContainer::decrement_refcount() { |
134 | uintptr_t old_value = refcount(); |
135 | assert((old_value & 0x1) != 0 && old_value >= 3, "precondition")do { if (!((old_value & 0x1) != 0 && old_value >= 3)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/gc/g1/g1CardSetContainers.inline.hpp" , 135, "assert(" "(old_value & 0x1) != 0 && old_value >= 3" ") failed", "precondition"); ::breakpoint(); } } while (0); |
136 | return Atomic::sub(&_ref_count, 2u); |
137 | } |
138 | |
139 | inline G1CardSetArray::G1CardSetArray(uint card_in_region, EntryCountType num_cards) : |
140 | G1CardSetContainer(), |
141 | _size(num_cards), |
142 | _num_entries(1) { |
143 | assert(_size > 0, "CardSetArray of size 0 not supported.")do { if (!(_size > 0)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/gc/g1/g1CardSetContainers.inline.hpp" , 143, "assert(" "_size > 0" ") failed", "CardSetArray of size 0 not supported." ); ::breakpoint(); } } while (0); |
144 | assert(_size < LockBitMask, "Only support CardSetArray of size %u or smaller.", LockBitMask - 1)do { if (!(_size < LockBitMask)) { (*g_assert_poison) = 'X' ;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/gc/g1/g1CardSetContainers.inline.hpp" , 144, "assert(" "_size < LockBitMask" ") failed", "Only support CardSetArray of size %u or smaller." , LockBitMask - 1); ::breakpoint(); } } while (0); |
145 | _data[0] = card_in_region; |
146 | } |
147 | |
148 | inline G1CardSetArray::G1CardSetArrayLocker::G1CardSetArrayLocker(EntryCountType volatile* num_entries_addr) : |
149 | _num_entries_addr(num_entries_addr) { |
150 | SpinYield s; |
151 | EntryCountType num_entries = Atomic::load(_num_entries_addr) & EntryMask; |
152 | while (true) { |
153 | EntryCountType old_value = Atomic::cmpxchg(_num_entries_addr, |
154 | num_entries, |
155 | (EntryCountType)(num_entries | LockBitMask)); |
156 | if (old_value == num_entries) { |
157 | // Succeeded locking the array. |
158 | _local_num_entries = num_entries; |
159 | break; |
160 | } |
161 | // Failed. Retry (with the lock bit stripped again). |
162 | num_entries = old_value & EntryMask; |
163 | s.wait(); |
164 | } |
165 | } |
166 | |
167 | inline G1AddCardResult G1CardSetArray::add(uint card_idx) { |
168 | assert(card_idx < (1u << (sizeof(_data[0]) * BitsPerByte)),do { if (!(card_idx < (1u << (sizeof(_data[0]) * BitsPerByte )))) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/gc/g1/g1CardSetContainers.inline.hpp" , 169, "assert(" "card_idx < (1u << (sizeof(_data[0]) * BitsPerByte))" ") failed", "Card index %u does not fit allowed card value range." , card_idx); ::breakpoint(); } } while (0) |
169 | "Card index %u does not fit allowed card value range.", card_idx)do { if (!(card_idx < (1u << (sizeof(_data[0]) * BitsPerByte )))) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/gc/g1/g1CardSetContainers.inline.hpp" , 169, "assert(" "card_idx < (1u << (sizeof(_data[0]) * BitsPerByte))" ") failed", "Card index %u does not fit allowed card value range." , card_idx); ::breakpoint(); } } while (0); |
170 | EntryCountType num_entries = Atomic::load_acquire(&_num_entries) & EntryMask; |
171 | EntryCountType idx = 0; |
172 | for (; idx < num_entries; idx++) { |
173 | if (_data[idx] == card_idx) { |
174 | return Found; |
175 | } |
176 | } |
177 | |
178 | // Since we did not find the card, lock. |
179 | G1CardSetArrayLocker x(&_num_entries); |
180 | |
181 | // Reload number of entries from the G1CardSetArrayLocker as it might have changed. |
182 | // It already read the actual value with the necessary synchronization. |
183 | num_entries = x.num_entries(); |
184 | // Look if the cards added while waiting for the lock are the same as our card. |
185 | for (; idx < num_entries; idx++) { |
186 | if (_data[idx] == card_idx) { |
187 | return Found; |
188 | } |
189 | } |
190 | |
191 | // Check if there is space left. |
192 | if (num_entries == _size) { |
193 | return Overflow; |
194 | } |
195 | |
196 | _data[num_entries] = card_idx; |
197 | |
198 | x.inc_num_entries(); |
199 | |
200 | return Added; |
201 | } |
202 | |
203 | inline bool G1CardSetArray::contains(uint card_idx) { |
204 | EntryCountType num_entries = Atomic::load_acquire(&_num_entries) & EntryMask; |
205 | |
206 | for (EntryCountType idx = 0; idx < num_entries; idx++) { |
207 | if (_data[idx] == card_idx) { |
208 | return true; |
209 | } |
210 | } |
211 | return false; |
212 | } |
213 | |
214 | template <class CardVisitor> |
215 | void G1CardSetArray::iterate(CardVisitor& found) { |
216 | EntryCountType num_entries = Atomic::load_acquire(&_num_entries) & EntryMask; |
217 | for (EntryCountType idx = 0; idx < num_entries; idx++) { |
218 | found(_data[idx]); |
219 | } |
220 | } |
221 | |
222 | inline G1CardSetBitMap::G1CardSetBitMap(uint card_in_region, uint size_in_bits) : |
223 | G1CardSetContainer(), _num_bits_set(1) { |
224 | assert(size_in_bits % (sizeof(_bits[0]) * BitsPerByte) == 0,do { if (!(size_in_bits % (sizeof(_bits[0]) * BitsPerByte) == 0)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/gc/g1/g1CardSetContainers.inline.hpp" , 225, "assert(" "size_in_bits % (sizeof(_bits[0]) * BitsPerByte) == 0" ") failed", "Size %u should be aligned to bitmap word size." , size_in_bits); ::breakpoint(); } } while (0) |
225 | "Size %u should be aligned to bitmap word size.", size_in_bits)do { if (!(size_in_bits % (sizeof(_bits[0]) * BitsPerByte) == 0)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/gc/g1/g1CardSetContainers.inline.hpp" , 225, "assert(" "size_in_bits % (sizeof(_bits[0]) * BitsPerByte) == 0" ") failed", "Size %u should be aligned to bitmap word size." , size_in_bits); ::breakpoint(); } } while (0); |
226 | BitMapView bm(_bits, size_in_bits); |
227 | bm.clear(); |
228 | bm.set_bit(card_in_region); |
229 | } |
230 | |
231 | inline G1AddCardResult G1CardSetBitMap::add(uint card_idx, size_t threshold, size_t size_in_bits) { |
232 | BitMapView bm(_bits, size_in_bits); |
233 | if (_num_bits_set >= threshold) { |
234 | return bm.at(card_idx) ? Found : Overflow; |
235 | } |
236 | if (bm.par_set_bit(card_idx)) { |
237 | Atomic::inc(&_num_bits_set, memory_order_relaxed); |
238 | return Added; |
239 | } |
240 | return Found; |
241 | } |
242 | |
243 | template <class CardVisitor> |
244 | inline void G1CardSetBitMap::iterate(CardVisitor& found, size_t size_in_bits, uint offset) { |
245 | BitMapView bm(_bits, size_in_bits); |
246 | BitMap::idx_t idx = bm.get_next_one_offset(0); |
247 | while (idx != size_in_bits) { |
248 | found((offset | (uint)idx)); |
249 | idx = bm.get_next_one_offset(idx + 1); |
250 | } |
251 | } |
252 | |
253 | inline G1CardSetHowl::G1CardSetHowl(EntryCountType card_in_region, G1CardSetConfiguration* config) : |
254 | G1CardSetContainer(), |
255 | _num_entries((config->max_cards_in_array() + 1)) /* Card Transfer will not increment _num_entries */ { |
256 | EntryCountType num_buckets = config->num_buckets_in_howl(); |
257 | EntryCountType bucket = config->howl_bucket_index(card_in_region); |
258 | for (uint i = 0; i < num_buckets; ++i) { |
259 | _buckets[i] = G1CardSetInlinePtr(); |
260 | if (i == bucket) { |
261 | G1CardSetInlinePtr value(&_buckets[i], _buckets[i]); |
262 | value.add(card_in_region, config->inline_ptr_bits_per_card(), config->max_cards_in_inline_ptr()); |
263 | } |
264 | } |
265 | } |
266 | |
267 | inline bool G1CardSetHowl::contains(uint card_idx, G1CardSetConfiguration* config) { |
268 | EntryCountType bucket = config->howl_bucket_index(card_idx); |
269 | CardSetPtr* array_entry = get_card_set_addr(bucket); |
270 | CardSetPtr card_set = Atomic::load_acquire(array_entry); |
271 | |
272 | switch (G1CardSet::card_set_type(card_set)) { |
273 | case G1CardSet::CardSetArrayOfCards : { |
274 | return G1CardSet::card_set_ptr<G1CardSetArray>(card_set)->contains(card_idx); |
275 | } |
276 | case G1CardSet::CardSetBitMap: { |
277 | uint card_offset = config->howl_bitmap_offset(card_idx); |
278 | return G1CardSet::card_set_ptr<G1CardSetBitMap>(card_set)->contains(card_offset, config->max_cards_in_howl_bitmap()); |
279 | } |
280 | case G1CardSet::CardSetInlinePtr: { |
281 | G1CardSetInlinePtr ptr(card_set); |
282 | return ptr.contains(card_idx, config->inline_ptr_bits_per_card()); |
283 | } |
284 | case G1CardSet::CardSetHowl: {// Fullcard set entry |
285 | assert(card_set == G1CardSet::FullCardSet, "Must be")do { if (!(card_set == G1CardSet::FullCardSet)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/gc/g1/g1CardSetContainers.inline.hpp" , 285, "assert(" "card_set == G1CardSet::FullCardSet" ") failed" , "Must be"); ::breakpoint(); } } while (0); |
286 | return true; |
287 | } |
288 | } |
289 | return false; |
290 | } |
291 | |
292 | template <class CardOrRangeVisitor> |
293 | inline void G1CardSetHowl::iterate(CardOrRangeVisitor& found, G1CardSetConfiguration* config) { |
294 | for (uint i = 0; i < config->num_buckets_in_howl(); ++i) { |
295 | iterate_cardset(_buckets[i], i, found, config); |
296 | } |
297 | } |
298 | |
299 | template <class CardSetPtrVisitor> |
300 | inline void G1CardSetHowl::iterate(CardSetPtrVisitor& found, uint num_card_sets) { |
301 | for (uint i = 0; i < num_card_sets; ++i) { |
302 | found(&_buckets[i]); |
303 | } |
304 | } |
305 | |
306 | template <class CardOrRangeVisitor> |
307 | inline void G1CardSetHowl::iterate_cardset(CardSetPtr const card_set, uint index, CardOrRangeVisitor& found, G1CardSetConfiguration* config) { |
308 | switch (G1CardSet::card_set_type(card_set)) { |
309 | case G1CardSet::CardSetInlinePtr: { |
310 | if (found.start_iterate(G1GCPhaseTimes::MergeRSHowlInline)) { |
311 | G1CardSetInlinePtr ptr(card_set); |
312 | ptr.iterate(found, config->inline_ptr_bits_per_card()); |
313 | } |
314 | return; |
315 | } |
316 | case G1CardSet::CardSetArrayOfCards : { |
317 | if (found.start_iterate(G1GCPhaseTimes::MergeRSHowlArrayOfCards)) { |
318 | G1CardSet::card_set_ptr<G1CardSetArray>(card_set)->iterate(found); |
319 | } |
320 | return; |
321 | } |
322 | case G1CardSet::CardSetBitMap: { |
323 | if (found.start_iterate(G1GCPhaseTimes::MergeRSHowlBitmap)) { |
324 | uint offset = index << config->log2_max_cards_in_howl_bitmap(); |
325 | G1CardSet::card_set_ptr<G1CardSetBitMap>(card_set)->iterate(found, config->max_cards_in_howl_bitmap(), offset); |
326 | } |
327 | return; |
328 | } |
329 | case G1CardSet::CardSetHowl: { // actually FullCardSet |
330 | assert(card_set == G1CardSet::FullCardSet, "Must be")do { if (!(card_set == G1CardSet::FullCardSet)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/gc/g1/g1CardSetContainers.inline.hpp" , 330, "assert(" "card_set == G1CardSet::FullCardSet" ") failed" , "Must be"); ::breakpoint(); } } while (0); |
331 | if (found.start_iterate(G1GCPhaseTimes::MergeRSHowlFull)) { |
332 | uint offset = index << config->log2_max_cards_in_howl_bitmap(); |
333 | found(offset, config->max_cards_in_howl_bitmap()); |
334 | } |
335 | return; |
336 | } |
337 | } |
338 | } |
339 | |
340 | inline G1CardSetHowl::EntryCountType G1CardSetHowl::num_buckets(size_t size_in_bits, size_t max_cards_in_array, size_t max_num_buckets) { |
341 | size_t size_bitmap_bytes = BitMap::calc_size_in_words(size_in_bits) * BytesPerWord; |
342 | // Ensure that in the worst case arrays consume half the memory size |
343 | // of storing the entire bitmap |
344 | size_t max_size_arrays_bytes = size_bitmap_bytes / 2; |
345 | size_t size_array_bytes = max_cards_in_array * sizeof(G1CardSetArray::EntryDataType); |
346 | size_t num_arrays = max_size_arrays_bytes / size_array_bytes; |
347 | // We use shifts and masks for indexing the array. So round down to the next |
348 | // power of two to not use more than expected memory. |
349 | num_arrays = round_down_power_of_2(MAX2((size_t)1, MIN2(num_arrays, max_num_buckets))); |
350 | return (EntryCountType)num_arrays; |
351 | } |
352 | |
353 | #endif // SHARE_GC_G1_G1CARDSETCONTAINERS_INLINE_HPP |