Mercurial > hg > openjdk > jdk7u > hotspot
changeset 4703:73863f836e34 jdk7u25-b31
8014611: reserve_and_align() assumptions are invalid on windows
Summary: also reviewed by ron.durbin@oracle.com, thomas.schatzl@oracle.com
Reviewed-by: dcubed, brutisso
author | jcoomes |
---|---|
date | Thu, 23 May 2013 03:08:19 -0700 |
parents | 8d0aee729774 |
children | dd9090ad5521 |
files | src/os/posix/vm/os_posix.cpp src/os/windows/vm/os_windows.cpp src/share/vm/runtime/os.cpp src/share/vm/runtime/os.hpp src/share/vm/runtime/virtualspace.cpp src/share/vm/runtime/virtualspace.hpp |
diffstat | 6 files changed, 75 insertions(+), 12 deletions(-) [+] |
line wrap: on
line diff
--- a/src/os/posix/vm/os_posix.cpp Fri May 31 08:00:19 2013 -0700 +++ b/src/os/posix/vm/os_posix.cpp Thu May 23 03:08:19 2013 -0700 @@ -116,6 +116,10 @@ return aligned_base; } +bool os::can_release_partial_region() { + return true; +} + void os::Posix::print_load_average(outputStream* st) { st->print("load average:"); double loadavg[3];
--- a/src/os/windows/vm/os_windows.cpp Fri May 31 08:00:19 2013 -0700 +++ b/src/os/windows/vm/os_windows.cpp Thu May 23 03:08:19 2013 -0700 @@ -2941,6 +2941,10 @@ } } +bool os::can_release_partial_region() { + return false; +} + // Multiple threads can race in this code but it's not possible to unmap small sections of // virtual space to get requested alignment, like posix-like os's. // Windows prevents multiple thread from remapping over each other so this loop is thread-safe.
--- a/src/share/vm/runtime/os.cpp Fri May 31 08:00:19 2013 -0700 +++ b/src/share/vm/runtime/os.cpp Thu May 23 03:08:19 2013 -0700 @@ -1078,6 +1078,12 @@ return formatted_path; } +bool os::release_or_uncommit_partial_region(char * addr, size_t bytes) { + if (can_release_partial_region()) { + return release_memory(addr, bytes); + } + return uncommit_memory(addr, bytes); +} bool os::set_boot_path(char fileSep, char pathSep) { const char* home = Arguments::get_java_home();
--- a/src/share/vm/runtime/os.hpp Fri May 31 08:00:19 2013 -0700 +++ b/src/share/vm/runtime/os.hpp Thu May 23 03:08:19 2013 -0700 @@ -243,6 +243,8 @@ bool executable = false); static bool uncommit_memory(char* addr, size_t bytes); static bool release_memory(char* addr, size_t bytes); + static bool can_release_partial_region(); + static bool release_or_uncommit_partial_region(char* addr, size_t bytes); enum ProtType { MEM_PROT_NONE, MEM_PROT_READ, MEM_PROT_RW, MEM_PROT_RWX }; static bool protect_memory(char* addr, size_t bytes, ProtType prot,
--- a/src/share/vm/runtime/virtualspace.cpp Fri May 31 08:00:19 2013 -0700 +++ b/src/share/vm/runtime/virtualspace.cpp Thu May 23 03:08:19 2013 -0700 @@ -80,17 +80,41 @@ const size_t end_delta = len - (beg_delta + required_size); if (beg_delta != 0) { - os::release_memory(addr, beg_delta); + os::release_or_uncommit_partial_region(addr, beg_delta); } if (end_delta != 0) { char* release_addr = (char*) (s + beg_delta + required_size); - os::release_memory(release_addr, end_delta); + os::release_or_uncommit_partial_region(release_addr, end_delta); } return (char*) (s + beg_delta); } +void ReservedSpace::set_raw_base_and_size(char * const raw_base, + size_t raw_size) { + assert(raw_base == NULL || !os::can_release_partial_region(), "sanity"); + _raw_base = raw_base; + _raw_size = raw_size; +} + +// On some systems (e.g., windows), the address returned by os::reserve_memory() +// is the only addr that can be passed to os::release_memory(). If alignment +// was done by this class, that original address is _raw_base. +void ReservedSpace::release_memory(char* default_addr, size_t default_size) { + bool ok; + if (_raw_base == NULL) { + ok = os::release_memory(default_addr, default_size); + } else { + assert(!os::can_release_partial_region(), "sanity"); + ok = os::release_memory(_raw_base, _raw_size); + } + if (!ok) { + fatal("os::release_memory failed"); + } + set_raw_base_and_size(NULL, 0); +} + char* ReservedSpace::reserve_and_align(const size_t reserve_size, const size_t prefix_size, const size_t prefix_align, @@ -109,6 +133,10 @@ fatal("os::release_memory failed"); } + if (!os::can_release_partial_region()) { + set_raw_base_and_size(raw_addr, reserve_size); + } + #ifdef ASSERT if (result != NULL) { const size_t raw = size_t(raw_addr); @@ -126,8 +154,10 @@ } // Helper method. -static bool failed_to_reserve_as_requested(char* base, char* requested_address, - const size_t size, bool special) +bool ReservedSpace::failed_to_reserve_as_requested(char* base, + char* requested_address, + const size_t size, + bool special) { if (base == requested_address || requested_address == NULL) return false; // did not fail @@ -146,9 +176,7 @@ fatal("os::release_memory_special failed"); } } else { - if (!os::release_memory(base, size)) { - fatal("os::release_memory failed"); - } + release_memory(base, size); } } return true; @@ -176,6 +204,8 @@ assert(noaccess_prefix == 0 || noaccess_prefix == prefix_align, "noaccess prefix wrong"); + set_raw_base_and_size(NULL, 0); + // Add in noaccess_prefix to prefix_size; const size_t adjusted_prefix_size = prefix_size + noaccess_prefix; const size_t size = adjusted_prefix_size + suffix_size; @@ -223,9 +253,7 @@ // result is often the same address (if the kernel hands out virtual // addresses from low to high), or an address that is offset by the increase // in size. Exploit that to minimize the amount of extra space requested. - if (!os::release_memory(addr, size)) { - fatal("os::release_memory failed"); - } + release_memory(addr, size); const size_t extra = MAX2(ofs, suffix_align - ofs); addr = reserve_and_align(size + extra, adjusted_prefix_size, prefix_align, @@ -264,6 +292,8 @@ assert(alignment == 0 || is_power_of_2((intptr_t)alignment), "not a power of 2"); + set_raw_base_and_size(NULL, 0); + alignment = MAX2(alignment, (size_t)os::vm_page_size()); // Assert that if noaccess_prefix is used, it is the same as alignment. @@ -339,7 +369,8 @@ // Check alignment constraints if ((((size_t)base + noaccess_prefix) & (alignment - 1)) != 0) { // Base not aligned, retry - if (!os::release_memory(base, size)) fatal("os::release_memory failed"); + release_memory(base, size); + // Make sure that size is aligned size = align_size_up(size, alignment); base = os::reserve_memory_aligned(size, alignment); @@ -377,6 +408,7 @@ "size not allocation aligned"); _base = base; _size = size; + set_raw_base_and_size(NULL, 0); _alignment = alignment; _noaccess_prefix = 0; _special = special; @@ -432,7 +464,7 @@ if (special()) { os::release_memory_special(real_base, real_size); } else{ - os::release_memory(real_base, real_size); + release_memory(real_base, real_size); } _base = NULL; _size = 0;
--- a/src/share/vm/runtime/virtualspace.hpp Fri May 31 08:00:19 2013 -0700 +++ b/src/share/vm/runtime/virtualspace.hpp Thu May 23 03:08:19 2013 -0700 @@ -35,6 +35,12 @@ char* _base; size_t _size; size_t _noaccess_prefix; + + // The base and size prior to any alignment done by this class; used only on + // systems that cannot release part of a region. + char* _raw_base; + size_t _raw_size; + size_t _alignment; bool _special; bool _executable; @@ -42,11 +48,20 @@ // ReservedSpace ReservedSpace(char* base, size_t size, size_t alignment, bool special, bool executable); + + bool failed_to_reserve_as_requested(char* base, char* requested_address, + const size_t size, bool special); void initialize(size_t size, size_t alignment, bool large, char* requested_address, const size_t noaccess_prefix, bool executable); + inline void set_raw_base_and_size(char * const raw_base, size_t raw_size); + + // Release virtual address space. If alignment was done, use the saved + // address and size when releasing. + void release_memory(char * default_addr, size_t default_size); + // Release parts of an already-reserved memory region [addr, addr + len) to // get a new region that has "compound alignment." Return the start of the // resulting region, or NULL on failure.