src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp
changeset 52925 9c18c9d839d3
child 53244 9807daeb47c4
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp	Mon Dec 10 15:47:44 2018 +0100
@@ -0,0 +1,431 @@
+/*
+ * Copyright (c) 2013, 2018, Red Hat, Inc. All rights reserved.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_GC_SHENANDOAH_SHENANDOAHHEAPREGION_HPP
+#define SHARE_VM_GC_SHENANDOAH_SHENANDOAHHEAPREGION_HPP
+
+#include "gc/shared/space.hpp"
+#include "gc/shenandoah/shenandoahAllocRequest.hpp"
+#include "gc/shenandoah/shenandoahAsserts.hpp"
+#include "gc/shenandoah/shenandoahHeap.hpp"
+#include "gc/shenandoah/shenandoahPacer.hpp"
+#include "memory/universe.hpp"
+#include "utilities/sizes.hpp"
+
+class VMStructs;
+
+class ShenandoahHeapRegion : public ContiguousSpace {
+  friend class VMStructs;
+private:
+  /*
+    Region state is described by a state machine. Transitions are guarded by
+    heap lock, which allows changing the state of several regions atomically.
+    Region states can be logically aggregated in groups.
+
+      "Empty":
+      .................................................................
+      .                                                               .
+      .                                                               .
+      .         Uncommitted  <-------  Committed <------------------------\
+      .              |                     |                          .   |
+      .              \---------v-----------/                          .   |
+      .                        |                                      .   |
+      .........................|.......................................   |
+                               |                                          |
+      "Active":                |                                          |
+      .........................|.......................................   |
+      .                        |                                      .   |
+      .      /-----------------^-------------------\                  .   |
+      .      |                                     |                  .   |
+      .      v                                     v    "Humongous":  .   |
+      .   Regular ---\-----\     ..................O................  .   |
+      .     |  ^     |     |     .                 |               .  .   |
+      .     |  |     |     |     .                 *---------\     .  .   |
+      .     v  |     |     |     .                 v         v     .  .   |
+      .    Pinned  Cset    |     .  HStart <--> H/Start   H/Cont   .  .   |
+      .       ^    / |     |     .  Pinned         v         |     .  .   |
+      .       |   /  |     |     .                 *<--------/     .  .   |
+      .       |  v   |     |     .                 |               .  .   |
+      .  CsetPinned  |     |     ..................O................  .   |
+      .              |     |                       |                  .   |
+      .              \-----\---v-------------------/                  .   |
+      .                        |                                      .   |
+      .........................|.......................................   |
+                               |                                          |
+      "Trash":                 |                                          |
+      .........................|.......................................   |
+      .                        |                                      .   |
+      .                        v                                      .   |
+      .                      Trash ---------------------------------------/
+      .                                                               .
+      .                                                               .
+      .................................................................
+
+    Transition from "Empty" to "Active" is first allocation. It can go from {Uncommitted, Committed}
+    to {Regular, "Humongous"}. The allocation may happen in Regular regions too, but not in Humongous.
+
+    Transition from "Active" to "Trash" is reclamation. It can go from CSet during the normal cycle,
+    and from {Regular, "Humongous"} for immediate reclamation. The existence of Trash state allows
+    quick reclamation without actual cleaning up.
+
+    Transition from "Trash" to "Empty" is recycling. It cleans up the regions and corresponding metadata.
+    Can be done asynchronously and in bulk.
+
+    Note how internal transitions disallow logic bugs:
+      a) No region can go Empty, unless properly reclaimed/recycled;
+      b) No region can go Uncommitted, unless reclaimed/recycled first;
+      c) Only Regular regions can go to CSet;
+      d) Pinned cannot go Trash, thus it could never be reclaimed until unpinned;
+      e) Pinned cannot go CSet, thus it never moves;
+      f) Humongous cannot be used for regular allocations;
+      g) Humongous cannot go CSet, thus it never moves;
+      h) Humongous start can go pinned, and thus can be protected from moves (humongous continuations should
+         follow associated humongous starts, not pinnable/movable by themselves);
+      i) Empty cannot go Trash, avoiding useless work;
+      j) ...
+   */
+
+  enum RegionState {
+    _empty_uncommitted,       // region is empty and has memory uncommitted
+    _empty_committed,         // region is empty and has memory committed
+    _regular,                 // region is for regular allocations
+    _humongous_start,         // region is the humongous start
+    _humongous_cont,          // region is the humongous continuation
+    _pinned_humongous_start,  // region is both humongous start and pinned
+    _cset,                    // region is in collection set
+    _pinned,                  // region is pinned
+    _pinned_cset,             // region is pinned and in cset (evac failure path)
+    _trash,                   // region contains only trash
+  };
+
+  const char* region_state_to_string(RegionState s) const {
+    switch (s) {
+      case _empty_uncommitted:       return "Empty Uncommitted";
+      case _empty_committed:         return "Empty Committed";
+      case _regular:                 return "Regular";
+      case _humongous_start:         return "Humongous Start";
+      case _humongous_cont:          return "Humongous Continuation";
+      case _pinned_humongous_start:  return "Humongous Start, Pinned";
+      case _cset:                    return "Collection Set";
+      case _pinned:                  return "Pinned";
+      case _pinned_cset:             return "Collection Set, Pinned";
+      case _trash:                   return "Trash";
+      default:
+        ShouldNotReachHere();
+        return "";
+    }
+  }
+
+  // This method protects from accidental changes in enum order:
+  int region_state_to_ordinal(RegionState s) const {
+    switch (s) {
+      case _empty_uncommitted:      return 0;
+      case _empty_committed:        return 1;
+      case _regular:                return 2;
+      case _humongous_start:        return 3;
+      case _humongous_cont:         return 4;
+      case _cset:                   return 5;
+      case _pinned:                 return 6;
+      case _trash:                  return 7;
+      case _pinned_cset:            return 8;
+      case _pinned_humongous_start: return 9;
+      default:
+        ShouldNotReachHere();
+        return -1;
+    }
+  }
+
+  void report_illegal_transition(const char* method);
+
+public:
+  // Allowed transitions from the outside code:
+  void make_regular_allocation();
+  void make_regular_bypass();
+  void make_humongous_start();
+  void make_humongous_cont();
+  void make_humongous_start_bypass();
+  void make_humongous_cont_bypass();
+  void make_pinned();
+  void make_unpinned();
+  void make_cset();
+  void make_trash();
+  void make_trash_immediate();
+  void make_empty();
+  void make_uncommitted();
+  void make_committed_bypass();
+
+  // Individual states:
+  bool is_empty_uncommitted()      const { return _state == _empty_uncommitted; }
+  bool is_empty_committed()        const { return _state == _empty_committed; }
+  bool is_regular()                const { return _state == _regular; }
+  bool is_humongous_continuation() const { return _state == _humongous_cont; }
+
+  // Participation in logical groups:
+  bool is_empty()                  const { return is_empty_committed() || is_empty_uncommitted(); }
+  bool is_active()                 const { return !is_empty() && !is_trash(); }
+  bool is_trash()                  const { return _state == _trash; }
+  bool is_humongous_start()        const { return _state == _humongous_start || _state == _pinned_humongous_start; }
+  bool is_humongous()              const { return is_humongous_start() || is_humongous_continuation(); }
+  bool is_committed()              const { return !is_empty_uncommitted(); }
+  bool is_cset()                   const { return _state == _cset   || _state == _pinned_cset; }
+  bool is_pinned()                 const { return _state == _pinned || _state == _pinned_cset || _state == _pinned_humongous_start; }
+
+  // Macro-properties:
+  bool is_alloc_allowed()          const { return is_empty() || is_regular() || _state == _pinned; }
+  bool is_move_allowed()           const { return is_regular() || _state == _cset || (ShenandoahHumongousMoves && _state == _humongous_start); }
+
+  RegionState state()              const { return _state; }
+  int  state_ordinal()             const { return region_state_to_ordinal(_state); }
+
+private:
+  static size_t RegionCount;
+  static size_t RegionSizeBytes;
+  static size_t RegionSizeWords;
+  static size_t RegionSizeBytesShift;
+  static size_t RegionSizeWordsShift;
+  static size_t RegionSizeBytesMask;
+  static size_t RegionSizeWordsMask;
+  static size_t HumongousThresholdBytes;
+  static size_t HumongousThresholdWords;
+  static size_t MaxTLABSizeBytes;
+  static size_t MaxTLABSizeWords;
+
+  // Global allocation counter, increased for each allocation under Shenandoah heap lock.
+  // Padded to avoid false sharing with the read-only fields above.
+  struct PaddedAllocSeqNum {
+    DEFINE_PAD_MINUS_SIZE(0, DEFAULT_CACHE_LINE_SIZE, sizeof(uint64_t));
+    uint64_t value;
+    DEFINE_PAD_MINUS_SIZE(1, DEFAULT_CACHE_LINE_SIZE, 0);
+
+    PaddedAllocSeqNum() {
+      // start with 1, reserve 0 for uninitialized value
+      value = 1;
+    }
+  };
+
+  static PaddedAllocSeqNum _alloc_seq_num;
+
+  // Never updated fields
+  ShenandoahHeap* _heap;
+  ShenandoahPacer* _pacer;
+  MemRegion _reserved;
+  size_t _region_number;
+
+  // Rarely updated fields
+  HeapWord* _new_top;
+  size_t _critical_pins;
+  double _empty_time;
+
+  // Seldom updated fields
+  RegionState _state;
+
+  // Frequently updated fields
+  size_t _tlab_allocs;
+  size_t _gclab_allocs;
+  size_t _shared_allocs;
+
+  uint64_t _seqnum_first_alloc_mutator;
+  uint64_t _seqnum_first_alloc_gc;
+  uint64_t _seqnum_last_alloc_mutator;
+  uint64_t _seqnum_last_alloc_gc;
+
+  volatile size_t _live_data;
+
+  // Claim some space at the end to protect next region
+  DEFINE_PAD_MINUS_SIZE(0, DEFAULT_CACHE_LINE_SIZE, 0);
+
+public:
+  ShenandoahHeapRegion(ShenandoahHeap* heap, HeapWord* start, size_t size_words, size_t index, bool committed);
+
+  static const size_t MIN_NUM_REGIONS = 10;
+
+  static void setup_sizes(size_t initial_heap_size, size_t max_heap_size);
+
+  double empty_time() {
+    return _empty_time;
+  }
+
+  inline static size_t required_regions(size_t bytes) {
+    return (bytes + ShenandoahHeapRegion::region_size_bytes() - 1) >> ShenandoahHeapRegion::region_size_bytes_shift();
+  }
+
+  inline static size_t region_count() {
+    return ShenandoahHeapRegion::RegionCount;
+  }
+
+  inline static size_t region_size_bytes() {
+    return ShenandoahHeapRegion::RegionSizeBytes;
+  }
+
+  inline static size_t region_size_words() {
+    return ShenandoahHeapRegion::RegionSizeWords;
+  }
+
+  inline static size_t region_size_bytes_shift() {
+    return ShenandoahHeapRegion::RegionSizeBytesShift;
+  }
+
+  inline static size_t region_size_words_shift() {
+    return ShenandoahHeapRegion::RegionSizeWordsShift;
+  }
+
+  inline static size_t region_size_bytes_mask() {
+    return ShenandoahHeapRegion::RegionSizeBytesMask;
+  }
+
+  inline static size_t region_size_words_mask() {
+    return ShenandoahHeapRegion::RegionSizeWordsMask;
+  }
+
+  // Convert to jint with sanity checking
+  inline static jint region_size_bytes_jint() {
+    assert (ShenandoahHeapRegion::RegionSizeBytes <= (size_t)max_jint, "sanity");
+    return (jint)ShenandoahHeapRegion::RegionSizeBytes;
+  }
+
+  // Convert to jint with sanity checking
+  inline static jint region_size_words_jint() {
+    assert (ShenandoahHeapRegion::RegionSizeWords <= (size_t)max_jint, "sanity");
+    return (jint)ShenandoahHeapRegion::RegionSizeWords;
+  }
+
+  // Convert to jint with sanity checking
+  inline static jint region_size_bytes_shift_jint() {
+    assert (ShenandoahHeapRegion::RegionSizeBytesShift <= (size_t)max_jint, "sanity");
+    return (jint)ShenandoahHeapRegion::RegionSizeBytesShift;
+  }
+
+  // Convert to jint with sanity checking
+  inline static jint region_size_words_shift_jint() {
+    assert (ShenandoahHeapRegion::RegionSizeWordsShift <= (size_t)max_jint, "sanity");
+    return (jint)ShenandoahHeapRegion::RegionSizeWordsShift;
+  }
+
+  inline static size_t humongous_threshold_bytes() {
+    return ShenandoahHeapRegion::HumongousThresholdBytes;
+  }
+
+  inline static size_t humongous_threshold_words() {
+    return ShenandoahHeapRegion::HumongousThresholdWords;
+  }
+
+  inline static size_t max_tlab_size_bytes() {
+    return ShenandoahHeapRegion::MaxTLABSizeBytes;
+  }
+
+  inline static size_t max_tlab_size_words() {
+    return ShenandoahHeapRegion::MaxTLABSizeWords;
+  }
+
+  static uint64_t seqnum_current_alloc() {
+    // Last used seq number
+    return _alloc_seq_num.value - 1;
+  }
+
+  size_t region_number() const;
+
+  // Allocation (return NULL if full)
+  inline HeapWord* allocate(size_t word_size, ShenandoahAllocRequest::Type type);
+
+  HeapWord* allocate(size_t word_size) shenandoah_not_implemented_return(NULL)
+
+  void clear_live_data();
+  void set_live_data(size_t s);
+
+  // Increase live data for newly allocated region
+  inline void increase_live_data_alloc_words(size_t s);
+
+  // Increase live data for region scanned with GC
+  inline void increase_live_data_gc_words(size_t s);
+
+  bool has_live() const;
+  size_t get_live_data_bytes() const;
+  size_t get_live_data_words() const;
+
+  void print_on(outputStream* st) const;
+
+  size_t garbage() const;
+
+  void recycle();
+
+  void oop_iterate(OopIterateClosure* cl);
+
+  HeapWord* block_start_const(const void* p) const;
+
+  bool in_collection_set() const;
+
+  // Find humongous start region that this region belongs to
+  ShenandoahHeapRegion* humongous_start_region() const;
+
+  CompactibleSpace* next_compaction_space() const shenandoah_not_implemented_return(NULL);
+  void prepare_for_compaction(CompactPoint* cp)   shenandoah_not_implemented;
+  void adjust_pointers()                          shenandoah_not_implemented;
+  void compact()                                  shenandoah_not_implemented;
+
+  void set_new_top(HeapWord* new_top) { _new_top = new_top; }
+  HeapWord* new_top() const { return _new_top; }
+
+  inline void adjust_alloc_metadata(ShenandoahAllocRequest::Type type, size_t);
+  void reset_alloc_metadata_to_shared();
+  void reset_alloc_metadata();
+  size_t get_shared_allocs() const;
+  size_t get_tlab_allocs() const;
+  size_t get_gclab_allocs() const;
+
+  uint64_t seqnum_first_alloc() const {
+    if (_seqnum_first_alloc_mutator == 0) return _seqnum_first_alloc_gc;
+    if (_seqnum_first_alloc_gc == 0)      return _seqnum_first_alloc_mutator;
+    return MIN2(_seqnum_first_alloc_mutator, _seqnum_first_alloc_gc);
+  }
+
+  uint64_t seqnum_last_alloc() const {
+    return MAX2(_seqnum_last_alloc_mutator, _seqnum_last_alloc_gc);
+  }
+
+  uint64_t seqnum_first_alloc_mutator() const {
+    return _seqnum_first_alloc_mutator;
+  }
+
+  uint64_t seqnum_last_alloc_mutator()  const {
+    return _seqnum_last_alloc_mutator;
+  }
+
+  uint64_t seqnum_first_alloc_gc() const {
+    return _seqnum_first_alloc_gc;
+  }
+
+  uint64_t seqnum_last_alloc_gc()  const {
+    return _seqnum_last_alloc_gc;
+  }
+
+private:
+  void do_commit();
+  void do_uncommit();
+
+  void oop_iterate_objects(OopIterateClosure* cl);
+  void oop_iterate_humongous(OopIterateClosure* cl);
+
+  inline void internal_increase_live_data(size_t s);
+};
+
+#endif // SHARE_VM_GC_SHENANDOAH_SHENANDOAHHEAPREGION_HPP