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