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 } |