< prev index next >

src/share/vm/memory/universe.cpp

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

*** 689,795 **** // NarrowOopHeapBaseMin + heap_size < 4Gb // ZeroBased - Use zero based compressed oops with encoding when // NarrowOopHeapBaseMin + heap_size < 32Gb // HeapBased - Use compressed oops with heap base + encoding. - // 4Gb - static const uint64_t UnscaledOopHeapMax = (uint64_t(max_juint) + 1); - // 32Gb - // OopEncodingHeapMax == UnscaledOopHeapMax << LogMinObjAlignmentInBytes; - - char* Universe::preferred_heap_base(size_t heap_size, size_t alignment, NARROW_OOP_MODE mode) { - assert(is_size_aligned((size_t)OopEncodingHeapMax, alignment), "Must be"); - assert(is_size_aligned((size_t)UnscaledOopHeapMax, alignment), "Must be"); - assert(is_size_aligned(heap_size, alignment), "Must be"); - - uintx heap_base_min_address_aligned = align_size_up(HeapBaseMinAddress, alignment); - - size_t base = 0; - #ifdef _LP64 - if (UseCompressedOops) { - assert(mode == UnscaledNarrowOop || - mode == ZeroBasedNarrowOop || - mode == HeapBasedNarrowOop, "mode is invalid"); - const size_t total_size = heap_size + heap_base_min_address_aligned; - // Return specified base for the first request. - if (!FLAG_IS_DEFAULT(HeapBaseMinAddress) && (mode == UnscaledNarrowOop)) { - base = heap_base_min_address_aligned; - - // If the total size is small enough to allow UnscaledNarrowOop then - // just use UnscaledNarrowOop. - } else if ((total_size <= OopEncodingHeapMax) && (mode != HeapBasedNarrowOop)) { - if ((total_size <= UnscaledOopHeapMax) && (mode == UnscaledNarrowOop) && - (Universe::narrow_oop_shift() == 0)) { - // Use 32-bits oops without encoding and - // place heap's top on the 4Gb boundary - base = (UnscaledOopHeapMax - heap_size); - } else { - // Can't reserve with NarrowOopShift == 0 - Universe::set_narrow_oop_shift(LogMinObjAlignmentInBytes); - - if (mode == UnscaledNarrowOop || - mode == ZeroBasedNarrowOop && total_size <= UnscaledOopHeapMax) { - - // Use zero based compressed oops with encoding and - // place heap's top on the 32Gb boundary in case - // total_size > 4Gb or failed to reserve below 4Gb. - uint64_t heap_top = OopEncodingHeapMax; - - // For small heaps, save some space for compressed class pointer - // space so it can be decoded with no base. - if (UseCompressedClassPointers && !UseSharedSpaces && - OopEncodingHeapMax <= 32*G) { - - uint64_t class_space = align_size_up(CompressedClassSpaceSize, alignment); - assert(is_size_aligned((size_t)OopEncodingHeapMax-class_space, - alignment), "difference must be aligned too"); - uint64_t new_top = OopEncodingHeapMax-class_space; - - if (total_size <= new_top) { - heap_top = new_top; - } - } - - // Align base to the adjusted top of the heap - base = heap_top - heap_size; - } - } - } else { - // UnscaledNarrowOop encoding didn't work, and no base was found for ZeroBasedOops or - // HeapBasedNarrowOop encoding was requested. So, can't reserve below 32Gb. - Universe::set_narrow_oop_shift(LogMinObjAlignmentInBytes); - } - - // Set narrow_oop_base and narrow_oop_use_implicit_null_checks - // used in ReservedHeapSpace() constructors. - // The final values will be set in initialize_heap() below. - if ((base != 0) && ((base + heap_size) <= OopEncodingHeapMax)) { - // Use zero based compressed oops - Universe::set_narrow_oop_base(NULL); - // Don't need guard page for implicit checks in indexed - // addressing mode with zero based Compressed Oops. - Universe::set_narrow_oop_use_implicit_null_checks(true); - } else { - // Set to a non-NULL value so the ReservedSpace ctor computes - // the correct no-access prefix. - // The final value will be set in initialize_heap() below. - Universe::set_narrow_oop_base((address)UnscaledOopHeapMax); - #if defined(_WIN64) || defined(AIX) - if (UseLargePages) { - // Cannot allocate guard pages for implicit checks in indexed - // addressing mode when large pages are specified on windows. - Universe::set_narrow_oop_use_implicit_null_checks(false); - } - #endif // _WIN64 - } - } - #endif - - assert(is_ptr_aligned((char*)base, alignment), "Must be"); - return (char*)base; // also return NULL (don't care) for 32-bit VM - } - jint Universe::initialize_heap() { if (UseParallelGC) { #if INCLUDE_ALL_GCS Universe::_collectedHeap = new ParallelScavengeHeap(); --- 689,698 ----
*** 839,872 **** // This also makes implicit null checking work, because the // memory+1 page below heap_base needs to cause a signal. // See needs_explicit_null_check. // Only set the heap base for compressed oops because it indicates // compressed oops for pstack code. ! if (((uint64_t)Universe::heap()->reserved_region().end() > OopEncodingHeapMax)) { ! // Can't reserve heap below 32Gb. ! // keep the Universe::narrow_oop_base() set in Universe::reserve_heap() ! Universe::set_narrow_oop_shift(LogMinObjAlignmentInBytes); ! #ifdef AIX ! // There is no protected page before the heap. This assures all oops ! // are decoded so that NULL is preserved, so this page will not be accessed. ! Universe::set_narrow_oop_use_implicit_null_checks(false); ! #endif ! } else { ! Universe::set_narrow_oop_base(0); ! #ifdef _WIN64 ! if (!Universe::narrow_oop_use_implicit_null_checks()) { ! // Don't need guard page for implicit checks in indexed addressing ! // mode with zero based Compressed Oops. ! Universe::set_narrow_oop_use_implicit_null_checks(true); ! } ! #endif // _WIN64 ! if((uint64_t)Universe::heap()->reserved_region().end() > UnscaledOopHeapMax) { ! // Can't reserve heap below 4Gb. Universe::set_narrow_oop_shift(LogMinObjAlignmentInBytes); - } else { - Universe::set_narrow_oop_shift(0); } } Universe::set_narrow_ptrs_base(Universe::narrow_oop_base()); if (PrintCompressedOopsMode || (PrintMiscellaneous && Verbose)) { --- 742,758 ---- // This also makes implicit null checking work, because the // memory+1 page below heap_base needs to cause a signal. // See needs_explicit_null_check. // Only set the heap base for compressed oops because it indicates // compressed oops for pstack code. ! if ((uint64_t)Universe::heap()->reserved_region().end() > UnscaledOopHeapMax) { ! // Didn't reserve heap below 4Gb. Must shift. Universe::set_narrow_oop_shift(LogMinObjAlignmentInBytes); } + if ((uint64_t)Universe::heap()->reserved_region().end() <= OopEncodingHeapMax) { + // Did reserve heap below 32Gb. Can use base == 0; + Universe::set_narrow_oop_base(0); } Universe::set_narrow_ptrs_base(Universe::narrow_oop_base()); if (PrintCompressedOopsMode || (PrintMiscellaneous && Verbose)) {
*** 898,972 **** Universe::heap()->base(), Universe::heap()->reserved_region().byte_size()/M); tty->print(", Compressed Oops mode: %s", narrow_oop_mode_to_string(narrow_oop_mode())); if (Universe::narrow_oop_base() != 0) { ! tty->print(":" PTR_FORMAT, Universe::narrow_oop_base()); } if (Universe::narrow_oop_shift() != 0) { tty->print(", Oop shift amount: %d", Universe::narrow_oop_shift()); } tty->cr(); tty->cr(); } ! // Reserve the Java heap, which is now the same for all GCs. ReservedSpace Universe::reserve_heap(size_t heap_size, size_t alignment) { assert(alignment <= Arguments::conservative_max_heap_alignment(), err_msg("actual alignment "SIZE_FORMAT" must be within maximum heap alignment "SIZE_FORMAT, alignment, Arguments::conservative_max_heap_alignment())); size_t total_reserved = align_size_up(heap_size, alignment); assert(!UseCompressedOops || (total_reserved <= (OopEncodingHeapMax - os::vm_page_size())), "heap size is too big for compressed oops"); bool use_large_pages = UseLargePages && is_size_aligned(alignment, os::large_page_size()); assert(!UseLargePages || UseParallelGC || use_large_pages, "Wrong alignment to use large pages"); ! char* addr = Universe::preferred_heap_base(total_reserved, alignment, Universe::UnscaledNarrowOop); ! ! ReservedHeapSpace total_rs(total_reserved, alignment, use_large_pages, addr); if (UseCompressedOops) { ! if (addr != NULL && !total_rs.is_reserved()) { ! // Failed to reserve at specified address - the requested memory ! // region is taken already, for example, by 'java' launcher. ! // Try again to reserver heap higher. ! addr = Universe::preferred_heap_base(total_reserved, alignment, Universe::ZeroBasedNarrowOop); ! ! ReservedHeapSpace total_rs0(total_reserved, alignment, ! use_large_pages, addr); ! ! if (addr != NULL && !total_rs0.is_reserved()) { ! // Failed to reserve at specified address again - give up. ! addr = Universe::preferred_heap_base(total_reserved, alignment, Universe::HeapBasedNarrowOop); ! assert(addr == NULL, ""); ! ReservedHeapSpace total_rs1(total_reserved, alignment, ! use_large_pages, addr); ! total_rs = total_rs1; ! } else { ! total_rs = total_rs0; } } } ! if (!total_rs.is_reserved()) { ! vm_exit_during_initialization(err_msg("Could not reserve enough space for " SIZE_FORMAT "KB object heap", total_reserved/K)); ! return total_rs; } if (UseCompressedOops) { // Universe::initialize_heap() will reset this to NULL if unscaled // or zero-based narrow oops are actually used. ! address base = (address)(total_rs.base() - os::vm_page_size()); Universe::set_narrow_oop_base(base); } return total_rs; } // It's the caller's responsibility to ensure glitch-freedom // (if required). --- 784,991 ---- Universe::heap()->base(), Universe::heap()->reserved_region().byte_size()/M); tty->print(", Compressed Oops mode: %s", narrow_oop_mode_to_string(narrow_oop_mode())); if (Universe::narrow_oop_base() != 0) { ! tty->print(": " PTR_FORMAT, Universe::narrow_oop_base()); } if (Universe::narrow_oop_shift() != 0) { tty->print(", Oop shift amount: %d", Universe::narrow_oop_shift()); } + if (!Universe::narrow_oop_use_implicit_null_checks()) { + tty->print(", no protected page in front of the heap"); + } + tty->cr(); tty->cr(); } ! #define SIZE_64K ((uint64_t) 0x10000ULL) ! #define SIZE_256M ((uint64_t) 0x10000000ULL) ! #define SIZE_32G ((uint64_t) 0x800000000ULL) ! ! // 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 uintptr_t addresses[] = { ! #ifdef _LP64 ! 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, ! #endif ! 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]; ! } ! ReservedSpace Universe::reserve_heap(size_t heap_size, size_t alignment) { + assert(alignment <= Arguments::conservative_max_heap_alignment(), err_msg("actual alignment "SIZE_FORMAT" must be within maximum heap alignment "SIZE_FORMAT, alignment, Arguments::conservative_max_heap_alignment())); + size_t total_reserved = align_size_up(heap_size, alignment); assert(!UseCompressedOops || (total_reserved <= (OopEncodingHeapMax - os::vm_page_size())), "heap size is too big for compressed oops"); bool use_large_pages = UseLargePages && is_size_aligned(alignment, os::large_page_size()); assert(!UseLargePages || UseParallelGC || use_large_pages, "Wrong alignment to use large pages"); ! // Address where to allocate the heap. NULL: anywhere. ! char* addr = NULL; ! size_t disjoint_noaccess_prefix = 0; if (UseCompressedOops) { ! // Try to get a heap by: ! // 0) if HeapBaseMinAddress is set, try this address first. ! // 1) get heap for unscaled (base = 0, shift = 0) ! // 2) failing that, get heap for zerobased (base = 0, shift != 0) ! // 3) failing that, get heap for disjointbase (base != 0, shift != 0) ! // 4) failing that, any heap will do. ! ! // Loop over compressed oop modes; try to obtain a fitting memory range; ! // if success, release it again and let ReservedHeapSpace attempt to ! // allocate in the same range. ! for (int i = 0; i <= 4; i++) { ! disjoint_noaccess_prefix = 0; ! switch (i) { ! case 0: ! // Attempt to alloc at user-given address. ! if (!FLAG_IS_DEFAULT(HeapBaseMinAddress)) { ! addr = os::attempt_reserve_memory_at(total_reserved, (char *)HeapBaseMinAddress); ! if (is_disjoint_heap_base_address((address)addr)) { ! disjoint_noaccess_prefix = ReservedHeapSpace::noaccess_prefix_size(alignment); ! } ! } ! break; ! case 1: ! // Attempt to alloc for unscaled. ! addr = os::attempt_reserve_memory_in_range(total_reserved, alignment, ! (char*) HeapBaseMinAddress, ! (char*) UnscaledOopHeapMax, ! HeapSearchSteps); ! break; ! case 2: ! { ! // zerobased: Attempt to allocate in the lower 32G. ! // But leave room for the compressed class pointers. ! 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 <= 32*G) { ! uint64_t class_space = align_size_up(CompressedClassSpaceSize, alignment); ! assert(is_size_aligned((size_t)OopEncodingHeapMax-class_space, ! alignment), "difference must be aligned too"); ! zerobased_max = (char*) OopEncodingHeapMax - class_space; } + + addr = os::attempt_reserve_memory_in_range(total_reserved, alignment, + (char*) MAX2((char*)UnscaledOopHeapMax, (char*)HeapBaseMinAddress), + (char*) zerobased_max, + HeapSearchSteps); + } + break; + case 3: + // disjointbase. Here we just try a bushel of OS-dependend known + // disjoint-based friendly addresses. + { + char** addresses = get_attach_addresses_for_disjoint_mode(); + addr = os::attempt_reserve_memory_at_multiple(total_reserved, addresses); + disjoint_noaccess_prefix = ReservedHeapSpace::noaccess_prefix_size(alignment); + } + break; + case 4: + addr = 0; + break; + default: + ShouldNotReachHere(); } + + // If we could not find space for the current mode, try the next mode. + if (!addr && i < 4) { + continue; } ! // If we did find space, release space; ReservedHeapSpace will allocate ! // again. ! if (addr) { ! os::release_memory(addr, total_reserved); ! break; // Quit the for loop. ! } ! ! } // for loop ! } ! ! // now create the space ! ReservedHeapSpace total_rs(total_reserved, alignment, ! use_large_pages, addr + disjoint_noaccess_prefix); ! ! if (addr != NULL && !total_rs.is_reserved()) { ! // Try arbitrary position. ! ReservedHeapSpace total_rs1(total_reserved, alignment, use_large_pages, NULL); ! disjoint_noaccess_prefix = 0; ! total_rs = total_rs1; } + if (total_rs.is_reserved()) { + // we are good. + if (UseCompressedOops) { // Universe::initialize_heap() will reset this to NULL if unscaled // or zero-based narrow oops are actually used. ! // SAPJVM GL 2014-09-22 ! // Else heap start and base MUST differ, so that NULL can be encoded nonambigous. ! address base = (address)(total_rs.base() - ReservedHeapSpace::noaccess_prefix_size(alignment)); Universe::set_narrow_oop_base(base); } + return total_rs; + } + + vm_exit_during_initialization( + err_msg("Could not reserve enough space for " SIZE_FORMAT "KB object heap", + total_reserved/K)); + + // satisfy compiler + ShouldNotReachHere(); + return ReservedHeapSpace(0, 0, false, 0); } // It's the caller's responsibility to ensure glitch-freedom // (if required).
*** 980,999 **** --- 999,1024 ---- switch (mode) { case UnscaledNarrowOop: return "32-bit"; case ZeroBasedNarrowOop: return "Zero based"; + case DisjointBaseNarrowOop: + return "Non-zero disjoint base"; case HeapBasedNarrowOop: return "Non-zero based"; } ShouldNotReachHere(); return ""; } Universe::NARROW_OOP_MODE Universe::narrow_oop_mode() { + if (narrow_oop_base_disjoint()) { + return DisjointBaseNarrowOop; + } + if (narrow_oop_base() != 0) { return HeapBasedNarrowOop; } if (narrow_oop_shift() != 0) {
< prev index next >