Wed, 18 Aug 2010 10:59:06 -0700
6977924: Changes for 6975078 produce build error with certain gcc versions
Summary: The changes introduced for 6975078 assign badHeapOopVal to the _allocation field in the ResourceObj class. In 32 bit linux builds with certain versions of gcc this assignment will be flagged as an error while compiling allocation.cpp. In 32 bit builds the constant value badHeapOopVal (which is cast to an intptr_t) is negative. The _allocation field is typed as an unsigned intptr_t and gcc catches this as an error.
Reviewed-by: jcoomes, ysr, phh
1 /*
2 * Copyright (c) 1997, 2005, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
23 */
25 # include "incls/_precompiled.incl"
26 # include "incls/_allocation.cpp.incl"
28 void* CHeapObj::operator new(size_t size){
29 return (void *) AllocateHeap(size, "CHeapObj-new");
30 }
32 void CHeapObj::operator delete(void* p){
33 FreeHeap(p);
34 }
36 void* StackObj::operator new(size_t size) { ShouldNotCallThis(); return 0; };
37 void StackObj::operator delete(void* p) { ShouldNotCallThis(); };
38 void* _ValueObj::operator new(size_t size) { ShouldNotCallThis(); return 0; };
39 void _ValueObj::operator delete(void* p) { ShouldNotCallThis(); };
41 void* ResourceObj::operator new(size_t size, allocation_type type) {
42 address res;
43 switch (type) {
44 case C_HEAP:
45 res = (address)AllocateHeap(size, "C_Heap: ResourceOBJ");
46 DEBUG_ONLY(set_allocation_type(res, C_HEAP);)
47 break;
48 case RESOURCE_AREA:
49 // new(size) sets allocation type RESOURCE_AREA.
50 res = (address)operator new(size);
51 break;
52 default:
53 ShouldNotReachHere();
54 }
55 return res;
56 }
58 void ResourceObj::operator delete(void* p) {
59 assert(((ResourceObj *)p)->allocated_on_C_heap(),
60 "delete only allowed for C_HEAP objects");
61 DEBUG_ONLY(((ResourceObj *)p)->_allocation = (uintptr_t) badHeapOopVal;)
62 FreeHeap(p);
63 }
65 #ifdef ASSERT
66 void ResourceObj::set_allocation_type(address res, allocation_type type) {
67 // Set allocation type in the resource object
68 uintptr_t allocation = (uintptr_t)res;
69 assert((allocation & allocation_mask) == 0, "address should be aligned to 4 bytes at least");
70 assert(type <= allocation_mask, "incorrect allocation type");
71 ((ResourceObj *)res)->_allocation = ~(allocation + type);
72 }
74 ResourceObj::allocation_type ResourceObj::get_allocation_type() const {
75 assert(~(_allocation | allocation_mask) == (uintptr_t)this, "lost resource object");
76 return (allocation_type)((~_allocation) & allocation_mask);
77 }
79 ResourceObj::ResourceObj() { // default constructor
80 if (~(_allocation | allocation_mask) != (uintptr_t)this) {
81 set_allocation_type((address)this, STACK_OR_EMBEDDED);
82 } else if (allocated_on_stack()) {
83 // For some reason we got a value which looks like an allocation on stack.
84 // Pass if it is really allocated on stack.
85 assert(Thread::current()->on_local_stack((address)this),"should be on stack");
86 } else {
87 assert(allocated_on_res_area() || allocated_on_C_heap() || allocated_on_arena(),
88 "allocation_type should be set by operator new()");
89 }
90 }
92 ResourceObj::ResourceObj(const ResourceObj& r) { // default copy constructor
93 // Used in ClassFileParser::parse_constant_pool_entries() for ClassFileStream.
94 set_allocation_type((address)this, STACK_OR_EMBEDDED);
95 }
97 ResourceObj& ResourceObj::operator=(const ResourceObj& r) { // default copy assignment
98 // Used in InlineTree::ok_to_inline() for WarmCallInfo.
99 assert(allocated_on_stack(), "copy only into local");
100 // Keep current _allocation value;
101 return *this;
102 }
104 ResourceObj::~ResourceObj() {
105 // allocated_on_C_heap() also checks that encoded (in _allocation) address == this.
106 if (!allocated_on_C_heap()) { // ResourceObj::delete() zaps _allocation for C_heap.
107 _allocation = (uintptr_t) badHeapOopVal; // zap type
108 }
109 }
110 #endif // ASSERT
113 void trace_heap_malloc(size_t size, const char* name, void* p) {
114 // A lock is not needed here - tty uses a lock internally
115 tty->print_cr("Heap malloc " INTPTR_FORMAT " %7d %s", p, size, name == NULL ? "" : name);
116 }
119 void trace_heap_free(void* p) {
120 // A lock is not needed here - tty uses a lock internally
121 tty->print_cr("Heap free " INTPTR_FORMAT, p);
122 }
124 bool warn_new_operator = false; // see vm_main
126 //--------------------------------------------------------------------------------------
127 // ChunkPool implementation
129 // MT-safe pool of chunks to reduce malloc/free thrashing
130 // NB: not using Mutex because pools are used before Threads are initialized
131 class ChunkPool {
132 Chunk* _first; // first cached Chunk; its first word points to next chunk
133 size_t _num_chunks; // number of unused chunks in pool
134 size_t _num_used; // number of chunks currently checked out
135 const size_t _size; // size of each chunk (must be uniform)
137 // Our three static pools
138 static ChunkPool* _large_pool;
139 static ChunkPool* _medium_pool;
140 static ChunkPool* _small_pool;
142 // return first element or null
143 void* get_first() {
144 Chunk* c = _first;
145 if (_first) {
146 _first = _first->next();
147 _num_chunks--;
148 }
149 return c;
150 }
152 public:
153 // All chunks in a ChunkPool has the same size
154 ChunkPool(size_t size) : _size(size) { _first = NULL; _num_chunks = _num_used = 0; }
156 // Allocate a new chunk from the pool (might expand the pool)
157 void* allocate(size_t bytes) {
158 assert(bytes == _size, "bad size");
159 void* p = NULL;
160 { ThreadCritical tc;
161 _num_used++;
162 p = get_first();
163 if (p == NULL) p = os::malloc(bytes);
164 }
165 if (p == NULL)
166 vm_exit_out_of_memory(bytes, "ChunkPool::allocate");
168 return p;
169 }
171 // Return a chunk to the pool
172 void free(Chunk* chunk) {
173 assert(chunk->length() + Chunk::aligned_overhead_size() == _size, "bad size");
174 ThreadCritical tc;
175 _num_used--;
177 // Add chunk to list
178 chunk->set_next(_first);
179 _first = chunk;
180 _num_chunks++;
181 }
183 // Prune the pool
184 void free_all_but(size_t n) {
185 // if we have more than n chunks, free all of them
186 ThreadCritical tc;
187 if (_num_chunks > n) {
188 // free chunks at end of queue, for better locality
189 Chunk* cur = _first;
190 for (size_t i = 0; i < (n - 1) && cur != NULL; i++) cur = cur->next();
192 if (cur != NULL) {
193 Chunk* next = cur->next();
194 cur->set_next(NULL);
195 cur = next;
197 // Free all remaining chunks
198 while(cur != NULL) {
199 next = cur->next();
200 os::free(cur);
201 _num_chunks--;
202 cur = next;
203 }
204 }
205 }
206 }
208 // Accessors to preallocated pool's
209 static ChunkPool* large_pool() { assert(_large_pool != NULL, "must be initialized"); return _large_pool; }
210 static ChunkPool* medium_pool() { assert(_medium_pool != NULL, "must be initialized"); return _medium_pool; }
211 static ChunkPool* small_pool() { assert(_small_pool != NULL, "must be initialized"); return _small_pool; }
213 static void initialize() {
214 _large_pool = new ChunkPool(Chunk::size + Chunk::aligned_overhead_size());
215 _medium_pool = new ChunkPool(Chunk::medium_size + Chunk::aligned_overhead_size());
216 _small_pool = new ChunkPool(Chunk::init_size + Chunk::aligned_overhead_size());
217 }
219 static void clean() {
220 enum { BlocksToKeep = 5 };
221 _small_pool->free_all_but(BlocksToKeep);
222 _medium_pool->free_all_but(BlocksToKeep);
223 _large_pool->free_all_but(BlocksToKeep);
224 }
225 };
227 ChunkPool* ChunkPool::_large_pool = NULL;
228 ChunkPool* ChunkPool::_medium_pool = NULL;
229 ChunkPool* ChunkPool::_small_pool = NULL;
231 void chunkpool_init() {
232 ChunkPool::initialize();
233 }
235 void
236 Chunk::clean_chunk_pool() {
237 ChunkPool::clean();
238 }
241 //--------------------------------------------------------------------------------------
242 // ChunkPoolCleaner implementation
243 //
245 class ChunkPoolCleaner : public PeriodicTask {
246 enum { CleaningInterval = 5000 }; // cleaning interval in ms
248 public:
249 ChunkPoolCleaner() : PeriodicTask(CleaningInterval) {}
250 void task() {
251 ChunkPool::clean();
252 }
253 };
255 //--------------------------------------------------------------------------------------
256 // Chunk implementation
258 void* Chunk::operator new(size_t requested_size, size_t length) {
259 // requested_size is equal to sizeof(Chunk) but in order for the arena
260 // allocations to come out aligned as expected the size must be aligned
261 // to expected arean alignment.
262 // expect requested_size but if sizeof(Chunk) doesn't match isn't proper size we must align it.
263 assert(ARENA_ALIGN(requested_size) == aligned_overhead_size(), "Bad alignment");
264 size_t bytes = ARENA_ALIGN(requested_size) + length;
265 switch (length) {
266 case Chunk::size: return ChunkPool::large_pool()->allocate(bytes);
267 case Chunk::medium_size: return ChunkPool::medium_pool()->allocate(bytes);
268 case Chunk::init_size: return ChunkPool::small_pool()->allocate(bytes);
269 default: {
270 void *p = os::malloc(bytes);
271 if (p == NULL)
272 vm_exit_out_of_memory(bytes, "Chunk::new");
273 return p;
274 }
275 }
276 }
278 void Chunk::operator delete(void* p) {
279 Chunk* c = (Chunk*)p;
280 switch (c->length()) {
281 case Chunk::size: ChunkPool::large_pool()->free(c); break;
282 case Chunk::medium_size: ChunkPool::medium_pool()->free(c); break;
283 case Chunk::init_size: ChunkPool::small_pool()->free(c); break;
284 default: os::free(c);
285 }
286 }
288 Chunk::Chunk(size_t length) : _len(length) {
289 _next = NULL; // Chain on the linked list
290 }
293 void Chunk::chop() {
294 Chunk *k = this;
295 while( k ) {
296 Chunk *tmp = k->next();
297 // clear out this chunk (to detect allocation bugs)
298 if (ZapResourceArea) memset(k->bottom(), badResourceValue, k->length());
299 delete k; // Free chunk (was malloc'd)
300 k = tmp;
301 }
302 }
304 void Chunk::next_chop() {
305 _next->chop();
306 _next = NULL;
307 }
310 void Chunk::start_chunk_pool_cleaner_task() {
311 #ifdef ASSERT
312 static bool task_created = false;
313 assert(!task_created, "should not start chuck pool cleaner twice");
314 task_created = true;
315 #endif
316 ChunkPoolCleaner* cleaner = new ChunkPoolCleaner();
317 cleaner->enroll();
318 }
320 //------------------------------Arena------------------------------------------
322 Arena::Arena(size_t init_size) {
323 size_t round_size = (sizeof (char *)) - 1;
324 init_size = (init_size+round_size) & ~round_size;
325 _first = _chunk = new (init_size) Chunk(init_size);
326 _hwm = _chunk->bottom(); // Save the cached hwm, max
327 _max = _chunk->top();
328 set_size_in_bytes(init_size);
329 }
331 Arena::Arena() {
332 _first = _chunk = new (Chunk::init_size) Chunk(Chunk::init_size);
333 _hwm = _chunk->bottom(); // Save the cached hwm, max
334 _max = _chunk->top();
335 set_size_in_bytes(Chunk::init_size);
336 }
338 Arena::Arena(Arena *a) : _chunk(a->_chunk), _hwm(a->_hwm), _max(a->_max), _first(a->_first) {
339 set_size_in_bytes(a->size_in_bytes());
340 }
342 Arena *Arena::move_contents(Arena *copy) {
343 copy->destruct_contents();
344 copy->_chunk = _chunk;
345 copy->_hwm = _hwm;
346 copy->_max = _max;
347 copy->_first = _first;
348 copy->set_size_in_bytes(size_in_bytes());
349 // Destroy original arena
350 reset();
351 return copy; // Return Arena with contents
352 }
354 Arena::~Arena() {
355 destruct_contents();
356 }
358 // Destroy this arenas contents and reset to empty
359 void Arena::destruct_contents() {
360 if (UseMallocOnly && _first != NULL) {
361 char* end = _first->next() ? _first->top() : _hwm;
362 free_malloced_objects(_first, _first->bottom(), end, _hwm);
363 }
364 _first->chop();
365 reset();
366 }
369 // Total of all Chunks in arena
370 size_t Arena::used() const {
371 size_t sum = _chunk->length() - (_max-_hwm); // Size leftover in this Chunk
372 register Chunk *k = _first;
373 while( k != _chunk) { // Whilst have Chunks in a row
374 sum += k->length(); // Total size of this Chunk
375 k = k->next(); // Bump along to next Chunk
376 }
377 return sum; // Return total consumed space.
378 }
381 // Grow a new Chunk
382 void* Arena::grow( size_t x ) {
383 // Get minimal required size. Either real big, or even bigger for giant objs
384 size_t len = MAX2(x, (size_t) Chunk::size);
386 Chunk *k = _chunk; // Get filled-up chunk address
387 _chunk = new (len) Chunk(len);
389 if (_chunk == NULL)
390 vm_exit_out_of_memory(len * Chunk::aligned_overhead_size(), "Arena::grow");
392 if (k) k->set_next(_chunk); // Append new chunk to end of linked list
393 else _first = _chunk;
394 _hwm = _chunk->bottom(); // Save the cached hwm, max
395 _max = _chunk->top();
396 set_size_in_bytes(size_in_bytes() + len);
397 void* result = _hwm;
398 _hwm += x;
399 return result;
400 }
404 // Reallocate storage in Arena.
405 void *Arena::Arealloc(void* old_ptr, size_t old_size, size_t new_size) {
406 assert(new_size >= 0, "bad size");
407 if (new_size == 0) return NULL;
408 #ifdef ASSERT
409 if (UseMallocOnly) {
410 // always allocate a new object (otherwise we'll free this one twice)
411 char* copy = (char*)Amalloc(new_size);
412 size_t n = MIN2(old_size, new_size);
413 if (n > 0) memcpy(copy, old_ptr, n);
414 Afree(old_ptr,old_size); // Mostly done to keep stats accurate
415 return copy;
416 }
417 #endif
418 char *c_old = (char*)old_ptr; // Handy name
419 // Stupid fast special case
420 if( new_size <= old_size ) { // Shrink in-place
421 if( c_old+old_size == _hwm) // Attempt to free the excess bytes
422 _hwm = c_old+new_size; // Adjust hwm
423 return c_old;
424 }
426 // make sure that new_size is legal
427 size_t corrected_new_size = ARENA_ALIGN(new_size);
429 // See if we can resize in-place
430 if( (c_old+old_size == _hwm) && // Adjusting recent thing
431 (c_old+corrected_new_size <= _max) ) { // Still fits where it sits
432 _hwm = c_old+corrected_new_size; // Adjust hwm
433 return c_old; // Return old pointer
434 }
436 // Oops, got to relocate guts
437 void *new_ptr = Amalloc(new_size);
438 memcpy( new_ptr, c_old, old_size );
439 Afree(c_old,old_size); // Mostly done to keep stats accurate
440 return new_ptr;
441 }
444 // Determine if pointer belongs to this Arena or not.
445 bool Arena::contains( const void *ptr ) const {
446 #ifdef ASSERT
447 if (UseMallocOnly) {
448 // really slow, but not easy to make fast
449 if (_chunk == NULL) return false;
450 char** bottom = (char**)_chunk->bottom();
451 for (char** p = (char**)_hwm - 1; p >= bottom; p--) {
452 if (*p == ptr) return true;
453 }
454 for (Chunk *c = _first; c != NULL; c = c->next()) {
455 if (c == _chunk) continue; // current chunk has been processed
456 char** bottom = (char**)c->bottom();
457 for (char** p = (char**)c->top() - 1; p >= bottom; p--) {
458 if (*p == ptr) return true;
459 }
460 }
461 return false;
462 }
463 #endif
464 if( (void*)_chunk->bottom() <= ptr && ptr < (void*)_hwm )
465 return true; // Check for in this chunk
466 for (Chunk *c = _first; c; c = c->next()) {
467 if (c == _chunk) continue; // current chunk has been processed
468 if ((void*)c->bottom() <= ptr && ptr < (void*)c->top()) {
469 return true; // Check for every chunk in Arena
470 }
471 }
472 return false; // Not in any Chunk, so not in Arena
473 }
476 #ifdef ASSERT
477 void* Arena::malloc(size_t size) {
478 assert(UseMallocOnly, "shouldn't call");
479 // use malloc, but save pointer in res. area for later freeing
480 char** save = (char**)internal_malloc_4(sizeof(char*));
481 return (*save = (char*)os::malloc(size));
482 }
484 // for debugging with UseMallocOnly
485 void* Arena::internal_malloc_4(size_t x) {
486 assert( (x&(sizeof(char*)-1)) == 0, "misaligned size" );
487 if (_hwm + x > _max) {
488 return grow(x);
489 } else {
490 char *old = _hwm;
491 _hwm += x;
492 return old;
493 }
494 }
495 #endif
498 //--------------------------------------------------------------------------------------
499 // Non-product code
501 #ifndef PRODUCT
502 // The global operator new should never be called since it will usually indicate
503 // a memory leak. Use CHeapObj as the base class of such objects to make it explicit
504 // that they're allocated on the C heap.
505 // Commented out in product version to avoid conflicts with third-party C++ native code.
506 // %% note this is causing a problem on solaris debug build. the global
507 // new is being called from jdk source and causing data corruption.
508 // src/share/native/sun/awt/font/fontmanager/textcache/hsMemory.cpp::hsSoftNew
509 // define CATCH_OPERATOR_NEW_USAGE if you want to use this.
510 #ifdef CATCH_OPERATOR_NEW_USAGE
511 void* operator new(size_t size){
512 static bool warned = false;
513 if (!warned && warn_new_operator)
514 warning("should not call global (default) operator new");
515 warned = true;
516 return (void *) AllocateHeap(size, "global operator new");
517 }
518 #endif
520 void AllocatedObj::print() const { print_on(tty); }
521 void AllocatedObj::print_value() const { print_value_on(tty); }
523 void AllocatedObj::print_on(outputStream* st) const {
524 st->print_cr("AllocatedObj(" INTPTR_FORMAT ")", this);
525 }
527 void AllocatedObj::print_value_on(outputStream* st) const {
528 st->print("AllocatedObj(" INTPTR_FORMAT ")", this);
529 }
531 size_t Arena::_bytes_allocated = 0;
533 AllocStats::AllocStats() {
534 start_mallocs = os::num_mallocs;
535 start_frees = os::num_frees;
536 start_malloc_bytes = os::alloc_bytes;
537 start_res_bytes = Arena::_bytes_allocated;
538 }
540 int AllocStats::num_mallocs() { return os::num_mallocs - start_mallocs; }
541 size_t AllocStats::alloc_bytes() { return os::alloc_bytes - start_malloc_bytes; }
542 size_t AllocStats::resource_bytes() { return Arena::_bytes_allocated - start_res_bytes; }
543 int AllocStats::num_frees() { return os::num_frees - start_frees; }
544 void AllocStats::print() {
545 tty->print("%d mallocs (%ldK), %d frees, %ldK resrc",
546 num_mallocs(), alloc_bytes()/K, num_frees(), resource_bytes()/K);
547 }
550 // debugging code
551 inline void Arena::free_all(char** start, char** end) {
552 for (char** p = start; p < end; p++) if (*p) os::free(*p);
553 }
555 void Arena::free_malloced_objects(Chunk* chunk, char* hwm, char* max, char* hwm2) {
556 assert(UseMallocOnly, "should not call");
557 // free all objects malloced since resource mark was created; resource area
558 // contains their addresses
559 if (chunk->next()) {
560 // this chunk is full, and some others too
561 for (Chunk* c = chunk->next(); c != NULL; c = c->next()) {
562 char* top = c->top();
563 if (c->next() == NULL) {
564 top = hwm2; // last junk is only used up to hwm2
565 assert(c->contains(hwm2), "bad hwm2");
566 }
567 free_all((char**)c->bottom(), (char**)top);
568 }
569 assert(chunk->contains(hwm), "bad hwm");
570 assert(chunk->contains(max), "bad max");
571 free_all((char**)hwm, (char**)max);
572 } else {
573 // this chunk was partially used
574 assert(chunk->contains(hwm), "bad hwm");
575 assert(chunk->contains(hwm2), "bad hwm2");
576 free_all((char**)hwm, (char**)hwm2);
577 }
578 }
581 ReallocMark::ReallocMark() {
582 #ifdef ASSERT
583 Thread *thread = ThreadLocalStorage::get_thread_slow();
584 _nesting = thread->resource_area()->nesting();
585 #endif
586 }
588 void ReallocMark::check() {
589 #ifdef ASSERT
590 if (_nesting != Thread::current()->resource_area()->nesting()) {
591 fatal("allocation bug: array could grow within nested ResourceMark");
592 }
593 #endif
594 }
596 #endif // Non-product