1 /*
   2  * Copyright (c) 2013, 2019, Red Hat, Inc. All rights reserved.
   3  *
   4  * This code is free software; you can redistribute it and/or modify it
   5  * under the terms of the GNU General Public License version 2 only, as
   6  * published by the Free Software Foundation.
   7  *
   8  * This code is distributed in the hope that it will be useful, but WITHOUT
   9  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  10  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  11  * version 2 for more details (a copy is included in the LICENSE file that
  12  * accompanied this code).
  13  *
  14  * You should have received a copy of the GNU General Public License version
  15  * 2 along with this work; if not, write to the Free Software Foundation,
  16  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  17  *
  18  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  19  * or visit www.oracle.com if you need additional information or have any
  20  * questions.
  21  *
  22  */
  23 
  24 #ifndef SHARE_VM_GC_SHENANDOAH_SHENANDOAHHEAPREGION_HPP
  25 #define SHARE_VM_GC_SHENANDOAH_SHENANDOAHHEAPREGION_HPP
  26 
  27 #include "gc_implementation/shenandoah/shenandoahAllocRequest.hpp"
  28 #include "gc_implementation/shenandoah/shenandoahAsserts.hpp"
  29 #include "gc_implementation/shenandoah/shenandoahHeap.hpp"
  30 #include "gc_implementation/shenandoah/shenandoahPacer.hpp"
  31 #include "gc_implementation/shenandoah/shenandoahPadding.hpp"
  32 
  33 class VMStructs;
  34 class ShenandoahHeapRegionStateConstant;
  35 
  36 class ShenandoahHeapRegion {
  37   friend class VMStructs;
  38   friend class ShenandoahHeapRegionStateConstant;
  39 private:
  40   /*
  41     Region state is described by a state machine. Transitions are guarded by
  42     heap lock, which allows changing the state of several regions atomically.
  43     Region states can be logically aggregated in groups.
  44 
  45       "Empty":
  46       .................................................................
  47       .                                                               .
  48       .                                                               .
  49       .         Uncommitted  <-------  Committed <------------------------\
  50       .              |                     |                          .   |
  51       .              \---------v-----------/                          .   |
  52       .                        |                                      .   |
  53       .........................|.......................................   |
  54                                |                                          |
  55       "Active":                |                                          |
  56       .........................|.......................................   |
  57       .                        |                                      .   |
  58       .      /-----------------^-------------------\                  .   |
  59       .      |                                     |                  .   |
  60       .      v                                     v    "Humongous":  .   |
  61       .   Regular ---\-----\     ..................O................  .   |
  62       .     |  ^     |     |     .                 |               .  .   |
  63       .     |  |     |     |     .                 *---------\     .  .   |
  64       .     v  |     |     |     .                 v         v     .  .   |
  65       .    Pinned  Cset    |     .  HStart <--> H/Start   H/Cont   .  .   |
  66       .       ^    / |     |     .  Pinned         v         |     .  .   |
  67       .       |   /  |     |     .                 *<--------/     .  .   |
  68       .       |  v   |     |     .                 |               .  .   |
  69       .  CsetPinned  |     |     ..................O................  .   |
  70       .              |     |                       |                  .   |
  71       .              \-----\---v-------------------/                  .   |
  72       .                        |                                      .   |
  73       .........................|.......................................   |
  74                                |                                          |
  75       "Trash":                 |                                          |
  76       .........................|.......................................   |
  77       .                        |                                      .   |
  78       .                        v                                      .   |
  79       .                      Trash ---------------------------------------/
  80       .                                                               .
  81       .                                                               .
  82       .................................................................
  83 
  84     Transition from "Empty" to "Active" is first allocation. It can go from {Uncommitted, Committed}
  85     to {Regular, "Humongous"}. The allocation may happen in Regular regions too, but not in Humongous.
  86 
  87     Transition from "Active" to "Trash" is reclamation. It can go from CSet during the normal cycle,
  88     and from {Regular, "Humongous"} for immediate reclamation. The existence of Trash state allows
  89     quick reclamation without actual cleaning up.
  90 
  91     Transition from "Trash" to "Empty" is recycling. It cleans up the regions and corresponding metadata.
  92     Can be done asynchronously and in bulk.
  93 
  94     Note how internal transitions disallow logic bugs:
  95       a) No region can go Empty, unless properly reclaimed/recycled;
  96       b) No region can go Uncommitted, unless reclaimed/recycled first;
  97       c) Only Regular regions can go to CSet;
  98       d) Pinned cannot go Trash, thus it could never be reclaimed until unpinned;
  99       e) Pinned cannot go CSet, thus it never moves;
 100       f) Humongous cannot be used for regular allocations;
 101       g) Humongous cannot go CSet, thus it never moves;
 102       h) Humongous start can go pinned, and thus can be protected from moves (humongous continuations should
 103          follow associated humongous starts, not pinnable/movable by themselves);
 104       i) Empty cannot go Trash, avoiding useless work;
 105       j) ...
 106    */
 107 
 108   enum RegionState {
 109     _empty_uncommitted,       // region is empty and has memory uncommitted
 110     _empty_committed,         // region is empty and has memory committed
 111     _regular,                 // region is for regular allocations
 112     _humongous_start,         // region is the humongous start
 113     _humongous_cont,          // region is the humongous continuation
 114     _pinned_humongous_start,  // region is both humongous start and pinned
 115     _cset,                    // region is in collection set
 116     _pinned,                  // region is pinned
 117     _pinned_cset,             // region is pinned and in cset (evac failure path)
 118     _trash,                   // region contains only trash
 119     _REGION_STATES_NUM        // last
 120   };
 121 
 122   static const char* region_state_to_string(RegionState s) {
 123     switch (s) {
 124       case _empty_uncommitted:       return "Empty Uncommitted";
 125       case _empty_committed:         return "Empty Committed";
 126       case _regular:                 return "Regular";
 127       case _humongous_start:         return "Humongous Start";
 128       case _humongous_cont:          return "Humongous Continuation";
 129       case _pinned_humongous_start:  return "Humongous Start, Pinned";
 130       case _cset:                    return "Collection Set";
 131       case _pinned:                  return "Pinned";
 132       case _pinned_cset:             return "Collection Set, Pinned";
 133       case _trash:                   return "Trash";
 134       default:
 135         ShouldNotReachHere();
 136         return "";
 137     }
 138   }
 139 
 140   // This method protects from accidental changes in enum order:
 141   int region_state_to_ordinal(RegionState s) const {
 142     switch (s) {
 143       case _empty_uncommitted:      return 0;
 144       case _empty_committed:        return 1;
 145       case _regular:                return 2;
 146       case _humongous_start:        return 3;
 147       case _humongous_cont:         return 4;
 148       case _cset:                   return 5;
 149       case _pinned:                 return 6;
 150       case _trash:                  return 7;
 151       case _pinned_cset:            return 8;
 152       case _pinned_humongous_start: return 9;
 153       default:
 154         ShouldNotReachHere();
 155         return -1;
 156     }
 157   }
 158 
 159   void report_illegal_transition(const char* method);
 160 
 161 public:
 162   static const int region_states_num() {
 163     return _REGION_STATES_NUM;
 164   }
 165 
 166   // Allowed transitions from the outside code:
 167   void make_regular_allocation();
 168   void make_regular_bypass();
 169   void make_humongous_start();
 170   void make_humongous_cont();
 171   void make_humongous_start_bypass();
 172   void make_humongous_cont_bypass();
 173   void make_pinned();
 174   void make_unpinned();
 175   void make_cset();
 176   void make_trash();
 177   void make_trash_immediate();
 178   void make_empty();
 179   void make_uncommitted();
 180   void make_committed_bypass();
 181 
 182   // Individual states:
 183   bool is_empty_uncommitted()      const { return _state == _empty_uncommitted; }
 184   bool is_empty_committed()        const { return _state == _empty_committed; }
 185   bool is_regular()                const { return _state == _regular; }
 186   bool is_humongous_continuation() const { return _state == _humongous_cont; }
 187 
 188   // Participation in logical groups:
 189   bool is_empty()                  const { return is_empty_committed() || is_empty_uncommitted(); }
 190   bool is_active()                 const { return !is_empty() && !is_trash(); }
 191   bool is_trash()                  const { return _state == _trash; }
 192   bool is_humongous_start()        const { return _state == _humongous_start || _state == _pinned_humongous_start; }
 193   bool is_humongous()              const { return is_humongous_start() || is_humongous_continuation(); }
 194   bool is_committed()              const { return !is_empty_uncommitted(); }
 195   bool is_cset()                   const { return _state == _cset   || _state == _pinned_cset; }
 196   bool is_pinned()                 const { return _state == _pinned || _state == _pinned_cset || _state == _pinned_humongous_start; }
 197 
 198   // Macro-properties:
 199   bool is_alloc_allowed()          const { return is_empty() || is_regular() || _state == _pinned; }
 200   bool is_stw_move_allowed()       const { return is_regular() || _state == _cset || (ShenandoahHumongousMoves && _state == _humongous_start); }
 201 
 202   RegionState state()              const { return _state; }
 203   int  state_ordinal()             const { return region_state_to_ordinal(_state); }
 204 
 205   void record_pin();
 206   void record_unpin();
 207   size_t pin_count() const;
 208 
 209 private:
 210   static size_t RegionCount;
 211   static size_t RegionSizeBytes;
 212   static size_t RegionSizeWords;
 213   static size_t RegionSizeBytesShift;
 214   static size_t RegionSizeWordsShift;
 215   static size_t RegionSizeBytesMask;
 216   static size_t RegionSizeWordsMask;
 217   static size_t HumongousThresholdBytes;
 218   static size_t HumongousThresholdWords;
 219   static size_t MaxTLABSizeBytes;
 220   static size_t MaxTLABSizeWords;
 221 
 222   // Never updated fields
 223   size_t const _index;
 224   HeapWord* const _bottom;
 225   HeapWord* const _end;
 226 
 227   // Rarely updated fields
 228   HeapWord* _new_top;
 229   double _empty_time;
 230 
 231   // Seldom updated fields
 232   RegionState _state;
 233 
 234   // Frequently updated fields
 235   HeapWord* _top;
 236 
 237   size_t _tlab_allocs;
 238   size_t _gclab_allocs;
 239 
 240   volatile jint _live_data;
 241   volatile jint _critical_pins;
 242 
 243   HeapWord* volatile _update_watermark;
 244 
 245 public:
 246   ShenandoahHeapRegion(HeapWord* start, size_t index, bool committed);
 247 
 248   static const size_t MIN_NUM_REGIONS = 10;
 249 
 250   // Return adjusted max heap size
 251   static size_t setup_sizes(size_t max_heap_size);
 252 
 253   double empty_time() {
 254     return _empty_time;
 255   }
 256 
 257   inline static size_t required_regions(size_t bytes) {
 258     return (bytes + ShenandoahHeapRegion::region_size_bytes() - 1) >> ShenandoahHeapRegion::region_size_bytes_shift();
 259   }
 260 
 261   inline static size_t region_count() {
 262     return ShenandoahHeapRegion::RegionCount;
 263   }
 264 
 265   inline static size_t region_size_bytes() {
 266     return ShenandoahHeapRegion::RegionSizeBytes;
 267   }
 268 
 269   inline static size_t region_size_words() {
 270     return ShenandoahHeapRegion::RegionSizeWords;
 271   }
 272 
 273   inline static size_t region_size_bytes_shift() {
 274     return ShenandoahHeapRegion::RegionSizeBytesShift;
 275   }
 276 
 277   inline static size_t region_size_words_shift() {
 278     return ShenandoahHeapRegion::RegionSizeWordsShift;
 279   }
 280 
 281   inline static size_t region_size_bytes_mask() {
 282     return ShenandoahHeapRegion::RegionSizeBytesMask;
 283   }
 284 
 285   inline static size_t region_size_words_mask() {
 286     return ShenandoahHeapRegion::RegionSizeWordsMask;
 287   }
 288 
 289   // Convert to jint with sanity checking
 290   inline static jint region_size_bytes_jint() {
 291     assert (ShenandoahHeapRegion::RegionSizeBytes <= (size_t)max_jint, "sanity");
 292     return (jint)ShenandoahHeapRegion::RegionSizeBytes;
 293   }
 294 
 295   // Convert to jint with sanity checking
 296   inline static jint region_size_words_jint() {
 297     assert (ShenandoahHeapRegion::RegionSizeWords <= (size_t)max_jint, "sanity");
 298     return (jint)ShenandoahHeapRegion::RegionSizeWords;
 299   }
 300 
 301   // Convert to jint with sanity checking
 302   inline static jint region_size_bytes_shift_jint() {
 303     assert (ShenandoahHeapRegion::RegionSizeBytesShift <= (size_t)max_jint, "sanity");
 304     return (jint)ShenandoahHeapRegion::RegionSizeBytesShift;
 305   }
 306 
 307   // Convert to jint with sanity checking
 308   inline static jint region_size_words_shift_jint() {
 309     assert (ShenandoahHeapRegion::RegionSizeWordsShift <= (size_t)max_jint, "sanity");
 310     return (jint)ShenandoahHeapRegion::RegionSizeWordsShift;
 311   }
 312 
 313   inline static size_t humongous_threshold_bytes() {
 314     return ShenandoahHeapRegion::HumongousThresholdBytes;
 315   }
 316 
 317   inline static size_t humongous_threshold_words() {
 318     return ShenandoahHeapRegion::HumongousThresholdWords;
 319   }
 320 
 321   inline static size_t max_tlab_size_bytes() {
 322     return ShenandoahHeapRegion::MaxTLABSizeBytes;
 323   }
 324 
 325   inline static size_t max_tlab_size_words() {
 326     return ShenandoahHeapRegion::MaxTLABSizeWords;
 327   }
 328 
 329   inline size_t index() const {
 330     return _index;
 331   }
 332 
 333   // Allocation (return NULL if full)
 334   inline HeapWord* allocate(size_t word_size, ShenandoahAllocRequest::Type type);
 335 
 336   inline void clear_live_data();
 337   void set_live_data(size_t s);
 338 
 339   // Increase live data for newly allocated region
 340   inline void increase_live_data_alloc_words(size_t s);
 341 
 342   // Increase live data for region scanned with GC
 343   inline void increase_live_data_gc_words(size_t s);
 344 
 345   inline bool has_live() const;
 346   inline size_t get_live_data_bytes() const;
 347   inline size_t get_live_data_words() const;
 348 
 349   inline size_t garbage() const;
 350 
 351   void print_on(outputStream* st) const;
 352 
 353   void recycle();
 354 
 355   HeapWord* block_start(const void* p) const;
 356   size_t block_size(const HeapWord* p) const;
 357   bool block_is_obj(const HeapWord* p) const { return p < top(); }
 358 
 359   // Find humongous start region that this region belongs to
 360   ShenandoahHeapRegion* humongous_start_region() const;
 361 
 362   HeapWord* top() const         { return _top;     }
 363   void set_top(HeapWord* v)     { _top = v;        }
 364 
 365   HeapWord* new_top() const     { return _new_top; }
 366   void set_new_top(HeapWord* v) { _new_top = v;    }
 367 
 368   HeapWord* bottom() const      { return _bottom;  }
 369   HeapWord* end() const         { return _end;     }
 370 
 371   size_t capacity() const       { return byte_size(bottom(), end()); }
 372   size_t used() const           { return byte_size(bottom(), top()); }
 373   size_t free() const           { return byte_size(top(),    end()); }
 374 
 375   inline void adjust_alloc_metadata(ShenandoahAllocRequest::Type type, size_t);
 376   void reset_alloc_metadata();
 377   size_t get_shared_allocs() const;
 378   size_t get_tlab_allocs() const;
 379   size_t get_gclab_allocs() const;
 380 
 381   inline HeapWord* get_update_watermark() const;
 382   inline void set_update_watermark(HeapWord* w);
 383   inline void set_update_watermark_at_safepoint(HeapWord* w);
 384 
 385 private:
 386   void do_commit();
 387   void do_uncommit();
 388 
 389   inline void internal_increase_live_data(size_t s);
 390 
 391   void set_state(RegionState to);
 392 };
 393 
 394 #endif // SHARE_VM_GC_SHENANDOAH_SHENANDOAHHEAPREGION_HPP