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