src/share/vm/runtime/virtualspace.cpp

Print this page
rev 4525 : 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

*** 79,99 **** return NULL; // Cannot do proper alignment. } const size_t end_delta = len - (beg_delta + required_size); if (beg_delta != 0) { ! os::release_memory(addr, beg_delta); } if (end_delta != 0) { char* release_addr = (char*) (s + beg_delta + required_size); ! os::release_memory(release_addr, end_delta); } return (char*) (s + beg_delta); } char* ReservedSpace::reserve_and_align(const size_t reserve_size, const size_t prefix_size, const size_t prefix_align, const size_t suffix_size, const size_t suffix_align) --- 79,123 ---- return NULL; // Cannot do proper alignment. } const size_t end_delta = len - (beg_delta + required_size); if (beg_delta != 0) { ! os::release_or_uncommit_partial_region(addr, beg_delta); } if (end_delta != 0) { char* release_addr = (char*) (s + beg_delta + required_size); ! 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, const size_t suffix_size, const size_t suffix_align)
*** 108,117 **** --- 132,145 ---- suffix_align); if (result == NULL && !os::release_memory(raw_addr, reserve_size)) { 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); const size_t res = size_t(result); assert(res >= raw, "alignment decreased start addr");
*** 125,136 **** return result; } // Helper method. ! static bool 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 if (base != NULL) { --- 153,166 ---- return result; } // Helper method. ! 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 if (base != NULL) {
*** 145,159 **** if (special) { if (!os::release_memory_special(base, size)) { fatal("os::release_memory_special failed"); } } else { ! if (!os::release_memory(base, size)) { ! fatal("os::release_memory failed"); } } - } return true; } ReservedSpace::ReservedSpace(const size_t prefix_size, const size_t prefix_align, --- 175,187 ---- if (special) { if (!os::release_memory_special(base, size)) { fatal("os::release_memory_special failed"); } } else { ! release_memory(base, size); } } return true; } ReservedSpace::ReservedSpace(const size_t prefix_size, const size_t prefix_align,
*** 175,184 **** --- 203,214 ---- // Assert that if noaccess_prefix is used, it is the same as prefix_align. 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; // On systems where the entire region has to be reserved and committed up
*** 222,234 **** // On most operating systems, another allocation with a somewhat larger size // will return an address "close to" that of the previous allocation. The // 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"); ! } const size_t extra = MAX2(ofs, suffix_align - ofs); addr = reserve_and_align(size + extra, adjusted_prefix_size, prefix_align, suffix_size, suffix_align); if (addr == NULL) { --- 252,262 ---- // On most operating systems, another allocation with a somewhat larger size // will return an address "close to" that of the previous allocation. The // 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. ! release_memory(addr, size); const size_t extra = MAX2(ofs, suffix_align - ofs); addr = reserve_and_align(size + extra, adjusted_prefix_size, prefix_align, suffix_size, suffix_align); if (addr == NULL) {
*** 263,272 **** --- 291,302 ---- assert((alignment & (granularity - 1)) == 0, "alignment not aligned to os::vm_allocation_granularity()"); 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. assert(noaccess_prefix == 0 || noaccess_prefix == alignment, "noaccess prefix wrong");
*** 338,348 **** if (base == NULL) return; // 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"); // Make sure that size is aligned size = align_size_up(size, alignment); base = os::reserve_memory_aligned(size, alignment); if (requested_address != 0 && --- 368,379 ---- if (base == NULL) return; // Check alignment constraints if ((((size_t)base + noaccess_prefix) & (alignment - 1)) != 0) { // Base not aligned, retry ! release_memory(base, size); ! // Make sure that size is aligned size = align_size_up(size, alignment); base = os::reserve_memory_aligned(size, alignment); if (requested_address != 0 &&
*** 376,385 **** --- 407,417 ---- bool special, bool executable) { assert((size % os::vm_allocation_granularity()) == 0, "size not allocation aligned"); _base = base; _size = size; + set_raw_base_and_size(NULL, 0); _alignment = alignment; _noaccess_prefix = 0; _special = special; _executable = executable; }
*** 431,441 **** char *real_base = _base - _noaccess_prefix; const size_t real_size = _size + _noaccess_prefix; if (special()) { os::release_memory_special(real_base, real_size); } else{ ! os::release_memory(real_base, real_size); } _base = NULL; _size = 0; _noaccess_prefix = 0; _special = false; --- 463,473 ---- char *real_base = _base - _noaccess_prefix; const size_t real_size = _size + _noaccess_prefix; if (special()) { os::release_memory_special(real_base, real_size); } else{ ! release_memory(real_base, real_size); } _base = NULL; _size = 0; _noaccess_prefix = 0; _special = false;