Mon, 24 Mar 2014 15:30:14 +0100
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
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 +}