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

Wed, 27 Apr 2016 01:25:04 +0800

author
aoqi
date
Wed, 27 Apr 2016 01:25:04 +0800
changeset 0
f90c822e73f8
child 6876
710a3c8b516e
permissions
-rw-r--r--

Initial load
http://hg.openjdk.java.net/jdk8u/jdk8u/hotspot/
changeset: 6782:28b50d07f6f8
tag: jdk8u25-b17

aoqi@0 1 /*
aoqi@0 2 * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
aoqi@0 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
aoqi@0 4 *
aoqi@0 5 * This code is free software; you can redistribute it and/or modify it
aoqi@0 6 * under the terms of the GNU General Public License version 2 only, as
aoqi@0 7 * published by the Free Software Foundation.
aoqi@0 8 *
aoqi@0 9 * This code is distributed in the hope that it will be useful, but WITHOUT
aoqi@0 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
aoqi@0 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
aoqi@0 12 * version 2 for more details (a copy is included in the LICENSE file that
aoqi@0 13 * accompanied this code).
aoqi@0 14 *
aoqi@0 15 * You should have received a copy of the GNU General Public License version
aoqi@0 16 * 2 along with this work; if not, write to the Free Software Foundation,
aoqi@0 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
aoqi@0 18 *
aoqi@0 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
aoqi@0 20 * or visit www.oracle.com if you need additional information or have any
aoqi@0 21 * questions.
aoqi@0 22 *
aoqi@0 23 */
aoqi@0 24
aoqi@0 25
aoqi@0 26 #include "precompiled.hpp"
aoqi@0 27 #include "code/nmethod.hpp"
aoqi@0 28 #include "gc_implementation/g1/g1CodeCacheRemSet.hpp"
aoqi@0 29 #include "memory/iterator.hpp"
aoqi@0 30
aoqi@0 31 PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC
aoqi@0 32
aoqi@0 33 G1CodeRootChunk::G1CodeRootChunk() : _top(NULL), _next(NULL), _prev(NULL) {
aoqi@0 34 _top = bottom();
aoqi@0 35 }
aoqi@0 36
aoqi@0 37 void G1CodeRootChunk::reset() {
aoqi@0 38 _next = _prev = NULL;
aoqi@0 39 _top = bottom();
aoqi@0 40 }
aoqi@0 41
aoqi@0 42 void G1CodeRootChunk::nmethods_do(CodeBlobClosure* cl) {
aoqi@0 43 nmethod** cur = bottom();
aoqi@0 44 while (cur != _top) {
aoqi@0 45 cl->do_code_blob(*cur);
aoqi@0 46 cur++;
aoqi@0 47 }
aoqi@0 48 }
aoqi@0 49
aoqi@0 50 FreeList<G1CodeRootChunk> G1CodeRootSet::_free_list;
aoqi@0 51 size_t G1CodeRootSet::_num_chunks_handed_out = 0;
aoqi@0 52
aoqi@0 53 G1CodeRootChunk* G1CodeRootSet::new_chunk() {
aoqi@0 54 G1CodeRootChunk* result = _free_list.get_chunk_at_head();
aoqi@0 55 if (result == NULL) {
aoqi@0 56 result = new G1CodeRootChunk();
aoqi@0 57 }
aoqi@0 58 G1CodeRootSet::_num_chunks_handed_out++;
aoqi@0 59 result->reset();
aoqi@0 60 return result;
aoqi@0 61 }
aoqi@0 62
aoqi@0 63 void G1CodeRootSet::free_chunk(G1CodeRootChunk* chunk) {
aoqi@0 64 _free_list.return_chunk_at_head(chunk);
aoqi@0 65 G1CodeRootSet::_num_chunks_handed_out--;
aoqi@0 66 }
aoqi@0 67
aoqi@0 68 void G1CodeRootSet::free_all_chunks(FreeList<G1CodeRootChunk>* list) {
aoqi@0 69 G1CodeRootSet::_num_chunks_handed_out -= list->count();
aoqi@0 70 _free_list.prepend(list);
aoqi@0 71 }
aoqi@0 72
aoqi@0 73 void G1CodeRootSet::purge_chunks(size_t keep_ratio) {
aoqi@0 74 size_t keep = G1CodeRootSet::_num_chunks_handed_out * keep_ratio / 100;
aoqi@0 75
aoqi@0 76 if (keep >= (size_t)_free_list.count()) {
aoqi@0 77 return;
aoqi@0 78 }
aoqi@0 79
aoqi@0 80 FreeList<G1CodeRootChunk> temp;
aoqi@0 81 temp.initialize();
aoqi@0 82 temp.set_size(G1CodeRootChunk::word_size());
aoqi@0 83
aoqi@0 84 _free_list.getFirstNChunksFromList((size_t)_free_list.count() - keep, &temp);
aoqi@0 85
aoqi@0 86 G1CodeRootChunk* cur = temp.get_chunk_at_head();
aoqi@0 87 while (cur != NULL) {
aoqi@0 88 delete cur;
aoqi@0 89 cur = temp.get_chunk_at_head();
aoqi@0 90 }
aoqi@0 91 }
aoqi@0 92
aoqi@0 93 size_t G1CodeRootSet::static_mem_size() {
aoqi@0 94 return sizeof(_free_list) + sizeof(_num_chunks_handed_out);
aoqi@0 95 }
aoqi@0 96
aoqi@0 97 size_t G1CodeRootSet::fl_mem_size() {
aoqi@0 98 return _free_list.count() * _free_list.size();
aoqi@0 99 }
aoqi@0 100
aoqi@0 101 void G1CodeRootSet::initialize() {
aoqi@0 102 _free_list.initialize();
aoqi@0 103 _free_list.set_size(G1CodeRootChunk::word_size());
aoqi@0 104 }
aoqi@0 105
aoqi@0 106 G1CodeRootSet::G1CodeRootSet() : _list(), _length(0) {
aoqi@0 107 _list.initialize();
aoqi@0 108 _list.set_size(G1CodeRootChunk::word_size());
aoqi@0 109 }
aoqi@0 110
aoqi@0 111 G1CodeRootSet::~G1CodeRootSet() {
aoqi@0 112 clear();
aoqi@0 113 }
aoqi@0 114
aoqi@0 115 void G1CodeRootSet::add(nmethod* method) {
aoqi@0 116 if (!contains(method)) {
aoqi@0 117 // Try to add the nmethod. If there is not enough space, get a new chunk.
aoqi@0 118 if (_list.head() == NULL || _list.head()->is_full()) {
aoqi@0 119 G1CodeRootChunk* cur = new_chunk();
aoqi@0 120 _list.return_chunk_at_head(cur);
aoqi@0 121 }
aoqi@0 122 bool result = _list.head()->add(method);
aoqi@0 123 guarantee(result, err_msg("Not able to add nmethod "PTR_FORMAT" to newly allocated chunk.", method));
aoqi@0 124 _length++;
aoqi@0 125 }
aoqi@0 126 }
aoqi@0 127
aoqi@0 128 void G1CodeRootSet::remove(nmethod* method) {
aoqi@0 129 G1CodeRootChunk* found = find(method);
aoqi@0 130 if (found != NULL) {
aoqi@0 131 bool result = found->remove(method);
aoqi@0 132 guarantee(result, err_msg("could not find nmethod "PTR_FORMAT" during removal although we previously found it", method));
aoqi@0 133 // eventually free completely emptied chunk
aoqi@0 134 if (found->is_empty()) {
aoqi@0 135 _list.remove_chunk(found);
aoqi@0 136 free(found);
aoqi@0 137 }
aoqi@0 138 _length--;
aoqi@0 139 }
aoqi@0 140 assert(!contains(method), err_msg(PTR_FORMAT" still contains nmethod "PTR_FORMAT, this, method));
aoqi@0 141 }
aoqi@0 142
aoqi@0 143 nmethod* G1CodeRootSet::pop() {
aoqi@0 144 do {
aoqi@0 145 G1CodeRootChunk* cur = _list.head();
aoqi@0 146 if (cur == NULL) {
aoqi@0 147 assert(_length == 0, "when there are no chunks, there should be no elements");
aoqi@0 148 return NULL;
aoqi@0 149 }
aoqi@0 150 nmethod* result = cur->pop();
aoqi@0 151 if (result != NULL) {
aoqi@0 152 _length--;
aoqi@0 153 return result;
aoqi@0 154 } else {
aoqi@0 155 free(_list.get_chunk_at_head());
aoqi@0 156 }
aoqi@0 157 } while (true);
aoqi@0 158 }
aoqi@0 159
aoqi@0 160 G1CodeRootChunk* G1CodeRootSet::find(nmethod* method) {
aoqi@0 161 G1CodeRootChunk* cur = _list.head();
aoqi@0 162 while (cur != NULL) {
aoqi@0 163 if (cur->contains(method)) {
aoqi@0 164 return cur;
aoqi@0 165 }
aoqi@0 166 cur = (G1CodeRootChunk*)cur->next();
aoqi@0 167 }
aoqi@0 168 return NULL;
aoqi@0 169 }
aoqi@0 170
aoqi@0 171 void G1CodeRootSet::free(G1CodeRootChunk* chunk) {
aoqi@0 172 free_chunk(chunk);
aoqi@0 173 }
aoqi@0 174
aoqi@0 175 bool G1CodeRootSet::contains(nmethod* method) {
aoqi@0 176 return find(method) != NULL;
aoqi@0 177 }
aoqi@0 178
aoqi@0 179 void G1CodeRootSet::clear() {
aoqi@0 180 free_all_chunks(&_list);
aoqi@0 181 _length = 0;
aoqi@0 182 }
aoqi@0 183
aoqi@0 184 void G1CodeRootSet::nmethods_do(CodeBlobClosure* blk) const {
aoqi@0 185 G1CodeRootChunk* cur = _list.head();
aoqi@0 186 while (cur != NULL) {
aoqi@0 187 cur->nmethods_do(blk);
aoqi@0 188 cur = (G1CodeRootChunk*)cur->next();
aoqi@0 189 }
aoqi@0 190 }
aoqi@0 191
aoqi@0 192 size_t G1CodeRootSet::mem_size() {
aoqi@0 193 return sizeof(this) + _list.count() * _list.size();
aoqi@0 194 }
aoqi@0 195
aoqi@0 196 #ifndef PRODUCT
aoqi@0 197
aoqi@0 198 void G1CodeRootSet::test() {
aoqi@0 199 initialize();
aoqi@0 200
aoqi@0 201 assert(_free_list.count() == 0, "Free List must be empty");
aoqi@0 202 assert(_num_chunks_handed_out == 0, "No elements must have been handed out yet");
aoqi@0 203
aoqi@0 204 // The number of chunks that we allocate for purge testing.
aoqi@0 205 size_t const num_chunks = 10;
aoqi@0 206 {
aoqi@0 207 G1CodeRootSet set1;
aoqi@0 208 assert(set1.is_empty(), "Code root set must be initially empty but is not.");
aoqi@0 209
aoqi@0 210 set1.add((nmethod*)1);
aoqi@0 211 assert(_num_chunks_handed_out == 1,
aoqi@0 212 err_msg("Must have allocated and handed out one chunk, but handed out "
aoqi@0 213 SIZE_FORMAT" chunks", _num_chunks_handed_out));
aoqi@0 214 assert(set1.length() == 1, err_msg("Added exactly one element, but set contains "
aoqi@0 215 SIZE_FORMAT" elements", set1.length()));
aoqi@0 216
aoqi@0 217 // G1CodeRootChunk::word_size() is larger than G1CodeRootChunk::num_entries which
aoqi@0 218 // we cannot access.
aoqi@0 219 for (uint i = 0; i < G1CodeRootChunk::word_size() + 1; i++) {
aoqi@0 220 set1.add((nmethod*)1);
aoqi@0 221 }
aoqi@0 222 assert(_num_chunks_handed_out == 1,
aoqi@0 223 err_msg("Duplicate detection must have prevented allocation of further "
aoqi@0 224 "chunks but contains "SIZE_FORMAT, _num_chunks_handed_out));
aoqi@0 225 assert(set1.length() == 1,
aoqi@0 226 err_msg("Duplicate detection should not have increased the set size but "
aoqi@0 227 "is "SIZE_FORMAT, set1.length()));
aoqi@0 228
aoqi@0 229 size_t num_total_after_add = G1CodeRootChunk::word_size() + 1;
aoqi@0 230 for (size_t i = 0; i < num_total_after_add - 1; i++) {
aoqi@0 231 set1.add((nmethod*)(2 + i));
aoqi@0 232 }
aoqi@0 233 assert(_num_chunks_handed_out > 1,
aoqi@0 234 "After adding more code roots, more than one chunks should have been handed out");
aoqi@0 235 assert(set1.length() == num_total_after_add,
aoqi@0 236 err_msg("After adding in total "SIZE_FORMAT" distinct code roots, they "
aoqi@0 237 "need to be in the set, but there are only "SIZE_FORMAT,
aoqi@0 238 num_total_after_add, set1.length()));
aoqi@0 239
aoqi@0 240 size_t num_popped = 0;
aoqi@0 241 while (set1.pop() != NULL) {
aoqi@0 242 num_popped++;
aoqi@0 243 }
aoqi@0 244 assert(num_popped == num_total_after_add,
aoqi@0 245 err_msg("Managed to pop "SIZE_FORMAT" code roots, but only "SIZE_FORMAT" "
aoqi@0 246 "were added", num_popped, num_total_after_add));
aoqi@0 247 assert(_num_chunks_handed_out == 0,
aoqi@0 248 err_msg("After popping all elements, all chunks must have been returned "
aoqi@0 249 "but are still "SIZE_FORMAT, _num_chunks_handed_out));
aoqi@0 250
aoqi@0 251 purge_chunks(0);
aoqi@0 252 assert(_free_list.count() == 0,
aoqi@0 253 err_msg("After purging everything, the free list must be empty but still "
aoqi@0 254 "contains "SIZE_FORMAT" chunks", _free_list.count()));
aoqi@0 255
aoqi@0 256 // Add some more handed out chunks.
aoqi@0 257 size_t i = 0;
aoqi@0 258 while (_num_chunks_handed_out < num_chunks) {
aoqi@0 259 set1.add((nmethod*)i);
aoqi@0 260 i++;
aoqi@0 261 }
aoqi@0 262
aoqi@0 263 {
aoqi@0 264 // Generate chunks on the free list.
aoqi@0 265 G1CodeRootSet set2;
aoqi@0 266 size_t i = 0;
aoqi@0 267 while (_num_chunks_handed_out < num_chunks * 2) {
aoqi@0 268 set2.add((nmethod*)i);
aoqi@0 269 i++;
aoqi@0 270 }
aoqi@0 271 // Exit of the scope of the set2 object will call the destructor that generates
aoqi@0 272 // num_chunks elements on the free list.
aoqi@0 273 }
aoqi@0 274
aoqi@0 275 assert(_num_chunks_handed_out == num_chunks,
aoqi@0 276 err_msg("Deletion of the second set must have resulted in giving back "
aoqi@0 277 "those, but there is still "SIZE_FORMAT" handed out, expecting "
aoqi@0 278 SIZE_FORMAT, _num_chunks_handed_out, num_chunks));
aoqi@0 279 assert((size_t)_free_list.count() == num_chunks,
aoqi@0 280 err_msg("After freeing "SIZE_FORMAT" chunks, they must be on the free list "
aoqi@0 281 "but there are only "SIZE_FORMAT, num_chunks, _free_list.count()));
aoqi@0 282
aoqi@0 283 size_t const test_percentage = 50;
aoqi@0 284 purge_chunks(test_percentage);
aoqi@0 285 assert(_num_chunks_handed_out == num_chunks,
aoqi@0 286 err_msg("Purging must not hand out chunks but there are "SIZE_FORMAT,
aoqi@0 287 _num_chunks_handed_out));
aoqi@0 288 assert((size_t)_free_list.count() == (ssize_t)(num_chunks * test_percentage / 100),
aoqi@0 289 err_msg("Must have purged "SIZE_FORMAT" percent of "SIZE_FORMAT" chunks"
aoqi@0 290 "but there are "SSIZE_FORMAT, test_percentage, num_chunks,
aoqi@0 291 _free_list.count()));
aoqi@0 292 // Purge the remainder of the chunks on the free list.
aoqi@0 293 purge_chunks(0);
aoqi@0 294 assert(_free_list.count() == 0, "Free List must be empty");
aoqi@0 295 assert(_num_chunks_handed_out == num_chunks,
aoqi@0 296 err_msg("Expected to be "SIZE_FORMAT" chunks handed out from the first set "
aoqi@0 297 "but there are "SIZE_FORMAT, num_chunks, _num_chunks_handed_out));
aoqi@0 298
aoqi@0 299 // Exit of the scope of the set1 object will call the destructor that generates
aoqi@0 300 // num_chunks additional elements on the free list.
aoqi@0 301 }
aoqi@0 302
aoqi@0 303 assert(_num_chunks_handed_out == 0,
aoqi@0 304 err_msg("Deletion of the only set must have resulted in no chunks handed "
aoqi@0 305 "out, but there is still "SIZE_FORMAT" handed out", _num_chunks_handed_out));
aoqi@0 306 assert((size_t)_free_list.count() == num_chunks,
aoqi@0 307 err_msg("After freeing "SIZE_FORMAT" chunks, they must be on the free list "
aoqi@0 308 "but there are only "SSIZE_FORMAT, num_chunks, _free_list.count()));
aoqi@0 309
aoqi@0 310 // Restore initial state.
aoqi@0 311 purge_chunks(0);
aoqi@0 312 assert(_free_list.count() == 0, "Free List must be empty");
aoqi@0 313 assert(_num_chunks_handed_out == 0, "No elements must have been handed out yet");
aoqi@0 314 }
aoqi@0 315
aoqi@0 316 void TestCodeCacheRemSet_test() {
aoqi@0 317 G1CodeRootSet::test();
aoqi@0 318 }
aoqi@0 319 #endif

mercurial