1 /*
  2  * Copyright (c) 2023, 2024, 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.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::MaxTLABSizeBytes = 0;
 55 size_t ShenandoahHeapRegion::MaxTLABSizeWords = 0;
 56 
 57 ShenandoahHeapRegion::ShenandoahHeapRegion(HeapWord* start, size_t index, bool committed) :
 58   _index(index),
 59   _bottom(start),
 60   _end(start + RegionSizeWords),
 61   _new_top(nullptr),
 62   _empty_time(os::elapsedTime()),
 63   _state(committed ? _empty_committed : _empty_uncommitted),
 64   _top(start),
 65   _tlab_allocs(0),
 66   _gclab_allocs(0),
 67   _live_data(0),
 68   _critical_pins(0),
 69   _update_watermark(start) {
 70 
 71   assert(Universe::on_page_boundary(_bottom) && Universe::on_page_boundary(_end),
 72          "invalid space boundaries");
 73   if (ZapUnusedHeapArea && committed) {
 74     SpaceMangler::mangle_region(MemRegion(_bottom, _end));
 75   }
 76 }
 77 
 78 void ShenandoahHeapRegion::report_illegal_transition(const char *method) {
 79   stringStream ss;
 80   ss.print("Illegal region state transition from \"%s\", at %s\n  ", region_state_to_string(_state), method);
 81   print_on(&ss);
 82   fatal("%s", ss.freeze());
 83 }
 84 
 85 void ShenandoahHeapRegion::make_regular_allocation() {
 86   shenandoah_assert_heaplocked();
 87 
 88   switch (_state) {
 89     case _empty_uncommitted:
 90       do_commit();
 91     case _empty_committed:
 92       set_state(_regular);
 93     case _regular:
 94     case _pinned:
 95       return;
 96     default:
 97       report_illegal_transition("regular allocation");
 98   }
 99 }
100 
101 void ShenandoahHeapRegion::make_regular_bypass() {
102   shenandoah_assert_heaplocked();
103   assert (!Universe::is_fully_initialized() ||
104           ShenandoahHeap::heap()->is_full_gc_in_progress() ||
105           ShenandoahHeap::heap()->is_degenerated_gc_in_progress(),
106           "Only for STW GC or when Universe is initializing (CDS)");
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:
342       st->print("|H  ");
343       break;
344     case _pinned_humongous_start:
345       st->print("|HP ");
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;
460   }
461 }
462 
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));
503       vm_exit_during_initialization("Invalid -XX:ShenandoahMinRegionSize option", message);
504     }
505     if (ShenandoahMaxRegionSize < MIN_REGION_SIZE) {
506       err_msg message("" SIZE_FORMAT "%s should not be lower than min region size (" SIZE_FORMAT "%s).",
507                       byte_size_in_proper_unit(ShenandoahMaxRegionSize), proper_unit_for_byte_size(ShenandoahMaxRegionSize),
508                       byte_size_in_proper_unit(MIN_REGION_SIZE),         proper_unit_for_byte_size(MIN_REGION_SIZE));
509       vm_exit_during_initialization("Invalid -XX:ShenandoahMaxRegionSize option", message);
510     }
511     if (ShenandoahMinRegionSize > ShenandoahMaxRegionSize) {
512       err_msg message("Minimum (" SIZE_FORMAT "%s) should be larger than maximum (" SIZE_FORMAT "%s).",
513                       byte_size_in_proper_unit(ShenandoahMinRegionSize), proper_unit_for_byte_size(ShenandoahMinRegionSize),
514                       byte_size_in_proper_unit(ShenandoahMaxRegionSize), proper_unit_for_byte_size(ShenandoahMaxRegionSize));
515       vm_exit_during_initialization("Invalid -XX:ShenandoahMinRegionSize or -XX:ShenandoahMaxRegionSize", message);
516     }
517 
518     // We rapidly expand to max_heap_size in most scenarios, so that is the measure
519     // for usual heap sizes. Do not depend on initial_heap_size here.
520     region_size = max_heap_size / ShenandoahTargetNumRegions;
521 
522     // Now make sure that we don't go over or under our limits.
523     region_size = MAX2(ShenandoahMinRegionSize, region_size);
524     region_size = MIN2(ShenandoahMaxRegionSize, region_size);
525 
526   } else {
527     if (ShenandoahRegionSize > max_heap_size / MIN_NUM_REGIONS) {
528       err_msg message("Max heap size (" SIZE_FORMAT "%s) is too low to afford the minimum number "
529                               "of regions (" SIZE_FORMAT ") of requested size (" SIZE_FORMAT "%s).",
530                       byte_size_in_proper_unit(max_heap_size), proper_unit_for_byte_size(max_heap_size),
531                       MIN_NUM_REGIONS,
532                       byte_size_in_proper_unit(ShenandoahRegionSize), proper_unit_for_byte_size(ShenandoahRegionSize));
533       vm_exit_during_initialization("Invalid -XX:ShenandoahRegionSize option", message);
534     }
535     if (ShenandoahRegionSize < ShenandoahMinRegionSize) {
536       err_msg message("Heap region size (" SIZE_FORMAT "%s) should be larger than min region size (" SIZE_FORMAT "%s).",
537                       byte_size_in_proper_unit(ShenandoahRegionSize), proper_unit_for_byte_size(ShenandoahRegionSize),
538                       byte_size_in_proper_unit(ShenandoahMinRegionSize),  proper_unit_for_byte_size(ShenandoahMinRegionSize));
539       vm_exit_during_initialization("Invalid -XX:ShenandoahRegionSize option", message);
540     }
541     if (ShenandoahRegionSize > ShenandoahMaxRegionSize) {
542       err_msg message("Heap region size (" SIZE_FORMAT "%s) should be lower than max region size (" SIZE_FORMAT "%s).",
543                       byte_size_in_proper_unit(ShenandoahRegionSize), proper_unit_for_byte_size(ShenandoahRegionSize),
544                       byte_size_in_proper_unit(ShenandoahMaxRegionSize),  proper_unit_for_byte_size(ShenandoahMaxRegionSize));
545       vm_exit_during_initialization("Invalid -XX:ShenandoahRegionSize option", message);
546     }
547     region_size = ShenandoahRegionSize;
548   }
549 
550   // Make sure region size and heap size are page aligned.
551   // If large pages are used, we ensure that region size is aligned to large page size if
552   // heap size is large enough to accommodate minimal number of regions. Otherwise, we align
553   // region size to regular page size.
554 
555   // Figure out page size to use, and aligns up heap to page size
556   size_t page_size = os::vm_page_size();
557   if (UseLargePages) {
558     size_t large_page_size = os::large_page_size();
559     max_heap_size = align_up(max_heap_size, large_page_size);
560     if ((max_heap_size / align_up(region_size, large_page_size)) >= MIN_NUM_REGIONS) {
561       page_size = large_page_size;
562     } else {
563       // Should have been checked during argument initialization
564       assert(!ShenandoahUncommit, "Uncommit requires region size aligns to large page size");
565     }
566   } else {
567     max_heap_size = align_up(max_heap_size, page_size);
568   }
569 
570   // Align region size to page size
571   region_size = align_up(region_size, page_size);
572 
573   int region_size_log = log2i(region_size);
574   // Recalculate the region size to make sure it's a power of
575   // 2. This means that region_size is the largest power of 2 that's
576   // <= what we've calculated so far.
577   region_size = size_t(1) << region_size_log;
578 
579   // Now, set up the globals.
580   guarantee(RegionSizeBytesShift == 0, "we should only set it once");
581   RegionSizeBytesShift = (size_t)region_size_log;
582 
583   guarantee(RegionSizeWordsShift == 0, "we should only set it once");
584   RegionSizeWordsShift = RegionSizeBytesShift - LogHeapWordSize;
585 
586   guarantee(RegionSizeBytes == 0, "we should only set it once");
587   RegionSizeBytes = region_size;
588   RegionSizeWords = RegionSizeBytes >> LogHeapWordSize;
589   assert (RegionSizeWords*HeapWordSize == RegionSizeBytes, "sanity");
590 
591   guarantee(RegionSizeWordsMask == 0, "we should only set it once");
592   RegionSizeWordsMask = RegionSizeWords - 1;
593 
594   guarantee(RegionSizeBytesMask == 0, "we should only set it once");
595   RegionSizeBytesMask = RegionSizeBytes - 1;
596 
597   guarantee(RegionCount == 0, "we should only set it once");
598   RegionCount = align_up(max_heap_size, RegionSizeBytes) / RegionSizeBytes;
599   guarantee(RegionCount >= MIN_NUM_REGIONS, "Should have at least minimum regions");
600 
601   guarantee(MaxTLABSizeWords == 0, "we should only set it once");
602   MaxTLABSizeWords = align_down(RegionSizeWords, MinObjAlignment);
603 
604   guarantee(MaxTLABSizeBytes == 0, "we should only set it once");
605   MaxTLABSizeBytes = MaxTLABSizeWords * HeapWordSize;
606   assert (MaxTLABSizeBytes > MinTLABSize, "should be larger");
607 
608   return max_heap_size;
609 }
610 
611 void ShenandoahHeapRegion::do_commit() {
612   ShenandoahHeap* heap = ShenandoahHeap::heap();
613   if (!heap->is_heap_region_special() && !os::commit_memory((char *) bottom(), RegionSizeBytes, false)) {
614     report_java_out_of_memory("Unable to commit region");
615   }
616   if (!heap->commit_bitmap_slice(this)) {
617     report_java_out_of_memory("Unable to commit bitmaps for region");
618   }
619   if (AlwaysPreTouch) {
620     os::pretouch_memory(bottom(), end(), heap->pretouch_heap_page_size());
621   }
622   heap->increase_committed(ShenandoahHeapRegion::region_size_bytes());
623 }
624 
625 void ShenandoahHeapRegion::do_uncommit() {
626   ShenandoahHeap* heap = ShenandoahHeap::heap();
627   if (!heap->is_heap_region_special() && !os::uncommit_memory((char *) bottom(), RegionSizeBytes)) {
628     report_java_out_of_memory("Unable to uncommit region");
629   }
630   if (!heap->uncommit_bitmap_slice(this)) {
631     report_java_out_of_memory("Unable to uncommit bitmaps for region");
632   }
633   heap->decrease_committed(ShenandoahHeapRegion::region_size_bytes());
634 }
635 
636 void ShenandoahHeapRegion::set_state(RegionState to) {
637   EventShenandoahHeapRegionStateChange evt;
638   if (evt.should_commit()){
639     evt.set_index((unsigned) index());
640     evt.set_start((uintptr_t)bottom());
641     evt.set_used(used());
642     evt.set_from(_state);
643     evt.set_to(to);
644     evt.commit();
645   }
646   _state = to;
647 }
648 
649 void ShenandoahHeapRegion::record_pin() {
650   Atomic::add(&_critical_pins, (size_t)1);
651 }
652 
653 void ShenandoahHeapRegion::record_unpin() {
654   assert(pin_count() > 0, "Region " SIZE_FORMAT " should have non-zero pins", index());
655   Atomic::sub(&_critical_pins, (size_t)1);
656 }
657 
658 size_t ShenandoahHeapRegion::pin_count() const {
659   return Atomic::load(&_critical_pins);
660 }