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