1 /*
2 * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved.
3 * Copyright (c) 2013, 2020, Red Hat, Inc. All rights reserved.
4 * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
5 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 *
7 * This code is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License version 2 only, as
9 * published by the Free Software Foundation.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 *
25 */
26
27 #include "gc/shared/cardTable.hpp"
28 #include "gc/shared/space.hpp"
29 #include "gc/shared/tlab_globals.hpp"
30 #include "gc/shenandoah/shenandoahCardTable.hpp"
31 #include "gc/shenandoah/shenandoahFreeSet.hpp"
32 #include "gc/shenandoah/shenandoahGeneration.hpp"
33 #include "gc/shenandoah/shenandoahHeap.inline.hpp"
34 #include "gc/shenandoah/shenandoahHeapRegion.hpp"
35 #include "gc/shenandoah/shenandoahHeapRegionSet.inline.hpp"
36 #include "gc/shenandoah/shenandoahMarkingContext.inline.hpp"
37 #include "gc/shenandoah/shenandoahOldGeneration.hpp"
38 #include "gc/shenandoah/shenandoahScanRemembered.inline.hpp"
39 #include "gc/shenandoah/shenandoahYoungGeneration.hpp"
40 #include "jfr/jfrEvents.hpp"
41 #include "memory/allocation.hpp"
42 #include "memory/iterator.inline.hpp"
43 #include "memory/resourceArea.hpp"
44 #include "memory/universe.hpp"
45 #include "oops/oop.inline.hpp"
46 #include "runtime/globals_extension.hpp"
47 #include "runtime/java.hpp"
48 #include "runtime/mutexLocker.hpp"
49 #include "runtime/os.hpp"
50 #include "runtime/safepoint.hpp"
51 #include "utilities/powerOfTwo.hpp"
52
53 size_t ShenandoahHeapRegion::RegionCount = 0;
54 size_t ShenandoahHeapRegion::RegionSizeBytes = 0;
55 size_t ShenandoahHeapRegion::RegionSizeWords = 0;
56 size_t ShenandoahHeapRegion::RegionSizeBytesShift = 0;
57 size_t ShenandoahHeapRegion::RegionSizeWordsShift = 0;
58 size_t ShenandoahHeapRegion::RegionSizeBytesMask = 0;
59 size_t ShenandoahHeapRegion::RegionSizeWordsMask = 0;
60 size_t ShenandoahHeapRegion::MaxTLABSizeBytes = 0;
61 size_t ShenandoahHeapRegion::MaxTLABSizeWords = 0;
62
63 ShenandoahHeapRegion::ShenandoahHeapRegion(HeapWord* start, size_t index, bool committed) :
64 _index(index),
65 _bottom(start),
66 _end(start + RegionSizeWords),
67 _new_top(nullptr),
68 _empty_time(os::elapsedTime()),
69 _top_before_promoted(nullptr),
70 _top_at_evac_start(start),
71 _state(committed ? _empty_committed : _empty_uncommitted),
72 _top(start),
73 _tlab_allocs(0),
74 _gclab_allocs(0),
75 _plab_allocs(0),
76 _live_data(0),
77 _critical_pins(0),
78 _mixed_candidate_garbage_words(0),
79 _update_watermark(start),
80 _age(0),
81 #ifdef SHENANDOAH_CENSUS_NOISE
82 _youth(0),
83 #endif // SHENANDOAH_CENSUS_NOISE
84 _needs_bitmap_reset(false)
85 {
86
87 assert(Universe::on_page_boundary(_bottom) && Universe::on_page_boundary(_end),
88 "invalid space boundaries");
89 if (ZapUnusedHeapArea && committed) {
90 SpaceMangler::mangle_region(MemRegion(_bottom, _end));
91 }
92 _recycling.unset();
93 _has_self_forwards.unset();
94 }
95
96 void ShenandoahHeapRegion::report_illegal_transition(const char *method) {
97 stringStream ss;
98 ss.print("Illegal region state transition from \"%s\", at %s\n ", region_state_to_string(state()), method);
99 print_on(&ss);
100 fatal("%s", ss.freeze());
101 }
102
103 void ShenandoahHeapRegion::make_regular_allocation(ShenandoahAffiliation affiliation) {
104 shenandoah_assert_heaplocked();
105 reset_age();
106 switch (state()) {
107 case _empty_uncommitted:
108 do_commit();
109 case _empty_committed:
110 assert(this->affiliation() == affiliation, "Region affiliation should already be established");
111 set_state(_regular);
112 case _regular:
113 case _pinned:
114 return;
115 default:
116 report_illegal_transition("regular allocation");
117 }
118 }
119
120 // Change affiliation to YOUNG_GENERATION if _state is not _pinned_cset, _regular, or _pinned. This implements
121 // behavior previously performed as a side effect of make_regular_bypass(). This is used by Full GC in non-generational
122 // modes to transition regions from FREE. Note that all non-free regions in single-generational modes are young.
123 void ShenandoahHeapRegion::make_affiliated_maybe() {
124 shenandoah_assert_heaplocked();
125 assert(!ShenandoahHeap::heap()->mode()->is_generational(), "Only call if non-generational");
126 switch (state()) {
127 case _empty_uncommitted:
128 case _empty_committed:
129 case _cset:
130 case _humongous_start:
131 case _humongous_cont:
132 if (affiliation() != YOUNG_GENERATION) {
133 set_affiliation(YOUNG_GENERATION);
134 }
135 return;
136 case _pinned_cset:
137 case _regular:
138 case _pinned:
139 return;
140 default:
141 assert(false, "Unexpected _state in make_affiliated_maybe");
142 }
143 }
144
145 void ShenandoahHeapRegion::make_regular_bypass() {
146 shenandoah_assert_heaplocked();
147 assert (ShenandoahHeap::heap()->is_full_gc_in_progress() ||
148 ShenandoahHeap::heap()->is_degenerated_gc_in_progress(),
149 "Only for STW GC");
150 reset_age();
151 switch (state()) {
152 case _empty_uncommitted:
153 do_commit();
154 case _empty_committed:
155 case _cset:
156 case _humongous_start:
157 case _humongous_cont:
158 set_state(_regular);
159 return;
160 case _pinned_cset:
161 set_state(_pinned);
162 return;
163 case _regular:
164 case _pinned:
165 return;
166 default:
167 report_illegal_transition("regular bypass");
168 }
169 }
170
171 void ShenandoahHeapRegion::make_humongous_start() {
172 shenandoah_assert_heaplocked();
173 reset_age();
174 switch (state()) {
175 case _empty_uncommitted:
176 do_commit();
177 case _empty_committed:
178 set_state(_humongous_start);
179 return;
180 default:
181 report_illegal_transition("humongous start allocation");
182 }
183 }
184
185 void ShenandoahHeapRegion::make_humongous_start_bypass(ShenandoahAffiliation affiliation) {
186 shenandoah_assert_heaplocked();
187 assert (ShenandoahHeap::heap()->is_full_gc_in_progress(), "only for full GC");
188 // Don't bother to account for affiliated regions during Full GC. We recompute totals at end.
189 set_affiliation(affiliation);
190 reset_age();
191 switch (state()) {
192 case _empty_committed:
193 case _regular:
194 case _humongous_start:
195 case _humongous_cont:
196 set_state(_humongous_start);
197 return;
198 default:
199 report_illegal_transition("humongous start bypass");
200 }
201 }
202
203 void ShenandoahHeapRegion::make_humongous_cont() {
204 shenandoah_assert_heaplocked();
205 reset_age();
206 switch (state()) {
207 case _empty_uncommitted:
208 do_commit();
209 case _empty_committed:
210 set_state(_humongous_cont);
211 return;
212 default:
213 report_illegal_transition("humongous continuation allocation");
214 }
215 }
216
217 void ShenandoahHeapRegion::make_humongous_cont_bypass(ShenandoahAffiliation affiliation) {
218 shenandoah_assert_heaplocked();
219 assert (ShenandoahHeap::heap()->is_full_gc_in_progress(), "only for full GC");
220 set_affiliation(affiliation);
221 // Don't bother to account for affiliated regions during Full GC. We recompute totals at end.
222 reset_age();
223 switch (state()) {
224 case _empty_committed:
225 case _regular:
226 case _humongous_start:
227 case _humongous_cont:
228 set_state(_humongous_cont);
229 return;
230 default:
231 report_illegal_transition("humongous continuation bypass");
232 }
233 }
234
235 void ShenandoahHeapRegion::make_pinned() {
236 shenandoah_assert_heaplocked();
237 assert(pin_count() > 0, "Should have pins: %zu", pin_count());
238
239 switch (state()) {
240 case _regular:
241 set_state(_pinned);
242 case _pinned_cset:
243 case _pinned:
244 return;
245 case _humongous_start:
246 set_state(_pinned_humongous_start);
247 case _pinned_humongous_start:
248 return;
249 case _cset:
250 set_state(_pinned_cset);
251 return;
252 default:
253 report_illegal_transition("pinning");
254 }
255 }
256
257 void ShenandoahHeapRegion::make_unpinned() {
258 shenandoah_assert_heaplocked();
259 assert(pin_count() == 0, "Should not have pins: %zu", pin_count());
260
261 switch (state()) {
262 case _pinned:
263 assert(is_affiliated(), "Pinned region should be affiliated");
264 set_state(_regular);
265 return;
266 case _regular:
267 case _humongous_start:
268 return;
269 case _pinned_cset:
270 set_state(_cset);
271 return;
272 case _pinned_humongous_start:
273 set_state(_humongous_start);
274 return;
275 default:
276 report_illegal_transition("unpinning");
277 }
278 }
279
280 void ShenandoahHeapRegion::make_cset() {
281 shenandoah_assert_heaplocked();
282 // Leave age untouched. We need to consult the age when we are deciding whether to promote evacuated objects.
283 switch (state()) {
284 case _regular:
285 set_state(_cset);
286 case _cset:
287 return;
288 default:
289 report_illegal_transition("cset");
290 }
291 }
292
293 void ShenandoahHeapRegion::make_trash() {
294 shenandoah_assert_heaplocked();
295 reset_age();
296 switch (state()) {
297 case _humongous_start:
298 case _humongous_cont:
299 {
300 // Reclaiming humongous regions and reclaim humongous waste. When this region is eventually recycled, we'll reclaim
301 // its used memory. At recycle time, we no longer recognize this as a humongous region.
302 decrement_humongous_waste();
303 }
304 case _cset:
305 // Reclaiming cset regions
306 case _regular:
307 // Immediate region reclaim
308 set_state(_trash);
309 return;
310 default:
311 report_illegal_transition("trashing");
312 }
313 }
314
315 void ShenandoahHeapRegion::make_trash_immediate() {
316 make_trash();
317
318 // On this path, we know there are no marked objects in the region,
319 // tell marking context about it to bypass bitmap resets.
320 const ShenandoahHeap* heap = ShenandoahHeap::heap();
321 assert(heap->generation_for(affiliation())->is_mark_complete(), "Marking should be complete here.");
322 heap->marking_context()->reset_top_bitmap(this);
323 }
324
325 void ShenandoahHeapRegion::make_empty() {
326 reset_age();
327 CENSUS_NOISE(clear_youth();)
328 switch (state()) {
329 case _trash:
330 set_state(_empty_committed);
331 _empty_time = os::elapsedTime();
332 return;
333 default:
334 report_illegal_transition("emptying");
335 }
336 }
337
338 void ShenandoahHeapRegion::make_uncommitted() {
339 shenandoah_assert_heaplocked();
340 switch (state()) {
341 case _empty_committed:
342 do_uncommit();
343 set_state(_empty_uncommitted);
344 return;
345 default:
346 report_illegal_transition("uncommiting");
347 }
348 }
349
350 void ShenandoahHeapRegion::make_committed_bypass() {
351 shenandoah_assert_heaplocked();
352 assert (ShenandoahHeap::heap()->is_full_gc_in_progress(), "only for full GC");
353
354 switch (state()) {
355 case _empty_uncommitted:
356 do_commit();
357 set_state(_empty_committed);
358 return;
359 default:
360 report_illegal_transition("commit bypass");
361 }
362 }
363
364 void ShenandoahHeapRegion::reset_alloc_metadata() {
365 _tlab_allocs = 0;
366 _gclab_allocs = 0;
367 _plab_allocs = 0;
368 }
369
370 size_t ShenandoahHeapRegion::get_shared_allocs() const {
371 return used() - (_tlab_allocs + _gclab_allocs + _plab_allocs) * HeapWordSize;
372 }
373
374 size_t ShenandoahHeapRegion::get_tlab_allocs() const {
375 return _tlab_allocs * HeapWordSize;
376 }
377
378 size_t ShenandoahHeapRegion::get_gclab_allocs() const {
379 return _gclab_allocs * HeapWordSize;
380 }
381
382 size_t ShenandoahHeapRegion::get_plab_allocs() const {
383 return _plab_allocs * HeapWordSize;
384 }
385
386 void ShenandoahHeapRegion::set_live_data(size_t s) {
387 assert(Thread::current()->is_VM_thread(), "by VM thread");
388 _live_data.store_relaxed(s >> LogHeapWordSize);
389 }
390
391 void ShenandoahHeapRegion::print_on(outputStream* st) const {
392 st->print("|");
393 st->print("%5zu", this->_index);
394
395 switch (state()) {
396 case _empty_uncommitted:
397 st->print("|EU ");
398 break;
399 case _empty_committed:
400 st->print("|EC ");
401 break;
402 case _regular:
403 st->print("|R ");
404 break;
405 case _humongous_start:
406 st->print("|H ");
407 break;
408 case _pinned_humongous_start:
409 st->print("|HP ");
410 break;
411 case _humongous_cont:
412 st->print("|HC ");
413 break;
414 case _cset:
415 st->print("|CS ");
416 break;
417 case _trash:
418 st->print("|TR ");
419 break;
420 case _pinned:
421 st->print("|P ");
422 break;
423 case _pinned_cset:
424 st->print("|CSP");
425 break;
426 default:
427 ShouldNotReachHere();
428 }
429
430 st->print("|%s", shenandoah_affiliation_code(affiliation()));
431
432 #define SHR_PTR_FORMAT "%12" PRIxPTR
433
434 st->print("|BTE " SHR_PTR_FORMAT ", " SHR_PTR_FORMAT ", " SHR_PTR_FORMAT,
435 p2i(bottom()), p2i(top()), p2i(end()));
436 st->print("|TAMS " SHR_PTR_FORMAT,
437 p2i(ShenandoahHeap::heap()->marking_context()->top_at_mark_start(const_cast<ShenandoahHeapRegion*>(this))));
438 st->print("|UWM " SHR_PTR_FORMAT,
439 p2i(_update_watermark.load_relaxed()));
440 st->print("|U %5zu%1s", byte_size_in_proper_unit(used()), proper_unit_for_byte_size(used()));
441 st->print("|T %5zu%1s", byte_size_in_proper_unit(get_tlab_allocs()), proper_unit_for_byte_size(get_tlab_allocs()));
442 st->print("|G %5zu%1s", byte_size_in_proper_unit(get_gclab_allocs()), proper_unit_for_byte_size(get_gclab_allocs()));
443 if (ShenandoahHeap::heap()->mode()->is_generational()) {
444 st->print("|P %5zu%1s", byte_size_in_proper_unit(get_plab_allocs()), proper_unit_for_byte_size(get_plab_allocs()));
445 }
446 st->print("|S %5zu%1s", byte_size_in_proper_unit(get_shared_allocs()), proper_unit_for_byte_size(get_shared_allocs()));
447 st->print("|L %5zu%1s", byte_size_in_proper_unit(get_live_data_bytes()), proper_unit_for_byte_size(get_live_data_bytes()));
448 st->print("|CP %3zu", pin_count());
449 st->cr();
450
451 #undef SHR_PTR_FORMAT
452 }
453
454 // oop_iterate without closure, return true if completed without cancellation
455 bool ShenandoahHeapRegion::oop_coalesce_and_fill(bool cancellable) {
456
457 assert(!is_humongous(), "No need to fill or coalesce humongous regions");
458 if (!is_active()) {
459 end_preemptible_coalesce_and_fill();
460 return true;
461 }
462
463 ShenandoahGenerationalHeap* heap = ShenandoahGenerationalHeap::heap();
464 ShenandoahMarkingContext* marking_context = heap->marking_context();
465
466 // Expect marking to be completed for the old generation before we fill in unmarked objects
467 assert(heap->old_generation()->is_mark_complete(), "sanity");
468 assert(is_old(), "Only need to coalesce and fill old regions");
469
470 // All objects above TAMS are considered live even though their mark bits will not be set. Note that young-
471 // gen evacuations that interrupt a long-running old-gen concurrent mark may promote objects into old-gen
472 // while the old-gen concurrent marking is ongoing. These newly promoted objects will reside above TAMS
473 // and will be treated as live during the current old-gen marking pass, even though they will not be
474 // explicitly marked.
475 HeapWord* t = marking_context->top_at_mark_start(this);
476
477 // Resume coalesce and fill from this address
478 HeapWord* obj_addr = resume_coalesce_and_fill();
479
480 while (obj_addr < t) {
481 oop obj = cast_to_oop(obj_addr);
482 if (marking_context->is_marked(obj)) {
483 assert(obj->klass() != nullptr, "klass should not be nullptr");
484 obj_addr += obj->size();
485 } else {
486 // Object is not marked. Coalesce and fill dead object with dead neighbors.
487 HeapWord* next_marked_obj = marking_context->get_next_marked_addr(obj_addr, t);
488 assert(next_marked_obj <= t, "next marked object cannot exceed top");
489 size_t fill_size = next_marked_obj - obj_addr;
490 assert(fill_size >= ShenandoahHeap::min_fill_size(), "previously allocated object known to be larger than min_size");
491 ShenandoahHeap::fill_with_object(obj_addr, fill_size);
492 heap->old_generation()->card_scan()->coalesce_objects(obj_addr, fill_size);
493 obj_addr = next_marked_obj;
494 }
495 if (cancellable && heap->cancelled_gc()) {
496 suspend_coalesce_and_fill(obj_addr);
497 return false;
498 }
499 }
500 // Mark that this region has been coalesced and filled
501 end_preemptible_coalesce_and_fill();
502 return true;
503 }
504
505 size_t get_card_count(size_t words) {
506 assert(words % CardTable::card_size_in_words() == 0, "Humongous iteration must span whole number of cards");
507 assert(CardTable::card_size_in_words() * (words / CardTable::card_size_in_words()) == words,
508 "slice must be integral number of cards");
509 return words / CardTable::card_size_in_words();
510 }
511
512 void ShenandoahHeapRegion::oop_iterate_humongous_slice_dirty(OopIterateClosure* blk,
513 HeapWord* start, size_t words, bool write_table) const {
514 assert(is_humongous(), "only humongous region here");
515
516 ShenandoahHeapRegion* r = humongous_start_region();
517 oop obj = cast_to_oop(r->bottom());
518 size_t num_cards = get_card_count(words);
519
520 ShenandoahGenerationalHeap* heap = ShenandoahGenerationalHeap::heap();
521 ShenandoahScanRemembered* scanner = heap->old_generation()->card_scan();
522 size_t card_index = scanner->card_index_for_addr(start);
523 if (write_table) {
524 while (num_cards-- > 0) {
525 if (scanner->is_write_card_dirty(card_index++)) {
526 obj->oop_iterate(blk, MemRegion(start, start + CardTable::card_size_in_words()));
527 }
528 start += CardTable::card_size_in_words();
529 }
530 } else {
531 while (num_cards-- > 0) {
532 if (scanner->is_card_dirty(card_index++)) {
533 obj->oop_iterate(blk, MemRegion(start, start + CardTable::card_size_in_words()));
534 }
535 start += CardTable::card_size_in_words();
536 }
537 }
538 }
539
540 void ShenandoahHeapRegion::oop_iterate_humongous_slice_all(OopIterateClosure* cl, HeapWord* start, size_t words) const {
541 assert(is_humongous(), "only humongous region here");
542
543 ShenandoahHeapRegion* r = humongous_start_region();
544 oop obj = cast_to_oop(r->bottom());
545
546 // Scan all data, regardless of whether cards are dirty
547 obj->oop_iterate(cl, MemRegion(start, start + words));
548 }
549
550 ShenandoahHeapRegion* ShenandoahHeapRegion::humongous_start_region() const {
551 ShenandoahHeap* heap = ShenandoahHeap::heap();
552 assert(is_humongous(), "Must be a part of the humongous region");
553 size_t i = index();
554 ShenandoahHeapRegion* r = const_cast<ShenandoahHeapRegion*>(this);
555 while (!r->is_humongous_start()) {
556 assert(i > 0, "Sanity");
557 i--;
558 r = heap->get_region(i);
559 assert(r->is_humongous(), "Must be a part of the humongous region");
560 }
561 assert(r->is_humongous_start(), "Must be");
562 return r;
563 }
564
565
566 void ShenandoahHeapRegion::recycle_internal() {
567 assert(_recycling.is_set() && is_trash(), "Wrong state");
568 ShenandoahHeap* heap = ShenandoahHeap::heap();
569
570 _top_at_evac_start = _bottom;
571 _mixed_candidate_garbage_words = 0;
572 clear_live_data();
573 reset_alloc_metadata();
574 heap->marking_context()->reset_top_at_mark_start(this);
575 set_update_watermark(bottom());
576 clear_has_self_forwards();
577 if (is_old()) {
578 heap->old_generation()->clear_cards_for(this);
579 }
580
581 if (ZapUnusedHeapArea) {
582 SpaceMangler::mangle_region(MemRegion(bottom(), top()));
583 }
584 set_top(bottom());
585 set_affiliation(FREE);
586
587 // Lastly, set region state to empty
588 make_empty();
589 }
590
591 // Upon return, this region has been recycled. We try to recycle it.
592 // We may fail if some other thread recycled it before we do.
593 void ShenandoahHeapRegion::try_recycle_under_lock() {
594 shenandoah_assert_heaplocked();
595 if (!is_trash()) {
596 return;
597 }
598 if (_recycling.try_set()) {
599 if (is_trash()) {
600 // At freeset rebuild time, which precedes recycling of collection set, we treat all cset regions as
601 // part of capacity, as empty, as fully available, and as unaffiliated. This provides short-lived optimism
602 // for triggering heuristics. It greatly simplifies and reduces the locking overhead required
603 // by more time-precise accounting of these details.
604 recycle_internal();
605 }
606 _recycling.unset();
607 } else {
608 // Ensure recycling is unset before returning to mutator to continue memory allocation.
609 // Otherwise, the mutator might see region as fully recycled and might change its affiliation only to have
610 // the racing GC worker thread overwrite its affiliation to FREE.
611 while (_recycling.is_set()) {
612 if (os::is_MP()) {
613 SpinPause();
614 } else {
615 os::naked_yield();
616 }
617 }
618 assert(!is_trash(), "Must not");
619 }
620 }
621
622 // Note that return from try_recycle() does not mean the region has been recycled. It only means that
623 // some GC worker thread has taken responsibility to recycle the region, eventually.
624 void ShenandoahHeapRegion::try_recycle() {
625 shenandoah_assert_not_heaplocked();
626 if (!is_trash()) {
627 return;
628 }
629 if (_recycling.try_set()) {
630 // Double check region state after win the race to set recycling flag
631 if (is_trash()) {
632 // At freeset rebuild time, which precedes recycling of collection set, we treat all cset regions as
633 // part of capacity, as empty, as fully available, and as unaffiliated. This provides short-lived optimism
634 // for triggering and pacing heuristics. It greatly simplifies and reduces the locking overhead required
635 // by more time-precise accounting of these details.
636 recycle_internal();
637 }
638 _recycling.unset();
639 }
640 }
641
642 HeapWord* ShenandoahHeapRegion::block_start(const void* p) const {
643 assert(MemRegion(bottom(), end()).contains(p),
644 "p (" PTR_FORMAT ") not in space [" PTR_FORMAT ", " PTR_FORMAT ")",
645 p2i(p), p2i(bottom()), p2i(end()));
646 if (p >= top()) {
647 return top();
648 } else {
649 HeapWord* last = bottom();
650 HeapWord* cur = last;
651 while (cur <= p) {
652 last = cur;
653 cur += cast_to_oop(cur)->size();
654 }
655 shenandoah_assert_correct(nullptr, cast_to_oop(last));
656 return last;
657 }
658 }
659
660 size_t ShenandoahHeapRegion::block_size(const HeapWord* p) const {
661 assert(MemRegion(bottom(), end()).contains(p),
662 "p (" PTR_FORMAT ") not in space [" PTR_FORMAT ", " PTR_FORMAT ")",
663 p2i(p), p2i(bottom()), p2i(end()));
664 if (p < top()) {
665 return cast_to_oop(p)->size();
666 } else {
667 assert(p == top(), "just checking");
668 return pointer_delta(end(), (HeapWord*) p);
669 }
670 }
671
672 size_t ShenandoahHeapRegion::setup_sizes(size_t max_heap_size) {
673 // Generational Shenandoah needs this alignment for card tables.
674 if (strcmp(ShenandoahGCMode, "generational") == 0) {
675 max_heap_size = align_up(max_heap_size , CardTable::ct_max_alignment_constraint());
676 }
677
678 size_t region_size;
679 if (FLAG_IS_DEFAULT(ShenandoahRegionSize)) {
680 // We rapidly expand to max_heap_size in most scenarios, so that is the measure
681 // for usual heap sizes. Do not depend on initial_heap_size here.
682 region_size = max_heap_size / ShenandoahTargetNumRegions;
683
684 // Now make sure that we don't go over or under our limits.
685 region_size = MAX2(MIN_REGION_SIZE, region_size);
686 region_size = MIN2(MAX_REGION_SIZE, region_size);
687 } else {
688 if (ShenandoahRegionSize > max_heap_size / MIN_NUM_REGIONS) {
689 err_msg message("Max heap size (%zu%s) is too low to afford the minimum number "
690 "of regions (%zu) of requested size (%zu%s).",
691 byte_size_in_proper_unit(max_heap_size), proper_unit_for_byte_size(max_heap_size),
692 MIN_NUM_REGIONS,
693 byte_size_in_proper_unit(ShenandoahRegionSize), proper_unit_for_byte_size(ShenandoahRegionSize));
694 vm_exit_during_initialization("Invalid -XX:ShenandoahRegionSize option", message);
695 }
696 if (ShenandoahRegionSize < MIN_REGION_SIZE) {
697 err_msg message("Heap region size (%zu%s) should be larger than min region size (%zu%s).",
698 byte_size_in_proper_unit(ShenandoahRegionSize), proper_unit_for_byte_size(ShenandoahRegionSize),
699 byte_size_in_proper_unit(MIN_REGION_SIZE), proper_unit_for_byte_size(MIN_REGION_SIZE));
700 vm_exit_during_initialization("Invalid -XX:ShenandoahRegionSize option", message);
701 }
702 if (ShenandoahRegionSize > MAX_REGION_SIZE) {
703 err_msg message("Heap region size (%zu%s) should be lower than max region size (%zu%s).",
704 byte_size_in_proper_unit(ShenandoahRegionSize), proper_unit_for_byte_size(ShenandoahRegionSize),
705 byte_size_in_proper_unit(MAX_REGION_SIZE), proper_unit_for_byte_size(MAX_REGION_SIZE));
706 vm_exit_during_initialization("Invalid -XX:ShenandoahRegionSize option", message);
707 }
708 region_size = ShenandoahRegionSize;
709 }
710
711 // Make sure region size and heap size are page aligned.
712 // If large pages are used, we ensure that region size is aligned to large page size if
713 // heap size is large enough to accommodate minimal number of regions. Otherwise, we align
714 // region size to regular page size.
715
716 // Figure out page size to use, and aligns up heap to page size
717 size_t page_size = os::vm_page_size();
718 if (UseLargePages) {
719 size_t large_page_size = os::large_page_size();
720 max_heap_size = align_up(max_heap_size, large_page_size);
721 if ((max_heap_size / align_up(region_size, large_page_size)) >= MIN_NUM_REGIONS) {
722 page_size = large_page_size;
723 } else {
724 // Should have been checked during argument initialization
725 assert(!ShenandoahUncommit, "Uncommit requires region size aligns to large page size");
726 }
727 } else {
728 max_heap_size = align_up(max_heap_size, page_size);
729 }
730
731 // Align region size to page size
732 region_size = align_up(region_size, page_size);
733
734 int region_size_log = log2i(region_size);
735 // Recalculate the region size to make sure it's a power of
736 // 2. This means that region_size is the largest power of 2 that's
737 // <= what we've calculated so far.
738 region_size = size_t(1) << region_size_log;
739
740 // Now, set up the globals.
741 guarantee(RegionSizeBytesShift == 0, "we should only set it once");
742 RegionSizeBytesShift = (size_t)region_size_log;
743
744 guarantee(RegionSizeWordsShift == 0, "we should only set it once");
745 RegionSizeWordsShift = RegionSizeBytesShift - LogHeapWordSize;
746
747 guarantee(RegionSizeBytes == 0, "we should only set it once");
748 RegionSizeBytes = region_size;
749 RegionSizeWords = RegionSizeBytes >> LogHeapWordSize;
750 assert (RegionSizeWords*HeapWordSize == RegionSizeBytes, "sanity");
751
752 guarantee(RegionSizeWordsMask == 0, "we should only set it once");
753 RegionSizeWordsMask = RegionSizeWords - 1;
754
755 guarantee(RegionSizeBytesMask == 0, "we should only set it once");
756 RegionSizeBytesMask = RegionSizeBytes - 1;
757
758 guarantee(RegionCount == 0, "we should only set it once");
759 RegionCount = align_up(max_heap_size, RegionSizeBytes) / RegionSizeBytes;
760 guarantee(RegionCount >= MIN_NUM_REGIONS, "Should have at least minimum regions");
761
762 // Limit TLAB size for better startup behavior and more equitable distribution of memory between contending mutator threads.
763 guarantee(MaxTLABSizeWords == 0, "we should only set it once");
764 // With compact object headers an object may grow by one word when an identity
765 // hash-code is injected during a GC copy. Never let the max TLAB equal a whole
766 // region: a region-sized TLAB could serve a region-sized object (bypassing the
767 // humongous path) and would itself be a region-sized LAB allocation request. Cap
768 // it one (object-aligned) word below the region so neither can happen.
769 size_t max_tlab_words = MIN2(RegionSizeWords, MAX2(RegionSizeWords / 32, (size_t) (256 * 1024) / HeapWordSize));
770 if (UseCompactObjectHeaders) {
771 max_tlab_words = MIN2(max_tlab_words, RegionSizeWords - align_object_size(1));
772 }
773 MaxTLABSizeWords = align_down(max_tlab_words, MinObjAlignment);
774
775 guarantee(MaxTLABSizeBytes == 0, "we should only set it once");
776 MaxTLABSizeBytes = MaxTLABSizeWords * HeapWordSize;
777 assert (MaxTLABSizeBytes > MinTLABSize, "should be larger");
778
779 return max_heap_size;
780 }
781
782 void ShenandoahHeapRegion::do_commit() {
783 ShenandoahHeap* heap = ShenandoahHeap::heap();
784 if (!heap->is_heap_region_special()) {
785 os::commit_memory_or_exit((char*) bottom(), RegionSizeBytes, false, "Unable to commit region");
786 }
787 if (!heap->is_bitmap_region_special()) {
788 heap->commit_bitmap_slice(this);
789 }
790 if (AlwaysPreTouch) {
791 os::pretouch_memory(bottom(), end(), heap->pretouch_heap_page_size());
792 }
793 if (ZapUnusedHeapArea) {
794 SpaceMangler::mangle_region(MemRegion(bottom(), end()));
795 }
796 heap->increase_committed(ShenandoahHeapRegion::region_size_bytes());
797 }
798
799 void ShenandoahHeapRegion::do_uncommit() {
800 ShenandoahHeap* heap = ShenandoahHeap::heap();
801 if (!heap->is_heap_region_special()) {
802 os::uncommit_memory((char *) bottom(), RegionSizeBytes);
803 }
804 if (!heap->is_bitmap_region_special()) {
805 heap->uncommit_bitmap_slice(this);
806 }
807 heap->decrease_committed(ShenandoahHeapRegion::region_size_bytes());
808 }
809
810 void ShenandoahHeapRegion::set_state(RegionState to) {
811 EventShenandoahHeapRegionStateChange evt;
812 if (evt.should_commit()){
813 evt.set_index((unsigned) index());
814 evt.set_start((uintptr_t)bottom());
815 evt.set_used(used());
816 evt.set_from(state());
817 evt.set_to(to);
818 evt.commit();
819 }
820 _state.release_store(to);
821 }
822
823 void ShenandoahHeapRegion::record_pin() {
824 _critical_pins.add_then_fetch((size_t)1);
825 }
826
827 void ShenandoahHeapRegion::record_unpin() {
828 assert(pin_count() > 0, "Region %zu should have non-zero pins", index());
829 _critical_pins.sub_then_fetch((size_t)1);
830 }
831
832 size_t ShenandoahHeapRegion::pin_count() const {
833 return _critical_pins.load_relaxed();
834 }
835
836 void ShenandoahHeapRegion::set_affiliation(ShenandoahAffiliation new_affiliation) {
837 ShenandoahHeap* heap = ShenandoahHeap::heap();
838
839 ShenandoahAffiliation region_affiliation = heap->region_affiliation(this);
840 ShenandoahMarkingContext* const ctx = heap->marking_context();
841 {
842 log_debug(gc)("Setting affiliation of Region %zu from %s to %s, top: " PTR_FORMAT ", TAMS: " PTR_FORMAT
843 ", watermark: " PTR_FORMAT ", top_bitmap: " PTR_FORMAT,
844 index(), shenandoah_affiliation_name(region_affiliation), shenandoah_affiliation_name(new_affiliation),
845 p2i(top()), p2i(ctx->top_at_mark_start(this)), p2i(_update_watermark.load_relaxed()), p2i(ctx->top_bitmap(this)));
846 }
847
848 #ifdef ASSERT
849 {
850 size_t idx = this->index();
851 HeapWord* top_bitmap = ctx->top_bitmap(this);
852
853 assert(ctx->is_bitmap_range_within_region_clear(top_bitmap, _end),
854 "Region %zu, bitmap should be clear between top_bitmap: " PTR_FORMAT " and end: " PTR_FORMAT, idx,
855 p2i(top_bitmap), p2i(_end));
856 }
857 #endif
858
859 if (region_affiliation == new_affiliation) {
860 return;
861 }
862
863 if (!heap->mode()->is_generational()) {
864 log_trace(gc)("Changing affiliation of region %zu from %s to %s",
865 index(), affiliation_name(), shenandoah_affiliation_name(new_affiliation));
866 heap->set_affiliation(this, new_affiliation);
867 return;
868 }
869
870 switch (new_affiliation) {
871 case FREE:
872 assert(!has_live(), "Free region should not have live data");
873 break;
874 case YOUNG_GENERATION:
875 reset_age();
876 break;
877 case OLD_GENERATION:
878 break;
879 default:
880 ShouldNotReachHere();
881 return;
882 }
883 heap->set_affiliation(this, new_affiliation);
884 }
885
886 void ShenandoahHeapRegion::decrement_humongous_waste() {
887 assert(is_humongous(), "Should only use this for humongous regions");
888 size_t waste_bytes = free();
889 if (waste_bytes > 0) {
890 ShenandoahHeap* heap = ShenandoahHeap::heap();
891 heap->free_set()->decrease_humongous_waste_for_regular_bypass(this, waste_bytes);
892 }
893 }