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