hotspot/src/share/vm/gc_implementation/g1/g1CodeCacheRemSet.cpp
changeset 24099 9c132a88935d
parent 23451 ed2b8bb28fed
child 24108 dfc2242fc6b0
equal deleted inserted replaced
24098:48f07e2c74de 24099:9c132a88935d
    43     cl->do_code_blob(*cur);
    43     cl->do_code_blob(*cur);
    44     cur++;
    44     cur++;
    45   }
    45   }
    46 }
    46 }
    47 
    47 
    48 FreeList<G1CodeRootChunk> G1CodeRootSet::_free_list;
    48 G1CodeRootChunkManager::G1CodeRootChunkManager() : _free_list(), _num_chunks_handed_out(0) {
    49 size_t G1CodeRootSet::_num_chunks_handed_out = 0;
    49   _free_list.initialize();
    50 
    50   _free_list.set_size(G1CodeRootChunk::word_size());
    51 G1CodeRootChunk* G1CodeRootSet::new_chunk() {
    51 }
    52   G1CodeRootChunk* result = _free_list.get_chunk_at_head();
    52 
    53   if (result == NULL) {
    53 size_t G1CodeRootChunkManager::fl_mem_size() {
    54     result = new G1CodeRootChunk();
    54   return _free_list.count() * _free_list.size();
    55   }
    55 }
    56   G1CodeRootSet::_num_chunks_handed_out++;
    56 
    57   result->reset();
    57 void G1CodeRootChunkManager::free_all_chunks(FreeList<G1CodeRootChunk>* list) {
    58   return result;
    58   _num_chunks_handed_out -= list->count();
    59 }
    59   _free_list.prepend(list);
    60 
    60 }
    61 void G1CodeRootSet::free_chunk(G1CodeRootChunk* chunk) {
    61 
       
    62 void G1CodeRootChunkManager::free_chunk(G1CodeRootChunk* chunk) {
    62   _free_list.return_chunk_at_head(chunk);
    63   _free_list.return_chunk_at_head(chunk);
    63   G1CodeRootSet::_num_chunks_handed_out--;
    64   _num_chunks_handed_out--;
    64 }
    65 }
    65 
    66 
    66 void G1CodeRootSet::free_all_chunks(FreeList<G1CodeRootChunk>* list) {
    67 void G1CodeRootChunkManager::purge_chunks(size_t keep_ratio) {
    67   G1CodeRootSet::_num_chunks_handed_out -= list->count();
    68   size_t keep = _num_chunks_handed_out * keep_ratio / 100;
    68   _free_list.prepend(list);
       
    69 }
       
    70 
       
    71 void G1CodeRootSet::purge_chunks(size_t keep_ratio) {
       
    72   size_t keep = G1CodeRootSet::_num_chunks_handed_out * keep_ratio / 100;
       
    73 
       
    74   if (keep >= (size_t)_free_list.count()) {
    69   if (keep >= (size_t)_free_list.count()) {
    75     return;
    70     return;
    76   }
    71   }
    77 
    72 
    78   FreeList<G1CodeRootChunk> temp;
    73   FreeList<G1CodeRootChunk> temp;
    86     delete cur;
    81     delete cur;
    87     cur = temp.get_chunk_at_head();
    82     cur = temp.get_chunk_at_head();
    88   }
    83   }
    89 }
    84 }
    90 
    85 
       
    86 size_t G1CodeRootChunkManager::static_mem_size() {
       
    87   return sizeof(this);
       
    88 }
       
    89 
       
    90 
       
    91 G1CodeRootChunk* G1CodeRootChunkManager::new_chunk() {
       
    92   G1CodeRootChunk* result = _free_list.get_chunk_at_head();
       
    93   if (result == NULL) {
       
    94     result = new G1CodeRootChunk();
       
    95   }
       
    96   _num_chunks_handed_out++;
       
    97   result->reset();
       
    98   return result;
       
    99 }
       
   100 
       
   101 #ifndef PRODUCT
       
   102 
       
   103 size_t G1CodeRootChunkManager::num_chunks_handed_out() const {
       
   104   return _num_chunks_handed_out;
       
   105 }
       
   106 
       
   107 size_t G1CodeRootChunkManager::num_free_chunks() const {
       
   108   return (size_t)_free_list.count();
       
   109 }
       
   110 
       
   111 #endif
       
   112 
       
   113 G1CodeRootChunkManager G1CodeRootSet::_default_chunk_manager;
       
   114 
       
   115 void G1CodeRootSet::purge_chunks(size_t keep_ratio) {
       
   116   _default_chunk_manager.purge_chunks(keep_ratio);
       
   117 }
       
   118 
    91 size_t G1CodeRootSet::static_mem_size() {
   119 size_t G1CodeRootSet::static_mem_size() {
    92   return sizeof(_free_list) + sizeof(_num_chunks_handed_out);
   120   return _default_chunk_manager.static_mem_size();
    93 }
   121 }
    94 
   122 
    95 size_t G1CodeRootSet::fl_mem_size() {
   123 size_t G1CodeRootSet::free_chunks_mem_size() {
    96   return _free_list.count() * _free_list.size();
   124   return _default_chunk_manager.fl_mem_size();
    97 }
   125 }
    98 
   126 
    99 void G1CodeRootSet::initialize() {
   127 G1CodeRootSet::G1CodeRootSet(G1CodeRootChunkManager* manager) : _manager(manager), _list(), _length(0) {
   100   _free_list.initialize();
   128   if (_manager == NULL) {
   101   _free_list.set_size(G1CodeRootChunk::word_size());
   129     _manager = &_default_chunk_manager;
   102 }
   130   }
   103 
       
   104 G1CodeRootSet::G1CodeRootSet() : _list(), _length(0) {
       
   105   _list.initialize();
   131   _list.initialize();
   106   _list.set_size(G1CodeRootChunk::word_size());
   132   _list.set_size(G1CodeRootChunk::word_size());
   107 }
   133 }
   108 
   134 
   109 G1CodeRootSet::~G1CodeRootSet() {
   135 G1CodeRootSet::~G1CodeRootSet() {
   192 }
   218 }
   193 
   219 
   194 #ifndef PRODUCT
   220 #ifndef PRODUCT
   195 
   221 
   196 void G1CodeRootSet::test() {
   222 void G1CodeRootSet::test() {
   197   initialize();
   223   G1CodeRootChunkManager mgr;
   198 
   224 
   199   assert(_free_list.count() == 0, "Free List must be empty");
   225   assert(mgr.num_chunks_handed_out() == 0, "Must not have handed out chunks yet");
   200   assert(_num_chunks_handed_out == 0, "No elements must have been handed out yet");
       
   201 
   226 
   202   // The number of chunks that we allocate for purge testing.
   227   // The number of chunks that we allocate for purge testing.
   203   size_t const num_chunks = 10;
   228   size_t const num_chunks = 10;
       
   229 
   204   {
   230   {
   205     G1CodeRootSet set1;
   231     G1CodeRootSet set1(&mgr);
   206     assert(set1.is_empty(), "Code root set must be initially empty but is not.");
   232     assert(set1.is_empty(), "Code root set must be initially empty but is not.");
   207 
   233 
   208     set1.add((nmethod*)1);
   234     set1.add((nmethod*)1);
   209     assert(_num_chunks_handed_out == 1,
   235     assert(mgr.num_chunks_handed_out() == 1,
   210            err_msg("Must have allocated and handed out one chunk, but handed out "
   236            err_msg("Must have allocated and handed out one chunk, but handed out "
   211                    SIZE_FORMAT" chunks", _num_chunks_handed_out));
   237                    SIZE_FORMAT" chunks", mgr.num_chunks_handed_out()));
   212     assert(set1.length() == 1, err_msg("Added exactly one element, but set contains "
   238     assert(set1.length() == 1, err_msg("Added exactly one element, but set contains "
   213                                        SIZE_FORMAT" elements", set1.length()));
   239                                        SIZE_FORMAT" elements", set1.length()));
   214 
   240 
   215     // G1CodeRootChunk::word_size() is larger than G1CodeRootChunk::num_entries which
   241     // G1CodeRootChunk::word_size() is larger than G1CodeRootChunk::num_entries which
   216     // we cannot access.
   242     // we cannot access.
   217     for (uint i = 0; i < G1CodeRootChunk::word_size() + 1; i++) {
   243     for (uint i = 0; i < G1CodeRootChunk::word_size() + 1; i++) {
   218       set1.add((nmethod*)1);
   244       set1.add((nmethod*)1);
   219     }
   245     }
   220     assert(_num_chunks_handed_out == 1,
   246     assert(mgr.num_chunks_handed_out() == 1,
   221            err_msg("Duplicate detection must have prevented allocation of further "
   247            err_msg("Duplicate detection must have prevented allocation of further "
   222                    "chunks but contains "SIZE_FORMAT, _num_chunks_handed_out));
   248                    "chunks but allocated "SIZE_FORMAT, mgr.num_chunks_handed_out()));
   223     assert(set1.length() == 1,
   249     assert(set1.length() == 1,
   224            err_msg("Duplicate detection should not have increased the set size but "
   250            err_msg("Duplicate detection should not have increased the set size but "
   225                    "is "SIZE_FORMAT, set1.length()));
   251                    "is "SIZE_FORMAT, set1.length()));
   226 
   252 
   227     size_t num_total_after_add = G1CodeRootChunk::word_size() + 1;
   253     size_t num_total_after_add = G1CodeRootChunk::word_size() + 1;
   228     for (size_t i = 0; i < num_total_after_add - 1; i++) {
   254     for (size_t i = 0; i < num_total_after_add - 1; i++) {
   229       set1.add((nmethod*)(2 + i));
   255       set1.add((nmethod*)(uintptr_t)(2 + i));
   230     }
   256     }
   231     assert(_num_chunks_handed_out > 1,
   257     assert(mgr.num_chunks_handed_out() > 1,
   232            "After adding more code roots, more than one chunks should have been handed out");
   258            "After adding more code roots, more than one additional chunk should have been handed out");
   233     assert(set1.length() == num_total_after_add,
   259     assert(set1.length() == num_total_after_add,
   234            err_msg("After adding in total "SIZE_FORMAT" distinct code roots, they "
   260            err_msg("After adding in total "SIZE_FORMAT" distinct code roots, they "
   235                    "need to be in the set, but there are only "SIZE_FORMAT,
   261                    "need to be in the set, but there are only "SIZE_FORMAT,
   236                    num_total_after_add, set1.length()));
   262                    num_total_after_add, set1.length()));
   237 
   263 
   240       num_popped++;
   266       num_popped++;
   241     }
   267     }
   242     assert(num_popped == num_total_after_add,
   268     assert(num_popped == num_total_after_add,
   243            err_msg("Managed to pop "SIZE_FORMAT" code roots, but only "SIZE_FORMAT" "
   269            err_msg("Managed to pop "SIZE_FORMAT" code roots, but only "SIZE_FORMAT" "
   244                    "were added", num_popped, num_total_after_add));
   270                    "were added", num_popped, num_total_after_add));
   245     assert(_num_chunks_handed_out == 0,
   271     assert(mgr.num_chunks_handed_out() == 0,
   246            err_msg("After popping all elements, all chunks must have been returned "
   272            err_msg("After popping all elements, all chunks must have been returned "
   247                    "but are still "SIZE_FORMAT, _num_chunks_handed_out));
   273                    "but there are still "SIZE_FORMAT" additional", mgr.num_chunks_handed_out()));
   248 
   274 
   249     purge_chunks(0);
   275     mgr.purge_chunks(0);
   250     assert(_free_list.count() == 0,
   276     assert(mgr.num_free_chunks() == 0,
   251            err_msg("After purging everything, the free list must be empty but still "
   277            err_msg("After purging everything, the free list must be empty but still "
   252                    "contains "SIZE_FORMAT" chunks", _free_list.count()));
   278                    "contains "SIZE_FORMAT" chunks", mgr.num_free_chunks()));
   253 
   279 
   254     // Add some more handed out chunks.
   280     // Add some more handed out chunks.
   255     size_t i = 0;
   281     size_t i = 0;
   256     while (_num_chunks_handed_out < num_chunks) {
   282     while (mgr.num_chunks_handed_out() < num_chunks) {
   257       set1.add((nmethod*)i);
   283       set1.add((nmethod*)i);
   258       i++;
   284       i++;
   259     }
   285     }
   260 
   286 
   261     {
   287     {
   262       // Generate chunks on the free list.
   288       // Generate chunks on the free list.
   263       G1CodeRootSet set2;
   289       G1CodeRootSet set2(&mgr);
   264       size_t i = 0;
   290       size_t i = 0;
   265       while (_num_chunks_handed_out < num_chunks * 2) {
   291       while (mgr.num_chunks_handed_out() < (num_chunks * 2)) {
   266         set2.add((nmethod*)i);
   292         set2.add((nmethod*)i);
   267         i++;
   293         i++;
   268       }
   294       }
   269       // Exit of the scope of the set2 object will call the destructor that generates
   295       // Exit of the scope of the set2 object will call the destructor that generates
   270       // num_chunks elements on the free list.
   296       // num_chunks elements on the free list.
   271     }
   297     }
   272 
   298 
   273     assert(_num_chunks_handed_out == num_chunks,
   299     assert(mgr.num_chunks_handed_out() == num_chunks,
   274            err_msg("Deletion of the second set must have resulted in giving back "
   300            err_msg("Deletion of the second set must have resulted in giving back "
   275                    "those, but there is still "SIZE_FORMAT" handed out, expecting "
   301                    "those, but there are still "SIZE_FORMAT" additional handed out, expecting "
   276                    SIZE_FORMAT, _num_chunks_handed_out, num_chunks));
   302                    SIZE_FORMAT, mgr.num_chunks_handed_out(), num_chunks));
   277     assert((size_t)_free_list.count() == num_chunks,
   303     assert(mgr.num_free_chunks() == num_chunks,
   278            err_msg("After freeing "SIZE_FORMAT" chunks, they must be on the free list "
   304            err_msg("After freeing "SIZE_FORMAT" chunks, they must be on the free list "
   279                    "but there are only "SIZE_FORMAT, num_chunks, _free_list.count()));
   305                    "but there are only "SIZE_FORMAT, num_chunks, mgr.num_free_chunks()));
   280 
   306 
   281     size_t const test_percentage = 50;
   307     size_t const test_percentage = 50;
   282     purge_chunks(test_percentage);
   308     mgr.purge_chunks(test_percentage);
   283     assert(_num_chunks_handed_out == num_chunks,
   309     assert(mgr.num_chunks_handed_out() == num_chunks,
   284            err_msg("Purging must not hand out chunks but there are "SIZE_FORMAT,
   310            err_msg("Purging must not hand out chunks but there are "SIZE_FORMAT,
   285                    _num_chunks_handed_out));
   311                    mgr.num_chunks_handed_out()));
   286     assert((size_t)_free_list.count() == (ssize_t)(num_chunks * test_percentage / 100),
   312     assert(mgr.num_free_chunks() == (size_t)(mgr.num_chunks_handed_out() * test_percentage / 100),
   287            err_msg("Must have purged "SIZE_FORMAT" percent of "SIZE_FORMAT" chunks"
   313            err_msg("Must have purged "SIZE_FORMAT" percent of "SIZE_FORMAT" chunks"
   288                    "but there are "SSIZE_FORMAT, test_percentage, num_chunks,
   314                    "but there are "SIZE_FORMAT, test_percentage, num_chunks,
   289                    _free_list.count()));
   315                    mgr.num_free_chunks()));
   290     // Purge the remainder of the chunks on the free list.
   316     // Purge the remainder of the chunks on the free list.
   291     purge_chunks(0);
   317     mgr.purge_chunks(0);
   292     assert(_free_list.count() == 0, "Free List must be empty");
   318     assert(mgr.num_free_chunks() == 0, "Free List must be empty");
   293     assert(_num_chunks_handed_out == num_chunks,
   319     assert(mgr.num_chunks_handed_out() == num_chunks,
   294            err_msg("Expected to be "SIZE_FORMAT" chunks handed out from the first set "
   320            err_msg("Expected to be "SIZE_FORMAT" chunks handed out from the first set "
   295                    "but there are "SIZE_FORMAT, num_chunks, _num_chunks_handed_out));
   321                    "but there are "SIZE_FORMAT, num_chunks, mgr.num_chunks_handed_out()));
   296 
   322 
   297     // Exit of the scope of the set1 object will call the destructor that generates
   323     // Exit of the scope of the set1 object will call the destructor that generates
   298     // num_chunks additional elements on the free list.
   324     // num_chunks additional elements on the free list.
   299   }
   325    }
   300 
   326 
   301   assert(_num_chunks_handed_out == 0,
   327   assert(mgr.num_chunks_handed_out() == 0,
   302          err_msg("Deletion of the only set must have resulted in no chunks handed "
   328          err_msg("Deletion of the only set must have resulted in no chunks handed "
   303                  "out, but there is still "SIZE_FORMAT" handed out", _num_chunks_handed_out));
   329                  "out, but there is still "SIZE_FORMAT" handed out", mgr.num_chunks_handed_out()));
   304   assert((size_t)_free_list.count() == num_chunks,
   330   assert(mgr.num_free_chunks() == num_chunks,
   305          err_msg("After freeing "SIZE_FORMAT" chunks, they must be on the free list "
   331          err_msg("After freeing "SIZE_FORMAT" chunks, they must be on the free list "
   306                  "but there are only "SSIZE_FORMAT, num_chunks, _free_list.count()));
   332                  "but there are only "SIZE_FORMAT, num_chunks, mgr.num_free_chunks()));
   307 
   333 
   308   // Restore initial state.
   334   // Restore initial state.
   309   purge_chunks(0);
   335   mgr.purge_chunks(0);
   310   assert(_free_list.count() == 0, "Free List must be empty");
   336   assert(mgr.num_free_chunks() == 0, "Free List must be empty");
   311   assert(_num_chunks_handed_out == 0, "No elements must have been handed out yet");
   337   assert(mgr.num_chunks_handed_out() == 0, "No additional elements must have been handed out yet");
   312 }
   338 }
   313 
   339 
   314 void TestCodeCacheRemSet_test() {
   340 void TestCodeCacheRemSet_test() {
   315   G1CodeRootSet::test();
   341   G1CodeRootSet::test();
   316 }
   342 }