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 #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) {
  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));
  79     }
  80 #endif
  81     return (char*)Amalloc(size);
  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   NOT_PRODUCT(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     NOT_PRODUCT(_size_in_bytes = _area->size_in_bytes();)
 104     debug_only(_area->_nesting++;)
 105     assert( _area->_nesting > 0, "must stack allocate RMs" );
 106   }
 107 
 108  public:
 109 
 110 #ifndef ASSERT
 111   ResourceMark(Thread *thread) {
 112     assert(thread == Thread::current(), "not the current thread");
 113     initialize(thread);
 114   }
 115 #else
 116   ResourceMark(Thread *thread);
 117 #endif // ASSERT
 118 
 119   ResourceMark()               { initialize(Thread::current()); }
 120 
 121   ResourceMark( ResourceArea *r ) :
 122     _area(r), _chunk(r->_chunk), _hwm(r->_hwm), _max(r->_max) {
 123     NOT_PRODUCT(_size_in_bytes = _area->size_in_bytes();)
 124     debug_only(_area->_nesting++;)
 125     assert( _area->_nesting > 0, "must stack allocate RMs" );
 126   }
 127 
 128   void reset_to_mark() {
 129     if (UseMallocOnly) free_malloced_objects();
 130 
 131     if( _chunk->next() )        // Delete later chunks
 132       _chunk->next_chop();
 133     _area->_chunk = _chunk;     // Roll back arena to saved chunk
 134     _area->_hwm = _hwm;
 135     _area->_max = _max;
 136 
 137     // clear out this chunk (to detect allocation bugs)
 138     if (ZapResourceArea) memset(_hwm, badResourceValue, _max - _hwm);
 139     _area->set_size_in_bytes(size_in_bytes());
 140   }
 141 
 142   ~ResourceMark() {
 143     assert( _area->_nesting > 0, "must stack allocate RMs" );
 144     debug_only(_area->_nesting--;)
 145     reset_to_mark();
 146   }
 147 
 148 
 149  private:
 150   void free_malloced_objects()                                         PRODUCT_RETURN;
 151   size_t size_in_bytes()       NOT_PRODUCT({ return _size_in_bytes; }) PRODUCT_RETURN0;
 152 };
 153 
 154 //------------------------------DeoptResourceMark-----------------------------------
 155 // A deopt resource mark releases all resources allocated after it was constructed
 156 // when the destructor is called.  Typically used as a local variable. It differs
 157 // from a typical resource more in that it is C-Heap allocated so that deoptimization
 158 // can use data structures that are arena based but are not amenable to vanilla
 159 // ResourceMarks because deoptimization can not use a stack allocated mark. During
 160 // deoptimization we go thru the following steps:
 161 //
 162 // 0: start in assembly stub and call either uncommon_trap/fetch_unroll_info
 163 // 1: create the vframeArray (contains pointers to Resource allocated structures)
 164 //   This allocates the DeoptResourceMark.
 165 // 2: return to assembly stub and remove stub frame and deoptee frame and create
 166 //    the new skeletal frames.
 167 // 3: push new stub frame and call unpack_frames
 168 // 4: retrieve information from the vframeArray to populate the skeletal frames
 169 // 5: release the DeoptResourceMark
 170 // 6: return to stub and eventually to interpreter
 171 //
 172 // With old style eager deoptimization the vframeArray was created by the vmThread there
 173 // was no way for the vframeArray to contain resource allocated objects and so
 174 // a complex set of data structures to simulate an array of vframes in CHeap memory
 175 // was used. With new style lazy deoptimization the vframeArray is created in the
 176 // the thread that will use it and we can use a much simpler scheme for the vframeArray
 177 // leveraging existing data structures if we simply create a way to manage this one
 178 // special need for a ResourceMark. If ResourceMark simply inherited from CHeapObj
 179 // then existing ResourceMarks would work fine since no one use new to allocate them
 180 // and they would be stack allocated. This leaves open the possibilty of accidental
 181 // misuse so we simple duplicate the ResourceMark functionality here.
 182 
 183 class DeoptResourceMark: public CHeapObj {
 184 protected:
 185   ResourceArea *_area;          // Resource area to stack allocate
 186   Chunk *_chunk;                // saved arena chunk
 187   char *_hwm, *_max;
 188   NOT_PRODUCT(size_t _size_in_bytes;)
 189 
 190   void initialize(Thread *thread) {
 191     _area = thread->resource_area();
 192     _chunk = _area->_chunk;
 193     _hwm = _area->_hwm;
 194     _max= _area->_max;
 195     NOT_PRODUCT(_size_in_bytes = _area->size_in_bytes();)
 196     debug_only(_area->_nesting++;)
 197     assert( _area->_nesting > 0, "must stack allocate RMs" );
 198   }
 199 
 200  public:
 201 
 202 #ifndef ASSERT
 203   DeoptResourceMark(Thread *thread) {
 204     assert(thread == Thread::current(), "not the current thread");
 205     initialize(thread);
 206   }
 207 #else
 208   DeoptResourceMark(Thread *thread);
 209 #endif // ASSERT
 210 
 211   DeoptResourceMark()               { initialize(Thread::current()); }
 212 
 213   DeoptResourceMark( ResourceArea *r ) :
 214     _area(r), _chunk(r->_chunk), _hwm(r->_hwm), _max(r->_max) {
 215     NOT_PRODUCT(_size_in_bytes = _area->size_in_bytes();)
 216     debug_only(_area->_nesting++;)
 217     assert( _area->_nesting > 0, "must stack allocate RMs" );
 218   }
 219 
 220   void reset_to_mark() {
 221     if (UseMallocOnly) free_malloced_objects();
 222 
 223     if( _chunk->next() )        // Delete later chunks
 224       _chunk->next_chop();
 225     _area->_chunk = _chunk;     // Roll back arena to saved chunk
 226     _area->_hwm = _hwm;
 227     _area->_max = _max;
 228 
 229     // clear out this chunk (to detect allocation bugs)
 230     if (ZapResourceArea) memset(_hwm, badResourceValue, _max - _hwm);
 231     _area->set_size_in_bytes(size_in_bytes());
 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()       NOT_PRODUCT({ return _size_in_bytes; }) PRODUCT_RETURN0;
 244 };
 245 
 246 #endif // SHARE_VM_MEMORY_RESOURCEAREA_HPP