src/share/vm/memory/allocation.cpp

Wed, 18 Aug 2010 10:59:06 -0700

author
johnc
date
Wed, 18 Aug 2010 10:59:06 -0700
changeset 2076
413ad0331a0c
parent 2044
f4f596978298
child 2100
ebfb7c68865e
permissions
-rw-r--r--

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

mercurial