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