1 | /* |
2 | * Copyright (c) 2003, 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 | #include "precompiled.hpp" |
26 | #include "gc/parallel/psVirtualspace.hpp" |
27 | #include "memory/virtualspace.hpp" |
28 | #include "runtime/os.hpp" |
29 | |
30 | // PSVirtualSpace |
31 | |
32 | PSVirtualSpace::PSVirtualSpace(ReservedSpace rs, size_t alignment) : |
33 | _alignment(alignment) |
34 | { |
35 | set_reserved(rs); |
36 | set_committed(reserved_low_addr(), reserved_low_addr()); |
37 | DEBUG_ONLY(verify()); |
38 | } |
39 | |
40 | PSVirtualSpace::PSVirtualSpace(ReservedSpace rs) : |
41 | _alignment(os::vm_page_size()) |
42 | { |
43 | set_reserved(rs); |
44 | set_committed(reserved_low_addr(), reserved_low_addr()); |
45 | DEBUG_ONLY(verify()); |
46 | } |
47 | |
48 | // Deprecated. |
49 | PSVirtualSpace::PSVirtualSpace(): |
50 | _alignment(os::vm_page_size()), |
51 | _reserved_low_addr(NULL), |
52 | _reserved_high_addr(NULL), |
53 | _committed_low_addr(NULL), |
54 | _committed_high_addr(NULL), |
55 | _special(false) { |
56 | } |
57 | |
58 | // Deprecated. |
59 | bool PSVirtualSpace::initialize(ReservedSpace rs, |
60 | size_t commit_size) { |
61 | set_reserved(rs); |
62 | set_committed(reserved_low_addr(), reserved_low_addr()); |
63 | |
64 | // Commit to initial size. |
65 | assert(commit_size <= rs.size(), "commit_size too big" ); |
66 | bool result = commit_size > 0 ? expand_by(commit_size) : true; |
67 | DEBUG_ONLY(verify()); |
68 | return result; |
69 | } |
70 | |
71 | PSVirtualSpace::~PSVirtualSpace() { |
72 | release(); |
73 | } |
74 | |
75 | bool PSVirtualSpace::contains(void* p) const { |
76 | char* const cp = (char*)p; |
77 | return cp >= committed_low_addr() && cp < committed_high_addr(); |
78 | } |
79 | |
80 | void PSVirtualSpace::release() { |
81 | DEBUG_ONLY(PSVirtualSpaceVerifier this_verifier(this)); |
82 | // This may not release memory it didn't reserve. |
83 | // Use rs.release() to release the underlying memory instead. |
84 | _reserved_low_addr = _reserved_high_addr = NULL; |
85 | _committed_low_addr = _committed_high_addr = NULL; |
86 | _special = false; |
87 | } |
88 | |
89 | bool PSVirtualSpace::expand_by(size_t bytes) { |
90 | assert(is_aligned(bytes), "arg not aligned" ); |
91 | DEBUG_ONLY(PSVirtualSpaceVerifier this_verifier(this)); |
92 | |
93 | if (uncommitted_size() < bytes) { |
94 | return false; |
95 | } |
96 | |
97 | char* const base_addr = committed_high_addr(); |
98 | bool result = special() || |
99 | os::commit_memory(base_addr, bytes, alignment(), !ExecMem); |
100 | if (result) { |
101 | _committed_high_addr += bytes; |
102 | } |
103 | |
104 | return result; |
105 | } |
106 | |
107 | bool PSVirtualSpace::shrink_by(size_t bytes) { |
108 | assert(is_aligned(bytes), "arg not aligned" ); |
109 | DEBUG_ONLY(PSVirtualSpaceVerifier this_verifier(this)); |
110 | |
111 | if (committed_size() < bytes) { |
112 | return false; |
113 | } |
114 | |
115 | char* const base_addr = committed_high_addr() - bytes; |
116 | bool result = special() || os::uncommit_memory(base_addr, bytes); |
117 | if (result) { |
118 | _committed_high_addr -= bytes; |
119 | } |
120 | |
121 | return result; |
122 | } |
123 | |
124 | size_t |
125 | PSVirtualSpace::expand_into(PSVirtualSpace* other_space, size_t bytes) { |
126 | assert(is_aligned(bytes), "arg not aligned" ); |
127 | assert(grows_up(), "this space must grow up" ); |
128 | assert(other_space->grows_down(), "other space must grow down" ); |
129 | assert(reserved_high_addr() == other_space->reserved_low_addr(), |
130 | "spaces not contiguous" ); |
131 | assert(special() == other_space->special(), "one space is special, the other is not" ); |
132 | DEBUG_ONLY(PSVirtualSpaceVerifier this_verifier(this)); |
133 | DEBUG_ONLY(PSVirtualSpaceVerifier other_verifier(other_space)); |
134 | |
135 | size_t bytes_needed = bytes; |
136 | |
137 | // First use the uncommitted region in this space. |
138 | size_t tmp_bytes = MIN2(uncommitted_size(), bytes_needed); |
139 | if (tmp_bytes > 0) { |
140 | if (expand_by(tmp_bytes)) { |
141 | bytes_needed -= tmp_bytes; |
142 | } else { |
143 | return 0; |
144 | } |
145 | } |
146 | |
147 | // Next take from the uncommitted region in the other space, and commit it. |
148 | tmp_bytes = MIN2(other_space->uncommitted_size(), bytes_needed); |
149 | if (tmp_bytes > 0) { |
150 | char* const commit_base = committed_high_addr(); |
151 | if (other_space->special() || |
152 | os::commit_memory(commit_base, tmp_bytes, alignment(), !ExecMem)) { |
153 | // Reduce the reserved region in the other space. |
154 | other_space->set_reserved(other_space->reserved_low_addr() + tmp_bytes, |
155 | other_space->reserved_high_addr(), |
156 | other_space->special()); |
157 | |
158 | // Grow both reserved and committed in this space. |
159 | _reserved_high_addr += tmp_bytes; |
160 | _committed_high_addr += tmp_bytes; |
161 | bytes_needed -= tmp_bytes; |
162 | } else { |
163 | return bytes - bytes_needed; |
164 | } |
165 | } |
166 | |
167 | // Finally take from the already committed region in the other space. |
168 | tmp_bytes = bytes_needed; |
169 | if (tmp_bytes > 0) { |
170 | // Reduce both committed and reserved in the other space. |
171 | other_space->set_committed(other_space->committed_low_addr() + tmp_bytes, |
172 | other_space->committed_high_addr()); |
173 | other_space->set_reserved(other_space->reserved_low_addr() + tmp_bytes, |
174 | other_space->reserved_high_addr(), |
175 | other_space->special()); |
176 | |
177 | // Grow both reserved and committed in this space. |
178 | _reserved_high_addr += tmp_bytes; |
179 | _committed_high_addr += tmp_bytes; |
180 | } |
181 | |
182 | return bytes; |
183 | } |
184 | |
185 | #ifndef PRODUCT |
186 | bool PSVirtualSpace::is_aligned(size_t value, size_t align) { |
187 | const size_t tmp_value = value + align - 1; |
188 | const size_t mask = ~(align - 1); |
189 | return (tmp_value & mask) == value; |
190 | } |
191 | |
192 | bool PSVirtualSpace::is_aligned(size_t value) const { |
193 | return is_aligned(value, alignment()); |
194 | } |
195 | |
196 | bool PSVirtualSpace::is_aligned(char* value) const { |
197 | return is_aligned((size_t)value); |
198 | } |
199 | |
200 | void PSVirtualSpace::verify() const { |
201 | assert(is_aligned(alignment(), os::vm_page_size()), "bad alignment" ); |
202 | assert(is_aligned(reserved_low_addr()), "bad reserved_low_addr" ); |
203 | assert(is_aligned(reserved_high_addr()), "bad reserved_high_addr" ); |
204 | assert(is_aligned(committed_low_addr()), "bad committed_low_addr" ); |
205 | assert(is_aligned(committed_high_addr()), "bad committed_high_addr" ); |
206 | |
207 | // Reserved region must be non-empty or both addrs must be 0. |
208 | assert(reserved_low_addr() < reserved_high_addr() || |
209 | reserved_low_addr() == NULL && reserved_high_addr() == NULL, |
210 | "bad reserved addrs" ); |
211 | assert(committed_low_addr() <= committed_high_addr(), "bad committed addrs" ); |
212 | |
213 | if (grows_up()) { |
214 | assert(reserved_low_addr() == committed_low_addr(), "bad low addrs" ); |
215 | assert(reserved_high_addr() >= committed_high_addr(), "bad high addrs" ); |
216 | } else { |
217 | assert(reserved_high_addr() == committed_high_addr(), "bad high addrs" ); |
218 | assert(reserved_low_addr() <= committed_low_addr(), "bad low addrs" ); |
219 | } |
220 | } |
221 | |
222 | #endif // #ifndef PRODUCT |
223 | |
224 | void PSVirtualSpace::print_space_boundaries_on(outputStream* st) const { |
225 | st->print_cr(" [" PTR_FORMAT ", " PTR_FORMAT ", " PTR_FORMAT ")" , |
226 | p2i(low_boundary()), p2i(high()), p2i(high_boundary())); |
227 | } |
228 | |
229 | PSVirtualSpaceHighToLow::PSVirtualSpaceHighToLow(ReservedSpace rs, |
230 | size_t alignment) : |
231 | PSVirtualSpace(alignment) |
232 | { |
233 | set_reserved(rs); |
234 | set_committed(reserved_high_addr(), reserved_high_addr()); |
235 | DEBUG_ONLY(verify()); |
236 | } |
237 | |
238 | PSVirtualSpaceHighToLow::PSVirtualSpaceHighToLow(ReservedSpace rs) { |
239 | set_reserved(rs); |
240 | set_committed(reserved_high_addr(), reserved_high_addr()); |
241 | DEBUG_ONLY(verify()); |
242 | } |
243 | |
244 | bool PSVirtualSpaceHighToLow::expand_by(size_t bytes) { |
245 | assert(is_aligned(bytes), "arg not aligned" ); |
246 | DEBUG_ONLY(PSVirtualSpaceVerifier this_verifier(this)); |
247 | |
248 | if (uncommitted_size() < bytes) { |
249 | return false; |
250 | } |
251 | |
252 | char* const base_addr = committed_low_addr() - bytes; |
253 | bool result = special() || |
254 | os::commit_memory(base_addr, bytes, alignment(), !ExecMem); |
255 | if (result) { |
256 | _committed_low_addr -= bytes; |
257 | } |
258 | |
259 | return result; |
260 | } |
261 | |
262 | bool PSVirtualSpaceHighToLow::shrink_by(size_t bytes) { |
263 | assert(is_aligned(bytes), "arg not aligned" ); |
264 | DEBUG_ONLY(PSVirtualSpaceVerifier this_verifier(this)); |
265 | |
266 | if (committed_size() < bytes) { |
267 | return false; |
268 | } |
269 | |
270 | char* const base_addr = committed_low_addr(); |
271 | bool result = special() || os::uncommit_memory(base_addr, bytes); |
272 | if (result) { |
273 | _committed_low_addr += bytes; |
274 | } |
275 | |
276 | return result; |
277 | } |
278 | |
279 | size_t PSVirtualSpaceHighToLow::expand_into(PSVirtualSpace* other_space, |
280 | size_t bytes) { |
281 | assert(is_aligned(bytes), "arg not aligned" ); |
282 | assert(grows_down(), "this space must grow down" ); |
283 | assert(other_space->grows_up(), "other space must grow up" ); |
284 | assert(reserved_low_addr() == other_space->reserved_high_addr(), |
285 | "spaces not contiguous" ); |
286 | assert(special() == other_space->special(), "one space is special in memory, the other is not" ); |
287 | DEBUG_ONLY(PSVirtualSpaceVerifier this_verifier(this)); |
288 | DEBUG_ONLY(PSVirtualSpaceVerifier other_verifier(other_space)); |
289 | |
290 | size_t bytes_needed = bytes; |
291 | |
292 | // First use the uncommitted region in this space. |
293 | size_t tmp_bytes = MIN2(uncommitted_size(), bytes_needed); |
294 | if (tmp_bytes > 0) { |
295 | if (expand_by(tmp_bytes)) { |
296 | bytes_needed -= tmp_bytes; |
297 | } else { |
298 | return 0; |
299 | } |
300 | } |
301 | |
302 | // Next take from the uncommitted region in the other space, and commit it. |
303 | tmp_bytes = MIN2(other_space->uncommitted_size(), bytes_needed); |
304 | if (tmp_bytes > 0) { |
305 | char* const commit_base = committed_low_addr() - tmp_bytes; |
306 | if (other_space->special() || |
307 | os::commit_memory(commit_base, tmp_bytes, alignment(), !ExecMem)) { |
308 | // Reduce the reserved region in the other space. |
309 | other_space->set_reserved(other_space->reserved_low_addr(), |
310 | other_space->reserved_high_addr() - tmp_bytes, |
311 | other_space->special()); |
312 | |
313 | // Grow both reserved and committed in this space. |
314 | _reserved_low_addr -= tmp_bytes; |
315 | _committed_low_addr -= tmp_bytes; |
316 | bytes_needed -= tmp_bytes; |
317 | } else { |
318 | return bytes - bytes_needed; |
319 | } |
320 | } |
321 | |
322 | // Finally take from the already committed region in the other space. |
323 | tmp_bytes = bytes_needed; |
324 | if (tmp_bytes > 0) { |
325 | // Reduce both committed and reserved in the other space. |
326 | other_space->set_committed(other_space->committed_low_addr(), |
327 | other_space->committed_high_addr() - tmp_bytes); |
328 | other_space->set_reserved(other_space->reserved_low_addr(), |
329 | other_space->reserved_high_addr() - tmp_bytes, |
330 | other_space->special()); |
331 | |
332 | // Grow both reserved and committed in this space. |
333 | _reserved_low_addr -= tmp_bytes; |
334 | _committed_low_addr -= tmp_bytes; |
335 | } |
336 | |
337 | return bytes; |
338 | } |
339 | |
340 | void |
341 | PSVirtualSpaceHighToLow::print_space_boundaries_on(outputStream* st) const { |
342 | st->print_cr(" (" PTR_FORMAT ", " PTR_FORMAT ", " PTR_FORMAT "]" , |
343 | p2i(high_boundary()), p2i(low()), p2i(low_boundary())); |
344 | } |
345 | |