Sat, 23 Nov 2013 12:25:13 +0100
8028128: Add a type safe alternative for working with counter based data
Reviewed-by: dholmes, egahlin
1 /*
2 * Copyright (c) 2003, 2013, 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 */
25 #include "precompiled.hpp"
26 #include "gc_implementation/parallelScavenge/psVirtualspace.hpp"
27 #include "runtime/os.hpp"
28 #include "runtime/virtualspace.hpp"
29 #ifdef TARGET_OS_FAMILY_linux
30 # include "os_linux.inline.hpp"
31 #endif
32 #ifdef TARGET_OS_FAMILY_solaris
33 # include "os_solaris.inline.hpp"
34 #endif
35 #ifdef TARGET_OS_FAMILY_windows
36 # include "os_windows.inline.hpp"
37 #endif
38 #ifdef TARGET_OS_FAMILY_bsd
39 # include "os_bsd.inline.hpp"
40 #endif
42 // PSVirtualSpace
44 PSVirtualSpace::PSVirtualSpace(ReservedSpace rs, size_t alignment) :
45 _alignment(alignment)
46 {
47 set_reserved(rs);
48 set_committed(reserved_low_addr(), reserved_low_addr());
49 DEBUG_ONLY(verify());
50 }
52 PSVirtualSpace::PSVirtualSpace(ReservedSpace rs) :
53 _alignment(os::vm_page_size())
54 {
55 set_reserved(rs);
56 set_committed(reserved_low_addr(), reserved_low_addr());
57 DEBUG_ONLY(verify());
58 }
60 // Deprecated.
61 PSVirtualSpace::PSVirtualSpace(): _alignment(os::vm_page_size()) {
62 }
64 // Deprecated.
65 bool PSVirtualSpace::initialize(ReservedSpace rs,
66 size_t commit_size) {
67 set_reserved(rs);
68 set_committed(reserved_low_addr(), reserved_low_addr());
70 // Commit to initial size.
71 assert(commit_size <= rs.size(), "commit_size too big");
72 bool result = commit_size > 0 ? expand_by(commit_size) : true;
73 DEBUG_ONLY(verify());
74 return result;
75 }
77 PSVirtualSpace::~PSVirtualSpace() {
78 release();
79 }
81 bool PSVirtualSpace::contains(void* p) const {
82 char* const cp = (char*)p;
83 return cp >= committed_low_addr() && cp < committed_high_addr();
84 }
86 void PSVirtualSpace::release() {
87 DEBUG_ONLY(PSVirtualSpaceVerifier this_verifier(this));
88 // This may not release memory it didn't reserve.
89 // Use rs.release() to release the underlying memory instead.
90 _reserved_low_addr = _reserved_high_addr = NULL;
91 _committed_low_addr = _committed_high_addr = NULL;
92 _special = false;
93 }
95 bool PSVirtualSpace::expand_by(size_t bytes) {
96 assert(is_aligned(bytes), "arg not aligned");
97 DEBUG_ONLY(PSVirtualSpaceVerifier this_verifier(this));
99 if (uncommitted_size() < bytes) {
100 return false;
101 }
103 char* const base_addr = committed_high_addr();
104 bool result = special() ||
105 os::commit_memory(base_addr, bytes, alignment(), !ExecMem);
106 if (result) {
107 _committed_high_addr += bytes;
108 }
110 return result;
111 }
113 bool PSVirtualSpace::shrink_by(size_t bytes) {
114 assert(is_aligned(bytes), "arg not aligned");
115 DEBUG_ONLY(PSVirtualSpaceVerifier this_verifier(this));
117 if (committed_size() < bytes) {
118 return false;
119 }
121 char* const base_addr = committed_high_addr() - bytes;
122 bool result = special() || os::uncommit_memory(base_addr, bytes);
123 if (result) {
124 _committed_high_addr -= bytes;
125 }
127 return result;
128 }
130 size_t
131 PSVirtualSpace::expand_into(PSVirtualSpace* other_space, size_t bytes) {
132 assert(is_aligned(bytes), "arg not aligned");
133 assert(grows_up(), "this space must grow up");
134 assert(other_space->grows_down(), "other space must grow down");
135 assert(reserved_high_addr() == other_space->reserved_low_addr(),
136 "spaces not contiguous");
137 assert(special() == other_space->special(), "one space is special, the other is not");
138 DEBUG_ONLY(PSVirtualSpaceVerifier this_verifier(this));
139 DEBUG_ONLY(PSVirtualSpaceVerifier other_verifier(other_space));
141 size_t bytes_needed = bytes;
143 // First use the uncommitted region in this space.
144 size_t tmp_bytes = MIN2(uncommitted_size(), bytes_needed);
145 if (tmp_bytes > 0) {
146 if (expand_by(tmp_bytes)) {
147 bytes_needed -= tmp_bytes;
148 } else {
149 return 0;
150 }
151 }
153 // Next take from the uncommitted region in the other space, and commit it.
154 tmp_bytes = MIN2(other_space->uncommitted_size(), bytes_needed);
155 if (tmp_bytes > 0) {
156 char* const commit_base = committed_high_addr();
157 if (other_space->special() ||
158 os::commit_memory(commit_base, tmp_bytes, alignment(), !ExecMem)) {
159 // Reduce the reserved region in the other space.
160 other_space->set_reserved(other_space->reserved_low_addr() + tmp_bytes,
161 other_space->reserved_high_addr(),
162 other_space->special());
164 // Grow both reserved and committed in this space.
165 _reserved_high_addr += tmp_bytes;
166 _committed_high_addr += tmp_bytes;
167 bytes_needed -= tmp_bytes;
168 } else {
169 return bytes - bytes_needed;
170 }
171 }
173 // Finally take from the already committed region in the other space.
174 tmp_bytes = bytes_needed;
175 if (tmp_bytes > 0) {
176 // Reduce both committed and reserved in the other space.
177 other_space->set_committed(other_space->committed_low_addr() + tmp_bytes,
178 other_space->committed_high_addr());
179 other_space->set_reserved(other_space->reserved_low_addr() + tmp_bytes,
180 other_space->reserved_high_addr(),
181 other_space->special());
183 // Grow both reserved and committed in this space.
184 _reserved_high_addr += tmp_bytes;
185 _committed_high_addr += tmp_bytes;
186 }
188 return bytes;
189 }
191 #ifndef PRODUCT
192 bool PSVirtualSpace::is_aligned(size_t value, size_t align) {
193 const size_t tmp_value = value + align - 1;
194 const size_t mask = ~(align - 1);
195 return (tmp_value & mask) == value;
196 }
198 bool PSVirtualSpace::is_aligned(size_t value) const {
199 return is_aligned(value, alignment());
200 }
202 bool PSVirtualSpace::is_aligned(char* value) const {
203 return is_aligned((size_t)value);
204 }
206 void PSVirtualSpace::verify() const {
207 assert(is_aligned(alignment(), os::vm_page_size()), "bad alignment");
208 assert(is_aligned(reserved_low_addr()), "bad reserved_low_addr");
209 assert(is_aligned(reserved_high_addr()), "bad reserved_high_addr");
210 assert(is_aligned(committed_low_addr()), "bad committed_low_addr");
211 assert(is_aligned(committed_high_addr()), "bad committed_high_addr");
213 // Reserved region must be non-empty or both addrs must be 0.
214 assert(reserved_low_addr() < reserved_high_addr() ||
215 reserved_low_addr() == NULL && reserved_high_addr() == NULL,
216 "bad reserved addrs");
217 assert(committed_low_addr() <= committed_high_addr(), "bad committed addrs");
219 if (grows_up()) {
220 assert(reserved_low_addr() == committed_low_addr(), "bad low addrs");
221 assert(reserved_high_addr() >= committed_high_addr(), "bad high addrs");
222 } else {
223 assert(reserved_high_addr() == committed_high_addr(), "bad high addrs");
224 assert(reserved_low_addr() <= committed_low_addr(), "bad low addrs");
225 }
226 }
228 void PSVirtualSpace::print() const {
229 gclog_or_tty->print_cr("virtual space [" PTR_FORMAT "]: alignment="
230 SIZE_FORMAT "K grows %s%s",
231 this, alignment() / K, grows_up() ? "up" : "down",
232 special() ? " (pinned in memory)" : "");
233 gclog_or_tty->print_cr(" reserved=" SIZE_FORMAT "K"
234 " [" PTR_FORMAT "," PTR_FORMAT "]"
235 " committed=" SIZE_FORMAT "K"
236 " [" PTR_FORMAT "," PTR_FORMAT "]",
237 reserved_size() / K,
238 reserved_low_addr(), reserved_high_addr(),
239 committed_size() / K,
240 committed_low_addr(), committed_high_addr());
241 }
242 #endif // #ifndef PRODUCT
244 void PSVirtualSpace::print_space_boundaries_on(outputStream* st) const {
245 st->print_cr(" [" PTR_FORMAT ", " PTR_FORMAT ", " PTR_FORMAT ")",
246 low_boundary(), high(), high_boundary());
247 }
249 PSVirtualSpaceHighToLow::PSVirtualSpaceHighToLow(ReservedSpace rs,
250 size_t alignment) :
251 PSVirtualSpace(alignment)
252 {
253 set_reserved(rs);
254 set_committed(reserved_high_addr(), reserved_high_addr());
255 DEBUG_ONLY(verify());
256 }
258 PSVirtualSpaceHighToLow::PSVirtualSpaceHighToLow(ReservedSpace rs) {
259 set_reserved(rs);
260 set_committed(reserved_high_addr(), reserved_high_addr());
261 DEBUG_ONLY(verify());
262 }
264 bool PSVirtualSpaceHighToLow::expand_by(size_t bytes) {
265 assert(is_aligned(bytes), "arg not aligned");
266 DEBUG_ONLY(PSVirtualSpaceVerifier this_verifier(this));
268 if (uncommitted_size() < bytes) {
269 return false;
270 }
272 char* const base_addr = committed_low_addr() - bytes;
273 bool result = special() ||
274 os::commit_memory(base_addr, bytes, alignment(), !ExecMem);
275 if (result) {
276 _committed_low_addr -= bytes;
277 }
279 return result;
280 }
282 bool PSVirtualSpaceHighToLow::shrink_by(size_t bytes) {
283 assert(is_aligned(bytes), "arg not aligned");
284 DEBUG_ONLY(PSVirtualSpaceVerifier this_verifier(this));
286 if (committed_size() < bytes) {
287 return false;
288 }
290 char* const base_addr = committed_low_addr();
291 bool result = special() || os::uncommit_memory(base_addr, bytes);
292 if (result) {
293 _committed_low_addr += bytes;
294 }
296 return result;
297 }
299 size_t PSVirtualSpaceHighToLow::expand_into(PSVirtualSpace* other_space,
300 size_t bytes) {
301 assert(is_aligned(bytes), "arg not aligned");
302 assert(grows_down(), "this space must grow down");
303 assert(other_space->grows_up(), "other space must grow up");
304 assert(reserved_low_addr() == other_space->reserved_high_addr(),
305 "spaces not contiguous");
306 assert(special() == other_space->special(), "one space is special in memory, the other is not");
307 DEBUG_ONLY(PSVirtualSpaceVerifier this_verifier(this));
308 DEBUG_ONLY(PSVirtualSpaceVerifier other_verifier(other_space));
310 size_t bytes_needed = bytes;
312 // First use the uncommitted region in this space.
313 size_t tmp_bytes = MIN2(uncommitted_size(), bytes_needed);
314 if (tmp_bytes > 0) {
315 if (expand_by(tmp_bytes)) {
316 bytes_needed -= tmp_bytes;
317 } else {
318 return 0;
319 }
320 }
322 // Next take from the uncommitted region in the other space, and commit it.
323 tmp_bytes = MIN2(other_space->uncommitted_size(), bytes_needed);
324 if (tmp_bytes > 0) {
325 char* const commit_base = committed_low_addr() - tmp_bytes;
326 if (other_space->special() ||
327 os::commit_memory(commit_base, tmp_bytes, alignment(), !ExecMem)) {
328 // Reduce the reserved region in the other space.
329 other_space->set_reserved(other_space->reserved_low_addr(),
330 other_space->reserved_high_addr() - tmp_bytes,
331 other_space->special());
333 // Grow both reserved and committed in this space.
334 _reserved_low_addr -= tmp_bytes;
335 _committed_low_addr -= tmp_bytes;
336 bytes_needed -= tmp_bytes;
337 } else {
338 return bytes - bytes_needed;
339 }
340 }
342 // Finally take from the already committed region in the other space.
343 tmp_bytes = bytes_needed;
344 if (tmp_bytes > 0) {
345 // Reduce both committed and reserved in the other space.
346 other_space->set_committed(other_space->committed_low_addr(),
347 other_space->committed_high_addr() - tmp_bytes);
348 other_space->set_reserved(other_space->reserved_low_addr(),
349 other_space->reserved_high_addr() - tmp_bytes,
350 other_space->special());
352 // Grow both reserved and committed in this space.
353 _reserved_low_addr -= tmp_bytes;
354 _committed_low_addr -= tmp_bytes;
355 }
357 return bytes;
358 }
360 void
361 PSVirtualSpaceHighToLow::print_space_boundaries_on(outputStream* st) const {
362 st->print_cr(" (" PTR_FORMAT ", " PTR_FORMAT ", " PTR_FORMAT "]",
363 high_boundary(), low(), low_boundary());
364 }