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