8064457: Introduce compressed oops mode disjoint base and improve compressed heap handling.
authorgoetz
Mon, 05 Jan 2015 12:07:37 -0500
changeset 28372 ce0aad4b8c44
parent 28371 92e60e58ba8b
child 28373 26fdc99d32f8
8064457: Introduce compressed oops mode disjoint base and improve compressed heap handling. Summary: Introduce compressed oops mode disjoint base and improve compressed heap handling. Reviewed-by: kvn, coleenp
hotspot/src/share/vm/memory/metaspace.cpp
hotspot/src/share/vm/memory/universe.cpp
hotspot/src/share/vm/memory/universe.hpp
hotspot/src/share/vm/opto/matcher.hpp
hotspot/src/share/vm/prims/whitebox.cpp
hotspot/src/share/vm/runtime/arguments.cpp
hotspot/src/share/vm/runtime/arguments.hpp
hotspot/src/share/vm/runtime/globals.hpp
hotspot/src/share/vm/runtime/virtualspace.cpp
hotspot/src/share/vm/runtime/virtualspace.hpp
hotspot/src/share/vm/utilities/globalDefinitions.hpp
hotspot/src/share/vm/utilities/globalDefinitions_xlc.hpp
hotspot/test/runtime/CompressedOops/UseCompressedOops.java
--- a/hotspot/src/share/vm/memory/metaspace.cpp	Tue Dec 30 12:59:20 2014 -0500
+++ b/hotspot/src/share/vm/memory/metaspace.cpp	Mon Jan 05 12:07:37 2015 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2015, 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
@@ -422,7 +422,7 @@
     bool large_pages = false; // No large pages when dumping the CDS archive.
     char* shared_base = (char*)align_ptr_up((char*)SharedBaseAddress, Metaspace::reserve_alignment());
 
-    _rs = ReservedSpace(bytes, Metaspace::reserve_alignment(), large_pages, shared_base, 0);
+    _rs = ReservedSpace(bytes, Metaspace::reserve_alignment(), large_pages, shared_base);
     if (_rs.is_reserved()) {
       assert(shared_base == 0 || _rs.base() == shared_base, "should match");
     } else {
@@ -3025,7 +3025,7 @@
   ReservedSpace metaspace_rs = ReservedSpace(compressed_class_space_size(),
                                              _reserve_alignment,
                                              large_pages,
-                                             requested_addr, 0);
+                                             requested_addr);
   if (!metaspace_rs.is_reserved()) {
 #if INCLUDE_CDS
     if (UseSharedSpaces) {
@@ -3039,7 +3039,7 @@
              can_use_cds_with_metaspace_addr(addr + increment, cds_base)) {
         addr = addr + increment;
         metaspace_rs = ReservedSpace(compressed_class_space_size(),
-                                     _reserve_alignment, large_pages, addr, 0);
+                                     _reserve_alignment, large_pages, addr);
       }
     }
 #endif
--- a/hotspot/src/share/vm/memory/universe.cpp	Tue Dec 30 12:59:20 2014 -0500
+++ b/hotspot/src/share/vm/memory/universe.cpp	Mon Jan 05 12:07:37 2015 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2015, 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
@@ -694,103 +694,6 @@
 //     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) {
@@ -844,30 +747,13 @@
     // 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()
+    if ((uint64_t)Universe::heap()->reserved_region().end() > UnscaledOopHeapMax) {
+      // Didn't reserve heap below 4Gb.  Must shift.
       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 {
+    }
+    if ((uint64_t)Universe::heap()->reserved_region().end() <= OopEncodingHeapMax) {
+      // Did reserve heap below 32Gb. Can use base == 0;
       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());
@@ -875,6 +761,11 @@
     if (PrintCompressedOopsMode || (PrintMiscellaneous && Verbose)) {
       Universe::print_compressed_oops_mode();
     }
+
+    // Tell tests in which mode we run.
+    Arguments::PropertyList_add(new SystemProperty("java.vm.compressedOopsMode",
+                                                   narrow_oop_mode_to_string(narrow_oop_mode()),
+                                                   false));
   }
   // Universe::narrow_oop_base() is one page below the heap.
   assert((intptr_t)Universe::narrow_oop_base() <= (intptr_t)(Universe::heap()->base() -
@@ -903,22 +794,27 @@
   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());
+    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();
 }
 
-// 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");
@@ -928,46 +824,31 @@
       || 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);
+  // Now create the space.
+  ReservedHeapSpace total_rs(total_reserved, alignment, use_large_pages);
 
-  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 (total_rs.is_reserved()) {
+    assert((total_reserved == total_rs.size()) && ((uintptr_t)total_rs.base() % alignment == 0),
+           "must be exactly of required size and alignment");
+    // We are good.
 
-      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, "");
+    if (UseCompressedOops) {
+      // Universe::initialize_heap() will reset this to NULL if unscaled
+      // or zero-based narrow oops are actually used.
+      // Else heap start and base MUST differ, so that NULL can be encoded nonambigous.
+      Universe::set_narrow_oop_base((address)total_rs.compressed_oop_base());
+    }
 
-        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;
+  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);
 }
 
 
@@ -985,6 +866,8 @@
       return "32-bit";
     case ZeroBasedNarrowOop:
       return "Zero based";
+    case DisjointBaseNarrowOop:
+      return "Non-zero disjoint base";
     case HeapBasedNarrowOop:
       return "Non-zero based";
   }
@@ -995,6 +878,10 @@
 
 
 Universe::NARROW_OOP_MODE Universe::narrow_oop_mode() {
+  if (narrow_oop_base_disjoint()) {
+    return DisjointBaseNarrowOop;
+  }
+
   if (narrow_oop_base() != 0) {
     return HeapBasedNarrowOop;
   }
--- a/hotspot/src/share/vm/memory/universe.hpp	Tue Dec 30 12:59:20 2014 -0500
+++ b/hotspot/src/share/vm/memory/universe.hpp	Mon Jan 05 12:07:37 2015 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2015, 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
@@ -102,8 +102,8 @@
   friend class MarkSweep;
   friend class oopDesc;
   friend class ClassLoader;
-  friend class Arguments;
   friend class SystemDictionary;
+  friend class ReservedHeapSpace;
   friend class VMStructs;
   friend class VM_PopulateDumpSharedSpace;
   friend class Metaspace;
@@ -351,17 +351,40 @@
   //     NarrowOopHeapBaseMin + heap_size < 4Gb
   // 1 - Use zero based compressed oops with encoding when
   //     NarrowOopHeapBaseMin + heap_size < 32Gb
-  // 2 - Use compressed oops with heap base + encoding.
+  // 2 - Use compressed oops with disjoint heap base if
+  //     base is 32G-aligned and base > 0. This allows certain
+  //     optimizations in encoding/decoding.
+  //     Disjoint: Bits used in base are disjoint from bits used
+  //     for oops ==> oop = (cOop << 3) | base.  One can disjoint
+  //     the bits of an oop into base and compressed oop.
+  // 3 - Use compressed oops with heap base + encoding.
   enum NARROW_OOP_MODE {
     UnscaledNarrowOop  = 0,
     ZeroBasedNarrowOop = 1,
-    HeapBasedNarrowOop = 2
+    DisjointBaseNarrowOop = 2,
+    HeapBasedNarrowOop = 3,
+    AnyNarrowOopMode = 4
   };
   static NARROW_OOP_MODE narrow_oop_mode();
   static const char* narrow_oop_mode_to_string(NARROW_OOP_MODE mode);
   static char*    preferred_heap_base(size_t heap_size, size_t alignment, NARROW_OOP_MODE mode);
   static char*    preferred_metaspace_base(size_t heap_size, NARROW_OOP_MODE mode);
-  static address  narrow_oop_base()                       { return  _narrow_oop._base; }
+  static address  narrow_oop_base()                  { return  _narrow_oop._base; }
+  // Test whether bits of addr and possible offsets into the heap overlap.
+  static bool     is_disjoint_heap_base_address(address addr) {
+    return (((uint64_t)(intptr_t)addr) &
+            (((uint64_t)UCONST64(0xFFFFffffFFFFffff)) >> (32-LogMinObjAlignmentInBytes))) == 0;
+  }
+  // Check for disjoint base compressed oops.
+  static bool     narrow_oop_base_disjoint()        {
+    return _narrow_oop._base != NULL && is_disjoint_heap_base_address(_narrow_oop._base);
+  }
+  // Check for real heapbased compressed oops.
+  // We must subtract the base as the bits overlap.
+  // If we negate above function, we also get unscaled and zerobased.
+  static bool     narrow_oop_base_overlaps()          {
+    return _narrow_oop._base != NULL && !is_disjoint_heap_base_address(_narrow_oop._base);
+  }
   static bool  is_narrow_oop_base(void* addr)             { return (narrow_oop_base() == (address)addr); }
   static int      narrow_oop_shift()                      { return  _narrow_oop._shift; }
   static bool     narrow_oop_use_implicit_null_checks()   { return  _narrow_oop._use_implicit_null_checks; }
--- a/hotspot/src/share/vm/opto/matcher.hpp	Tue Dec 30 12:59:20 2014 -0500
+++ b/hotspot/src/share/vm/opto/matcher.hpp	Mon Jan 05 12:07:37 2015 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2015, 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
@@ -433,6 +433,13 @@
   // NullCheck oop_reg
   //
   inline static bool gen_narrow_oop_implicit_null_checks() {
+    // Advice matcher to perform null checks on the narrow oop side.
+    // Implicit checks are not possible on the uncompressed oop side anyway
+    // (at least not for read accesses).
+    // Performs significantly better (especially on Power 6).
+    if (!os::zero_page_read_protected()) {
+      return true;
+    }
     return Universe::narrow_oop_use_implicit_null_checks() &&
            (narrow_oop_use_complex_address() ||
             Universe::narrow_oop_base() != NULL);
--- a/hotspot/src/share/vm/prims/whitebox.cpp	Tue Dec 30 12:59:20 2014 -0500
+++ b/hotspot/src/share/vm/prims/whitebox.cpp	Mon Jan 05 12:07:37 2015 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015, 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
@@ -176,11 +176,11 @@
 
 WB_ENTRY(void, WB_ReadFromNoaccessArea(JNIEnv* env, jobject o))
   size_t granularity = os::vm_allocation_granularity();
-  ReservedHeapSpace rhs(100 * granularity, granularity, false, NULL);
+  ReservedHeapSpace rhs(100 * granularity, granularity, false);
   VirtualSpace vs;
   vs.initialize(rhs, 50 * granularity);
 
-  //Check if constraints are complied
+  // Check if constraints are complied
   if (!( UseCompressedOops && rhs.base() != NULL &&
          Universe::narrow_oop_base() != NULL &&
          Universe::narrow_oop_use_implicit_null_checks() )) {
@@ -203,7 +203,7 @@
 static jint wb_stress_virtual_space_resize(size_t reserved_space_size,
                                            size_t magnitude, size_t iterations) {
   size_t granularity = os::vm_allocation_granularity();
-  ReservedHeapSpace rhs(reserved_space_size * granularity, granularity, false, NULL);
+  ReservedHeapSpace rhs(reserved_space_size * granularity, granularity, false);
   VirtualSpace vs;
   if (!vs.initialize(rhs, 0)) {
     tty->print_cr("Failed to initialize VirtualSpace. Can't proceed.");
--- a/hotspot/src/share/vm/runtime/arguments.cpp	Tue Dec 30 12:59:20 2014 -0500
+++ b/hotspot/src/share/vm/runtime/arguments.cpp	Mon Jan 05 12:07:37 2015 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2015, 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
@@ -1522,15 +1522,6 @@
       FLAG_SET_ERGO(bool, UseCompressedOops, true);
     }
 #endif
-#ifdef _WIN64
-    if (UseLargePages && UseCompressedOops) {
-      // Cannot allocate guard pages for implicit checks in indexed addressing
-      // mode, when large pages are specified on windows.
-      // This flag could be switched ON if narrow oop base address is set to 0,
-      // see code in Universe::initialize_heap().
-      Universe::set_narrow_oop_use_implicit_null_checks(false);
-    }
-#endif //  _WIN64
   } else {
     if (UseCompressedOops && !FLAG_IS_DEFAULT(UseCompressedOops)) {
       warning("Max heap size too large for Compressed Oops");
@@ -2416,6 +2407,7 @@
 #ifdef COMPILER1
   status = status && verify_min_value(ValueMapInitialSize, 1, "ValueMapInitialSize");
 #endif
+  status = status && verify_min_value(HeapSearchSteps, 1, "HeapSearchSteps");
 
   if (PrintNMTStatistics) {
 #if INCLUDE_NMT
@@ -4102,6 +4094,10 @@
   PropertyList_add(plist, new_p);
 }
 
+void Arguments::PropertyList_add(SystemProperty *element) {
+  PropertyList_add(&_system_properties, element);
+}
+
 // This add maintains unique property key in the list.
 void Arguments::PropertyList_unique_add(SystemProperty** plist, const char* k, char* v, jboolean append) {
   if (plist == NULL)
--- a/hotspot/src/share/vm/runtime/arguments.hpp	Tue Dec 30 12:59:20 2014 -0500
+++ b/hotspot/src/share/vm/runtime/arguments.hpp	Mon Jan 05 12:07:37 2015 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2015, 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
@@ -572,6 +572,7 @@
   static void init_version_specific_system_properties();
 
   // Property List manipulation
+  static void PropertyList_add(SystemProperty *element);
   static void PropertyList_add(SystemProperty** plist, SystemProperty *element);
   static void PropertyList_add(SystemProperty** plist, const char* k, char* v);
   static void PropertyList_unique_add(SystemProperty** plist, const char* k, char* v) {
--- a/hotspot/src/share/vm/runtime/globals.hpp	Tue Dec 30 12:59:20 2014 -0500
+++ b/hotspot/src/share/vm/runtime/globals.hpp	Mon Jan 05 12:07:37 2015 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2015, 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
@@ -531,6 +531,11 @@
   product_pd(uintx, HeapBaseMinAddress,                                     \
           "OS specific low limit for heap base address")                    \
                                                                             \
+  product(uintx, HeapSearchSteps, 3 PPC64_ONLY(+17),                        \
+          "Heap allocation steps through preferred address regions to find" \
+          " where it can allocate the heap. Number of steps to take per "   \
+          "region.")                                                        \
+                                                                            \
   diagnostic(bool, PrintCompressedOopsMode, false,                          \
           "Print compressed oops base address and encoding mode")           \
                                                                             \
--- a/hotspot/src/share/vm/runtime/virtualspace.cpp	Tue Dec 30 12:59:20 2014 -0500
+++ b/hotspot/src/share/vm/runtime/virtualspace.cpp	Mon Jan 05 12:07:37 2015 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2015, 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
@@ -43,21 +43,19 @@
   // 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);
+  initialize(size, alignment, large_pages, NULL, 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);
+                             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, 0, executable);
+  initialize(size, alignment, large, NULL, executable);
 }
 
 // Helper method.
@@ -91,7 +89,6 @@
 
 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,
@@ -103,10 +100,6 @@
 
   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;
@@ -122,11 +115,6 @@
   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);
@@ -176,7 +164,7 @@
     if (base == NULL) return;
 
     // Check alignment constraints
-    if ((((size_t)base + noaccess_prefix) & (alignment - 1)) != 0) {
+    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
@@ -197,16 +185,6 @@
   _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");
 }
 
 
@@ -276,54 +254,336 @@
     _base = NULL;
     _size = 0;
     _noaccess_prefix = 0;
+    _alignment = 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");
+static size_t noaccess_prefix_size(size_t alignment) {
+  return lcm(os::vm_page_size(), alignment);
+}
 
-  // If there is no noaccess prefix, return.
-  if (_noaccess_prefix == 0) return;
+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);
 
-  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);
+  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((size == _size) && ((uintptr_t)_base % _alignment == 0),
-         "must be exactly of required size and alignment");
+  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;
+  }
 }
 
-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) {
+#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);
   }
-
-  // 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
@@ -791,8 +1051,7 @@
     ReservedSpace rs(size,          // size
                      alignment,     // alignment
                      UseLargePages, // large
-                     NULL,          // requested_address
-                     0);            // noacces_prefix
+                     (char *)NULL); // requested_address
 
     test_log(" rs.special() == %d", rs.special());
 
--- a/hotspot/src/share/vm/runtime/virtualspace.hpp	Tue Dec 30 12:59:20 2014 -0500
+++ b/hotspot/src/share/vm/runtime/virtualspace.hpp	Mon Jan 05 12:07:37 2015 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2015, 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
@@ -31,33 +31,29 @@
 
 class ReservedSpace VALUE_OBJ_CLASS_SPEC {
   friend class VMStructs;
- private:
+ protected:
   char*  _base;
   size_t _size;
   size_t _noaccess_prefix;
   size_t _alignment;
   bool   _special;
+ private:
   bool   _executable;
 
   // ReservedSpace
   ReservedSpace(char* base, size_t size, size_t alignment, bool special,
                 bool executable);
+ protected:
   void initialize(size_t size, size_t alignment, bool large,
                   char* requested_address,
-                  const size_t noaccess_prefix,
                   bool executable);
 
- protected:
-  // Create protection page at the beginning of the space.
-  void protect_noaccess_prefix(const size_t size);
-
  public:
   // Constructor
   ReservedSpace();
   ReservedSpace(size_t size);
   ReservedSpace(size_t size, size_t alignment, bool large,
-                char* requested_address = NULL,
-                const size_t noaccess_prefix = 0);
+                char* requested_address = NULL);
   ReservedSpace(size_t size, size_t alignment, bool large, bool executable);
 
   // Accessors
@@ -98,12 +94,23 @@
   return last_part(partition_size, alignment());
 }
 
-// Class encapsulating behavior specific of memory space reserved for Java heap
+// Class encapsulating behavior specific of memory space reserved for Java heap.
 class ReservedHeapSpace : public ReservedSpace {
-public:
-  // Constructor
-  ReservedHeapSpace(size_t size, size_t forced_base_alignment,
-                    bool large, char* requested_address);
+ private:
+  void try_reserve_heap(size_t size, size_t alignment, bool large,
+                        char *requested_address);
+  void try_reserve_range(char *highest_start, char *lowest_start,
+                         size_t attach_point_alignment, char *aligned_HBMA,
+                         char *upper_bound, size_t size, size_t alignment, bool large);
+  void initialize_compressed_heap(const size_t size, size_t alignment, bool large);
+  // Create protection page at the beginning of the space.
+  void establish_noaccess_prefix();
+ public:
+  // Constructor. Tries to find a heap that is good for compressed oops.
+  ReservedHeapSpace(size_t size, size_t forced_base_alignment, bool large);
+  // Returns the base to be used for compression, i.e. so that null can be
+  // encoded safely and implicit null checks can work.
+  char *compressed_oop_base() { return _base - _noaccess_prefix; }
 };
 
 // Class encapsulating behavior specific memory space for Code
--- a/hotspot/src/share/vm/utilities/globalDefinitions.hpp	Tue Dec 30 12:59:20 2014 -0500
+++ b/hotspot/src/share/vm/utilities/globalDefinitions.hpp	Mon Jan 05 12:07:37 2015 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2015, 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
@@ -124,9 +124,6 @@
 extern int BytesPerHeapOop;
 extern int BitsPerHeapOop;
 
-// Oop encoding heap max
-extern uint64_t OopEncodingHeapMax;
-
 const int BitsPerJavaInteger = 32;
 const int BitsPerJavaLong    = 64;
 const int BitsPerSize_t      = size_tSize * BitsPerByte;
@@ -195,7 +192,6 @@
   return (byte_size + (HeapWordSize-1)) >> LogHeapWordSize;
 }
 
-
 const size_t K                  = 1024;
 const size_t M                  = K*K;
 const size_t G                  = M*K;
@@ -397,8 +393,17 @@
 const int KlassAlignmentInBytes    = 1 << LogKlassAlignmentInBytes;
 const int KlassAlignment           = KlassAlignmentInBytes / HeapWordSize;
 
-// Klass encoding metaspace max size
-const uint64_t KlassEncodingMetaspaceMax = (uint64_t(max_juint) + 1) << LogKlassAlignmentInBytes;
+// Maximal size of heap where unscaled compression can be used. Also upper bound
+// for heap placement: 4GB.
+const  uint64_t UnscaledOopHeapMax = (uint64_t(max_juint) + 1);
+// Maximal size of heap where compressed oops can be used. Also upper bound for heap
+// placement for zero based compression algorithm: UnscaledOopHeapMax << LogMinObjAlignmentInBytes.
+extern uint64_t OopEncodingHeapMax;
+
+// Maximal size of compressed class space. Above this limit compression is not possible.
+// Also upper bound for placement of zero based class space. (Class space is further limited
+// to be < 3G, see arguments.cpp.)
+const  uint64_t KlassEncodingMetaspaceMax = (uint64_t(max_juint) + 1) << LogKlassAlignmentInBytes;
 
 // Machine dependent stuff
 
--- a/hotspot/src/share/vm/utilities/globalDefinitions_xlc.hpp	Tue Dec 30 12:59:20 2014 -0500
+++ b/hotspot/src/share/vm/utilities/globalDefinitions_xlc.hpp	Mon Jan 05 12:07:37 2015 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved.
  * Copyright 2012, 2013 SAP AG. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
@@ -172,21 +172,21 @@
 #define offset_of(klass,field) (size_t)((intx)&(((klass*)16)->field) - 16)
 
 // Some constant sizes used throughout the AIX port
-#define SIZE_1K   ((uint64_t)         0x400ULL)
-#define SIZE_4K   ((uint64_t)        0x1000ULL)
-#define SIZE_64K  ((uint64_t)       0x10000ULL)
-#define SIZE_1M   ((uint64_t)      0x100000ULL)
-#define SIZE_4M   ((uint64_t)      0x400000ULL)
-#define SIZE_8M   ((uint64_t)      0x800000ULL)
-#define SIZE_16M  ((uint64_t)     0x1000000ULL)
-#define SIZE_256M ((uint64_t)    0x10000000ULL)
-#define SIZE_1G   ((uint64_t)    0x40000000ULL)
-#define SIZE_2G   ((uint64_t)    0x80000000ULL)
-#define SIZE_4G   ((uint64_t)   0x100000000ULL)
-#define SIZE_16G  ((uint64_t)   0x400000000ULL)
-#define SIZE_32G  ((uint64_t)   0x800000000ULL)
-#define SIZE_64G  ((uint64_t)  0x1000000000ULL)
-#define SIZE_1T   ((uint64_t) 0x10000000000ULL)
+#define SIZE_1K   ((uint64_t) UCONST64(        0x400))
+#define SIZE_4K   ((uint64_t) UCONST64(       0x1000))
+#define SIZE_64K  ((uint64_t) UCONST64(      0x10000))
+#define SIZE_1M   ((uint64_t) UCONST64(     0x100000))
+#define SIZE_4M   ((uint64_t) UCONST64(     0x400000))
+#define SIZE_8M   ((uint64_t) UCONST64(     0x800000))
+#define SIZE_16M  ((uint64_t) UCONST64(    0x1000000))
+#define SIZE_256M ((uint64_t) UCONST64(   0x10000000))
+#define SIZE_1G   ((uint64_t) UCONST64(   0x40000000))
+#define SIZE_2G   ((uint64_t) UCONST64(   0x80000000))
+#define SIZE_4G   ((uint64_t) UCONST64(  0x100000000))
+#define SIZE_16G  ((uint64_t) UCONST64(  0x400000000))
+#define SIZE_32G  ((uint64_t) UCONST64(  0x800000000))
+#define SIZE_64G  ((uint64_t) UCONST64( 0x1000000000))
+#define SIZE_1T   ((uint64_t) UCONST64(0x10000000000))
 
 
 #endif // SHARE_VM_UTILITIES_GLOBALDEFINITIONS_XLC_HPP
--- a/hotspot/test/runtime/CompressedOops/UseCompressedOops.java	Tue Dec 30 12:59:20 2014 -0500
+++ b/hotspot/test/runtime/CompressedOops/UseCompressedOops.java	Mon Jan 05 12:07:37 2015 -0500
@@ -35,20 +35,42 @@
 public class UseCompressedOops {
 
     public static void main(String[] args) throws Exception {
+        testCompressedOopsModesGCs();
+        testCompressedOopsModesGCs("-XX:+UseLargePages");
+    }
+
+    public static void testCompressedOopsModesGCs(String... flags) throws Exception {
+        ArrayList<String> args = new ArrayList<>();
+        Collections.addAll(args, flags);
+
+        // Test default.
+        testCompressedOopsModes(args);
+        // Test GCs.
+        testCompressedOopsModes(args, "-XX:+UseG1GC");
+        testCompressedOopsModes(args, "-XX:+UseConcMarkSweepGC");
+        testCompressedOopsModes(args, "-XX:+UseSerialGC");
+        testCompressedOopsModes(args, "-XX:+UseParallelGC");
+        testCompressedOopsModes(args, "-XX:+UseParallelOldGC");
+    }
+
+    public static void testCompressedOopsModes(ArrayList<String> flags1, String... flags2) throws Exception {
+        ArrayList<String> args = new ArrayList<>();
+        args.addAll(flags1);
+        Collections.addAll(args, flags2);
 
         if (Platform.is64bit()) {
             // Explicitly turn of compressed oops
-            testCompressedOops("-XX:-UseCompressedOops", "-Xmx32m")
+            testCompressedOops(args, "-XX:-UseCompressedOops", "-Xmx32m")
                 .shouldNotContain("Compressed Oops")
                 .shouldHaveExitValue(0);
 
             // Compressed oops should be on by default
-            testCompressedOops("-Xmx32m")
+            testCompressedOops(args, "-Xmx32m")
                 .shouldContain("Compressed Oops mode")
                 .shouldHaveExitValue(0);
 
             // Explicly enabling compressed oops
-            testCompressedOops("-XX:+UseCompressedOops", "-Xmx32m")
+            testCompressedOops(args, "-XX:+UseCompressedOops", "-Xmx32m")
                 .shouldContain("Compressed Oops mode")
                 .shouldHaveExitValue(0);
 
@@ -58,68 +80,89 @@
             // puts the heap way up, forcing different behaviour.
             if (!Platform.isOSX() && !Platform.isSolaris()) {
                 // Larger than 4gb heap should result in zero based with shift 3
-                testCompressedOops("-XX:+UseCompressedOops", "-Xmx5g")
+                testCompressedOops(args, "-XX:+UseCompressedOops", "-Xmx5g")
+                    .shouldContain("Zero based")
+                    .shouldContain("Oop shift amount: 3")
+                    .shouldHaveExitValue(0);
+
+                // Larger than 3gb heap and HeapBaseMinAddress=1g should result in zero based with shift 3
+                testCompressedOops(args, "-XX:+UseCompressedOops", "-Xmx3200m", "-XX:HeapBaseMinAddress=1g")
                     .shouldContain("Zero based")
                     .shouldContain("Oop shift amount: 3")
                     .shouldHaveExitValue(0);
 
                 // Small heap above 4gb should result in zero based with shift 3
-                testCompressedOops("-XX:+UseCompressedOops", "-Xmx32m", "-XX:HeapBaseMinAddress=4g")
+                testCompressedOops(args, "-XX:+UseCompressedOops", "-Xmx32m", "-XX:HeapBaseMinAddress=4g")
                     .shouldContain("Zero based")
                     .shouldContain("Oop shift amount: 3")
                     .shouldHaveExitValue(0);
 
                 // Small heap above 32gb should result in non-zero based with shift 3
-                testCompressedOops("-XX:+UseCompressedOops", "-Xmx32m", "-XX:HeapBaseMinAddress=32g")
+                testCompressedOops(args, "-XX:+UseCompressedOops", "-Xmx32m", "-XX:HeapBaseMinAddress=32g")
+                    .shouldContain("Non-zero disjoint base")
+                    .shouldContain("Oop shift amount: 3")
+                    .shouldHaveExitValue(0);
+
+                // Small heap above 32gb should result in non-zero based with shift 3
+                testCompressedOops(args, "-XX:+UseCompressedOops", "-Xmx32m", "-XX:HeapBaseMinAddress=72704m")
                     .shouldContain("Non-zero based")
                     .shouldContain("Oop shift amount: 3")
                     .shouldHaveExitValue(0);
 
                 // 32gb heap with heap base above 64gb and object alignment set to 16 bytes should result
                 // in non-zero based with shift 4
-                testCompressedOops("-XX:+UseCompressedOops", "-Xmx32g", "-XX:ObjectAlignmentInBytes=16",
+                testCompressedOops(args, "-XX:+UseCompressedOops", "-Xmx32g", "-XX:ObjectAlignmentInBytes=16",
                                "-XX:HeapBaseMinAddress=64g")
-                    .shouldContain("Non-zero based")
+                    .shouldContain("Non-zero disjoint base")
                     .shouldContain("Oop shift amount: 4")
                     .shouldHaveExitValue(0);
 
                 // 32gb heap with object alignment set to 16 bytes should result in zero based with shift 4
-                testCompressedOops("-XX:+UseCompressedOops", "-Xmx32g", "-XX:ObjectAlignmentInBytes=16")
+                testCompressedOops(args, "-XX:+UseCompressedOops", "-Xmx32g", "-XX:ObjectAlignmentInBytes=16")
                     .shouldContain("Zero based")
                     .shouldContain("Oop shift amount: 4")
                     .shouldHaveExitValue(0);
             }
 
+            // This is a pathologic case for the heap allocation algorithm. Regression test.
+            // HeapBaseMinAddress must be 2g and should not be set on the command line.
+            testCompressedOops(args, "-XX:+UseCompressedOops", "-Xmx2g")
+                .shouldNotContain("Max heap size too large for Compressed Oops")
+                .shouldHaveExitValue(0);
+            testCompressedOops(args, "-XX:+UseCompressedOops", "-Xmx29g", "-XX:CompressedClassSpaceSize=1g")
+                .shouldNotContain("Max heap size too large for Compressed Oops")
+                .shouldHaveExitValue(0);
+
             // Explicitly enabling compressed oops with 32gb heap should result a warning
-            testCompressedOops("-XX:+UseCompressedOops", "-Xmx32g")
+            testCompressedOops(args, "-XX:+UseCompressedOops", "-Xmx32g")
                 .shouldContain("Max heap size too large for Compressed Oops")
                 .shouldHaveExitValue(0);
 
             // 32gb heap should not result a warning
-            testCompressedOops("-Xmx32g")
+            testCompressedOops(args, "-Xmx32g")
                 .shouldNotContain("Max heap size too large for Compressed Oops")
                 .shouldHaveExitValue(0);
 
             // Explicitly enabling compressed oops with 32gb heap and object
             // alignment set to 8 byte should result a warning
-            testCompressedOops("-XX:+UseCompressedOops", "-Xmx32g", "-XX:ObjectAlignmentInBytes=8")
+            testCompressedOops(args, "-XX:+UseCompressedOops", "-Xmx32g", "-XX:ObjectAlignmentInBytes=8")
                 .shouldContain("Max heap size too large for Compressed Oops")
                 .shouldHaveExitValue(0);
 
             // 64gb heap and object alignment set to 16 bytes should result in a warning
-            testCompressedOops("-XX:+UseCompressedOops", "-Xmx64g", "-XX:ObjectAlignmentInBytes=16")
+            testCompressedOops(args, "-XX:+UseCompressedOops", "-Xmx64g", "-XX:ObjectAlignmentInBytes=16")
                 .shouldContain("Max heap size too large for Compressed Oops")
                 .shouldHaveExitValue(0);
 
         } else {
             // Compressed oops should only apply to 64bit platforms
-            testCompressedOops("-XX:+UseCompressedOops", "-Xmx32m")
+            testCompressedOops(args, "-XX:+UseCompressedOops", "-Xmx32m")
                 .shouldContain("Unrecognized VM option 'UseCompressedOops'")
                 .shouldHaveExitValue(1);
         }
     }
 
-    private static OutputAnalyzer testCompressedOops(String... flags) throws Exception {
+    private static OutputAnalyzer testCompressedOops(ArrayList<String> flags1, String... flags2) throws Exception {
         ArrayList<String> args = new ArrayList<>();
 
         // Always run with these three:
@@ -128,7 +171,8 @@
         args.add("-Xms32m");
 
         // Add the extra flags
-        Collections.addAll(args, flags);
+        args.addAll(flags1);
+        Collections.addAll(args, flags2);
 
         args.add("-version");