# HG changeset patch # User johnc # Date 1312312393 25200 # Node ID 6aa4feb8a36605d58c8cd66e6fd4da1396446753 # Parent 14a2fd14c0db10ac77a33e1940e4e59e72bbdece 7069863: G1: SIGSEGV running SPECjbb2011 and -UseBiasedLocking Summary: Align the reserved size of the heap and perm to the heap region size to get a preferred heap base that is aligned to the region size, and call the correct heap reservation constructor. Also add a check in the heap reservation code that the reserved space starts at the requested address (if any). Reviewed-by: kvn, ysr diff -r 14a2fd14c0db -r 6aa4feb8a366 src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp --- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Mon Aug 01 10:04:28 2011 -0700 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Tue Aug 02 12:13:13 2011 -0700 @@ -1901,12 +1901,27 @@ PermanentGenerationSpec* pgs = collector_policy()->permanent_generation(); // Includes the perm-gen. - const size_t total_reserved = max_byte_size + pgs->max_size(); + // When compressed oops are enabled, the preferred heap base + // is calculated by subtracting the requested size from the + // 32Gb boundary and using the result as the base address for + // heap reservation. If the requested size is not aligned to + // HeapRegion::GrainBytes (i.e. the alignment that is passed + // into the ReservedHeapSpace constructor) then the actual + // base of the reserved heap may end up differing from the + // address that was requested (i.e. the preferred heap base). + // If this happens then we could end up using a non-optimal + // compressed oops mode. + + // Since max_byte_size is aligned to the size of a heap region (checked + // above), we also need to align the perm gen size as it might not be. + const size_t total_reserved = max_byte_size + + align_size_up(pgs->max_size(), HeapRegion::GrainBytes); + Universe::check_alignment(total_reserved, HeapRegion::GrainBytes, "g1 heap and perm"); + char* addr = Universe::preferred_heap_base(total_reserved, Universe::UnscaledNarrowOop); - ReservedSpace heap_rs(max_byte_size + pgs->max_size(), - HeapRegion::GrainBytes, - UseLargePages, addr); + ReservedHeapSpace heap_rs(total_reserved, HeapRegion::GrainBytes, + UseLargePages, addr); if (UseCompressedOops) { if (addr != NULL && !heap_rs.is_reserved()) { @@ -1914,14 +1929,17 @@ // region is taken already, for example, by 'java' launcher. // Try again to reserver heap higher. addr = Universe::preferred_heap_base(total_reserved, Universe::ZeroBasedNarrowOop); - ReservedSpace heap_rs0(total_reserved, HeapRegion::GrainBytes, - UseLargePages, addr); + + ReservedHeapSpace heap_rs0(total_reserved, HeapRegion::GrainBytes, + UseLargePages, addr); + if (addr != NULL && !heap_rs0.is_reserved()) { // Failed to reserve at specified address again - give up. addr = Universe::preferred_heap_base(total_reserved, Universe::HeapBasedNarrowOop); assert(addr == NULL, ""); - ReservedSpace heap_rs1(total_reserved, HeapRegion::GrainBytes, - UseLargePages, addr); + + ReservedHeapSpace heap_rs1(total_reserved, HeapRegion::GrainBytes, + UseLargePages, addr); heap_rs = heap_rs1; } else { heap_rs = heap_rs0; diff -r 14a2fd14c0db -r 6aa4feb8a366 src/share/vm/runtime/virtualspace.cpp --- a/src/share/vm/runtime/virtualspace.cpp Mon Aug 01 10:04:28 2011 -0700 +++ b/src/share/vm/runtime/virtualspace.cpp Tue Aug 02 12:13:13 2011 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -68,7 +68,7 @@ assert(len >= required_size, "len too small"); const size_t s = size_t(addr); - const size_t beg_ofs = s + prefix_size & suffix_align - 1; + const size_t beg_ofs = (s + prefix_size) & (suffix_align - 1); const size_t beg_delta = beg_ofs == 0 ? 0 : suffix_align - beg_ofs; if (len < beg_delta + required_size) { @@ -113,8 +113,8 @@ assert(res >= raw, "alignment decreased start addr"); assert(res + prefix_size + suffix_size <= raw + reserve_size, "alignment increased end addr"); - assert((res & prefix_align - 1) == 0, "bad alignment of prefix"); - assert((res + prefix_size & suffix_align - 1) == 0, + assert((res & (prefix_align - 1)) == 0, "bad alignment of prefix"); + assert(((res + prefix_size) & (suffix_align - 1)) == 0, "bad alignment of suffix"); } #endif @@ -135,7 +135,7 @@ assert(UseCompressedOops, "currently requested address used only for compressed oops"); if (PrintCompressedOopsMode) { tty->cr(); - tty->print_cr("Reserved memory at not requested address: " PTR_FORMAT " vs " PTR_FORMAT, base, requested_address); + tty->print_cr("Reserved memory not at requested address: " PTR_FORMAT " vs " PTR_FORMAT, base, requested_address); } // OS ignored requested address. Try different address. if (special) { @@ -162,11 +162,11 @@ assert(prefix_align != 0, "sanity"); assert(suffix_size != 0, "sanity"); assert(suffix_align != 0, "sanity"); - assert((prefix_size & prefix_align - 1) == 0, + assert((prefix_size & (prefix_align - 1)) == 0, "prefix_size not divisible by prefix_align"); - assert((suffix_size & suffix_align - 1) == 0, + assert((suffix_size & (suffix_align - 1)) == 0, "suffix_size not divisible by suffix_align"); - assert((suffix_align & prefix_align - 1) == 0, + assert((suffix_align & (prefix_align - 1)) == 0, "suffix_align not divisible by prefix_align"); // Assert that if noaccess_prefix is used, it is the same as prefix_align. @@ -210,8 +210,8 @@ if (addr == NULL) return; // Check whether the result has the needed alignment (unlikely unless - // prefix_align == suffix_align). - const size_t ofs = size_t(addr) + adjusted_prefix_size & suffix_align - 1; + // prefix_align < suffix_align). + const size_t ofs = (size_t(addr) + adjusted_prefix_size) & (suffix_align - 1); if (ofs != 0) { // Wrong alignment. Release, allocate more space and do manual alignment. // @@ -232,6 +232,15 @@ addr = reserve_and_align(size + suffix_align, adjusted_prefix_size, prefix_align, suffix_size, suffix_align); } + + if (requested_address != 0 && + failed_to_reserve_as_requested(addr, requested_address, size, false)) { + // As a result of the alignment constraints, the allocated addr differs + // from the requested address. Return back to the caller who can + // take remedial action (like try again without a requested address). + assert(_base == NULL, "should be"); + return; + } } _base = addr; @@ -245,13 +254,19 @@ const size_t noaccess_prefix, bool executable) { const size_t granularity = os::vm_allocation_granularity(); - assert((size & granularity - 1) == 0, + assert((size & (granularity - 1)) == 0, "size not aligned to os::vm_allocation_granularity()"); - assert((alignment & granularity - 1) == 0, + 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"); + 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; @@ -282,10 +297,8 @@ return; } // Check alignment constraints - if (alignment > 0) { - assert((uintptr_t) base % alignment == 0, - "Large pages returned a non-aligned address"); - } + assert((uintptr_t) base % alignment == 0, + "Large pages returned a non-aligned address"); _special = true; } else { // failed; try to reserve regular memory below @@ -321,7 +334,7 @@ if (base == NULL) return; // Check alignment constraints - if (alignment > 0 && ((size_t)base & alignment - 1) != 0) { + if ((((size_t)base + noaccess_prefix) & (alignment - 1)) != 0) { // Base not aligned, retry if (!os::release_memory(base, size)) fatal("os::release_memory failed"); // Reserve size large enough to do manual alignment and @@ -338,12 +351,21 @@ os::release_memory(extra_base, extra_size); base = os::reserve_memory(size, base); } while (base == NULL); + + if (requested_address != 0 && + failed_to_reserve_as_requested(base, requested_address, size, false)) { + // As a result of the alignment constraints, the allocated base differs + // from the requested address. Return back to the caller who can + // take remedial action (like try again without a requested address). + assert(_base == NULL, "should be"); + return; + } } } // Done _base = base; _size = size; - _alignment = MAX2(alignment, (size_t) os::vm_page_size()); + _alignment = alignment; _noaccess_prefix = noaccess_prefix; // Assert that if noaccess_prefix is used, it is the same as alignment.