< prev index next >

src/share/vm/runtime/virtualspace.cpp

Print this page
rev 7602 : 8064457: Introduce compressed oops mode disjoint base and improve compressed heap handling.

*** 41,65 **** size_t page_size = os::page_size_for_region(size, 1); bool large_pages = page_size != (size_t)os::vm_page_size(); // Don't force the alignment to be large page aligned, // since that will waste memory. size_t alignment = os::vm_allocation_granularity(); ! initialize(size, alignment, large_pages, NULL, 0, false); } ReservedSpace::ReservedSpace(size_t size, size_t alignment, bool large, ! char* requested_address, ! const size_t noaccess_prefix) { ! initialize(size+noaccess_prefix, alignment, large, requested_address, ! noaccess_prefix, false); } ReservedSpace::ReservedSpace(size_t size, size_t alignment, bool large, bool executable) { ! initialize(size, alignment, large, NULL, 0, executable); } // Helper method. static bool failed_to_reserve_as_requested(char* base, char* requested_address, const size_t size, bool special) --- 41,63 ---- size_t page_size = os::page_size_for_region(size, 1); bool large_pages = page_size != (size_t)os::vm_page_size(); // Don't force the alignment to be large page aligned, // since that will waste memory. size_t alignment = os::vm_allocation_granularity(); ! initialize(size, alignment, large_pages, NULL, false); } ReservedSpace::ReservedSpace(size_t size, size_t alignment, bool large, ! char* requested_address) { ! initialize(size, alignment, large, requested_address, false); } ReservedSpace::ReservedSpace(size_t size, size_t alignment, bool large, bool executable) { ! initialize(size, alignment, large, NULL, executable); } // Helper method. static bool failed_to_reserve_as_requested(char* base, char* requested_address, const size_t size, bool special)
*** 89,99 **** return true; } void ReservedSpace::initialize(size_t size, size_t alignment, bool large, char* requested_address, - const size_t noaccess_prefix, bool executable) { const size_t granularity = os::vm_allocation_granularity(); assert((size & (granularity - 1)) == 0, "size not aligned to os::vm_allocation_granularity()"); assert((alignment & (granularity - 1)) == 0, --- 87,96 ----
*** 101,114 **** assert(alignment == 0 || is_power_of_2((intptr_t)alignment), "not a power of 2"); 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"); - _base = NULL; _size = 0; _special = false; _executable = executable; _alignment = 0; --- 98,107 ----
*** 120,134 **** // If OS doesn't support demand paging for large page memory, we need // to use reserve_memory_special() to reserve and pin the entire region. bool special = large && !os::can_commit_large_page_memory(); char* base = NULL; - if (requested_address != 0) { - requested_address -= noaccess_prefix; // adjust requested address - assert(requested_address != NULL, "huge noaccess prefix?"); - } - if (special) { base = os::reserve_memory_special(size, alignment, requested_address, executable); if (base != NULL) { --- 113,122 ----
*** 174,184 **** } 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); --- 162,172 ---- } if (base == NULL) return; // Check alignment constraints ! if ((((size_t)base) & (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);
*** 195,214 **** } // Done _base = base; _size = size; _alignment = alignment; - _noaccess_prefix = noaccess_prefix; - - // Assert that if noaccess_prefix is used, it is the same as alignment. - assert(noaccess_prefix == 0 || - noaccess_prefix == _alignment, "noaccess prefix wrong"); - - assert(markOopDesc::encode_pointer_as_mark(_base)->decode_pointer() == _base, - "area must be distinguishable from marks for mark-sweep"); - assert(markOopDesc::encode_pointer_as_mark(&_base[size])->decode_pointer() == &_base[size], - "area must be distinguishable from marks for mark-sweep"); } ReservedSpace::ReservedSpace(char* base, size_t size, size_t alignment, bool special, bool executable) { --- 183,192 ----
*** 274,331 **** os::release_memory(real_base, real_size); } _base = NULL; _size = 0; _noaccess_prefix = 0; _special = false; _executable = false; } } ! void ReservedSpace::protect_noaccess_prefix(const size_t size) { ! assert( (_noaccess_prefix != 0) == (UseCompressedOops && _base != NULL && ! (Universe::narrow_oop_base() != NULL) && ! Universe::narrow_oop_use_implicit_null_checks()), ! "noaccess_prefix should be used only with non zero based compressed oops"); ! ! // If there is no noaccess prefix, return. ! if (_noaccess_prefix == 0) return; ! ! assert(_noaccess_prefix >= (size_t)os::vm_page_size(), ! "must be at least page size big"); // Protect memory at the base of the allocated region. // If special, the page was committed (only matters on windows) ! if (!os::protect_memory(_base, _noaccess_prefix, os::MEM_PROT_NONE, ! _special)) { fatal("cannot protect protection page"); } if (PrintCompressedOopsMode) { tty->cr(); ! tty->print_cr("Protected page at the reserved heap base: " PTR_FORMAT " / " INTX_FORMAT " bytes", _base, _noaccess_prefix); } _base += _noaccess_prefix; _size -= _noaccess_prefix; ! assert((size == _size) && ((uintptr_t)_base % _alignment == 0), ! "must be exactly of required size and alignment"); } ! ReservedHeapSpace::ReservedHeapSpace(size_t size, size_t alignment, ! bool large, char* requested_address) : ! ReservedSpace(size, alignment, large, ! requested_address, ! (UseCompressedOops && (Universe::narrow_oop_base() != NULL) && ! Universe::narrow_oop_use_implicit_null_checks()) ? ! lcm(os::vm_page_size(), alignment) : 0) { if (base() > 0) { MemTracker::record_virtual_memory_type((address)base(), mtJavaHeap); } - - // Only reserved space for the java heap should have a noaccess_prefix - // if using compressed oops. - protect_noaccess_prefix(size); } // Reserve space for code segment. Same as Java heap only we mark this as // executable. ReservedCodeSpace::ReservedCodeSpace(size_t r_size, --- 252,591 ---- os::release_memory(real_base, real_size); } _base = NULL; _size = 0; _noaccess_prefix = 0; + _alignment = 0; _special = false; _executable = false; } } ! static size_t noaccess_prefix_size(size_t alignment) { ! return lcm(os::vm_page_size(), alignment); ! } + void ReservedHeapSpace::establish_noaccess_prefix() { + assert(_alignment >= (size_t)os::vm_page_size(), "must be at least page size big"); + _noaccess_prefix = noaccess_prefix_size(_alignment); + + if (base() && base() + _size > (char *)OopEncodingHeapMax) { + if (true + WIN64_ONLY(&& !UseLargePages) + AIX_ONLY(&& os::vm_page_size() != SIZE_64K)) { // Protect memory at the base of the allocated region. // If special, the page was committed (only matters on windows) ! if (!os::protect_memory(_base, _noaccess_prefix, os::MEM_PROT_NONE, _special)) { fatal("cannot protect protection page"); } if (PrintCompressedOopsMode) { tty->cr(); ! tty->print_cr("Protected page at the reserved heap base: " ! PTR_FORMAT " / " INTX_FORMAT " bytes", _base, _noaccess_prefix); ! } ! assert(Universe::narrow_oop_use_implicit_null_checks() == true, "not initialized?"); ! } else { ! Universe::set_narrow_oop_use_implicit_null_checks(false); ! } } _base += _noaccess_prefix; _size -= _noaccess_prefix; ! assert(((uintptr_t)_base % _alignment == 0), "must be exactly of required alignment"); } ! // Tries to allocate memory of size 'size' at address requested_address with alignment 'alignment'. ! // Does not check whether the reserved memory actually is at requested_address, as the memory returned ! // might still fulfill the wishes of the caller. ! // Assures the memory is aligned to 'alignment'. ! // NOTE: If ReservedHeapSpace already points to some reserved memory this is freed, first. ! void ReservedHeapSpace::try_reserve_heap(size_t size, ! size_t alignment, ! bool large, ! char* requested_address) { ! if (_base != NULL) { ! // We tried before, but we didn't like the address delivered. ! release(); ! } ! ! // If OS doesn't support demand paging for large page memory, we need ! // to use reserve_memory_special() to reserve and pin the entire region. ! bool special = large && !os::can_commit_large_page_memory(); ! char* base = NULL; ! ! if (PrintCompressedOopsMode && Verbose) { ! tty->print("Trying to allocate at address " PTR_FORMAT " heap of size " PTR_FORMAT ".\n", ! requested_address, (address)size); ! } ! ! if (special) { ! base = os::reserve_memory_special(size, alignment, requested_address, false); ! ! if (base != NULL) { ! // Check alignment constraints. ! assert((uintptr_t) base % alignment == 0, ! err_msg("Large pages returned a non-aligned address, base: " ! PTR_FORMAT " alignment: " PTR_FORMAT, ! base, (void*)(uintptr_t)alignment)); ! _special = true; ! } ! } ! ! if (base == NULL) { ! // Failed; try to reserve regular memory below ! if (UseLargePages && (!FLAG_IS_DEFAULT(UseLargePages) || ! !FLAG_IS_DEFAULT(LargePageSizeInBytes))) { ! if (PrintCompressedOopsMode) { ! tty->cr(); ! tty->print_cr("Reserve regular memory without large pages."); ! } ! } ! ! // Optimistically assume that the OSes returns an aligned base pointer. ! // When reserving a large address range, most OSes seem to align to at ! // least 64K. ! ! // If the memory was requested at a particular address, use ! // os::attempt_reserve_memory_at() to avoid over mapping something ! // important. If available space is not detected, return NULL. ! ! if (requested_address != 0) { ! base = os::attempt_reserve_memory_at(size, requested_address); ! } else { ! base = os::reserve_memory(size, NULL, alignment); ! } ! } ! if (base == NULL) { return; } ! ! // Done ! _base = base; ! _size = size; ! _alignment = alignment; ! ! // Check alignment constraints ! if ((((size_t)base) & (alignment - 1)) != 0) { ! // Base not aligned, retry. ! release(); ! } ! } ! ! void ReservedHeapSpace::try_reserve_range(char *highest_start, ! char *lowest_start, ! size_t attach_point_alignment, ! char *aligned_heap_base_min_address, ! char *upper_bound, ! size_t size, ! size_t alignment, ! bool large) { ! const size_t attach_range = highest_start - lowest_start; ! // Cap num_attempts at possible number. ! // At least one is possible even for 0 sized attach range. ! const uint64_t num_attempts_possible = (attach_range / attach_point_alignment) + 1; ! const uint64_t num_attempts_to_try = MIN2((uint64_t)HeapSearchSteps, num_attempts_possible); ! ! const size_t stepsize = (attach_range == 0) ? // Only one try. ! (size_t) highest_start : align_size_up(attach_range / num_attempts_to_try, attach_point_alignment); ! ! // Try attach points from top to bottom. ! char* attach_point = highest_start; ! while (attach_point >= lowest_start && ! attach_point <= highest_start && // Avoid wrap around. ! ((_base == NULL) || ! (_base < aligned_heap_base_min_address || _base + size > upper_bound))) { ! try_reserve_heap(size, alignment, large, attach_point); ! attach_point -= stepsize; ! } ! } ! ! #define SIZE_64K ((uint64_t) UCONST64( 0x10000)) ! #define SIZE_256M ((uint64_t) UCONST64( 0x10000000)) ! #define SIZE_32G ((uint64_t) UCONST64( 0x800000000)) ! ! // Helper for heap allocation. Returns an array with addresses ! // (OS-specific) which are suited for disjoint base mode. Array is ! // NULL terminated. ! static char** get_attach_addresses_for_disjoint_mode() { ! static uint64_t addresses[] = { ! 2 * SIZE_32G, ! 3 * SIZE_32G, ! 4 * SIZE_32G, ! 8 * SIZE_32G, ! 10 * SIZE_32G, ! 1 * SIZE_64K * SIZE_32G, ! 2 * SIZE_64K * SIZE_32G, ! 3 * SIZE_64K * SIZE_32G, ! 4 * SIZE_64K * SIZE_32G, ! 16 * SIZE_64K * SIZE_32G, ! 32 * SIZE_64K * SIZE_32G, ! 34 * SIZE_64K * SIZE_32G, ! 0 ! }; ! ! // Sort out addresses smaller than HeapBaseMinAddress. This assumes ! // the array is sorted. ! uint i = 0; ! while (addresses[i] != 0 && ! (addresses[i] < OopEncodingHeapMax || addresses[i] < HeapBaseMinAddress)) { ! i++; ! } ! uint start = i; ! ! // Avoid more steps than requested. ! i = 0; ! while (addresses[start+i] != 0) { ! if (i == HeapSearchSteps) { ! addresses[start+i] = 0; ! break; ! } ! i++; ! } ! ! return (char**) &addresses[start]; ! } ! ! void ReservedHeapSpace::initialize_compressed_heap(const size_t size, size_t alignment, bool large) { ! guarantee(size + noaccess_prefix_size(alignment) <= OopEncodingHeapMax, ! "can not allocate compressed oop heap for this size"); ! guarantee(alignment == MAX2(alignment, (size_t)os::vm_page_size()), "alignment too small"); ! assert(HeapBaseMinAddress > 0, "sanity"); ! ! const size_t granularity = os::vm_allocation_granularity(); ! assert((size & (granularity - 1)) == 0, ! "size not aligned to os::vm_allocation_granularity()"); ! 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"); ! ! // The necessary attach point alignment for generated wish addresses. ! // This is needed to increase the chance of attaching for mmap and shmat. ! const size_t os_attach_point_alignment = ! AIX_ONLY(SIZE_256M) // Known shm boundary alignment. ! NOT_AIX(os::vm_allocation_granularity()); ! const size_t attach_point_alignment = lcm(alignment, os_attach_point_alignment); ! ! char *aligned_heap_base_min_address = (char *)align_ptr_up((void *)HeapBaseMinAddress, alignment); ! size_t noaccess_prefix = ((aligned_heap_base_min_address + size) > (char*)OopEncodingHeapMax) ? ! noaccess_prefix_size(alignment) : 0; ! ! // Attempt to alloc at user-given address. ! if (!FLAG_IS_DEFAULT(HeapBaseMinAddress)) { ! try_reserve_heap(size + noaccess_prefix, alignment, large, aligned_heap_base_min_address); ! if (_base != aligned_heap_base_min_address) { // Enforce this exact address. ! release(); ! } ! } ! ! // Keep heap at HeapBaseMinAddress. ! if (_base == NULL) { ! ! // Try to allocate the heap at addresses that allow efficient oop compression. ! // Different schemes are tried, in order of decreasing optimization potential. ! // ! // For this, try_reserve_heap() is called with the desired heap base addresses. ! // A call into the os layer to allocate at a given address can return memory ! // at a different address than requested. Still, this might be memory at a useful ! // address. try_reserve_heap() always returns this allocated memory, as only here ! // the criteria for a good heap are checked. ! ! // Attempt to allocate so that we can run without base and scale (32-Bit unscaled compressed oops). ! // Give it several tries from top of range to bottom. ! if (aligned_heap_base_min_address + size <= (char *)UnscaledOopHeapMax) { ! ! // Calc address range within we try to attach (range of possible start addresses). ! char* const highest_start = (char *)align_ptr_down((char *)UnscaledOopHeapMax - size, attach_point_alignment); ! char* const lowest_start = (char *)align_ptr_up ( aligned_heap_base_min_address , attach_point_alignment); ! try_reserve_range(highest_start, lowest_start, attach_point_alignment, ! aligned_heap_base_min_address, (char *)UnscaledOopHeapMax, size, alignment, large); ! } ! ! // zerobased: Attempt to allocate in the lower 32G. ! // But leave room for the compressed class pointers, which is allocated above ! // the heap. ! char *zerobased_max = (char *)OopEncodingHeapMax; ! // For small heaps, save some space for compressed class pointer ! // space so it can be decoded with no base. ! if (UseCompressedClassPointers && !UseSharedSpaces && ! OopEncodingHeapMax <= KlassEncodingMetaspaceMax) { ! const size_t class_space = align_size_up(CompressedClassSpaceSize, alignment); ! zerobased_max = (char *)OopEncodingHeapMax - class_space; ! } ! ! // Give it several tries from top of range to bottom. ! if (aligned_heap_base_min_address + size <= zerobased_max && // Zerobased theoretical possible. ! ((_base == NULL) || // No previous try succeeded. ! (_base + size > zerobased_max))) { // Unscaled delivered an arbitrary address. ! ! // Calc address range within we try to attach (range of possible start addresses). ! char *const highest_start = (char *)align_ptr_down(zerobased_max - size, attach_point_alignment); ! // SS10 and SS12u1 cannot compile "(char *)UnscaledOopHeapMax - size" on solaris sparc 32-bit: ! // "Cannot use int to initialize char*." Introduce aux variable. ! char *unscaled_end = (char *)UnscaledOopHeapMax; ! unscaled_end -= size; ! char *lowest_start = (size < UnscaledOopHeapMax) ? ! MAX2(unscaled_end, aligned_heap_base_min_address) : aligned_heap_base_min_address; ! lowest_start = (char *)align_ptr_up(lowest_start, attach_point_alignment); ! try_reserve_range(highest_start, lowest_start, attach_point_alignment, ! aligned_heap_base_min_address, zerobased_max, size, alignment, large); ! } ! ! // Now we go for heaps with base != 0. We need a noaccess prefix to efficiently ! // implement null checks. ! noaccess_prefix = noaccess_prefix_size(alignment); ! ! // Try to attach at addresses that are aligned to OopEncodingHeapMax. Disjointbase mode. ! char** addresses = get_attach_addresses_for_disjoint_mode(); ! int i = 0; ! while (addresses[i] && // End of array not yet reached. ! ((_base == NULL) || // No previous try succeeded. ! (_base + size > (char *)OopEncodingHeapMax && // Not zerobased or unscaled address. ! !Universe::is_disjoint_heap_base_address((address)_base)))) { // Not disjoint address. ! char* const attach_point = addresses[i]; ! assert(attach_point >= aligned_heap_base_min_address, "Flag support broken"); ! try_reserve_heap(size + noaccess_prefix, alignment, large, attach_point); ! i++; ! } ! ! // Last, desperate try without any placement. ! if (_base == NULL) { ! if (PrintCompressedOopsMode && Verbose) { ! tty->print("Trying to allocate at address NULL heap of size " PTR_FORMAT ".\n", (address)size + noaccess_prefix); ! } ! initialize(size + noaccess_prefix, alignment, large, NULL, false); ! } ! } ! } ! ! ReservedHeapSpace::ReservedHeapSpace(size_t size, size_t alignment, bool large) : ReservedSpace() { ! ! if (size == 0) { ! return; ! } ! ! // Heap size should be aligned to alignment, too. ! guarantee(is_size_aligned(size, alignment), "set by caller"); ! ! if (UseCompressedOops) { ! initialize_compressed_heap(size, alignment, large); ! if (_size > size) { ! // We allocated heap with noaccess prefix. ! // It can happen we get a zerobased/unscaled heap with noaccess prefix, ! // if we had to try at arbitrary address. ! establish_noaccess_prefix(); ! } ! } else { ! initialize(size, alignment, large, NULL, false); ! } ! ! assert(markOopDesc::encode_pointer_as_mark(_base)->decode_pointer() == _base, ! "area must be distinguishable from marks for mark-sweep"); ! assert(markOopDesc::encode_pointer_as_mark(&_base[size])->decode_pointer() == &_base[size], ! "area must be distinguishable from marks for mark-sweep"); ! if (base() > 0) { MemTracker::record_virtual_memory_type((address)base(), mtJavaHeap); } } // Reserve space for code segment. Same as Java heap only we mark this as // executable. ReservedCodeSpace::ReservedCodeSpace(size_t r_size,
*** 801,812 **** assert(is_size_aligned(size, alignment), "Incorrect input parameters"); ReservedSpace rs(size, // size alignment, // alignment UseLargePages, // large ! NULL, // requested_address ! 0); // noacces_prefix test_log(" rs.special() == %d", rs.special()); assert(rs.base() != NULL, "Must be"); assert(rs.size() == size, "Must be"); --- 1061,1071 ---- assert(is_size_aligned(size, alignment), "Incorrect input parameters"); ReservedSpace rs(size, // size alignment, // alignment UseLargePages, // large ! (char *)NULL); // requested_address test_log(" rs.special() == %d", rs.special()); assert(rs.base() != NULL, "Must be"); assert(rs.size() == size, "Must be");
< prev index next >