23 */ |
23 */ |
24 |
24 |
25 #include "precompiled.hpp" |
25 #include "precompiled.hpp" |
26 #include "memory/freeBlockDictionary.hpp" |
26 #include "memory/freeBlockDictionary.hpp" |
27 #include "memory/freeList.hpp" |
27 #include "memory/freeList.hpp" |
|
28 #include "memory/metablock.hpp" |
|
29 #include "memory/metachunk.hpp" |
28 #include "memory/sharedHeap.hpp" |
30 #include "memory/sharedHeap.hpp" |
29 #include "runtime/globals.hpp" |
31 #include "runtime/globals.hpp" |
30 #include "runtime/mutex.hpp" |
32 #include "runtime/mutex.hpp" |
31 #include "runtime/vmThread.hpp" |
33 #include "runtime/vmThread.hpp" |
32 |
34 |
60 , _protecting_lock(NULL) |
60 , _protecting_lock(NULL) |
61 #endif |
61 #endif |
62 { |
62 { |
63 _size = fc->size(); |
63 _size = fc->size(); |
64 _count = 1; |
64 _count = 1; |
65 _hint = 0; |
65 } |
66 init_statistics(); |
66 |
67 #ifndef PRODUCT |
67 template <class Chunk> |
68 _allocation_stats.set_returned_bytes(size() * HeapWordSize); |
68 void FreeList<Chunk>::link_head(Chunk* v) { |
69 #endif |
69 assert_proper_lock_protection(); |
70 } |
70 set_head(v); |
71 |
71 // If this method is not used (just set the head instead), |
72 template <class Chunk> |
72 // this check can be avoided. |
73 void FreeList<Chunk>::reset(size_t hint) { |
73 if (v != NULL) { |
|
74 v->link_prev(NULL); |
|
75 } |
|
76 } |
|
77 |
|
78 |
|
79 |
|
80 template <class Chunk> |
|
81 void FreeList<Chunk>::reset() { |
|
82 // Don't set the _size to 0 because this method is |
|
83 // used with a existing list that has a size but which has |
|
84 // been emptied. |
|
85 // Don't clear the _protecting_lock of an existing list. |
74 set_count(0); |
86 set_count(0); |
75 set_head(NULL); |
87 set_head(NULL); |
76 set_tail(NULL); |
88 set_tail(NULL); |
77 set_hint(hint); |
89 } |
78 } |
90 |
79 |
91 template <class Chunk> |
80 template <class Chunk> |
92 void FreeList<Chunk>::initialize() { |
81 void FreeList<Chunk>::init_statistics(bool split_birth) { |
93 #ifdef ASSERT |
82 _allocation_stats.initialize(split_birth); |
94 // Needed early because it might be checked in other initializing code. |
83 } |
95 set_protecting_lock(NULL); |
84 |
96 #endif |
85 template <class Chunk> |
97 reset(); |
86 Chunk* FreeList<Chunk>::get_chunk_at_head() { |
98 set_size(0); |
87 assert_proper_lock_protection(); |
99 } |
88 assert(head() == NULL || head()->prev() == NULL, "list invariant"); |
100 |
89 assert(tail() == NULL || tail()->next() == NULL, "list invariant"); |
101 template <class Chunk_t> |
90 Chunk* fc = head(); |
102 Chunk_t* FreeList<Chunk_t>::get_chunk_at_head() { |
|
103 assert_proper_lock_protection(); |
|
104 assert(head() == NULL || head()->prev() == NULL, "list invariant"); |
|
105 assert(tail() == NULL || tail()->next() == NULL, "list invariant"); |
|
106 Chunk_t* fc = head(); |
91 if (fc != NULL) { |
107 if (fc != NULL) { |
92 Chunk* nextFC = fc->next(); |
108 Chunk_t* nextFC = fc->next(); |
93 if (nextFC != NULL) { |
109 if (nextFC != NULL) { |
94 // The chunk fc being removed has a "next". Set the "next" to the |
110 // The chunk fc being removed has a "next". Set the "next" to the |
95 // "prev" of fc. |
111 // "prev" of fc. |
96 nextFC->link_prev(NULL); |
112 nextFC->link_prev(NULL); |
97 } else { // removed tail of list |
113 } else { // removed tail of list |
195 if (oldHead == NULL) { // only chunk in list |
211 if (oldHead == NULL) { // only chunk in list |
196 assert(tail() == NULL, "inconsistent FreeList"); |
212 assert(tail() == NULL, "inconsistent FreeList"); |
197 link_tail(chunk); |
213 link_tail(chunk); |
198 } |
214 } |
199 increment_count(); // of # of chunks in list |
215 increment_count(); // of # of chunks in list |
200 DEBUG_ONLY( |
|
201 if (record_return) { |
|
202 increment_returned_bytes_by(size()*HeapWordSize); |
|
203 } |
|
204 ) |
|
205 assert(head() == NULL || head()->prev() == NULL, "list invariant"); |
216 assert(head() == NULL || head()->prev() == NULL, "list invariant"); |
206 assert(tail() == NULL || tail()->next() == NULL, "list invariant"); |
217 assert(tail() == NULL || tail()->next() == NULL, "list invariant"); |
207 assert(head() == NULL || head()->size() == size(), "wrong item on list"); |
218 assert(head() == NULL || head()->size() == size(), "wrong item on list"); |
208 assert(tail() == NULL || tail()->size() == size(), "wrong item on list"); |
219 assert(tail() == NULL || tail()->size() == size(), "wrong item on list"); |
209 } |
220 } |
231 assert(head() == NULL, "inconsistent FreeList"); |
242 assert(head() == NULL, "inconsistent FreeList"); |
232 link_head(chunk); |
243 link_head(chunk); |
233 } |
244 } |
234 link_tail(chunk); |
245 link_tail(chunk); |
235 increment_count(); // of # of chunks in list |
246 increment_count(); // of # of chunks in list |
236 DEBUG_ONLY( |
|
237 if (record_return) { |
|
238 increment_returned_bytes_by(size()*HeapWordSize); |
|
239 } |
|
240 ) |
|
241 assert(head() == NULL || head()->prev() == NULL, "list invariant"); |
247 assert(head() == NULL || head()->prev() == NULL, "list invariant"); |
242 assert(tail() == NULL || tail()->next() == NULL, "list invariant"); |
248 assert(tail() == NULL || tail()->next() == NULL, "list invariant"); |
243 assert(head() == NULL || head()->size() == size(), "wrong item on list"); |
249 assert(head() == NULL || head()->size() == size(), "wrong item on list"); |
244 assert(tail() == NULL || tail()->size() == size(), "wrong item on list"); |
250 assert(tail() == NULL || tail()->size() == size(), "wrong item on list"); |
245 } |
251 } |
271 fl->set_tail(NULL); |
277 fl->set_tail(NULL); |
272 fl->set_count(0); |
278 fl->set_count(0); |
273 } |
279 } |
274 } |
280 } |
275 |
281 |
276 // verify_chunk_in_free_list() is used to verify that an item is in this free list. |
282 // verify_chunk_in_free_lists() is used to verify that an item is in this free list. |
277 // It is used as a debugging aid. |
283 // It is used as a debugging aid. |
278 template <class Chunk> |
284 template <class Chunk> |
279 bool FreeList<Chunk>::verify_chunk_in_free_list(Chunk* fc) const { |
285 bool FreeList<Chunk>::verify_chunk_in_free_list(Chunk* fc) const { |
280 // This is an internal consistency check, not part of the check that the |
286 // This is an internal consistency check, not part of the check that the |
281 // chunk is in the free lists. |
287 // chunk is in the free lists. |
292 return false; |
298 return false; |
293 } |
299 } |
294 |
300 |
295 #ifndef PRODUCT |
301 #ifndef PRODUCT |
296 template <class Chunk> |
302 template <class Chunk> |
297 void FreeList<Chunk>::verify_stats() const { |
|
298 // The +1 of the LH comparand is to allow some "looseness" in |
|
299 // checking: we usually call this interface when adding a block |
|
300 // and we'll subsequently update the stats; we cannot update the |
|
301 // stats beforehand because in the case of the large-block BT |
|
302 // dictionary for example, this might be the first block and |
|
303 // in that case there would be no place that we could record |
|
304 // the stats (which are kept in the block itself). |
|
305 assert((_allocation_stats.prev_sweep() + _allocation_stats.split_births() |
|
306 + _allocation_stats.coal_births() + 1) // Total Production Stock + 1 |
|
307 >= (_allocation_stats.split_deaths() + _allocation_stats.coal_deaths() |
|
308 + (ssize_t)count()), // Total Current Stock + depletion |
|
309 err_msg("FreeList " PTR_FORMAT " of size " SIZE_FORMAT |
|
310 " violates Conservation Principle: " |
|
311 "prev_sweep(" SIZE_FORMAT ")" |
|
312 " + split_births(" SIZE_FORMAT ")" |
|
313 " + coal_births(" SIZE_FORMAT ") + 1 >= " |
|
314 " split_deaths(" SIZE_FORMAT ")" |
|
315 " coal_deaths(" SIZE_FORMAT ")" |
|
316 " + count(" SSIZE_FORMAT ")", |
|
317 this, _size, _allocation_stats.prev_sweep(), _allocation_stats.split_births(), |
|
318 _allocation_stats.split_births(), _allocation_stats.split_deaths(), |
|
319 _allocation_stats.coal_deaths(), count())); |
|
320 } |
|
321 |
|
322 template <class Chunk> |
|
323 void FreeList<Chunk>::assert_proper_lock_protection_work() const { |
303 void FreeList<Chunk>::assert_proper_lock_protection_work() const { |
324 assert(_protecting_lock != NULL, "Don't call this directly"); |
304 assert(protecting_lock() != NULL, "Don't call this directly"); |
325 assert(ParallelGCThreads > 0, "Don't call this directly"); |
305 assert(ParallelGCThreads > 0, "Don't call this directly"); |
326 Thread* thr = Thread::current(); |
306 Thread* thr = Thread::current(); |
327 if (thr->is_VM_thread() || thr->is_ConcurrentGC_thread()) { |
307 if (thr->is_VM_thread() || thr->is_ConcurrentGC_thread()) { |
328 // assert that we are holding the freelist lock |
308 // assert that we are holding the freelist lock |
329 } else if (thr->is_GC_task_thread()) { |
309 } else if (thr->is_GC_task_thread()) { |
330 assert(_protecting_lock->owned_by_self(), "FreeList RACE DETECTED"); |
310 assert(protecting_lock()->owned_by_self(), "FreeList RACE DETECTED"); |
331 } else if (thr->is_Java_thread()) { |
311 } else if (thr->is_Java_thread()) { |
332 assert(!SafepointSynchronize::is_at_safepoint(), "Should not be executing"); |
312 assert(!SafepointSynchronize::is_at_safepoint(), "Should not be executing"); |
333 } else { |
313 } else { |
334 ShouldNotReachHere(); // unaccounted thread type? |
314 ShouldNotReachHere(); // unaccounted thread type? |
335 } |
315 } |
348 |
328 |
349 // Print the AllocationStats for the given free list. If the second argument |
329 // Print the AllocationStats for the given free list. If the second argument |
350 // to the call is a non-null string, it is printed in the first column; |
330 // to the call is a non-null string, it is printed in the first column; |
351 // otherwise, if the argument is null (the default), then the size of the |
331 // otherwise, if the argument is null (the default), then the size of the |
352 // (free list) block is printed in the first column. |
332 // (free list) block is printed in the first column. |
353 template <class Chunk> |
333 template <class Chunk_t> |
354 void FreeList<Chunk>::print_on(outputStream* st, const char* c) const { |
334 void FreeList<Chunk_t>::print_on(outputStream* st, const char* c) const { |
355 if (c != NULL) { |
335 if (c != NULL) { |
356 st->print("%16s", c); |
336 st->print("%16s", c); |
357 } else { |
337 } else { |
358 st->print(SIZE_FORMAT_W(16), size()); |
338 st->print(SIZE_FORMAT_W(16), size()); |
359 } |
339 } |
360 st->print("\t" |
340 } |
361 SSIZE_FORMAT_W(14) "\t" SSIZE_FORMAT_W(14) "\t" SSIZE_FORMAT_W(14) "\t" SSIZE_FORMAT_W(14) "\t" SSIZE_FORMAT_W(14) "\t" |
341 |
362 SSIZE_FORMAT_W(14) "\t" SSIZE_FORMAT_W(14) "\t" SSIZE_FORMAT_W(14) "\t" SSIZE_FORMAT_W(14) "\t" SSIZE_FORMAT_W(14) "\n", |
342 template class FreeList<Metablock>; |
363 bfr_surp(), surplus(), desired(), prev_sweep(), before_sweep(), |
343 template class FreeList<Metachunk>; |
364 count(), coal_births(), coal_deaths(), split_births(), split_deaths()); |
|
365 } |
|
366 |
|
367 #ifndef SERIALGC |
344 #ifndef SERIALGC |
368 // Needs to be after the definitions have been seen. |
|
369 template class FreeList<FreeChunk>; |
345 template class FreeList<FreeChunk>; |
370 #endif // SERIALGC |
346 #endif // SERIALGC |