aoqi@0: /* aoqi@0: * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. aoqi@0: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. aoqi@0: * aoqi@0: * This code is free software; you can redistribute it and/or modify it aoqi@0: * under the terms of the GNU General Public License version 2 only, as aoqi@0: * published by the Free Software Foundation. aoqi@0: * aoqi@0: * This code is distributed in the hope that it will be useful, but WITHOUT aoqi@0: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or aoqi@0: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License aoqi@0: * version 2 for more details (a copy is included in the LICENSE file that aoqi@0: * accompanied this code). aoqi@0: * aoqi@0: * You should have received a copy of the GNU General Public License version aoqi@0: * 2 along with this work; if not, write to the Free Software Foundation, aoqi@0: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. aoqi@0: * aoqi@0: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA aoqi@0: * or visit www.oracle.com if you need additional information or have any aoqi@0: * questions. aoqi@0: * aoqi@0: */ aoqi@0: aoqi@0: #include "precompiled.hpp" aoqi@0: #include "gc_implementation/parallelScavenge/psVirtualspace.hpp" aoqi@0: #include "runtime/os.hpp" aoqi@0: #include "runtime/virtualspace.hpp" aoqi@0: #ifdef TARGET_OS_FAMILY_linux aoqi@0: # include "os_linux.inline.hpp" aoqi@0: #endif aoqi@0: #ifdef TARGET_OS_FAMILY_solaris aoqi@0: # include "os_solaris.inline.hpp" aoqi@0: #endif aoqi@0: #ifdef TARGET_OS_FAMILY_windows aoqi@0: # include "os_windows.inline.hpp" aoqi@0: #endif aoqi@0: #ifdef TARGET_OS_FAMILY_aix aoqi@0: # include "os_aix.inline.hpp" aoqi@0: #endif aoqi@0: #ifdef TARGET_OS_FAMILY_bsd aoqi@0: # include "os_bsd.inline.hpp" aoqi@0: #endif aoqi@0: aoqi@0: PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC aoqi@0: aoqi@0: // PSVirtualSpace aoqi@0: aoqi@0: PSVirtualSpace::PSVirtualSpace(ReservedSpace rs, size_t alignment) : aoqi@0: _alignment(alignment) aoqi@0: { aoqi@0: set_reserved(rs); aoqi@0: set_committed(reserved_low_addr(), reserved_low_addr()); aoqi@0: DEBUG_ONLY(verify()); aoqi@0: } aoqi@0: aoqi@0: PSVirtualSpace::PSVirtualSpace(ReservedSpace rs) : aoqi@0: _alignment(os::vm_page_size()) aoqi@0: { aoqi@0: set_reserved(rs); aoqi@0: set_committed(reserved_low_addr(), reserved_low_addr()); aoqi@0: DEBUG_ONLY(verify()); aoqi@0: } aoqi@0: aoqi@0: // Deprecated. aoqi@0: PSVirtualSpace::PSVirtualSpace(): _alignment(os::vm_page_size()) { aoqi@0: } aoqi@0: aoqi@0: // Deprecated. aoqi@0: bool PSVirtualSpace::initialize(ReservedSpace rs, aoqi@0: size_t commit_size) { aoqi@0: set_reserved(rs); aoqi@0: set_committed(reserved_low_addr(), reserved_low_addr()); aoqi@0: aoqi@0: // Commit to initial size. aoqi@0: assert(commit_size <= rs.size(), "commit_size too big"); aoqi@0: bool result = commit_size > 0 ? expand_by(commit_size) : true; aoqi@0: DEBUG_ONLY(verify()); aoqi@0: return result; aoqi@0: } aoqi@0: aoqi@0: PSVirtualSpace::~PSVirtualSpace() { aoqi@0: release(); aoqi@0: } aoqi@0: aoqi@0: bool PSVirtualSpace::contains(void* p) const { aoqi@0: char* const cp = (char*)p; aoqi@0: return cp >= committed_low_addr() && cp < committed_high_addr(); aoqi@0: } aoqi@0: aoqi@0: void PSVirtualSpace::release() { aoqi@0: DEBUG_ONLY(PSVirtualSpaceVerifier this_verifier(this)); aoqi@0: // This may not release memory it didn't reserve. aoqi@0: // Use rs.release() to release the underlying memory instead. aoqi@0: _reserved_low_addr = _reserved_high_addr = NULL; aoqi@0: _committed_low_addr = _committed_high_addr = NULL; aoqi@0: _special = false; aoqi@0: } aoqi@0: aoqi@0: bool PSVirtualSpace::expand_by(size_t bytes) { aoqi@0: assert(is_aligned(bytes), "arg not aligned"); aoqi@0: DEBUG_ONLY(PSVirtualSpaceVerifier this_verifier(this)); aoqi@0: aoqi@0: if (uncommitted_size() < bytes) { aoqi@0: return false; aoqi@0: } aoqi@0: aoqi@0: char* const base_addr = committed_high_addr(); aoqi@0: bool result = special() || aoqi@0: os::commit_memory(base_addr, bytes, alignment(), !ExecMem); aoqi@0: if (result) { aoqi@0: _committed_high_addr += bytes; aoqi@0: } aoqi@0: aoqi@0: return result; aoqi@0: } aoqi@0: aoqi@0: bool PSVirtualSpace::shrink_by(size_t bytes) { aoqi@0: assert(is_aligned(bytes), "arg not aligned"); aoqi@0: DEBUG_ONLY(PSVirtualSpaceVerifier this_verifier(this)); aoqi@0: aoqi@0: if (committed_size() < bytes) { aoqi@0: return false; aoqi@0: } aoqi@0: aoqi@0: char* const base_addr = committed_high_addr() - bytes; aoqi@0: bool result = special() || os::uncommit_memory(base_addr, bytes); aoqi@0: if (result) { aoqi@0: _committed_high_addr -= bytes; aoqi@0: } aoqi@0: aoqi@0: return result; aoqi@0: } aoqi@0: aoqi@0: size_t aoqi@0: PSVirtualSpace::expand_into(PSVirtualSpace* other_space, size_t bytes) { aoqi@0: assert(is_aligned(bytes), "arg not aligned"); aoqi@0: assert(grows_up(), "this space must grow up"); aoqi@0: assert(other_space->grows_down(), "other space must grow down"); aoqi@0: assert(reserved_high_addr() == other_space->reserved_low_addr(), aoqi@0: "spaces not contiguous"); aoqi@0: assert(special() == other_space->special(), "one space is special, the other is not"); aoqi@0: DEBUG_ONLY(PSVirtualSpaceVerifier this_verifier(this)); aoqi@0: DEBUG_ONLY(PSVirtualSpaceVerifier other_verifier(other_space)); aoqi@0: aoqi@0: size_t bytes_needed = bytes; aoqi@0: aoqi@0: // First use the uncommitted region in this space. aoqi@0: size_t tmp_bytes = MIN2(uncommitted_size(), bytes_needed); aoqi@0: if (tmp_bytes > 0) { aoqi@0: if (expand_by(tmp_bytes)) { aoqi@0: bytes_needed -= tmp_bytes; aoqi@0: } else { aoqi@0: return 0; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // Next take from the uncommitted region in the other space, and commit it. aoqi@0: tmp_bytes = MIN2(other_space->uncommitted_size(), bytes_needed); aoqi@0: if (tmp_bytes > 0) { aoqi@0: char* const commit_base = committed_high_addr(); aoqi@0: if (other_space->special() || aoqi@0: os::commit_memory(commit_base, tmp_bytes, alignment(), !ExecMem)) { aoqi@0: // Reduce the reserved region in the other space. aoqi@0: other_space->set_reserved(other_space->reserved_low_addr() + tmp_bytes, aoqi@0: other_space->reserved_high_addr(), aoqi@0: other_space->special()); aoqi@0: aoqi@0: // Grow both reserved and committed in this space. aoqi@0: _reserved_high_addr += tmp_bytes; aoqi@0: _committed_high_addr += tmp_bytes; aoqi@0: bytes_needed -= tmp_bytes; aoqi@0: } else { aoqi@0: return bytes - bytes_needed; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // Finally take from the already committed region in the other space. aoqi@0: tmp_bytes = bytes_needed; aoqi@0: if (tmp_bytes > 0) { aoqi@0: // Reduce both committed and reserved in the other space. aoqi@0: other_space->set_committed(other_space->committed_low_addr() + tmp_bytes, aoqi@0: other_space->committed_high_addr()); aoqi@0: other_space->set_reserved(other_space->reserved_low_addr() + tmp_bytes, aoqi@0: other_space->reserved_high_addr(), aoqi@0: other_space->special()); aoqi@0: aoqi@0: // Grow both reserved and committed in this space. aoqi@0: _reserved_high_addr += tmp_bytes; aoqi@0: _committed_high_addr += tmp_bytes; aoqi@0: } aoqi@0: aoqi@0: return bytes; aoqi@0: } aoqi@0: aoqi@0: #ifndef PRODUCT aoqi@0: bool PSVirtualSpace::is_aligned(size_t value, size_t align) { aoqi@0: const size_t tmp_value = value + align - 1; aoqi@0: const size_t mask = ~(align - 1); aoqi@0: return (tmp_value & mask) == value; aoqi@0: } aoqi@0: aoqi@0: bool PSVirtualSpace::is_aligned(size_t value) const { aoqi@0: return is_aligned(value, alignment()); aoqi@0: } aoqi@0: aoqi@0: bool PSVirtualSpace::is_aligned(char* value) const { aoqi@0: return is_aligned((size_t)value); aoqi@0: } aoqi@0: aoqi@0: void PSVirtualSpace::verify() const { aoqi@0: assert(is_aligned(alignment(), os::vm_page_size()), "bad alignment"); aoqi@0: assert(is_aligned(reserved_low_addr()), "bad reserved_low_addr"); aoqi@0: assert(is_aligned(reserved_high_addr()), "bad reserved_high_addr"); aoqi@0: assert(is_aligned(committed_low_addr()), "bad committed_low_addr"); aoqi@0: assert(is_aligned(committed_high_addr()), "bad committed_high_addr"); aoqi@0: aoqi@0: // Reserved region must be non-empty or both addrs must be 0. aoqi@0: assert(reserved_low_addr() < reserved_high_addr() || aoqi@0: reserved_low_addr() == NULL && reserved_high_addr() == NULL, aoqi@0: "bad reserved addrs"); aoqi@0: assert(committed_low_addr() <= committed_high_addr(), "bad committed addrs"); aoqi@0: aoqi@0: if (grows_up()) { aoqi@0: assert(reserved_low_addr() == committed_low_addr(), "bad low addrs"); aoqi@0: assert(reserved_high_addr() >= committed_high_addr(), "bad high addrs"); aoqi@0: } else { aoqi@0: assert(reserved_high_addr() == committed_high_addr(), "bad high addrs"); aoqi@0: assert(reserved_low_addr() <= committed_low_addr(), "bad low addrs"); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: void PSVirtualSpace::print() const { aoqi@0: gclog_or_tty->print_cr("virtual space [" PTR_FORMAT "]: alignment=" aoqi@0: SIZE_FORMAT "K grows %s%s", aoqi@0: this, alignment() / K, grows_up() ? "up" : "down", aoqi@0: special() ? " (pinned in memory)" : ""); aoqi@0: gclog_or_tty->print_cr(" reserved=" SIZE_FORMAT "K" aoqi@0: " [" PTR_FORMAT "," PTR_FORMAT "]" aoqi@0: " committed=" SIZE_FORMAT "K" aoqi@0: " [" PTR_FORMAT "," PTR_FORMAT "]", aoqi@0: reserved_size() / K, aoqi@0: reserved_low_addr(), reserved_high_addr(), aoqi@0: committed_size() / K, aoqi@0: committed_low_addr(), committed_high_addr()); aoqi@0: } aoqi@0: #endif // #ifndef PRODUCT aoqi@0: aoqi@0: void PSVirtualSpace::print_space_boundaries_on(outputStream* st) const { aoqi@0: st->print_cr(" [" PTR_FORMAT ", " PTR_FORMAT ", " PTR_FORMAT ")", aoqi@0: low_boundary(), high(), high_boundary()); aoqi@0: } aoqi@0: aoqi@0: PSVirtualSpaceHighToLow::PSVirtualSpaceHighToLow(ReservedSpace rs, aoqi@0: size_t alignment) : aoqi@0: PSVirtualSpace(alignment) aoqi@0: { aoqi@0: set_reserved(rs); aoqi@0: set_committed(reserved_high_addr(), reserved_high_addr()); aoqi@0: DEBUG_ONLY(verify()); aoqi@0: } aoqi@0: aoqi@0: PSVirtualSpaceHighToLow::PSVirtualSpaceHighToLow(ReservedSpace rs) { aoqi@0: set_reserved(rs); aoqi@0: set_committed(reserved_high_addr(), reserved_high_addr()); aoqi@0: DEBUG_ONLY(verify()); aoqi@0: } aoqi@0: aoqi@0: bool PSVirtualSpaceHighToLow::expand_by(size_t bytes) { aoqi@0: assert(is_aligned(bytes), "arg not aligned"); aoqi@0: DEBUG_ONLY(PSVirtualSpaceVerifier this_verifier(this)); aoqi@0: aoqi@0: if (uncommitted_size() < bytes) { aoqi@0: return false; aoqi@0: } aoqi@0: aoqi@0: char* const base_addr = committed_low_addr() - bytes; aoqi@0: bool result = special() || aoqi@0: os::commit_memory(base_addr, bytes, alignment(), !ExecMem); aoqi@0: if (result) { aoqi@0: _committed_low_addr -= bytes; aoqi@0: } aoqi@0: aoqi@0: return result; aoqi@0: } aoqi@0: aoqi@0: bool PSVirtualSpaceHighToLow::shrink_by(size_t bytes) { aoqi@0: assert(is_aligned(bytes), "arg not aligned"); aoqi@0: DEBUG_ONLY(PSVirtualSpaceVerifier this_verifier(this)); aoqi@0: aoqi@0: if (committed_size() < bytes) { aoqi@0: return false; aoqi@0: } aoqi@0: aoqi@0: char* const base_addr = committed_low_addr(); aoqi@0: bool result = special() || os::uncommit_memory(base_addr, bytes); aoqi@0: if (result) { aoqi@0: _committed_low_addr += bytes; aoqi@0: } aoqi@0: aoqi@0: return result; aoqi@0: } aoqi@0: aoqi@0: size_t PSVirtualSpaceHighToLow::expand_into(PSVirtualSpace* other_space, aoqi@0: size_t bytes) { aoqi@0: assert(is_aligned(bytes), "arg not aligned"); aoqi@0: assert(grows_down(), "this space must grow down"); aoqi@0: assert(other_space->grows_up(), "other space must grow up"); aoqi@0: assert(reserved_low_addr() == other_space->reserved_high_addr(), aoqi@0: "spaces not contiguous"); aoqi@0: assert(special() == other_space->special(), "one space is special in memory, the other is not"); aoqi@0: DEBUG_ONLY(PSVirtualSpaceVerifier this_verifier(this)); aoqi@0: DEBUG_ONLY(PSVirtualSpaceVerifier other_verifier(other_space)); aoqi@0: aoqi@0: size_t bytes_needed = bytes; aoqi@0: aoqi@0: // First use the uncommitted region in this space. aoqi@0: size_t tmp_bytes = MIN2(uncommitted_size(), bytes_needed); aoqi@0: if (tmp_bytes > 0) { aoqi@0: if (expand_by(tmp_bytes)) { aoqi@0: bytes_needed -= tmp_bytes; aoqi@0: } else { aoqi@0: return 0; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // Next take from the uncommitted region in the other space, and commit it. aoqi@0: tmp_bytes = MIN2(other_space->uncommitted_size(), bytes_needed); aoqi@0: if (tmp_bytes > 0) { aoqi@0: char* const commit_base = committed_low_addr() - tmp_bytes; aoqi@0: if (other_space->special() || aoqi@0: os::commit_memory(commit_base, tmp_bytes, alignment(), !ExecMem)) { aoqi@0: // Reduce the reserved region in the other space. aoqi@0: other_space->set_reserved(other_space->reserved_low_addr(), aoqi@0: other_space->reserved_high_addr() - tmp_bytes, aoqi@0: other_space->special()); aoqi@0: aoqi@0: // Grow both reserved and committed in this space. aoqi@0: _reserved_low_addr -= tmp_bytes; aoqi@0: _committed_low_addr -= tmp_bytes; aoqi@0: bytes_needed -= tmp_bytes; aoqi@0: } else { aoqi@0: return bytes - bytes_needed; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // Finally take from the already committed region in the other space. aoqi@0: tmp_bytes = bytes_needed; aoqi@0: if (tmp_bytes > 0) { aoqi@0: // Reduce both committed and reserved in the other space. aoqi@0: other_space->set_committed(other_space->committed_low_addr(), aoqi@0: other_space->committed_high_addr() - tmp_bytes); aoqi@0: other_space->set_reserved(other_space->reserved_low_addr(), aoqi@0: other_space->reserved_high_addr() - tmp_bytes, aoqi@0: other_space->special()); aoqi@0: aoqi@0: // Grow both reserved and committed in this space. aoqi@0: _reserved_low_addr -= tmp_bytes; aoqi@0: _committed_low_addr -= tmp_bytes; aoqi@0: } aoqi@0: aoqi@0: return bytes; aoqi@0: } aoqi@0: aoqi@0: void aoqi@0: PSVirtualSpaceHighToLow::print_space_boundaries_on(outputStream* st) const { aoqi@0: st->print_cr(" (" PTR_FORMAT ", " PTR_FORMAT ", " PTR_FORMAT "]", aoqi@0: high_boundary(), low(), low_boundary()); aoqi@0: }