1 /* 2 * Copyright (c) 2013, 2019, Red Hat, Inc. All rights reserved. 3 * Copyright Amazon.com Inc. or its affiliates. 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 #ifndef SHARE_GC_SHENANDOAH_SHENANDOAHHEAPREGION_HPP 27 #define SHARE_GC_SHENANDOAH_SHENANDOAHHEAPREGION_HPP 28 29 #include "gc/shared/gc_globals.hpp" 30 #include "gc/shared/spaceDecorator.hpp" 31 #include "gc/shenandoah/shenandoahAffiliation.hpp" 32 #include "gc/shenandoah/shenandoahAgeCensus.hpp" 33 #include "gc/shenandoah/shenandoahAllocRequest.hpp" 34 #include "gc/shenandoah/shenandoahAsserts.hpp" 35 #include "gc/shenandoah/shenandoahHeap.hpp" 36 #include "gc/shenandoah/shenandoahPadding.hpp" 37 #include "utilities/sizes.hpp" 38 39 class VMStructs; 40 class ShenandoahHeapRegionStateConstant; 41 42 class ShenandoahHeapRegion { 43 friend class VMStructs; 44 friend class ShenandoahHeapRegionStateConstant; 45 private: 46 /* 47 Region state is described by a state machine. Transitions are guarded by 48 heap lock, which allows changing the state of several regions atomically. 49 Region states can be logically aggregated in groups. 50 51 "Empty": 52 ................................................................. 53 . . 54 . . 55 . Uncommitted <------- Committed <------------------------\ 56 . | | . | 57 . \---------v-----------/ . | 58 . | . | 59 .........................|....................................... | 60 | | 61 "Active": | | 62 .........................|....................................... | 63 . | . | 64 . /-----------------^-------------------\ . | 65 . | | . | 66 . v v "Humongous": . | 67 . Regular ---\-----\ ..................O................ . | 68 . | ^ | | . | . . | 69 . | | | | . *---------\ . . | 70 . v | | | . v v . . | 71 . Pinned Cset | . HStart <--> H/Start H/Cont . . | 72 . ^ / | | . Pinned v | . . | 73 . | / | | . *<--------/ . . | 74 . | v | | . | . . | 75 . CsetPinned | | ..................O................ . | 76 . | | | . | 77 . \-----\---v-------------------/ . | 78 . | . | 79 .........................|....................................... | 80 | | 81 "Trash": | | 82 .........................|....................................... | 83 . | . | 84 . v . | 85 . Trash ---------------------------------------/ 86 . . 87 . . 88 ................................................................. 89 90 Transition from "Empty" to "Active" is first allocation. It can go from {Uncommitted, Committed} 91 to {Regular, "Humongous"}. The allocation may happen in Regular regions too, but not in Humongous. 92 93 Transition from "Active" to "Trash" is reclamation. It can go from CSet during the normal cycle, 94 and from {Regular, "Humongous"} for immediate reclamation. The existence of Trash state allows 95 quick reclamation without actual cleaning up. 96 97 Transition from "Trash" to "Empty" is recycling. It cleans up the regions and corresponding metadata. 98 Can be done asynchronously and in bulk. 99 100 Note how internal transitions disallow logic bugs: 101 a) No region can go Empty, unless properly reclaimed/recycled; 102 b) No region can go Uncommitted, unless reclaimed/recycled first; 103 c) Only Regular regions can go to CSet; 104 d) Pinned cannot go Trash, thus it could never be reclaimed until unpinned; 105 e) Pinned cannot go CSet, thus it never moves; 106 f) Humongous cannot be used for regular allocations; 107 g) Humongous cannot go CSet, thus it never moves; 108 h) Humongous start can go pinned, and thus can be protected from moves (humongous continuations should 109 follow associated humongous starts, not pinnable/movable by themselves); 110 i) Empty cannot go Trash, avoiding useless work; 111 j) ... 112 */ 113 114 enum RegionState { 115 _empty_uncommitted, // region is empty and has memory uncommitted 116 _empty_committed, // region is empty and has memory committed 117 _regular, // region is for regular allocations 118 _humongous_start, // region is the humongous start 119 _humongous_cont, // region is the humongous continuation 120 _pinned_humongous_start, // region is both humongous start and pinned 121 _cset, // region is in collection set 122 _pinned, // region is pinned 123 _pinned_cset, // region is pinned and in cset (evac failure path) 124 _trash, // region contains only trash 125 _REGION_STATES_NUM // last 126 }; 127 128 public: 129 static const char* region_state_to_string(RegionState s) { 130 switch (s) { 131 case _empty_uncommitted: return "Empty Uncommitted"; 132 case _empty_committed: return "Empty Committed"; 133 case _regular: return "Regular"; 134 case _humongous_start: return "Humongous Start"; 135 case _humongous_cont: return "Humongous Continuation"; 136 case _pinned_humongous_start: return "Humongous Start, Pinned"; 137 case _cset: return "Collection Set"; 138 case _pinned: return "Pinned"; 139 case _pinned_cset: return "Collection Set, Pinned"; 140 case _trash: return "Trash"; 141 default: 142 ShouldNotReachHere(); 143 return ""; 144 } 145 } 146 147 private: 148 // This method protects from accidental changes in enum order: 149 int region_state_to_ordinal(RegionState s) const { 150 switch (s) { 151 case _empty_uncommitted: return 0; 152 case _empty_committed: return 1; 153 case _regular: return 2; 154 case _humongous_start: return 3; 155 case _humongous_cont: return 4; 156 case _cset: return 5; 157 case _pinned: return 6; 158 case _trash: return 7; 159 case _pinned_cset: return 8; 160 case _pinned_humongous_start: return 9; 161 default: 162 ShouldNotReachHere(); 163 return -1; 164 } 165 } 166 167 void report_illegal_transition(const char* method); 168 void recycle_internal(); 169 170 public: 171 static int region_states_num() { 172 return _REGION_STATES_NUM; 173 } 174 175 // Allowed transitions from the outside code: 176 void make_regular_allocation(ShenandoahAffiliation affiliation); 177 void make_affiliated_maybe(); 178 void make_regular_bypass(); 179 void make_humongous_start(); 180 void make_humongous_cont(); 181 void make_humongous_start_bypass(ShenandoahAffiliation affiliation); 182 void make_humongous_cont_bypass(ShenandoahAffiliation affiliation); 183 void make_pinned(); 184 void make_unpinned(); 185 void make_cset(); 186 void make_trash(); 187 void make_trash_immediate(); 188 void make_empty(); 189 void make_uncommitted(); 190 void make_committed_bypass(); 191 192 // Primitive state predicates 193 bool is_empty_uncommitted() const { return state() == _empty_uncommitted; } 194 bool is_empty_committed() const { return state() == _empty_committed; } 195 bool is_regular() const { return state() == _regular; } 196 bool is_humongous_continuation() const { return state() == _humongous_cont; } 197 bool is_regular_pinned() const { return state() == _pinned; } 198 bool is_trash() const { return state() == _trash; } 199 200 // Derived state predicates (boolean combinations of individual states) 201 bool static is_empty_state(RegionState state) { return state == _empty_committed || state == _empty_uncommitted; } 202 bool static is_humongous_start_state(RegionState state) { return state == _humongous_start || state == _pinned_humongous_start; } 203 bool is_empty() const { return is_empty_state(this->state()); } 204 bool is_active() const { auto cur_state = state(); return !is_empty_state(cur_state) && cur_state != _trash; } 205 bool is_humongous_start() const { return is_humongous_start_state(state()); } 206 bool is_humongous() const { auto cur_state = state(); return is_humongous_start_state(cur_state) || cur_state == _humongous_cont; } 207 bool is_committed() const { return !is_empty_uncommitted(); } 208 bool is_cset() const { auto cur_state = state(); return cur_state == _cset || cur_state == _pinned_cset; } 209 bool is_pinned() const { auto cur_state = state(); return cur_state == _pinned || cur_state == _pinned_cset || cur_state == _pinned_humongous_start; } 210 211 inline bool is_young() const; 212 inline bool is_old() const; 213 inline bool is_affiliated() const; 214 215 // Macro-properties: 216 bool is_alloc_allowed() const { auto cur_state = state(); return is_empty_state(cur_state) || cur_state == _regular || cur_state == _pinned; } 217 bool is_stw_move_allowed() const { auto cur_state = state(); return cur_state == _regular || cur_state == _cset || (ShenandoahHumongousMoves && cur_state == _humongous_start); } 218 219 RegionState state() const { return Atomic::load(&_state); } 220 int state_ordinal() const { return region_state_to_ordinal(state()); } 221 222 void record_pin(); 223 void record_unpin(); 224 size_t pin_count() const; 225 226 private: 227 static size_t RegionCount; 228 static size_t RegionSizeBytes; 229 static size_t RegionSizeWords; 230 static size_t RegionSizeBytesShift; 231 static size_t RegionSizeWordsShift; 232 static size_t RegionSizeBytesMask; 233 static size_t RegionSizeWordsMask; 234 static size_t MaxTLABSizeBytes; 235 static size_t MaxTLABSizeWords; 236 237 // Never updated fields 238 size_t const _index; 239 HeapWord* const _bottom; 240 HeapWord* const _end; 241 242 // Rarely updated fields 243 HeapWord* _new_top; 244 double _empty_time; 245 246 HeapWord* _top_before_promoted; 247 248 // Seldom updated fields 249 volatile RegionState _state; 250 HeapWord* _coalesce_and_fill_boundary; // for old regions not selected as collection set candidates. 251 252 // Frequently updated fields 253 HeapWord* _top; 254 255 size_t _tlab_allocs; 256 size_t _gclab_allocs; 257 size_t _plab_allocs; 258 259 volatile size_t _live_data; 260 volatile size_t _critical_pins; 261 262 HeapWord* volatile _update_watermark; 263 264 uint _age; 265 CENSUS_NOISE(uint _youth;) // tracks epochs of retrograde ageing (rejuvenation) 266 267 ShenandoahSharedFlag _recycling; // Used to indicate that the region is being recycled; see try_recycle*(). 268 269 bool _needs_bitmap_reset; 270 271 public: 272 ShenandoahHeapRegion(HeapWord* start, size_t index, bool committed); 273 274 static const size_t MIN_NUM_REGIONS = 10; 275 276 // Return adjusted max heap size 277 static size_t setup_sizes(size_t max_heap_size); 278 279 double empty_time() { 280 return _empty_time; 281 } 282 283 inline static size_t required_regions(size_t bytes) { 284 return (bytes + ShenandoahHeapRegion::region_size_bytes() - 1) >> ShenandoahHeapRegion::region_size_bytes_shift(); 285 } 286 287 inline static bool requires_humongous(size_t words) { 288 return words > ShenandoahHeapRegion::RegionSizeWords; 289 } 290 291 inline static size_t region_count() { 292 return ShenandoahHeapRegion::RegionCount; 293 } 294 295 inline static size_t region_size_bytes() { 296 return ShenandoahHeapRegion::RegionSizeBytes; 297 } 298 299 inline static size_t region_size_words() { 300 return ShenandoahHeapRegion::RegionSizeWords; 301 } 302 303 inline static size_t region_size_bytes_shift() { 304 return ShenandoahHeapRegion::RegionSizeBytesShift; 305 } 306 307 inline static size_t region_size_words_shift() { 308 return ShenandoahHeapRegion::RegionSizeWordsShift; 309 } 310 311 inline static size_t region_size_bytes_mask() { 312 return ShenandoahHeapRegion::RegionSizeBytesMask; 313 } 314 315 inline static size_t region_size_words_mask() { 316 return ShenandoahHeapRegion::RegionSizeWordsMask; 317 } 318 319 // Convert to jint with sanity checking 320 inline static jint region_size_bytes_jint() { 321 assert (ShenandoahHeapRegion::RegionSizeBytes <= (size_t)max_jint, "sanity"); 322 return (jint)ShenandoahHeapRegion::RegionSizeBytes; 323 } 324 325 // Convert to jint with sanity checking 326 inline static jint region_size_words_jint() { 327 assert (ShenandoahHeapRegion::RegionSizeWords <= (size_t)max_jint, "sanity"); 328 return (jint)ShenandoahHeapRegion::RegionSizeWords; 329 } 330 331 // Convert to jint with sanity checking 332 inline static jint region_size_bytes_shift_jint() { 333 assert (ShenandoahHeapRegion::RegionSizeBytesShift <= (size_t)max_jint, "sanity"); 334 return (jint)ShenandoahHeapRegion::RegionSizeBytesShift; 335 } 336 337 // Convert to jint with sanity checking 338 inline static jint region_size_words_shift_jint() { 339 assert (ShenandoahHeapRegion::RegionSizeWordsShift <= (size_t)max_jint, "sanity"); 340 return (jint)ShenandoahHeapRegion::RegionSizeWordsShift; 341 } 342 343 inline static size_t max_tlab_size_bytes() { 344 return ShenandoahHeapRegion::MaxTLABSizeBytes; 345 } 346 347 inline static size_t max_tlab_size_words() { 348 return ShenandoahHeapRegion::MaxTLABSizeWords; 349 } 350 351 inline size_t index() const { 352 return _index; 353 } 354 355 inline void save_top_before_promote(); 356 inline HeapWord* get_top_before_promote() const { return _top_before_promoted; } 357 inline void restore_top_before_promote(); 358 inline size_t garbage_before_padded_for_promote() const; 359 360 // If next available memory is not aligned on address that is multiple of alignment, fill the empty space 361 // so that returned object is aligned on an address that is a multiple of alignment_in_bytes. Requested 362 // size is in words. It is assumed that this->is_old(). A pad object is allocated, filled, and registered 363 // if necessary to assure the new allocation is properly aligned. Return nullptr if memory is not available. 364 inline HeapWord* allocate_aligned(size_t word_size, ShenandoahAllocRequest &req, size_t alignment_in_bytes); 365 366 // Allocation (return nullptr if full) 367 inline HeapWord* allocate(size_t word_size, const ShenandoahAllocRequest& req); 368 369 inline void clear_live_data(); 370 void set_live_data(size_t s); 371 372 // Increase live data for newly allocated region 373 inline void increase_live_data_alloc_words(size_t s); 374 375 // Increase live data for region scanned with GC 376 inline void increase_live_data_gc_words(size_t s); 377 378 inline bool has_live() const; 379 inline size_t get_live_data_bytes() const; 380 inline size_t get_live_data_words() const; 381 382 inline size_t garbage() const; 383 384 void print_on(outputStream* st) const; 385 386 void try_recycle_under_lock(); 387 388 void try_recycle(); 389 390 inline void begin_preemptible_coalesce_and_fill() { 391 _coalesce_and_fill_boundary = _bottom; 392 } 393 394 inline void end_preemptible_coalesce_and_fill() { 395 _coalesce_and_fill_boundary = _end; 396 } 397 398 inline void suspend_coalesce_and_fill(HeapWord* next_focus) { 399 _coalesce_and_fill_boundary = next_focus; 400 } 401 402 inline HeapWord* resume_coalesce_and_fill() { 403 return _coalesce_and_fill_boundary; 404 } 405 406 // Coalesce contiguous spans of garbage objects by filling header and registering start locations with remembered set. 407 // This is used by old-gen GC following concurrent marking to make old-gen HeapRegions parsable. Old regions must be 408 // parsable because the mark bitmap is not reliable during the concurrent old mark. 409 // Return true iff region is completely coalesced and filled. Returns false if cancelled before task is complete. 410 bool oop_coalesce_and_fill(bool cancellable); 411 412 // Invoke closure on every reference contained within the humongous object that spans this humongous 413 // region if the reference is contained within a DIRTY card and the reference is no more than words following 414 // start within the humongous object. 415 void oop_iterate_humongous_slice_dirty(OopIterateClosure* cl, HeapWord* start, size_t words, bool write_table) const; 416 417 // Invoke closure on every reference contained within the humongous object starting from start and 418 // ending at start + words. 419 void oop_iterate_humongous_slice_all(OopIterateClosure* cl, HeapWord* start, size_t words) const; 420 421 HeapWord* block_start(const void* p) const; 422 size_t block_size(const HeapWord* p) const; 423 bool block_is_obj(const HeapWord* p) const { return p < top(); } 424 425 // Find humongous start region that this region belongs to 426 ShenandoahHeapRegion* humongous_start_region() const; 427 428 HeapWord* top() const { return _top; } 429 void set_top(HeapWord* v) { _top = v; } 430 431 HeapWord* new_top() const { return _new_top; } 432 void set_new_top(HeapWord* v) { _new_top = v; } 433 434 HeapWord* bottom() const { return _bottom; } 435 HeapWord* end() const { return _end; } 436 437 size_t capacity() const { return byte_size(bottom(), end()); } 438 size_t used() const { return byte_size(bottom(), top()); } 439 size_t used_before_promote() const { return byte_size(bottom(), get_top_before_promote()); } 440 size_t free() const { return byte_size(top(), end()); } 441 442 // Does this region contain this address? 443 bool contains(HeapWord* p) const { 444 return (bottom() <= p) && (p < top()); 445 } 446 447 inline void adjust_alloc_metadata(ShenandoahAllocRequest::Type type, size_t); 448 void reset_alloc_metadata(); 449 size_t get_shared_allocs() const; 450 size_t get_tlab_allocs() const; 451 size_t get_gclab_allocs() const; 452 size_t get_plab_allocs() const; 453 454 inline HeapWord* get_update_watermark() const; 455 inline void set_update_watermark(HeapWord* w); 456 inline void set_update_watermark_at_safepoint(HeapWord* w); 457 458 inline ShenandoahAffiliation affiliation() const; 459 inline const char* affiliation_name() const; 460 461 void set_affiliation(ShenandoahAffiliation new_affiliation); 462 463 // Region ageing and rejuvenation 464 uint age() const { return _age; } 465 CENSUS_NOISE(uint youth() const { return _youth; }) 466 467 void increment_age() { 468 const uint max_age = markWord::max_age; 469 assert(_age <= max_age, "Error"); 470 if (_age++ >= max_age) { 471 _age = max_age; // clamp 472 } 473 } 474 475 void reset_age() { 476 CENSUS_NOISE(_youth += _age;) 477 _age = 0; 478 } 479 480 CENSUS_NOISE(void clear_youth() { _youth = 0; }) 481 482 inline bool need_bitmap_reset() const { 483 return _needs_bitmap_reset; 484 } 485 486 inline void set_needs_bitmap_reset() { 487 _needs_bitmap_reset = true; 488 } 489 490 inline void unset_needs_bitmap_reset() { 491 _needs_bitmap_reset = false; 492 } 493 494 private: 495 void decrement_humongous_waste() const; 496 void do_commit(); 497 void do_uncommit(); 498 499 inline void internal_increase_live_data(size_t s); 500 501 void set_state(RegionState to); 502 }; 503 504 #endif // SHARE_GC_SHENANDOAH_SHENANDOAHHEAPREGION_HPP