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