1 /*
   2  * Copyright (c) 1997, 2012, 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  */
  24 
  25 #ifndef SHARE_VM_MEMORY_RESOURCEAREA_HPP
  26 #define SHARE_VM_MEMORY_RESOURCEAREA_HPP
  27 
  28 #include "memory/allocation.hpp"
  29 #include "runtime/thread.inline.hpp"
  30 
  31 // The resource area holds temporary data structures in the VM.
  32 // The actual allocation areas are thread local. Typical usage:
  33 //
  34 //   ...
  35 //   {
  36 //     ResourceMark rm;
  37 //     int foo[] = NEW_RESOURCE_ARRAY(int, 64);
  38 //     ...
  39 //   }
  40 //   ...
  41 
  42 //------------------------------ResourceArea-----------------------------------
  43 // A ResourceArea is an Arena that supports safe usage of ResourceMark.
  44 class ResourceArea: public Arena {
  45   friend class ResourceMark;
  46   friend class DeoptResourceMark;
  47   friend class VMStructs;
  48   debug_only(int _nesting;)             // current # of nested ResourceMarks
  49   debug_only(static int _warned;)       // to suppress multiple warnings
  50 
  51 public:
  52   ResourceArea() {
  53     debug_only(_nesting = 0;)
  54   }
  55 
  56   ResourceArea(size_t init_size) : Arena(init_size) {
  57     debug_only(_nesting = 0;);
  58   }
  59 
  60   char* allocate_bytes(size_t size, AllocFailType alloc_failmode = AllocFailStrategy::EXIT_OOM) {
  61 #ifdef ASSERT
  62     if (_nesting < 1 && !_warned++)
  63       fatal("memory leak: allocating without ResourceMark");
  64     if (UseMallocOnly) {
  65       // use malloc, but save pointer in res. area for later freeing
  66       char** save = (char**)internal_malloc_4(sizeof(char*));
  67       return (*save = (char*)os::malloc(size, mtThread));
  68     }
  69 #endif
  70     return (char*)Amalloc(size, alloc_failmode);
  71   }
  72 
  73   debug_only(int nesting() const { return _nesting; });
  74 };
  75 
  76 
  77 //------------------------------ResourceMark-----------------------------------
  78 // A resource mark releases all resources allocated after it was constructed
  79 // when the destructor is called.  Typically used as a local variable.
  80 class ResourceMark: public StackObj {
  81 protected:
  82   ResourceArea *_area;          // Resource area to stack allocate
  83   Chunk *_chunk;                // saved arena chunk
  84   char *_hwm, *_max;
  85   size_t _size_in_bytes;
  86 
  87   void initialize(Thread *thread) {
  88     _area = thread->resource_area();
  89     _chunk = _area->_chunk;
  90     _hwm = _area->_hwm;
  91     _max= _area->_max;
  92     _size_in_bytes = _area->size_in_bytes();
  93     debug_only(_area->_nesting++;)
  94     assert( _area->_nesting > 0, "must stack allocate RMs" );
  95   }
  96  public:
  97 
  98 #ifndef ASSERT
  99   ResourceMark(Thread *thread) {
 100     assert(thread == Thread::current(), "not the current thread");
 101     initialize(thread);
 102   }
 103 #else
 104   ResourceMark(Thread *thread);
 105 #endif // ASSERT
 106 
 107   ResourceMark()               { initialize(Thread::current()); }
 108 
 109   ResourceMark( ResourceArea *r ) :
 110     _area(r), _chunk(r->_chunk), _hwm(r->_hwm), _max(r->_max) {
 111     _size_in_bytes = r->_size_in_bytes;
 112     debug_only(_area->_nesting++;)
 113     assert( _area->_nesting > 0, "must stack allocate RMs" );
 114   }
 115 
 116   void reset_to_mark() {
 117     if (UseMallocOnly) free_malloced_objects();
 118 
 119     if( _chunk->next() ) {       // Delete later chunks
 120       // reset arena size before delete chunks. Otherwise, the total
 121       // arena size could exceed total chunk size
 122       assert(_area->size_in_bytes() > size_in_bytes(), "Sanity check");
 123       _area->set_size_in_bytes(size_in_bytes());
 124       _chunk->next_chop();
 125     } else {
 126       assert(_area->size_in_bytes() == size_in_bytes(), "Sanity check");
 127     }
 128     _area->_chunk = _chunk;     // Roll back arena to saved chunk
 129     _area->_hwm = _hwm;
 130     _area->_max = _max;
 131 
 132     // clear out this chunk (to detect allocation bugs)
 133     if (ZapResourceArea) memset(_hwm, badResourceValue, _max - _hwm);
 134   }
 135 
 136   ~ResourceMark() {
 137     assert( _area->_nesting > 0, "must stack allocate RMs" );
 138     debug_only(_area->_nesting--;)
 139     reset_to_mark();
 140   }
 141 
 142 
 143  private:
 144   void free_malloced_objects()                                         PRODUCT_RETURN;
 145   size_t size_in_bytes() { return _size_in_bytes; }
 146 };
 147 
 148 //------------------------------DeoptResourceMark-----------------------------------
 149 // A deopt resource mark releases all resources allocated after it was constructed
 150 // when the destructor is called.  Typically used as a local variable. It differs
 151 // from a typical resource more in that it is C-Heap allocated so that deoptimization
 152 // can use data structures that are arena based but are not amenable to vanilla
 153 // ResourceMarks because deoptimization can not use a stack allocated mark. During
 154 // deoptimization we go thru the following steps:
 155 //
 156 // 0: start in assembly stub and call either uncommon_trap/fetch_unroll_info
 157 // 1: create the vframeArray (contains pointers to Resource allocated structures)
 158 //   This allocates the DeoptResourceMark.
 159 // 2: return to assembly stub and remove stub frame and deoptee frame and create
 160 //    the new skeletal frames.
 161 // 3: push new stub frame and call unpack_frames
 162 // 4: retrieve information from the vframeArray to populate the skeletal frames
 163 // 5: release the DeoptResourceMark
 164 // 6: return to stub and eventually to interpreter
 165 //
 166 // With old style eager deoptimization the vframeArray was created by the vmThread there
 167 // was no way for the vframeArray to contain resource allocated objects and so
 168 // a complex set of data structures to simulate an array of vframes in CHeap memory
 169 // was used. With new style lazy deoptimization the vframeArray is created in the
 170 // the thread that will use it and we can use a much simpler scheme for the vframeArray
 171 // leveraging existing data structures if we simply create a way to manage this one
 172 // special need for a ResourceMark. If ResourceMark simply inherited from CHeapObj
 173 // then existing ResourceMarks would work fine since no one use new to allocate them
 174 // and they would be stack allocated. This leaves open the possibilty of accidental
 175 // misuse so we simple duplicate the ResourceMark functionality here.
 176 
 177 class DeoptResourceMark: public CHeapObj<mtInternal> {
 178 protected:
 179   ResourceArea *_area;          // Resource area to stack allocate
 180   Chunk *_chunk;                // saved arena chunk
 181   char *_hwm, *_max;
 182   size_t _size_in_bytes;
 183 
 184   void initialize(Thread *thread) {
 185     _area = thread->resource_area();
 186     _chunk = _area->_chunk;
 187     _hwm = _area->_hwm;
 188     _max= _area->_max;
 189     _size_in_bytes = _area->size_in_bytes();
 190     debug_only(_area->_nesting++;)
 191     assert( _area->_nesting > 0, "must stack allocate RMs" );
 192   }
 193 
 194  public:
 195 
 196 #ifndef ASSERT
 197   DeoptResourceMark(Thread *thread) {
 198     assert(thread == Thread::current(), "not the current thread");
 199     initialize(thread);
 200   }
 201 #else
 202   DeoptResourceMark(Thread *thread);
 203 #endif // ASSERT
 204 
 205   DeoptResourceMark()               { initialize(Thread::current()); }
 206 
 207   DeoptResourceMark( ResourceArea *r ) :
 208     _area(r), _chunk(r->_chunk), _hwm(r->_hwm), _max(r->_max) {
 209     _size_in_bytes = _area->size_in_bytes();
 210     debug_only(_area->_nesting++;)
 211     assert( _area->_nesting > 0, "must stack allocate RMs" );
 212   }
 213 
 214   void reset_to_mark() {
 215     if (UseMallocOnly) free_malloced_objects();
 216 
 217     if( _chunk->next() ) {        // Delete later chunks
 218       // reset arena size before delete chunks. Otherwise, the total
 219       // arena size could exceed total chunk size
 220       assert(_area->size_in_bytes() > size_in_bytes(), "Sanity check");
 221       _area->set_size_in_bytes(size_in_bytes());
 222       _chunk->next_chop();
 223     } else {
 224       assert(_area->size_in_bytes() == size_in_bytes(), "Sanity check");
 225     }
 226     _area->_chunk = _chunk;     // Roll back arena to saved chunk
 227     _area->_hwm = _hwm;
 228     _area->_max = _max;
 229 
 230     // clear out this chunk (to detect allocation bugs)
 231     if (ZapResourceArea) memset(_hwm, badResourceValue, _max - _hwm);
 232   }
 233 
 234   ~DeoptResourceMark() {
 235     assert( _area->_nesting > 0, "must stack allocate RMs" );
 236     debug_only(_area->_nesting--;)
 237     reset_to_mark();
 238   }
 239 
 240 
 241  private:
 242   void free_malloced_objects()                                         PRODUCT_RETURN;
 243   size_t size_in_bytes() { return _size_in_bytes; };
 244 };
 245 
 246 #endif // SHARE_VM_MEMORY_RESOURCEAREA_HPP