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