8035406: Improve data structure for Code Cache remembered sets

Mon, 24 Mar 2014 15:30:14 +0100

author
tschatzl
date
Mon, 24 Mar 2014 15:30:14 +0100
changeset 6402
191174b49bec
parent 6399
f53edbc2b728
child 6403
d7070f371770

8035406: Improve data structure for Code Cache remembered sets
Summary: Change the code cache remembered sets data structure from a GrowableArray to a chunked list of nmethods. This makes the data structure more amenable to parallelization, and decreases freeing time.
Reviewed-by: mgerdin, brutisso

make/excludeSrc.make file | annotate | diff | comparison | revisions
src/share/vm/gc_implementation/g1/g1CodeCacheRemSet.cpp file | annotate | diff | comparison | revisions
src/share/vm/gc_implementation/g1/g1CodeCacheRemSet.hpp file | annotate | diff | comparison | revisions
src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp file | annotate | diff | comparison | revisions
src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp file | annotate | diff | comparison | revisions
src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp file | annotate | diff | comparison | revisions
src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp file | annotate | diff | comparison | revisions
src/share/vm/gc_implementation/g1/g1_globals.hpp file | annotate | diff | comparison | revisions
src/share/vm/gc_implementation/g1/heapRegion.cpp file | annotate | diff | comparison | revisions
src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp file | annotate | diff | comparison | revisions
src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp file | annotate | diff | comparison | revisions
src/share/vm/memory/freeList.cpp file | annotate | diff | comparison | revisions
src/share/vm/prims/jni.cpp file | annotate | diff | comparison | revisions
test/gc/g1/TestGCLogMessages.java file | annotate | diff | comparison | revisions
     1.1 --- a/make/excludeSrc.make	Mon Mar 17 15:18:45 2014 +0100
     1.2 +++ b/make/excludeSrc.make	Mon Mar 24 15:30:14 2014 +0100
     1.3 @@ -1,5 +1,5 @@
     1.4  #
     1.5 -# Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
     1.6 +# Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
     1.7  # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     1.8  #
     1.9  # This code is free software; you can redistribute it and/or modify it
    1.10 @@ -89,7 +89,7 @@
    1.11  	g1MMUTracker.cpp g1MarkSweep.cpp g1MemoryPool.cpp g1MonitoringSupport.cpp g1OopClosures.cpp \
    1.12  	g1RemSet.cpp g1RemSetSummary.cpp g1SATBCardTableModRefBS.cpp g1_globals.cpp heapRegion.cpp \
    1.13  	g1BiasedArray.cpp heapRegionRemSet.cpp heapRegionSeq.cpp heapRegionSet.cpp heapRegionSets.cpp \
    1.14 -	ptrQueue.cpp satbQueue.cpp sparsePRT.cpp survRateGroup.cpp vm_operations_g1.cpp \
    1.15 +	ptrQueue.cpp satbQueue.cpp sparsePRT.cpp survRateGroup.cpp vm_operations_g1.cpp g1CodeCacheRemSet.cpp \
    1.16  	adjoiningGenerations.cpp adjoiningVirtualSpaces.cpp asPSOldGen.cpp asPSYoungGen.cpp \
    1.17  	cardTableExtension.cpp gcTaskManager.cpp gcTaskThread.cpp objectStartArray.cpp \
    1.18  	parallelScavengeHeap.cpp parMarkBitMap.cpp pcTasks.cpp psAdaptiveSizePolicy.cpp \
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/src/share/vm/gc_implementation/g1/g1CodeCacheRemSet.cpp	Mon Mar 24 15:30:14 2014 +0100
     2.3 @@ -0,0 +1,317 @@
     2.4 +/*
     2.5 + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
     2.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     2.7 + *
     2.8 + * This code is free software; you can redistribute it and/or modify it
     2.9 + * under the terms of the GNU General Public License version 2 only, as
    2.10 + * published by the Free Software Foundation.
    2.11 + *
    2.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
    2.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    2.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    2.15 + * version 2 for more details (a copy is included in the LICENSE file that
    2.16 + * accompanied this code).
    2.17 + *
    2.18 + * You should have received a copy of the GNU General Public License version
    2.19 + * 2 along with this work; if not, write to the Free Software Foundation,
    2.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    2.21 + *
    2.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    2.23 + * or visit www.oracle.com if you need additional information or have any
    2.24 + * questions.
    2.25 + *
    2.26 + */
    2.27 +
    2.28 +
    2.29 +#include "precompiled.hpp"
    2.30 +#include "code/nmethod.hpp"
    2.31 +#include "gc_implementation/g1/g1CodeCacheRemSet.hpp"
    2.32 +#include "memory/iterator.hpp"
    2.33 +
    2.34 +G1CodeRootChunk::G1CodeRootChunk() : _top(NULL), _next(NULL), _prev(NULL) {
    2.35 +  _top = bottom();
    2.36 +}
    2.37 +
    2.38 +void G1CodeRootChunk::reset() {
    2.39 +  _next = _prev = NULL;
    2.40 +  _top = bottom();
    2.41 +}
    2.42 +
    2.43 +void G1CodeRootChunk::nmethods_do(CodeBlobClosure* cl) {
    2.44 +  nmethod** cur = bottom();
    2.45 +  while (cur != _top) {
    2.46 +    cl->do_code_blob(*cur);
    2.47 +    cur++;
    2.48 +  }
    2.49 +}
    2.50 +
    2.51 +FreeList<G1CodeRootChunk> G1CodeRootSet::_free_list;
    2.52 +size_t G1CodeRootSet::_num_chunks_handed_out = 0;
    2.53 +
    2.54 +G1CodeRootChunk* G1CodeRootSet::new_chunk() {
    2.55 +  G1CodeRootChunk* result = _free_list.get_chunk_at_head();
    2.56 +  if (result == NULL) {
    2.57 +    result = new G1CodeRootChunk();
    2.58 +  }
    2.59 +  G1CodeRootSet::_num_chunks_handed_out++;
    2.60 +  result->reset();
    2.61 +  return result;
    2.62 +}
    2.63 +
    2.64 +void G1CodeRootSet::free_chunk(G1CodeRootChunk* chunk) {
    2.65 +  _free_list.return_chunk_at_head(chunk);
    2.66 +  G1CodeRootSet::_num_chunks_handed_out--;
    2.67 +}
    2.68 +
    2.69 +void G1CodeRootSet::free_all_chunks(FreeList<G1CodeRootChunk>* list) {
    2.70 +  G1CodeRootSet::_num_chunks_handed_out -= list->count();
    2.71 +  _free_list.prepend(list);
    2.72 +}
    2.73 +
    2.74 +void G1CodeRootSet::purge_chunks(size_t keep_ratio) {
    2.75 +  size_t keep = G1CodeRootSet::_num_chunks_handed_out * keep_ratio / 100;
    2.76 +
    2.77 +  if (keep >= (size_t)_free_list.count()) {
    2.78 +    return;
    2.79 +  }
    2.80 +
    2.81 +  FreeList<G1CodeRootChunk> temp;
    2.82 +  temp.initialize();
    2.83 +  temp.set_size(G1CodeRootChunk::word_size());
    2.84 +
    2.85 +  _free_list.getFirstNChunksFromList((size_t)_free_list.count() - keep, &temp);
    2.86 +
    2.87 +  G1CodeRootChunk* cur = temp.get_chunk_at_head();
    2.88 +  while (cur != NULL) {
    2.89 +    delete cur;
    2.90 +    cur = temp.get_chunk_at_head();
    2.91 +  }
    2.92 +}
    2.93 +
    2.94 +size_t G1CodeRootSet::static_mem_size() {
    2.95 +  return sizeof(_free_list) + sizeof(_num_chunks_handed_out);
    2.96 +}
    2.97 +
    2.98 +size_t G1CodeRootSet::fl_mem_size() {
    2.99 +  return _free_list.count() * _free_list.size();
   2.100 +}
   2.101 +
   2.102 +void G1CodeRootSet::initialize() {
   2.103 +  _free_list.initialize();
   2.104 +  _free_list.set_size(G1CodeRootChunk::word_size());
   2.105 +}
   2.106 +
   2.107 +G1CodeRootSet::G1CodeRootSet() : _list(), _length(0) {
   2.108 +  _list.initialize();
   2.109 +  _list.set_size(G1CodeRootChunk::word_size());
   2.110 +}
   2.111 +
   2.112 +G1CodeRootSet::~G1CodeRootSet() {
   2.113 +  clear();
   2.114 +}
   2.115 +
   2.116 +void G1CodeRootSet::add(nmethod* method) {
   2.117 +  if (!contains(method)) {
   2.118 +    // Try to add the nmethod. If there is not enough space, get a new chunk.
   2.119 +    if (_list.head() == NULL || _list.head()->is_full()) {
   2.120 +      G1CodeRootChunk* cur = new_chunk();
   2.121 +      _list.return_chunk_at_head(cur);
   2.122 +    }
   2.123 +    bool result = _list.head()->add(method);
   2.124 +    guarantee(result, err_msg("Not able to add nmethod "PTR_FORMAT" to newly allocated chunk.", method));
   2.125 +    _length++;
   2.126 +  }
   2.127 +}
   2.128 +
   2.129 +void G1CodeRootSet::remove(nmethod* method) {
   2.130 +  G1CodeRootChunk* found = find(method);
   2.131 +  if (found != NULL) {
   2.132 +    bool result = found->remove(method);
   2.133 +    guarantee(result, err_msg("could not find nmethod "PTR_FORMAT" during removal although we previously found it", method));
   2.134 +    // eventually free completely emptied chunk
   2.135 +    if (found->is_empty()) {
   2.136 +      _list.remove_chunk(found);
   2.137 +      free(found);
   2.138 +    }
   2.139 +    _length--;
   2.140 +  }
   2.141 +  assert(!contains(method), err_msg(PTR_FORMAT" still contains nmethod "PTR_FORMAT, this, method));
   2.142 +}
   2.143 +
   2.144 +nmethod* G1CodeRootSet::pop() {
   2.145 +  do {
   2.146 +    G1CodeRootChunk* cur = _list.head();
   2.147 +    if (cur == NULL) {
   2.148 +      assert(_length == 0, "when there are no chunks, there should be no elements");
   2.149 +      return NULL;
   2.150 +    }
   2.151 +    nmethod* result = cur->pop();
   2.152 +    if (result != NULL) {
   2.153 +      _length--;
   2.154 +      return result;
   2.155 +    } else {
   2.156 +      free(_list.get_chunk_at_head());
   2.157 +    }
   2.158 +  } while (true);
   2.159 +}
   2.160 +
   2.161 +G1CodeRootChunk* G1CodeRootSet::find(nmethod* method) {
   2.162 +  G1CodeRootChunk* cur = _list.head();
   2.163 +  while (cur != NULL) {
   2.164 +    if (cur->contains(method)) {
   2.165 +      return cur;
   2.166 +    }
   2.167 +    cur = (G1CodeRootChunk*)cur->next();
   2.168 +  }
   2.169 +  return NULL;
   2.170 +}
   2.171 +
   2.172 +void G1CodeRootSet::free(G1CodeRootChunk* chunk) {
   2.173 +  free_chunk(chunk);
   2.174 +}
   2.175 +
   2.176 +bool G1CodeRootSet::contains(nmethod* method) {
   2.177 +  return find(method) != NULL;
   2.178 +}
   2.179 +
   2.180 +void G1CodeRootSet::clear() {
   2.181 +  free_all_chunks(&_list);
   2.182 +  _length = 0;
   2.183 +}
   2.184 +
   2.185 +void G1CodeRootSet::nmethods_do(CodeBlobClosure* blk) const {
   2.186 +  G1CodeRootChunk* cur = _list.head();
   2.187 +  while (cur != NULL) {
   2.188 +    cur->nmethods_do(blk);
   2.189 +    cur = (G1CodeRootChunk*)cur->next();
   2.190 +  }
   2.191 +}
   2.192 +
   2.193 +size_t G1CodeRootSet::mem_size() {
   2.194 +  return sizeof(this) + _list.count() * _list.size();
   2.195 +}
   2.196 +
   2.197 +#ifndef PRODUCT
   2.198 +
   2.199 +void G1CodeRootSet::test() {
   2.200 +  initialize();
   2.201 +
   2.202 +  assert(_free_list.count() == 0, "Free List must be empty");
   2.203 +  assert(_num_chunks_handed_out == 0, "No elements must have been handed out yet");
   2.204 +
   2.205 +  // The number of chunks that we allocate for purge testing.
   2.206 +  size_t const num_chunks = 10;
   2.207 +  {
   2.208 +    G1CodeRootSet set1;
   2.209 +    assert(set1.is_empty(), "Code root set must be initially empty but is not.");
   2.210 +
   2.211 +    set1.add((nmethod*)1);
   2.212 +    assert(_num_chunks_handed_out == 1,
   2.213 +           err_msg("Must have allocated and handed out one chunk, but handed out "
   2.214 +                   SIZE_FORMAT" chunks", _num_chunks_handed_out));
   2.215 +    assert(set1.length() == 1, err_msg("Added exactly one element, but set contains "
   2.216 +                                       SIZE_FORMAT" elements", set1.length()));
   2.217 +
   2.218 +    // G1CodeRootChunk::word_size() is larger than G1CodeRootChunk::num_entries which
   2.219 +    // we cannot access.
   2.220 +    for (uint i = 0; i < G1CodeRootChunk::word_size() + 1; i++) {
   2.221 +      set1.add((nmethod*)1);
   2.222 +    }
   2.223 +    assert(_num_chunks_handed_out == 1,
   2.224 +           err_msg("Duplicate detection must have prevented allocation of further "
   2.225 +                   "chunks but contains "SIZE_FORMAT, _num_chunks_handed_out));
   2.226 +    assert(set1.length() == 1,
   2.227 +           err_msg("Duplicate detection should not have increased the set size but "
   2.228 +                   "is "SIZE_FORMAT, set1.length()));
   2.229 +
   2.230 +    size_t num_total_after_add = G1CodeRootChunk::word_size() + 1;
   2.231 +    for (size_t i = 0; i < num_total_after_add - 1; i++) {
   2.232 +      set1.add((nmethod*)(2 + i));
   2.233 +    }
   2.234 +    assert(_num_chunks_handed_out > 1,
   2.235 +           "After adding more code roots, more than one chunks should have been handed out");
   2.236 +    assert(set1.length() == num_total_after_add,
   2.237 +           err_msg("After adding in total "SIZE_FORMAT" distinct code roots, they "
   2.238 +                   "need to be in the set, but there are only "SIZE_FORMAT,
   2.239 +                   num_total_after_add, set1.length()));
   2.240 +
   2.241 +    size_t num_popped = 0;
   2.242 +    while (set1.pop() != NULL) {
   2.243 +      num_popped++;
   2.244 +    }
   2.245 +    assert(num_popped == num_total_after_add,
   2.246 +           err_msg("Managed to pop "SIZE_FORMAT" code roots, but only "SIZE_FORMAT" "
   2.247 +                   "were added", num_popped, num_total_after_add));
   2.248 +    assert(_num_chunks_handed_out == 0,
   2.249 +           err_msg("After popping all elements, all chunks must have been returned "
   2.250 +                   "but are still "SIZE_FORMAT, _num_chunks_handed_out));
   2.251 +
   2.252 +    purge_chunks(0);
   2.253 +    assert(_free_list.count() == 0,
   2.254 +           err_msg("After purging everything, the free list must be empty but still "
   2.255 +                   "contains "SIZE_FORMAT" chunks", _free_list.count()));
   2.256 +
   2.257 +    // Add some more handed out chunks.
   2.258 +    size_t i = 0;
   2.259 +    while (_num_chunks_handed_out < num_chunks) {
   2.260 +      set1.add((nmethod*)i);
   2.261 +      i++;
   2.262 +    }
   2.263 +
   2.264 +    {
   2.265 +      // Generate chunks on the free list.
   2.266 +      G1CodeRootSet set2;
   2.267 +      size_t i = 0;
   2.268 +      while (_num_chunks_handed_out < num_chunks * 2) {
   2.269 +        set2.add((nmethod*)i);
   2.270 +        i++;
   2.271 +      }
   2.272 +      // Exit of the scope of the set2 object will call the destructor that generates
   2.273 +      // num_chunks elements on the free list.
   2.274 +    }
   2.275 +
   2.276 +    assert(_num_chunks_handed_out == num_chunks,
   2.277 +           err_msg("Deletion of the second set must have resulted in giving back "
   2.278 +                   "those, but there is still "SIZE_FORMAT" handed out, expecting "
   2.279 +                   SIZE_FORMAT, _num_chunks_handed_out, num_chunks));
   2.280 +    assert((size_t)_free_list.count() == num_chunks,
   2.281 +           err_msg("After freeing "SIZE_FORMAT" chunks, they must be on the free list "
   2.282 +                   "but there are only "SIZE_FORMAT, num_chunks, _free_list.count()));
   2.283 +
   2.284 +    size_t const test_percentage = 50;
   2.285 +    purge_chunks(test_percentage);
   2.286 +    assert(_num_chunks_handed_out == num_chunks,
   2.287 +           err_msg("Purging must not hand out chunks but there are "SIZE_FORMAT,
   2.288 +                   _num_chunks_handed_out));
   2.289 +    assert((size_t)_free_list.count() == (ssize_t)(num_chunks * test_percentage / 100),
   2.290 +           err_msg("Must have purged "SIZE_FORMAT" percent of "SIZE_FORMAT" chunks"
   2.291 +                   "but there are "SSIZE_FORMAT, test_percentage, num_chunks,
   2.292 +                   _free_list.count()));
   2.293 +    // Purge the remainder of the chunks on the free list.
   2.294 +    purge_chunks(0);
   2.295 +    assert(_free_list.count() == 0, "Free List must be empty");
   2.296 +    assert(_num_chunks_handed_out == num_chunks,
   2.297 +           err_msg("Expected to be "SIZE_FORMAT" chunks handed out from the first set "
   2.298 +                   "but there are "SIZE_FORMAT, num_chunks, _num_chunks_handed_out));
   2.299 +
   2.300 +    // Exit of the scope of the set1 object will call the destructor that generates
   2.301 +    // num_chunks additional elements on the free list.
   2.302 +  }
   2.303 +
   2.304 +  assert(_num_chunks_handed_out == 0,
   2.305 +         err_msg("Deletion of the only set must have resulted in no chunks handed "
   2.306 +                 "out, but there is still "SIZE_FORMAT" handed out", _num_chunks_handed_out));
   2.307 +  assert((size_t)_free_list.count() == num_chunks,
   2.308 +         err_msg("After freeing "SIZE_FORMAT" chunks, they must be on the free list "
   2.309 +                 "but there are only "SSIZE_FORMAT, num_chunks, _free_list.count()));
   2.310 +
   2.311 +  // Restore initial state.
   2.312 +  purge_chunks(0);
   2.313 +  assert(_free_list.count() == 0, "Free List must be empty");
   2.314 +  assert(_num_chunks_handed_out == 0, "No elements must have been handed out yet");
   2.315 +}
   2.316 +
   2.317 +void TestCodeCacheRemSet_test() {
   2.318 +  G1CodeRootSet::test();
   2.319 +}
   2.320 +#endif
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/src/share/vm/gc_implementation/g1/g1CodeCacheRemSet.hpp	Mon Mar 24 15:30:14 2014 +0100
     3.3 @@ -0,0 +1,188 @@
     3.4 +/*
     3.5 + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
     3.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     3.7 + *
     3.8 + * This code is free software; you can redistribute it and/or modify it
     3.9 + * under the terms of the GNU General Public License version 2 only, as
    3.10 + * published by the Free Software Foundation.
    3.11 + *
    3.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
    3.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    3.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    3.15 + * version 2 for more details (a copy is included in the LICENSE file that
    3.16 + * accompanied this code).
    3.17 + *
    3.18 + * You should have received a copy of the GNU General Public License version
    3.19 + * 2 along with this work; if not, write to the Free Software Foundation,
    3.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    3.21 + *
    3.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    3.23 + * or visit www.oracle.com if you need additional information or have any
    3.24 + * questions.
    3.25 + *
    3.26 + */
    3.27 +
    3.28 +#ifndef SHARE_VM_GC_IMPLEMENTATION_G1_G1CODECACHEREMSET_HPP
    3.29 +#define SHARE_VM_GC_IMPLEMENTATION_G1_G1CODECACHEREMSET_HPP
    3.30 +
    3.31 +#include "memory/allocation.hpp"
    3.32 +#include "memory/freeList.hpp"
    3.33 +#include "runtime/globals.hpp"
    3.34 +
    3.35 +class CodeBlobClosure;
    3.36 +
    3.37 +class G1CodeRootChunk : public CHeapObj<mtGC> {
    3.38 + private:
    3.39 +  static const int NUM_ENTRIES = 32;
    3.40 + public:
    3.41 +  G1CodeRootChunk*     _next;
    3.42 +  G1CodeRootChunk*     _prev;
    3.43 +
    3.44 +  nmethod** _top;
    3.45 +
    3.46 +  nmethod* _data[NUM_ENTRIES];
    3.47 +
    3.48 +  nmethod** bottom() const {
    3.49 +    return (nmethod**) &(_data[0]);
    3.50 +  }
    3.51 +
    3.52 +  nmethod** end() const {
    3.53 +    return (nmethod**) &(_data[NUM_ENTRIES]);
    3.54 +  }
    3.55 +
    3.56 + public:
    3.57 +  G1CodeRootChunk();
    3.58 +  ~G1CodeRootChunk() {}
    3.59 +
    3.60 +  static size_t word_size() { return (size_t)(align_size_up_(sizeof(G1CodeRootChunk), HeapWordSize) / HeapWordSize); }
    3.61 +
    3.62 +  // FreeList "interface" methods
    3.63 +
    3.64 +  G1CodeRootChunk* next() const         { return _next; }
    3.65 +  G1CodeRootChunk* prev() const         { return _prev; }
    3.66 +  void set_next(G1CodeRootChunk* v)     { _next = v; assert(v != this, "Boom");}
    3.67 +  void set_prev(G1CodeRootChunk* v)     { _prev = v; assert(v != this, "Boom");}
    3.68 +  void clear_next()       { set_next(NULL); }
    3.69 +  void clear_prev()       { set_prev(NULL); }
    3.70 +
    3.71 +  size_t size() const { return word_size(); }
    3.72 +
    3.73 +  void link_next(G1CodeRootChunk* ptr)  { set_next(ptr); }
    3.74 +  void link_prev(G1CodeRootChunk* ptr)  { set_prev(ptr); }
    3.75 +  void link_after(G1CodeRootChunk* ptr) {
    3.76 +    link_next(ptr);
    3.77 +    if (ptr != NULL) ptr->link_prev((G1CodeRootChunk*)this);
    3.78 +  }
    3.79 +
    3.80 +  bool is_free()                 { return true; }
    3.81 +
    3.82 +  // New G1CodeRootChunk routines
    3.83 +
    3.84 +  void reset();
    3.85 +
    3.86 +  bool is_empty() const {
    3.87 +    return _top == bottom();
    3.88 +  }
    3.89 +
    3.90 +  bool is_full() const {
    3.91 +    return _top == (nmethod**)end();
    3.92 +  }
    3.93 +
    3.94 +  bool contains(nmethod* method) {
    3.95 +    nmethod** cur = bottom();
    3.96 +    while (cur != _top) {
    3.97 +      if (*cur == method) return true;
    3.98 +      cur++;
    3.99 +    }
   3.100 +    return false;
   3.101 +  }
   3.102 +
   3.103 +  bool add(nmethod* method) {
   3.104 +    if (is_full()) return false;
   3.105 +    *_top = method;
   3.106 +    _top++;
   3.107 +    return true;
   3.108 +  }
   3.109 +
   3.110 +  bool remove(nmethod* method) {
   3.111 +    nmethod** cur = bottom();
   3.112 +    while (cur != _top) {
   3.113 +      if (*cur == method) {
   3.114 +        memmove(cur, cur + 1, (_top - (cur + 1)) * sizeof(nmethod**));
   3.115 +        _top--;
   3.116 +        return true;
   3.117 +      }
   3.118 +      cur++;
   3.119 +    }
   3.120 +    return false;
   3.121 +  }
   3.122 +
   3.123 +  void nmethods_do(CodeBlobClosure* blk);
   3.124 +
   3.125 +  nmethod* pop() {
   3.126 +    if (is_empty()) {
   3.127 +      return NULL;
   3.128 +    }
   3.129 +    _top--;
   3.130 +    return *_top;
   3.131 +  }
   3.132 +};
   3.133 +
   3.134 +// Implements storage for a set of code roots.
   3.135 +// All methods that modify the set are not thread-safe except if otherwise noted.
   3.136 +class G1CodeRootSet VALUE_OBJ_CLASS_SPEC {
   3.137 + private:
   3.138 +  // Global free chunk list management
   3.139 +  static FreeList<G1CodeRootChunk> _free_list;
   3.140 +  // Total number of chunks handed out
   3.141 +  static size_t _num_chunks_handed_out;
   3.142 +
   3.143 +  static G1CodeRootChunk* new_chunk();
   3.144 +  static void free_chunk(G1CodeRootChunk* chunk);
   3.145 +  // Free all elements of the given list.
   3.146 +  static void free_all_chunks(FreeList<G1CodeRootChunk>* list);
   3.147 +
   3.148 +  // Return the chunk that contains the given nmethod, NULL otherwise.
   3.149 +  // Scans the list of chunks backwards, as this method is used to add new
   3.150 +  // entries, which are typically added in bulk for a single nmethod.
   3.151 +  G1CodeRootChunk* find(nmethod* method);
   3.152 +  void free(G1CodeRootChunk* chunk);
   3.153 +
   3.154 +  size_t _length;
   3.155 +  FreeList<G1CodeRootChunk> _list;
   3.156 +
   3.157 + public:
   3.158 +  G1CodeRootSet();
   3.159 +  ~G1CodeRootSet();
   3.160 +
   3.161 +  static void initialize();
   3.162 +  static void purge_chunks(size_t keep_ratio);
   3.163 +
   3.164 +  static size_t static_mem_size();
   3.165 +  static size_t fl_mem_size();
   3.166 +
   3.167 +  // Search for the code blob from the recently allocated ones to find duplicates more quickly, as this
   3.168 +  // method is likely to be repeatedly called with the same nmethod.
   3.169 +  void add(nmethod* method);
   3.170 +
   3.171 +  void remove(nmethod* method);
   3.172 +  nmethod* pop();
   3.173 +
   3.174 +  bool contains(nmethod* method);
   3.175 +
   3.176 +  void clear();
   3.177 +
   3.178 +  void nmethods_do(CodeBlobClosure* blk) const;
   3.179 +
   3.180 +  bool is_empty() { return length() == 0; }
   3.181 +
   3.182 +  // Length in elements
   3.183 +  size_t length() const { return _length; }
   3.184 +
   3.185 +  // Memory size in bytes taken by this set.
   3.186 +  size_t mem_size();
   3.187 +
   3.188 +  static void test() PRODUCT_RETURN;
   3.189 +};
   3.190 +
   3.191 +#endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1CODECACHEREMSET_HPP
     4.1 --- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp	Mon Mar 17 15:18:45 2014 +0100
     4.2 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp	Mon Mar 24 15:30:14 2014 +0100
     4.3 @@ -5934,6 +5934,8 @@
     4.4    // strong code roots for a particular heap region.
     4.5    migrate_strong_code_roots();
     4.6  
     4.7 +  purge_code_root_memory();
     4.8 +
     4.9    if (g1_policy()->during_initial_mark_pause()) {
    4.10      // Reset the claim values set during marking the strong code roots
    4.11      reset_heap_region_claim_values();
    4.12 @@ -6810,6 +6812,13 @@
    4.13    g1_policy()->phase_times()->record_strong_code_root_migration_time(migration_time_ms);
    4.14  }
    4.15  
    4.16 +void G1CollectedHeap::purge_code_root_memory() {
    4.17 +  double purge_start = os::elapsedTime();
    4.18 +  G1CodeRootSet::purge_chunks(G1CodeRootsChunkCacheKeepPercent);
    4.19 +  double purge_time_ms = (os::elapsedTime() - purge_start) * 1000.0;
    4.20 +  g1_policy()->phase_times()->record_strong_code_root_purge_time(purge_time_ms);
    4.21 +}
    4.22 +
    4.23  // Mark all the code roots that point into regions *not* in the
    4.24  // collection set.
    4.25  //
    4.26 @@ -6880,7 +6889,7 @@
    4.27        // Code roots should never be attached to a continuation of a humongous region
    4.28        assert(hrrs->strong_code_roots_list_length() == 0,
    4.29               err_msg("code roots should never be attached to continuations of humongous region "HR_FORMAT
    4.30 -                     " starting at "HR_FORMAT", but has "INT32_FORMAT,
    4.31 +                     " starting at "HR_FORMAT", but has "SIZE_FORMAT,
    4.32                       HR_FORMAT_PARAMS(hr), HR_FORMAT_PARAMS(hr->humongous_start_region()),
    4.33                       hrrs->strong_code_roots_list_length()));
    4.34        return false;
     5.1 --- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp	Mon Mar 17 15:18:45 2014 +0100
     5.2 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp	Mon Mar 24 15:30:14 2014 +0100
     5.3 @@ -1,5 +1,5 @@
     5.4  /*
     5.5 - * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
     5.6 + * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved.
     5.7   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     5.8   *
     5.9   * This code is free software; you can redistribute it and/or modify it
    5.10 @@ -1647,6 +1647,9 @@
    5.11    // that were not successfullly evacuated are not migrated.
    5.12    void migrate_strong_code_roots();
    5.13  
    5.14 +  // Free up superfluous code root memory.
    5.15 +  void purge_code_root_memory();
    5.16 +
    5.17    // During an initial mark pause, mark all the code roots that
    5.18    // point into regions *not* in the collection set.
    5.19    void mark_strong_code_roots(uint worker_id);
     6.1 --- a/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp	Mon Mar 17 15:18:45 2014 +0100
     6.2 +++ b/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp	Mon Mar 24 15:30:14 2014 +0100
     6.3 @@ -1,5 +1,5 @@
     6.4  /*
     6.5 - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
     6.6 + * Copyright (c) 2013, 2014 Oracle and/or its affiliates. All rights reserved.
     6.7   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     6.8   *
     6.9   * This code is free software; you can redistribute it and/or modify it
    6.10 @@ -250,6 +250,9 @@
    6.11      // Strong code root migration time
    6.12      misc_time_ms += _cur_strong_code_root_migration_time_ms;
    6.13  
    6.14 +    // Strong code root purge time
    6.15 +    misc_time_ms += _cur_strong_code_root_purge_time_ms;
    6.16 +
    6.17      // Subtract the time taken to clean the card table from the
    6.18      // current value of "other time"
    6.19      misc_time_ms += _cur_clear_ct_time_ms;
    6.20 @@ -299,6 +302,7 @@
    6.21    }
    6.22    print_stats(1, "Code Root Fixup", _cur_collection_code_root_fixup_time_ms);
    6.23    print_stats(1, "Code Root Migration", _cur_strong_code_root_migration_time_ms);
    6.24 +  print_stats(1, "Code Root Purge", _cur_strong_code_root_purge_time_ms);
    6.25    print_stats(1, "Clear CT", _cur_clear_ct_time_ms);
    6.26    double misc_time_ms = pause_time_sec * MILLIUNITS - accounted_time_ms();
    6.27    print_stats(1, "Other", misc_time_ms);
     7.1 --- a/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp	Mon Mar 17 15:18:45 2014 +0100
     7.2 +++ b/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp	Mon Mar 24 15:30:14 2014 +0100
     7.3 @@ -1,5 +1,5 @@
     7.4  /*
     7.5 - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
     7.6 + * Copyright (c) 2013, 2014 Oracle and/or its affiliates. All rights reserved.
     7.7   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     7.8   *
     7.9   * This code is free software; you can redistribute it and/or modify it
    7.10 @@ -131,6 +131,7 @@
    7.11    double _cur_collection_par_time_ms;
    7.12    double _cur_collection_code_root_fixup_time_ms;
    7.13    double _cur_strong_code_root_migration_time_ms;
    7.14 +  double _cur_strong_code_root_purge_time_ms;
    7.15  
    7.16    double _cur_clear_ct_time_ms;
    7.17    double _cur_ref_proc_time_ms;
    7.18 @@ -223,6 +224,10 @@
    7.19      _cur_strong_code_root_migration_time_ms = ms;
    7.20    }
    7.21  
    7.22 +  void record_strong_code_root_purge_time(double ms) {
    7.23 +    _cur_strong_code_root_purge_time_ms = ms;
    7.24 +  }
    7.25 +
    7.26    void record_ref_proc_time(double ms) {
    7.27      _cur_ref_proc_time_ms = ms;
    7.28    }
     8.1 --- a/src/share/vm/gc_implementation/g1/g1_globals.hpp	Mon Mar 17 15:18:45 2014 +0100
     8.2 +++ b/src/share/vm/gc_implementation/g1/g1_globals.hpp	Mon Mar 24 15:30:14 2014 +0100
     8.3 @@ -1,5 +1,5 @@
     8.4  /*
     8.5 - * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
     8.6 + * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved.
     8.7   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     8.8   *
     8.9   * This code is free software; you can redistribute it and/or modify it
    8.10 @@ -285,6 +285,10 @@
    8.11    product(uintx, G1MixedGCCountTarget, 8,                                   \
    8.12            "The target number of mixed GCs after a marking cycle.")          \
    8.13                                                                              \
    8.14 +  experimental(uintx, G1CodeRootsChunkCacheKeepPercent, 10,                 \
    8.15 +          "The amount of code root chunks that should be kept at most "     \
    8.16 +          "as percentage of already allocated.")                            \
    8.17 +                                                                            \
    8.18    experimental(uintx, G1OldCSetRegionThresholdPercent, 10,                  \
    8.19            "An upper bound for the number of old CSet regions expressed "    \
    8.20            "as a percentage of the heap size.")                              \
     9.1 --- a/src/share/vm/gc_implementation/g1/heapRegion.cpp	Mon Mar 17 15:18:45 2014 +0100
     9.2 +++ b/src/share/vm/gc_implementation/g1/heapRegion.cpp	Mon Mar 24 15:30:14 2014 +0100
     9.3 @@ -710,14 +710,14 @@
     9.4    }
     9.5  
     9.6    HeapRegionRemSet* hrrs = rem_set();
     9.7 -  int strong_code_roots_length = hrrs->strong_code_roots_list_length();
     9.8 +  size_t strong_code_roots_length = hrrs->strong_code_roots_list_length();
     9.9  
    9.10    // if this region is empty then there should be no entries
    9.11    // on its strong code root list
    9.12    if (is_empty()) {
    9.13      if (strong_code_roots_length > 0) {
    9.14        gclog_or_tty->print_cr("region ["PTR_FORMAT","PTR_FORMAT"] is empty "
    9.15 -                             "but has "INT32_FORMAT" code root entries",
    9.16 +                             "but has "SIZE_FORMAT" code root entries",
    9.17                               bottom(), end(), strong_code_roots_length);
    9.18        *failures = true;
    9.19      }
    9.20 @@ -727,7 +727,7 @@
    9.21    if (continuesHumongous()) {
    9.22      if (strong_code_roots_length > 0) {
    9.23        gclog_or_tty->print_cr("region "HR_FORMAT" is a continuation of a humongous "
    9.24 -                             "region but has "INT32_FORMAT" code root entries",
    9.25 +                             "region but has "SIZE_FORMAT" code root entries",
    9.26                               HR_FORMAT_PARAMS(this), strong_code_roots_length);
    9.27        *failures = true;
    9.28      }
    10.1 --- a/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp	Mon Mar 17 15:18:45 2014 +0100
    10.2 +++ b/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp	Mon Mar 24 15:30:14 2014 +0100
    10.3 @@ -1,5 +1,5 @@
    10.4  /*
    10.5 - * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
    10.6 + * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved.
    10.7   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    10.8   *
    10.9   * This code is free software; you can redistribute it and/or modify it
   10.10 @@ -259,10 +259,9 @@
   10.11  size_t OtherRegionsTable::_fine_eviction_stride = 0;
   10.12  size_t OtherRegionsTable::_fine_eviction_sample_size = 0;
   10.13  
   10.14 -OtherRegionsTable::OtherRegionsTable(HeapRegion* hr) :
   10.15 +OtherRegionsTable::OtherRegionsTable(HeapRegion* hr, Mutex* m) :
   10.16    _g1h(G1CollectedHeap::heap()),
   10.17 -  _m(Mutex::leaf, "An OtherRegionsTable lock", true),
   10.18 -  _hr(hr),
   10.19 +  _hr(hr), _m(m),
   10.20    _coarse_map(G1CollectedHeap::heap()->max_regions(),
   10.21                false /* in-resource-area */),
   10.22    _fine_grain_regions(NULL),
   10.23 @@ -442,7 +441,7 @@
   10.24    size_t ind = from_hrs_ind & _mod_max_fine_entries_mask;
   10.25    PerRegionTable* prt = find_region_table(ind, from_hr);
   10.26    if (prt == NULL) {
   10.27 -    MutexLockerEx x(&_m, Mutex::_no_safepoint_check_flag);
   10.28 +    MutexLockerEx x(_m, Mutex::_no_safepoint_check_flag);
   10.29      // Confirm that it's really not there...
   10.30      prt = find_region_table(ind, from_hr);
   10.31      if (prt == NULL) {
   10.32 @@ -544,7 +543,7 @@
   10.33  jint OtherRegionsTable::_n_coarsenings = 0;
   10.34  
   10.35  PerRegionTable* OtherRegionsTable::delete_region_table() {
   10.36 -  assert(_m.owned_by_self(), "Precondition");
   10.37 +  assert(_m->owned_by_self(), "Precondition");
   10.38    assert(_n_fine_entries == _max_fine_entries, "Precondition");
   10.39    PerRegionTable* max = NULL;
   10.40    jint max_occ = 0;
   10.41 @@ -676,8 +675,6 @@
   10.42  
   10.43  
   10.44  size_t OtherRegionsTable::occupied() const {
   10.45 -  // Cast away const in this case.
   10.46 -  MutexLockerEx x((Mutex*)&_m, Mutex::_no_safepoint_check_flag);
   10.47    size_t sum = occ_fine();
   10.48    sum += occ_sparse();
   10.49    sum += occ_coarse();
   10.50 @@ -707,8 +704,6 @@
   10.51  }
   10.52  
   10.53  size_t OtherRegionsTable::mem_size() const {
   10.54 -  // Cast away const in this case.
   10.55 -  MutexLockerEx x((Mutex*)&_m, Mutex::_no_safepoint_check_flag);
   10.56    size_t sum = 0;
   10.57    // all PRTs are of the same size so it is sufficient to query only one of them.
   10.58    if (_first_all_fine_prts != NULL) {
   10.59 @@ -739,7 +734,6 @@
   10.60  }
   10.61  
   10.62  void OtherRegionsTable::clear() {
   10.63 -  MutexLockerEx x(&_m, Mutex::_no_safepoint_check_flag);
   10.64    // if there are no entries, skip this step
   10.65    if (_first_all_fine_prts != NULL) {
   10.66      guarantee(_first_all_fine_prts != NULL && _last_all_fine_prts != NULL, "just checking");
   10.67 @@ -759,7 +753,7 @@
   10.68  }
   10.69  
   10.70  void OtherRegionsTable::clear_incoming_entry(HeapRegion* from_hr) {
   10.71 -  MutexLockerEx x(&_m, Mutex::_no_safepoint_check_flag);
   10.72 +  MutexLockerEx x(_m, Mutex::_no_safepoint_check_flag);
   10.73    size_t hrs_ind = (size_t) from_hr->hrs_index();
   10.74    size_t ind = hrs_ind & _mod_max_fine_entries_mask;
   10.75    if (del_single_region_table(ind, from_hr)) {
   10.76 @@ -805,7 +799,7 @@
   10.77  
   10.78  bool OtherRegionsTable::contains_reference(OopOrNarrowOopStar from) const {
   10.79    // Cast away const in this case.
   10.80 -  MutexLockerEx x((Mutex*)&_m, Mutex::_no_safepoint_check_flag);
   10.81 +  MutexLockerEx x((Mutex*)_m, Mutex::_no_safepoint_check_flag);
   10.82    return contains_reference_locked(from);
   10.83  }
   10.84  
   10.85 @@ -850,7 +844,9 @@
   10.86  
   10.87  HeapRegionRemSet::HeapRegionRemSet(G1BlockOffsetSharedArray* bosa,
   10.88                                     HeapRegion* hr)
   10.89 -  : _bosa(bosa), _strong_code_roots_list(NULL), _other_regions(hr) {
   10.90 +  : _bosa(bosa),
   10.91 +    _m(Mutex::leaf, FormatBuffer<128>("HeapRegionRemSet lock #"UINT32_FORMAT, hr->hrs_index()), true),
   10.92 +    _code_roots(), _other_regions(hr, &_m) {
   10.93    reset_for_par_iteration();
   10.94  }
   10.95  
   10.96 @@ -883,7 +879,7 @@
   10.97  }
   10.98  
   10.99  #ifndef PRODUCT
  10.100 -void HeapRegionRemSet::print() const {
  10.101 +void HeapRegionRemSet::print() {
  10.102    HeapRegionRemSetIterator iter(this);
  10.103    size_t card_index;
  10.104    while (iter.has_next(card_index)) {
  10.105 @@ -909,14 +905,14 @@
  10.106  }
  10.107  
  10.108  void HeapRegionRemSet::clear() {
  10.109 -  if (_strong_code_roots_list != NULL) {
  10.110 -    delete _strong_code_roots_list;
  10.111 -  }
  10.112 -  _strong_code_roots_list = new (ResourceObj::C_HEAP, mtGC)
  10.113 -                                GrowableArray<nmethod*>(10, 0, NULL, true);
  10.114 +  MutexLockerEx x(&_m, Mutex::_no_safepoint_check_flag);
  10.115 +  clear_locked();
  10.116 +}
  10.117  
  10.118 +void HeapRegionRemSet::clear_locked() {
  10.119 +  _code_roots.clear();
  10.120    _other_regions.clear();
  10.121 -  assert(occupied() == 0, "Should be clear.");
  10.122 +  assert(occupied_locked() == 0, "Should be clear.");
  10.123    reset_for_par_iteration();
  10.124  }
  10.125  
  10.126 @@ -937,22 +933,14 @@
  10.127  
  10.128  void HeapRegionRemSet::add_strong_code_root(nmethod* nm) {
  10.129    assert(nm != NULL, "sanity");
  10.130 -  // Search for the code blob from the RHS to avoid
  10.131 -  // duplicate entries as much as possible
  10.132 -  if (_strong_code_roots_list->find_from_end(nm) < 0) {
  10.133 -    // Code blob isn't already in the list
  10.134 -    _strong_code_roots_list->push(nm);
  10.135 -  }
  10.136 +  _code_roots.add(nm);
  10.137  }
  10.138  
  10.139  void HeapRegionRemSet::remove_strong_code_root(nmethod* nm) {
  10.140    assert(nm != NULL, "sanity");
  10.141 -  int idx = _strong_code_roots_list->find(nm);
  10.142 -  if (idx >= 0) {
  10.143 -    _strong_code_roots_list->remove_at(idx);
  10.144 -  }
  10.145 +  _code_roots.remove(nm);
  10.146    // Check that there were no duplicates
  10.147 -  guarantee(_strong_code_roots_list->find(nm) < 0, "duplicate entry found");
  10.148 +  guarantee(!_code_roots.contains(nm), "duplicate entry found");
  10.149  }
  10.150  
  10.151  class NMethodMigrationOopClosure : public OopClosure {
  10.152 @@ -1014,8 +1002,8 @@
  10.153    GrowableArray<nmethod*> to_be_retained(10);
  10.154    G1CollectedHeap* g1h = G1CollectedHeap::heap();
  10.155  
  10.156 -  while (_strong_code_roots_list->is_nonempty()) {
  10.157 -    nmethod *nm = _strong_code_roots_list->pop();
  10.158 +  while (!_code_roots.is_empty()) {
  10.159 +    nmethod *nm = _code_roots.pop();
  10.160      if (nm != NULL) {
  10.161        NMethodMigrationOopClosure oop_cl(g1h, hr(), nm);
  10.162        nm->oops_do(&oop_cl);
  10.163 @@ -1038,20 +1026,16 @@
  10.164  }
  10.165  
  10.166  void HeapRegionRemSet::strong_code_roots_do(CodeBlobClosure* blk) const {
  10.167 -  for (int i = 0; i < _strong_code_roots_list->length(); i += 1) {
  10.168 -    nmethod* nm = _strong_code_roots_list->at(i);
  10.169 -    blk->do_code_blob(nm);
  10.170 -  }
  10.171 +  _code_roots.nmethods_do(blk);
  10.172  }
  10.173  
  10.174  size_t HeapRegionRemSet::strong_code_roots_mem_size() {
  10.175 -  return sizeof(GrowableArray<nmethod*>) +
  10.176 -         _strong_code_roots_list->max_length() * sizeof(nmethod*);
  10.177 +  return _code_roots.mem_size();
  10.178  }
  10.179  
  10.180  //-------------------- Iteration --------------------
  10.181  
  10.182 -HeapRegionRemSetIterator:: HeapRegionRemSetIterator(const HeapRegionRemSet* hrrs) :
  10.183 +HeapRegionRemSetIterator:: HeapRegionRemSetIterator(HeapRegionRemSet* hrrs) :
  10.184    _hrrs(hrrs),
  10.185    _g1h(G1CollectedHeap::heap()),
  10.186    _coarse_map(&hrrs->_other_regions._coarse_map),
    11.1 --- a/src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp	Mon Mar 17 15:18:45 2014 +0100
    11.2 +++ b/src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp	Mon Mar 24 15:30:14 2014 +0100
    11.3 @@ -1,5 +1,5 @@
    11.4  /*
    11.5 - * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
    11.6 + * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved.
    11.7   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    11.8   *
    11.9   * This code is free software; you can redistribute it and/or modify it
   11.10 @@ -25,6 +25,7 @@
   11.11  #ifndef SHARE_VM_GC_IMPLEMENTATION_G1_HEAPREGIONREMSET_HPP
   11.12  #define SHARE_VM_GC_IMPLEMENTATION_G1_HEAPREGIONREMSET_HPP
   11.13  
   11.14 +#include "gc_implementation/g1/g1CodeCacheRemSet.hpp"
   11.15  #include "gc_implementation/g1/sparsePRT.hpp"
   11.16  
   11.17  // Remembered set for a heap region.  Represent a set of "cards" that
   11.18 @@ -72,7 +73,7 @@
   11.19    friend class HeapRegionRemSetIterator;
   11.20  
   11.21    G1CollectedHeap* _g1h;
   11.22 -  Mutex            _m;
   11.23 +  Mutex*           _m;
   11.24    HeapRegion*      _hr;
   11.25  
   11.26    // These are protected by "_m".
   11.27 @@ -129,7 +130,7 @@
   11.28    void unlink_from_all(PerRegionTable * prt);
   11.29  
   11.30  public:
   11.31 -  OtherRegionsTable(HeapRegion* hr);
   11.32 +  OtherRegionsTable(HeapRegion* hr, Mutex* m);
   11.33  
   11.34    HeapRegion* hr() const { return _hr; }
   11.35  
   11.36 @@ -141,7 +142,6 @@
   11.37    // objects.
   11.38    void scrub(CardTableModRefBS* ctbs, BitMap* region_bm, BitMap* card_bm);
   11.39  
   11.40 -  // Not const because it takes a lock.
   11.41    size_t occupied() const;
   11.42    size_t occ_fine() const;
   11.43    size_t occ_coarse() const;
   11.44 @@ -192,9 +192,11 @@
   11.45    G1BlockOffsetSharedArray* _bosa;
   11.46    G1BlockOffsetSharedArray* bosa() const { return _bosa; }
   11.47  
   11.48 -  // A list of code blobs (nmethods) whose code contains pointers into
   11.49 +  // A set of code blobs (nmethods) whose code contains pointers into
   11.50    // the region that owns this RSet.
   11.51 -  GrowableArray<nmethod*>* _strong_code_roots_list;
   11.52 +  G1CodeRootSet _code_roots;
   11.53 +
   11.54 +  Mutex _m;
   11.55  
   11.56    OtherRegionsTable _other_regions;
   11.57  
   11.58 @@ -218,8 +220,7 @@
   11.59    static void print_event(outputStream* str, Event evnt);
   11.60  
   11.61  public:
   11.62 -  HeapRegionRemSet(G1BlockOffsetSharedArray* bosa,
   11.63 -                   HeapRegion* hr);
   11.64 +  HeapRegionRemSet(G1BlockOffsetSharedArray* bosa, HeapRegion* hr);
   11.65  
   11.66    static int num_par_rem_sets();
   11.67    static void setup_remset_size();
   11.68 @@ -228,7 +229,11 @@
   11.69      return _other_regions.hr();
   11.70    }
   11.71  
   11.72 -  size_t occupied() const {
   11.73 +  size_t occupied() {
   11.74 +    MutexLockerEx x(&_m, Mutex::_no_safepoint_check_flag);
   11.75 +    return occupied_locked();
   11.76 +  }
   11.77 +  size_t occupied_locked() {
   11.78      return _other_regions.occupied();
   11.79    }
   11.80    size_t occ_fine() const {
   11.81 @@ -260,6 +265,7 @@
   11.82    // The region is being reclaimed; clear its remset, and any mention of
   11.83    // entries for this region in other remsets.
   11.84    void clear();
   11.85 +  void clear_locked();
   11.86  
   11.87    // Attempt to claim the region.  Returns true iff this call caused an
   11.88    // atomic transition from Unclaimed to Claimed.
   11.89 @@ -289,6 +295,7 @@
   11.90    // The actual # of bytes this hr_remset takes up.
   11.91    // Note also includes the strong code root set.
   11.92    size_t mem_size() {
   11.93 +    MutexLockerEx x(&_m, Mutex::_no_safepoint_check_flag);
   11.94      return _other_regions.mem_size()
   11.95        // This correction is necessary because the above includes the second
   11.96        // part.
   11.97 @@ -299,13 +306,13 @@
   11.98    // Returns the memory occupancy of all static data structures associated
   11.99    // with remembered sets.
  11.100    static size_t static_mem_size() {
  11.101 -    return OtherRegionsTable::static_mem_size();
  11.102 +    return OtherRegionsTable::static_mem_size() + G1CodeRootSet::static_mem_size();
  11.103    }
  11.104  
  11.105    // Returns the memory occupancy of all free_list data structures associated
  11.106    // with remembered sets.
  11.107    static size_t fl_mem_size() {
  11.108 -    return OtherRegionsTable::fl_mem_size();
  11.109 +    return OtherRegionsTable::fl_mem_size() + G1CodeRootSet::fl_mem_size();
  11.110    }
  11.111  
  11.112    bool contains_reference(OopOrNarrowOopStar from) const {
  11.113 @@ -328,21 +335,21 @@
  11.114    void strong_code_roots_do(CodeBlobClosure* blk) const;
  11.115  
  11.116    // Returns the number of elements in the strong code roots list
  11.117 -  int strong_code_roots_list_length() {
  11.118 -    return _strong_code_roots_list->length();
  11.119 +  size_t strong_code_roots_list_length() {
  11.120 +    return _code_roots.length();
  11.121    }
  11.122  
  11.123    // Returns true if the strong code roots contains the given
  11.124    // nmethod.
  11.125    bool strong_code_roots_list_contains(nmethod* nm) {
  11.126 -    return _strong_code_roots_list->contains(nm);
  11.127 +    return _code_roots.contains(nm);
  11.128    }
  11.129  
  11.130    // Returns the amount of memory, in bytes, currently
  11.131    // consumed by the strong code roots.
  11.132    size_t strong_code_roots_mem_size();
  11.133  
  11.134 -  void print() const;
  11.135 +  void print() PRODUCT_RETURN;
  11.136  
  11.137    // Called during a stop-world phase to perform any deferred cleanups.
  11.138    static void cleanup();
  11.139 @@ -350,6 +357,7 @@
  11.140    // Declare the heap size (in # of regions) to the HeapRegionRemSet(s).
  11.141    // (Uses it to initialize from_card_cache).
  11.142    static void init_heap(uint max_regions) {
  11.143 +    G1CodeRootSet::initialize();
  11.144      OtherRegionsTable::init_from_card_cache((size_t) max_regions);
  11.145    }
  11.146  
  11.147 @@ -384,7 +392,7 @@
  11.148  class HeapRegionRemSetIterator : public StackObj {
  11.149  
  11.150    // The region RSet over which we're iterating.
  11.151 -  const HeapRegionRemSet* _hrrs;
  11.152 +  HeapRegionRemSet* _hrrs;
  11.153  
  11.154    // Local caching of HRRS fields.
  11.155    const BitMap*             _coarse_map;
  11.156 @@ -441,7 +449,7 @@
  11.157  public:
  11.158    // We require an iterator to be initialized before use, so the
  11.159    // constructor does little.
  11.160 -  HeapRegionRemSetIterator(const HeapRegionRemSet* hrrs);
  11.161 +  HeapRegionRemSetIterator(HeapRegionRemSet* hrrs);
  11.162  
  11.163    // If there remains one or more cards to be yielded, returns true and
  11.164    // sets "card_index" to one of those cards (which is then considered
    12.1 --- a/src/share/vm/memory/freeList.cpp	Mon Mar 17 15:18:45 2014 +0100
    12.2 +++ b/src/share/vm/memory/freeList.cpp	Mon Mar 24 15:30:14 2014 +0100
    12.3 @@ -1,5 +1,5 @@
    12.4  /*
    12.5 - * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
    12.6 + * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved.
    12.7   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    12.8   *
    12.9   * This code is free software; you can redistribute it and/or modify it
   12.10 @@ -34,6 +34,7 @@
   12.11  
   12.12  #if INCLUDE_ALL_GCS
   12.13  #include "gc_implementation/concurrentMarkSweep/freeChunk.hpp"
   12.14 +#include "gc_implementation/g1/g1CodeCacheRemSet.hpp"
   12.15  #endif // INCLUDE_ALL_GCS
   12.16  
   12.17  // Free list.  A FreeList is used to access a linked list of chunks
   12.18 @@ -332,4 +333,5 @@
   12.19  template class FreeList<Metachunk>;
   12.20  #if INCLUDE_ALL_GCS
   12.21  template class FreeList<FreeChunk>;
   12.22 +template class FreeList<G1CodeRootChunk>;
   12.23  #endif // INCLUDE_ALL_GCS
    13.1 --- a/src/share/vm/prims/jni.cpp	Mon Mar 17 15:18:45 2014 +0100
    13.2 +++ b/src/share/vm/prims/jni.cpp	Mon Mar 24 15:30:14 2014 +0100
    13.3 @@ -5083,6 +5083,7 @@
    13.4  #if INCLUDE_ALL_GCS
    13.5  void TestOldFreeSpaceCalculation_test();
    13.6  void TestG1BiasedArray_test();
    13.7 +void TestCodeCacheRemSet_test();
    13.8  #endif
    13.9  
   13.10  void execute_internal_vm_tests() {
   13.11 @@ -5108,6 +5109,7 @@
   13.12      run_unit_test(TestOldFreeSpaceCalculation_test());
   13.13      run_unit_test(TestG1BiasedArray_test());
   13.14      run_unit_test(HeapRegionRemSet::test_prt());
   13.15 +    run_unit_test(TestCodeCacheRemSet_test());
   13.16  #endif
   13.17      tty->print_cr("All internal VM tests passed");
   13.18    }
    14.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.2 +++ b/test/gc/g1/TestGCLogMessages.java	Mon Mar 24 15:30:14 2014 +0100
    14.3 @@ -0,0 +1,61 @@
    14.4 +/*
    14.5 + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
    14.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    14.7 + *
    14.8 + * This code is free software; you can redistribute it and/or modify it
    14.9 + * under the terms of the GNU General Public License version 2 only, as
   14.10 + * published by the Free Software Foundation.
   14.11 + *
   14.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
   14.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   14.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14.15 + * version 2 for more details (a copy is included in the LICENSE file that
   14.16 + * accompanied this code).
   14.17 + *
   14.18 + * You should have received a copy of the GNU General Public License version
   14.19 + * 2 along with this work; if not, write to the Free Software Foundation,
   14.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   14.21 + *
   14.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   14.23 + * or visit www.oracle.com if you need additional information or have any
   14.24 + * questions.
   14.25 + */
   14.26 +
   14.27 +/*
   14.28 + * @test TestPrintGCDetails
   14.29 + * @bug 8035406
   14.30 + * @summary Ensure that the PrintGCDetails output for a minor GC with G1
   14.31 + * includes the expected necessary messages.
   14.32 + * @key gc
   14.33 + * @library /testlibrary
   14.34 + */
   14.35 +
   14.36 +import com.oracle.java.testlibrary.ProcessTools;
   14.37 +import com.oracle.java.testlibrary.OutputAnalyzer;
   14.38 +
   14.39 +public class TestGCLogMessages {
   14.40 +  public static void main(String[] args) throws Exception {
   14.41 +
   14.42 +    ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC",
   14.43 +                                                              "-Xmx10M",
   14.44 +                                                              "-XX:+PrintGCDetails",
   14.45 +                                                              GCTest.class.getName());
   14.46 +
   14.47 +    OutputAnalyzer output = new OutputAnalyzer(pb.start());
   14.48 +
   14.49 +    output.shouldContain("[Code Root Purge");
   14.50 +    output.shouldHaveExitValue(0);
   14.51 +  }
   14.52 +
   14.53 +  static class GCTest {
   14.54 +    private static byte[] garbage;
   14.55 +    public static void main(String [] args) {
   14.56 +      System.out.println("Creating garbage");
   14.57 +      // create 128MB of garbage. This should result in at least one GC
   14.58 +      for (int i = 0; i < 1024; i++) {
   14.59 +        garbage = new byte[128 * 1024];
   14.60 +      }
   14.61 +      System.out.println("Done");
   14.62 +    }
   14.63 +  }
   14.64 +}

mercurial