1 /*
   2  * Copyright (c) 2013, 2015, Red Hat, Inc. and/or its affiliates.
   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 #include "gc/shenandoah/shenandoahHeap.hpp"
  25 #include "gc/shenandoah/shenandoahHeapRegionSet.hpp"
  26 #include "gc/shenandoah/shenandoahHeapRegion.inline.hpp"
  27 #include "utilities/quickSort.hpp"
  28 
  29 ShenandoahHeapRegionSet::ShenandoahHeapRegionSet(size_t max_regions):
  30   _reserved_end(max_regions),
  31   _active_end(0),
  32   _regions(NEW_C_HEAP_ARRAY(ShenandoahHeapRegion*, max_regions, mtGC)),
  33   _current_index(0)
  34 {
  35 }
  36 
  37 ShenandoahHeapRegionSet::~ShenandoahHeapRegionSet() {
  38   FREE_C_HEAP_ARRAY(ShenandoahHeapRegion*, _regions);
  39 }
  40 
  41 class PrintHeapRegionClosure : public ShenandoahHeapRegionClosure {
  42  public:
  43   bool doHeapRegion(ShenandoahHeapRegion* r) {
  44     r->print();
  45     return false;
  46   }
  47 };
  48 
  49 class PrintHeapRegionSummaryClosure : public ShenandoahHeapRegionClosure {
  50  public:
  51   bool doHeapRegion(ShenandoahHeapRegion* r) {
  52     tty->print(""SIZE_FORMAT, r->region_number());
  53     return false;
  54   }
  55 };
  56 
  57 
  58 size_t ShenandoahHeapRegionSet::count() const {
  59   return _active_end - _current_index;
  60 }
  61 
  62 void ShenandoahHeapRegionSet::clear() {
  63   _active_end = 0;
  64   _current_index = 0;
  65 }
  66 
  67 void ShenandoahHeapRegionSet::add_region(ShenandoahHeapRegion* r) {
  68   if (_active_end < _reserved_end) {
  69     _regions[_active_end] = r;
  70     _active_end++;
  71   }
  72 }
  73 
  74 void ShenandoahHeapRegionSet::add_region_check_for_duplicates(ShenandoahHeapRegion* r) {
  75   // FIXME There's a bug where the zeroth region is not checked, so check it here
  76   if (_active_end < _reserved_end && !contains(r) && _regions[0] != r) {
  77     _regions[_active_end] = r;
  78     _active_end++;
  79   }
  80 }
  81 
  82 // Apply blk->doHeapRegion() on all committed regions in address order,
  83 // terminating the iteration early if doHeapRegion() returns true.
  84 void ShenandoahHeapRegionSet::active_heap_region_iterate(ShenandoahHeapRegionClosure* blk,
  85                                                   bool skip_dirty_regions,
  86                                                   bool skip_humongous_continuation) const {
  87   size_t i;
  88   for (i = 0; i < _active_end; i++) {
  89     ShenandoahHeapRegion* current = _regions[i];
  90     assert(current->region_number() <= _reserved_end, "Tautology");
  91 
  92     if (skip_humongous_continuation && current->is_humongous_continuation()) {
  93       continue;
  94     }
  95     if (skip_dirty_regions && current->in_collection_set()) {
  96       continue;
  97     }
  98     if (blk->doHeapRegion(current)) {
  99       return;
 100     }
 101   }
 102 }
 103 
 104 void ShenandoahHeapRegionSet::unclaimed_heap_region_iterate(ShenandoahHeapRegionClosure* blk,
 105                                                   bool skip_dirty_regions,
 106                                                   bool skip_humongous_continuation) const {
 107   size_t i;
 108 
 109   // There's a bug here where the zeroth region is missed  --chf
 110   for (i = _current_index + 1; i < _active_end; i++) {
 111     ShenandoahHeapRegion* current = _regions[i];
 112     assert(current->region_number() <= _reserved_end, "Tautology");
 113 
 114     if (skip_humongous_continuation && current->is_humongous_continuation()) {
 115       continue;
 116     }
 117     if (skip_dirty_regions && current->in_collection_set()) {
 118       continue;
 119     }
 120     if (blk->doHeapRegion(current)) {
 121       return;
 122     }
 123   }
 124 }
 125 
 126 // Iterates over all of the regions.
 127 void ShenandoahHeapRegionSet::heap_region_iterate(ShenandoahHeapRegionClosure* blk,
 128                                                   bool skip_dirty_regions,
 129                                                   bool skip_humongous_continuation) const {
 130   active_heap_region_iterate(blk, skip_dirty_regions, skip_humongous_continuation);
 131 }
 132 
 133 class PrintHeapRegionsClosure : public
 134    ShenandoahHeapRegionClosure {
 135 private:
 136   outputStream* _st;
 137 public:
 138   PrintHeapRegionsClosure() : _st(tty) {}
 139   PrintHeapRegionsClosure(outputStream* st) : _st(st) {}
 140 
 141   bool doHeapRegion(ShenandoahHeapRegion* r) {
 142     r->print_on(_st);
 143     return false;
 144   }
 145 };
 146 
 147 void ShenandoahHeapRegionSet::print(outputStream* out) {
 148   out->print_cr("_current_index: "SIZE_FORMAT" current region: %p, _active_end: "SIZE_FORMAT, _current_index, _regions[_current_index], _active_end);
 149 
 150   PrintHeapRegionsClosure pc1(out);
 151   heap_region_iterate(&pc1, false, false);
 152 }
 153 
 154 void ShenandoahHeapRegionSet::next() {
 155   if (_current_index < _active_end) {
 156     _current_index++;
 157   }
 158 }
 159 
 160 ShenandoahHeapRegion* ShenandoahHeapRegionSet::claim_next() {
 161   size_t next = Atomic::add(1, &_current_index) - 1;
 162   if (next < _active_end) {
 163     return get(next);
 164   } else {
 165     return NULL;
 166   }
 167   return NULL;
 168 }
 169 
 170 class FindRegionClosure : public ShenandoahHeapRegionClosure {
 171   ShenandoahHeapRegion* _query;
 172   bool _result;
 173 public:
 174 
 175   FindRegionClosure(ShenandoahHeapRegion* query) : _query(query), _result(false) {}
 176 
 177   bool doHeapRegion(ShenandoahHeapRegion* r) {
 178     _result = (r == _query);
 179     return _result;
 180   }
 181 
 182   bool result() { return _result;}
 183 };
 184 
 185 bool ShenandoahHeapRegionSet::contains(ShenandoahHeapRegion* r) {
 186   FindRegionClosure cl(r);
 187   active_heap_region_iterate(&cl);
 188   return cl.result();
 189 }
 190 
 191 HeapWord* ShenandoahHeapRegionSet::bottom() const {
 192   return get(0)->bottom();
 193 }
 194 
 195 HeapWord* ShenandoahHeapRegionSet::end() const {
 196   return get(_active_end - 1)->end();
 197 }
 198 
 199 ShenandoahHeapRegion* ShenandoahHeapRegionSet::get(size_t i) const {
 200   if (i < _active_end) {
 201     return _regions[i];
 202   } else {
 203     return NULL;
 204   }
 205 }
 206 
 207 ShenandoahHeapRegion* ShenandoahHeapRegionSet::current() const {
 208   if (_current_index < _active_end) {
 209     return get(_current_index);
 210   } else {
 211     return NULL;
 212   }
 213 }