src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp

Fri, 10 Oct 2014 15:51:58 +0200

author
tschatzl
date
Fri, 10 Oct 2014 15:51:58 +0200
changeset 7257
e7d0505c8a30
parent 7208
7baf47cb97cb
child 7535
7ae4e26cb1e0
child 7828
cbc7c4c9e11c
permissions
-rw-r--r--

8059758: Footprint regressions with JDK-8038423
Summary: Changes in JDK-8038423 always initialize (zero out) virtual memory used for auxiliary data structures. This causes a footprint regression for G1 in startup benchmarks. This is because they do not touch that memory at all, so the operating system does not actually commit these pages. The fix is to, if the initialization value of the data structures matches the default value of just committed memory (=0), do not do anything.
Reviewed-by: jwilhelm, brutisso

     1 /*
     2  * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.
     8  *
     9  * This code is distributed in the hope that it will be useful, but WITHOUT
    10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    12  * version 2 for more details (a copy is included in the LICENSE file that
    13  * accompanied this code).
    14  *
    15  * You should have received a copy of the GNU General Public License version
    16  * 2 along with this work; if not, write to the Free Software Foundation,
    17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    18  *
    19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    20  * or visit www.oracle.com if you need additional information or have any
    21  * questions.
    22  *
    23  */
    25 #include "precompiled.hpp"
    26 #include "gc_implementation/g1/concurrentG1Refine.hpp"
    27 #include "gc_implementation/g1/g1BlockOffsetTable.inline.hpp"
    28 #include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
    29 #include "gc_implementation/g1/heapRegionRemSet.hpp"
    30 #include "gc_implementation/g1/heapRegionManager.inline.hpp"
    31 #include "memory/allocation.hpp"
    32 #include "memory/padded.inline.hpp"
    33 #include "memory/space.inline.hpp"
    34 #include "oops/oop.inline.hpp"
    35 #include "utilities/bitMap.inline.hpp"
    36 #include "utilities/globalDefinitions.hpp"
    37 #include "utilities/growableArray.hpp"
    39 PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC
    41 class PerRegionTable: public CHeapObj<mtGC> {
    42   friend class OtherRegionsTable;
    43   friend class HeapRegionRemSetIterator;
    45   HeapRegion*     _hr;
    46   BitMap          _bm;
    47   jint            _occupied;
    49   // next pointer for free/allocated 'all' list
    50   PerRegionTable* _next;
    52   // prev pointer for the allocated 'all' list
    53   PerRegionTable* _prev;
    55   // next pointer in collision list
    56   PerRegionTable * _collision_list_next;
    58   // Global free list of PRTs
    59   static PerRegionTable* _free_list;
    61 protected:
    62   // We need access in order to union things into the base table.
    63   BitMap* bm() { return &_bm; }
    65   void recount_occupied() {
    66     _occupied = (jint) bm()->count_one_bits();
    67   }
    69   PerRegionTable(HeapRegion* hr) :
    70     _hr(hr),
    71     _occupied(0),
    72     _bm(HeapRegion::CardsPerRegion, false /* in-resource-area */),
    73     _collision_list_next(NULL), _next(NULL), _prev(NULL)
    74   {}
    76   void add_card_work(CardIdx_t from_card, bool par) {
    77     if (!_bm.at(from_card)) {
    78       if (par) {
    79         if (_bm.par_at_put(from_card, 1)) {
    80           Atomic::inc(&_occupied);
    81         }
    82       } else {
    83         _bm.at_put(from_card, 1);
    84         _occupied++;
    85       }
    86     }
    87   }
    89   void add_reference_work(OopOrNarrowOopStar from, bool par) {
    90     // Must make this robust in case "from" is not in "_hr", because of
    91     // concurrency.
    93     if (G1TraceHeapRegionRememberedSet) {
    94       gclog_or_tty->print_cr("    PRT::Add_reference_work(" PTR_FORMAT "->" PTR_FORMAT").",
    95                              from,
    96                              UseCompressedOops
    97                              ? (void *)oopDesc::load_decode_heap_oop((narrowOop*)from)
    98                              : (void *)oopDesc::load_decode_heap_oop((oop*)from));
    99     }
   101     HeapRegion* loc_hr = hr();
   102     // If the test below fails, then this table was reused concurrently
   103     // with this operation.  This is OK, since the old table was coarsened,
   104     // and adding a bit to the new table is never incorrect.
   105     // If the table used to belong to a continues humongous region and is
   106     // now reused for the corresponding start humongous region, we need to
   107     // make sure that we detect this. Thus, we call is_in_reserved_raw()
   108     // instead of just is_in_reserved() here.
   109     if (loc_hr->is_in_reserved_raw(from)) {
   110       size_t hw_offset = pointer_delta((HeapWord*)from, loc_hr->bottom());
   111       CardIdx_t from_card = (CardIdx_t)
   112           hw_offset >> (CardTableModRefBS::card_shift - LogHeapWordSize);
   114       assert(0 <= from_card && (size_t)from_card < HeapRegion::CardsPerRegion,
   115              "Must be in range.");
   116       add_card_work(from_card, par);
   117     }
   118   }
   120 public:
   122   HeapRegion* hr() const { return _hr; }
   124   jint occupied() const {
   125     // Overkill, but if we ever need it...
   126     // guarantee(_occupied == _bm.count_one_bits(), "Check");
   127     return _occupied;
   128   }
   130   void init(HeapRegion* hr, bool clear_links_to_all_list) {
   131     if (clear_links_to_all_list) {
   132       set_next(NULL);
   133       set_prev(NULL);
   134     }
   135     _hr = hr;
   136     _collision_list_next = NULL;
   137     _occupied = 0;
   138     _bm.clear();
   139   }
   141   void add_reference(OopOrNarrowOopStar from) {
   142     add_reference_work(from, /*parallel*/ true);
   143   }
   145   void seq_add_reference(OopOrNarrowOopStar from) {
   146     add_reference_work(from, /*parallel*/ false);
   147   }
   149   void scrub(CardTableModRefBS* ctbs, BitMap* card_bm) {
   150     HeapWord* hr_bot = hr()->bottom();
   151     size_t hr_first_card_index = ctbs->index_for(hr_bot);
   152     bm()->set_intersection_at_offset(*card_bm, hr_first_card_index);
   153     recount_occupied();
   154   }
   156   void add_card(CardIdx_t from_card_index) {
   157     add_card_work(from_card_index, /*parallel*/ true);
   158   }
   160   void seq_add_card(CardIdx_t from_card_index) {
   161     add_card_work(from_card_index, /*parallel*/ false);
   162   }
   164   // (Destructively) union the bitmap of the current table into the given
   165   // bitmap (which is assumed to be of the same size.)
   166   void union_bitmap_into(BitMap* bm) {
   167     bm->set_union(_bm);
   168   }
   170   // Mem size in bytes.
   171   size_t mem_size() const {
   172     return sizeof(PerRegionTable) + _bm.size_in_words() * HeapWordSize;
   173   }
   175   // Requires "from" to be in "hr()".
   176   bool contains_reference(OopOrNarrowOopStar from) const {
   177     assert(hr()->is_in_reserved(from), "Precondition.");
   178     size_t card_ind = pointer_delta(from, hr()->bottom(),
   179                                     CardTableModRefBS::card_size);
   180     return _bm.at(card_ind);
   181   }
   183   // Bulk-free the PRTs from prt to last, assumes that they are
   184   // linked together using their _next field.
   185   static void bulk_free(PerRegionTable* prt, PerRegionTable* last) {
   186     while (true) {
   187       PerRegionTable* fl = _free_list;
   188       last->set_next(fl);
   189       PerRegionTable* res = (PerRegionTable*) Atomic::cmpxchg_ptr(prt, &_free_list, fl);
   190       if (res == fl) {
   191         return;
   192       }
   193     }
   194     ShouldNotReachHere();
   195   }
   197   static void free(PerRegionTable* prt) {
   198     bulk_free(prt, prt);
   199   }
   201   // Returns an initialized PerRegionTable instance.
   202   static PerRegionTable* alloc(HeapRegion* hr) {
   203     PerRegionTable* fl = _free_list;
   204     while (fl != NULL) {
   205       PerRegionTable* nxt = fl->next();
   206       PerRegionTable* res =
   207         (PerRegionTable*)
   208         Atomic::cmpxchg_ptr(nxt, &_free_list, fl);
   209       if (res == fl) {
   210         fl->init(hr, true);
   211         return fl;
   212       } else {
   213         fl = _free_list;
   214       }
   215     }
   216     assert(fl == NULL, "Loop condition.");
   217     return new PerRegionTable(hr);
   218   }
   220   PerRegionTable* next() const { return _next; }
   221   void set_next(PerRegionTable* next) { _next = next; }
   222   PerRegionTable* prev() const { return _prev; }
   223   void set_prev(PerRegionTable* prev) { _prev = prev; }
   225   // Accessor and Modification routines for the pointer for the
   226   // singly linked collision list that links the PRTs within the
   227   // OtherRegionsTable::_fine_grain_regions hash table.
   228   //
   229   // It might be useful to also make the collision list doubly linked
   230   // to avoid iteration over the collisions list during scrubbing/deletion.
   231   // OTOH there might not be many collisions.
   233   PerRegionTable* collision_list_next() const {
   234     return _collision_list_next;
   235   }
   237   void set_collision_list_next(PerRegionTable* next) {
   238     _collision_list_next = next;
   239   }
   241   PerRegionTable** collision_list_next_addr() {
   242     return &_collision_list_next;
   243   }
   245   static size_t fl_mem_size() {
   246     PerRegionTable* cur = _free_list;
   247     size_t res = 0;
   248     while (cur != NULL) {
   249       res += cur->mem_size();
   250       cur = cur->next();
   251     }
   252     return res;
   253   }
   255   static void test_fl_mem_size();
   256 };
   258 PerRegionTable* PerRegionTable::_free_list = NULL;
   260 size_t OtherRegionsTable::_max_fine_entries = 0;
   261 size_t OtherRegionsTable::_mod_max_fine_entries_mask = 0;
   262 size_t OtherRegionsTable::_fine_eviction_stride = 0;
   263 size_t OtherRegionsTable::_fine_eviction_sample_size = 0;
   265 OtherRegionsTable::OtherRegionsTable(HeapRegion* hr, Mutex* m) :
   266   _g1h(G1CollectedHeap::heap()),
   267   _hr(hr), _m(m),
   268   _coarse_map(G1CollectedHeap::heap()->max_regions(),
   269               false /* in-resource-area */),
   270   _fine_grain_regions(NULL),
   271   _first_all_fine_prts(NULL), _last_all_fine_prts(NULL),
   272   _n_fine_entries(0), _n_coarse_entries(0),
   273   _fine_eviction_start(0),
   274   _sparse_table(hr)
   275 {
   276   typedef PerRegionTable* PerRegionTablePtr;
   278   if (_max_fine_entries == 0) {
   279     assert(_mod_max_fine_entries_mask == 0, "Both or none.");
   280     size_t max_entries_log = (size_t)log2_long((jlong)G1RSetRegionEntries);
   281     _max_fine_entries = (size_t)1 << max_entries_log;
   282     _mod_max_fine_entries_mask = _max_fine_entries - 1;
   284     assert(_fine_eviction_sample_size == 0
   285            && _fine_eviction_stride == 0, "All init at same time.");
   286     _fine_eviction_sample_size = MAX2((size_t)4, max_entries_log);
   287     _fine_eviction_stride = _max_fine_entries / _fine_eviction_sample_size;
   288   }
   290   _fine_grain_regions = NEW_C_HEAP_ARRAY3(PerRegionTablePtr, _max_fine_entries,
   291                         mtGC, CURRENT_PC, AllocFailStrategy::RETURN_NULL);
   293   if (_fine_grain_regions == NULL) {
   294     vm_exit_out_of_memory(sizeof(void*)*_max_fine_entries, OOM_MALLOC_ERROR,
   295                           "Failed to allocate _fine_grain_entries.");
   296   }
   298   for (size_t i = 0; i < _max_fine_entries; i++) {
   299     _fine_grain_regions[i] = NULL;
   300   }
   301 }
   303 void OtherRegionsTable::link_to_all(PerRegionTable* prt) {
   304   // We always append to the beginning of the list for convenience;
   305   // the order of entries in this list does not matter.
   306   if (_first_all_fine_prts != NULL) {
   307     assert(_first_all_fine_prts->prev() == NULL, "invariant");
   308     _first_all_fine_prts->set_prev(prt);
   309     prt->set_next(_first_all_fine_prts);
   310   } else {
   311     // this is the first element we insert. Adjust the "last" pointer
   312     _last_all_fine_prts = prt;
   313     assert(prt->next() == NULL, "just checking");
   314   }
   315   // the new element is always the first element without a predecessor
   316   prt->set_prev(NULL);
   317   _first_all_fine_prts = prt;
   319   assert(prt->prev() == NULL, "just checking");
   320   assert(_first_all_fine_prts == prt, "just checking");
   321   assert((_first_all_fine_prts == NULL && _last_all_fine_prts == NULL) ||
   322          (_first_all_fine_prts != NULL && _last_all_fine_prts != NULL),
   323          "just checking");
   324   assert(_last_all_fine_prts == NULL || _last_all_fine_prts->next() == NULL,
   325          "just checking");
   326   assert(_first_all_fine_prts == NULL || _first_all_fine_prts->prev() == NULL,
   327          "just checking");
   328 }
   330 void OtherRegionsTable::unlink_from_all(PerRegionTable* prt) {
   331   if (prt->prev() != NULL) {
   332     assert(_first_all_fine_prts != prt, "just checking");
   333     prt->prev()->set_next(prt->next());
   334     // removing the last element in the list?
   335     if (_last_all_fine_prts == prt) {
   336       _last_all_fine_prts = prt->prev();
   337     }
   338   } else {
   339     assert(_first_all_fine_prts == prt, "just checking");
   340     _first_all_fine_prts = prt->next();
   341     // list is empty now?
   342     if (_first_all_fine_prts == NULL) {
   343       _last_all_fine_prts = NULL;
   344     }
   345   }
   347   if (prt->next() != NULL) {
   348     prt->next()->set_prev(prt->prev());
   349   }
   351   prt->set_next(NULL);
   352   prt->set_prev(NULL);
   354   assert((_first_all_fine_prts == NULL && _last_all_fine_prts == NULL) ||
   355          (_first_all_fine_prts != NULL && _last_all_fine_prts != NULL),
   356          "just checking");
   357   assert(_last_all_fine_prts == NULL || _last_all_fine_prts->next() == NULL,
   358          "just checking");
   359   assert(_first_all_fine_prts == NULL || _first_all_fine_prts->prev() == NULL,
   360          "just checking");
   361 }
   363 int**  FromCardCache::_cache = NULL;
   364 uint   FromCardCache::_max_regions = 0;
   365 size_t FromCardCache::_static_mem_size = 0;
   367 void FromCardCache::initialize(uint n_par_rs, uint max_num_regions) {
   368   guarantee(_cache == NULL, "Should not call this multiple times");
   370   _max_regions = max_num_regions;
   371   _cache = Padded2DArray<int, mtGC>::create_unfreeable(n_par_rs,
   372                                                        _max_regions,
   373                                                        &_static_mem_size);
   375   invalidate(0, _max_regions);
   376 }
   378 void FromCardCache::invalidate(uint start_idx, size_t new_num_regions) {
   379   guarantee((size_t)start_idx + new_num_regions <= max_uintx,
   380             err_msg("Trying to invalidate beyond maximum region, from %u size "SIZE_FORMAT,
   381                     start_idx, new_num_regions));
   382   for (uint i = 0; i < HeapRegionRemSet::num_par_rem_sets(); i++) {
   383     uint end_idx = (start_idx + (uint)new_num_regions);
   384     assert(end_idx <= _max_regions, "Must be within max.");
   385     for (uint j = start_idx; j < end_idx; j++) {
   386       set(i, j, InvalidCard);
   387     }
   388   }
   389 }
   391 #ifndef PRODUCT
   392 void FromCardCache::print(outputStream* out) {
   393   for (uint i = 0; i < HeapRegionRemSet::num_par_rem_sets(); i++) {
   394     for (uint j = 0; j < _max_regions; j++) {
   395       out->print_cr("_from_card_cache["UINT32_FORMAT"]["UINT32_FORMAT"] = "INT32_FORMAT".",
   396                     i, j, at(i, j));
   397     }
   398   }
   399 }
   400 #endif
   402 void FromCardCache::clear(uint region_idx) {
   403   uint num_par_remsets = HeapRegionRemSet::num_par_rem_sets();
   404   for (uint i = 0; i < num_par_remsets; i++) {
   405     set(i, region_idx, InvalidCard);
   406   }
   407 }
   409 void OtherRegionsTable::initialize(uint max_regions) {
   410   FromCardCache::initialize(HeapRegionRemSet::num_par_rem_sets(), max_regions);
   411 }
   413 void OtherRegionsTable::invalidate(uint start_idx, size_t num_regions) {
   414   FromCardCache::invalidate(start_idx, num_regions);
   415 }
   417 void OtherRegionsTable::print_from_card_cache() {
   418   FromCardCache::print();
   419 }
   421 void OtherRegionsTable::add_reference(OopOrNarrowOopStar from, int tid) {
   422   uint cur_hrm_ind = hr()->hrm_index();
   424   if (G1TraceHeapRegionRememberedSet) {
   425     gclog_or_tty->print_cr("ORT::add_reference_work(" PTR_FORMAT "->" PTR_FORMAT ").",
   426                                                     from,
   427                                                     UseCompressedOops
   428                                                     ? (void *)oopDesc::load_decode_heap_oop((narrowOop*)from)
   429                                                     : (void *)oopDesc::load_decode_heap_oop((oop*)from));
   430   }
   432   int from_card = (int)(uintptr_t(from) >> CardTableModRefBS::card_shift);
   434   if (G1TraceHeapRegionRememberedSet) {
   435     gclog_or_tty->print_cr("Table for [" PTR_FORMAT "...): card %d (cache = "INT32_FORMAT")",
   436                   hr()->bottom(), from_card,
   437                   FromCardCache::at((uint)tid, cur_hrm_ind));
   438   }
   440   if (FromCardCache::contains_or_replace((uint)tid, cur_hrm_ind, from_card)) {
   441     if (G1TraceHeapRegionRememberedSet) {
   442       gclog_or_tty->print_cr("  from-card cache hit.");
   443     }
   444     assert(contains_reference(from), "We just added it!");
   445     return;
   446   }
   448   // Note that this may be a continued H region.
   449   HeapRegion* from_hr = _g1h->heap_region_containing_raw(from);
   450   RegionIdx_t from_hrm_ind = (RegionIdx_t) from_hr->hrm_index();
   452   // If the region is already coarsened, return.
   453   if (_coarse_map.at(from_hrm_ind)) {
   454     if (G1TraceHeapRegionRememberedSet) {
   455       gclog_or_tty->print_cr("  coarse map hit.");
   456     }
   457     assert(contains_reference(from), "We just added it!");
   458     return;
   459   }
   461   // Otherwise find a per-region table to add it to.
   462   size_t ind = from_hrm_ind & _mod_max_fine_entries_mask;
   463   PerRegionTable* prt = find_region_table(ind, from_hr);
   464   if (prt == NULL) {
   465     MutexLockerEx x(_m, Mutex::_no_safepoint_check_flag);
   466     // Confirm that it's really not there...
   467     prt = find_region_table(ind, from_hr);
   468     if (prt == NULL) {
   470       uintptr_t from_hr_bot_card_index =
   471         uintptr_t(from_hr->bottom())
   472           >> CardTableModRefBS::card_shift;
   473       CardIdx_t card_index = from_card - from_hr_bot_card_index;
   474       assert(0 <= card_index && (size_t)card_index < HeapRegion::CardsPerRegion,
   475              "Must be in range.");
   476       if (G1HRRSUseSparseTable &&
   477           _sparse_table.add_card(from_hrm_ind, card_index)) {
   478         if (G1RecordHRRSOops) {
   479           HeapRegionRemSet::record(hr(), from);
   480           if (G1TraceHeapRegionRememberedSet) {
   481             gclog_or_tty->print("   Added card " PTR_FORMAT " to region "
   482                                 "[" PTR_FORMAT "...) for ref " PTR_FORMAT ".\n",
   483                                 align_size_down(uintptr_t(from),
   484                                                 CardTableModRefBS::card_size),
   485                                 hr()->bottom(), from);
   486           }
   487         }
   488         if (G1TraceHeapRegionRememberedSet) {
   489           gclog_or_tty->print_cr("   added card to sparse table.");
   490         }
   491         assert(contains_reference_locked(from), "We just added it!");
   492         return;
   493       } else {
   494         if (G1TraceHeapRegionRememberedSet) {
   495           gclog_or_tty->print_cr("   [tid %d] sparse table entry "
   496                         "overflow(f: %d, t: %u)",
   497                         tid, from_hrm_ind, cur_hrm_ind);
   498         }
   499       }
   501       if (_n_fine_entries == _max_fine_entries) {
   502         prt = delete_region_table();
   503         // There is no need to clear the links to the 'all' list here:
   504         // prt will be reused immediately, i.e. remain in the 'all' list.
   505         prt->init(from_hr, false /* clear_links_to_all_list */);
   506       } else {
   507         prt = PerRegionTable::alloc(from_hr);
   508         link_to_all(prt);
   509       }
   511       PerRegionTable* first_prt = _fine_grain_regions[ind];
   512       prt->set_collision_list_next(first_prt);
   513       _fine_grain_regions[ind] = prt;
   514       _n_fine_entries++;
   516       if (G1HRRSUseSparseTable) {
   517         // Transfer from sparse to fine-grain.
   518         SparsePRTEntry *sprt_entry = _sparse_table.get_entry(from_hrm_ind);
   519         assert(sprt_entry != NULL, "There should have been an entry");
   520         for (int i = 0; i < SparsePRTEntry::cards_num(); i++) {
   521           CardIdx_t c = sprt_entry->card(i);
   522           if (c != SparsePRTEntry::NullEntry) {
   523             prt->add_card(c);
   524           }
   525         }
   526         // Now we can delete the sparse entry.
   527         bool res = _sparse_table.delete_entry(from_hrm_ind);
   528         assert(res, "It should have been there.");
   529       }
   530     }
   531     assert(prt != NULL && prt->hr() == from_hr, "consequence");
   532   }
   533   // Note that we can't assert "prt->hr() == from_hr", because of the
   534   // possibility of concurrent reuse.  But see head comment of
   535   // OtherRegionsTable for why this is OK.
   536   assert(prt != NULL, "Inv");
   538   prt->add_reference(from);
   540   if (G1RecordHRRSOops) {
   541     HeapRegionRemSet::record(hr(), from);
   542     if (G1TraceHeapRegionRememberedSet) {
   543       gclog_or_tty->print("Added card " PTR_FORMAT " to region "
   544                           "[" PTR_FORMAT "...) for ref " PTR_FORMAT ".\n",
   545                           align_size_down(uintptr_t(from),
   546                                           CardTableModRefBS::card_size),
   547                           hr()->bottom(), from);
   548     }
   549   }
   550   assert(contains_reference(from), "We just added it!");
   551 }
   553 PerRegionTable*
   554 OtherRegionsTable::find_region_table(size_t ind, HeapRegion* hr) const {
   555   assert(0 <= ind && ind < _max_fine_entries, "Preconditions.");
   556   PerRegionTable* prt = _fine_grain_regions[ind];
   557   while (prt != NULL && prt->hr() != hr) {
   558     prt = prt->collision_list_next();
   559   }
   560   // Loop postcondition is the method postcondition.
   561   return prt;
   562 }
   564 jint OtherRegionsTable::_n_coarsenings = 0;
   566 PerRegionTable* OtherRegionsTable::delete_region_table() {
   567   assert(_m->owned_by_self(), "Precondition");
   568   assert(_n_fine_entries == _max_fine_entries, "Precondition");
   569   PerRegionTable* max = NULL;
   570   jint max_occ = 0;
   571   PerRegionTable** max_prev;
   572   size_t max_ind;
   574   size_t i = _fine_eviction_start;
   575   for (size_t k = 0; k < _fine_eviction_sample_size; k++) {
   576     size_t ii = i;
   577     // Make sure we get a non-NULL sample.
   578     while (_fine_grain_regions[ii] == NULL) {
   579       ii++;
   580       if (ii == _max_fine_entries) ii = 0;
   581       guarantee(ii != i, "We must find one.");
   582     }
   583     PerRegionTable** prev = &_fine_grain_regions[ii];
   584     PerRegionTable* cur = *prev;
   585     while (cur != NULL) {
   586       jint cur_occ = cur->occupied();
   587       if (max == NULL || cur_occ > max_occ) {
   588         max = cur;
   589         max_prev = prev;
   590         max_ind = i;
   591         max_occ = cur_occ;
   592       }
   593       prev = cur->collision_list_next_addr();
   594       cur = cur->collision_list_next();
   595     }
   596     i = i + _fine_eviction_stride;
   597     if (i >= _n_fine_entries) i = i - _n_fine_entries;
   598   }
   600   _fine_eviction_start++;
   602   if (_fine_eviction_start >= _n_fine_entries) {
   603     _fine_eviction_start -= _n_fine_entries;
   604   }
   606   guarantee(max != NULL, "Since _n_fine_entries > 0");
   608   // Set the corresponding coarse bit.
   609   size_t max_hrm_index = (size_t) max->hr()->hrm_index();
   610   if (!_coarse_map.at(max_hrm_index)) {
   611     _coarse_map.at_put(max_hrm_index, true);
   612     _n_coarse_entries++;
   613     if (G1TraceHeapRegionRememberedSet) {
   614       gclog_or_tty->print("Coarsened entry in region [" PTR_FORMAT "...] "
   615                  "for region [" PTR_FORMAT "...] (%d coarse entries).\n",
   616                  hr()->bottom(),
   617                  max->hr()->bottom(),
   618                  _n_coarse_entries);
   619     }
   620   }
   622   // Unsplice.
   623   *max_prev = max->collision_list_next();
   624   Atomic::inc(&_n_coarsenings);
   625   _n_fine_entries--;
   626   return max;
   627 }
   630 // At present, this must be called stop-world single-threaded.
   631 void OtherRegionsTable::scrub(CardTableModRefBS* ctbs,
   632                               BitMap* region_bm, BitMap* card_bm) {
   633   // First eliminated garbage regions from the coarse map.
   634   if (G1RSScrubVerbose) {
   635     gclog_or_tty->print_cr("Scrubbing region %u:", hr()->hrm_index());
   636   }
   638   assert(_coarse_map.size() == region_bm->size(), "Precondition");
   639   if (G1RSScrubVerbose) {
   640     gclog_or_tty->print("   Coarse map: before = "SIZE_FORMAT"...",
   641                         _n_coarse_entries);
   642   }
   643   _coarse_map.set_intersection(*region_bm);
   644   _n_coarse_entries = _coarse_map.count_one_bits();
   645   if (G1RSScrubVerbose) {
   646     gclog_or_tty->print_cr("   after = "SIZE_FORMAT".", _n_coarse_entries);
   647   }
   649   // Now do the fine-grained maps.
   650   for (size_t i = 0; i < _max_fine_entries; i++) {
   651     PerRegionTable* cur = _fine_grain_regions[i];
   652     PerRegionTable** prev = &_fine_grain_regions[i];
   653     while (cur != NULL) {
   654       PerRegionTable* nxt = cur->collision_list_next();
   655       // If the entire region is dead, eliminate.
   656       if (G1RSScrubVerbose) {
   657         gclog_or_tty->print_cr("     For other region %u:",
   658                                cur->hr()->hrm_index());
   659       }
   660       if (!region_bm->at((size_t) cur->hr()->hrm_index())) {
   661         *prev = nxt;
   662         cur->set_collision_list_next(NULL);
   663         _n_fine_entries--;
   664         if (G1RSScrubVerbose) {
   665           gclog_or_tty->print_cr("          deleted via region map.");
   666         }
   667         unlink_from_all(cur);
   668         PerRegionTable::free(cur);
   669       } else {
   670         // Do fine-grain elimination.
   671         if (G1RSScrubVerbose) {
   672           gclog_or_tty->print("          occ: before = %4d.", cur->occupied());
   673         }
   674         cur->scrub(ctbs, card_bm);
   675         if (G1RSScrubVerbose) {
   676           gclog_or_tty->print_cr("          after = %4d.", cur->occupied());
   677         }
   678         // Did that empty the table completely?
   679         if (cur->occupied() == 0) {
   680           *prev = nxt;
   681           cur->set_collision_list_next(NULL);
   682           _n_fine_entries--;
   683           unlink_from_all(cur);
   684           PerRegionTable::free(cur);
   685         } else {
   686           prev = cur->collision_list_next_addr();
   687         }
   688       }
   689       cur = nxt;
   690     }
   691   }
   692   // Since we may have deleted a from_card_cache entry from the RS, clear
   693   // the FCC.
   694   clear_fcc();
   695 }
   697 bool OtherRegionsTable::is_empty() const {
   698   return occ_sparse() == 0 && occ_coarse() == 0 && _first_all_fine_prts == NULL;
   699 }
   701 size_t OtherRegionsTable::occupied() const {
   702   size_t sum = occ_fine();
   703   sum += occ_sparse();
   704   sum += occ_coarse();
   705   return sum;
   706 }
   708 size_t OtherRegionsTable::occ_fine() const {
   709   size_t sum = 0;
   711   size_t num = 0;
   712   PerRegionTable * cur = _first_all_fine_prts;
   713   while (cur != NULL) {
   714     sum += cur->occupied();
   715     cur = cur->next();
   716     num++;
   717   }
   718   guarantee(num == _n_fine_entries, "just checking");
   719   return sum;
   720 }
   722 size_t OtherRegionsTable::occ_coarse() const {
   723   return (_n_coarse_entries * HeapRegion::CardsPerRegion);
   724 }
   726 size_t OtherRegionsTable::occ_sparse() const {
   727   return _sparse_table.occupied();
   728 }
   730 size_t OtherRegionsTable::mem_size() const {
   731   size_t sum = 0;
   732   // all PRTs are of the same size so it is sufficient to query only one of them.
   733   if (_first_all_fine_prts != NULL) {
   734     assert(_last_all_fine_prts != NULL &&
   735       _first_all_fine_prts->mem_size() == _last_all_fine_prts->mem_size(), "check that mem_size() is constant");
   736     sum += _first_all_fine_prts->mem_size() * _n_fine_entries;
   737   }
   738   sum += (sizeof(PerRegionTable*) * _max_fine_entries);
   739   sum += (_coarse_map.size_in_words() * HeapWordSize);
   740   sum += (_sparse_table.mem_size());
   741   sum += sizeof(OtherRegionsTable) - sizeof(_sparse_table); // Avoid double counting above.
   742   return sum;
   743 }
   745 size_t OtherRegionsTable::static_mem_size() {
   746   return FromCardCache::static_mem_size();
   747 }
   749 size_t OtherRegionsTable::fl_mem_size() {
   750   return PerRegionTable::fl_mem_size();
   751 }
   753 void OtherRegionsTable::clear_fcc() {
   754   FromCardCache::clear(hr()->hrm_index());
   755 }
   757 void OtherRegionsTable::clear() {
   758   // if there are no entries, skip this step
   759   if (_first_all_fine_prts != NULL) {
   760     guarantee(_first_all_fine_prts != NULL && _last_all_fine_prts != NULL, "just checking");
   761     PerRegionTable::bulk_free(_first_all_fine_prts, _last_all_fine_prts);
   762     memset(_fine_grain_regions, 0, _max_fine_entries * sizeof(_fine_grain_regions[0]));
   763   } else {
   764     guarantee(_first_all_fine_prts == NULL && _last_all_fine_prts == NULL, "just checking");
   765   }
   767   _first_all_fine_prts = _last_all_fine_prts = NULL;
   768   _sparse_table.clear();
   769   _coarse_map.clear();
   770   _n_fine_entries = 0;
   771   _n_coarse_entries = 0;
   773   clear_fcc();
   774 }
   776 bool OtherRegionsTable::del_single_region_table(size_t ind,
   777                                                 HeapRegion* hr) {
   778   assert(0 <= ind && ind < _max_fine_entries, "Preconditions.");
   779   PerRegionTable** prev_addr = &_fine_grain_regions[ind];
   780   PerRegionTable* prt = *prev_addr;
   781   while (prt != NULL && prt->hr() != hr) {
   782     prev_addr = prt->collision_list_next_addr();
   783     prt = prt->collision_list_next();
   784   }
   785   if (prt != NULL) {
   786     assert(prt->hr() == hr, "Loop postcondition.");
   787     *prev_addr = prt->collision_list_next();
   788     unlink_from_all(prt);
   789     PerRegionTable::free(prt);
   790     _n_fine_entries--;
   791     return true;
   792   } else {
   793     return false;
   794   }
   795 }
   797 bool OtherRegionsTable::contains_reference(OopOrNarrowOopStar from) const {
   798   // Cast away const in this case.
   799   MutexLockerEx x((Mutex*)_m, Mutex::_no_safepoint_check_flag);
   800   return contains_reference_locked(from);
   801 }
   803 bool OtherRegionsTable::contains_reference_locked(OopOrNarrowOopStar from) const {
   804   HeapRegion* hr = _g1h->heap_region_containing_raw(from);
   805   RegionIdx_t hr_ind = (RegionIdx_t) hr->hrm_index();
   806   // Is this region in the coarse map?
   807   if (_coarse_map.at(hr_ind)) return true;
   809   PerRegionTable* prt = find_region_table(hr_ind & _mod_max_fine_entries_mask,
   810                                      hr);
   811   if (prt != NULL) {
   812     return prt->contains_reference(from);
   814   } else {
   815     uintptr_t from_card =
   816       (uintptr_t(from) >> CardTableModRefBS::card_shift);
   817     uintptr_t hr_bot_card_index =
   818       uintptr_t(hr->bottom()) >> CardTableModRefBS::card_shift;
   819     assert(from_card >= hr_bot_card_index, "Inv");
   820     CardIdx_t card_index = from_card - hr_bot_card_index;
   821     assert(0 <= card_index && (size_t)card_index < HeapRegion::CardsPerRegion,
   822            "Must be in range.");
   823     return _sparse_table.contains_card(hr_ind, card_index);
   824   }
   825 }
   827 void
   828 OtherRegionsTable::do_cleanup_work(HRRSCleanupTask* hrrs_cleanup_task) {
   829   _sparse_table.do_cleanup_work(hrrs_cleanup_task);
   830 }
   832 // Determines how many threads can add records to an rset in parallel.
   833 // This can be done by either mutator threads together with the
   834 // concurrent refinement threads or GC threads.
   835 uint HeapRegionRemSet::num_par_rem_sets() {
   836   return MAX2(DirtyCardQueueSet::num_par_ids() + ConcurrentG1Refine::thread_num(), (uint)ParallelGCThreads);
   837 }
   839 HeapRegionRemSet::HeapRegionRemSet(G1BlockOffsetSharedArray* bosa,
   840                                    HeapRegion* hr)
   841   : _bosa(bosa),
   842     _m(Mutex::leaf, FormatBuffer<128>("HeapRegionRemSet lock #%u", hr->hrm_index()), true),
   843     _code_roots(), _other_regions(hr, &_m), _iter_state(Unclaimed), _iter_claimed(0) {
   844   reset_for_par_iteration();
   845 }
   847 void HeapRegionRemSet::setup_remset_size() {
   848   // Setup sparse and fine-grain tables sizes.
   849   // table_size = base * (log(region_size / 1M) + 1)
   850   const int LOG_M = 20;
   851   int region_size_log_mb = MAX2(HeapRegion::LogOfHRGrainBytes - LOG_M, 0);
   852   if (FLAG_IS_DEFAULT(G1RSetSparseRegionEntries)) {
   853     G1RSetSparseRegionEntries = G1RSetSparseRegionEntriesBase * (region_size_log_mb + 1);
   854   }
   855   if (FLAG_IS_DEFAULT(G1RSetRegionEntries)) {
   856     G1RSetRegionEntries = G1RSetRegionEntriesBase * (region_size_log_mb + 1);
   857   }
   858   guarantee(G1RSetSparseRegionEntries > 0 && G1RSetRegionEntries > 0 , "Sanity");
   859 }
   861 bool HeapRegionRemSet::claim_iter() {
   862   if (_iter_state != Unclaimed) return false;
   863   jint res = Atomic::cmpxchg(Claimed, (jint*)(&_iter_state), Unclaimed);
   864   return (res == Unclaimed);
   865 }
   867 void HeapRegionRemSet::set_iter_complete() {
   868   _iter_state = Complete;
   869 }
   871 bool HeapRegionRemSet::iter_is_complete() {
   872   return _iter_state == Complete;
   873 }
   875 #ifndef PRODUCT
   876 void HeapRegionRemSet::print() {
   877   HeapRegionRemSetIterator iter(this);
   878   size_t card_index;
   879   while (iter.has_next(card_index)) {
   880     HeapWord* card_start =
   881       G1CollectedHeap::heap()->bot_shared()->address_for_index(card_index);
   882     gclog_or_tty->print_cr("  Card " PTR_FORMAT, card_start);
   883   }
   884   if (iter.n_yielded() != occupied()) {
   885     gclog_or_tty->print_cr("Yielded disagrees with occupied:");
   886     gclog_or_tty->print_cr("  %6d yielded (%6d coarse, %6d fine).",
   887                   iter.n_yielded(),
   888                   iter.n_yielded_coarse(), iter.n_yielded_fine());
   889     gclog_or_tty->print_cr("  %6d occ     (%6d coarse, %6d fine).",
   890                   occupied(), occ_coarse(), occ_fine());
   891   }
   892   guarantee(iter.n_yielded() == occupied(),
   893             "We should have yielded all the represented cards.");
   894 }
   895 #endif
   897 void HeapRegionRemSet::cleanup() {
   898   SparsePRT::cleanup_all();
   899 }
   901 void HeapRegionRemSet::clear() {
   902   MutexLockerEx x(&_m, Mutex::_no_safepoint_check_flag);
   903   clear_locked();
   904 }
   906 void HeapRegionRemSet::clear_locked() {
   907   _code_roots.clear();
   908   _other_regions.clear();
   909   assert(occupied_locked() == 0, "Should be clear.");
   910   reset_for_par_iteration();
   911 }
   913 void HeapRegionRemSet::reset_for_par_iteration() {
   914   _iter_state = Unclaimed;
   915   _iter_claimed = 0;
   916   // It's good to check this to make sure that the two methods are in sync.
   917   assert(verify_ready_for_par_iteration(), "post-condition");
   918 }
   920 void HeapRegionRemSet::scrub(CardTableModRefBS* ctbs,
   921                              BitMap* region_bm, BitMap* card_bm) {
   922   _other_regions.scrub(ctbs, region_bm, card_bm);
   923 }
   925 // Code roots support
   926 //
   927 // The code root set is protected by two separate locking schemes
   928 // When at safepoint the per-hrrs lock must be held during modifications
   929 // except when doing a full gc.
   930 // When not at safepoint the CodeCache_lock must be held during modifications.
   931 // When concurrent readers access the contains() function
   932 // (during the evacuation phase) no removals are allowed.
   934 void HeapRegionRemSet::add_strong_code_root(nmethod* nm) {
   935   assert(nm != NULL, "sanity");
   936   // Optimistic unlocked contains-check
   937   if (!_code_roots.contains(nm)) {
   938     MutexLockerEx ml(&_m, Mutex::_no_safepoint_check_flag);
   939     add_strong_code_root_locked(nm);
   940   }
   941 }
   943 void HeapRegionRemSet::add_strong_code_root_locked(nmethod* nm) {
   944   assert(nm != NULL, "sanity");
   945   _code_roots.add(nm);
   946 }
   948 void HeapRegionRemSet::remove_strong_code_root(nmethod* nm) {
   949   assert(nm != NULL, "sanity");
   950   assert_locked_or_safepoint(CodeCache_lock);
   952   MutexLockerEx ml(CodeCache_lock->owned_by_self() ? NULL : &_m, Mutex::_no_safepoint_check_flag);
   953   _code_roots.remove(nm);
   955   // Check that there were no duplicates
   956   guarantee(!_code_roots.contains(nm), "duplicate entry found");
   957 }
   959 void HeapRegionRemSet::strong_code_roots_do(CodeBlobClosure* blk) const {
   960   _code_roots.nmethods_do(blk);
   961 }
   963 void HeapRegionRemSet::clean_strong_code_roots(HeapRegion* hr) {
   964   _code_roots.clean(hr);
   965 }
   967 size_t HeapRegionRemSet::strong_code_roots_mem_size() {
   968   return _code_roots.mem_size();
   969 }
   971 HeapRegionRemSetIterator:: HeapRegionRemSetIterator(HeapRegionRemSet* hrrs) :
   972   _hrrs(hrrs),
   973   _g1h(G1CollectedHeap::heap()),
   974   _coarse_map(&hrrs->_other_regions._coarse_map),
   975   _bosa(hrrs->bosa()),
   976   _is(Sparse),
   977   // Set these values so that we increment to the first region.
   978   _coarse_cur_region_index(-1),
   979   _coarse_cur_region_cur_card(HeapRegion::CardsPerRegion-1),
   980   _cur_card_in_prt(HeapRegion::CardsPerRegion),
   981   _fine_cur_prt(NULL),
   982   _n_yielded_coarse(0),
   983   _n_yielded_fine(0),
   984   _n_yielded_sparse(0),
   985   _sparse_iter(&hrrs->_other_regions._sparse_table) {}
   987 bool HeapRegionRemSetIterator::coarse_has_next(size_t& card_index) {
   988   if (_hrrs->_other_regions._n_coarse_entries == 0) return false;
   989   // Go to the next card.
   990   _coarse_cur_region_cur_card++;
   991   // Was the last the last card in the current region?
   992   if (_coarse_cur_region_cur_card == HeapRegion::CardsPerRegion) {
   993     // Yes: find the next region.  This may leave _coarse_cur_region_index
   994     // Set to the last index, in which case there are no more coarse
   995     // regions.
   996     _coarse_cur_region_index =
   997       (int) _coarse_map->get_next_one_offset(_coarse_cur_region_index + 1);
   998     if ((size_t)_coarse_cur_region_index < _coarse_map->size()) {
   999       _coarse_cur_region_cur_card = 0;
  1000       HeapWord* r_bot =
  1001         _g1h->region_at((uint) _coarse_cur_region_index)->bottom();
  1002       _cur_region_card_offset = _bosa->index_for(r_bot);
  1003     } else {
  1004       return false;
  1007   // If we didn't return false above, then we can yield a card.
  1008   card_index = _cur_region_card_offset + _coarse_cur_region_cur_card;
  1009   return true;
  1012 bool HeapRegionRemSetIterator::fine_has_next(size_t& card_index) {
  1013   if (fine_has_next()) {
  1014     _cur_card_in_prt =
  1015       _fine_cur_prt->_bm.get_next_one_offset(_cur_card_in_prt + 1);
  1017   if (_cur_card_in_prt == HeapRegion::CardsPerRegion) {
  1018     // _fine_cur_prt may still be NULL in case if there are not PRTs at all for
  1019     // the remembered set.
  1020     if (_fine_cur_prt == NULL || _fine_cur_prt->next() == NULL) {
  1021       return false;
  1023     PerRegionTable* next_prt = _fine_cur_prt->next();
  1024     switch_to_prt(next_prt);
  1025     _cur_card_in_prt = _fine_cur_prt->_bm.get_next_one_offset(_cur_card_in_prt + 1);
  1028   card_index = _cur_region_card_offset + _cur_card_in_prt;
  1029   guarantee(_cur_card_in_prt < HeapRegion::CardsPerRegion,
  1030             err_msg("Card index "SIZE_FORMAT" must be within the region", _cur_card_in_prt));
  1031   return true;
  1034 bool HeapRegionRemSetIterator::fine_has_next() {
  1035   return _cur_card_in_prt != HeapRegion::CardsPerRegion;
  1038 void HeapRegionRemSetIterator::switch_to_prt(PerRegionTable* prt) {
  1039   assert(prt != NULL, "Cannot switch to NULL prt");
  1040   _fine_cur_prt = prt;
  1042   HeapWord* r_bot = _fine_cur_prt->hr()->bottom();
  1043   _cur_region_card_offset = _bosa->index_for(r_bot);
  1045   // The bitmap scan for the PRT always scans from _cur_region_cur_card + 1.
  1046   // To avoid special-casing this start case, and not miss the first bitmap
  1047   // entry, initialize _cur_region_cur_card with -1 instead of 0.
  1048   _cur_card_in_prt = (size_t)-1;
  1051 bool HeapRegionRemSetIterator::has_next(size_t& card_index) {
  1052   switch (_is) {
  1053   case Sparse: {
  1054     if (_sparse_iter.has_next(card_index)) {
  1055       _n_yielded_sparse++;
  1056       return true;
  1058     // Otherwise, deliberate fall-through
  1059     _is = Fine;
  1060     PerRegionTable* initial_fine_prt = _hrrs->_other_regions._first_all_fine_prts;
  1061     if (initial_fine_prt != NULL) {
  1062       switch_to_prt(_hrrs->_other_regions._first_all_fine_prts);
  1065   case Fine:
  1066     if (fine_has_next(card_index)) {
  1067       _n_yielded_fine++;
  1068       return true;
  1070     // Otherwise, deliberate fall-through
  1071     _is = Coarse;
  1072   case Coarse:
  1073     if (coarse_has_next(card_index)) {
  1074       _n_yielded_coarse++;
  1075       return true;
  1077     // Otherwise...
  1078     break;
  1080   assert(ParallelGCThreads > 1 ||
  1081          n_yielded() == _hrrs->occupied(),
  1082          "Should have yielded all the cards in the rem set "
  1083          "(in the non-par case).");
  1084   return false;
  1089 OopOrNarrowOopStar* HeapRegionRemSet::_recorded_oops = NULL;
  1090 HeapWord**          HeapRegionRemSet::_recorded_cards = NULL;
  1091 HeapRegion**        HeapRegionRemSet::_recorded_regions = NULL;
  1092 int                 HeapRegionRemSet::_n_recorded = 0;
  1094 HeapRegionRemSet::Event* HeapRegionRemSet::_recorded_events = NULL;
  1095 int*         HeapRegionRemSet::_recorded_event_index = NULL;
  1096 int          HeapRegionRemSet::_n_recorded_events = 0;
  1098 void HeapRegionRemSet::record(HeapRegion* hr, OopOrNarrowOopStar f) {
  1099   if (_recorded_oops == NULL) {
  1100     assert(_n_recorded == 0
  1101            && _recorded_cards == NULL
  1102            && _recorded_regions == NULL,
  1103            "Inv");
  1104     _recorded_oops    = NEW_C_HEAP_ARRAY(OopOrNarrowOopStar, MaxRecorded, mtGC);
  1105     _recorded_cards   = NEW_C_HEAP_ARRAY(HeapWord*,          MaxRecorded, mtGC);
  1106     _recorded_regions = NEW_C_HEAP_ARRAY(HeapRegion*,        MaxRecorded, mtGC);
  1108   if (_n_recorded == MaxRecorded) {
  1109     gclog_or_tty->print_cr("Filled up 'recorded' (%d).", MaxRecorded);
  1110   } else {
  1111     _recorded_cards[_n_recorded] =
  1112       (HeapWord*)align_size_down(uintptr_t(f),
  1113                                  CardTableModRefBS::card_size);
  1114     _recorded_oops[_n_recorded] = f;
  1115     _recorded_regions[_n_recorded] = hr;
  1116     _n_recorded++;
  1120 void HeapRegionRemSet::record_event(Event evnt) {
  1121   if (!G1RecordHRRSEvents) return;
  1123   if (_recorded_events == NULL) {
  1124     assert(_n_recorded_events == 0
  1125            && _recorded_event_index == NULL,
  1126            "Inv");
  1127     _recorded_events = NEW_C_HEAP_ARRAY(Event, MaxRecordedEvents, mtGC);
  1128     _recorded_event_index = NEW_C_HEAP_ARRAY(int, MaxRecordedEvents, mtGC);
  1130   if (_n_recorded_events == MaxRecordedEvents) {
  1131     gclog_or_tty->print_cr("Filled up 'recorded_events' (%d).", MaxRecordedEvents);
  1132   } else {
  1133     _recorded_events[_n_recorded_events] = evnt;
  1134     _recorded_event_index[_n_recorded_events] = _n_recorded;
  1135     _n_recorded_events++;
  1139 void HeapRegionRemSet::print_event(outputStream* str, Event evnt) {
  1140   switch (evnt) {
  1141   case Event_EvacStart:
  1142     str->print("Evac Start");
  1143     break;
  1144   case Event_EvacEnd:
  1145     str->print("Evac End");
  1146     break;
  1147   case Event_RSUpdateEnd:
  1148     str->print("RS Update End");
  1149     break;
  1153 void HeapRegionRemSet::print_recorded() {
  1154   int cur_evnt = 0;
  1155   Event cur_evnt_kind;
  1156   int cur_evnt_ind = 0;
  1157   if (_n_recorded_events > 0) {
  1158     cur_evnt_kind = _recorded_events[cur_evnt];
  1159     cur_evnt_ind = _recorded_event_index[cur_evnt];
  1162   for (int i = 0; i < _n_recorded; i++) {
  1163     while (cur_evnt < _n_recorded_events && i == cur_evnt_ind) {
  1164       gclog_or_tty->print("Event: ");
  1165       print_event(gclog_or_tty, cur_evnt_kind);
  1166       gclog_or_tty->cr();
  1167       cur_evnt++;
  1168       if (cur_evnt < MaxRecordedEvents) {
  1169         cur_evnt_kind = _recorded_events[cur_evnt];
  1170         cur_evnt_ind = _recorded_event_index[cur_evnt];
  1173     gclog_or_tty->print("Added card " PTR_FORMAT " to region [" PTR_FORMAT "...]"
  1174                         " for ref " PTR_FORMAT ".\n",
  1175                         _recorded_cards[i], _recorded_regions[i]->bottom(),
  1176                         _recorded_oops[i]);
  1180 void HeapRegionRemSet::reset_for_cleanup_tasks() {
  1181   SparsePRT::reset_for_cleanup_tasks();
  1184 void HeapRegionRemSet::do_cleanup_work(HRRSCleanupTask* hrrs_cleanup_task) {
  1185   _other_regions.do_cleanup_work(hrrs_cleanup_task);
  1188 void
  1189 HeapRegionRemSet::finish_cleanup_task(HRRSCleanupTask* hrrs_cleanup_task) {
  1190   SparsePRT::finish_cleanup_task(hrrs_cleanup_task);
  1193 #ifndef PRODUCT
  1194 void PerRegionTable::test_fl_mem_size() {
  1195   PerRegionTable* dummy = alloc(NULL);
  1197   size_t min_prt_size = sizeof(void*) + dummy->bm()->size_in_words() * HeapWordSize;
  1198   assert(dummy->mem_size() > min_prt_size,
  1199          err_msg("PerRegionTable memory usage is suspiciously small, only has "SIZE_FORMAT" bytes. "
  1200                  "Should be at least "SIZE_FORMAT" bytes.", dummy->mem_size(), min_prt_size));
  1201   free(dummy);
  1202   guarantee(dummy->mem_size() == fl_mem_size(), "fl_mem_size() does not return the correct element size");
  1203   // try to reset the state
  1204   _free_list = NULL;
  1205   delete dummy;
  1208 void HeapRegionRemSet::test_prt() {
  1209   PerRegionTable::test_fl_mem_size();
  1212 void HeapRegionRemSet::test() {
  1213   os::sleep(Thread::current(), (jlong)5000, false);
  1214   G1CollectedHeap* g1h = G1CollectedHeap::heap();
  1216   // Run with "-XX:G1LogRSetRegionEntries=2", so that 1 and 5 end up in same
  1217   // hash bucket.
  1218   HeapRegion* hr0 = g1h->region_at(0);
  1219   HeapRegion* hr1 = g1h->region_at(1);
  1220   HeapRegion* hr2 = g1h->region_at(5);
  1221   HeapRegion* hr3 = g1h->region_at(6);
  1222   HeapRegion* hr4 = g1h->region_at(7);
  1223   HeapRegion* hr5 = g1h->region_at(8);
  1225   HeapWord* hr1_start = hr1->bottom();
  1226   HeapWord* hr1_mid = hr1_start + HeapRegion::GrainWords/2;
  1227   HeapWord* hr1_last = hr1->end() - 1;
  1229   HeapWord* hr2_start = hr2->bottom();
  1230   HeapWord* hr2_mid = hr2_start + HeapRegion::GrainWords/2;
  1231   HeapWord* hr2_last = hr2->end() - 1;
  1233   HeapWord* hr3_start = hr3->bottom();
  1234   HeapWord* hr3_mid = hr3_start + HeapRegion::GrainWords/2;
  1235   HeapWord* hr3_last = hr3->end() - 1;
  1237   HeapRegionRemSet* hrrs = hr0->rem_set();
  1239   // Make three references from region 0x101...
  1240   hrrs->add_reference((OopOrNarrowOopStar)hr1_start);
  1241   hrrs->add_reference((OopOrNarrowOopStar)hr1_mid);
  1242   hrrs->add_reference((OopOrNarrowOopStar)hr1_last);
  1244   hrrs->add_reference((OopOrNarrowOopStar)hr2_start);
  1245   hrrs->add_reference((OopOrNarrowOopStar)hr2_mid);
  1246   hrrs->add_reference((OopOrNarrowOopStar)hr2_last);
  1248   hrrs->add_reference((OopOrNarrowOopStar)hr3_start);
  1249   hrrs->add_reference((OopOrNarrowOopStar)hr3_mid);
  1250   hrrs->add_reference((OopOrNarrowOopStar)hr3_last);
  1252   // Now cause a coarsening.
  1253   hrrs->add_reference((OopOrNarrowOopStar)hr4->bottom());
  1254   hrrs->add_reference((OopOrNarrowOopStar)hr5->bottom());
  1256   // Now, does iteration yield these three?
  1257   HeapRegionRemSetIterator iter(hrrs);
  1258   size_t sum = 0;
  1259   size_t card_index;
  1260   while (iter.has_next(card_index)) {
  1261     HeapWord* card_start =
  1262       G1CollectedHeap::heap()->bot_shared()->address_for_index(card_index);
  1263     gclog_or_tty->print_cr("  Card " PTR_FORMAT ".", card_start);
  1264     sum++;
  1266   guarantee(sum == 11 - 3 + 2048, "Failure");
  1267   guarantee(sum == hrrs->occupied(), "Failure");
  1269 #endif

mercurial