< prev index next >

src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp

Print this page

  1 /*
  2  * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
  3  * Copyright (c) 2013, 2019, Red Hat, Inc. All rights reserved.

  4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  5  *
  6  * This code is free software; you can redistribute it and/or modify it
  7  * under the terms of the GNU General Public License version 2 only, as
  8  * published by the Free Software Foundation.
  9  *
 10  * This code is distributed in the hope that it will be useful, but WITHOUT
 11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 13  * version 2 for more details (a copy is included in the LICENSE file that
 14  * accompanied this code).
 15  *
 16  * You should have received a copy of the GNU General Public License version
 17  * 2 along with this work; if not, write to the Free Software Foundation,
 18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 19  *
 20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 21  * or visit www.oracle.com if you need additional information or have any
 22  * questions.
 23  *
 24  */
 25 
 26 #include "precompiled.hpp"

 27 #include "gc/shared/space.inline.hpp"
 28 #include "gc/shared/tlab_globals.hpp"


 29 #include "gc/shenandoah/shenandoahHeapRegionSet.inline.hpp"
 30 #include "gc/shenandoah/shenandoahHeap.inline.hpp"
 31 #include "gc/shenandoah/shenandoahHeapRegion.hpp"
 32 #include "gc/shenandoah/shenandoahMarkingContext.inline.hpp"




 33 #include "jfr/jfrEvents.hpp"
 34 #include "memory/allocation.hpp"
 35 #include "memory/iterator.inline.hpp"
 36 #include "memory/resourceArea.hpp"
 37 #include "memory/universe.hpp"
 38 #include "oops/oop.inline.hpp"
 39 #include "runtime/atomic.hpp"
 40 #include "runtime/globals_extension.hpp"
 41 #include "runtime/java.hpp"
 42 #include "runtime/mutexLocker.hpp"
 43 #include "runtime/os.hpp"
 44 #include "runtime/safepoint.hpp"
 45 #include "utilities/powerOfTwo.hpp"
 46 

 47 size_t ShenandoahHeapRegion::RegionCount = 0;
 48 size_t ShenandoahHeapRegion::RegionSizeBytes = 0;
 49 size_t ShenandoahHeapRegion::RegionSizeWords = 0;
 50 size_t ShenandoahHeapRegion::RegionSizeBytesShift = 0;
 51 size_t ShenandoahHeapRegion::RegionSizeWordsShift = 0;
 52 size_t ShenandoahHeapRegion::RegionSizeBytesMask = 0;
 53 size_t ShenandoahHeapRegion::RegionSizeWordsMask = 0;
 54 size_t ShenandoahHeapRegion::HumongousThresholdBytes = 0;
 55 size_t ShenandoahHeapRegion::HumongousThresholdWords = 0;
 56 size_t ShenandoahHeapRegion::MaxTLABSizeBytes = 0;
 57 size_t ShenandoahHeapRegion::MaxTLABSizeWords = 0;
 58 
 59 ShenandoahHeapRegion::ShenandoahHeapRegion(HeapWord* start, size_t index, bool committed) :
 60   _index(index),
 61   _bottom(start),
 62   _end(start + RegionSizeWords),
 63   _new_top(nullptr),
 64   _empty_time(os::elapsedTime()),

 65   _state(committed ? _empty_committed : _empty_uncommitted),
 66   _top(start),
 67   _tlab_allocs(0),
 68   _gclab_allocs(0),

 69   _live_data(0),
 70   _critical_pins(0),
 71   _update_watermark(start) {





 72 
 73   assert(Universe::on_page_boundary(_bottom) && Universe::on_page_boundary(_end),
 74          "invalid space boundaries");
 75   if (ZapUnusedHeapArea && committed) {
 76     SpaceMangler::mangle_region(MemRegion(_bottom, _end));
 77   }
 78 }
 79 
 80 void ShenandoahHeapRegion::report_illegal_transition(const char *method) {
 81   stringStream ss;
 82   ss.print("Illegal region state transition from \"%s\", at %s\n  ", region_state_to_string(_state), method);
 83   print_on(&ss);
 84   fatal("%s", ss.freeze());
 85 }
 86 
 87 void ShenandoahHeapRegion::make_regular_allocation() {
 88   shenandoah_assert_heaplocked();
 89 
 90   switch (_state) {
 91     case _empty_uncommitted:
 92       do_commit();
 93     case _empty_committed:

 94       set_state(_regular);
 95     case _regular:
 96     case _pinned:
 97       return;
 98     default:
 99       report_illegal_transition("regular allocation");
100   }
101 }
102 



























103 void ShenandoahHeapRegion::make_regular_bypass() {
104   shenandoah_assert_heaplocked();
105   assert (ShenandoahHeap::heap()->is_full_gc_in_progress() || ShenandoahHeap::heap()->is_degenerated_gc_in_progress(),
106           "only for full or degen GC");
107 
108   switch (_state) {
109     case _empty_uncommitted:
110       do_commit();
111     case _empty_committed:
112     case _cset:
113     case _humongous_start:
114     case _humongous_cont:
115       set_state(_regular);
116       return;
117     case _pinned_cset:
118       set_state(_pinned);
119       return;
120     case _regular:
121     case _pinned:
122       return;
123     default:
124       report_illegal_transition("regular bypass");
125   }
126 }
127 
128 void ShenandoahHeapRegion::make_humongous_start() {
129   shenandoah_assert_heaplocked();

130   switch (_state) {
131     case _empty_uncommitted:
132       do_commit();
133     case _empty_committed:
134       set_state(_humongous_start);
135       return;
136     default:
137       report_illegal_transition("humongous start allocation");
138   }
139 }
140 
141 void ShenandoahHeapRegion::make_humongous_start_bypass() {
142   shenandoah_assert_heaplocked();
143   assert (ShenandoahHeap::heap()->is_full_gc_in_progress(), "only for full GC");
144 


145   switch (_state) {
146     case _empty_committed:
147     case _regular:
148     case _humongous_start:
149     case _humongous_cont:
150       set_state(_humongous_start);
151       return;
152     default:
153       report_illegal_transition("humongous start bypass");
154   }
155 }
156 
157 void ShenandoahHeapRegion::make_humongous_cont() {
158   shenandoah_assert_heaplocked();

159   switch (_state) {
160     case _empty_uncommitted:
161       do_commit();
162     case _empty_committed:
163      set_state(_humongous_cont);
164       return;
165     default:
166       report_illegal_transition("humongous continuation allocation");
167   }
168 }
169 
170 void ShenandoahHeapRegion::make_humongous_cont_bypass() {
171   shenandoah_assert_heaplocked();
172   assert (ShenandoahHeap::heap()->is_full_gc_in_progress(), "only for full GC");
173 


174   switch (_state) {
175     case _empty_committed:
176     case _regular:
177     case _humongous_start:
178     case _humongous_cont:
179       set_state(_humongous_cont);
180       return;
181     default:
182       report_illegal_transition("humongous continuation bypass");
183   }
184 }
185 
186 void ShenandoahHeapRegion::make_pinned() {
187   shenandoah_assert_heaplocked();
188   assert(pin_count() > 0, "Should have pins: " SIZE_FORMAT, pin_count());
189 
190   switch (_state) {
191     case _regular:
192       set_state(_pinned);
193     case _pinned_cset:
194     case _pinned:
195       return;
196     case _humongous_start:
197       set_state(_pinned_humongous_start);
198     case _pinned_humongous_start:
199       return;
200     case _cset:
201       _state = _pinned_cset;
202       return;
203     default:
204       report_illegal_transition("pinning");
205   }
206 }
207 
208 void ShenandoahHeapRegion::make_unpinned() {
209   shenandoah_assert_heaplocked();
210   assert(pin_count() == 0, "Should not have pins: " SIZE_FORMAT, pin_count());
211 
212   switch (_state) {
213     case _pinned:

214       set_state(_regular);
215       return;
216     case _regular:
217     case _humongous_start:
218       return;
219     case _pinned_cset:
220       set_state(_cset);
221       return;
222     case _pinned_humongous_start:
223       set_state(_humongous_start);
224       return;
225     default:
226       report_illegal_transition("unpinning");
227   }
228 }
229 
230 void ShenandoahHeapRegion::make_cset() {
231   shenandoah_assert_heaplocked();

232   switch (_state) {
233     case _regular:
234       set_state(_cset);
235     case _cset:
236       return;
237     default:
238       report_illegal_transition("cset");
239   }
240 }
241 
242 void ShenandoahHeapRegion::make_trash() {
243   shenandoah_assert_heaplocked();

244   switch (_state) {
245     case _cset:
246       // Reclaiming cset regions
247     case _humongous_start:
248     case _humongous_cont:
249       // Reclaiming humongous regions






250     case _regular:
251       // Immediate region reclaim
252       set_state(_trash);
253       return;
254     default:
255       report_illegal_transition("trashing");
256   }
257 }
258 
259 void ShenandoahHeapRegion::make_trash_immediate() {
260   make_trash();
261 
262   // On this path, we know there are no marked objects in the region,
263   // tell marking context about it to bypass bitmap resets.
264   ShenandoahHeap::heap()->complete_marking_context()->reset_top_bitmap(this);

265 }
266 
267 void ShenandoahHeapRegion::make_empty() {
268   shenandoah_assert_heaplocked();


269   switch (_state) {
270     case _trash:
271       set_state(_empty_committed);
272       _empty_time = os::elapsedTime();
273       return;
274     default:
275       report_illegal_transition("emptying");
276   }
277 }
278 
279 void ShenandoahHeapRegion::make_uncommitted() {
280   shenandoah_assert_heaplocked();
281   switch (_state) {
282     case _empty_committed:
283       do_uncommit();
284       set_state(_empty_uncommitted);
285       return;
286     default:
287       report_illegal_transition("uncommiting");
288   }
289 }
290 
291 void ShenandoahHeapRegion::make_committed_bypass() {
292   shenandoah_assert_heaplocked();
293   assert (ShenandoahHeap::heap()->is_full_gc_in_progress(), "only for full GC");
294 
295   switch (_state) {
296     case _empty_uncommitted:
297       do_commit();
298       set_state(_empty_committed);
299       return;
300     default:
301       report_illegal_transition("commit bypass");
302   }
303 }
304 
305 void ShenandoahHeapRegion::reset_alloc_metadata() {
306   _tlab_allocs = 0;
307   _gclab_allocs = 0;

308 }
309 
310 size_t ShenandoahHeapRegion::get_shared_allocs() const {
311   return used() - (_tlab_allocs + _gclab_allocs) * HeapWordSize;
312 }
313 
314 size_t ShenandoahHeapRegion::get_tlab_allocs() const {
315   return _tlab_allocs * HeapWordSize;
316 }
317 
318 size_t ShenandoahHeapRegion::get_gclab_allocs() const {
319   return _gclab_allocs * HeapWordSize;
320 }
321 




322 void ShenandoahHeapRegion::set_live_data(size_t s) {
323   assert(Thread::current()->is_VM_thread(), "by VM thread");
324   _live_data = (s >> LogHeapWordSize);
325 }
326 
327 void ShenandoahHeapRegion::print_on(outputStream* st) const {
328   st->print("|");
329   st->print(SIZE_FORMAT_W(5), this->_index);
330 
331   switch (_state) {
332     case _empty_uncommitted:
333       st->print("|EU ");
334       break;
335     case _empty_committed:
336       st->print("|EC ");
337       break;
338     case _regular:
339       st->print("|R  ");
340       break;
341     case _humongous_start:

346       break;
347     case _humongous_cont:
348       st->print("|HC ");
349       break;
350     case _cset:
351       st->print("|CS ");
352       break;
353     case _trash:
354       st->print("|TR ");
355       break;
356     case _pinned:
357       st->print("|P  ");
358       break;
359     case _pinned_cset:
360       st->print("|CSP");
361       break;
362     default:
363       ShouldNotReachHere();
364   }
365 


366 #define SHR_PTR_FORMAT "%12" PRIxPTR
367 
368   st->print("|BTE " SHR_PTR_FORMAT  ", " SHR_PTR_FORMAT ", " SHR_PTR_FORMAT,
369             p2i(bottom()), p2i(top()), p2i(end()));
370   st->print("|TAMS " SHR_PTR_FORMAT,
371             p2i(ShenandoahHeap::heap()->marking_context()->top_at_mark_start(const_cast<ShenandoahHeapRegion*>(this))));
372   st->print("|UWM " SHR_PTR_FORMAT,
373             p2i(_update_watermark));
374   st->print("|U " SIZE_FORMAT_W(5) "%1s", byte_size_in_proper_unit(used()),                proper_unit_for_byte_size(used()));
375   st->print("|T " SIZE_FORMAT_W(5) "%1s", byte_size_in_proper_unit(get_tlab_allocs()),     proper_unit_for_byte_size(get_tlab_allocs()));
376   st->print("|G " SIZE_FORMAT_W(5) "%1s", byte_size_in_proper_unit(get_gclab_allocs()),    proper_unit_for_byte_size(get_gclab_allocs()));



377   st->print("|S " SIZE_FORMAT_W(5) "%1s", byte_size_in_proper_unit(get_shared_allocs()),   proper_unit_for_byte_size(get_shared_allocs()));
378   st->print("|L " SIZE_FORMAT_W(5) "%1s", byte_size_in_proper_unit(get_live_data_bytes()), proper_unit_for_byte_size(get_live_data_bytes()));
379   st->print("|CP " SIZE_FORMAT_W(3), pin_count());
380   st->cr();
381 
382 #undef SHR_PTR_FORMAT
383 }
384 
385 void ShenandoahHeapRegion::oop_iterate(OopIterateClosure* blk) {
386   if (!is_active()) return;
387   if (is_humongous()) {
388     oop_iterate_humongous(blk);
389   } else {
390     oop_iterate_objects(blk);






























391   }



392 }
393 
394 void ShenandoahHeapRegion::oop_iterate_objects(OopIterateClosure* blk) {
395   assert(! is_humongous(), "no humongous region here");
396   HeapWord* obj_addr = bottom();
397   HeapWord* t = top();
398   // Could call objects iterate, but this is easier.




















399   while (obj_addr < t) {
400     oop obj = cast_to_oop(obj_addr);
401     obj_addr += obj->oop_iterate_size(blk);



















402   }



403 }
404 
405 void ShenandoahHeapRegion::oop_iterate_humongous(OopIterateClosure* blk) {




406   assert(is_humongous(), "only humongous region here");


407   // Find head.
408   ShenandoahHeapRegion* r = humongous_start_region();
409   assert(r->is_humongous_start(), "need humongous head here");



410   oop obj = cast_to_oop(r->bottom());
411   obj->oop_iterate(blk, MemRegion(bottom(), top()));























412 }
413 
414 ShenandoahHeapRegion* ShenandoahHeapRegion::humongous_start_region() const {
415   ShenandoahHeap* heap = ShenandoahHeap::heap();
416   assert(is_humongous(), "Must be a part of the humongous region");
417   size_t i = index();
418   ShenandoahHeapRegion* r = const_cast<ShenandoahHeapRegion*>(this);
419   while (!r->is_humongous_start()) {
420     assert(i > 0, "Sanity");
421     i--;
422     r = heap->get_region(i);
423     assert(r->is_humongous(), "Must be a part of the humongous region");
424   }
425   assert(r->is_humongous_start(), "Must be");
426   return r;
427 }
428 
429 void ShenandoahHeapRegion::recycle() {







430   set_top(bottom());
431   clear_live_data();
432 
433   reset_alloc_metadata();
434 
435   ShenandoahHeap::heap()->marking_context()->reset_top_at_mark_start(this);
436   set_update_watermark(bottom());
437 
438   make_empty();
439 

440   if (ZapUnusedHeapArea) {
441     SpaceMangler::mangle_region(MemRegion(bottom(), end()));
442   }
443 }
444 
445 HeapWord* ShenandoahHeapRegion::block_start(const void* p) const {
446   assert(MemRegion(bottom(), end()).contains(p),
447          "p (" PTR_FORMAT ") not in space [" PTR_FORMAT ", " PTR_FORMAT ")",
448          p2i(p), p2i(bottom()), p2i(end()));
449   if (p >= top()) {
450     return top();
451   } else {
452     HeapWord* last = bottom();
453     HeapWord* cur = last;
454     while (cur <= p) {
455       last = cur;
456       cur += cast_to_oop(cur)->size();
457     }
458     shenandoah_assert_correct(nullptr, cast_to_oop(last));
459     return last;

463 size_t ShenandoahHeapRegion::block_size(const HeapWord* p) const {
464   assert(MemRegion(bottom(), end()).contains(p),
465          "p (" PTR_FORMAT ") not in space [" PTR_FORMAT ", " PTR_FORMAT ")",
466          p2i(p), p2i(bottom()), p2i(end()));
467   if (p < top()) {
468     return cast_to_oop(p)->size();
469   } else {
470     assert(p == top(), "just checking");
471     return pointer_delta(end(), (HeapWord*) p);
472   }
473 }
474 
475 size_t ShenandoahHeapRegion::setup_sizes(size_t max_heap_size) {
476   // Absolute minimums we should not ever break.
477   static const size_t MIN_REGION_SIZE = 256*K;
478 
479   if (FLAG_IS_DEFAULT(ShenandoahMinRegionSize)) {
480     FLAG_SET_DEFAULT(ShenandoahMinRegionSize, MIN_REGION_SIZE);
481   }
482 





483   size_t region_size;
484   if (FLAG_IS_DEFAULT(ShenandoahRegionSize)) {
485     if (ShenandoahMinRegionSize > max_heap_size / MIN_NUM_REGIONS) {
486       err_msg message("Max heap size (" SIZE_FORMAT "%s) is too low to afford the minimum number "
487                       "of regions (" SIZE_FORMAT ") of minimum region size (" SIZE_FORMAT "%s).",
488                       byte_size_in_proper_unit(max_heap_size), proper_unit_for_byte_size(max_heap_size),
489                       MIN_NUM_REGIONS,
490                       byte_size_in_proper_unit(ShenandoahMinRegionSize), proper_unit_for_byte_size(ShenandoahMinRegionSize));
491       vm_exit_during_initialization("Invalid -XX:ShenandoahMinRegionSize option", message);
492     }
493     if (ShenandoahMinRegionSize < MIN_REGION_SIZE) {
494       err_msg message("" SIZE_FORMAT "%s should not be lower than minimum region size (" SIZE_FORMAT "%s).",
495                       byte_size_in_proper_unit(ShenandoahMinRegionSize), proper_unit_for_byte_size(ShenandoahMinRegionSize),
496                       byte_size_in_proper_unit(MIN_REGION_SIZE),         proper_unit_for_byte_size(MIN_REGION_SIZE));
497       vm_exit_during_initialization("Invalid -XX:ShenandoahMinRegionSize option", message);
498     }
499     if (ShenandoahMinRegionSize < MinTLABSize) {
500       err_msg message("" SIZE_FORMAT "%s should not be lower than TLAB size size (" SIZE_FORMAT "%s).",
501                       byte_size_in_proper_unit(ShenandoahMinRegionSize), proper_unit_for_byte_size(ShenandoahMinRegionSize),
502                       byte_size_in_proper_unit(MinTLABSize),             proper_unit_for_byte_size(MinTLABSize));

651     evt.set_used(used());
652     evt.set_from(_state);
653     evt.set_to(to);
654     evt.commit();
655   }
656   _state = to;
657 }
658 
659 void ShenandoahHeapRegion::record_pin() {
660   Atomic::add(&_critical_pins, (size_t)1);
661 }
662 
663 void ShenandoahHeapRegion::record_unpin() {
664   assert(pin_count() > 0, "Region " SIZE_FORMAT " should have non-zero pins", index());
665   Atomic::sub(&_critical_pins, (size_t)1);
666 }
667 
668 size_t ShenandoahHeapRegion::pin_count() const {
669   return Atomic::load(&_critical_pins);
670 }

































































  1 /*
  2  * Copyright (c) 2023, 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 "precompiled.hpp"
 28 #include "gc/shared/cardTable.hpp"
 29 #include "gc/shared/space.inline.hpp"
 30 #include "gc/shared/tlab_globals.hpp"
 31 #include "gc/shenandoah/shenandoahCardTable.hpp"
 32 #include "gc/shenandoah/shenandoahFreeSet.hpp"
 33 #include "gc/shenandoah/shenandoahHeapRegionSet.inline.hpp"
 34 #include "gc/shenandoah/shenandoahHeap.inline.hpp"
 35 #include "gc/shenandoah/shenandoahHeapRegion.hpp"
 36 #include "gc/shenandoah/shenandoahMarkingContext.inline.hpp"
 37 #include "gc/shenandoah/shenandoahOldGeneration.hpp"
 38 #include "gc/shenandoah/shenandoahGeneration.hpp"
 39 #include "gc/shenandoah/shenandoahYoungGeneration.hpp"
 40 #include "gc/shenandoah/shenandoahScanRemembered.inline.hpp"
 41 #include "jfr/jfrEvents.hpp"
 42 #include "memory/allocation.hpp"
 43 #include "memory/iterator.inline.hpp"
 44 #include "memory/resourceArea.hpp"
 45 #include "memory/universe.hpp"
 46 #include "oops/oop.inline.hpp"
 47 #include "runtime/atomic.hpp"
 48 #include "runtime/globals_extension.hpp"
 49 #include "runtime/java.hpp"
 50 #include "runtime/mutexLocker.hpp"
 51 #include "runtime/os.hpp"
 52 #include "runtime/safepoint.hpp"
 53 #include "utilities/powerOfTwo.hpp"
 54 
 55 
 56 size_t ShenandoahHeapRegion::RegionCount = 0;
 57 size_t ShenandoahHeapRegion::RegionSizeBytes = 0;
 58 size_t ShenandoahHeapRegion::RegionSizeWords = 0;
 59 size_t ShenandoahHeapRegion::RegionSizeBytesShift = 0;
 60 size_t ShenandoahHeapRegion::RegionSizeWordsShift = 0;
 61 size_t ShenandoahHeapRegion::RegionSizeBytesMask = 0;
 62 size_t ShenandoahHeapRegion::RegionSizeWordsMask = 0;
 63 size_t ShenandoahHeapRegion::HumongousThresholdBytes = 0;
 64 size_t ShenandoahHeapRegion::HumongousThresholdWords = 0;
 65 size_t ShenandoahHeapRegion::MaxTLABSizeBytes = 0;
 66 size_t ShenandoahHeapRegion::MaxTLABSizeWords = 0;
 67 
 68 ShenandoahHeapRegion::ShenandoahHeapRegion(HeapWord* start, size_t index, bool committed) :
 69   _index(index),
 70   _bottom(start),
 71   _end(start + RegionSizeWords),
 72   _new_top(nullptr),
 73   _empty_time(os::elapsedTime()),
 74   _top_before_promoted(nullptr),
 75   _state(committed ? _empty_committed : _empty_uncommitted),
 76   _top(start),
 77   _tlab_allocs(0),
 78   _gclab_allocs(0),
 79   _plab_allocs(0),
 80   _live_data(0),
 81   _critical_pins(0),
 82   _update_watermark(start),
 83   _age(0)
 84 #ifdef SHENANDOAH_CENSUS_NOISE
 85   , _youth(0)
 86 #endif // SHENANDOAH_CENSUS_NOISE
 87   {
 88 
 89   assert(Universe::on_page_boundary(_bottom) && Universe::on_page_boundary(_end),
 90          "invalid space boundaries");
 91   if (ZapUnusedHeapArea && committed) {
 92     SpaceMangler::mangle_region(MemRegion(_bottom, _end));
 93   }
 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().
122 void ShenandoahHeapRegion::make_young_maybe() {
123   shenandoah_assert_heaplocked();
124   switch (_state) {
125    case _empty_uncommitted:
126    case _empty_committed:
127    case _cset:
128    case _humongous_start:
129    case _humongous_cont:
130      if (affiliation() != YOUNG_GENERATION) {
131        if (is_old()) {
132          ShenandoahHeap::heap()->old_generation()->decrement_affiliated_region_count();
133        }
134        set_affiliation(YOUNG_GENERATION);
135        ShenandoahHeap::heap()->young_generation()->increment_affiliated_region_count();
136      }
137      return;
138    case _pinned_cset:
139    case _regular:
140    case _pinned:
141      return;
142    default:
143      assert(false, "Unexpected _state in make_young_maybe");
144   }
145 }
146 
147 void ShenandoahHeapRegion::make_regular_bypass() {
148   shenandoah_assert_heaplocked();
149   assert (ShenandoahHeap::heap()->is_full_gc_in_progress() || ShenandoahHeap::heap()->is_degenerated_gc_in_progress(),
150           "only for full or degen GC");
151   reset_age();
152   switch (_state) {
153     case _empty_uncommitted:
154       do_commit();
155     case _empty_committed:
156     case _cset:
157     case _humongous_start:
158     case _humongous_cont:
159       set_state(_regular);
160       return;
161     case _pinned_cset:
162       set_state(_pinned);
163       return;
164     case _regular:
165     case _pinned:
166       return;
167     default:
168       report_illegal_transition("regular bypass");
169   }
170 }
171 
172 void ShenandoahHeapRegion::make_humongous_start() {
173   shenandoah_assert_heaplocked();
174   reset_age();
175   switch (_state) {
176     case _empty_uncommitted:
177       do_commit();
178     case _empty_committed:
179       set_state(_humongous_start);
180       return;
181     default:
182       report_illegal_transition("humongous start allocation");
183   }
184 }
185 
186 void ShenandoahHeapRegion::make_humongous_start_bypass(ShenandoahAffiliation affiliation) {
187   shenandoah_assert_heaplocked();
188   assert (ShenandoahHeap::heap()->is_full_gc_in_progress(), "only for full GC");
189   // Don't bother to account for affiliated regions during Full GC.  We recompute totals at end.
190   set_affiliation(affiliation);
191   reset_age();
192   switch (_state) {
193     case _empty_committed:
194     case _regular:
195     case _humongous_start:
196     case _humongous_cont:
197       set_state(_humongous_start);
198       return;
199     default:
200       report_illegal_transition("humongous start bypass");
201   }
202 }
203 
204 void ShenandoahHeapRegion::make_humongous_cont() {
205   shenandoah_assert_heaplocked();
206   reset_age();
207   switch (_state) {
208     case _empty_uncommitted:
209       do_commit();
210     case _empty_committed:
211      set_state(_humongous_cont);
212       return;
213     default:
214       report_illegal_transition("humongous continuation allocation");
215   }
216 }
217 
218 void ShenandoahHeapRegion::make_humongous_cont_bypass(ShenandoahAffiliation affiliation) {
219   shenandoah_assert_heaplocked();
220   assert (ShenandoahHeap::heap()->is_full_gc_in_progress(), "only for full GC");
221   set_affiliation(affiliation);
222   // Don't bother to account for affiliated regions during Full GC.  We recompute totals at end.
223   reset_age();
224   switch (_state) {
225     case _empty_committed:
226     case _regular:
227     case _humongous_start:
228     case _humongous_cont:
229       set_state(_humongous_cont);
230       return;
231     default:
232       report_illegal_transition("humongous continuation bypass");
233   }
234 }
235 
236 void ShenandoahHeapRegion::make_pinned() {
237   shenandoah_assert_heaplocked();
238   assert(pin_count() > 0, "Should have pins: " SIZE_FORMAT, pin_count());
239 
240   switch (_state) {
241     case _regular:
242       set_state(_pinned);
243     case _pinned_cset:
244     case _pinned:
245       return;
246     case _humongous_start:
247       set_state(_pinned_humongous_start);
248     case _pinned_humongous_start:
249       return;
250     case _cset:
251       _state = _pinned_cset;
252       return;
253     default:
254       report_illegal_transition("pinning");
255   }
256 }
257 
258 void ShenandoahHeapRegion::make_unpinned() {
259   shenandoah_assert_heaplocked();
260   assert(pin_count() == 0, "Should not have pins: " SIZE_FORMAT, pin_count());
261 
262   switch (_state) {
263     case _pinned:
264       assert(is_affiliated(), "Pinned region should be affiliated");
265       set_state(_regular);
266       return;
267     case _regular:
268     case _humongous_start:
269       return;
270     case _pinned_cset:
271       set_state(_cset);
272       return;
273     case _pinned_humongous_start:
274       set_state(_humongous_start);
275       return;
276     default:
277       report_illegal_transition("unpinning");
278   }
279 }
280 
281 void ShenandoahHeapRegion::make_cset() {
282   shenandoah_assert_heaplocked();
283   // Leave age untouched.  We need to consult the age when we are deciding whether to promote evacuated objects.
284   switch (_state) {
285     case _regular:
286       set_state(_cset);
287     case _cset:
288       return;
289     default:
290       report_illegal_transition("cset");
291   }
292 }
293 
294 void ShenandoahHeapRegion::make_trash() {
295   shenandoah_assert_heaplocked();
296   reset_age();
297   switch (_state) {


298     case _humongous_start:
299     case _humongous_cont:
300     {
301       // Reclaiming humongous regions and reclaim humongous waste.  When this region is eventually recycled, we'll reclaim
302       // its used memory.  At recycle time, we no longer recognize this as a humongous region.
303       decrement_humongous_waste();
304     }
305     case _cset:
306       // Reclaiming cset regions
307     case _regular:
308       // Immediate region reclaim
309       set_state(_trash);
310       return;
311     default:
312       report_illegal_transition("trashing");
313   }
314 }
315 
316 void ShenandoahHeapRegion::make_trash_immediate() {
317   make_trash();
318 
319   // On this path, we know there are no marked objects in the region,
320   // tell marking context about it to bypass bitmap resets.
321   assert(ShenandoahHeap::heap()->active_generation()->is_mark_complete(), "Marking should be complete here.");
322   ShenandoahHeap::heap()->marking_context()->reset_top_bitmap(this);
323 }
324 
325 void ShenandoahHeapRegion::make_empty() {
326   shenandoah_assert_heaplocked();
327   reset_age();
328   CENSUS_NOISE(clear_youth();)
329   switch (_state) {
330     case _trash:
331       set_state(_empty_committed);
332       _empty_time = os::elapsedTime();
333       return;
334     default:
335       report_illegal_transition("emptying");
336   }
337 }
338 
339 void ShenandoahHeapRegion::make_uncommitted() {
340   shenandoah_assert_heaplocked();
341   switch (_state) {
342     case _empty_committed:
343       do_uncommit();
344       set_state(_empty_uncommitted);
345       return;
346     default:
347       report_illegal_transition("uncommiting");
348   }
349 }
350 
351 void ShenandoahHeapRegion::make_committed_bypass() {
352   shenandoah_assert_heaplocked();
353   assert (ShenandoahHeap::heap()->is_full_gc_in_progress(), "only for full GC");
354 
355   switch (_state) {
356     case _empty_uncommitted:
357       do_commit();
358       set_state(_empty_committed);
359       return;
360     default:
361       report_illegal_transition("commit bypass");
362   }
363 }
364 
365 void ShenandoahHeapRegion::reset_alloc_metadata() {
366   _tlab_allocs = 0;
367   _gclab_allocs = 0;
368   _plab_allocs = 0;
369 }
370 
371 size_t ShenandoahHeapRegion::get_shared_allocs() const {
372   return used() - (_tlab_allocs + _gclab_allocs + _plab_allocs) * HeapWordSize;
373 }
374 
375 size_t ShenandoahHeapRegion::get_tlab_allocs() const {
376   return _tlab_allocs * HeapWordSize;
377 }
378 
379 size_t ShenandoahHeapRegion::get_gclab_allocs() const {
380   return _gclab_allocs * HeapWordSize;
381 }
382 
383 size_t ShenandoahHeapRegion::get_plab_allocs() const {
384   return _plab_allocs * HeapWordSize;
385 }
386 
387 void ShenandoahHeapRegion::set_live_data(size_t s) {
388   assert(Thread::current()->is_VM_thread(), "by VM thread");
389   _live_data = (s >> LogHeapWordSize);
390 }
391 
392 void ShenandoahHeapRegion::print_on(outputStream* st) const {
393   st->print("|");
394   st->print(SIZE_FORMAT_W(5), this->_index);
395 
396   switch (_state) {
397     case _empty_uncommitted:
398       st->print("|EU ");
399       break;
400     case _empty_committed:
401       st->print("|EC ");
402       break;
403     case _regular:
404       st->print("|R  ");
405       break;
406     case _humongous_start:

411       break;
412     case _humongous_cont:
413       st->print("|HC ");
414       break;
415     case _cset:
416       st->print("|CS ");
417       break;
418     case _trash:
419       st->print("|TR ");
420       break;
421     case _pinned:
422       st->print("|P  ");
423       break;
424     case _pinned_cset:
425       st->print("|CSP");
426       break;
427     default:
428       ShouldNotReachHere();
429   }
430 
431   st->print("|%s", shenandoah_affiliation_code(affiliation()));
432 
433 #define SHR_PTR_FORMAT "%12" PRIxPTR
434 
435   st->print("|BTE " SHR_PTR_FORMAT  ", " SHR_PTR_FORMAT ", " SHR_PTR_FORMAT,
436             p2i(bottom()), p2i(top()), p2i(end()));
437   st->print("|TAMS " SHR_PTR_FORMAT,
438             p2i(ShenandoahHeap::heap()->marking_context()->top_at_mark_start(const_cast<ShenandoahHeapRegion*>(this))));
439   st->print("|UWM " SHR_PTR_FORMAT,
440             p2i(_update_watermark));
441   st->print("|U " SIZE_FORMAT_W(5) "%1s", byte_size_in_proper_unit(used()),                proper_unit_for_byte_size(used()));
442   st->print("|T " SIZE_FORMAT_W(5) "%1s", byte_size_in_proper_unit(get_tlab_allocs()),     proper_unit_for_byte_size(get_tlab_allocs()));
443   st->print("|G " SIZE_FORMAT_W(5) "%1s", byte_size_in_proper_unit(get_gclab_allocs()),    proper_unit_for_byte_size(get_gclab_allocs()));
444   if (ShenandoahHeap::heap()->mode()->is_generational()) {
445     st->print("|P " SIZE_FORMAT_W(5) "%1s", byte_size_in_proper_unit(get_plab_allocs()),   proper_unit_for_byte_size(get_plab_allocs()));
446   }
447   st->print("|S " SIZE_FORMAT_W(5) "%1s", byte_size_in_proper_unit(get_shared_allocs()),   proper_unit_for_byte_size(get_shared_allocs()));
448   st->print("|L " SIZE_FORMAT_W(5) "%1s", byte_size_in_proper_unit(get_live_data_bytes()), proper_unit_for_byte_size(get_live_data_bytes()));
449   st->print("|CP " SIZE_FORMAT_W(3), pin_count());
450   st->cr();
451 
452 #undef SHR_PTR_FORMAT
453 }
454 
455 // oop_iterate without closure and without cancellation.  always return true.
456 bool ShenandoahHeapRegion::oop_fill_and_coalesce_without_cancel() {
457   HeapWord* obj_addr = resume_coalesce_and_fill();
458 
459   assert(!is_humongous(), "No need to fill or coalesce humongous regions");
460   if (!is_active()) {
461     end_preemptible_coalesce_and_fill();
462     return true;
463   }
464 
465   ShenandoahHeap* heap = ShenandoahHeap::heap();
466   ShenandoahMarkingContext* marking_context = heap->marking_context();
467   // All objects above TAMS are considered live even though their mark bits will not be set.  Note that young-
468   // gen evacuations that interrupt a long-running old-gen concurrent mark may promote objects into old-gen
469   // while the old-gen concurrent marking is ongoing.  These newly promoted objects will reside above TAMS
470   // and will be treated as live during the current old-gen marking pass, even though they will not be
471   // explicitly marked.
472   HeapWord* t = marking_context->top_at_mark_start(this);
473 
474   // Expect marking to be completed before these threads invoke this service.
475   assert(heap->active_generation()->is_mark_complete(), "sanity");
476   while (obj_addr < t) {
477     oop obj = cast_to_oop(obj_addr);
478     if (marking_context->is_marked(obj)) {
479       assert(obj->klass() != nullptr, "klass should not be nullptr");
480       obj_addr += obj->size();
481     } else {
482       // Object is not marked.  Coalesce and fill dead object with dead neighbors.
483       HeapWord* next_marked_obj = marking_context->get_next_marked_addr(obj_addr, t);
484       assert(next_marked_obj <= t, "next marked object cannot exceed top");
485       size_t fill_size = next_marked_obj - obj_addr;
486       assert(fill_size >= ShenandoahHeap::min_fill_size(), "previously allocated objects known to be larger than min_size");
487       ShenandoahHeap::fill_with_object(obj_addr, fill_size);
488       heap->card_scan()->coalesce_objects(obj_addr, fill_size);
489       obj_addr = next_marked_obj;
490     }
491   }
492   // Mark that this region has been coalesced and filled
493   end_preemptible_coalesce_and_fill();
494   return true;
495 }
496 
497 // oop_iterate without closure, return true if completed without cancellation
498 bool ShenandoahHeapRegion::oop_fill_and_coalesce() {
499   HeapWord* obj_addr = resume_coalesce_and_fill();
500   // Consider yielding to cancel/preemption request after this many coalesce operations (skip marked, or coalesce free).
501   const size_t preemption_stride = 128;
502 
503   assert(!is_humongous(), "No need to fill or coalesce humongous regions");
504   if (!is_active()) {
505     end_preemptible_coalesce_and_fill();
506     return true;
507   }
508 
509   ShenandoahHeap* heap = ShenandoahHeap::heap();
510   ShenandoahMarkingContext* marking_context = heap->marking_context();
511   // All objects above TAMS are considered live even though their mark bits will not be set.  Note that young-
512   // gen evacuations that interrupt a long-running old-gen concurrent mark may promote objects into old-gen
513   // while the old-gen concurrent marking is ongoing.  These newly promoted objects will reside above TAMS
514   // and will be treated as live during the current old-gen marking pass, even though they will not be
515   // explicitly marked.
516   HeapWord* t = marking_context->top_at_mark_start(this);
517 
518   // Expect marking to be completed before these threads invoke this service.
519   assert(heap->active_generation()->is_mark_complete(), "sanity");
520 
521   size_t ops_before_preempt_check = preemption_stride;
522   while (obj_addr < t) {
523     oop obj = cast_to_oop(obj_addr);
524     if (marking_context->is_marked(obj)) {
525       assert(obj->klass() != nullptr, "klass should not be nullptr");
526       obj_addr += obj->size();
527     } else {
528       // Object is not marked.  Coalesce and fill dead object with dead neighbors.
529       HeapWord* next_marked_obj = marking_context->get_next_marked_addr(obj_addr, t);
530       assert(next_marked_obj <= t, "next marked object cannot exceed top");
531       size_t fill_size = next_marked_obj - obj_addr;
532       assert(fill_size >= ShenandoahHeap::min_fill_size(), "previously allocated object known to be larger than min_size");
533       ShenandoahHeap::fill_with_object(obj_addr, fill_size);
534       heap->card_scan()->coalesce_objects(obj_addr, fill_size);
535       obj_addr = next_marked_obj;
536     }
537     if (ops_before_preempt_check-- == 0) {
538       if (heap->cancelled_gc()) {
539         suspend_coalesce_and_fill(obj_addr);
540         return false;
541       }
542       ops_before_preempt_check = preemption_stride;
543     }
544   }
545   // Mark that this region has been coalesced and filled
546   end_preemptible_coalesce_and_fill();
547   return true;
548 }
549 
550 // DO NOT CANCEL.  If this worker thread has accepted responsibility for scanning a particular range of addresses, it
551 // must finish the work before it can be cancelled.
552 void ShenandoahHeapRegion::oop_iterate_humongous_slice(OopIterateClosure* blk, bool dirty_only,
553                                                        HeapWord* start, size_t words, bool write_table) {
554   assert(words % CardTable::card_size_in_words() == 0, "Humongous iteration must span whole number of cards");
555   assert(is_humongous(), "only humongous region here");
556   ShenandoahHeap* heap = ShenandoahHeap::heap();
557 
558   // Find head.
559   ShenandoahHeapRegion* r = humongous_start_region();
560   assert(r->is_humongous_start(), "need humongous head here");
561   assert(CardTable::card_size_in_words() * (words / CardTable::card_size_in_words()) == words,
562          "slice must be integral number of cards");
563 
564   oop obj = cast_to_oop(r->bottom());
565   RememberedScanner* scanner = ShenandoahHeap::heap()->card_scan();
566   size_t card_index = scanner->card_index_for_addr(start);
567   size_t num_cards = words / CardTable::card_size_in_words();
568 
569   if (dirty_only) {
570     if (write_table) {
571       while (num_cards-- > 0) {
572         if (scanner->is_write_card_dirty(card_index++)) {
573           obj->oop_iterate(blk, MemRegion(start, start + CardTable::card_size_in_words()));
574         }
575         start += CardTable::card_size_in_words();
576       }
577     } else {
578       while (num_cards-- > 0) {
579         if (scanner->is_card_dirty(card_index++)) {
580           obj->oop_iterate(blk, MemRegion(start, start + CardTable::card_size_in_words()));
581         }
582         start += CardTable::card_size_in_words();
583       }
584     }
585   } else {
586     // Scan all data, regardless of whether cards are dirty
587     obj->oop_iterate(blk, MemRegion(start, start + num_cards * CardTable::card_size_in_words()));
588   }
589 }
590 
591 ShenandoahHeapRegion* ShenandoahHeapRegion::humongous_start_region() const {
592   ShenandoahHeap* heap = ShenandoahHeap::heap();
593   assert(is_humongous(), "Must be a part of the humongous region");
594   size_t i = index();
595   ShenandoahHeapRegion* r = const_cast<ShenandoahHeapRegion*>(this);
596   while (!r->is_humongous_start()) {
597     assert(i > 0, "Sanity");
598     i--;
599     r = heap->get_region(i);
600     assert(r->is_humongous(), "Must be a part of the humongous region");
601   }
602   assert(r->is_humongous_start(), "Must be");
603   return r;
604 }
605 
606 void ShenandoahHeapRegion::recycle() {
607   shenandoah_assert_heaplocked();
608   ShenandoahHeap* heap = ShenandoahHeap::heap();
609   ShenandoahGeneration* generation = heap->generation_for(affiliation());
610 
611   heap->decrease_used(generation, used());
612   generation->decrement_affiliated_region_count();
613 
614   set_top(bottom());
615   clear_live_data();
616 
617   reset_alloc_metadata();
618 
619   heap->marking_context()->reset_top_at_mark_start(this);
620   set_update_watermark(bottom());
621 
622   make_empty();
623 
624   set_affiliation(FREE);
625   if (ZapUnusedHeapArea) {
626     SpaceMangler::mangle_region(MemRegion(bottom(), end()));
627   }
628 }
629 
630 HeapWord* ShenandoahHeapRegion::block_start(const void* p) const {
631   assert(MemRegion(bottom(), end()).contains(p),
632          "p (" PTR_FORMAT ") not in space [" PTR_FORMAT ", " PTR_FORMAT ")",
633          p2i(p), p2i(bottom()), p2i(end()));
634   if (p >= top()) {
635     return top();
636   } else {
637     HeapWord* last = bottom();
638     HeapWord* cur = last;
639     while (cur <= p) {
640       last = cur;
641       cur += cast_to_oop(cur)->size();
642     }
643     shenandoah_assert_correct(nullptr, cast_to_oop(last));
644     return last;

648 size_t ShenandoahHeapRegion::block_size(const HeapWord* p) const {
649   assert(MemRegion(bottom(), end()).contains(p),
650          "p (" PTR_FORMAT ") not in space [" PTR_FORMAT ", " PTR_FORMAT ")",
651          p2i(p), p2i(bottom()), p2i(end()));
652   if (p < top()) {
653     return cast_to_oop(p)->size();
654   } else {
655     assert(p == top(), "just checking");
656     return pointer_delta(end(), (HeapWord*) p);
657   }
658 }
659 
660 size_t ShenandoahHeapRegion::setup_sizes(size_t max_heap_size) {
661   // Absolute minimums we should not ever break.
662   static const size_t MIN_REGION_SIZE = 256*K;
663 
664   if (FLAG_IS_DEFAULT(ShenandoahMinRegionSize)) {
665     FLAG_SET_DEFAULT(ShenandoahMinRegionSize, MIN_REGION_SIZE);
666   }
667 
668   // Generational Shenandoah needs this alignment for card tables.
669   if (strcmp(ShenandoahGCMode, "generational") == 0) {
670     max_heap_size = align_up(max_heap_size , CardTable::ct_max_alignment_constraint());
671   }
672 
673   size_t region_size;
674   if (FLAG_IS_DEFAULT(ShenandoahRegionSize)) {
675     if (ShenandoahMinRegionSize > max_heap_size / MIN_NUM_REGIONS) {
676       err_msg message("Max heap size (" SIZE_FORMAT "%s) is too low to afford the minimum number "
677                       "of regions (" SIZE_FORMAT ") of minimum region size (" SIZE_FORMAT "%s).",
678                       byte_size_in_proper_unit(max_heap_size), proper_unit_for_byte_size(max_heap_size),
679                       MIN_NUM_REGIONS,
680                       byte_size_in_proper_unit(ShenandoahMinRegionSize), proper_unit_for_byte_size(ShenandoahMinRegionSize));
681       vm_exit_during_initialization("Invalid -XX:ShenandoahMinRegionSize option", message);
682     }
683     if (ShenandoahMinRegionSize < MIN_REGION_SIZE) {
684       err_msg message("" SIZE_FORMAT "%s should not be lower than minimum region size (" SIZE_FORMAT "%s).",
685                       byte_size_in_proper_unit(ShenandoahMinRegionSize), proper_unit_for_byte_size(ShenandoahMinRegionSize),
686                       byte_size_in_proper_unit(MIN_REGION_SIZE),         proper_unit_for_byte_size(MIN_REGION_SIZE));
687       vm_exit_during_initialization("Invalid -XX:ShenandoahMinRegionSize option", message);
688     }
689     if (ShenandoahMinRegionSize < MinTLABSize) {
690       err_msg message("" SIZE_FORMAT "%s should not be lower than TLAB size size (" SIZE_FORMAT "%s).",
691                       byte_size_in_proper_unit(ShenandoahMinRegionSize), proper_unit_for_byte_size(ShenandoahMinRegionSize),
692                       byte_size_in_proper_unit(MinTLABSize),             proper_unit_for_byte_size(MinTLABSize));

841     evt.set_used(used());
842     evt.set_from(_state);
843     evt.set_to(to);
844     evt.commit();
845   }
846   _state = to;
847 }
848 
849 void ShenandoahHeapRegion::record_pin() {
850   Atomic::add(&_critical_pins, (size_t)1);
851 }
852 
853 void ShenandoahHeapRegion::record_unpin() {
854   assert(pin_count() > 0, "Region " SIZE_FORMAT " should have non-zero pins", index());
855   Atomic::sub(&_critical_pins, (size_t)1);
856 }
857 
858 size_t ShenandoahHeapRegion::pin_count() const {
859   return Atomic::load(&_critical_pins);
860 }
861 
862 void ShenandoahHeapRegion::set_affiliation(ShenandoahAffiliation new_affiliation) {
863   ShenandoahHeap* heap = ShenandoahHeap::heap();
864 
865   ShenandoahAffiliation region_affiliation = heap->region_affiliation(this);
866   {
867     ShenandoahMarkingContext* const ctx = heap->complete_marking_context();
868     log_debug(gc)("Setting affiliation of Region " SIZE_FORMAT " from %s to %s, top: " PTR_FORMAT ", TAMS: " PTR_FORMAT
869                   ", watermark: " PTR_FORMAT ", top_bitmap: " PTR_FORMAT,
870                   index(), shenandoah_affiliation_name(region_affiliation), shenandoah_affiliation_name(new_affiliation),
871                   p2i(top()), p2i(ctx->top_at_mark_start(this)), p2i(_update_watermark), p2i(ctx->top_bitmap(this)));
872   }
873 
874 #ifdef ASSERT
875   {
876     // During full gc, heap->complete_marking_context() is not valid, may equal nullptr.
877     ShenandoahMarkingContext* const ctx = heap->complete_marking_context();
878     size_t idx = this->index();
879     HeapWord* top_bitmap = ctx->top_bitmap(this);
880 
881     assert(ctx->is_bitmap_clear_range(top_bitmap, _end),
882            "Region " SIZE_FORMAT ", bitmap should be clear between top_bitmap: " PTR_FORMAT " and end: " PTR_FORMAT, idx,
883            p2i(top_bitmap), p2i(_end));
884   }
885 #endif
886 
887   if (region_affiliation == new_affiliation) {
888     return;
889   }
890 
891   if (!heap->mode()->is_generational()) {
892     log_trace(gc)("Changing affiliation of region %zu from %s to %s",
893                   index(), affiliation_name(), shenandoah_affiliation_name(new_affiliation));
894     heap->set_affiliation(this, new_affiliation);
895     return;
896   }
897 
898   switch (new_affiliation) {
899     case FREE:
900       assert(!has_live(), "Free region should not have live data");
901       break;
902     case YOUNG_GENERATION:
903       reset_age();
904       break;
905     case OLD_GENERATION:
906       // TODO: should we reset_age() for OLD as well?  Examine invocations of set_affiliation(). Some contexts redundantly
907       //       invoke reset_age().
908       break;
909     default:
910       ShouldNotReachHere();
911       return;
912   }
913   heap->set_affiliation(this, new_affiliation);
914 }
915 
916 void ShenandoahHeapRegion::decrement_humongous_waste() const {
917   assert(is_humongous(), "Should only use this for humongous regions");
918   size_t waste_bytes = free();
919   if (waste_bytes > 0) {
920     ShenandoahHeap* heap = ShenandoahHeap::heap();
921     ShenandoahGeneration* generation = heap->generation_for(affiliation());
922     heap->decrease_humongous_waste(generation, waste_bytes);
923   }
924 }
< prev index next >