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