changeset 26394:bcf7be47a0ac

Merge
author duke
date Wed, 05 Jul 2017 20:00:03 +0200
parents 290847867ded 3b419bf4f176
children b2287cac7813
files hotspot/agent/src/share/classes/sun/jvm/hotspot/gc_implementation/g1/HeapRegionSeq.java hotspot/src/share/vm/gc_implementation/g1/heapRegionSeq.cpp hotspot/src/share/vm/gc_implementation/g1/heapRegionSeq.hpp hotspot/src/share/vm/gc_implementation/g1/heapRegionSeq.inline.hpp jdk/src/java.desktop/share/conf/cmm/lcms/CIEXYZ.pf jdk/src/java.desktop/share/conf/cmm/lcms/GRAY.pf jdk/src/java.desktop/share/conf/cmm/lcms/LINEAR_RGB.pf jdk/src/java.desktop/share/conf/cmm/lcms/PYCC.pf jdk/src/java.desktop/share/conf/cmm/lcms/sRGB.pf jdk/test/java/awt/Mixing/AWT_Mixing/Util.java nashorn/bin/dump_octane_code.sh nashorn/bin/fixorphantests.sh nashorn/bin/fixwhitespace.sh nashorn/bin/jjsdebug.sh nashorn/bin/rm-non-tracked.sh nashorn/bin/run_octane.sh nashorn/bin/rundiff.sh nashorn/bin/runopt.sh nashorn/bin/runopt_noassert.sh nashorn/bin/runopt_nojfr.sh
diffstat 311 files changed, 12476 insertions(+), 5861 deletions(-) [+]
line wrap: on
line diff
--- a/.hgtags-top-repo	Thu Sep 04 14:45:48 2014 -0700
+++ b/.hgtags-top-repo	Wed Jul 05 20:00:03 2017 +0200
@@ -271,3 +271,4 @@
 d3ec8d048e6c3c46b6e0ee011cc551ad386dfba5 jdk9-b26
 ba5645f2735b41ed085d07ba20fa7b322afff318 jdk9-b27
 ea2f7981236f3812436958748ab3d26e80a35130 jdk9-b28
+9e6581aeda388a23fbee021fc33e6aa152a60657 jdk9-b29
--- a/corba/.hgtags	Thu Sep 04 14:45:48 2014 -0700
+++ b/corba/.hgtags	Wed Jul 05 20:00:03 2017 +0200
@@ -271,3 +271,4 @@
 6c777df597bbf5abba3488d44c401edfe73c74af jdk9-b26
 7e06bf1dcb0907b80ddf59315426ce9ce775e56d jdk9-b27
 a00b04ef067e39f50b9a0fea6f1904e35d632a73 jdk9-b28
+163a9cd806fd09970baf1f5f42b92a3cfe7ee945 jdk9-b29
--- a/hotspot/.hgtags	Thu Sep 04 14:45:48 2014 -0700
+++ b/hotspot/.hgtags	Wed Jul 05 20:00:03 2017 +0200
@@ -431,3 +431,4 @@
 48b95a073d752d6891cc0d1d2836b321ecf3ce0c jdk9-b26
 f95347244306affc32ce3056f27ceff7b2100810 jdk9-b27
 657294869d7ff063e055f5492cab7ce5612ca851 jdk9-b28
+deb29e92f68ace2808a36ecfa18c7d61dcb645bb jdk9-b29
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc_implementation/g1/G1CollectedHeap.java	Thu Sep 04 14:45:48 2014 -0700
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc_implementation/g1/G1CollectedHeap.java	Wed Jul 05 20:00:03 2017 +0200
@@ -43,8 +43,8 @@
 // Mirror class for G1CollectedHeap.
 
 public class G1CollectedHeap extends SharedHeap {
-    // HeapRegionSeq _seq;
-    static private long hrsFieldOffset;
+    // HeapRegionManager _hrm;
+    static private long hrmFieldOffset;
     // MemRegion _g1_reserved;
     static private long g1ReservedFieldOffset;
     // size_t _summary_bytes_used;
@@ -67,7 +67,7 @@
     static private synchronized void initialize(TypeDataBase db) {
         Type type = db.lookupType("G1CollectedHeap");
 
-        hrsFieldOffset = type.getField("_hrs").getOffset();
+        hrmFieldOffset = type.getField("_hrm").getOffset();
         summaryBytesUsedField = type.getCIntegerField("_summary_bytes_used");
         g1mmField = type.getAddressField("_g1mm");
         oldSetFieldOffset = type.getField("_old_set").getOffset();
@@ -75,7 +75,7 @@
     }
 
     public long capacity() {
-        return hrs().capacity();
+        return hrm().capacity();
     }
 
     public long used() {
@@ -83,13 +83,13 @@
     }
 
     public long n_regions() {
-        return hrs().length();
+        return hrm().length();
     }
 
-    private HeapRegionSeq hrs() {
-        Address hrsAddr = addr.addOffsetTo(hrsFieldOffset);
-        return (HeapRegionSeq) VMObjectFactory.newObject(HeapRegionSeq.class,
-                                                         hrsAddr);
+    private HeapRegionManager hrm() {
+        Address hrmAddr = addr.addOffsetTo(hrmFieldOffset);
+        return (HeapRegionManager) VMObjectFactory.newObject(HeapRegionManager.class,
+                                                         hrmAddr);
     }
 
     public G1MonitoringSupport g1mm() {
@@ -110,7 +110,7 @@
     }
 
     private Iterator<HeapRegion> heapRegionIterator() {
-        return hrs().heapRegionIterator();
+        return hrm().heapRegionIterator();
     }
 
     public void heapRegionIterate(SpaceClosure scl) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc_implementation/g1/HeapRegionManager.java	Wed Jul 05 20:00:03 2017 +0200
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2011, 2014, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package sun.jvm.hotspot.gc_implementation.g1;
+
+import java.util.Iterator;
+import java.util.Observable;
+import java.util.Observer;
+
+import sun.jvm.hotspot.debugger.Address;
+import sun.jvm.hotspot.runtime.VM;
+import sun.jvm.hotspot.runtime.VMObject;
+import sun.jvm.hotspot.runtime.VMObjectFactory;
+import sun.jvm.hotspot.types.AddressField;
+import sun.jvm.hotspot.types.CIntegerField;
+import sun.jvm.hotspot.types.Type;
+import sun.jvm.hotspot.types.TypeDataBase;
+
+// Mirror class for HeapRegionManager.
+
+public class HeapRegionManager extends VMObject {
+    // G1HeapRegionTable _regions
+    static private long regionsFieldOffset;
+    // uint _committed_length
+    static private CIntegerField numCommittedField;
+
+    static {
+        VM.registerVMInitializedObserver(new Observer() {
+                public void update(Observable o, Object data) {
+                    initialize(VM.getVM().getTypeDataBase());
+                }
+            });
+    }
+
+    static private synchronized void initialize(TypeDataBase db) {
+        Type type = db.lookupType("HeapRegionManager");
+
+        regionsFieldOffset = type.getField("_regions").getOffset();
+        numCommittedField = type.getCIntegerField("_num_committed");
+    }
+
+    private G1HeapRegionTable regions() {
+        Address regionsAddr = addr.addOffsetTo(regionsFieldOffset);
+        return (G1HeapRegionTable) VMObjectFactory.newObject(G1HeapRegionTable.class,
+                                                             regionsAddr);
+    }
+
+    public long capacity() {
+        return length() * HeapRegion.grainBytes();
+    }
+
+    public long length() {
+        return regions().length();
+    }
+
+    public long committedLength() {
+        return numCommittedField.getValue(addr);
+    }
+
+    public Iterator<HeapRegion> heapRegionIterator() {
+        return regions().heapRegionIterator(length());
+    }
+
+    public HeapRegionManager(Address addr) {
+        super(addr);
+    }
+}
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc_implementation/g1/HeapRegionSeq.java	Thu Sep 04 14:45:48 2014 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,88 +0,0 @@
-/*
- * Copyright (c) 2011, 2013, 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
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-package sun.jvm.hotspot.gc_implementation.g1;
-
-import java.util.Iterator;
-import java.util.Observable;
-import java.util.Observer;
-
-import sun.jvm.hotspot.debugger.Address;
-import sun.jvm.hotspot.runtime.VM;
-import sun.jvm.hotspot.runtime.VMObject;
-import sun.jvm.hotspot.runtime.VMObjectFactory;
-import sun.jvm.hotspot.types.AddressField;
-import sun.jvm.hotspot.types.CIntegerField;
-import sun.jvm.hotspot.types.Type;
-import sun.jvm.hotspot.types.TypeDataBase;
-
-// Mirror class for HeapRegionSeq. It essentially encapsulates the G1HeapRegionTable.
-
-public class HeapRegionSeq extends VMObject {
-    // G1HeapRegionTable _regions
-    static private long regionsFieldOffset;
-    // uint _committed_length
-    static private CIntegerField numCommittedField;
-
-    static {
-        VM.registerVMInitializedObserver(new Observer() {
-                public void update(Observable o, Object data) {
-                    initialize(VM.getVM().getTypeDataBase());
-                }
-            });
-    }
-
-    static private synchronized void initialize(TypeDataBase db) {
-        Type type = db.lookupType("HeapRegionSeq");
-
-        regionsFieldOffset = type.getField("_regions").getOffset();
-        numCommittedField = type.getCIntegerField("_num_committed");
-    }
-
-    private G1HeapRegionTable regions() {
-        Address regionsAddr = addr.addOffsetTo(regionsFieldOffset);
-        return (G1HeapRegionTable) VMObjectFactory.newObject(G1HeapRegionTable.class,
-                                                             regionsAddr);
-    }
-
-    public long capacity() {
-        return length() * HeapRegion.grainBytes();
-    }
-
-    public long length() {
-        return regions().length();
-    }
-
-    public long committedLength() {
-        return numCommittedField.getValue(addr);
-    }
-
-    public Iterator<HeapRegion> heapRegionIterator() {
-        return regions().heapRegionIterator(length());
-    }
-
-    public HeapRegionSeq(Address addr) {
-        super(addr);
-    }
-}
--- a/hotspot/make/Makefile	Thu Sep 04 14:45:48 2014 -0700
+++ b/hotspot/make/Makefile	Wed Jul 05 20:00:03 2017 +0200
@@ -721,6 +721,19 @@
 	   ($(CD) $(JDK_IMAGE_DIR)/debug && $(TAR) -xf -) ; \
 	fi
 
+copy_optimized_jdk::
+	$(RM) -r $(JDK_IMAGE_DIR)/optimized
+	$(MKDIR) -p $(JDK_IMAGE_DIR)/optimized
+	if [ -d $(JDK_IMPORT_PATH)/optimized ] ; then \
+	  ($(CD) $(JDK_IMPORT_PATH)/optimized && \
+	   $(TAR) -cf - $(JDK_DIRS)) | \
+	   ($(CD) $(JDK_IMAGE_DIR)/optimized && $(TAR) -xf -) ; \
+	else \
+	  ($(CD) $(JDK_IMPORT_PATH) && \
+	   $(TAR) -cf - $(JDK_DIRS)) | \
+	   ($(CD) $(JDK_IMAGE_DIR)/optimized && $(TAR) -xf -) ; \
+	fi
+
 #
 # Check target
 #
--- a/hotspot/make/jprt.gmk	Thu Sep 04 14:45:48 2014 -0700
+++ b/hotspot/make/jprt.gmk	Wed Jul 05 20:00:03 2017 +0200
@@ -42,6 +42,9 @@
 jprt_build_fastdebugEmb:
 	$(MAKE) JAVASE_EMBEDDED=true MINIMIZE_RAM_USAGE=true jprt_build_fastdebug
 
+jprt_build_optimizedEmb:
+	$(MAKE) JAVASE_EMBEDDED=true MINIMIZE_RAM_USAGE=true jprt_build_optimized
+
 jprt_build_productOpen:
 	$(MAKE) OPENJDK=true jprt_build_product
 
@@ -51,6 +54,9 @@
 jprt_build_fastdebugOpen:
 	$(MAKE) OPENJDK=true jprt_build_fastdebug
 
+jprt_build_optimizedOpen:
+	$(MAKE) OPENJDK=true jprt_build_optimized
+
 jprt_build_product: all_product copy_product_jdk export_product_jdk
 	( $(CD) $(JDK_IMAGE_DIR) && \
 	  $(ZIPEXE) $(ZIPFLAGS) -r $(JPRT_ARCHIVE_BUNDLE) . )
@@ -63,5 +69,9 @@
 	( $(CD) $(JDK_IMAGE_DIR)/debug && \
 	  $(ZIPEXE) $(ZIPFLAGS) -r $(JPRT_ARCHIVE_BUNDLE) . )
 
-.PHONY: jprt_build_product jprt_build_fastdebug jprt_build_debug
+jprt_build_optimized: all_optimized copy_optimized_jdk export_optimized_jdk
+	( $(CD) $(JDK_IMAGE_DIR)/optimized && \
+	  $(ZIPEXE) $(ZIPFLAGS) -r $(JPRT_ARCHIVE_BUNDLE) . )
 
+.PHONY: jprt_build_product jprt_build_fastdebug jprt_build_debug jprt_build_optimized
+
--- a/hotspot/make/jprt.properties	Thu Sep 04 14:45:48 2014 -0700
+++ b/hotspot/make/jprt.properties	Wed Jul 05 20:00:03 2017 +0200
@@ -93,13 +93,13 @@
 # Standard list of jprt build targets for this source tree
 
 jprt.build.targets.standard= \
-    ${jprt.my.solaris.sparcv9}-{product|fastdebug|optimized}, \
+    ${jprt.my.solaris.sparcv9}-{product|fastdebug}, \
     ${jprt.my.solaris.x64}-{product|fastdebug}, \
     ${jprt.my.linux.i586}-{product|fastdebug}, \
-    ${jprt.my.linux.x64}-{product|fastdebug|optimized}, \
+    ${jprt.my.linux.x64}-{product|fastdebug}, \
     ${jprt.my.macosx.x64}-{product|fastdebug}, \
     ${jprt.my.windows.i586}-{product|fastdebug}, \
-    ${jprt.my.windows.x64}-{product|fastdebug|optimized}, \
+    ${jprt.my.windows.x64}-{product|fastdebug}, \
     ${jprt.my.linux.armvh}-{product|fastdebug}
 
 jprt.build.targets.open= \
--- a/hotspot/make/windows/makefiles/vm.make	Thu Sep 04 14:45:48 2014 -0700
+++ b/hotspot/make/windows/makefiles/vm.make	Wed Jul 05 20:00:03 2017 +0200
@@ -34,6 +34,9 @@
 CXX_FLAGS=$(CXX_FLAGS) /D "PRODUCT"
 !else
 CXX_FLAGS=$(CXX_FLAGS) /D "ASSERT"
+!if "$(BUILDARCH)" == "amd64"
+CXX_FLAGS=$(CXX_FLAGS) /homeparams
+!endif
 !endif
 
 !if "$(Variant)" == "compiler1"
--- a/hotspot/src/cpu/x86/vm/vm_version_x86.cpp	Thu Sep 04 14:45:48 2014 -0700
+++ b/hotspot/src/cpu/x86/vm/vm_version_x86.cpp	Wed Jul 05 20:00:03 2017 +0200
@@ -604,6 +604,17 @@
 
 #if INCLUDE_RTM_OPT
   if (UseRTMLocking) {
+    if (is_intel_family_core()) {
+      if ((_model == CPU_MODEL_HASWELL_E3) ||
+          (_model == CPU_MODEL_HASWELL_E7 && _stepping < 3) ||
+          (_model == CPU_MODEL_BROADWELL  && _stepping < 4)) {
+        if (!UnlockExperimentalVMOptions) {
+          vm_exit_during_initialization("UseRTMLocking is only available as experimental option on this platform. It must be enabled via -XX:+UnlockExperimentalVMOptions flag.");
+        } else {
+          warning("UseRTMLocking is only available as experimental option on this platform.");
+        }
+      }
+    }
     if (!FLAG_IS_CMDLINE(UseRTMLocking)) {
       // RTM locking should be used only for applications with
       // high lock contention. For now we do not use it by default.
--- a/hotspot/src/cpu/x86/vm/vm_version_x86.hpp	Thu Sep 04 14:45:48 2014 -0700
+++ b/hotspot/src/cpu/x86/vm/vm_version_x86.hpp	Wed Jul 05 20:00:03 2017 +0200
@@ -276,7 +276,10 @@
     CPU_MODEL_WESTMERE_EX    = 0x2f,
     CPU_MODEL_SANDYBRIDGE    = 0x2a,
     CPU_MODEL_SANDYBRIDGE_EP = 0x2d,
-    CPU_MODEL_IVYBRIDGE_EP   = 0x3a
+    CPU_MODEL_IVYBRIDGE_EP   = 0x3a,
+    CPU_MODEL_HASWELL_E3     = 0x3c,
+    CPU_MODEL_HASWELL_E7     = 0x3f,
+    CPU_MODEL_BROADWELL      = 0x3d
   } cpuExtendedFamily;
 
   // cpuid information block.  All info derived from executing cpuid with
--- a/hotspot/src/os/windows/vm/os_windows.cpp	Thu Sep 04 14:45:48 2014 -0700
+++ b/hotspot/src/os/windows/vm/os_windows.cpp	Wed Jul 05 20:00:03 2017 +0200
@@ -135,11 +135,6 @@
       if (ForceTimeHighResolution)
         timeEndPeriod(1L);
 
-      // Workaround for issue when a custom launcher doesn't call
-      // DestroyJavaVM and NMT is trying to track memory when free is
-      // called from a static destructor
-      MemTracker::shutdown();
-
       break;
     default:
       break;
@@ -414,6 +409,8 @@
 
 LONG WINAPI topLevelExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo);
 
+extern jint volatile vm_getting_terminated;
+
 // Thread start routine for all new Java threads
 static unsigned __stdcall java_start(Thread* thread) {
   // Try to randomize the cache line index of hot stack frames.
@@ -435,9 +432,17 @@
     }
   }
 
+  // Diagnostic code to investigate JDK-6573254 (Part I)
+  unsigned res = 90115;  // non-java thread
+  if (thread->is_Java_thread()) {
+    JavaThread* java_thread = (JavaThread*)thread;
+    res = java_lang_Thread::is_daemon(java_thread->threadObj())
+          ? 70115        // java daemon thread
+          : 80115;       // java non-daemon thread
+  }
 
   // Install a win32 structured exception handler around every thread created
-  // by VM, so VM can genrate error dump when an exception occurred in non-
+  // by VM, so VM can generate error dump when an exception occurred in non-
   // Java thread (e.g. VM thread).
   __try {
      thread->run();
@@ -453,6 +458,11 @@
     Atomic::dec_ptr((intptr_t*)&os::win32::_os_thread_count);
   }
 
+  // Diagnostic code to investigate JDK-6573254 (Part II)
+  if (OrderAccess::load_acquire(&vm_getting_terminated)) {
+    return res;
+  }
+
   return 0;
 }
 
--- a/hotspot/src/share/tools/ProjectCreator/BuildConfig.java	Thu Sep 04 14:45:48 2014 -0700
+++ b/hotspot/src/share/tools/ProjectCreator/BuildConfig.java	Wed Jul 05 20:00:03 2017 +0200
@@ -504,7 +504,7 @@
 
         super.init(includes, defines);
 
-        getV("CompilerFlags").addAll(getCI().getDebugCompilerFlags(getOptFlag()));
+        getV("CompilerFlags").addAll(getCI().getDebugCompilerFlags(getOptFlag(), get("PlatformName")));
         getV("LinkerFlags").addAll(getCI().getDebugLinkerFlags());
    }
 }
@@ -619,7 +619,7 @@
 abstract class CompilerInterface {
     abstract Vector getBaseCompilerFlags(Vector defines, Vector includes, String outDir);
     abstract Vector getBaseLinkerFlags(String outDir, String outDll, String platformName);
-    abstract Vector getDebugCompilerFlags(String opt);
+    abstract Vector getDebugCompilerFlags(String opt, String platformName);
     abstract Vector getDebugLinkerFlags();
     abstract void   getAdditionalNonKernelLinkerFlags(Vector rv);
     abstract Vector getProductCompilerFlags();
--- a/hotspot/src/share/tools/ProjectCreator/WinGammaPlatformVC10.java	Thu Sep 04 14:45:48 2014 -0700
+++ b/hotspot/src/share/tools/ProjectCreator/WinGammaPlatformVC10.java	Wed Jul 05 20:00:03 2017 +0200
@@ -357,7 +357,7 @@
     }
 
     @Override
-    Vector getDebugCompilerFlags(String opt) {
+    Vector getDebugCompilerFlags(String opt, String platformName) {
         Vector rv = new Vector();
 
         // Set /On option
@@ -369,6 +369,10 @@
         addAttr(rv, "RuntimeLibrary", "MultiThreadedDLL");
         // Set /Oy- option
         addAttr(rv, "OmitFramePointers", "false");
+        // Set /homeparams for x64 debug builds
+        if(platformName.equals("x64")) {
+            addAttr(rv, "AdditionalOptions", "/homeparams");
+        }
 
         return rv;
     }
--- a/hotspot/src/share/tools/ProjectCreator/WinGammaPlatformVC7.java	Thu Sep 04 14:45:48 2014 -0700
+++ b/hotspot/src/share/tools/ProjectCreator/WinGammaPlatformVC7.java	Wed Jul 05 20:00:03 2017 +0200
@@ -284,7 +284,7 @@
 
    }
 
-   Vector getDebugCompilerFlags(String opt) {
+   Vector getDebugCompilerFlags(String opt, String platformName) {
       Vector rv = new Vector();
 
       getDebugCompilerFlags_common(opt, rv);
--- a/hotspot/src/share/tools/ProjectCreator/WinGammaPlatformVC8.java	Thu Sep 04 14:45:48 2014 -0700
+++ b/hotspot/src/share/tools/ProjectCreator/WinGammaPlatformVC8.java	Wed Jul 05 20:00:03 2017 +0200
@@ -48,7 +48,7 @@
     }
 
 
-    Vector getDebugCompilerFlags(String opt) {
+    Vector getDebugCompilerFlags(String opt, String platformName) {
         Vector rv = new Vector();
 
         getDebugCompilerFlags_common(opt,rv);
--- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp	Thu Sep 04 14:45:48 2014 -0700
+++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp	Wed Jul 05 20:00:03 2017 +0200
@@ -328,9 +328,11 @@
 void ConcurrentMarkSweepGeneration::initialize_performance_counters() {
 
   const char* gen_name = "old";
+  GenCollectorPolicy* gcp = (GenCollectorPolicy*) GenCollectedHeap::heap()->collector_policy();
 
   // Generation Counters - generation 1, 1 subspace
-  _gen_counters = new GenerationCounters(gen_name, 1, 1, &_virtual_space);
+  _gen_counters = new GenerationCounters(gen_name, 1, 1,
+      gcp->min_old_size(), gcp->max_old_size(), &_virtual_space);
 
   _space_counters = new GSpaceCounters(gen_name, 0,
                                        _virtual_space.reserved_size(),
--- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp	Thu Sep 04 14:45:48 2014 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp	Wed Jul 05 20:00:03 2017 +0200
@@ -34,8 +34,8 @@
 #include "gc_implementation/g1/g1OopClosures.inline.hpp"
 #include "gc_implementation/g1/g1RemSet.hpp"
 #include "gc_implementation/g1/heapRegion.inline.hpp"
+#include "gc_implementation/g1/heapRegionManager.inline.hpp"
 #include "gc_implementation/g1/heapRegionRemSet.hpp"
-#include "gc_implementation/g1/heapRegionSeq.inline.hpp"
 #include "gc_implementation/g1/heapRegionSet.inline.hpp"
 #include "gc_implementation/shared/vmGCOperations.hpp"
 #include "gc_implementation/shared/gcTimer.hpp"
@@ -434,10 +434,6 @@
   }
 }
 
-bool ConcurrentMark::not_yet_marked(oop obj) const {
-  return _g1h->is_obj_ill(obj);
-}
-
 CMRootRegions::CMRootRegions() :
   _young_list(NULL), _cm(NULL), _scan_in_progress(false),
   _should_abort(false),  _next_survivor(NULL) { }
@@ -892,7 +888,16 @@
   }
 
   virtual bool doHeapRegion(HeapRegion* r) {
-    return _bitmap->getNextMarkedWordAddress(r->bottom(), r->end()) != r->end();
+    // This closure can be called concurrently to the mutator, so we must make sure
+    // that the result of the getNextMarkedWordAddress() call is compared to the
+    // value passed to it as limit to detect any found bits.
+    // We can use the region's orig_end() for the limit and the comparison value
+    // as it always contains the "real" end of the region that never changes and
+    // has no side effects.
+    // Due to the latter, there can also be no problem with the compiler generating
+    // reloads of the orig_end() call.
+    HeapWord* end = r->orig_end();
+    return _bitmap->getNextMarkedWordAddress(r->bottom(), end) != end;
   }
 };
 
@@ -1117,20 +1122,17 @@
     if (!_cm->has_aborted()) {
       do {
         double start_vtime_sec = os::elapsedVTime();
-        double start_time_sec = os::elapsedTime();
         double mark_step_duration_ms = G1ConcMarkStepDurationMillis;
 
         the_task->do_marking_step(mark_step_duration_ms,
                                   true  /* do_termination */,
                                   false /* is_serial*/);
 
-        double end_time_sec = os::elapsedTime();
         double end_vtime_sec = os::elapsedVTime();
         double elapsed_vtime_sec = end_vtime_sec - start_vtime_sec;
-        double elapsed_time_sec = end_time_sec - start_time_sec;
         _cm->clear_has_overflown();
 
-        bool ret = _cm->do_yield_check(worker_id);
+        _cm->do_yield_check(worker_id);
 
         jlong sleep_time_ms;
         if (!_cm->has_aborted() && the_task->has_aborted()) {
@@ -1140,17 +1142,6 @@
           os::sleep(Thread::current(), sleep_time_ms, false);
           SuspendibleThreadSet::join();
         }
-        double end_time2_sec = os::elapsedTime();
-        double elapsed_time2_sec = end_time2_sec - start_time_sec;
-
-#if 0
-          gclog_or_tty->print_cr("CM: elapsed %1.4lf ms, sleep %1.4lf ms, "
-                                 "overhead %1.4lf",
-                                 elapsed_vtime_sec * 1000.0, (double) sleep_time_ms,
-                                 the_task->conc_overhead(os::elapsedTime()) * 8.0);
-          gclog_or_tty->print_cr("elapsed time %1.4lf ms, time 2: %1.4lf ms",
-                                 elapsed_time_sec * 1000.0, elapsed_time2_sec * 1000.0);
-#endif
       } while (!_cm->has_aborted() && the_task->has_aborted());
     }
     the_task->record_end_time();
@@ -1409,7 +1400,7 @@
   void set_bit_for_region(HeapRegion* hr) {
     assert(!hr->continuesHumongous(), "should have filtered those out");
 
-    BitMap::idx_t index = (BitMap::idx_t) hr->hrs_index();
+    BitMap::idx_t index = (BitMap::idx_t) hr->hrm_index();
     if (!hr->startsHumongous()) {
       // Normal (non-humongous) case: just set the bit.
       _region_bm->par_at_put(index, true);
@@ -1597,7 +1588,7 @@
       if (_verbose) {
         gclog_or_tty->print_cr("Region %u: marked bytes mismatch: "
                                "expected: " SIZE_FORMAT ", actual: " SIZE_FORMAT,
-                               hr->hrs_index(), exp_marked_bytes, act_marked_bytes);
+                               hr->hrm_index(), exp_marked_bytes, act_marked_bytes);
       }
       failures += 1;
     }
@@ -1606,7 +1597,7 @@
     // (which was just calculated) region bit maps.
     // We're not OK if the bit in the calculated expected region
     // bitmap is set and the bit in the actual region bitmap is not.
-    BitMap::idx_t index = (BitMap::idx_t) hr->hrs_index();
+    BitMap::idx_t index = (BitMap::idx_t) hr->hrm_index();
 
     bool expected = _exp_region_bm->at(index);
     bool actual = _region_bm->at(index);
@@ -1614,7 +1605,7 @@
       if (_verbose) {
         gclog_or_tty->print_cr("Region %u: region bitmap mismatch: "
                                "expected: %s, actual: %s",
-                               hr->hrs_index(),
+                               hr->hrm_index(),
                                BOOL_TO_STR(expected), BOOL_TO_STR(actual));
       }
       failures += 1;
@@ -1635,7 +1626,7 @@
         if (_verbose) {
           gclog_or_tty->print_cr("Region %u: card bitmap mismatch at " SIZE_FORMAT ": "
                                  "expected: %s, actual: %s",
-                                 hr->hrs_index(), i,
+                                 hr->hrm_index(), i,
                                  BOOL_TO_STR(expected), BOOL_TO_STR(actual));
         }
         failures += 1;
@@ -2949,11 +2940,6 @@
   _nextMarkBitMap->clearRange(mr);
 }
 
-void ConcurrentMark::clearRangeBothBitmaps(MemRegion mr) {
-  clearRangePrevBitmap(mr);
-  clearRangeNextBitmap(mr);
-}
-
 HeapRegion*
 ConcurrentMark::claim_region(uint worker_id) {
   // "checkpoint" the finger
@@ -3256,7 +3242,7 @@
     assert(limit_idx <= end_idx, "or else use atomics");
 
     // Aggregate the "stripe" in the count data associated with hr.
-    uint hrs_index = hr->hrs_index();
+    uint hrm_index = hr->hrm_index();
     size_t marked_bytes = 0;
 
     for (uint i = 0; i < _max_worker_id; i += 1) {
@@ -3265,7 +3251,7 @@
 
       // Fetch the marked_bytes in this region for task i and
       // add it to the running total for this region.
-      marked_bytes += marked_bytes_array[hrs_index];
+      marked_bytes += marked_bytes_array[hrm_index];
 
       // Now union the bitmaps[0,max_worker_id)[start_idx..limit_idx)
       // into the global card bitmap.
@@ -3499,17 +3485,6 @@
   }
 }
 
-bool ConcurrentMark::containing_card_is_marked(void* p) {
-  size_t offset = pointer_delta(p, _g1h->reserved_region().start(), 1);
-  return _card_bm.at(offset >> CardTableModRefBS::card_shift);
-}
-
-bool ConcurrentMark::containing_cards_are_marked(void* start,
-                                                 void* last) {
-  return containing_card_is_marked(start) &&
-         containing_card_is_marked(last);
-}
-
 #ifndef PRODUCT
 // for debugging purposes
 void ConcurrentMark::print_finger() {
@@ -3762,7 +3737,7 @@
 
   if (_cm->verbose_medium()) {
       gclog_or_tty->print_cr("[%u] regular clock, interval = %1.2lfms, "
-                        "scanned = %d%s, refs reached = %d%s",
+                        "scanned = "SIZE_FORMAT"%s, refs reached = "SIZE_FORMAT"%s",
                         _worker_id, last_interval_ms,
                         _words_scanned,
                         (_words_scanned >= _words_scanned_limit) ? " (*)" : "",
--- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp	Thu Sep 04 14:45:48 2014 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp	Wed Jul 05 20:00:03 2017 +0200
@@ -683,7 +683,9 @@
     return _task_queues->steal(worker_id, hash_seed, obj);
   }
 
-  ConcurrentMark(G1CollectedHeap* g1h, G1RegionToSpaceMapper* prev_bitmap_storage, G1RegionToSpaceMapper* next_bitmap_storage);
+  ConcurrentMark(G1CollectedHeap* g1h,
+                 G1RegionToSpaceMapper* prev_bitmap_storage,
+                 G1RegionToSpaceMapper* next_bitmap_storage);
   ~ConcurrentMark();
 
   ConcurrentMarkThread* cmThread() { return _cmThread; }
@@ -712,8 +714,10 @@
   // inconsistent) and always passing the size. hr is the region that
   // contains the object and it's passed optionally from callers who
   // might already have it (no point in recalculating it).
-  inline void grayRoot(oop obj, size_t word_size,
-                       uint worker_id, HeapRegion* hr = NULL);
+  inline void grayRoot(oop obj,
+                       size_t word_size,
+                       uint worker_id,
+                       HeapRegion* hr = NULL);
 
   // It iterates over the heap and for each object it comes across it
   // will dump the contents of its reference fields, as well as
@@ -734,7 +738,8 @@
   //   AND MARKED : indicates that an object is both explicitly and
   //   implicitly live (it should be one or the other, not both)
   void print_reachable(const char* str,
-                       VerifyOption vo, bool all) PRODUCT_RETURN;
+                       VerifyOption vo,
+                       bool all) PRODUCT_RETURN;
 
   // Clear the next marking bitmap (will be called concurrently).
   void clearNextBitmap();
@@ -771,12 +776,11 @@
   // this carefully!
   inline void markPrev(oop p);
 
-  // Clears marks for all objects in the given range, for the prev,
-  // next, or both bitmaps.  NB: the previous bitmap is usually
+  // Clears marks for all objects in the given range, for the prev or
+  // next bitmaps.  NB: the previous bitmap is usually
   // read-only, so use this carefully!
   void clearRangePrevBitmap(MemRegion mr);
   void clearRangeNextBitmap(MemRegion mr);
-  void clearRangeBothBitmaps(MemRegion mr);
 
   // Notify data structures that a GC has started.
   void note_start_of_gc() {
@@ -798,21 +802,6 @@
                            bool verify_thread_buffers,
                            bool verify_fingers) PRODUCT_RETURN;
 
-  bool isMarked(oop p) const {
-    assert(p != NULL && p->is_oop(), "expected an oop");
-    HeapWord* addr = (HeapWord*)p;
-    assert(addr >= _nextMarkBitMap->startWord() ||
-           addr < _nextMarkBitMap->endWord(), "in a region");
-
-    return _nextMarkBitMap->isMarked(addr);
-  }
-
-  inline bool not_yet_marked(oop p) const;
-
-  // XXX Debug code
-  bool containing_card_is_marked(void* p);
-  bool containing_cards_are_marked(void* start, void* last);
-
   bool isPrevMarked(oop p) const {
     assert(p != NULL && p->is_oop(), "expected an oop");
     HeapWord* addr = (HeapWord*)p;
@@ -898,7 +887,8 @@
   // marked_bytes array slot for the given HeapRegion.
   // Sets the bits in the given card bitmap that are associated with the
   // cards that are spanned by the memory region.
-  inline void count_region(MemRegion mr, HeapRegion* hr,
+  inline void count_region(MemRegion mr,
+                           HeapRegion* hr,
                            size_t* marked_bytes_array,
                            BitMap* task_card_bm);
 
@@ -906,56 +896,27 @@
   // data structures for the given worker id.
   inline void count_region(MemRegion mr, HeapRegion* hr, uint worker_id);
 
-  // Counts the given memory region in the task/worker counting
-  // data structures for the given worker id.
-  inline void count_region(MemRegion mr, uint worker_id);
-
   // Counts the given object in the given task/worker counting
   // data structures.
-  inline void count_object(oop obj, HeapRegion* hr,
+  inline void count_object(oop obj,
+                           HeapRegion* hr,
                            size_t* marked_bytes_array,
                            BitMap* task_card_bm);
 
-  // Counts the given object in the task/worker counting data
-  // structures for the given worker id.
-  inline void count_object(oop obj, HeapRegion* hr, uint worker_id);
-
   // Attempts to mark the given object and, if successful, counts
   // the object in the given task/worker counting structures.
-  inline bool par_mark_and_count(oop obj, HeapRegion* hr,
+  inline bool par_mark_and_count(oop obj,
+                                 HeapRegion* hr,
                                  size_t* marked_bytes_array,
                                  BitMap* task_card_bm);
 
   // Attempts to mark the given object and, if successful, counts
   // the object in the task/worker counting structures for the
   // given worker id.
-  inline bool par_mark_and_count(oop obj, size_t word_size,
-                                 HeapRegion* hr, uint worker_id);
-
-  // Attempts to mark the given object and, if successful, counts
-  // the object in the task/worker counting structures for the
-  // given worker id.
-  inline bool par_mark_and_count(oop obj, HeapRegion* hr, uint worker_id);
-
-  // Similar to the above routine but we don't know the heap region that
-  // contains the object to be marked/counted, which this routine looks up.
-  inline bool par_mark_and_count(oop obj, uint worker_id);
-
-  // Similar to the above routine but there are times when we cannot
-  // safely calculate the size of obj due to races and we, therefore,
-  // pass the size in as a parameter. It is the caller's responsibility
-  // to ensure that the size passed in for obj is valid.
-  inline bool par_mark_and_count(oop obj, size_t word_size, uint worker_id);
-
-  // Unconditionally mark the given object, and unconditionally count
-  // the object in the counting structures for worker id 0.
-  // Should *not* be called from parallel code.
-  inline bool mark_and_count(oop obj, HeapRegion* hr);
-
-  // Similar to the above routine but we don't know the heap region that
-  // contains the object to be marked/counted, which this routine looks up.
-  // Should *not* be called from parallel code.
-  inline bool mark_and_count(oop obj);
+  inline bool par_mark_and_count(oop obj,
+                                 size_t word_size,
+                                 HeapRegion* hr,
+                                 uint worker_id);
 
   // Returns true if initialization was successfully completed.
   bool completed_initialization() const {
@@ -1227,9 +1188,12 @@
     _finger = new_finger;
   }
 
-  CMTask(uint worker_id, ConcurrentMark *cm,
-         size_t* marked_bytes, BitMap* card_bm,
-         CMTaskQueue* task_queue, CMTaskQueueSet* task_queues);
+  CMTask(uint worker_id,
+         ConcurrentMark *cm,
+         size_t* marked_bytes,
+         BitMap* card_bm,
+         CMTaskQueue* task_queue,
+         CMTaskQueueSet* task_queues);
 
   // it prints statistics associated with this task
   void print_stats();
--- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.inline.hpp	Thu Sep 04 14:45:48 2014 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.inline.hpp	Wed Jul 05 20:00:03 2017 +0200
@@ -86,7 +86,7 @@
   HeapWord* start = mr.start();
   HeapWord* end = mr.end();
   size_t region_size_bytes = mr.byte_size();
-  uint index = hr->hrs_index();
+  uint index = hr->hrm_index();
 
   assert(!hr->continuesHumongous(), "should not be HC region");
   assert(hr == g1h->heap_region_containing(start), "sanity");
@@ -125,14 +125,6 @@
   count_region(mr, hr, marked_bytes_array, task_card_bm);
 }
 
-// Counts the given memory region, which may be a single object, in the
-// task/worker counting data structures for the given worker id.
-inline void ConcurrentMark::count_region(MemRegion mr, uint worker_id) {
-  HeapWord* addr = mr.start();
-  HeapRegion* hr = _g1h->heap_region_containing_raw(addr);
-  count_region(mr, hr, worker_id);
-}
-
 // Counts the given object in the given task/worker counting data structures.
 inline void ConcurrentMark::count_object(oop obj,
                                          HeapRegion* hr,
@@ -142,17 +134,6 @@
   count_region(mr, hr, marked_bytes_array, task_card_bm);
 }
 
-// Counts the given object in the task/worker counting data
-// structures for the given worker id.
-inline void ConcurrentMark::count_object(oop obj,
-                                         HeapRegion* hr,
-                                         uint worker_id) {
-  size_t* marked_bytes_array = count_marked_bytes_array_for(worker_id);
-  BitMap* task_card_bm = count_card_bitmap_for(worker_id);
-  HeapWord* addr = (HeapWord*) obj;
-  count_object(obj, hr, marked_bytes_array, task_card_bm);
-}
-
 // Attempts to mark the given object and, if successful, counts
 // the object in the given task/worker counting structures.
 inline bool ConcurrentMark::par_mark_and_count(oop obj,
@@ -184,63 +165,6 @@
   return false;
 }
 
-// Attempts to mark the given object and, if successful, counts
-// the object in the task/worker counting structures for the
-// given worker id.
-inline bool ConcurrentMark::par_mark_and_count(oop obj,
-                                               HeapRegion* hr,
-                                               uint worker_id) {
-  HeapWord* addr = (HeapWord*)obj;
-  if (_nextMarkBitMap->parMark(addr)) {
-    // Update the task specific count data for the object.
-    count_object(obj, hr, worker_id);
-    return true;
-  }
-  return false;
-}
-
-// As above - but we don't know the heap region containing the
-// object and so have to supply it.
-inline bool ConcurrentMark::par_mark_and_count(oop obj, uint worker_id) {
-  HeapWord* addr = (HeapWord*)obj;
-  HeapRegion* hr = _g1h->heap_region_containing_raw(addr);
-  return par_mark_and_count(obj, hr, worker_id);
-}
-
-// Similar to the above routine but we already know the size, in words, of
-// the object that we wish to mark/count
-inline bool ConcurrentMark::par_mark_and_count(oop obj,
-                                               size_t word_size,
-                                               uint worker_id) {
-  HeapWord* addr = (HeapWord*)obj;
-  if (_nextMarkBitMap->parMark(addr)) {
-    // Update the task specific count data for the object.
-    MemRegion mr(addr, word_size);
-    count_region(mr, worker_id);
-    return true;
-  }
-  return false;
-}
-
-// Unconditionally mark the given object, and unconditionally count
-// the object in the counting structures for worker id 0.
-// Should *not* be called from parallel code.
-inline bool ConcurrentMark::mark_and_count(oop obj, HeapRegion* hr) {
-  HeapWord* addr = (HeapWord*)obj;
-  _nextMarkBitMap->mark(addr);
-  // Update the task specific count data for the object.
-  count_object(obj, hr, 0 /* worker_id */);
-  return true;
-}
-
-// As above - but we don't have the heap region containing the
-// object, so we have to supply it.
-inline bool ConcurrentMark::mark_and_count(oop obj) {
-  HeapWord* addr = (HeapWord*)obj;
-  HeapRegion* hr = _g1h->heap_region_containing_raw(addr);
-  return mark_and_count(obj, hr);
-}
-
 inline bool CMBitMapRO::iterate(BitMapClosure* cl, MemRegion mr) {
   HeapWord* start_addr = MAX2(startWord(), mr.start());
   HeapWord* end_addr = MIN2(endWord(), mr.end());
--- a/hotspot/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.cpp	Thu Sep 04 14:45:48 2014 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.cpp	Wed Jul 05 20:00:03 2017 +0200
@@ -30,14 +30,7 @@
 #include "runtime/java.hpp"
 #include "services/memTracker.hpp"
 
-PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC
 
-void G1BlockOffsetSharedArrayMappingChangedListener::on_commit(uint start_idx, size_t num_regions) {
-  // Nothing to do. The BOT is hard-wired to be part of the HeapRegion, and we cannot
-  // retrieve it here since this would cause firing of several asserts. The code
-  // executed after commit of a region already needs to do some re-initialization of
-  // the HeapRegion, so we combine that.
-}
 
 //////////////////////////////////////////////////////////////////////
 // G1BlockOffsetSharedArray
@@ -59,10 +52,10 @@
   if (TraceBlockOffsetTable) {
     gclog_or_tty->print_cr("G1BlockOffsetSharedArray::G1BlockOffsetSharedArray: ");
     gclog_or_tty->print_cr("  "
-                  "  rs.base(): " INTPTR_FORMAT
-                  "  rs.size(): " INTPTR_FORMAT
-                  "  rs end(): " INTPTR_FORMAT,
-                  bot_reserved.start(), bot_reserved.byte_size(), bot_reserved.end());
+                  "  rs.base(): " PTR_FORMAT
+                  "  rs.size(): " SIZE_FORMAT
+                  "  rs end(): " PTR_FORMAT,
+                  p2i(bot_reserved.start()), bot_reserved.byte_size(), p2i(bot_reserved.end()));
   }
 }
 
@@ -72,26 +65,16 @@
   return (delta & right_n_bits(LogN_words)) == (size_t)NoBits;
 }
 
-void G1BlockOffsetSharedArray::set_offset_array(HeapWord* left, HeapWord* right, u_char offset) {
-  set_offset_array(index_for(left), index_for(right -1), offset);
-}
-
 //////////////////////////////////////////////////////////////////////
 // G1BlockOffsetArray
 //////////////////////////////////////////////////////////////////////
 
 G1BlockOffsetArray::G1BlockOffsetArray(G1BlockOffsetSharedArray* array,
-                                       MemRegion mr, bool init_to_zero) :
+                                       MemRegion mr) :
   G1BlockOffsetTable(mr.start(), mr.end()),
   _unallocated_block(_bottom),
-  _array(array), _gsp(NULL),
-  _init_to_zero(init_to_zero) {
+  _array(array), _gsp(NULL) {
   assert(_bottom <= _end, "arguments out of order");
-  if (!_init_to_zero) {
-    // initialize cards to point back to mr.start()
-    set_remainder_to_point_to_start(mr.start() + N_words, mr.end());
-    _array->set_offset_array(0, 0);  // set first card to 0
-  }
 }
 
 void G1BlockOffsetArray::set_space(G1OffsetTableContigSpace* sp) {
@@ -181,93 +164,6 @@
   DEBUG_ONLY(check_all_cards(start_card, end_card);)
 }
 
-// The block [blk_start, blk_end) has been allocated;
-// adjust the block offset table to represent this information;
-// right-open interval: [blk_start, blk_end)
-void
-G1BlockOffsetArray::alloc_block(HeapWord* blk_start, HeapWord* blk_end) {
-  mark_block(blk_start, blk_end);
-  allocated(blk_start, blk_end);
-}
-
-// Adjust BOT to show that a previously whole block has been split
-// into two.
-void G1BlockOffsetArray::split_block(HeapWord* blk, size_t blk_size,
-                                     size_t left_blk_size) {
-  // Verify that the BOT shows [blk, blk + blk_size) to be one block.
-  verify_single_block(blk, blk_size);
-  // Update the BOT to indicate that [blk + left_blk_size, blk + blk_size)
-  // is one single block.
-  mark_block(blk + left_blk_size, blk + blk_size);
-}
-
-
-// Action_mark - update the BOT for the block [blk_start, blk_end).
-//               Current typical use is for splitting a block.
-// Action_single - update the BOT for an allocation.
-// Action_verify - BOT verification.
-void G1BlockOffsetArray::do_block_internal(HeapWord* blk_start,
-                                           HeapWord* blk_end,
-                                           Action action) {
-  assert(Universe::heap()->is_in_reserved(blk_start),
-         "reference must be into the heap");
-  assert(Universe::heap()->is_in_reserved(blk_end-1),
-         "limit must be within the heap");
-  // This is optimized to make the test fast, assuming we only rarely
-  // cross boundaries.
-  uintptr_t end_ui = (uintptr_t)(blk_end - 1);
-  uintptr_t start_ui = (uintptr_t)blk_start;
-  // Calculate the last card boundary preceding end of blk
-  intptr_t boundary_before_end = (intptr_t)end_ui;
-  clear_bits(boundary_before_end, right_n_bits(LogN));
-  if (start_ui <= (uintptr_t)boundary_before_end) {
-    // blk starts at or crosses a boundary
-    // Calculate index of card on which blk begins
-    size_t    start_index = _array->index_for(blk_start);
-    // Index of card on which blk ends
-    size_t    end_index   = _array->index_for(blk_end - 1);
-    // Start address of card on which blk begins
-    HeapWord* boundary    = _array->address_for_index(start_index);
-    assert(boundary <= blk_start, "blk should start at or after boundary");
-    if (blk_start != boundary) {
-      // blk starts strictly after boundary
-      // adjust card boundary and start_index forward to next card
-      boundary += N_words;
-      start_index++;
-    }
-    assert(start_index <= end_index, "monotonicity of index_for()");
-    assert(boundary <= (HeapWord*)boundary_before_end, "tautology");
-    switch (action) {
-      case Action_mark: {
-        if (init_to_zero()) {
-          _array->set_offset_array(start_index, boundary, blk_start);
-          break;
-        } // Else fall through to the next case
-      }
-      case Action_single: {
-        _array->set_offset_array(start_index, boundary, blk_start);
-        // We have finished marking the "offset card". We need to now
-        // mark the subsequent cards that this blk spans.
-        if (start_index < end_index) {
-          HeapWord* rem_st = _array->address_for_index(start_index) + N_words;
-          HeapWord* rem_end = _array->address_for_index(end_index) + N_words;
-          set_remainder_to_point_to_start(rem_st, rem_end);
-        }
-        break;
-      }
-      case Action_check: {
-        _array->check_offset_array(start_index, boundary, blk_start);
-        // We have finished checking the "offset card". We need to now
-        // check the subsequent cards that this blk spans.
-        check_all_cards(start_index + 1, end_index);
-        break;
-      }
-      default:
-        ShouldNotReachHere();
-    }
-  }
-}
-
 // The card-interval [start_card, end_card] is a closed interval; this
 // is an expensive check -- use with care and only under protection of
 // suitable flag.
@@ -306,25 +202,6 @@
   }
 }
 
-// The range [blk_start, blk_end) represents a single contiguous block
-// of storage; modify the block offset table to represent this
-// information; Right-open interval: [blk_start, blk_end)
-// NOTE: this method does _not_ adjust _unallocated_block.
-void
-G1BlockOffsetArray::single_block(HeapWord* blk_start, HeapWord* blk_end) {
-  do_block_internal(blk_start, blk_end, Action_single);
-}
-
-// Mark the BOT such that if [blk_start, blk_end) straddles a card
-// boundary, the card following the first such boundary is marked
-// with the appropriate offset.
-// NOTE: this method does _not_ adjust _unallocated_block or
-// any cards subsequent to the first one.
-void
-G1BlockOffsetArray::mark_block(HeapWord* blk_start, HeapWord* blk_end) {
-  do_block_internal(blk_start, blk_end, Action_mark);
-}
-
 HeapWord* G1BlockOffsetArray::block_start_unsafe(const void* addr) {
   assert(_bottom <= addr && addr < _end,
          "addr must be covered by this Array");
@@ -381,7 +258,7 @@
   assert(next_boundary <= _array->_end,
          err_msg("next_boundary is beyond the end of the covered region "
                  " next_boundary " PTR_FORMAT " _array->_end " PTR_FORMAT,
-                 next_boundary, _array->_end));
+                 p2i(next_boundary), p2i(_array->_end)));
   if (addr >= gsp()->top()) return gsp()->top();
   while (next_boundary < addr) {
     while (n <= next_boundary) {
@@ -397,57 +274,13 @@
   return forward_to_block_containing_addr_const(q, n, addr);
 }
 
-HeapWord* G1BlockOffsetArray::block_start_careful(const void* addr) const {
-  assert(_array->offset_array(0) == 0, "objects can't cross covered areas");
-
-  assert(_bottom <= addr && addr < _end,
-         "addr must be covered by this Array");
-  // Must read this exactly once because it can be modified by parallel
-  // allocation.
-  HeapWord* ub = _unallocated_block;
-  if (BlockOffsetArrayUseUnallocatedBlock && addr >= ub) {
-    assert(ub < _end, "tautology (see above)");
-    return ub;
-  }
-
-  // Otherwise, find the block start using the table, but taking
-  // care (cf block_start_unsafe() above) not to parse any objects/blocks
-  // on the cards themselves.
-  size_t index = _array->index_for(addr);
-  assert(_array->address_for_index(index) == addr,
-         "arg should be start of card");
-
-  HeapWord* q = (HeapWord*)addr;
-  uint offset;
-  do {
-    offset = _array->offset_array(index--);
-    q -= offset;
-  } while (offset == N_words);
-  assert(q <= addr, "block start should be to left of arg");
-  return q;
-}
-
 // Note that the committed size of the covered space may have changed,
 // so the table size might also wish to change.
 void G1BlockOffsetArray::resize(size_t new_word_size) {
   HeapWord* new_end = _bottom + new_word_size;
-  if (_end < new_end && !init_to_zero()) {
-    // verify that the old and new boundaries are also card boundaries
-    assert(_array->is_card_boundary(_end),
-           "_end not a card boundary");
-    assert(_array->is_card_boundary(new_end),
-           "new _end would not be a card boundary");
-    // set all the newly added cards
-    _array->set_offset_array(_end, new_end, N_words);
-  }
   _end = new_end;  // update _end
 }
 
-void G1BlockOffsetArray::set_region(MemRegion mr) {
-  _bottom = mr.start();
-  _end = mr.end();
-}
-
 //
 //              threshold_
 //              |   _index_
@@ -522,7 +355,7 @@
                   "blk_start: " PTR_FORMAT ", "
                   "boundary: " PTR_FORMAT,
                   (uint)_array->offset_array(orig_index),
-                  blk_start, boundary));
+                  p2i(blk_start), p2i(boundary)));
   for (size_t j = orig_index + 1; j <= end_index; j++) {
     assert(_array->offset_array(j) > 0 &&
            _array->offset_array(j) <=
@@ -556,9 +389,9 @@
                              "card addr: "PTR_FORMAT" BOT entry: %u "
                              "obj: "PTR_FORMAT" word size: "SIZE_FORMAT" "
                              "cards: ["SIZE_FORMAT","SIZE_FORMAT"]",
-                             block_start, card, card_addr,
+                             p2i(block_start), card, p2i(card_addr),
                              _array->offset_array(card),
-                             obj_start, word_size, first_card, last_card);
+                             p2i(obj_start), word_size, first_card, last_card);
       return false;
     }
   }
@@ -572,10 +405,10 @@
   size_t to_index = _array->index_for(_end);
   out->print_cr(">> BOT for area ["PTR_FORMAT","PTR_FORMAT") "
                 "cards ["SIZE_FORMAT","SIZE_FORMAT")",
-                _bottom, _end, from_index, to_index);
+                p2i(_bottom), p2i(_end), from_index, to_index);
   for (size_t i = from_index; i < to_index; ++i) {
     out->print_cr("  entry "SIZE_FORMAT_W(8)" | "PTR_FORMAT" : %3u",
-                  i, _array->address_for_index(i),
+                  i, p2i(_array->address_for_index(i)),
                   (uint) _array->offset_array(i));
   }
 }
@@ -606,7 +439,7 @@
 G1BlockOffsetArrayContigSpace::
 G1BlockOffsetArrayContigSpace(G1BlockOffsetSharedArray* array,
                               MemRegion mr) :
-  G1BlockOffsetArray(array, mr, true)
+  G1BlockOffsetArray(array, mr)
 {
   _next_offset_threshold = NULL;
   _next_offset_index = 0;
@@ -641,15 +474,6 @@
   return _next_offset_threshold;
 }
 
-void G1BlockOffsetArrayContigSpace::zero_bottom_entry() {
-  assert(!Universe::heap()->is_in_reserved(_array->_offset_array),
-         "just checking");
-  size_t bottom_index = _array->index_for(_bottom);
-  assert(_array->address_for_index(bottom_index) == _bottom,
-         "Precondition of call");
-  _array->set_offset_array(bottom_index, 0);
-}
-
 void
 G1BlockOffsetArrayContigSpace::set_for_starts_humongous(HeapWord* new_top) {
   assert(new_top <= _end, "_end should have already been updated");
@@ -663,7 +487,7 @@
 void
 G1BlockOffsetArrayContigSpace::print_on(outputStream* out) {
   G1BlockOffsetArray::print_on(out);
-  out->print_cr("  next offset threshold: "PTR_FORMAT, _next_offset_threshold);
+  out->print_cr("  next offset threshold: "PTR_FORMAT, p2i(_next_offset_threshold));
   out->print_cr("  next offset index:     "SIZE_FORMAT, _next_offset_index);
 }
 #endif // !PRODUCT
--- a/hotspot/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.hpp	Thu Sep 04 14:45:48 2014 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.hpp	Wed Jul 05 20:00:03 2017 +0200
@@ -109,7 +109,12 @@
 
 class G1BlockOffsetSharedArrayMappingChangedListener : public G1MappingChangedListener {
  public:
-  virtual void on_commit(uint start_idx, size_t num_regions);
+  virtual void on_commit(uint start_idx, size_t num_regions) {
+    // Nothing to do. The BOT is hard-wired to be part of the HeapRegion, and we cannot
+    // retrieve it here since this would cause firing of several asserts. The code
+    // executed after commit of a region already needs to do some re-initialization of
+    // the HeapRegion, so we combine that.
+  }
 };
 
 // This implementation of "G1BlockOffsetTable" divides the covered region
@@ -153,8 +158,6 @@
   // For performance these have to devolve to array accesses in product builds.
   inline u_char offset_array(size_t index) const;
 
-  void set_offset_array(HeapWord* left, HeapWord* right, u_char offset);
-
   void set_offset_array_raw(size_t index, u_char offset) {
     _offset_array[index] = offset;
   }
@@ -165,8 +168,6 @@
 
   inline void set_offset_array(size_t left, size_t right, u_char offset);
 
-  inline void check_offset_array(size_t index, HeapWord* high, HeapWord* low) const;
-
   bool is_card_boundary(HeapWord* p) const;
 
 public:
@@ -193,8 +194,6 @@
   // G1BlockOffsetTable(s) to initialize cards.
   G1BlockOffsetSharedArray(MemRegion heap, G1RegionToSpaceMapper* storage);
 
-  void set_bottom(HeapWord* new_bottom);
-
   // Return the appropriate index into "_offset_array" for "p".
   inline size_t index_for(const void* p) const;
   inline size_t index_for_raw(const void* p) const;
@@ -220,14 +219,6 @@
     LogN    = G1BlockOffsetSharedArray::LogN
   };
 
-  // The following enums are used by do_block_helper
-  enum Action {
-    Action_single,      // BOT records a single block (see single_block())
-    Action_mark,        // BOT marks the start of a block (see mark_block())
-    Action_check        // Check that BOT records block correctly
-                        // (see verify_single_block()).
-  };
-
   // This is the array, which can be shared by several BlockOffsetArray's
   // servicing different
   G1BlockOffsetSharedArray* _array;
@@ -235,10 +226,6 @@
   // The space that owns this subregion.
   G1OffsetTableContigSpace* _gsp;
 
-  // If true, array entries are initialized to 0; otherwise, they are
-  // initialized to point backwards to the beginning of the covered region.
-  bool _init_to_zero;
-
   // The portion [_unallocated_block, _sp.end()) of the space that
   // is a single block known not to contain any objects.
   // NOTE: See BlockOffsetArrayUseUnallocatedBlock flag.
@@ -253,9 +240,6 @@
   // that is closed: [start_index, end_index]
   void set_remainder_to_point_to_start_incl(size_t start, size_t end);
 
-  // A helper function for BOT adjustment/verification work
-  void do_block_internal(HeapWord* blk_start, HeapWord* blk_end, Action action);
-
 protected:
 
   G1OffsetTableContigSpace* gsp() const { return _gsp; }
@@ -303,11 +287,9 @@
 
 public:
   // The space may not have it's bottom and top set yet, which is why the
-  // region is passed as a parameter.  If "init_to_zero" is true, the
-  // elements of the array are initialized to zero.  Otherwise, they are
-  // initialized to point backwards to the beginning.
-  G1BlockOffsetArray(G1BlockOffsetSharedArray* array, MemRegion mr,
-                     bool init_to_zero);
+  // region is passed as a parameter. The elements of the array are
+  // initialized to zero.
+  G1BlockOffsetArray(G1BlockOffsetSharedArray* array, MemRegion mr);
 
   // Note: this ought to be part of the constructor, but that would require
   // "this" to be passed as a parameter to a member constructor for
@@ -315,114 +297,19 @@
   // This would be legal C++, but MS VC++ doesn't allow it.
   void set_space(G1OffsetTableContigSpace* sp);
 
-  // Resets the covered region to the given "mr".
-  void set_region(MemRegion mr);
-
   // Resets the covered region to one with the same _bottom as before but
   // the "new_word_size".
   void resize(size_t new_word_size);
 
-  // These must be guaranteed to work properly (i.e., do nothing)
-  // when "blk_start" ("blk" for second version) is "NULL".
-  virtual void alloc_block(HeapWord* blk_start, HeapWord* blk_end);
-  virtual void alloc_block(HeapWord* blk, size_t size) {
-    alloc_block(blk, blk + size);
-  }
-
-  // The following methods are useful and optimized for a
-  // general, non-contiguous space.
-
-  // Given a block [blk_start, blk_start + full_blk_size), and
-  // a left_blk_size < full_blk_size, adjust the BOT to show two
-  // blocks [blk_start, blk_start + left_blk_size) and
-  // [blk_start + left_blk_size, blk_start + full_blk_size).
-  // It is assumed (and verified in the non-product VM) that the
-  // BOT was correct for the original block.
-  void split_block(HeapWord* blk_start, size_t full_blk_size,
-                           size_t left_blk_size);
-
-  // Adjust the BOT to show that it has a single block in the
-  // range [blk_start, blk_start + size). All necessary BOT
-  // cards are adjusted, but _unallocated_block isn't.
-  void single_block(HeapWord* blk_start, HeapWord* blk_end);
-  void single_block(HeapWord* blk, size_t size) {
-    single_block(blk, blk + size);
-  }
-
-  // Adjust BOT to show that it has a block in the range
-  // [blk_start, blk_start + size). Only the first card
-  // of BOT is touched. It is assumed (and verified in the
-  // non-product VM) that the remaining cards of the block
-  // are correct.
-  void mark_block(HeapWord* blk_start, HeapWord* blk_end);
-  void mark_block(HeapWord* blk, size_t size) {
-    mark_block(blk, blk + size);
-  }
-
-  // Adjust _unallocated_block to indicate that a particular
-  // block has been newly allocated or freed. It is assumed (and
-  // verified in the non-product VM) that the BOT is correct for
-  // the given block.
-  inline void allocated(HeapWord* blk_start, HeapWord* blk_end) {
-    // Verify that the BOT shows [blk, blk + blk_size) to be one block.
-    verify_single_block(blk_start, blk_end);
-    if (BlockOffsetArrayUseUnallocatedBlock) {
-      _unallocated_block = MAX2(_unallocated_block, blk_end);
-    }
-  }
-
-  inline void allocated(HeapWord* blk, size_t size) {
-    allocated(blk, blk + size);
-  }
-
-  inline void freed(HeapWord* blk_start, HeapWord* blk_end);
-
-  inline void freed(HeapWord* blk, size_t size);
-
   virtual HeapWord* block_start_unsafe(const void* addr);
   virtual HeapWord* block_start_unsafe_const(const void* addr) const;
 
-  // Requires "addr" to be the start of a card and returns the
-  // start of the block that contains the given address.
-  HeapWord* block_start_careful(const void* addr) const;
-
-  // If true, initialize array slots with no allocated blocks to zero.
-  // Otherwise, make them point back to the front.
-  bool init_to_zero() { return _init_to_zero; }
-
-  // Verification & debugging - ensure that the offset table reflects the fact
-  // that the block [blk_start, blk_end) or [blk, blk + size) is a
-  // single block of storage. NOTE: can;t const this because of
-  // call to non-const do_block_internal() below.
-  inline void verify_single_block(HeapWord* blk_start, HeapWord* blk_end) {
-    if (VerifyBlockOffsetArray) {
-      do_block_internal(blk_start, blk_end, Action_check);
-    }
-  }
-
-  inline void verify_single_block(HeapWord* blk, size_t size) {
-    verify_single_block(blk, blk + size);
-  }
-
   // Used by region verification. Checks that the contents of the
   // BOT reflect that there's a single object that spans the address
   // range [obj_start, obj_start + word_size); returns true if this is
   // the case, returns false if it's not.
   bool verify_for_object(HeapWord* obj_start, size_t word_size) const;
 
-  // Verify that the given block is before _unallocated_block
-  inline void verify_not_unallocated(HeapWord* blk_start,
-                                     HeapWord* blk_end) const {
-    if (BlockOffsetArrayUseUnallocatedBlock) {
-      assert(blk_start < blk_end, "Block inconsistency?");
-      assert(blk_end <= _unallocated_block, "_unallocated_block problem");
-    }
-  }
-
-  inline void verify_not_unallocated(HeapWord* blk, size_t size) const {
-    verify_not_unallocated(blk, blk + size);
-  }
-
   void check_all_cards(size_t left_card, size_t right_card) const;
 
   virtual void print_on(outputStream* out) PRODUCT_RETURN;
@@ -445,14 +332,12 @@
                       blk_start, blk_end);
   }
 
-  // Variant of zero_bottom_entry that does not check for availability of the
+  // Zero out the entry for _bottom (offset will be zero). Does not check for availability of the
   // memory first.
   void zero_bottom_entry_raw();
   // Variant of initialize_threshold that does not check for availability of the
   // memory first.
   HeapWord* initialize_threshold_raw();
-  // Zero out the entry for _bottom (offset will be zero).
-  void zero_bottom_entry();
  public:
   G1BlockOffsetArrayContigSpace(G1BlockOffsetSharedArray* array, MemRegion mr);
 
--- a/hotspot/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.inline.hpp	Thu Sep 04 14:45:48 2014 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.inline.hpp	Wed Jul 05 20:00:03 2017 +0200
@@ -91,13 +91,6 @@
   }
 }
 
-void G1BlockOffsetSharedArray::check_offset_array(size_t index, HeapWord* high, HeapWord* low) const {
-  check_index(index, "index out of range");
-  assert(high >= low, "addresses out of order");
-  check_offset(pointer_delta(high, low), "offset too large");
-  assert(_offset_array[index] == pointer_delta(high, low), "Wrong offset");
-}
-
 // Variant of index_for that does not check the index for validity.
 inline size_t G1BlockOffsetSharedArray::index_for_raw(const void* p) const {
   return pointer_delta((char*)p, _reserved.start(), sizeof(char)) >> LogN;
@@ -193,28 +186,4 @@
   return q;
 }
 
-//////////////////////////////////////////////////////////////////////////
-// BlockOffsetArrayNonContigSpace inlines
-//////////////////////////////////////////////////////////////////////////
-inline void G1BlockOffsetArray::freed(HeapWord* blk_start, HeapWord* blk_end) {
-  // Verify that the BOT shows [blk_start, blk_end) to be one block.
-  verify_single_block(blk_start, blk_end);
-  // adjust _unallocated_block upward or downward
-  // as appropriate
-  if (BlockOffsetArrayUseUnallocatedBlock) {
-    assert(_unallocated_block <= _end,
-           "Inconsistent value for _unallocated_block");
-    if (blk_end >= _unallocated_block && blk_start <= _unallocated_block) {
-      // CMS-specific note: a block abutting _unallocated_block to
-      // its left is being freed, a new block is being added or
-      // we are resetting following a compaction
-      _unallocated_block = blk_start;
-    }
-  }
-}
-
-inline void G1BlockOffsetArray::freed(HeapWord* blk, size_t size) {
-  freed(blk, blk + size);
-}
-
 #endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1BLOCKOFFSETTABLE_INLINE_HPP
--- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp	Thu Sep 04 14:45:48 2014 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp	Wed Jul 05 20:00:03 2017 +0200
@@ -532,9 +532,9 @@
       // again to allocate from it.
       append_secondary_free_list();
 
-      assert(_hrs.num_free_regions() > 0, "if the secondary_free_list was not "
+      assert(_hrm.num_free_regions() > 0, "if the secondary_free_list was not "
              "empty we should have moved at least one entry to the free_list");
-      HeapRegion* res = _hrs.allocate_free_region(is_old);
+      HeapRegion* res = _hrm.allocate_free_region(is_old);
       if (G1ConcRegionFreeingVerbose) {
         gclog_or_tty->print_cr("G1ConcRegionFreeing [region alloc] : "
                                "allocated "HR_FORMAT" from secondary_free_list",
@@ -575,7 +575,7 @@
     }
   }
 
-  res = _hrs.allocate_free_region(is_old);
+  res = _hrm.allocate_free_region(is_old);
 
   if (res == NULL) {
     if (G1ConcRegionFreeingVerbose) {
@@ -601,7 +601,7 @@
       // always expand the heap by an amount aligned to the heap
       // region size, the free list should in theory not be empty.
       // In either case allocate_free_region() will check for NULL.
-      res = _hrs.allocate_free_region(is_old);
+      res = _hrm.allocate_free_region(is_old);
     } else {
       _expand_heap_after_alloc_failure = false;
     }
@@ -613,7 +613,7 @@
 G1CollectedHeap::humongous_obj_allocate_initialize_regions(uint first,
                                                            uint num_regions,
                                                            size_t word_size) {
-  assert(first != G1_NO_HRS_INDEX, "pre-condition");
+  assert(first != G1_NO_HRM_INDEX, "pre-condition");
   assert(isHumongous(word_size), "word_size should be humongous");
   assert(num_regions * HeapRegion::GrainWords >= word_size, "pre-condition");
 
@@ -751,7 +751,7 @@
 
   verify_region_sets_optional();
 
-  uint first = G1_NO_HRS_INDEX;
+  uint first = G1_NO_HRM_INDEX;
   uint obj_regions = (uint)(align_size_up_(word_size, HeapRegion::GrainWords) / HeapRegion::GrainWords);
 
   if (obj_regions == 1) {
@@ -760,7 +760,7 @@
     // later.
     HeapRegion* hr = new_region(word_size, true /* is_old */, false /* do_expand */);
     if (hr != NULL) {
-      first = hr->hrs_index();
+      first = hr->hrm_index();
     }
   } else {
     // We can't allocate humongous regions spanning more than one region while
@@ -776,18 +776,18 @@
 
     // Policy: Try only empty regions (i.e. already committed first). Maybe we
     // are lucky enough to find some.
-    first = _hrs.find_contiguous_only_empty(obj_regions);
-    if (first != G1_NO_HRS_INDEX) {
-      _hrs.allocate_free_regions_starting_at(first, obj_regions);
-    }
-  }
-
-  if (first == G1_NO_HRS_INDEX) {
+    first = _hrm.find_contiguous_only_empty(obj_regions);
+    if (first != G1_NO_HRM_INDEX) {
+      _hrm.allocate_free_regions_starting_at(first, obj_regions);
+    }
+  }
+
+  if (first == G1_NO_HRM_INDEX) {
     // Policy: We could not find enough regions for the humongous object in the
     // free list. Look through the heap to find a mix of free and uncommitted regions.
     // If so, try expansion.
-    first = _hrs.find_contiguous_empty_or_unavailable(obj_regions);
-    if (first != G1_NO_HRS_INDEX) {
+    first = _hrm.find_contiguous_empty_or_unavailable(obj_regions);
+    if (first != G1_NO_HRM_INDEX) {
       // We found something. Make sure these regions are committed, i.e. expand
       // the heap. Alternatively we could do a defragmentation GC.
       ergo_verbose1(ErgoHeapSizing,
@@ -796,7 +796,7 @@
                     ergo_format_byte("allocation request"),
                     word_size * HeapWordSize);
 
-      _hrs.expand_at(first, obj_regions);
+      _hrm.expand_at(first, obj_regions);
       g1_policy()->record_new_heap_size(num_regions());
 
 #ifdef ASSERT
@@ -806,14 +806,14 @@
         assert(is_on_master_free_list(hr), "sanity");
       }
 #endif
-      _hrs.allocate_free_regions_starting_at(first, obj_regions);
+      _hrm.allocate_free_regions_starting_at(first, obj_regions);
     } else {
       // Policy: Potentially trigger a defragmentation GC.
     }
   }
 
   HeapWord* result = NULL;
-  if (first != G1_NO_HRS_INDEX) {
+  if (first != G1_NO_HRM_INDEX) {
     result = humongous_obj_allocate_initialize_regions(first, obj_regions, word_size);
     assert(result != NULL, "it should always return a valid result");
 
@@ -1248,7 +1248,7 @@
     : _hr_printer(hr_printer) { }
 };
 
-void G1CollectedHeap::print_hrs_post_compaction() {
+void G1CollectedHeap::print_hrm_post_compaction() {
   PostCompactionPrinterClosure cl(hr_printer());
   heap_region_iterate(&cl);
 }
@@ -1417,7 +1417,7 @@
         // that all the COMMIT / UNCOMMIT events are generated before
         // the end GC event.
 
-        print_hrs_post_compaction();
+        print_hrm_post_compaction();
         _hr_printer.end_gc(true /* full */, (size_t) total_collections());
       }
 
@@ -1490,7 +1490,7 @@
       // Update the number of full collections that have been completed.
       increment_old_marking_cycles_completed(false /* concurrent */);
 
-      _hrs.verify_optional();
+      _hrm.verify_optional();
       verify_region_sets_optional();
 
       verify_after_gc();
@@ -1734,7 +1734,7 @@
                 ergo_format_byte("allocation request"),
                 word_size * HeapWordSize);
   if (expand(expand_bytes)) {
-    _hrs.verify_optional();
+    _hrm.verify_optional();
     verify_region_sets_optional();
     return attempt_allocation_at_safepoint(word_size,
                                  false /* expect_null_mutator_alloc_region */);
@@ -1762,7 +1762,7 @@
   uint regions_to_expand = (uint)(aligned_expand_bytes / HeapRegion::GrainBytes);
   assert(regions_to_expand > 0, "Must expand by at least one region");
 
-  uint expanded_by = _hrs.expand_by(regions_to_expand);
+  uint expanded_by = _hrm.expand_by(regions_to_expand);
 
   if (expanded_by > 0) {
     size_t actual_expand_bytes = expanded_by * HeapRegion::GrainBytes;
@@ -1775,7 +1775,7 @@
     // The expansion of the virtual storage space was unsuccessful.
     // Let's see if it was because we ran out of swap.
     if (G1ExitOnExpansionFailure &&
-        _hrs.available() >= regions_to_expand) {
+        _hrm.available() >= regions_to_expand) {
       // We had head room...
       vm_exit_out_of_memory(aligned_expand_bytes, OOM_MMAP_ERROR, "G1 heap expansion");
     }
@@ -1790,7 +1790,7 @@
                                          HeapRegion::GrainBytes);
   uint num_regions_to_remove = (uint)(shrink_bytes / HeapRegion::GrainBytes);
 
-  uint num_regions_removed = _hrs.shrink_by(num_regions_to_remove);
+  uint num_regions_removed = _hrm.shrink_by(num_regions_to_remove);
   size_t shrunk_bytes = num_regions_removed * HeapRegion::GrainBytes;
 
   ergo_verbose3(ErgoHeapSizing,
@@ -1823,7 +1823,7 @@
   shrink_helper(shrink_bytes);
   rebuild_region_sets(true /* free_list_only */);
 
-  _hrs.verify_optional();
+  _hrm.verify_optional();
   verify_region_sets_optional();
 }
 
@@ -1867,6 +1867,7 @@
   _old_marking_cycles_started(0),
   _old_marking_cycles_completed(0),
   _concurrent_cycle_started(false),
+  _heap_summary_sent(false),
   _in_cset_fast_test(),
   _dirty_cards_region_list(NULL),
   _worker_cset_start_region(NULL),
@@ -2032,7 +2033,7 @@
                                          CMBitMap::mark_distance(),
                                          mtGC);
 
-  _hrs.initialize(heap_storage, prev_bitmap_storage, next_bitmap_storage, bot_storage, cardtable_storage, card_counts_storage);
+  _hrm.initialize(heap_storage, prev_bitmap_storage, next_bitmap_storage, bot_storage, cardtable_storage, card_counts_storage);
   g1_barrier_set()->initialize(cardtable_storage);
    // Do later initialization work for concurrent refinement.
   _cg1r->init(card_counts_storage);
@@ -2053,8 +2054,8 @@
 
   _g1h = this;
 
-  _in_cset_fast_test.initialize(_hrs.reserved().start(), _hrs.reserved().end(), HeapRegion::GrainBytes);
-  _humongous_is_live.initialize(_hrs.reserved().start(), _hrs.reserved().end(), HeapRegion::GrainBytes);
+  _in_cset_fast_test.initialize(_hrm.reserved().start(), _hrm.reserved().end(), HeapRegion::GrainBytes);
+  _humongous_is_live.initialize(_hrm.reserved().start(), _hrm.reserved().end(), HeapRegion::GrainBytes);
 
   // Create the ConcurrentMark data structure and thread.
   // (Must do this late, so that "max_regions" is defined.)
@@ -2115,7 +2116,7 @@
 
   // Here we allocate the dummy HeapRegion that is required by the
   // G1AllocRegion class.
-  HeapRegion* dummy_region = _hrs.get_dummy_region();
+  HeapRegion* dummy_region = _hrm.get_dummy_region();
 
   // We'll re-use the same region whether the alloc region will
   // require BOT updates or not and, if it doesn't, then a non-young
@@ -2232,14 +2233,14 @@
 }
 
 size_t G1CollectedHeap::capacity() const {
-  return _hrs.length() * HeapRegion::GrainBytes;
+  return _hrm.length() * HeapRegion::GrainBytes;
 }
 
 void G1CollectedHeap::reset_gc_time_stamps(HeapRegion* hr) {
   assert(!hr->continuesHumongous(), "pre-condition");
   hr->reset_gc_time_stamp();
   if (hr->startsHumongous()) {
-    uint first_index = hr->hrs_index() + 1;
+    uint first_index = hr->hrm_index() + 1;
     uint last_index = hr->last_hc_index();
     for (uint i = first_index; i < last_index; i += 1) {
       HeapRegion* chr = region_at(i);
@@ -2445,13 +2446,24 @@
     _gc_timer_cm->register_gc_end();
     _gc_tracer_cm->report_gc_end(_gc_timer_cm->gc_end(), _gc_timer_cm->time_partitions());
 
+    // Clear state variables to prepare for the next concurrent cycle.
     _concurrent_cycle_started = false;
+    _heap_summary_sent = false;
   }
 }
 
 void G1CollectedHeap::trace_heap_after_concurrent_cycle() {
   if (_concurrent_cycle_started) {
-    trace_heap_after_gc(_gc_tracer_cm);
+    // This function can be called when:
+    //  the cleanup pause is run
+    //  the concurrent cycle is aborted before the cleanup pause.
+    //  the concurrent cycle is aborted after the cleanup pause,
+    //   but before the concurrent cycle end has been registered.
+    // Make sure that we only send the heap information once.
+    if (!_heap_summary_sent) {
+      trace_heap_after_gc(_gc_tracer_cm);
+      _heap_summary_sent = true;
+    }
   }
 }
 
@@ -2537,7 +2549,7 @@
 }
 
 bool G1CollectedHeap::is_in(const void* p) const {
-  if (_hrs.reserved().contains(p)) {
+  if (_hrm.reserved().contains(p)) {
     // Given that we know that p is in the reserved space,
     // heap_region_containing_raw() should successfully
     // return the containing region.
@@ -2551,7 +2563,7 @@
 #ifdef ASSERT
 bool G1CollectedHeap::is_in_exact(const void* p) const {
   bool contains = reserved_region().contains(p);
-  bool available = _hrs.is_available(addr_to_region((HeapWord*)p));
+  bool available = _hrm.is_available(addr_to_region((HeapWord*)p));
   if (contains && available) {
     return true;
   } else {
@@ -2618,7 +2630,7 @@
 }
 
 void G1CollectedHeap::heap_region_iterate(HeapRegionClosure* cl) const {
-  _hrs.iterate(cl);
+  _hrm.iterate(cl);
 }
 
 void
@@ -2626,7 +2638,7 @@
                                                  uint worker_id,
                                                  uint num_workers,
                                                  jint claim_value) const {
-  _hrs.par_iterate(cl, worker_id, num_workers, claim_value);
+  _hrm.par_iterate(cl, worker_id, num_workers, claim_value);
 }
 
 class ResetClaimValuesClosure: public HeapRegionClosure {
@@ -2846,9 +2858,9 @@
 }
 
 HeapRegion* G1CollectedHeap::next_compaction_region(const HeapRegion* from) const {
-  HeapRegion* result = _hrs.next_region_in_heap(from);
+  HeapRegion* result = _hrm.next_region_in_heap(from);
   while (result != NULL && result->isHumongous()) {
-    result = _hrs.next_region_in_heap(result);
+    result = _hrm.next_region_in_heap(result);
   }
   return result;
 }
@@ -2908,7 +2920,7 @@
 }
 
 size_t G1CollectedHeap::max_capacity() const {
-  return _hrs.reserved().byte_size();
+  return _hrm.reserved().byte_size();
 }
 
 jlong G1CollectedHeap::millis_since_last_gc() {
@@ -3437,9 +3449,9 @@
   st->print(" total " SIZE_FORMAT "K, used " SIZE_FORMAT "K",
             capacity()/K, used_unlocked()/K);
   st->print(" [" INTPTR_FORMAT ", " INTPTR_FORMAT ", " INTPTR_FORMAT ")",
-            _hrs.reserved().start(),
-            _hrs.reserved().start() + _hrs.length() + HeapRegion::GrainWords,
-            _hrs.reserved().end());
+            _hrm.reserved().start(),
+            _hrm.reserved().start() + _hrm.length() + HeapRegion::GrainWords,
+            _hrm.reserved().end());
   st->cr();
   st->print("  region size " SIZE_FORMAT "K, ", HeapRegion::GrainBytes / K);
   uint young_regions = _young_list->length();
@@ -3682,7 +3694,7 @@
     }
     G1CollectedHeap* g1h = G1CollectedHeap::heap();
 
-    uint region_idx = r->hrs_index();
+    uint region_idx = r->hrm_index();
     bool is_candidate = !g1h->humongous_region_is_always_live(region_idx);
     // Is_candidate already filters out humongous regions with some remembered set.
     // This will not lead to humongous object that we mistakenly keep alive because
@@ -4205,7 +4217,7 @@
     // output from the concurrent mark thread interfering with this
     // logging output either.
 
-    _hrs.verify_optional();
+    _hrm.verify_optional();
     verify_region_sets_optional();
 
     TASKQUEUE_STATS_ONLY(if (ParallelGCVerbose) print_taskqueue_stats());
@@ -6024,7 +6036,7 @@
                                   bool locked) {
   assert(!hr->isHumongous(), "this is only for non-humongous regions");
   assert(!hr->is_empty(), "the region should not be empty");
-  assert(_hrs.is_available(hr->hrs_index()), "region should be committed");
+  assert(_hrm.is_available(hr->hrm_index()), "region should be committed");
   assert(free_list != NULL, "pre-condition");
 
   if (G1VerifyBitmaps) {
@@ -6055,7 +6067,7 @@
   hr->set_notHumongous();
   free_region(hr, free_list, par);
 
-  uint i = hr->hrs_index() + 1;
+  uint i = hr->hrm_index() + 1;
   while (i < last_index) {
     HeapRegion* curr_hr = region_at(i);
     assert(curr_hr->continuesHumongous(), "invariant");
@@ -6079,7 +6091,7 @@
   assert(list != NULL, "list can't be null");
   if (!list->is_empty()) {
     MutexLockerEx x(FreeList_lock, Mutex::_no_safepoint_check_flag);
-    _hrs.insert_list_into_free_list(list);
+    _hrm.insert_list_into_free_list(list);
   }
 }
 
@@ -6448,7 +6460,7 @@
     // While this cleanup is not strictly necessary to be done (or done instantly),
     // given that their occurrence is very low, this saves us this additional
     // complexity.
-    uint region_idx = r->hrs_index();
+    uint region_idx = r->hrm_index();
     if (g1h->humongous_is_live(region_idx) ||
         g1h->humongous_region_is_always_live(region_idx)) {
 
@@ -6687,22 +6699,22 @@
     // this is that during a full GC string deduplication needs to know if
     // a collected region was young or old when the full GC was initiated.
   }
-  _hrs.remove_all_free_regions();
+  _hrm.remove_all_free_regions();
 }
 
 class RebuildRegionSetsClosure : public HeapRegionClosure {
 private:
   bool            _free_list_only;
   HeapRegionSet*   _old_set;
-  HeapRegionSeq*   _hrs;
+  HeapRegionManager*   _hrm;
   size_t          _total_used;
 
 public:
   RebuildRegionSetsClosure(bool free_list_only,
-                           HeapRegionSet* old_set, HeapRegionSeq* hrs) :
+                           HeapRegionSet* old_set, HeapRegionManager* hrm) :
     _free_list_only(free_list_only),
-    _old_set(old_set), _hrs(hrs), _total_used(0) {
-    assert(_hrs->num_free_regions() == 0, "pre-condition");
+    _old_set(old_set), _hrm(hrm), _total_used(0) {
+    assert(_hrm->num_free_regions() == 0, "pre-condition");
     if (!free_list_only) {
       assert(_old_set->is_empty(), "pre-condition");
     }
@@ -6715,7 +6727,7 @@
 
     if (r->is_empty()) {
       // Add free regions to the free list
-      _hrs->insert_into_free_list(r);
+      _hrm->insert_into_free_list(r);
     } else if (!_free_list_only) {
       assert(!r->is_young(), "we should not come across young regions");
 
@@ -6743,7 +6755,7 @@
     _young_list->empty_list();
   }
 
-  RebuildRegionSetsClosure cl(free_list_only, &_old_set, &_hrs);
+  RebuildRegionSetsClosure cl(free_list_only, &_old_set, &_hrm);
   heap_region_iterate(&cl);
 
   if (!free_list_only) {
@@ -6933,7 +6945,7 @@
 private:
   HeapRegionSet*   _old_set;
   HeapRegionSet*   _humongous_set;
-  HeapRegionSeq*   _hrs;
+  HeapRegionManager*   _hrm;
 
 public:
   HeapRegionSetCount _old_count;
@@ -6942,8 +6954,8 @@
 
   VerifyRegionListsClosure(HeapRegionSet* old_set,
                            HeapRegionSet* humongous_set,
-                           HeapRegionSeq* hrs) :
-    _old_set(old_set), _humongous_set(humongous_set), _hrs(hrs),
+                           HeapRegionManager* hrm) :
+    _old_set(old_set), _humongous_set(humongous_set), _hrm(hrm),
     _old_count(), _humongous_count(), _free_count(){ }
 
   bool doHeapRegion(HeapRegion* hr) {
@@ -6954,19 +6966,19 @@
     if (hr->is_young()) {
       // TODO
     } else if (hr->startsHumongous()) {
-      assert(hr->containing_set() == _humongous_set, err_msg("Heap region %u is starts humongous but not in humongous set.", hr->hrs_index()));
+      assert(hr->containing_set() == _humongous_set, err_msg("Heap region %u is starts humongous but not in humongous set.", hr->hrm_index()));
       _humongous_count.increment(1u, hr->capacity());
     } else if (hr->is_empty()) {
-      assert(_hrs->is_free(hr), err_msg("Heap region %u is empty but not on the free list.", hr->hrs_index()));
+      assert(_hrm->is_free(hr), err_msg("Heap region %u is empty but not on the free list.", hr->hrm_index()));
       _free_count.increment(1u, hr->capacity());
     } else {
-      assert(hr->containing_set() == _old_set, err_msg("Heap region %u is old but not in the old set.", hr->hrs_index()));
+      assert(hr->containing_set() == _old_set, err_msg("Heap region %u is old but not in the old set.", hr->hrm_index()));
       _old_count.increment(1u, hr->capacity());
     }
     return false;
   }
 
-  void verify_counts(HeapRegionSet* old_set, HeapRegionSet* humongous_set, HeapRegionSeq* free_list) {
+  void verify_counts(HeapRegionSet* old_set, HeapRegionSet* humongous_set, HeapRegionManager* free_list) {
     guarantee(old_set->length() == _old_count.length(), err_msg("Old set count mismatch. Expected %u, actual %u.", old_set->length(), _old_count.length()));
     guarantee(old_set->total_capacity_bytes() == _old_count.capacity(), err_msg("Old set capacity mismatch. Expected " SIZE_FORMAT ", actual " SIZE_FORMAT,
         old_set->total_capacity_bytes(), _old_count.capacity()));
@@ -6985,7 +6997,7 @@
   assert_heap_locked_or_at_safepoint(true /* should_be_vm_thread */);
 
   // First, check the explicit lists.
-  _hrs.verify();
+  _hrm.verify();
   {
     // Given that a concurrent operation might be adding regions to
     // the secondary free list we have to take the lock before
@@ -7016,9 +7028,9 @@
   // Finally, make sure that the region accounting in the lists is
   // consistent with what we see in the heap.
 
-  VerifyRegionListsClosure cl(&_old_set, &_humongous_set, &_hrs);
+  VerifyRegionListsClosure cl(&_old_set, &_humongous_set, &_hrm);
   heap_region_iterate(&cl);
-  cl.verify_counts(&_old_set, &_humongous_set, &_hrs);
+  cl.verify_counts(&_old_set, &_humongous_set, &_hrm);
 }
 
 // Optimized nmethod scanning
--- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp	Thu Sep 04 14:45:48 2014 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp	Wed Jul 05 20:00:03 2017 +0200
@@ -33,7 +33,7 @@
 #include "gc_implementation/g1/g1MonitoringSupport.hpp"
 #include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp"
 #include "gc_implementation/g1/g1YCTypes.hpp"
-#include "gc_implementation/g1/heapRegionSeq.hpp"
+#include "gc_implementation/g1/heapRegionManager.hpp"
 #include "gc_implementation/g1/heapRegionSet.hpp"
 #include "gc_implementation/shared/hSpaceCounters.hpp"
 #include "gc_implementation/shared/parGCAllocBuffer.hpp"
@@ -291,7 +291,7 @@
   G1RegionMappingChangedListener _listener;
 
   // The sequence of all heap regions in the heap.
-  HeapRegionSeq _hrs;
+  HeapRegionManager _hrm;
 
   // Alloc region used to satisfy mutator allocation requests.
   MutatorAllocRegion _mutator_alloc_region;
@@ -415,6 +415,7 @@
   volatile unsigned int _old_marking_cycles_completed;
 
   bool _concurrent_cycle_started;
+  bool _heap_summary_sent;
 
   // This is a non-product method that is helpful for testing. It is
   // called at the end of a GC and artificially expands the heap by
@@ -429,7 +430,7 @@
 
   // If the HR printer is active, dump the state of the regions in the
   // heap after a compaction.
-  void print_hrs_post_compaction();
+  void print_hrm_post_compaction();
 
   double verify(bool guard, const char* msg);
   void verify_before_gc();
@@ -715,7 +716,7 @@
   // We register a region with the fast "in collection set" test. We
   // simply set to true the array slot corresponding to this region.
   void register_region_with_in_cset_fast_test(HeapRegion* r) {
-    _in_cset_fast_test.set_in_cset(r->hrs_index());
+    _in_cset_fast_test.set_in_cset(r->hrm_index());
   }
 
   // This is a fast test on whether a reference points into the
@@ -1171,17 +1172,17 @@
   // But G1CollectedHeap doesn't yet support this.
 
   virtual bool is_maximal_no_gc() const {
-    return _hrs.available() == 0;
+    return _hrm.available() == 0;
   }
 
   // The current number of regions in the heap.
-  uint num_regions() const { return _hrs.length(); }
+  uint num_regions() const { return _hrm.length(); }
 
   // The max number of regions in the heap.
-  uint max_regions() const { return _hrs.max_length(); }
+  uint max_regions() const { return _hrm.max_length(); }
 
   // The number of regions that are completely free.
-  uint num_free_regions() const { return _hrs.num_free_regions(); }
+  uint num_free_regions() const { return _hrm.num_free_regions(); }
 
   // The number of regions that are not completely free.
   uint num_used_regions() const { return num_regions() - num_free_regions(); }
@@ -1233,7 +1234,7 @@
 
 #ifdef ASSERT
   bool is_on_master_free_list(HeapRegion* hr) {
-    return _hrs.is_free(hr);
+    return _hrm.is_free(hr);
   }
 #endif // ASSERT
 
@@ -1245,7 +1246,7 @@
   }
 
   void append_secondary_free_list() {
-    _hrs.insert_list_into_free_list(&_secondary_free_list);
+    _hrm.insert_list_into_free_list(&_secondary_free_list);
   }
 
   void append_secondary_free_list_if_not_empty_with_lock() {
@@ -1356,13 +1357,13 @@
   // Return "TRUE" iff the given object address is in the reserved
   // region of g1.
   bool is_in_g1_reserved(const void* p) const {
-    return _hrs.reserved().contains(p);
+    return _hrm.reserved().contains(p);
   }
 
   // Returns a MemRegion that corresponds to the space that has been
   // reserved for the heap
   MemRegion g1_reserved() const {
-    return _hrs.reserved();
+    return _hrm.reserved();
   }
 
   virtual bool is_in_closed_subset(const void* p) const;
--- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp	Thu Sep 04 14:45:48 2014 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp	Wed Jul 05 20:00:03 2017 +0200
@@ -30,15 +30,15 @@
 #include "gc_implementation/g1/g1AllocRegion.inline.hpp"
 #include "gc_implementation/g1/g1CollectorPolicy.hpp"
 #include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp"
+#include "gc_implementation/g1/heapRegionManager.inline.hpp"
 #include "gc_implementation/g1/heapRegionSet.inline.hpp"
-#include "gc_implementation/g1/heapRegionSeq.inline.hpp"
 #include "runtime/orderAccess.inline.hpp"
 #include "utilities/taskqueue.hpp"
 
 // Inline functions for G1CollectedHeap
 
 // Return the region with the given index. It assumes the index is valid.
-inline HeapRegion* G1CollectedHeap::region_at(uint index) const { return _hrs.at(index); }
+inline HeapRegion* G1CollectedHeap::region_at(uint index) const { return _hrm.at(index); }
 
 inline uint G1CollectedHeap::addr_to_region(HeapWord* addr) const {
   assert(is_in_reserved(addr),
@@ -48,7 +48,7 @@
 }
 
 inline HeapWord* G1CollectedHeap::bottom_addr_for_region(uint index) const {
-  return _hrs.reserved().start() + index * HeapRegion::GrainWords;
+  return _hrm.reserved().start() + index * HeapRegion::GrainWords;
 }
 
 template <class T>
@@ -57,7 +57,7 @@
   assert(is_in_g1_reserved((const void*) addr),
       err_msg("Address "PTR_FORMAT" is outside of the heap ranging from ["PTR_FORMAT" to "PTR_FORMAT")",
           p2i((void*)addr), p2i(g1_reserved().start()), p2i(g1_reserved().end())));
-  return _hrs.addr_to_region((HeapWord*) addr);
+  return _hrm.addr_to_region((HeapWord*) addr);
 }
 
 template <class T>
@@ -87,7 +87,7 @@
 }
 
 inline bool G1CollectedHeap::obj_in_cs(oop obj) {
-  HeapRegion* r = _hrs.addr_to_region((HeapWord*) obj);
+  HeapRegion* r = _hrm.addr_to_region((HeapWord*) obj);
   return r != NULL && r->in_collection_set();
 }
 
--- a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp	Thu Sep 04 14:45:48 2014 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp	Wed Jul 05 20:00:03 2017 +0200
@@ -32,7 +32,7 @@
 #include "gc_implementation/g1/g1GCPhaseTimes.hpp"
 #include "gc_implementation/g1/g1OopClosures.inline.hpp"
 #include "gc_implementation/g1/g1RemSet.inline.hpp"
-#include "gc_implementation/g1/heapRegionSeq.inline.hpp"
+#include "gc_implementation/g1/heapRegionManager.inline.hpp"
 #include "gc_implementation/g1/heapRegionRemSet.hpp"
 #include "memory/iterator.hpp"
 #include "oops/oop.inline.hpp"
--- a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp	Thu Sep 04 14:45:48 2014 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp	Wed Jul 05 20:00:03 2017 +0200
@@ -29,7 +29,7 @@
 #include "gc_implementation/g1/g1OopClosures.inline.hpp"
 #include "gc_implementation/g1/heapRegion.inline.hpp"
 #include "gc_implementation/g1/heapRegionRemSet.hpp"
-#include "gc_implementation/g1/heapRegionSeq.inline.hpp"
+#include "gc_implementation/g1/heapRegionManager.inline.hpp"
 #include "gc_implementation/shared/liveRange.hpp"
 #include "memory/genOopClosures.inline.hpp"
 #include "memory/iterator.hpp"
@@ -322,34 +322,11 @@
   return false;
 }
 
-HeapWord* HeapRegion::next_block_start_careful(HeapWord* addr) {
-  HeapWord* low = addr;
-  HeapWord* high = end();
-  while (low < high) {
-    size_t diff = pointer_delta(high, low);
-    // Must add one below to bias toward the high amount.  Otherwise, if
-  // "high" were at the desired value, and "low" were one less, we
-    // would not converge on "high".  This is not symmetric, because
-    // we set "high" to a block start, which might be the right one,
-    // which we don't do for "low".
-    HeapWord* middle = low + (diff+1)/2;
-    if (middle == high) return high;
-    HeapWord* mid_bs = block_start_careful(middle);
-    if (mid_bs < addr) {
-      low = middle;
-    } else {
-      high = mid_bs;
-    }
-  }
-  assert(low == high && low >= addr, "Didn't work.");
-  return low;
-}
-
-HeapRegion::HeapRegion(uint hrs_index,
+HeapRegion::HeapRegion(uint hrm_index,
                        G1BlockOffsetSharedArray* sharedOffsetArray,
                        MemRegion mr) :
     G1OffsetTableContigSpace(sharedOffsetArray, mr),
-    _hrs_index(hrs_index),
+    _hrm_index(hrm_index),
     _humongous_type(NotHumongous), _humongous_start_region(NULL),
     _in_collection_set(false),
     _next_in_special_set(NULL), _orig_end(NULL),
--- a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp	Thu Sep 04 14:45:48 2014 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp	Wed Jul 05 20:00:03 2017 +0200
@@ -54,15 +54,15 @@
 
 #define HR_FORMAT "%u:(%s)["PTR_FORMAT","PTR_FORMAT","PTR_FORMAT"]"
 #define HR_FORMAT_PARAMS(_hr_) \
-                (_hr_)->hrs_index(), \
+                (_hr_)->hrm_index(), \
                 (_hr_)->is_survivor() ? "S" : (_hr_)->is_young() ? "E" : \
                 (_hr_)->startsHumongous() ? "HS" : \
                 (_hr_)->continuesHumongous() ? "HC" : \
                 !(_hr_)->is_empty() ? "O" : "F", \
                 p2i((_hr_)->bottom()), p2i((_hr_)->top()), p2i((_hr_)->end())
 
-// sentinel value for hrs_index
-#define G1_NO_HRS_INDEX ((uint) -1)
+// sentinel value for hrm_index
+#define G1_NO_HRM_INDEX ((uint) -1)
 
 // A dirty card to oop closure for heap regions. It
 // knows how to get the G1 heap and how to use the bitmap
@@ -206,10 +206,6 @@
     _offsets.reset_bot();
   }
 
-  void update_bot_for_object(HeapWord* start, size_t word_size) {
-    _offsets.alloc_block(start, word_size);
-  }
-
   void print_bot_on(outputStream* out) {
     _offsets.print_on(out);
   }
@@ -234,7 +230,7 @@
 
  protected:
   // The index of this region in the heap region sequence.
-  uint  _hrs_index;
+  uint  _hrm_index;
 
   HumongousType _humongous_type;
   // For a humongous region, region in which it starts.
@@ -330,7 +326,7 @@
   size_t _predicted_bytes_to_copy;
 
  public:
-  HeapRegion(uint hrs_index,
+  HeapRegion(uint hrm_index,
              G1BlockOffsetSharedArray* sharedOffsetArray,
              MemRegion mr);
 
@@ -385,9 +381,9 @@
   inline HeapWord* par_allocate_no_bot_updates(size_t word_size);
   inline HeapWord* allocate_no_bot_updates(size_t word_size);
 
-  // If this region is a member of a HeapRegionSeq, the index in that
+  // If this region is a member of a HeapRegionManager, the index in that
   // sequence, otherwise -1.
-  uint hrs_index() const { return _hrs_index; }
+  uint hrm_index() const { return _hrm_index; }
 
   // The number of bytes marked live in the region in the last marking phase.
   size_t marked_bytes()    { return _prev_marked_bytes; }
@@ -458,7 +454,7 @@
   // with this HS region.
   uint last_hc_index() const {
     assert(startsHumongous(), "don't call this otherwise");
-    return hrs_index() + region_num();
+    return hrm_index() + region_num();
   }
 
   // Same as Space::is_in_reserved, but will use the original size of the region.
@@ -570,7 +566,7 @@
   void set_next_dirty_cards_region(HeapRegion* hr) { _next_dirty_cards_region = hr; }
   bool is_on_dirty_cards_region_list() const { return get_next_dirty_cards_region() != NULL; }
 
-  HeapWord* orig_end() { return _orig_end; }
+  HeapWord* orig_end() const { return _orig_end; }
 
   // Reset HR stuff to default values.
   void hr_clear(bool par, bool clear_space, bool locked = false);
@@ -737,18 +733,6 @@
                                    bool filter_young,
                                    jbyte* card_ptr);
 
-  // A version of block start that is guaranteed to find *some* block
-  // boundary at or before "p", but does not object iteration, and may
-  // therefore be used safely when the heap is unparseable.
-  HeapWord* block_start_careful(const void* p) const {
-    return _offsets.block_start_careful(p);
-  }
-
-  // Requires that "addr" is within the region.  Returns the start of the
-  // first ("careful") block that starts at or after "addr", or else the
-  // "end" of the region if there is no such block.
-  HeapWord* next_block_start_careful(HeapWord* addr);
-
   size_t recorded_rs_length() const        { return _recorded_rs_length; }
   double predicted_elapsed_time_ms() const { return _predicted_elapsed_time_ms; }
   size_t predicted_bytes_to_copy() const   { return _predicted_bytes_to_copy; }
@@ -813,7 +797,7 @@
 // HeapRegionClosure is used for iterating over regions.
 // Terminates the iteration when the "doHeapRegion" method returns "true".
 class HeapRegionClosure : public StackObj {
-  friend class HeapRegionSeq;
+  friend class HeapRegionManager;
   friend class G1CollectedHeap;
 
   bool _complete;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionManager.cpp	Wed Jul 05 20:00:03 2017 +0200
@@ -0,0 +1,446 @@
+/*
+ * Copyright (c) 2001, 2014, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "gc_implementation/g1/heapRegion.hpp"
+#include "gc_implementation/g1/heapRegionManager.inline.hpp"
+#include "gc_implementation/g1/heapRegionSet.inline.hpp"
+#include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
+#include "gc_implementation/g1/concurrentG1Refine.hpp"
+#include "memory/allocation.hpp"
+
+void HeapRegionManager::initialize(G1RegionToSpaceMapper* heap_storage,
+                               G1RegionToSpaceMapper* prev_bitmap,
+                               G1RegionToSpaceMapper* next_bitmap,
+                               G1RegionToSpaceMapper* bot,
+                               G1RegionToSpaceMapper* cardtable,
+                               G1RegionToSpaceMapper* card_counts) {
+  _allocated_heapregions_length = 0;
+
+  _heap_mapper = heap_storage;
+
+  _prev_bitmap_mapper = prev_bitmap;
+  _next_bitmap_mapper = next_bitmap;
+
+  _bot_mapper = bot;
+  _cardtable_mapper = cardtable;
+
+  _card_counts_mapper = card_counts;
+
+  MemRegion reserved = heap_storage->reserved();
+  _regions.initialize(reserved.start(), reserved.end(), HeapRegion::GrainBytes);
+
+  _available_map.resize(_regions.length(), false);
+  _available_map.clear();
+}
+
+bool HeapRegionManager::is_available(uint region) const {
+  return _available_map.at(region);
+}
+
+#ifdef ASSERT
+bool HeapRegionManager::is_free(HeapRegion* hr) const {
+  return _free_list.contains(hr);
+}
+#endif
+
+HeapRegion* HeapRegionManager::new_heap_region(uint hrm_index) {
+  HeapWord* bottom = G1CollectedHeap::heap()->bottom_addr_for_region(hrm_index);
+  MemRegion mr(bottom, bottom + HeapRegion::GrainWords);
+  assert(reserved().contains(mr), "invariant");
+  return new HeapRegion(hrm_index, G1CollectedHeap::heap()->bot_shared(), mr);
+}
+
+void HeapRegionManager::commit_regions(uint index, size_t num_regions) {
+  guarantee(num_regions > 0, "Must commit more than zero regions");
+  guarantee(_num_committed + num_regions <= max_length(), "Cannot commit more than the maximum amount of regions");
+
+  _num_committed += (uint)num_regions;
+
+  _heap_mapper->commit_regions(index, num_regions);
+
+  // Also commit auxiliary data
+  _prev_bitmap_mapper->commit_regions(index, num_regions);
+  _next_bitmap_mapper->commit_regions(index, num_regions);
+
+  _bot_mapper->commit_regions(index, num_regions);
+  _cardtable_mapper->commit_regions(index, num_regions);
+
+  _card_counts_mapper->commit_regions(index, num_regions);
+}
+
+void HeapRegionManager::uncommit_regions(uint start, size_t num_regions) {
+  guarantee(num_regions >= 1, err_msg("Need to specify at least one region to uncommit, tried to uncommit zero regions at %u", start));
+  guarantee(_num_committed >= num_regions, "pre-condition");
+
+  // Print before uncommitting.
+  if (G1CollectedHeap::heap()->hr_printer()->is_active()) {
+    for (uint i = start; i < start + num_regions; i++) {
+      HeapRegion* hr = at(i);
+      G1CollectedHeap::heap()->hr_printer()->uncommit(hr->bottom(), hr->end());
+    }
+  }
+
+  _num_committed -= (uint)num_regions;
+
+  _available_map.par_clear_range(start, start + num_regions, BitMap::unknown_range);
+  _heap_mapper->uncommit_regions(start, num_regions);
+
+  // Also uncommit auxiliary data
+  _prev_bitmap_mapper->uncommit_regions(start, num_regions);
+  _next_bitmap_mapper->uncommit_regions(start, num_regions);
+
+  _bot_mapper->uncommit_regions(start, num_regions);
+  _cardtable_mapper->uncommit_regions(start, num_regions);
+
+  _card_counts_mapper->uncommit_regions(start, num_regions);
+}
+
+void HeapRegionManager::make_regions_available(uint start, uint num_regions) {
+  guarantee(num_regions > 0, "No point in calling this for zero regions");
+  commit_regions(start, num_regions);
+  for (uint i = start; i < start + num_regions; i++) {
+    if (_regions.get_by_index(i) == NULL) {
+      HeapRegion* new_hr = new_heap_region(i);
+      _regions.set_by_index(i, new_hr);
+      _allocated_heapregions_length = MAX2(_allocated_heapregions_length, i + 1);
+    }
+  }
+
+  _available_map.par_set_range(start, start + num_regions, BitMap::unknown_range);
+
+  for (uint i = start; i < start + num_regions; i++) {
+    assert(is_available(i), err_msg("Just made region %u available but is apparently not.", i));
+    HeapRegion* hr = at(i);
+    if (G1CollectedHeap::heap()->hr_printer()->is_active()) {
+      G1CollectedHeap::heap()->hr_printer()->commit(hr->bottom(), hr->end());
+    }
+    HeapWord* bottom = G1CollectedHeap::heap()->bottom_addr_for_region(i);
+    MemRegion mr(bottom, bottom + HeapRegion::GrainWords);
+
+    hr->initialize(mr);
+    insert_into_free_list(at(i));
+  }
+}
+
+uint HeapRegionManager::expand_by(uint num_regions) {
+  return expand_at(0, num_regions);
+}
+
+uint HeapRegionManager::expand_at(uint start, uint num_regions) {
+  if (num_regions == 0) {
+    return 0;
+  }
+
+  uint cur = start;
+  uint idx_last_found = 0;
+  uint num_last_found = 0;
+
+  uint expanded = 0;
+
+  while (expanded < num_regions &&
+         (num_last_found = find_unavailable_from_idx(cur, &idx_last_found)) > 0) {
+    uint to_expand = MIN2(num_regions - expanded, num_last_found);
+    make_regions_available(idx_last_found, to_expand);
+    expanded += to_expand;
+    cur = idx_last_found + num_last_found + 1;
+  }
+
+  verify_optional();
+  return expanded;
+}
+
+uint HeapRegionManager::find_contiguous(size_t num, bool empty_only) {
+  uint found = 0;
+  size_t length_found = 0;
+  uint cur = 0;
+
+  while (length_found < num && cur < max_length()) {
+    HeapRegion* hr = _regions.get_by_index(cur);
+    if ((!empty_only && !is_available(cur)) || (is_available(cur) && hr != NULL && hr->is_empty())) {
+      // This region is a potential candidate for allocation into.
+      length_found++;
+    } else {
+      // This region is not a candidate. The next region is the next possible one.
+      found = cur + 1;
+      length_found = 0;
+    }
+    cur++;
+  }
+
+  if (length_found == num) {
+    for (uint i = found; i < (found + num); i++) {
+      HeapRegion* hr = _regions.get_by_index(i);
+      // sanity check
+      guarantee((!empty_only && !is_available(i)) || (is_available(i) && hr != NULL && hr->is_empty()),
+                err_msg("Found region sequence starting at " UINT32_FORMAT ", length " SIZE_FORMAT
+                        " that is not empty at " UINT32_FORMAT ". Hr is " PTR_FORMAT, found, num, i, p2i(hr)));
+    }
+    return found;
+  } else {
+    return G1_NO_HRM_INDEX;
+  }
+}
+
+HeapRegion* HeapRegionManager::next_region_in_heap(const HeapRegion* r) const {
+  guarantee(r != NULL, "Start region must be a valid region");
+  guarantee(is_available(r->hrm_index()), err_msg("Trying to iterate starting from region %u which is not in the heap", r->hrm_index()));
+  for (uint i = r->hrm_index() + 1; i < _allocated_heapregions_length; i++) {
+    HeapRegion* hr = _regions.get_by_index(i);
+    if (is_available(i)) {
+      return hr;
+    }
+  }
+  return NULL;
+}
+
+void HeapRegionManager::iterate(HeapRegionClosure* blk) const {
+  uint len = max_length();
+
+  for (uint i = 0; i < len; i++) {
+    if (!is_available(i)) {
+      continue;
+    }
+    guarantee(at(i) != NULL, err_msg("Tried to access region %u that has a NULL HeapRegion*", i));
+    bool res = blk->doHeapRegion(at(i));
+    if (res) {
+      blk->incomplete();
+      return;
+    }
+  }
+}
+
+uint HeapRegionManager::find_unavailable_from_idx(uint start_idx, uint* res_idx) const {
+  guarantee(res_idx != NULL, "checking");
+  guarantee(start_idx <= (max_length() + 1), "checking");
+
+  uint num_regions = 0;
+
+  uint cur = start_idx;
+  while (cur < max_length() && is_available(cur)) {
+    cur++;
+  }
+  if (cur == max_length()) {
+    return num_regions;
+  }
+  *res_idx = cur;
+  while (cur < max_length() && !is_available(cur)) {
+    cur++;
+  }
+  num_regions = cur - *res_idx;
+#ifdef ASSERT
+  for (uint i = *res_idx; i < (*res_idx + num_regions); i++) {
+    assert(!is_available(i), "just checking");
+  }
+  assert(cur == max_length() || num_regions == 0 || is_available(cur),
+         err_msg("The region at the current position %u must be available or at the end of the heap.", cur));
+#endif
+  return num_regions;
+}
+
+uint HeapRegionManager::start_region_for_worker(uint worker_i, uint num_workers, uint num_regions) const {
+  return num_regions * worker_i / num_workers;
+}
+
+void HeapRegionManager::par_iterate(HeapRegionClosure* blk, uint worker_id, uint num_workers, jint claim_value) const {
+  const uint start_index = start_region_for_worker(worker_id, num_workers, _allocated_heapregions_length);
+
+  // Every worker will actually look at all regions, skipping over regions that
+  // are currently not committed.
+  // This also (potentially) iterates over regions newly allocated during GC. This
+  // is no problem except for some extra work.
+  for (uint count = 0; count < _allocated_heapregions_length; count++) {
+    const uint index = (start_index + count) % _allocated_heapregions_length;
+    assert(0 <= index && index < _allocated_heapregions_length, "sanity");
+    // Skip over unavailable regions
+    if (!is_available(index)) {
+      continue;
+    }
+    HeapRegion* r = _regions.get_by_index(index);
+    // We'll ignore "continues humongous" regions (we'll process them
+    // when we come across their corresponding "start humongous"
+    // region) and regions already claimed.
+    if (r->claim_value() == claim_value || r->continuesHumongous()) {
+      continue;
+    }
+    // OK, try to claim it
+    if (!r->claimHeapRegion(claim_value)) {
+      continue;
+    }
+    // Success!
+    if (r->startsHumongous()) {
+      // If the region is "starts humongous" we'll iterate over its
+      // "continues humongous" first; in fact we'll do them
+      // first. The order is important. In one case, calling the
+      // closure on the "starts humongous" region might de-allocate
+      // and clear all its "continues humongous" regions and, as a
+      // result, we might end up processing them twice. So, we'll do
+      // them first (note: most closures will ignore them anyway) and
+      // then we'll do the "starts humongous" region.
+      for (uint ch_index = index + 1; ch_index < index + r->region_num(); ch_index++) {
+        HeapRegion* chr = _regions.get_by_index(ch_index);
+
+        assert(chr->continuesHumongous(), "Must be humongous region");
+        assert(chr->humongous_start_region() == r,
+               err_msg("Must work on humongous continuation of the original start region "
+                       PTR_FORMAT ", but is " PTR_FORMAT, p2i(r), p2i(chr)));
+        assert(chr->claim_value() != claim_value,
+               "Must not have been claimed yet because claiming of humongous continuation first claims the start region");
+
+        bool claim_result = chr->claimHeapRegion(claim_value);
+        // We should always be able to claim it; no one else should
+        // be trying to claim this region.
+        guarantee(claim_result, "We should always be able to claim the continuesHumongous part of the humongous object");
+
+        bool res2 = blk->doHeapRegion(chr);
+        if (res2) {
+          return;
+        }
+
+        // Right now, this holds (i.e., no closure that actually
+        // does something with "continues humongous" regions
+        // clears them). We might have to weaken it in the future,
+        // but let's leave these two asserts here for extra safety.
+        assert(chr->continuesHumongous(), "should still be the case");
+        assert(chr->humongous_start_region() == r, "sanity");
+      }
+    }
+
+    bool res = blk->doHeapRegion(r);
+    if (res) {
+      return;
+    }
+  }
+}
+
+uint HeapRegionManager::shrink_by(uint num_regions_to_remove) {
+  assert(length() > 0, "the region sequence should not be empty");
+  assert(length() <= _allocated_heapregions_length, "invariant");
+  assert(_allocated_heapregions_length > 0, "we should have at least one region committed");
+  assert(num_regions_to_remove < length(), "We should never remove all regions");
+
+  if (num_regions_to_remove == 0) {
+    return 0;
+  }
+
+  uint removed = 0;
+  uint cur = _allocated_heapregions_length - 1;
+  uint idx_last_found = 0;
+  uint num_last_found = 0;
+
+  while ((removed < num_regions_to_remove) &&
+      (num_last_found = find_empty_from_idx_reverse(cur, &idx_last_found)) > 0) {
+    uint to_remove = MIN2(num_regions_to_remove - removed, num_last_found);
+
+    uncommit_regions(idx_last_found + num_last_found - to_remove, to_remove);
+
+    cur -= num_last_found;
+    removed += to_remove;
+  }
+
+  verify_optional();
+
+  return removed;
+}
+
+uint HeapRegionManager::find_empty_from_idx_reverse(uint start_idx, uint* res_idx) const {
+  guarantee(start_idx < _allocated_heapregions_length, "checking");
+  guarantee(res_idx != NULL, "checking");
+
+  uint num_regions_found = 0;
+
+  jlong cur = start_idx;
+  while (cur != -1 && !(is_available(cur) && at(cur)->is_empty())) {
+    cur--;
+  }
+  if (cur == -1) {
+    return num_regions_found;
+  }
+  jlong old_cur = cur;
+  // cur indexes the first empty region
+  while (cur != -1 && is_available(cur) && at(cur)->is_empty()) {
+    cur--;
+  }
+  *res_idx = cur + 1;
+  num_regions_found = old_cur - cur;
+
+#ifdef ASSERT
+  for (uint i = *res_idx; i < (*res_idx + num_regions_found); i++) {
+    assert(at(i)->is_empty(), "just checking");
+  }
+#endif
+  return num_regions_found;
+}
+
+void HeapRegionManager::verify() {
+  guarantee(length() <= _allocated_heapregions_length,
+            err_msg("invariant: _length: %u _allocated_length: %u",
+                    length(), _allocated_heapregions_length));
+  guarantee(_allocated_heapregions_length <= max_length(),
+            err_msg("invariant: _allocated_length: %u _max_length: %u",
+                    _allocated_heapregions_length, max_length()));
+
+  bool prev_committed = true;
+  uint num_committed = 0;
+  HeapWord* prev_end = heap_bottom();
+  for (uint i = 0; i < _allocated_heapregions_length; i++) {
+    if (!is_available(i)) {
+      prev_committed = false;
+      continue;
+    }
+    num_committed++;
+    HeapRegion* hr = _regions.get_by_index(i);
+    guarantee(hr != NULL, err_msg("invariant: i: %u", i));
+    guarantee(!prev_committed || hr->bottom() == prev_end,
+              err_msg("invariant i: %u "HR_FORMAT" prev_end: "PTR_FORMAT,
+                      i, HR_FORMAT_PARAMS(hr), p2i(prev_end)));
+    guarantee(hr->hrm_index() == i,
+              err_msg("invariant: i: %u hrm_index(): %u", i, hr->hrm_index()));
+    // Asserts will fire if i is >= _length
+    HeapWord* addr = hr->bottom();
+    guarantee(addr_to_region(addr) == hr, "sanity");
+    // We cannot check whether the region is part of a particular set: at the time
+    // this method may be called, we have only completed allocation of the regions,
+    // but not put into a region set.
+    prev_committed = true;
+    if (hr->startsHumongous()) {
+      prev_end = hr->orig_end();
+    } else {
+      prev_end = hr->end();
+    }
+  }
+  for (uint i = _allocated_heapregions_length; i < max_length(); i++) {
+    guarantee(_regions.get_by_index(i) == NULL, err_msg("invariant i: %u", i));
+  }
+
+  guarantee(num_committed == _num_committed, err_msg("Found %u committed regions, but should be %u", num_committed, _num_committed));
+  _free_list.verify();
+}
+
+#ifndef PRODUCT
+void HeapRegionManager::verify_optional() {
+  verify();
+}
+#endif // PRODUCT
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionManager.hpp	Wed Jul 05 20:00:03 2017 +0200
@@ -0,0 +1,239 @@
+/*
+ * Copyright (c) 2001, 2013, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_GC_IMPLEMENTATION_G1_HEAPREGIONMANAGER_HPP
+#define SHARE_VM_GC_IMPLEMENTATION_G1_HEAPREGIONMANAGER_HPP
+
+#include "gc_implementation/g1/g1BiasedArray.hpp"
+#include "gc_implementation/g1/g1RegionToSpaceMapper.hpp"
+#include "gc_implementation/g1/heapRegionSet.hpp"
+
+class HeapRegion;
+class HeapRegionClosure;
+class FreeRegionList;
+
+class G1HeapRegionTable : public G1BiasedMappedArray<HeapRegion*> {
+ protected:
+  virtual HeapRegion* default_value() const { return NULL; }
+};
+
+// This class keeps track of the actual heap memory, auxiliary data
+// and its metadata (i.e., HeapRegion instances) and the list of free regions.
+//
+// This allows maximum flexibility for deciding what to commit or uncommit given
+// a request from outside.
+//
+// HeapRegions are kept in the _regions array in address order. A region's
+// index in the array corresponds to its index in the heap (i.e., 0 is the
+// region at the bottom of the heap, 1 is the one after it, etc.). Two
+// regions that are consecutive in the array should also be adjacent in the
+// address space (i.e., region(i).end() == region(i+1).bottom().
+//
+// We create a HeapRegion when we commit the region's address space
+// for the first time. When we uncommit the address space of a
+// region we retain the HeapRegion to be able to re-use it in the
+// future (in case we recommit it).
+//
+// We keep track of three lengths:
+//
+// * _num_committed (returned by length()) is the number of currently
+//   committed regions. These may not be contiguous.
+// * _allocated_heapregions_length (not exposed outside this class) is the
+//   number of regions+1 for which we have HeapRegions.
+// * max_length() returns the maximum number of regions the heap can have.
+//
+
+class HeapRegionManager: public CHeapObj<mtGC> {
+  friend class VMStructs;
+
+  G1HeapRegionTable _regions;
+
+  G1RegionToSpaceMapper* _heap_mapper;
+  G1RegionToSpaceMapper* _prev_bitmap_mapper;
+  G1RegionToSpaceMapper* _next_bitmap_mapper;
+  G1RegionToSpaceMapper* _bot_mapper;
+  G1RegionToSpaceMapper* _cardtable_mapper;
+  G1RegionToSpaceMapper* _card_counts_mapper;
+
+  FreeRegionList _free_list;
+
+  // Each bit in this bitmap indicates that the corresponding region is available
+  // for allocation.
+  BitMap _available_map;
+
+   // The number of regions committed in the heap.
+  uint _num_committed;
+
+  // Internal only. The highest heap region +1 we allocated a HeapRegion instance for.
+  uint _allocated_heapregions_length;
+
+  HeapWord* heap_bottom() const { return _regions.bottom_address_mapped(); }
+  HeapWord* heap_end() const {return _regions.end_address_mapped(); }
+
+  void make_regions_available(uint index, uint num_regions = 1);
+
+  // Pass down commit calls to the VirtualSpace.
+  void commit_regions(uint index, size_t num_regions = 1);
+  void uncommit_regions(uint index, size_t num_regions = 1);
+
+  // Notify other data structures about change in the heap layout.
+  void update_committed_space(HeapWord* old_end, HeapWord* new_end);
+  // Calculate the starting region for each worker during parallel iteration so
+  // that they do not all start from the same region.
+  uint start_region_for_worker(uint worker_i, uint num_workers, uint num_regions) const;
+
+  // Find a contiguous set of empty or uncommitted regions of length num and return
+  // the index of the first region or G1_NO_HRM_INDEX if the search was unsuccessful.
+  // If only_empty is true, only empty regions are considered.
+  // Searches from bottom to top of the heap, doing a first-fit.
+  uint find_contiguous(size_t num, bool only_empty);
+  // Finds the next sequence of unavailable regions starting from start_idx. Returns the
+  // length of the sequence found. If this result is zero, no such sequence could be found,
+  // otherwise res_idx indicates the start index of these regions.
+  uint find_unavailable_from_idx(uint start_idx, uint* res_idx) const;
+  // Finds the next sequence of empty regions starting from start_idx, going backwards in
+  // the heap. Returns the length of the sequence found. If this value is zero, no
+  // sequence could be found, otherwise res_idx contains the start index of this range.
+  uint find_empty_from_idx_reverse(uint start_idx, uint* res_idx) const;
+  // Allocate a new HeapRegion for the given index.
+  HeapRegion* new_heap_region(uint hrm_index);
+#ifdef ASSERT
+public:
+  bool is_free(HeapRegion* hr) const;
+#endif
+  // Returns whether the given region is available for allocation.
+  bool is_available(uint region) const;
+
+ public:
+  // Empty constructor, we'll initialize it with the initialize() method.
+  HeapRegionManager() : _regions(), _heap_mapper(NULL), _num_committed(0),
+                    _next_bitmap_mapper(NULL), _prev_bitmap_mapper(NULL), _bot_mapper(NULL),
+                    _allocated_heapregions_length(0), _available_map(),
+                    _free_list("Free list", new MasterFreeRegionListMtSafeChecker())
+  { }
+
+  void initialize(G1RegionToSpaceMapper* heap_storage,
+                  G1RegionToSpaceMapper* prev_bitmap,
+                  G1RegionToSpaceMapper* next_bitmap,
+                  G1RegionToSpaceMapper* bot,
+                  G1RegionToSpaceMapper* cardtable,
+                  G1RegionToSpaceMapper* card_counts);
+
+  // Return the "dummy" region used for G1AllocRegion. This is currently a hardwired
+  // new HeapRegion that owns HeapRegion at index 0. Since at the moment we commit
+  // the heap from the lowest address, this region (and its associated data
+  // structures) are available and we do not need to check further.
+  HeapRegion* get_dummy_region() { return new_heap_region(0); }
+
+  // Return the HeapRegion at the given index. Assume that the index
+  // is valid.
+  inline HeapRegion* at(uint index) const;
+
+  // If addr is within the committed space return its corresponding
+  // HeapRegion, otherwise return NULL.
+  inline HeapRegion* addr_to_region(HeapWord* addr) const;
+
+  // Insert the given region into the free region list.
+  inline void insert_into_free_list(HeapRegion* hr);
+
+  // Insert the given region list into the global free region list.
+  void insert_list_into_free_list(FreeRegionList* list) {
+    _free_list.add_ordered(list);
+  }
+
+  HeapRegion* allocate_free_region(bool is_old) {
+    HeapRegion* hr = _free_list.remove_region(is_old);
+
+    if (hr != NULL) {
+      assert(hr->next() == NULL, "Single region should not have next");
+      assert(is_available(hr->hrm_index()), "Must be committed");
+    }
+    return hr;
+  }
+
+  inline void allocate_free_regions_starting_at(uint first, uint num_regions);
+
+  // Remove all regions from the free list.
+  void remove_all_free_regions() {
+    _free_list.remove_all();
+  }
+
+  // Return the number of committed free regions in the heap.
+  uint num_free_regions() const {
+    return _free_list.length();
+  }
+
+  size_t total_capacity_bytes() const {
+    return num_free_regions() * HeapRegion::GrainBytes;
+  }
+
+  // Return the number of available (uncommitted) regions.
+  uint available() const { return max_length() - length(); }
+
+  // Return the number of regions that have been committed in the heap.
+  uint length() const { return _num_committed; }
+
+  // Return the maximum number of regions in the heap.
+  uint max_length() const { return (uint)_regions.length(); }
+
+  MemRegion reserved() const { return MemRegion(heap_bottom(), heap_end()); }
+
+  // Expand the sequence to reflect that the heap has grown. Either create new
+  // HeapRegions, or re-use existing ones. Returns the number of regions the
+  // sequence was expanded by. If a HeapRegion allocation fails, the resulting
+  // number of regions might be smaller than what's desired.
+  uint expand_by(uint num_regions);
+
+  // Makes sure that the regions from start to start+num_regions-1 are available
+  // for allocation. Returns the number of regions that were committed to achieve
+  // this.
+  uint expand_at(uint start, uint num_regions);
+
+  // Find a contiguous set of empty regions of length num. Returns the start index of
+  // that set, or G1_NO_HRM_INDEX.
+  uint find_contiguous_only_empty(size_t num) { return find_contiguous(num, true); }
+  // Find a contiguous set of empty or unavailable regions of length num. Returns the
+  // start index of that set, or G1_NO_HRM_INDEX.
+  uint find_contiguous_empty_or_unavailable(size_t num) { return find_contiguous(num, false); }
+
+  HeapRegion* next_region_in_heap(const HeapRegion* r) const;
+
+  // Apply blk->doHeapRegion() on all committed regions in address order,
+  // terminating the iteration early if doHeapRegion() returns true.
+  void iterate(HeapRegionClosure* blk) const;
+
+  void par_iterate(HeapRegionClosure* blk, uint worker_id, uint no_of_par_workers, jint claim_value) const;
+
+  // Uncommit up to num_regions_to_remove regions that are completely free.
+  // Return the actual number of uncommitted regions.
+  uint shrink_by(uint num_regions_to_remove);
+
+  void verify();
+
+  // Do some sanity checking.
+  void verify_optional() PRODUCT_RETURN;
+};
+
+#endif // SHARE_VM_GC_IMPLEMENTATION_G1_HEAPREGIONMANAGER_HPP
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionManager.inline.hpp	Wed Jul 05 20:00:03 2017 +0200
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2001, 2014, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_GC_IMPLEMENTATION_G1_HEAPREGIONMANAGER_INLINE_HPP
+#define SHARE_VM_GC_IMPLEMENTATION_G1_HEAPREGIONMANAGER_INLINE_HPP
+
+#include "gc_implementation/g1/heapRegion.hpp"
+#include "gc_implementation/g1/heapRegionManager.hpp"
+#include "gc_implementation/g1/heapRegionSet.inline.hpp"
+
+inline HeapRegion* HeapRegionManager::addr_to_region(HeapWord* addr) const {
+  assert(addr < heap_end(),
+        err_msg("addr: "PTR_FORMAT" end: "PTR_FORMAT, p2i(addr), p2i(heap_end())));
+  assert(addr >= heap_bottom(),
+        err_msg("addr: "PTR_FORMAT" bottom: "PTR_FORMAT, p2i(addr), p2i(heap_bottom())));
+
+  HeapRegion* hr = _regions.get_by_address(addr);
+  return hr;
+}
+
+inline HeapRegion* HeapRegionManager::at(uint index) const {
+  assert(is_available(index), "pre-condition");
+  HeapRegion* hr = _regions.get_by_index(index);
+  assert(hr != NULL, "sanity");
+  assert(hr->hrm_index() == index, "sanity");
+  return hr;
+}
+
+inline void HeapRegionManager::insert_into_free_list(HeapRegion* hr) {
+  _free_list.add_ordered(hr);
+}
+
+inline void HeapRegionManager::allocate_free_regions_starting_at(uint first, uint num_regions) {
+  _free_list.remove_starting_at(at(first), num_regions);
+}
+
+#endif // SHARE_VM_GC_IMPLEMENTATION_G1_HEAPREGIONMANAGER_INLINE_HPP
--- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp	Thu Sep 04 14:45:48 2014 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp	Wed Jul 05 20:00:03 2017 +0200
@@ -27,7 +27,7 @@
 #include "gc_implementation/g1/g1BlockOffsetTable.inline.hpp"
 #include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
 #include "gc_implementation/g1/heapRegionRemSet.hpp"
-#include "gc_implementation/g1/heapRegionSeq.inline.hpp"
+#include "gc_implementation/g1/heapRegionManager.inline.hpp"
 #include "memory/allocation.hpp"
 #include "memory/padded.inline.hpp"
 #include "memory/space.inline.hpp"
@@ -420,7 +420,7 @@
 }
 
 void OtherRegionsTable::add_reference(OopOrNarrowOopStar from, int tid) {
-  uint cur_hrs_ind = hr()->hrs_index();
+  uint cur_hrm_ind = hr()->hrm_index();
 
   if (G1TraceHeapRegionRememberedSet) {
     gclog_or_tty->print_cr("ORT::add_reference_work(" PTR_FORMAT "->" PTR_FORMAT ").",
@@ -435,10 +435,10 @@
   if (G1TraceHeapRegionRememberedSet) {
     gclog_or_tty->print_cr("Table for [" PTR_FORMAT "...): card %d (cache = %d)",
                   hr()->bottom(), from_card,
-                  FromCardCache::at((uint)tid, cur_hrs_ind));
+                  FromCardCache::at((uint)tid, cur_hrm_ind));
   }
 
-  if (FromCardCache::contains_or_replace((uint)tid, cur_hrs_ind, from_card)) {
+  if (FromCardCache::contains_or_replace((uint)tid, cur_hrm_ind, from_card)) {
     if (G1TraceHeapRegionRememberedSet) {
       gclog_or_tty->print_cr("  from-card cache hit.");
     }
@@ -448,7 +448,7 @@
 
   // Note that this may be a continued H region.
   HeapRegion* from_hr = _g1h->heap_region_containing_raw(from);
-  RegionIdx_t from_hrs_ind = (RegionIdx_t) from_hr->hrs_index();
+  RegionIdx_t from_hrs_ind = (RegionIdx_t) from_hr->hrm_index();
 
   // If the region is already coarsened, return.
   if (_coarse_map.at(from_hrs_ind)) {
@@ -495,7 +495,7 @@
         if (G1TraceHeapRegionRememberedSet) {
           gclog_or_tty->print_cr("   [tid %d] sparse table entry "
                         "overflow(f: %d, t: %u)",
-                        tid, from_hrs_ind, cur_hrs_ind);
+                        tid, from_hrs_ind, cur_hrm_ind);
         }
       }
 
@@ -607,9 +607,9 @@
   guarantee(max != NULL, "Since _n_fine_entries > 0");
 
   // Set the corresponding coarse bit.
-  size_t max_hrs_index = (size_t) max->hr()->hrs_index();
-  if (!_coarse_map.at(max_hrs_index)) {
-    _coarse_map.at_put(max_hrs_index, true);
+  size_t max_hrm_index = (size_t) max->hr()->hrm_index();
+  if (!_coarse_map.at(max_hrm_index)) {
+    _coarse_map.at_put(max_hrm_index, true);
     _n_coarse_entries++;
     if (G1TraceHeapRegionRememberedSet) {
       gclog_or_tty->print("Coarsened entry in region [" PTR_FORMAT "...] "
@@ -633,7 +633,7 @@
                               BitMap* region_bm, BitMap* card_bm) {
   // First eliminated garbage regions from the coarse map.
   if (G1RSScrubVerbose) {
-    gclog_or_tty->print_cr("Scrubbing region %u:", hr()->hrs_index());
+    gclog_or_tty->print_cr("Scrubbing region %u:", hr()->hrm_index());
   }
 
   assert(_coarse_map.size() == region_bm->size(), "Precondition");
@@ -656,9 +656,9 @@
       // If the entire region is dead, eliminate.
       if (G1RSScrubVerbose) {
         gclog_or_tty->print_cr("     For other region %u:",
-                               cur->hr()->hrs_index());
+                               cur->hr()->hrm_index());
       }
-      if (!region_bm->at((size_t) cur->hr()->hrs_index())) {
+      if (!region_bm->at((size_t) cur->hr()->hrm_index())) {
         *prev = nxt;
         cur->set_collision_list_next(NULL);
         _n_fine_entries--;
@@ -752,7 +752,7 @@
 }
 
 void OtherRegionsTable::clear_fcc() {
-  FromCardCache::clear(hr()->hrs_index());
+  FromCardCache::clear(hr()->hrm_index());
 }
 
 void OtherRegionsTable::clear() {
@@ -803,7 +803,7 @@
 
 bool OtherRegionsTable::contains_reference_locked(OopOrNarrowOopStar from) const {
   HeapRegion* hr = _g1h->heap_region_containing_raw(from);
-  RegionIdx_t hr_ind = (RegionIdx_t) hr->hrs_index();
+  RegionIdx_t hr_ind = (RegionIdx_t) hr->hrm_index();
   // Is this region in the coarse map?
   if (_coarse_map.at(hr_ind)) return true;
 
@@ -840,7 +840,7 @@
 HeapRegionRemSet::HeapRegionRemSet(G1BlockOffsetSharedArray* bosa,
                                    HeapRegion* hr)
   : _bosa(bosa),
-    _m(Mutex::leaf, FormatBuffer<128>("HeapRegionRemSet lock #%u", hr->hrs_index()), true),
+    _m(Mutex::leaf, FormatBuffer<128>("HeapRegionRemSet lock #%u", hr->hrm_index()), true),
     _code_roots(), _other_regions(hr, &_m), _iter_state(Unclaimed), _iter_claimed(0) {
   reset_for_par_iteration();
 }
--- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSeq.cpp	Thu Sep 04 14:45:48 2014 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,450 +0,0 @@
-/*
- * Copyright (c) 2001, 2014, 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
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#include "precompiled.hpp"
-#include "gc_implementation/g1/heapRegion.hpp"
-#include "gc_implementation/g1/heapRegionSeq.inline.hpp"
-#include "gc_implementation/g1/heapRegionSet.inline.hpp"
-#include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
-#include "gc_implementation/g1/concurrentG1Refine.hpp"
-#include "memory/allocation.hpp"
-
-void HeapRegionSeq::initialize(G1RegionToSpaceMapper* heap_storage,
-                               G1RegionToSpaceMapper* prev_bitmap,
-                               G1RegionToSpaceMapper* next_bitmap,
-                               G1RegionToSpaceMapper* bot,
-                               G1RegionToSpaceMapper* cardtable,
-                               G1RegionToSpaceMapper* card_counts) {
-  _allocated_heapregions_length = 0;
-
-  _heap_mapper = heap_storage;
-
-  _prev_bitmap_mapper = prev_bitmap;
-  _next_bitmap_mapper = next_bitmap;
-
-  _bot_mapper = bot;
-  _cardtable_mapper = cardtable;
-
-  _card_counts_mapper = card_counts;
-
-  MemRegion reserved = heap_storage->reserved();
-  _regions.initialize(reserved.start(), reserved.end(), HeapRegion::GrainBytes);
-
-  _available_map.resize(_regions.length(), false);
-  _available_map.clear();
-}
-
-bool HeapRegionSeq::is_available(uint region) const {
-  return _available_map.at(region);
-}
-
-#ifdef ASSERT
-bool HeapRegionSeq::is_free(HeapRegion* hr) const {
-  return _free_list.contains(hr);
-}
-#endif
-
-HeapRegion* HeapRegionSeq::new_heap_region(uint hrs_index) {
-  HeapWord* bottom = G1CollectedHeap::heap()->bottom_addr_for_region(hrs_index);
-  MemRegion mr(bottom, bottom + HeapRegion::GrainWords);
-  assert(reserved().contains(mr), "invariant");
-  return new HeapRegion(hrs_index, G1CollectedHeap::heap()->bot_shared(), mr);
-}
-
-void HeapRegionSeq::commit_regions(uint index, size_t num_regions) {
-  guarantee(num_regions > 0, "Must commit more than zero regions");
-  guarantee(_num_committed + num_regions <= max_length(), "Cannot commit more than the maximum amount of regions");
-
-  _num_committed += (uint)num_regions;
-
-  _heap_mapper->commit_regions(index, num_regions);
-
-  // Also commit auxiliary data
-  _prev_bitmap_mapper->commit_regions(index, num_regions);
-  _next_bitmap_mapper->commit_regions(index, num_regions);
-
-  _bot_mapper->commit_regions(index, num_regions);
-  _cardtable_mapper->commit_regions(index, num_regions);
-
-  _card_counts_mapper->commit_regions(index, num_regions);
-}
-
-void HeapRegionSeq::uncommit_regions(uint start, size_t num_regions) {
-  guarantee(num_regions >= 1, err_msg("Need to specify at least one region to uncommit, tried to uncommit zero regions at %u", start));
-  guarantee(_num_committed >= num_regions, "pre-condition");
-
-  // Print before uncommitting.
-  if (G1CollectedHeap::heap()->hr_printer()->is_active()) {
-    for (uint i = start; i < start + num_regions; i++) {
-      HeapRegion* hr = at(i);
-      G1CollectedHeap::heap()->hr_printer()->uncommit(hr->bottom(), hr->end());
-    }
-  }
-
-  _num_committed -= (uint)num_regions;
-
-  _available_map.par_clear_range(start, start + num_regions, BitMap::unknown_range);
-  _heap_mapper->uncommit_regions(start, num_regions);
-
-  // Also uncommit auxiliary data
-  _prev_bitmap_mapper->uncommit_regions(start, num_regions);
-  _next_bitmap_mapper->uncommit_regions(start, num_regions);
-
-  _bot_mapper->uncommit_regions(start, num_regions);
-  _cardtable_mapper->uncommit_regions(start, num_regions);
-
-  _card_counts_mapper->uncommit_regions(start, num_regions);
-}
-
-void HeapRegionSeq::make_regions_available(uint start, uint num_regions) {
-  guarantee(num_regions > 0, "No point in calling this for zero regions");
-  commit_regions(start, num_regions);
-  for (uint i = start; i < start + num_regions; i++) {
-    if (_regions.get_by_index(i) == NULL) {
-      HeapRegion* new_hr = new_heap_region(i);
-      _regions.set_by_index(i, new_hr);
-      _allocated_heapregions_length = MAX2(_allocated_heapregions_length, i + 1);
-    }
-  }
-
-  _available_map.par_set_range(start, start + num_regions, BitMap::unknown_range);
-
-  for (uint i = start; i < start + num_regions; i++) {
-    assert(is_available(i), err_msg("Just made region %u available but is apparently not.", i));
-    HeapRegion* hr = at(i);
-    if (G1CollectedHeap::heap()->hr_printer()->is_active()) {
-      G1CollectedHeap::heap()->hr_printer()->commit(hr->bottom(), hr->end());
-    }
-    HeapWord* bottom = G1CollectedHeap::heap()->bottom_addr_for_region(i);
-    MemRegion mr(bottom, bottom + HeapRegion::GrainWords);
-
-    hr->initialize(mr);
-    insert_into_free_list(at(i));
-  }
-}
-
-uint HeapRegionSeq::expand_by(uint num_regions) {
-  return expand_at(0, num_regions);
-}
-
-uint HeapRegionSeq::expand_at(uint start, uint num_regions) {
-  if (num_regions == 0) {
-    return 0;
-  }
-
-  uint cur = start;
-  uint idx_last_found = 0;
-  uint num_last_found = 0;
-
-  uint expanded = 0;
-
-  while (expanded < num_regions &&
-         (num_last_found = find_unavailable_from_idx(cur, &idx_last_found)) > 0) {
-    uint to_expand = MIN2(num_regions - expanded, num_last_found);
-    make_regions_available(idx_last_found, to_expand);
-    expanded += to_expand;
-    cur = idx_last_found + num_last_found + 1;
-  }
-
-  verify_optional();
-  return expanded;
-}
-
-uint HeapRegionSeq::find_contiguous(size_t num, bool empty_only) {
-  uint found = 0;
-  size_t length_found = 0;
-  uint cur = 0;
-
-  while (length_found < num && cur < max_length()) {
-    HeapRegion* hr = _regions.get_by_index(cur);
-    if ((!empty_only && !is_available(cur)) || (is_available(cur) && hr != NULL && hr->is_empty())) {
-      // This region is a potential candidate for allocation into.
-      length_found++;
-    } else {
-      // This region is not a candidate. The next region is the next possible one.
-      found = cur + 1;
-      length_found = 0;
-    }
-    cur++;
-  }
-
-  if (length_found == num) {
-    for (uint i = found; i < (found + num); i++) {
-      HeapRegion* hr = _regions.get_by_index(i);
-      // sanity check
-      guarantee((!empty_only && !is_available(i)) || (is_available(i) && hr != NULL && hr->is_empty()),
-                err_msg("Found region sequence starting at " UINT32_FORMAT ", length " SIZE_FORMAT
-                        " that is not empty at " UINT32_FORMAT ". Hr is " PTR_FORMAT, found, num, i, p2i(hr)));
-    }
-    return found;
-  } else {
-    return G1_NO_HRS_INDEX;
-  }
-}
-
-HeapRegion* HeapRegionSeq::next_region_in_heap(const HeapRegion* r) const {
-  guarantee(r != NULL, "Start region must be a valid region");
-  guarantee(is_available(r->hrs_index()), err_msg("Trying to iterate starting from region %u which is not in the heap", r->hrs_index()));
-  for (uint i = r->hrs_index() + 1; i < _allocated_heapregions_length; i++) {
-    HeapRegion* hr = _regions.get_by_index(i);
-    if (is_available(i)) {
-      return hr;
-    }
-  }
-  return NULL;
-}
-
-void HeapRegionSeq::iterate(HeapRegionClosure* blk) const {
-  uint len = max_length();
-
-  for (uint i = 0; i < len; i++) {
-    if (!is_available(i)) {
-      continue;
-    }
-    guarantee(at(i) != NULL, err_msg("Tried to access region %u that has a NULL HeapRegion*", i));
-    bool res = blk->doHeapRegion(at(i));
-    if (res) {
-      blk->incomplete();
-      return;
-    }
-  }
-}
-
-uint HeapRegionSeq::find_unavailable_from_idx(uint start_idx, uint* res_idx) const {
-  guarantee(res_idx != NULL, "checking");
-  guarantee(start_idx <= (max_length() + 1), "checking");
-
-  uint num_regions = 0;
-
-  uint cur = start_idx;
-  while (cur < max_length() && is_available(cur)) {
-    cur++;
-  }
-  if (cur == max_length()) {
-    return num_regions;
-  }
-  *res_idx = cur;
-  while (cur < max_length() && !is_available(cur)) {
-    cur++;
-  }
-  num_regions = cur - *res_idx;
-#ifdef ASSERT
-  for (uint i = *res_idx; i < (*res_idx + num_regions); i++) {
-    assert(!is_available(i), "just checking");
-  }
-  assert(cur == max_length() || num_regions == 0 || is_available(cur),
-         err_msg("The region at the current position %u must be available or at the end of the heap.", cur));
-#endif
-  return num_regions;
-}
-
-uint HeapRegionSeq::start_region_for_worker(uint worker_i, uint num_workers, uint num_regions) const {
-  return num_regions * worker_i / num_workers;
-}
-
-void HeapRegionSeq::par_iterate(HeapRegionClosure* blk, uint worker_id, uint num_workers, jint claim_value) const {
-  const uint start_index = start_region_for_worker(worker_id, num_workers, _allocated_heapregions_length);
-
-  // Every worker will actually look at all regions, skipping over regions that
-  // are currently not committed.
-  // This also (potentially) iterates over regions newly allocated during GC. This
-  // is no problem except for some extra work.
-  for (uint count = 0; count < _allocated_heapregions_length; count++) {
-    const uint index = (start_index + count) % _allocated_heapregions_length;
-    assert(0 <= index && index < _allocated_heapregions_length, "sanity");
-    // Skip over unavailable regions
-    if (!is_available(index)) {
-      continue;
-    }
-    HeapRegion* r = _regions.get_by_index(index);
-    // We'll ignore "continues humongous" regions (we'll process them
-    // when we come across their corresponding "start humongous"
-    // region) and regions already claimed.
-    if (r->claim_value() == claim_value || r->continuesHumongous()) {
-      continue;
-    }
-    // OK, try to claim it
-    if (!r->claimHeapRegion(claim_value)) {
-      continue;
-    }
-    // Success!
-    if (r->startsHumongous()) {
-      // If the region is "starts humongous" we'll iterate over its
-      // "continues humongous" first; in fact we'll do them
-      // first. The order is important. In one case, calling the
-      // closure on the "starts humongous" region might de-allocate
-      // and clear all its "continues humongous" regions and, as a
-      // result, we might end up processing them twice. So, we'll do
-      // them first (note: most closures will ignore them anyway) and
-      // then we'll do the "starts humongous" region.
-      for (uint ch_index = index + 1; ch_index < index + r->region_num(); ch_index++) {
-        HeapRegion* chr = _regions.get_by_index(ch_index);
-
-        assert(chr->continuesHumongous(), "Must be humongous region");
-        assert(chr->humongous_start_region() == r,
-               err_msg("Must work on humongous continuation of the original start region "
-                       PTR_FORMAT ", but is " PTR_FORMAT, p2i(r), p2i(chr)));
-        assert(chr->claim_value() != claim_value,
-               "Must not have been claimed yet because claiming of humongous continuation first claims the start region");
-
-        bool claim_result = chr->claimHeapRegion(claim_value);
-        // We should always be able to claim it; no one else should
-        // be trying to claim this region.
-        guarantee(claim_result, "We should always be able to claim the continuesHumongous part of the humongous object");
-
-        bool res2 = blk->doHeapRegion(chr);
-        if (res2) {
-          return;
-        }
-
-        // Right now, this holds (i.e., no closure that actually
-        // does something with "continues humongous" regions
-        // clears them). We might have to weaken it in the future,
-        // but let's leave these two asserts here for extra safety.
-        assert(chr->continuesHumongous(), "should still be the case");
-        assert(chr->humongous_start_region() == r, "sanity");
-      }
-    }
-
-    bool res = blk->doHeapRegion(r);
-    if (res) {
-      return;
-    }
-  }
-}
-
-uint HeapRegionSeq::shrink_by(uint num_regions_to_remove) {
-  assert(length() > 0, "the region sequence should not be empty");
-  assert(length() <= _allocated_heapregions_length, "invariant");
-  assert(_allocated_heapregions_length > 0, "we should have at least one region committed");
-  assert(num_regions_to_remove < length(), "We should never remove all regions");
-
-  if (num_regions_to_remove == 0) {
-    return 0;
-  }
-
-  uint removed = 0;
-  uint cur = _allocated_heapregions_length - 1;
-  uint idx_last_found = 0;
-  uint num_last_found = 0;
-
-  while ((removed < num_regions_to_remove) &&
-      (num_last_found = find_empty_from_idx_reverse(cur, &idx_last_found)) > 0) {
-    // Only allow uncommit from the end of the heap.
-    if ((idx_last_found + num_last_found) != _allocated_heapregions_length) {
-      return 0;
-    }
-    uint to_remove = MIN2(num_regions_to_remove - removed, num_last_found);
-
-    uncommit_regions(idx_last_found + num_last_found - to_remove, to_remove);
-
-    cur -= num_last_found;
-    removed += to_remove;
-  }
-
-  verify_optional();
-
-  return removed;
-}
-
-uint HeapRegionSeq::find_empty_from_idx_reverse(uint start_idx, uint* res_idx) const {
-  guarantee(start_idx < _allocated_heapregions_length, "checking");
-  guarantee(res_idx != NULL, "checking");
-
-  uint num_regions_found = 0;
-
-  jlong cur = start_idx;
-  while (cur != -1 && !(is_available(cur) && at(cur)->is_empty())) {
-    cur--;
-  }
-  if (cur == -1) {
-    return num_regions_found;
-  }
-  jlong old_cur = cur;
-  // cur indexes the first empty region
-  while (cur != -1 && is_available(cur) && at(cur)->is_empty()) {
-    cur--;
-  }
-  *res_idx = cur + 1;
-  num_regions_found = old_cur - cur;
-
-#ifdef ASSERT
-  for (uint i = *res_idx; i < (*res_idx + num_regions_found); i++) {
-    assert(at(i)->is_empty(), "just checking");
-  }
-#endif
-  return num_regions_found;
-}
-
-void HeapRegionSeq::verify() {
-  guarantee(length() <= _allocated_heapregions_length,
-            err_msg("invariant: _length: %u _allocated_length: %u",
-                    length(), _allocated_heapregions_length));
-  guarantee(_allocated_heapregions_length <= max_length(),
-            err_msg("invariant: _allocated_length: %u _max_length: %u",
-                    _allocated_heapregions_length, max_length()));
-
-  bool prev_committed = true;
-  uint num_committed = 0;
-  HeapWord* prev_end = heap_bottom();
-  for (uint i = 0; i < _allocated_heapregions_length; i++) {
-    if (!is_available(i)) {
-      prev_committed = false;
-      continue;
-    }
-    num_committed++;
-    HeapRegion* hr = _regions.get_by_index(i);
-    guarantee(hr != NULL, err_msg("invariant: i: %u", i));
-    guarantee(!prev_committed || hr->bottom() == prev_end,
-              err_msg("invariant i: %u "HR_FORMAT" prev_end: "PTR_FORMAT,
-                      i, HR_FORMAT_PARAMS(hr), p2i(prev_end)));
-    guarantee(hr->hrs_index() == i,
-              err_msg("invariant: i: %u hrs_index(): %u", i, hr->hrs_index()));
-    // Asserts will fire if i is >= _length
-    HeapWord* addr = hr->bottom();
-    guarantee(addr_to_region(addr) == hr, "sanity");
-    // We cannot check whether the region is part of a particular set: at the time
-    // this method may be called, we have only completed allocation of the regions,
-    // but not put into a region set.
-    prev_committed = true;
-    if (hr->startsHumongous()) {
-      prev_end = hr->orig_end();
-    } else {
-      prev_end = hr->end();
-    }
-  }
-  for (uint i = _allocated_heapregions_length; i < max_length(); i++) {
-    guarantee(_regions.get_by_index(i) == NULL, err_msg("invariant i: %u", i));
-  }
-
-  guarantee(num_committed == _num_committed, err_msg("Found %u committed regions, but should be %u", num_committed, _num_committed));
-  _free_list.verify();
-}
-
-#ifndef PRODUCT
-void HeapRegionSeq::verify_optional() {
-  verify();
-}
-#endif // PRODUCT
-
--- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSeq.hpp	Thu Sep 04 14:45:48 2014 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,239 +0,0 @@
-/*
- * Copyright (c) 2001, 2013, 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
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef SHARE_VM_GC_IMPLEMENTATION_G1_HEAPREGIONSEQ_HPP
-#define SHARE_VM_GC_IMPLEMENTATION_G1_HEAPREGIONSEQ_HPP
-
-#include "gc_implementation/g1/g1BiasedArray.hpp"
-#include "gc_implementation/g1/g1RegionToSpaceMapper.hpp"
-#include "gc_implementation/g1/heapRegionSet.hpp"
-
-class HeapRegion;
-class HeapRegionClosure;
-class FreeRegionList;
-
-class G1HeapRegionTable : public G1BiasedMappedArray<HeapRegion*> {
- protected:
-  virtual HeapRegion* default_value() const { return NULL; }
-};
-
-// This class keeps track of the actual heap memory, auxiliary data
-// and its metadata (i.e., HeapRegion instances) and the list of free regions.
-//
-// This allows maximum flexibility for deciding what to commit or uncommit given
-// a request from outside.
-//
-// HeapRegions are kept in the _regions array in address order. A region's
-// index in the array corresponds to its index in the heap (i.e., 0 is the
-// region at the bottom of the heap, 1 is the one after it, etc.). Two
-// regions that are consecutive in the array should also be adjacent in the
-// address space (i.e., region(i).end() == region(i+1).bottom().
-//
-// We create a HeapRegion when we commit the region's address space
-// for the first time. When we uncommit the address space of a
-// region we retain the HeapRegion to be able to re-use it in the
-// future (in case we recommit it).
-//
-// We keep track of three lengths:
-//
-// * _num_committed (returned by length()) is the number of currently
-//   committed regions. These may not be contiguous.
-// * _allocated_heapregions_length (not exposed outside this class) is the
-//   number of regions+1 for which we have HeapRegions.
-// * max_length() returns the maximum number of regions the heap can have.
-//
-
-class HeapRegionSeq: public CHeapObj<mtGC> {
-  friend class VMStructs;
-
-  G1HeapRegionTable _regions;
-
-  G1RegionToSpaceMapper* _heap_mapper;
-  G1RegionToSpaceMapper* _prev_bitmap_mapper;
-  G1RegionToSpaceMapper* _next_bitmap_mapper;
-  G1RegionToSpaceMapper* _bot_mapper;
-  G1RegionToSpaceMapper* _cardtable_mapper;
-  G1RegionToSpaceMapper* _card_counts_mapper;
-
-  FreeRegionList _free_list;
-
-  // Each bit in this bitmap indicates that the corresponding region is available
-  // for allocation.
-  BitMap _available_map;
-
-   // The number of regions committed in the heap.
-  uint _num_committed;
-
-  // Internal only. The highest heap region +1 we allocated a HeapRegion instance for.
-  uint _allocated_heapregions_length;
-
-  HeapWord* heap_bottom() const { return _regions.bottom_address_mapped(); }
-  HeapWord* heap_end() const {return _regions.end_address_mapped(); }
-
-  void make_regions_available(uint index, uint num_regions = 1);
-
-  // Pass down commit calls to the VirtualSpace.
-  void commit_regions(uint index, size_t num_regions = 1);
-  void uncommit_regions(uint index, size_t num_regions = 1);
-
-  // Notify other data structures about change in the heap layout.
-  void update_committed_space(HeapWord* old_end, HeapWord* new_end);
-  // Calculate the starting region for each worker during parallel iteration so
-  // that they do not all start from the same region.
-  uint start_region_for_worker(uint worker_i, uint num_workers, uint num_regions) const;
-
-  // Find a contiguous set of empty or uncommitted regions of length num and return
-  // the index of the first region or G1_NO_HRS_INDEX if the search was unsuccessful.
-  // If only_empty is true, only empty regions are considered.
-  // Searches from bottom to top of the heap, doing a first-fit.
-  uint find_contiguous(size_t num, bool only_empty);
-  // Finds the next sequence of unavailable regions starting from start_idx. Returns the
-  // length of the sequence found. If this result is zero, no such sequence could be found,
-  // otherwise res_idx indicates the start index of these regions.
-  uint find_unavailable_from_idx(uint start_idx, uint* res_idx) const;
-  // Finds the next sequence of empty regions starting from start_idx, going backwards in
-  // the heap. Returns the length of the sequence found. If this value is zero, no
-  // sequence could be found, otherwise res_idx contains the start index of this range.
-  uint find_empty_from_idx_reverse(uint start_idx, uint* res_idx) const;
-  // Allocate a new HeapRegion for the given index.
-  HeapRegion* new_heap_region(uint hrs_index);
-#ifdef ASSERT
-public:
-  bool is_free(HeapRegion* hr) const;
-#endif
-  // Returns whether the given region is available for allocation.
-  bool is_available(uint region) const;
-
- public:
-  // Empty constructor, we'll initialize it with the initialize() method.
-  HeapRegionSeq() : _regions(), _heap_mapper(NULL), _num_committed(0),
-                    _next_bitmap_mapper(NULL), _prev_bitmap_mapper(NULL), _bot_mapper(NULL),
-                    _allocated_heapregions_length(0), _available_map(),
-                    _free_list("Free list", new MasterFreeRegionListMtSafeChecker())
-  { }
-
-  void initialize(G1RegionToSpaceMapper* heap_storage,
-                  G1RegionToSpaceMapper* prev_bitmap,
-                  G1RegionToSpaceMapper* next_bitmap,
-                  G1RegionToSpaceMapper* bot,
-                  G1RegionToSpaceMapper* cardtable,
-                  G1RegionToSpaceMapper* card_counts);
-
-  // Return the "dummy" region used for G1AllocRegion. This is currently a hardwired
-  // new HeapRegion that owns HeapRegion at index 0. Since at the moment we commit
-  // the heap from the lowest address, this region (and its associated data
-  // structures) are available and we do not need to check further.
-  HeapRegion* get_dummy_region() { return new_heap_region(0); }
-
-  // Return the HeapRegion at the given index. Assume that the index
-  // is valid.
-  inline HeapRegion* at(uint index) const;
-
-  // If addr is within the committed space return its corresponding
-  // HeapRegion, otherwise return NULL.
-  inline HeapRegion* addr_to_region(HeapWord* addr) const;
-
-  // Insert the given region into the free region list.
-  inline void insert_into_free_list(HeapRegion* hr);
-
-  // Insert the given region list into the global free region list.
-  void insert_list_into_free_list(FreeRegionList* list) {
-    _free_list.add_ordered(list);
-  }
-
-  HeapRegion* allocate_free_region(bool is_old) {
-    HeapRegion* hr = _free_list.remove_region(is_old);
-
-    if (hr != NULL) {
-      assert(hr->next() == NULL, "Single region should not have next");
-      assert(is_available(hr->hrs_index()), "Must be committed");
-    }
-    return hr;
-  }
-
-  inline void allocate_free_regions_starting_at(uint first, uint num_regions);
-
-  // Remove all regions from the free list.
-  void remove_all_free_regions() {
-    _free_list.remove_all();
-  }
-
-  // Return the number of committed free regions in the heap.
-  uint num_free_regions() const {
-    return _free_list.length();
-  }
-
-  size_t total_capacity_bytes() const {
-    return num_free_regions() * HeapRegion::GrainBytes;
-  }
-
-  // Return the number of available (uncommitted) regions.
-  uint available() const { return max_length() - length(); }
-
-  // Return the number of regions that have been committed in the heap.
-  uint length() const { return _num_committed; }
-
-  // Return the maximum number of regions in the heap.
-  uint max_length() const { return (uint)_regions.length(); }
-
-  MemRegion reserved() const { return MemRegion(heap_bottom(), heap_end()); }
-
-  // Expand the sequence to reflect that the heap has grown. Either create new
-  // HeapRegions, or re-use existing ones. Returns the number of regions the
-  // sequence was expanded by. If a HeapRegion allocation fails, the resulting
-  // number of regions might be smaller than what's desired.
-  uint expand_by(uint num_regions);
-
-  // Makes sure that the regions from start to start+num_regions-1 are available
-  // for allocation. Returns the number of regions that were committed to achieve
-  // this.
-  uint expand_at(uint start, uint num_regions);
-
-  // Find a contiguous set of empty regions of length num. Returns the start index of
-  // that set, or G1_NO_HRS_INDEX.
-  uint find_contiguous_only_empty(size_t num) { return find_contiguous(num, true); }
-  // Find a contiguous set of empty or unavailable regions of length num. Returns the
-  // start index of that set, or G1_NO_HRS_INDEX.
-  uint find_contiguous_empty_or_unavailable(size_t num) { return find_contiguous(num, false); }
-
-  HeapRegion* next_region_in_heap(const HeapRegion* r) const;
-
-  // Apply blk->doHeapRegion() on all committed regions in address order,
-  // terminating the iteration early if doHeapRegion() returns true.
-  void iterate(HeapRegionClosure* blk) const;
-
-  void par_iterate(HeapRegionClosure* blk, uint worker_id, uint no_of_par_workers, jint claim_value) const;
-
-  // Uncommit up to num_regions_to_remove regions that are completely free.
-  // Return the actual number of uncommitted regions.
-  uint shrink_by(uint num_regions_to_remove);
-
-  void verify();
-
-  // Do some sanity checking.
-  void verify_optional() PRODUCT_RETURN;
-};
-
-#endif // SHARE_VM_GC_IMPLEMENTATION_G1_HEAPREGIONSEQ_HPP
-
--- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSeq.inline.hpp	Thu Sep 04 14:45:48 2014 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,58 +0,0 @@
-/*
- * Copyright (c) 2001, 2014, 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
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef SHARE_VM_GC_IMPLEMENTATION_G1_HEAPREGIONSEQ_INLINE_HPP
-#define SHARE_VM_GC_IMPLEMENTATION_G1_HEAPREGIONSEQ_INLINE_HPP
-
-#include "gc_implementation/g1/heapRegion.hpp"
-#include "gc_implementation/g1/heapRegionSeq.hpp"
-#include "gc_implementation/g1/heapRegionSet.inline.hpp"
-
-inline HeapRegion* HeapRegionSeq::addr_to_region(HeapWord* addr) const {
-  assert(addr < heap_end(),
-        err_msg("addr: "PTR_FORMAT" end: "PTR_FORMAT, p2i(addr), p2i(heap_end())));
-  assert(addr >= heap_bottom(),
-        err_msg("addr: "PTR_FORMAT" bottom: "PTR_FORMAT, p2i(addr), p2i(heap_bottom())));
-
-  HeapRegion* hr = _regions.get_by_address(addr);
-  return hr;
-}
-
-inline HeapRegion* HeapRegionSeq::at(uint index) const {
-  assert(is_available(index), "pre-condition");
-  HeapRegion* hr = _regions.get_by_index(index);
-  assert(hr != NULL, "sanity");
-  assert(hr->hrs_index() == index, "sanity");
-  return hr;
-}
-
-inline void HeapRegionSeq::insert_into_free_list(HeapRegion* hr) {
-  _free_list.add_ordered(hr);
-}
-
-inline void HeapRegionSeq::allocate_free_regions_starting_at(uint first, uint num_regions) {
-  _free_list.remove_starting_at(at(first), num_regions);
-}
-
-#endif // SHARE_VM_GC_IMPLEMENTATION_G1_HEAPREGIONSEQ_INLINE_HPP
--- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.cpp	Thu Sep 04 14:45:48 2014 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.cpp	Wed Jul 05 20:00:03 2017 +0200
@@ -39,11 +39,11 @@
 
 #ifndef PRODUCT
 void HeapRegionSetBase::verify_region(HeapRegion* hr) {
-  assert(hr->containing_set() == this, err_msg("Inconsistent containing set for %u", hr->hrs_index()));
-  assert(!hr->is_young(), err_msg("Adding young region %u", hr->hrs_index())); // currently we don't use these sets for young regions
-  assert(hr->isHumongous() == regions_humongous(), err_msg("Wrong humongous state for region %u and set %s", hr->hrs_index(), name()));
-  assert(hr->is_empty() == regions_empty(), err_msg("Wrong empty state for region %u and set %s", hr->hrs_index(), name()));
-  assert(hr->rem_set()->verify_ready_for_par_iteration(), err_msg("Wrong iteration state %u", hr->hrs_index()));
+  assert(hr->containing_set() == this, err_msg("Inconsistent containing set for %u", hr->hrm_index()));
+  assert(!hr->is_young(), err_msg("Adding young region %u", hr->hrm_index())); // currently we don't use these sets for young regions
+  assert(hr->isHumongous() == regions_humongous(), err_msg("Wrong humongous state for region %u and set %s", hr->hrm_index(), name()));
+  assert(hr->is_empty() == regions_empty(), err_msg("Wrong empty state for region %u and set %s", hr->hrm_index(), name()));
+  assert(hr->rem_set()->verify_ready_for_par_iteration(), err_msg("Wrong iteration state %u", hr->hrm_index()));
 }
 #endif
 
@@ -158,7 +158,7 @@
     HeapRegion* curr_from = from_list->_head;
 
     while (curr_from != NULL) {
-      while (curr_to != NULL && curr_to->hrs_index() < curr_from->hrs_index()) {
+      while (curr_to != NULL && curr_to->hrm_index() < curr_from->hrm_index()) {
         curr_to = curr_to->next();
       }
 
@@ -183,7 +183,7 @@
       }
     }
 
-    if (_tail->hrs_index() < from_list->_tail->hrs_index()) {
+    if (_tail->hrm_index() < from_list->_tail->hrm_index()) {
       _tail = from_list->_tail;
     }
   }
@@ -309,8 +309,8 @@
     if (curr->next() != NULL) {
       guarantee(curr->next()->prev() == curr, "Next or prev pointers messed up");
     }
-    guarantee(curr->hrs_index() == 0 || curr->hrs_index() > last_index, "List should be sorted");
-    last_index = curr->hrs_index();
+    guarantee(curr->hrm_index() == 0 || curr->hrm_index() > last_index, "List should be sorted");
+    last_index = curr->hrm_index();
 
     capacity += curr->capacity();
 
@@ -319,7 +319,7 @@
     curr = curr->next();
   }
 
-  guarantee(_tail == prev0, err_msg("Expected %s to end with %u but it ended with %u.", name(), _tail->hrs_index(), prev0->hrs_index()));
+  guarantee(_tail == prev0, err_msg("Expected %s to end with %u but it ended with %u.", name(), _tail->hrm_index(), prev0->hrm_index()));
   guarantee(_tail == NULL || _tail->next() == NULL, "_tail should not have a next");
   guarantee(length() == count, err_msg("%s count mismatch. Expected %u, actual %u.", name(), length(), count));
   guarantee(total_capacity_bytes() == capacity, err_msg("%s capacity mismatch. Expected " SIZE_FORMAT ", actual " SIZE_FORMAT,
--- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.hpp	Thu Sep 04 14:45:48 2014 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.hpp	Wed Jul 05 20:00:03 2017 +0200
@@ -238,14 +238,14 @@
 
   // Add hr to the list. The region should not be a member of another set.
   // Assumes that the list is ordered and will preserve that order. The order
-  // is determined by hrs_index.
+  // is determined by hrm_index.
   inline void add_ordered(HeapRegion* hr);
 
   // Removes from head or tail based on the given argument.
   HeapRegion* remove_region(bool from_head);
 
   // Merge two ordered lists. The result is also ordered. The order is
-  // determined by hrs_index.
+  // determined by hrm_index.
   void add_ordered(FreeRegionList* from_list);
 
   // It empties the list by removing all regions from it.
--- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.inline.hpp	Thu Sep 04 14:45:48 2014 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.inline.hpp	Wed Jul 05 20:00:03 2017 +0200
@@ -60,14 +60,14 @@
   if (_head != NULL) {
     HeapRegion* curr;
 
-    if (_last != NULL && _last->hrs_index() < hr->hrs_index()) {
+    if (_last != NULL && _last->hrm_index() < hr->hrm_index()) {
       curr = _last;
     } else {
       curr = _head;
     }
 
     // Find first entry with a Region Index larger than entry to insert.
-    while (curr != NULL && curr->hrs_index() < hr->hrs_index()) {
+    while (curr != NULL && curr->hrm_index() < hr->hrm_index()) {
       curr = curr->next();
     }
 
--- a/hotspot/src/share/vm/gc_implementation/g1/sparsePRT.cpp	Thu Sep 04 14:45:48 2014 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/sparsePRT.cpp	Wed Jul 05 20:00:03 2017 +0200
@@ -453,7 +453,7 @@
 bool SparsePRT::add_card(RegionIdx_t region_id, CardIdx_t card_index) {
 #if SPARSE_PRT_VERBOSE
   gclog_or_tty->print_cr("  Adding card %d from region %d to region %u sparse.",
-                         card_index, region_id, _hr->hrs_index());
+                         card_index, region_id, _hr->hrm_index());
 #endif
   if (_next->occupied_entries() * 2 > _next->capacity()) {
     expand();
@@ -505,7 +505,7 @@
 
 #if SPARSE_PRT_VERBOSE
   gclog_or_tty->print_cr("  Expanded sparse table for %u to %d.",
-                         _hr->hrs_index(), _next->capacity());
+                         _hr->hrm_index(), _next->capacity());
 #endif
   for (size_t i = 0; i < last->capacity(); i++) {
     SparsePRTEntry* e = last->entry((int)i);
--- a/hotspot/src/share/vm/gc_implementation/g1/vmStructs_g1.hpp	Thu Sep 04 14:45:48 2014 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/vmStructs_g1.hpp	Wed Jul 05 20:00:03 2017 +0200
@@ -26,7 +26,7 @@
 #define SHARE_VM_GC_IMPLEMENTATION_G1_VMSTRUCTS_G1_HPP
 
 #include "gc_implementation/g1/heapRegion.hpp"
-#include "gc_implementation/g1/heapRegionSeq.inline.hpp"
+#include "gc_implementation/g1/heapRegionManager.inline.hpp"
 #include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
 
 #define VM_STRUCTS_G1(nonstatic_field, static_field)                          \
@@ -42,10 +42,10 @@
   nonstatic_field(G1HeapRegionTable, _bias,             size_t)               \
   nonstatic_field(G1HeapRegionTable, _shift_by,         uint)                 \
                                                                               \
-  nonstatic_field(HeapRegionSeq,   _regions,            G1HeapRegionTable)    \
-  nonstatic_field(HeapRegionSeq,   _num_committed,      uint)                 \
+  nonstatic_field(HeapRegionManager, _regions,          G1HeapRegionTable)    \
+  nonstatic_field(HeapRegionManager, _num_committed,    uint)                 \
                                                                               \
-  nonstatic_field(G1CollectedHeap, _hrs,                HeapRegionSeq)        \
+  nonstatic_field(G1CollectedHeap, _hrm,                HeapRegionManager)    \
   nonstatic_field(G1CollectedHeap, _summary_bytes_used, size_t)               \
   nonstatic_field(G1CollectedHeap, _g1mm,               G1MonitoringSupport*) \
   nonstatic_field(G1CollectedHeap, _old_set,            HeapRegionSetBase)    \
@@ -72,7 +72,7 @@
                                                                               \
   declare_type(G1OffsetTableContigSpace, CompactibleSpace)                    \
   declare_type(HeapRegion, G1OffsetTableContigSpace)                          \
-  declare_toplevel_type(HeapRegionSeq)                                        \
+  declare_toplevel_type(HeapRegionManager)                                        \
   declare_toplevel_type(HeapRegionSetBase)                                    \
   declare_toplevel_type(HeapRegionSetCount)                                   \
   declare_toplevel_type(G1MonitoringSupport)                                  \
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psGenerationCounters.cpp	Thu Sep 04 14:45:48 2014 -0700
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psGenerationCounters.cpp	Wed Jul 05 20:00:03 2017 +0200
@@ -30,6 +30,8 @@
 
 PSGenerationCounters::PSGenerationCounters(const char* name,
                                        int ordinal, int spaces,
+                                       size_t min_capacity,
+                                       size_t max_capacity,
                                        PSVirtualSpace* v):
     _ps_virtual_space(v) {
 
@@ -52,11 +54,11 @@
 
     cname = PerfDataManager::counter_name(_name_space, "minCapacity");
     PerfDataManager::create_constant(SUN_GC, cname, PerfData::U_Bytes,
-      _ps_virtual_space->committed_size(), CHECK);
+      min_capacity, CHECK);
 
     cname = PerfDataManager::counter_name(_name_space, "maxCapacity");
     PerfDataManager::create_constant(SUN_GC, cname, PerfData::U_Bytes,
-      _ps_virtual_space->reserved_size(), CHECK);
+      max_capacity, CHECK);
 
     cname = PerfDataManager::counter_name(_name_space, "capacity");
     _current_size = PerfDataManager::create_variable(SUN_GC, cname,
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psGenerationCounters.hpp	Thu Sep 04 14:45:48 2014 -0700
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psGenerationCounters.hpp	Wed Jul 05 20:00:03 2017 +0200
@@ -41,7 +41,7 @@
 
  public:
   PSGenerationCounters(const char* name, int ordinal, int spaces,
-                     PSVirtualSpace* v);
+                       size_t min_capacity, size_t max_capacity, PSVirtualSpace* v);
 
   void update_all() {
     assert(_virtual_space == NULL, "Only one should be in use");
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psOldGen.cpp	Thu Sep 04 14:45:48 2014 -0700
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psOldGen.cpp	Wed Jul 05 20:00:03 2017 +0200
@@ -149,8 +149,8 @@
 
 void PSOldGen::initialize_performance_counters(const char* perf_data_name, int level) {
   // Generation Counters, generation 'level', 1 subspace
-  _gen_counters = new PSGenerationCounters(perf_data_name, level, 1,
-                                           virtual_space());
+  _gen_counters = new PSGenerationCounters(perf_data_name, level, 1, _min_gen_size,
+                                           _max_gen_size, virtual_space());
   _space_counters = new SpaceCounters(perf_data_name, 0,
                                       virtual_space()->reserved_size(),
                                       _object_space, _gen_counters);
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psYoungGen.cpp	Thu Sep 04 14:45:48 2014 -0700
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psYoungGen.cpp	Wed Jul 05 20:00:03 2017 +0200
@@ -101,7 +101,8 @@
   }
 
   // Generation Counters - generation 0, 3 subspaces
-  _gen_counters = new PSGenerationCounters("new", 0, 3, _virtual_space);
+  _gen_counters = new PSGenerationCounters("new", 0, 3, _min_gen_size,
+                                           _max_gen_size, _virtual_space);
 
   // Compute maximum space sizes for performance counters
   ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap();
--- a/hotspot/src/share/vm/gc_implementation/shared/generationCounters.cpp	Thu Sep 04 14:45:48 2014 -0700
+++ b/hotspot/src/share/vm/gc_implementation/shared/generationCounters.cpp	Wed Jul 05 20:00:03 2017 +0200
@@ -62,11 +62,12 @@
 
 GenerationCounters::GenerationCounters(const char* name,
                                        int ordinal, int spaces,
+                                       size_t min_capacity, size_t max_capacity,
                                        VirtualSpace* v)
   : _virtual_space(v) {
   assert(v != NULL, "don't call this constructor if v == NULL");
   initialize(name, ordinal, spaces,
-             v->committed_size(), v->reserved_size(), v->committed_size());
+             min_capacity, max_capacity, v->committed_size());
 }
 
 GenerationCounters::GenerationCounters(const char* name,
--- a/hotspot/src/share/vm/gc_implementation/shared/generationCounters.hpp	Thu Sep 04 14:45:48 2014 -0700
+++ b/hotspot/src/share/vm/gc_implementation/shared/generationCounters.hpp	Wed Jul 05 20:00:03 2017 +0200
@@ -66,7 +66,7 @@
 
  public:
   GenerationCounters(const char* name, int ordinal, int spaces,
-                     VirtualSpace* v);
+                     size_t min_capacity, size_t max_capacity, VirtualSpace* v);
 
   ~GenerationCounters() {
     if (_name_space != NULL) FREE_C_HEAP_ARRAY(char, _name_space, mtGC);
--- a/hotspot/src/share/vm/memory/defNewGeneration.cpp	Thu Sep 04 14:45:48 2014 -0700
+++ b/hotspot/src/share/vm/memory/defNewGeneration.cpp	Wed Jul 05 20:00:03 2017 +0200
@@ -214,9 +214,11 @@
   _max_eden_size = size - (2*_max_survivor_size);
 
   // allocate the performance counters
+  GenCollectorPolicy* gcp = (GenCollectorPolicy*) GenCollectedHeap::heap()->collector_policy();
 
   // Generation counters -- generation 0, 3 subspaces
-  _gen_counters = new GenerationCounters("new", 0, 3, &_virtual_space);
+  _gen_counters = new GenerationCounters("new", 0, 3,
+      gcp->min_young_size(), gcp->max_young_size(), &_virtual_space);
   _gc_counters = new CollectorCounters(policy, 0);
 
   _eden_counters = new CSpaceCounters("eden", 0, _max_eden_size, _eden_space,
--- a/hotspot/src/share/vm/memory/filemap.cpp	Thu Sep 04 14:45:48 2014 -0700
+++ b/hotspot/src/share/vm/memory/filemap.cpp	Wed Jul 05 20:00:03 2017 +0200
@@ -445,7 +445,7 @@
       // close and remove the file. See bug 6372906.
       close();
       remove(_full_path);
-      fail_stop("Unable to write to shared archive file.", NULL);
+      fail_stop("Unable to write to shared archive file.");
     }
   }
   _file_offset += nbytes;
@@ -463,7 +463,7 @@
       // that the written file is the correct length.
       _file_offset -= 1;
       if (lseek(_fd, _file_offset, SEEK_SET) < 0) {
-        fail_stop("Unable to seek.", NULL);
+        fail_stop("Unable to seek.");
       }
       char zero = 0;
       write_bytes(&zero, 1);
@@ -534,7 +534,7 @@
   // other reserved memory (like the code cache).
   ReservedSpace rs(size, os::vm_allocation_granularity(), false, requested_addr);
   if (!rs.is_reserved()) {
-    fail_continue(err_msg("Unable to reserve shared space at required address " INTPTR_FORMAT, requested_addr));
+    fail_continue("Unable to reserve shared space at required address " INTPTR_FORMAT, requested_addr);
     return rs;
   }
   // the reserved virtual memory is for mapping class data sharing archive
@@ -558,7 +558,7 @@
                               requested_addr, size, si->_read_only,
                               si->_allow_exec);
   if (base == NULL || base != si->_base) {
-    fail_continue(err_msg("Unable to map %s shared space at required address.", shared_region_name[i]));
+    fail_continue("Unable to map %s shared space at required address.", shared_region_name[i]);
     return NULL;
   }
 #ifdef _WINDOWS
@@ -584,7 +584,7 @@
 
 void FileMapInfo::assert_mark(bool check) {
   if (!check) {
-    fail_stop("Mark mismatch while restoring from shared file.", NULL);
+    fail_stop("Mark mismatch while restoring from shared file.");
   }
 }
 
@@ -709,7 +709,7 @@
 void FileMapInfo::stop_sharing_and_unmap(const char* msg) {
   FileMapInfo *map_info = FileMapInfo::current_info();
   if (map_info) {
-    map_info->fail_continue(msg);
+    map_info->fail_continue("%s", msg);
     for (int i = 0; i < MetaspaceShared::n_regions; i++) {
       if (map_info->_header->_space[i]._base != NULL) {
         map_info->unmap_region(i);
@@ -717,6 +717,6 @@
       }
     }
   } else if (DumpSharedSpaces) {
-    fail_stop(msg, NULL);
+    fail_stop("%s", msg);
   }
 }
--- a/hotspot/src/share/vm/memory/filemap.hpp	Thu Sep 04 14:45:48 2014 -0700
+++ b/hotspot/src/share/vm/memory/filemap.hpp	Wed Jul 05 20:00:03 2017 +0200
@@ -190,8 +190,8 @@
   bool  remap_shared_readonly_as_readwrite();
 
   // Errors.
-  static void fail_stop(const char *msg, ...);
-  static void fail_continue(const char *msg, ...);
+  static void fail_stop(const char *msg, ...) ATTRIBUTE_PRINTF(1, 2);
+  static void fail_continue(const char *msg, ...) ATTRIBUTE_PRINTF(1, 2);
 
   // Return true if given address is in the mapped shared space.
   bool is_in_shared_space(const void* p) NOT_CDS_RETURN_(false);
--- a/hotspot/src/share/vm/memory/metaspace.cpp	Thu Sep 04 14:45:48 2014 -0700
+++ b/hotspot/src/share/vm/memory/metaspace.cpp	Wed Jul 05 20:00:03 2017 +0200
@@ -3126,6 +3126,8 @@
 
   if (DumpSharedSpaces) {
 #if INCLUDE_CDS
+    MetaspaceShared::estimate_regions_size();
+
     SharedReadOnlySize  = align_size_up(SharedReadOnlySize,  max_alignment);
     SharedReadWriteSize = align_size_up(SharedReadWriteSize, max_alignment);
     SharedMiscDataSize  = align_size_up(SharedMiscDataSize,  max_alignment);
--- a/hotspot/src/share/vm/memory/metaspaceShared.cpp	Thu Sep 04 14:45:48 2014 -0700
+++ b/hotspot/src/share/vm/memory/metaspaceShared.cpp	Wed Jul 05 20:00:03 2017 +0200
@@ -816,6 +816,7 @@
         //tty->print_cr("Preload failed: %s", class_name);
       }
     }
+    fclose(file);
   } else {
     char errmsg[JVM_MAXPATHLEN];
     os::lasterror(errmsg, JVM_MAXPATHLEN);
@@ -1086,3 +1087,49 @@
   }
   return true;
 }
+
+int MetaspaceShared::count_class(const char* classlist_file) {
+  if (classlist_file == NULL) {
+    return 0;
+  }
+  char class_name[256];
+  int class_count = 0;
+  FILE* file = fopen(classlist_file, "r");
+  if (file != NULL) {
+    while ((fgets(class_name, sizeof class_name, file)) != NULL) {
+      if (*class_name == '#') { // comment
+        continue;
+      }
+      class_count++;
+    }
+    fclose(file);
+  } else {
+    char errmsg[JVM_MAXPATHLEN];
+    os::lasterror(errmsg, JVM_MAXPATHLEN);
+    tty->print_cr("Loading classlist failed: %s", errmsg);
+    exit(1);
+  }
+
+  return class_count;
+}
+
+// the sizes are good for typical large applications that have a lot of shared
+// classes
+void MetaspaceShared::estimate_regions_size() {
+  int class_count = count_class(SharedClassListFile);
+  class_count += count_class(ExtraSharedClassListFile);
+
+  if (class_count > LargeThresholdClassCount) {
+    if (class_count < HugeThresholdClassCount) {
+      SET_ESTIMATED_SIZE(Large, ReadOnly);
+      SET_ESTIMATED_SIZE(Large, ReadWrite);
+      SET_ESTIMATED_SIZE(Large, MiscData);
+      SET_ESTIMATED_SIZE(Large, MiscCode);
+    } else {
+      SET_ESTIMATED_SIZE(Huge,  ReadOnly);
+      SET_ESTIMATED_SIZE(Huge,  ReadWrite);
+      SET_ESTIMATED_SIZE(Huge,  MiscData);
+      SET_ESTIMATED_SIZE(Huge,  MiscCode);
+    }
+  }
+}
--- a/hotspot/src/share/vm/memory/metaspaceShared.hpp	Thu Sep 04 14:45:48 2014 -0700
+++ b/hotspot/src/share/vm/memory/metaspaceShared.hpp	Wed Jul 05 20:00:03 2017 +0200
@@ -30,6 +30,19 @@
 #include "utilities/exceptions.hpp"
 #include "utilities/macros.hpp"
 
+#define LargeSharedArchiveSize    (300*M)
+#define HugeSharedArchiveSize     (800*M)
+#define ReadOnlyRegionPercentage  0.4
+#define ReadWriteRegionPercentage 0.55
+#define MiscDataRegionPercentage  0.03
+#define MiscCodeRegionPercentage  0.02
+#define LargeThresholdClassCount  5000
+#define HugeThresholdClassCount   40000
+
+#define SET_ESTIMATED_SIZE(type, region)                              \
+  Shared ##region## Size  = FLAG_IS_DEFAULT(Shared ##region## Size) ? \
+    (type ## SharedArchiveSize *  region ## RegionPercentage) : Shared ## region ## Size
+
 class FileMapInfo;
 
 // Class Data Sharing Support
@@ -112,5 +125,8 @@
   static void link_one_shared_class(Klass* obj, TRAPS);
   static void check_one_shared_class(Klass* obj);
   static void link_and_cleanup_shared_classes(TRAPS);
+
+  static int count_class(const char* classlist_file);
+  static void estimate_regions_size() NOT_CDS_RETURN;
 };
 #endif // SHARE_VM_MEMORY_METASPACE_SHARED_HPP
--- a/hotspot/src/share/vm/memory/tenuredGeneration.cpp	Thu Sep 04 14:45:48 2014 -0700
+++ b/hotspot/src/share/vm/memory/tenuredGeneration.cpp	Wed Jul 05 20:00:03 2017 +0200
@@ -53,9 +53,11 @@
   // initialize performance counters
 
   const char* gen_name = "old";
+  GenCollectorPolicy* gcp = (GenCollectorPolicy*) GenCollectedHeap::heap()->collector_policy();
 
   // Generation Counters -- generation 1, 1 subspace
-  _gen_counters = new GenerationCounters(gen_name, 1, 1, &_virtual_space);
+  _gen_counters = new GenerationCounters(gen_name, 1, 1,
+      gcp->min_old_size(), gcp->max_old_size(), &_virtual_space);
 
   _gc_counters = new CollectorCounters("MSC", 1);
 
--- a/hotspot/src/share/vm/oops/instanceKlass.cpp	Thu Sep 04 14:45:48 2014 -0700
+++ b/hotspot/src/share/vm/oops/instanceKlass.cpp	Wed Jul 05 20:00:03 2017 +0200
@@ -68,7 +68,7 @@
 #include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
 #include "gc_implementation/g1/g1OopClosures.inline.hpp"
 #include "gc_implementation/g1/g1RemSet.inline.hpp"
-#include "gc_implementation/g1/heapRegionSeq.inline.hpp"
+#include "gc_implementation/g1/heapRegionManager.inline.hpp"
 #include "gc_implementation/parNew/parOopClosures.inline.hpp"
 #include "gc_implementation/parallelScavenge/parallelScavengeHeap.inline.hpp"
 #include "gc_implementation/parallelScavenge/psPromotionManager.inline.hpp"
--- a/hotspot/src/share/vm/oops/instanceMirrorKlass.cpp	Thu Sep 04 14:45:48 2014 -0700
+++ b/hotspot/src/share/vm/oops/instanceMirrorKlass.cpp	Wed Jul 05 20:00:03 2017 +0200
@@ -42,7 +42,7 @@
 #include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
 #include "gc_implementation/g1/g1OopClosures.inline.hpp"
 #include "gc_implementation/g1/g1RemSet.inline.hpp"
-#include "gc_implementation/g1/heapRegionSeq.inline.hpp"
+#include "gc_implementation/g1/heapRegionManager.inline.hpp"
 #include "gc_implementation/parNew/parOopClosures.inline.hpp"
 #include "gc_implementation/parallelScavenge/psPromotionManager.inline.hpp"
 #include "gc_implementation/parallelScavenge/psScavenge.inline.hpp"
--- a/hotspot/src/share/vm/oops/instanceRefKlass.cpp	Thu Sep 04 14:45:48 2014 -0700
+++ b/hotspot/src/share/vm/oops/instanceRefKlass.cpp	Wed Jul 05 20:00:03 2017 +0200
@@ -38,7 +38,7 @@
 #include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
 #include "gc_implementation/g1/g1OopClosures.inline.hpp"
 #include "gc_implementation/g1/g1RemSet.inline.hpp"
-#include "gc_implementation/g1/heapRegionSeq.inline.hpp"
+#include "gc_implementation/g1/heapRegionManager.inline.hpp"
 #include "gc_implementation/parNew/parOopClosures.inline.hpp"
 #include "gc_implementation/parallelScavenge/psPromotionManager.inline.hpp"
 #include "gc_implementation/parallelScavenge/psScavenge.inline.hpp"
--- a/hotspot/src/share/vm/oops/objArrayKlass.cpp	Thu Sep 04 14:45:48 2014 -0700
+++ b/hotspot/src/share/vm/oops/objArrayKlass.cpp	Wed Jul 05 20:00:03 2017 +0200
@@ -51,7 +51,7 @@
 #include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
 #include "gc_implementation/g1/g1OopClosures.inline.hpp"
 #include "gc_implementation/g1/g1RemSet.inline.hpp"
-#include "gc_implementation/g1/heapRegionSeq.inline.hpp"
+#include "gc_implementation/g1/heapRegionManager.inline.hpp"
 #include "gc_implementation/parNew/parOopClosures.inline.hpp"
 #include "gc_implementation/parallelScavenge/psCompactionManager.hpp"
 #include "gc_implementation/parallelScavenge/psPromotionManager.inline.hpp"
--- a/hotspot/src/share/vm/opto/type.cpp	Thu Sep 04 14:45:48 2014 -0700
+++ b/hotspot/src/share/vm/opto/type.cpp	Wed Jul 05 20:00:03 2017 +0200
@@ -1708,8 +1708,8 @@
 // Make a TypeTuple from the range of a method signature
 const TypeTuple *TypeTuple::make_range(ciSignature* sig) {
   ciType* return_type = sig->return_type();
-  uint total_fields = TypeFunc::Parms + return_type->size();
-  const Type **field_array = fields(total_fields);
+  uint arg_cnt = return_type->size();
+  const Type **field_array = fields(arg_cnt);
   switch (return_type->basic_type()) {
   case T_LONG:
     field_array[TypeFunc::Parms]   = TypeLong::LONG;
@@ -1734,26 +1734,26 @@
   default:
     ShouldNotReachHere();
   }
-  return (TypeTuple*)(new TypeTuple(total_fields,field_array))->hashcons();
+  return (TypeTuple*)(new TypeTuple(TypeFunc::Parms + arg_cnt, field_array))->hashcons();
 }
 
 // Make a TypeTuple from the domain of a method signature
 const TypeTuple *TypeTuple::make_domain(ciInstanceKlass* recv, ciSignature* sig) {
-  uint total_fields = TypeFunc::Parms + sig->size();
+  uint arg_cnt = sig->size();
 
   uint pos = TypeFunc::Parms;
   const Type **field_array;
   if (recv != NULL) {
-    total_fields++;
-    field_array = fields(total_fields);
+    arg_cnt++;
+    field_array = fields(arg_cnt);
     // Use get_const_type here because it respects UseUniqueSubclasses:
     field_array[pos++] = get_const_type(recv)->join_speculative(TypePtr::NOTNULL);
   } else {
-    field_array = fields(total_fields);
+    field_array = fields(arg_cnt);
   }
 
   int i = 0;
-  while (pos < total_fields) {
+  while (pos < TypeFunc::Parms + arg_cnt) {
     ciType* type = sig->type_at(i);
 
     switch (type->basic_type()) {
@@ -1780,7 +1780,8 @@
     }
     i++;
   }
-  return (TypeTuple*)(new TypeTuple(total_fields,field_array))->hashcons();
+
+  return (TypeTuple*)(new TypeTuple(TypeFunc::Parms + arg_cnt, field_array))->hashcons();
 }
 
 const TypeTuple *TypeTuple::make( uint cnt, const Type **fields ) {
@@ -1789,6 +1790,7 @@
 
 //------------------------------fields-----------------------------------------
 // Subroutine call type with space allocated for argument types
+// Memory for Control, I_O, Memory, FramePtr, and ReturnAdr is allocated implicitly
 const Type **TypeTuple::fields( uint arg_cnt ) {
   const Type **flds = (const Type **)(Compile::current()->type_arena()->Amalloc_4((TypeFunc::Parms+arg_cnt)*sizeof(Type*) ));
   flds[TypeFunc::Control  ] = Type::CONTROL;
--- a/hotspot/src/share/vm/opto/type.hpp	Thu Sep 04 14:45:48 2014 -0700
+++ b/hotspot/src/share/vm/opto/type.hpp	Wed Jul 05 20:00:03 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2014, 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
@@ -635,6 +635,7 @@
   static const TypeTuple *make_domain(ciInstanceKlass* recv, ciSignature *sig);
 
   // Subroutine call type with space allocated for argument types
+  // Memory for Control, I_O, Memory, FramePtr, and ReturnAdr is allocated implicitly
   static const Type **fields( uint arg_cnt );
 
   virtual const Type *xmeet( const Type *t ) const;
--- a/hotspot/src/share/vm/runtime/java.cpp	Thu Sep 04 14:45:48 2014 -0700
+++ b/hotspot/src/share/vm/runtime/java.cpp	Wed Jul 05 20:00:03 2017 +0200
@@ -430,6 +430,8 @@
   }
 }
 
+jint volatile vm_getting_terminated = 0;
+
 // Note: before_exit() can be executed only once, if more than one threads
 //       are trying to shutdown the VM at the same time, only one thread
 //       can run before_exit() and all other threads must wait.
@@ -460,6 +462,8 @@
     }
   }
 
+  OrderAccess::release_store(&vm_getting_terminated, 1);
+
   // The only difference between this and Win32's _onexit procs is that
   // this version is invoked before any threads get killed.
   ExitProc* current = exit_procs;
--- a/hotspot/src/share/vm/services/mallocTracker.hpp	Thu Sep 04 14:45:48 2014 -0700
+++ b/hotspot/src/share/vm/services/mallocTracker.hpp	Wed Jul 05 20:00:03 2017 +0200
@@ -171,8 +171,9 @@
   // Total malloc'd memory used by arenas
   size_t total_arena() const;
 
-  inline size_t thread_count() {
-    return by_type(mtThreadStack)->malloc_count();
+  inline size_t thread_count() const {
+    MallocMemorySnapshot* s = const_cast<MallocMemorySnapshot*>(this);
+    return s->by_type(mtThreadStack)->malloc_count();
   }
 
   void reset();
--- a/hotspot/src/share/vm/services/memBaseline.cpp	Thu Sep 04 14:45:48 2014 -0700
+++ b/hotspot/src/share/vm/services/memBaseline.cpp	Wed Jul 05 20:00:03 2017 +0200
@@ -70,15 +70,13 @@
  */
 class MallocAllocationSiteWalker : public MallocSiteWalker {
  private:
-  SortedLinkedList<MallocSite, compare_malloc_size, ResourceObj::ARENA>
-                 _malloc_sites;
+  SortedLinkedList<MallocSite, compare_malloc_size> _malloc_sites;
   size_t         _count;
 
   // Entries in MallocSiteTable with size = 0 and count = 0,
   // when the malloc site is not longer there.
  public:
-  MallocAllocationSiteWalker(Arena* arena) : _count(0), _malloc_sites(arena) {
-  }
+  MallocAllocationSiteWalker() : _count(0) { }
 
   inline size_t count() const { return _count; }
 
@@ -109,13 +107,12 @@
 // Walk all virtual memory regions for baselining
 class VirtualMemoryAllocationWalker : public VirtualMemoryWalker {
  private:
-  SortedLinkedList<ReservedMemoryRegion, compare_virtual_memory_base, ResourceObj::ARENA>
+  SortedLinkedList<ReservedMemoryRegion, compare_virtual_memory_base>
                 _virtual_memory_regions;
   size_t        _count;
 
  public:
-  VirtualMemoryAllocationWalker(Arena* a) : _count(0), _virtual_memory_regions(a) {
-  }
+  VirtualMemoryAllocationWalker() : _count(0) { }
 
   bool do_allocation_site(const ReservedMemoryRegion* rgn)  {
     if (rgn->size() >= MemBaseline::SIZE_THRESHOLD) {
@@ -136,39 +133,30 @@
 
 
 bool MemBaseline::baseline_summary() {
-  assert(_malloc_memory_snapshot == NULL, "Malloc baseline not yet reset");
-  assert(_virtual_memory_snapshot == NULL, "Virtual baseline not yet reset");
-
-  _malloc_memory_snapshot =  new (arena()) MallocMemorySnapshot();
-  _virtual_memory_snapshot = new (arena()) VirtualMemorySnapshot();
-  if (_malloc_memory_snapshot == NULL || _virtual_memory_snapshot == NULL) {
-    return false;
-  }
-  MallocMemorySummary::snapshot(_malloc_memory_snapshot);
-  VirtualMemorySummary::snapshot(_virtual_memory_snapshot);
+  MallocMemorySummary::snapshot(&_malloc_memory_snapshot);
+  VirtualMemorySummary::snapshot(&_virtual_memory_snapshot);
   return true;
 }
 
 bool MemBaseline::baseline_allocation_sites() {
-  assert(arena() != NULL, "Just check");
   // Malloc allocation sites
-  MallocAllocationSiteWalker malloc_walker(arena());
+  MallocAllocationSiteWalker malloc_walker;
   if (!MallocSiteTable::walk_malloc_site(&malloc_walker)) {
     return false;
   }
 
-  _malloc_sites.set_head(malloc_walker.malloc_sites()->head());
+  _malloc_sites.move(malloc_walker.malloc_sites());
   // The malloc sites are collected in size order
   _malloc_sites_order = by_size;
 
   // Virtual memory allocation sites
-  VirtualMemoryAllocationWalker virtual_memory_walker(arena());
+  VirtualMemoryAllocationWalker virtual_memory_walker;
   if (!VirtualMemoryTracker::walk_virtual_memory(&virtual_memory_walker)) {
     return false;
   }
 
   // Virtual memory allocations are collected in call stack order
-  _virtual_memory_allocations.set_head(virtual_memory_walker.virtual_memory_allocations()->head());
+  _virtual_memory_allocations.move(virtual_memory_walker.virtual_memory_allocations());
 
   if (!aggregate_virtual_memory_allocation_sites()) {
     return false;
@@ -180,11 +168,6 @@
 }
 
 bool MemBaseline::baseline(bool summaryOnly) {
-  if (arena() == NULL) {
-    _arena = new (std::nothrow, mtNMT) Arena(mtNMT);
-    if (arena() == NULL) return false;
-  }
-
   reset();
 
   _class_count = InstanceKlass::number_of_instance_classes();
@@ -211,8 +194,7 @@
 }
 
 bool MemBaseline::aggregate_virtual_memory_allocation_sites() {
-  SortedLinkedList<VirtualMemoryAllocationSite, compare_allocation_site, ResourceObj::ARENA>
-    allocation_sites(arena());
+  SortedLinkedList<VirtualMemoryAllocationSite, compare_allocation_site> allocation_sites;
 
   VirtualMemoryAllocationIterator itr = virtual_memory_allocations();
   const ReservedMemoryRegion* rgn;
@@ -230,12 +212,12 @@
     site->commit_memory(rgn->committed_size());
   }
 
-  _virtual_memory_sites.set_head(allocation_sites.head());
+  _virtual_memory_sites.move(&allocation_sites);
   return true;
 }
 
 MallocSiteIterator MemBaseline::malloc_sites(SortingOrder order) {
-  assert(!_malloc_sites.is_empty(), "Detail baseline?");
+  assert(!_malloc_sites.is_empty(), "Not detail baseline");
   switch(order) {
     case by_size:
       malloc_sites_to_size_order();
@@ -251,7 +233,7 @@
 }
 
 VirtualMemorySiteIterator MemBaseline::virtual_memory_sites(SortingOrder order) {
-  assert(!_virtual_memory_sites.is_empty(), "Detail baseline?");
+  assert(!_virtual_memory_sites.is_empty(), "Not detail baseline");
   switch(order) {
     case by_size:
       virtual_memory_sites_to_size_order();
@@ -270,8 +252,7 @@
 // Sorting allocations sites in different orders
 void MemBaseline::malloc_sites_to_size_order() {
   if (_malloc_sites_order != by_size) {
-    SortedLinkedList<MallocSite, compare_malloc_size, ResourceObj::ARENA>
-      tmp(arena());
+    SortedLinkedList<MallocSite, compare_malloc_size> tmp;
 
     // Add malloc sites to sorted linked list to sort into size order
     tmp.move(&_malloc_sites);
@@ -283,8 +264,7 @@
 
 void MemBaseline::malloc_sites_to_allocation_site_order() {
   if (_malloc_sites_order != by_site) {
-    SortedLinkedList<MallocSite, compare_malloc_site, ResourceObj::ARENA>
-      tmp(arena());
+    SortedLinkedList<MallocSite, compare_malloc_site> tmp;
     // Add malloc sites to sorted linked list to sort into site (address) order
     tmp.move(&_malloc_sites);
     _malloc_sites.set_head(tmp.head());
@@ -295,8 +275,7 @@
 
 void MemBaseline::virtual_memory_sites_to_size_order() {
   if (_virtual_memory_sites_order != by_size) {
-    SortedLinkedList<VirtualMemoryAllocationSite, compare_virtual_memory_size, ResourceObj::ARENA>
-      tmp(arena());
+    SortedLinkedList<VirtualMemoryAllocationSite, compare_virtual_memory_size> tmp;
 
     tmp.move(&_virtual_memory_sites);
 
@@ -308,10 +287,9 @@
 
 void MemBaseline::virtual_memory_sites_to_reservation_site_order() {
   if (_virtual_memory_sites_order != by_size) {
-    SortedLinkedList<VirtualMemoryAllocationSite, compare_virtual_memory_site, ResourceObj::ARENA>
-      tmp(arena());
+    SortedLinkedList<VirtualMemoryAllocationSite, compare_virtual_memory_site> tmp;
 
-    tmp.add(&_virtual_memory_sites);
+    tmp.move(&_virtual_memory_sites);
 
     _virtual_memory_sites.set_head(tmp.head());
     tmp.set_head(NULL);
--- a/hotspot/src/share/vm/services/memBaseline.hpp	Thu Sep 04 14:45:48 2014 -0700
+++ b/hotspot/src/share/vm/services/memBaseline.hpp	Wed Jul 05 20:00:03 2017 +0200
@@ -61,28 +61,22 @@
   };
 
  private:
-  // All baseline data is stored in this arena
-  Arena*                  _arena;
-
   // Summary information
-  MallocMemorySnapshot*   _malloc_memory_snapshot;
-  VirtualMemorySnapshot*  _virtual_memory_snapshot;
+  MallocMemorySnapshot   _malloc_memory_snapshot;
+  VirtualMemorySnapshot  _virtual_memory_snapshot;
 
   size_t               _class_count;
 
   // Allocation sites information
   // Malloc allocation sites
-  LinkedListImpl<MallocSite, ResourceObj::ARENA>
-                       _malloc_sites;
+  LinkedListImpl<MallocSite>                  _malloc_sites;
 
   // All virtual memory allocations
-  LinkedListImpl<ReservedMemoryRegion, ResourceObj::ARENA>
-                       _virtual_memory_allocations;
+  LinkedListImpl<ReservedMemoryRegion>        _virtual_memory_allocations;
 
   // Virtual memory allocations by allocation sites, always in by_address
   // order
-  LinkedListImpl<VirtualMemoryAllocationSite, ResourceObj::ARENA>
-                       _virtual_memory_sites;
+  LinkedListImpl<VirtualMemoryAllocationSite> _virtual_memory_sites;
 
   SortingOrder         _malloc_sites_order;
   SortingOrder         _virtual_memory_sites_order;
@@ -93,30 +87,23 @@
   // create a memory baseline
   MemBaseline():
     _baseline_type(Not_baselined),
-    _class_count(0),
-    _arena(NULL),
-    _malloc_memory_snapshot(NULL),
-    _virtual_memory_snapshot(NULL),
-    _malloc_sites(NULL) {
+    _class_count(0) {
   }
 
   ~MemBaseline() {
     reset();
-    if (_arena != NULL) {
-      delete _arena;
-    }
   }
 
   bool baseline(bool summaryOnly = true);
 
   BaselineType baseline_type() const { return _baseline_type; }
 
-  MallocMemorySnapshot* malloc_memory_snapshot() const {
-    return _malloc_memory_snapshot;
+  MallocMemorySnapshot* malloc_memory_snapshot() {
+    return &_malloc_memory_snapshot;
   }
 
-  VirtualMemorySnapshot* virtual_memory_snapshot() const {
-    return _virtual_memory_snapshot;
+  VirtualMemorySnapshot* virtual_memory_snapshot() {
+    return &_virtual_memory_snapshot;
   }
 
   MallocSiteIterator malloc_sites(SortingOrder order);
@@ -133,10 +120,8 @@
   // memory
   size_t total_reserved_memory() const {
     assert(baseline_type() != Not_baselined, "Not yet baselined");
-    assert(_virtual_memory_snapshot != NULL, "No virtual memory snapshot");
-    assert(_malloc_memory_snapshot != NULL,  "No malloc memory snapshot");
-    size_t amount = _malloc_memory_snapshot->total() +
-           _virtual_memory_snapshot->total_reserved();
+    size_t amount = _malloc_memory_snapshot.total() +
+           _virtual_memory_snapshot.total_reserved();
     return amount;
   }
 
@@ -144,32 +129,30 @@
   // virtual memory
   size_t total_committed_memory() const {
     assert(baseline_type() != Not_baselined, "Not yet baselined");
-    assert(_virtual_memory_snapshot != NULL,
-      "Not a snapshot");
-    size_t amount = _malloc_memory_snapshot->total() +
-           _virtual_memory_snapshot->total_committed();
+    size_t amount = _malloc_memory_snapshot.total() +
+           _virtual_memory_snapshot.total_committed();
     return amount;
   }
 
   size_t total_arena_memory() const {
     assert(baseline_type() != Not_baselined, "Not yet baselined");
-    assert(_malloc_memory_snapshot != NULL, "Not yet baselined");
-    return _malloc_memory_snapshot->total_arena();
+    return _malloc_memory_snapshot.total_arena();
   }
 
   size_t malloc_tracking_overhead() const {
     assert(baseline_type() != Not_baselined, "Not yet baselined");
-    return _malloc_memory_snapshot->malloc_overhead()->size();
+    MemBaseline* bl = const_cast<MemBaseline*>(this);
+    return bl->_malloc_memory_snapshot.malloc_overhead()->size();
   }
 
-  const MallocMemory* malloc_memory(MEMFLAGS flag) const {
-    assert(_malloc_memory_snapshot != NULL, "Not a snapshot");
-    return _malloc_memory_snapshot->by_type(flag);
+  MallocMemory* malloc_memory(MEMFLAGS flag) {
+    assert(baseline_type() != Not_baselined, "Not yet baselined");
+    return _malloc_memory_snapshot.by_type(flag);
   }
 
-  const VirtualMemory* virtual_memory(MEMFLAGS flag) const {
-    assert(_virtual_memory_snapshot != NULL, "Not a snapshot");
-    return _virtual_memory_snapshot->by_type(flag);
+  VirtualMemory* virtual_memory(MEMFLAGS flag) {
+    assert(baseline_type() != Not_baselined, "Not yet baselined");
+    return _virtual_memory_snapshot.by_type(flag);
   }
 
 
@@ -180,24 +163,19 @@
 
   size_t thread_count() const {
     assert(baseline_type() != Not_baselined, "Not yet baselined");
-    assert(_malloc_memory_snapshot != NULL, "Baselined?");
-    return _malloc_memory_snapshot->thread_count();
+    return _malloc_memory_snapshot.thread_count();
   }
 
   // reset the baseline for reuse
   void reset() {
     _baseline_type = Not_baselined;
-    _malloc_memory_snapshot = NULL;
-    _virtual_memory_snapshot = NULL;
+    _malloc_memory_snapshot.reset();
+    _virtual_memory_snapshot.reset();
     _class_count  = 0;
 
-    _malloc_sites = NULL;
-    _virtual_memory_sites = NULL;
-    _virtual_memory_allocations = NULL;
-
-    if (_arena != NULL) {
-      _arena->destruct_contents();
-    }
+    _malloc_sites.clear();
+    _virtual_memory_sites.clear();
+    _virtual_memory_allocations.clear();
   }
 
  private:
@@ -210,8 +188,6 @@
   // Aggregate virtual memory allocation by allocation sites
   bool aggregate_virtual_memory_allocation_sites();
 
-  Arena* arena() { return _arena; }
-
   // Sorting allocation sites in different orders
   // Sort allocation sites in size order
   void malloc_sites_to_size_order();
--- a/hotspot/test/compiler/classUnloading/anonymousClass/TestAnonymousClassUnloading.java	Thu Sep 04 14:45:48 2014 -0700
+++ b/hotspot/test/compiler/classUnloading/anonymousClass/TestAnonymousClassUnloading.java	Wed Jul 05 20:00:03 2017 +0200
@@ -35,7 +35,9 @@
  * @summary "Tests unloading of anonymous classes."
  * @library /testlibrary /testlibrary/whitebox
  * @compile TestAnonymousClassUnloading.java
- * @run main ClassFileInstaller TestAnonymousClassUnloading sun.hotspot.WhiteBox
+ * @run main ClassFileInstaller TestAnonymousClassUnloading
+ *                              sun.hotspot.WhiteBox
+ *                              sun.hotspot.WhiteBox$WhiteBoxPermission
  * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:-BackgroundCompilation TestAnonymousClassUnloading
  */
 public class TestAnonymousClassUnloading {
--- a/hotspot/test/compiler/classUnloading/methodUnloading/TestMethodUnloading.java	Thu Sep 04 14:45:48 2014 -0700
+++ b/hotspot/test/compiler/classUnloading/methodUnloading/TestMethodUnloading.java	Wed Jul 05 20:00:03 2017 +0200
@@ -36,7 +36,7 @@
  * @build WorkerClass
  * @run main ClassFileInstaller sun.hotspot.WhiteBox
  *                              sun.hotspot.WhiteBox$WhiteBoxPermission
- * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:-BackgroundCompilation -XX:-UseCompressedOops -XX:+UseParallelGC -XX:CompileOnly=TestMethodUnloading::doWork TestMethodUnloading
+ * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:-BackgroundCompilation -XX:-UseCompressedOops -XX:CompileOnly=TestMethodUnloading::doWork TestMethodUnloading
  */
 public class TestMethodUnloading {
     private static final String workerClassName = "WorkerClass";
--- a/hotspot/test/compiler/rtm/cli/TestPrintPreciseRTMLockingStatisticsOptionOnSupportedConfig.java	Thu Sep 04 14:45:48 2014 -0700
+++ b/hotspot/test/compiler/rtm/cli/TestPrintPreciseRTMLockingStatisticsOptionOnSupportedConfig.java	Wed Jul 05 20:00:03 2017 +0200
@@ -54,16 +54,19 @@
         CommandLineOptionTest.verifyOptionValueForSameVM(optionName,
                 TestPrintPreciseRTMLockingStatisticsBase.DEFAULT_VALUE,
                 CommandLineOptionTest.UNLOCK_DIAGNOSTIC_VM_OPTIONS,
+                CommandLineOptionTest.UNLOCK_EXPERIMENTAL_VM_OPTIONS,
                 "-XX:+UseRTMLocking");
 
         CommandLineOptionTest.verifyOptionValueForSameVM(optionName,
                 TestPrintPreciseRTMLockingStatisticsBase.DEFAULT_VALUE,
                 CommandLineOptionTest.UNLOCK_DIAGNOSTIC_VM_OPTIONS,
+                CommandLineOptionTest.UNLOCK_EXPERIMENTAL_VM_OPTIONS,
                 "-XX:-UseRTMLocking", prepareOptionValue("true"));
 
         // verify that option could be turned on
         CommandLineOptionTest.verifyOptionValueForSameVM(optionName, "true",
                 CommandLineOptionTest.UNLOCK_DIAGNOSTIC_VM_OPTIONS,
+                CommandLineOptionTest.UNLOCK_EXPERIMENTAL_VM_OPTIONS,
                 "-XX:+UseRTMLocking", prepareOptionValue("true"));
     }
 
--- a/hotspot/test/compiler/rtm/cli/TestUseRTMDeoptOptionOnSupportedConfig.java	Thu Sep 04 14:45:48 2014 -0700
+++ b/hotspot/test/compiler/rtm/cli/TestUseRTMDeoptOptionOnSupportedConfig.java	Wed Jul 05 20:00:03 2017 +0200
@@ -63,13 +63,16 @@
         // verify default value
         CommandLineOptionTest.verifyOptionValueForSameVM("UseRTMDeopt",
                 TestUseRTMDeoptOptionOnSupportedConfig.DEFAULT_VALUE,
+                CommandLineOptionTest.UNLOCK_EXPERIMENTAL_VM_OPTIONS,
                 "-XX:+UseRTMLocking");
         // verify that option is off when UseRTMLocking is off
-        CommandLineOptionTest.verifyOptionValueForSameVM("UseRTMDeopt",
-                "false", "-XX:-UseRTMLocking", "-XX:+UseRTMDeopt");
+        CommandLineOptionTest.verifyOptionValueForSameVM("UseRTMDeopt", "false",
+                CommandLineOptionTest.UNLOCK_EXPERIMENTAL_VM_OPTIONS,
+                "-XX:-UseRTMLocking", "-XX:+UseRTMDeopt");
         // verify that option could be turned on
-        CommandLineOptionTest.verifyOptionValueForSameVM("UseRTMDeopt",
-                "true", "-XX:+UseRTMLocking", "-XX:+UseRTMDeopt");
+        CommandLineOptionTest.verifyOptionValueForSameVM("UseRTMDeopt", "true",
+                CommandLineOptionTest.UNLOCK_EXPERIMENTAL_VM_OPTIONS,
+                "-XX:+UseRTMLocking", "-XX:+UseRTMDeopt");
     }
 
     public static void main(String args[]) throws Throwable {
--- a/hotspot/test/compiler/rtm/cli/TestUseRTMLockingOptionOnSupportedConfig.java	Thu Sep 04 14:45:48 2014 -0700
+++ b/hotspot/test/compiler/rtm/cli/TestUseRTMLockingOptionOnSupportedConfig.java	Wed Jul 05 20:00:03 2017 +0200
@@ -59,24 +59,31 @@
                 new String[]{
                         RTMGenericCommandLineOptionTest.RTM_INSTR_ERROR,
                         unrecongnizedOption
-                }, ExitCode.OK, "-XX:+UseRTMLocking"
+                }, ExitCode.OK,
+                CommandLineOptionTest.UNLOCK_EXPERIMENTAL_VM_OPTIONS,
+                "-XX:+UseRTMLocking"
         );
 
         CommandLineOptionTest.verifySameJVMStartup(null,
                 new String[]{
                         RTMGenericCommandLineOptionTest.RTM_INSTR_ERROR,
                         unrecongnizedOption
-                }, ExitCode.OK, "-XX:-UseRTMLocking"
+                }, ExitCode.OK,
+                CommandLineOptionTest.UNLOCK_EXPERIMENTAL_VM_OPTIONS,
+                "-XX:-UseRTMLocking"
         );
         // verify that UseRTMLocking is of by default
         CommandLineOptionTest.verifyOptionValueForSameVM("UseRTMLocking",
-                TestUseRTMLockingOptionOnSupportedConfig.DEFAULT_VALUE);
+                TestUseRTMLockingOptionOnSupportedConfig.DEFAULT_VALUE,
+                CommandLineOptionTest.UNLOCK_EXPERIMENTAL_VM_OPTIONS);
         // verify that we can change UseRTMLocking value
         CommandLineOptionTest.verifyOptionValueForSameVM("UseRTMLocking",
                 TestUseRTMLockingOptionOnSupportedConfig.DEFAULT_VALUE,
+                CommandLineOptionTest.UNLOCK_EXPERIMENTAL_VM_OPTIONS,
                 "-XX:-UseRTMLocking");
         CommandLineOptionTest.verifyOptionValueForSameVM("UseRTMLocking",
-                "true", "-XX:+UseRTMLocking");
+                "true", CommandLineOptionTest.UNLOCK_EXPERIMENTAL_VM_OPTIONS,
+                "-XX:+UseRTMLocking");
     }
 
     public static void main(String args[]) throws Throwable {
--- a/hotspot/test/compiler/rtm/cli/TestUseRTMLockingOptionWithBiasedLocking.java	Thu Sep 04 14:45:48 2014 -0700
+++ b/hotspot/test/compiler/rtm/cli/TestUseRTMLockingOptionWithBiasedLocking.java	Wed Jul 05 20:00:03 2017 +0200
@@ -54,18 +54,22 @@
         // verify that we will not get a warning
         CommandLineOptionTest.verifySameJVMStartup(null,
                 new String[] { warningMessage }, ExitCode.OK,
+                CommandLineOptionTest.UNLOCK_EXPERIMENTAL_VM_OPTIONS,
                 "-XX:+UseRTMLocking", "-XX:-UseBiasedLocking");
         // verify that we will get a warning
         CommandLineOptionTest.verifySameJVMStartup(
                 new String[] { warningMessage }, null, ExitCode.OK,
+                CommandLineOptionTest.UNLOCK_EXPERIMENTAL_VM_OPTIONS,
                 "-XX:+UseRTMLocking", "-XX:+UseBiasedLocking");
         // verify that UseBiasedLocking is false when we use rtm locking
         CommandLineOptionTest.verifyOptionValueForSameVM("UseBiasedLocking",
-                "false", "-XX:+UseRTMLocking");
+                "false", CommandLineOptionTest.UNLOCK_EXPERIMENTAL_VM_OPTIONS,
+                "-XX:+UseRTMLocking");
         // verify that we can't turn on biased locking when
         // using rtm locking
         CommandLineOptionTest.verifyOptionValueForSameVM("UseBiasedLocking",
-                "false", "-XX:+UseRTMLocking", "-XX:+UseBiasedLocking");
+                "false", CommandLineOptionTest.UNLOCK_EXPERIMENTAL_VM_OPTIONS,
+                "-XX:+UseRTMLocking", "-XX:+UseBiasedLocking");
     }
 
     public static void main(String args[]) throws Throwable {
--- a/hotspot/test/gc/g1/TestHumongousShrinkHeap.java	Thu Sep 04 14:45:48 2014 -0700
+++ b/hotspot/test/gc/g1/TestHumongousShrinkHeap.java	Wed Jul 05 20:00:03 2017 +0200
@@ -22,9 +22,8 @@
  */
 
 /**
- * @ignore 8041506, 8041946, 8042051
  * @test TestHumongousShrinkHeap
- * @bug 8036025
+ * @bug 8036025 8056043
  * @summary Verify that heap shrinks after GC in the presence of fragmentation due to humongous objects
  * @library /testlibrary
  * @run main/othervm -XX:MinHeapFreeRatio=10 -XX:MaxHeapFreeRatio=50 -XX:+UseG1GC -XX:G1HeapRegionSize=1M -verbose:gc TestHumongousShrinkHeap
--- a/hotspot/test/gc/g1/TestStringDeduplicationTools.java	Thu Sep 04 14:45:48 2014 -0700
+++ b/hotspot/test/gc/g1/TestStringDeduplicationTools.java	Wed Jul 05 20:00:03 2017 +0200
@@ -129,8 +129,19 @@
         return list;
     }
 
+    /**
+     * Verifies that the given list contains expected number of unique strings.
+     * It's possible that deduplication hasn't completed yet, so the method
+     * will perform several attempts to check with a little pause between.
+     * The method throws RuntimeException to signal that verification failed.
+     *
+     * @param list strings to check
+     * @param uniqueExpected expected number of unique strings
+     * @throws RuntimeException if check fails
+     */
     private static void verifyStrings(ArrayList<String> list, int uniqueExpected) {
-        for (;;) {
+        boolean passed = false;
+        for (int attempts = 0; attempts < 10; attempts++) {
             // Check number of deduplicated strings
             ArrayList<Object> unique = new ArrayList<Object>(uniqueExpected);
             for (String string: list) {
@@ -153,11 +164,11 @@
                                ", uniqueExpected=" + uniqueExpected);
 
             if (unique.size() == uniqueExpected) {
-                System.out.println("Deduplication completed");
+                System.out.println("Deduplication completed (as fast as " + attempts + " iterations)");
+                passed = true;
                 break;
             } else {
                 System.out.println("Deduplication not completed, waiting...");
-
                 // Give the deduplication thread time to complete
                 try {
                     Thread.sleep(1000);
@@ -166,6 +177,9 @@
                 }
             }
         }
+        if (!passed) {
+            throw new RuntimeException("String verification failed");
+        }
     }
 
     private static OutputAnalyzer runTest(String... extraArgs) throws Exception {
@@ -247,14 +261,20 @@
             forceDeduplication(ageThreshold, FullGC);
 
             // Wait for deduplication to occur
-            while (getValue(dupString1) != getValue(baseString)) {
+            for (int attempts = 0; attempts < 10; attempts++) {
+                if (getValue(dupString1) == getValue(baseString)) {
+                    break;
+                }
                 System.out.println("Waiting...");
                 try {
-                    Thread.sleep(100);
+                    Thread.sleep(1000);
                 } catch (Exception e) {
                     throw new RuntimeException(e);
                 }
             }
+            if (getValue(dupString1) != getValue(baseString)) {
+                throw new RuntimeException("Deduplication has not occurred");
+            }
 
             // Create a new duplicate of baseString
             StringBuilder sb2 = new StringBuilder(baseString);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/gc/whitebox/TestWBGC.java	Wed Jul 05 20:00:03 2017 +0200
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2014, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test TestWBGC
+ * @bug 8055098
+ * @summary Test verify that WB methods isObjectInOldGen and youngGC works correctly.
+ * @library /testlibrary /testlibrary/whitebox
+ * @build TestWBGC
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ * @run driver TestWBGC
+ */
+import com.oracle.java.testlibrary.*;
+import sun.hotspot.WhiteBox;
+
+public class TestWBGC {
+
+    public static void main(String args[]) throws Exception {
+        ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
+                true,
+                "-Xbootclasspath/a:.",
+                "-XX:+UnlockDiagnosticVMOptions",
+                "-XX:+WhiteBoxAPI",
+                "-XX:MaxTenuringThreshold=1",
+                "-XX:+PrintGC",
+                GCYoungTest.class.getName());
+
+        OutputAnalyzer output = new OutputAnalyzer(pb.start());
+        System.out.println(output.getStdout());
+        output.shouldHaveExitValue(0);
+        output.shouldContain("WhiteBox Initiated Young GC");
+        output.shouldNotContain("Full");
+        // To be sure that we don't provoke Full GC additionaly to young
+    }
+
+    public static class GCYoungTest {
+        static WhiteBox wb = WhiteBox.getWhiteBox();
+        public static Object obj;
+
+        public static void main(String args[]) {
+            obj = new Object();
+            Asserts.assertFalse(wb.isObjectInOldGen(obj));
+            wb.youngGC();
+            wb.youngGC();
+            // 2 young GC is needed to promote object into OldGen
+            Asserts.assertTrue(wb.isObjectInOldGen(obj));
+        }
+    }
+}
--- a/hotspot/test/runtime/CompressedOops/CompressedClassPointers.java	Thu Sep 04 14:45:48 2014 -0700
+++ b/hotspot/test/runtime/CompressedOops/CompressedClassPointers.java	Wed Jul 05 20:00:03 2017 +0200
@@ -26,7 +26,6 @@
  * @bug 8024927
  * @summary Testing address of compressed class pointer space as best as possible.
  * @library /testlibrary
- * @ignore 8055164
  */
 
 import com.oracle.java.testlibrary.*;
@@ -89,7 +88,6 @@
             "-version");
         OutputAnalyzer output = new OutputAnalyzer(pb.start());
         output.shouldContain("HeapBaseMinAddress must be at least");
-        output.shouldContain("HotSpot");
         output.shouldHaveExitValue(0);
     }
 
--- a/hotspot/test/runtime/NMT/CommandLineEmptyArgument.java	Thu Sep 04 14:45:48 2014 -0700
+++ b/hotspot/test/runtime/NMT/CommandLineEmptyArgument.java	Wed Jul 05 20:00:03 2017 +0200
@@ -26,7 +26,6 @@
  * @key nmt
  * @summary Empty argument to NMT should result in an informative error message
  * @library /testlibrary
- * @ignore 8055051
  */
 
 import com.oracle.java.testlibrary.*;
--- a/hotspot/test/runtime/NMT/JcmdDetailDiff.java	Thu Sep 04 14:45:48 2014 -0700
+++ b/hotspot/test/runtime/NMT/JcmdDetailDiff.java	Wed Jul 05 20:00:03 2017 +0200
@@ -62,21 +62,18 @@
 
         output = new OutputAnalyzer(pb.start());
         output.shouldContain("Test (reserved=256KB +256KB, committed=0KB)");
-        output.shouldContain("WB_NMTReserveMemory");
 
         wb.NMTCommitMemory(addr, commitSize);
         pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "detail.diff", "scale=KB"});
 
         output = new OutputAnalyzer(pb.start());
         output.shouldContain("Test (reserved=256KB +256KB, committed=128KB +128KB)");
-        output.shouldContain("WB_NMTReserveMemory");
 
         wb.NMTUncommitMemory(addr, commitSize);
         pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "detail.diff", "scale=KB"});
 
         output = new OutputAnalyzer(pb.start());
         output.shouldContain("Test (reserved=256KB +256KB, committed=0KB)");
-        output.shouldContain("WB_NMTReserveMemory");
 
         wb.NMTReleaseMemory(addr, reserveSize);
         pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "detail.diff", "scale=KB"});
--- a/hotspot/test/runtime/NMT/MallocSiteHashOverflow.java	Thu Sep 04 14:45:48 2014 -0700
+++ b/hotspot/test/runtime/NMT/MallocSiteHashOverflow.java	Wed Jul 05 20:00:03 2017 +0200
@@ -22,10 +22,9 @@
  */
 
 /*
- * @key stress
  * @test
  * @summary Test corner case that overflows malloc site hashtable bucket
- * @key nmt jcmd
+ * @key nmt jcmd stress
  * @library /testlibrary /testlibrary/whitebox
  * @ignore - This test is disabled since it will stress NMT and timeout during normal testing
  * @build MallocSiteHashOverflow
--- a/hotspot/test/runtime/NMT/MallocStressTest.java	Thu Sep 04 14:45:48 2014 -0700
+++ b/hotspot/test/runtime/NMT/MallocStressTest.java	Wed Jul 05 20:00:03 2017 +0200
@@ -22,10 +22,9 @@
  */
 
 /*
- * @key stress
  * @test
  * @summary Stress test for malloc tracking
- * @key nmt jcmd
+ * @key nmt jcmd stress
  * @library /testlibrary /testlibrary/whitebox
  * @build MallocStressTest
  * @ignore - This test is disabled since it will stress NMT and timeout during normal testing
--- a/hotspot/test/runtime/NMT/NMTWithCDS.java	Thu Sep 04 14:45:48 2014 -0700
+++ b/hotspot/test/runtime/NMT/NMTWithCDS.java	Wed Jul 05 20:00:03 2017 +0200
@@ -34,14 +34,15 @@
 
   public static void main(String[] args) throws Exception {
     ProcessBuilder pb;
-    pb = ProcessTools.createJavaProcessBuilder("-XX:SharedArchiveFile=./sample.jsa", "-Xshare:dump");
+    pb = ProcessTools.createJavaProcessBuilder(
+        "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=./sample.jsa", "-Xshare:dump");
     OutputAnalyzer output = new OutputAnalyzer(pb.start());
     try {
       output.shouldContain("Loading classes to share");
       output.shouldHaveExitValue(0);
 
       pb = ProcessTools.createJavaProcessBuilder(
-        "-XX:NativeMemoryTracking=detail", "-XX:SharedArchiveFile=./sample.jsa", "-Xshare:on", "-version");
+        "-XX:+UnlockDiagnosticVMOptions", "-XX:NativeMemoryTracking=detail", "-XX:SharedArchiveFile=./sample.jsa", "-Xshare:on", "-version");
       output = new OutputAnalyzer(pb.start());
       output.shouldContain("sharing");
       output.shouldHaveExitValue(0);
--- a/hotspot/test/runtime/NMT/VirtualAllocCommitUncommitRecommit.java	Thu Sep 04 14:45:48 2014 -0700
+++ b/hotspot/test/runtime/NMT/VirtualAllocCommitUncommitRecommit.java	Wed Jul 05 20:00:03 2017 +0200
@@ -26,7 +26,6 @@
  * @summary Test reserve/commit/uncommit/release of virtual memory and that we track it correctly
  * @key nmt jcmd
  * @library /testlibrary /testlibrary/whitebox
- * @ignore
  * @build VirtualAllocCommitUncommitRecommit
  * @run main ClassFileInstaller sun.hotspot.WhiteBox
  * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:NativeMemoryTracking=detail VirtualAllocCommitUncommitRecommit
@@ -43,8 +42,8 @@
 
     public static void main(String args[]) throws Exception {
         OutputAnalyzer output;
-        long commitSize = 4 * 1024; // 4KB
-        long reserveSize = 1024 * 1024; // 1024KB
+        long commitSize = 128 * 1024; // 128KB
+        long reserveSize = 4 * 1024 * 1024; // 4096KB
         long addr;
 
         String pid = Integer.toString(ProcessTools.getProcessId());
@@ -63,11 +62,11 @@
                 "VM.native_memory", "detail" });
 
         output = new OutputAnalyzer(pb.start());
-        output.shouldContain("Test (reserved=1024KB, committed=0KB)");
+        output.shouldContain("Test (reserved=4096KB, committed=0KB)");
         if (has_nmt_detail) {
             output.shouldMatch("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*"
                     + Long.toHexString(addr + reserveSize)
-                    + "\\] reserved 1024KB for Test");
+                    + "\\] reserved 4096KB for Test");
         }
 
         long addrA = addr;
@@ -84,24 +83,24 @@
         wb.NMTCommitMemory(addrD, commitSize);
 
         output = new OutputAnalyzer(pb.start());
-        output.shouldContain("Test (reserved=1024KB, committed=16KB)");
+        output.shouldContain("Test (reserved=4096KB, committed=512KB)");
 
         if (has_nmt_detail) {
             output.shouldMatch("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*"
                     + Long.toHexString(addr + reserveSize)
-                    + "\\] reserved 1024KB for Test");
+                    + "\\] reserved 4096KB for Test");
         }
         // uncommit BC
         wb.NMTUncommitMemory(addrB, commitSize);
         wb.NMTUncommitMemory(addrC, commitSize);
 
         output = new OutputAnalyzer(pb.start());
-        output.shouldContain("Test (reserved=1024KB, committed=8KB)");
+        output.shouldContain("Test (reserved=4096KB, committed=256KB)");
 
         if (has_nmt_detail) {
             output.shouldMatch("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*"
                     + Long.toHexString(addr + reserveSize)
-                    + "\\] reserved 1024KB for Test");
+                    + "\\] reserved 4096KB for Test");
         }
 
         // commit EF
@@ -109,22 +108,22 @@
         wb.NMTCommitMemory(addrF, commitSize);
 
         output = new OutputAnalyzer(pb.start());
-        output.shouldContain("Test (reserved=1024KB, committed=16KB)");
+        output.shouldContain("Test (reserved=4096KB, committed=512KB)");
         if (has_nmt_detail) {
             output.shouldMatch("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*"
                     + Long.toHexString(addr + reserveSize)
-                    + "\\] reserved 1024KB for Test");
+                    + "\\] reserved 4096KB for Test");
         }
 
         // uncommit A
         wb.NMTUncommitMemory(addrA, commitSize);
 
         output = new OutputAnalyzer(pb.start());
-        output.shouldContain("Test (reserved=1024KB, committed=12KB)");
+        output.shouldContain("Test (reserved=4096KB, committed=384KB)");
         if (has_nmt_detail) {
             output.shouldMatch("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*"
                     + Long.toHexString(addr + reserveSize)
-                    + "\\] reserved 1024KB for Test");
+                    + "\\] reserved 4096KB for Test");
         }
 
         // commit ABC
@@ -133,11 +132,11 @@
         wb.NMTCommitMemory(addrC, commitSize);
 
         output = new OutputAnalyzer(pb.start());
-        output.shouldContain("Test (reserved=1024KB, committed=24KB)");
+        output.shouldContain("Test (reserved=4096KB, committed=768KB)");
         if (has_nmt_detail) {
             output.shouldMatch("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*"
                     + Long.toHexString(addr + reserveSize)
-                    + "\\] reserved 1024KB for Test");
+                    + "\\] reserved 4096KB for Test");
         }
 
         // uncommit ABCDEF
@@ -149,11 +148,11 @@
         wb.NMTUncommitMemory(addrF, commitSize);
 
         output = new OutputAnalyzer(pb.start());
-        output.shouldContain("Test (reserved=1024KB, committed=0KB)");
+        output.shouldContain("Test (reserved=4096KB, committed=0KB)");
         if (has_nmt_detail) {
             output.shouldMatch("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*"
                     + Long.toHexString(addr + reserveSize)
-                    + "\\] reserved 1024KB for Test");
+                    + "\\] reserved 4096KB for Test");
         }
 
         // release
@@ -161,6 +160,6 @@
         output = new OutputAnalyzer(pb.start());
         output.shouldNotContain("Test (reserved=");
         output.shouldNotMatch("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*"
-                + Long.toHexString(addr + reserveSize) + "\\] reserved");
+                + Long.toHexString(addr + reserveSize) + "\\] reserved 4096KB for Test");
     }
 }
--- a/hotspot/test/runtime/jsig/Test8017498.sh	Thu Sep 04 14:45:48 2014 -0700
+++ b/hotspot/test/runtime/jsig/Test8017498.sh	Wed Jul 05 20:00:03 2017 +0200
@@ -31,15 +31,14 @@
 ## @bug 8022301
 ## @bug 8025519
 ## @summary sigaction(sig) results in process hang/timed-out if sig is much greater than SIGRTMAX
-## @ignore 8041727
 ## @run shell/timeout=60 Test8017498.sh
 ##
 
-if [ "${TESTSRC}" = "" ]
-then
-  TESTSRC=${PWD}
+if [ -z "${TESTSRC}" ]; then
+  TESTSRC="${PWD}"
   echo "TESTSRC not set.  Using "${TESTSRC}" as default"
 fi
+
 echo "TESTSRC=${TESTSRC}"
 ## Adding common setup Variables for running shell tests.
 . ${TESTSRC}/../../test_env.sh
@@ -52,13 +51,13 @@
   Linux)
     echo "Testing on Linux"
     gcc_cmd=`which gcc`
-    if [ "x$gcc_cmd" == "x" ]; then
+    if [ -z "$gcc_cmd" ]; then
         echo "WARNING: gcc not found. Cannot execute test." 2>&1
         exit 0;
     fi
     MY_LD_PRELOAD=${TESTJAVA}${FS}jre${FS}lib${FS}${VM_CPU}${FS}libjsig.so
-    if [ "$VM_BITS" == "32" ] && [ "$VM_CPU" != "arm" ] && [ "$VM_CPU" != "ppc" ]; then
-            EXTRA_CFLAG=-m32
+    if [ "$VM_BITS" = "32" ] && [ "$VM_CPU" != "arm" ] && [ "$VM_CPU" != "ppc" ]; then
+        EXTRA_CFLAG=-m32
     fi
     echo MY_LD_PRELOAD = ${MY_LD_PRELOAD}
     ;;
@@ -70,7 +69,7 @@
 
 THIS_DIR=.
 
-cp ${TESTSRC}${FS}*.java ${THIS_DIR}
+cp "${TESTSRC}${FS}"*.java "${THIS_DIR}"
 ${COMPILEJAVA}${FS}bin${FS}javac *.java
 
 $gcc_cmd -DLINUX -fPIC -shared \
@@ -80,16 +79,19 @@
     -I${COMPILEJAVA}${FS}include${FS}linux \
     ${TESTSRC}${FS}TestJNI.c
 
+if [ $? -ne 0 ] ; then
+    echo "Compile failed, Ignoring failed compilation and forcing the test to pass"
+    exit 0
+fi
+
 # run the java test in the background
 cmd="LD_PRELOAD=$MY_LD_PRELOAD \
     ${TESTJAVA}${FS}bin${FS}java \
     -Djava.library.path=. -server TestJNI 100"
-echo "$cmd > test.out 2>&1"
-eval $cmd > test.out 2>&1
+echo "$cmd > test.out"
+eval $cmd > test.out
 
-grep "old handler" test.out > ${NULL}
-if [ $? = 0 ]
-then
+if grep "old handler" test.out > ${NULL}; then
     echo "Test Passed"
     exit 0
 fi
--- a/jaxp/.hgtags	Thu Sep 04 14:45:48 2014 -0700
+++ b/jaxp/.hgtags	Wed Jul 05 20:00:03 2017 +0200
@@ -271,3 +271,4 @@
 a5aea8318ae4a9c2105228568688875142d70344 jdk9-b26
 2bfaf29cc90b19948938e3ef1a0983eee68806c7 jdk9-b27
 dc1e26434b3fd7e9b8eeab149103c1e30965f95c jdk9-b28
+30adcd13a313ea91e81164801a2f89282756d933 jdk9-b29
--- a/jaxws/.hgtags	Thu Sep 04 14:45:48 2014 -0700
+++ b/jaxws/.hgtags	Wed Jul 05 20:00:03 2017 +0200
@@ -274,3 +274,4 @@
 9b43f3993b96c2213428e95127a2d3fd0e709d3a jdk9-b26
 dcaa586ab756420e9a62643793bacef2c84bf637 jdk9-b27
 5282a14f131f897cc9575872c0fae72d47dc4e65 jdk9-b28
+3d1a4bfb6abbf5011ba6d8896301ee3b6ef3ba72 jdk9-b29
--- a/jdk/.hgtags	Thu Sep 04 14:45:48 2014 -0700
+++ b/jdk/.hgtags	Wed Jul 05 20:00:03 2017 +0200
@@ -271,3 +271,4 @@
 dde9f5cfde5f46e62ceb5fab81151578e5277aef jdk9-b26
 f0870554049807d3392bd7976ab114f7f2b7bafa jdk9-b27
 1828f73b35cfe35e460e41fd6e087ab1f83e0621 jdk9-b28
+2da27e8e2c865e154f0c2eb9009f011a44649b11 jdk9-b29
--- a/jdk/make/CreateJars.gmk	Thu Sep 04 14:45:48 2014 -0700
+++ b/jdk/make/CreateJars.gmk	Wed Jul 05 20:00:03 2017 +0200
@@ -76,13 +76,24 @@
     iw ja ko lt lv mk ms mt nl no pl pt ro ru sk sl sq sr sv \
     th tr uk vi zh
 
-LOCALEDATA_INCLUDES := $(addprefix sun/text/resources/, $(LOCALEDATA_INCLUDE_LOCALES)) \
+LOCALEDATA_INCLUDES := sun/util/resources/provider/NonEnLocaleDataMetaInfo.class
+LOCALEDATA_INCLUDES += $(addprefix sun/text/resources/, $(LOCALEDATA_INCLUDE_LOCALES)) \
     $(addprefix sun/util/resources/, $(LOCALEDATA_INCLUDE_LOCALES))
 
-$(eval $(call SetupArchive,BUILD_LOCALEDATA_JAR, , \
-    SRCS := $(JDK_OUTPUTDIR)/modules/jdk.localedata, \
+LOCALEDATA_SERVICES_DIR := $(IMAGES_OUTPUTDIR)/localemetainfo
+
+LOCALEDATA_METAINF_SERVICES := $(LOCALEDATA_SERVICES_DIR)/META-INF/services/sun.util.locale.provider.LocaleDataMetaInfo
+
+$(LOCALEDATA_METAINF_SERVICES): $(JDK_TOPDIR)/src/jdk.localedata/META-INF/localedata-services/sun.util.locale.provider.LocaleDataMetaInfo
+	$(install-file)
+
+$(eval $(call SetupArchive,BUILD_LOCALEDATA_JAR, \
+    $(LOCALEDATA_METAINF_SERVICES), \
+    SRCS := $(JDK_OUTPUTDIR)/modules/jdk.localedata \
+        $(LOCALEDATA_SERVICES_DIR), \
     SUFFIXES := .class _dict _th, \
     INCLUDES := $(LOCALEDATA_INCLUDES), \
+    EXTRA_FILES := META-INF/services/sun.util.locale.provider.LocaleDataMetaInfo, \
     JAR := $(IMAGES_OUTPUTDIR)/lib/ext/localedata.jar, \
     SKIP_METAINF := true))
 
@@ -210,6 +221,8 @@
     sun/tools/tree \
     sun/tools/util \
     sun/util/cldr/CLDRLocaleDataMetaInfo.class \
+    sun/util/resources/provider/NonEnLocaleDataMetaInfo.class \
+    META-INF/services/sun.util.locale.provider.LocaleDataMetaInfo \
     sun/util/resources/cldr \
     $(LOCALEDATA_INCLUDES) \
     com/oracle/jrockit/jfr \
@@ -429,13 +442,23 @@
 
 CLDRDATA_JAR_DST := $(IMAGES_OUTPUTDIR)/lib/ext/cldrdata.jar
 
-$(eval $(call SetupArchive,BUILD_CLDRDATA_JAR, , \
+CLDR_SERVICES_DIR := $(IMAGES_OUTPUTDIR)/cldrmetainfo
+
+CLDR_METAINF_SERVICES := $(CLDR_SERVICES_DIR)/META-INF/services/sun.util.locale.provider.LocaleDataMetaInfo
+
+$(CLDR_METAINF_SERVICES): $(JDK_TOPDIR)/src/jdk.localedata/META-INF/cldrdata-services/sun.util.locale.provider.LocaleDataMetaInfo
+	$(install-file)
+
+$(eval $(call SetupArchive,BUILD_CLDRDATA_JAR, \
+    $(CLDR_METAINF_SERVICES), \
     SRCS := $(JDK_OUTPUTDIR)/modules/jdk.localedata \
-        $(JDK_OUTPUTDIR)/modules/java.base, \
+        $(JDK_OUTPUTDIR)/modules/java.base \
+        $(CLDR_SERVICES_DIR), \
     SUFFIXES := .class, \
     INCLUDES := sun/text/resources/cldr \
         sun/util/cldr/CLDRLocaleDataMetaInfo.class \
         sun/util/resources/cldr, \
+    EXTRA_FILES := META-INF/services/sun.util.locale.provider.LocaleDataMetaInfo, \
     JAR := $(CLDRDATA_JAR_DST), \
     EXTRA_MANIFEST_ATTR := CLDR-Version: $(CLDRVERSION), \
     SKIP_METAINF := true))
--- a/jdk/make/copy/Copy-java.desktop.gmk	Thu Sep 04 14:45:48 2014 -0700
+++ b/jdk/make/copy/Copy-java.desktop.gmk	Wed Jul 05 20:00:03 2017 +0200
@@ -43,25 +43,6 @@
 
 ################################################################################
 
-ICCPROFILE_DEST_DIR := $(LIB_DST_DIR)/cmm
-
-ifdef OPENJDK
-  ICCPROFILE_SRC_DIR := $(JDK_TOPDIR)/src/java.desktop/share/conf/cmm/lcms
-else
-  ICCPROFILE_SRC_DIR := $(JDK_TOPDIR)/src/closed/java.desktop/share/conf/cmm/kcms
-endif
-
-ICCPROFILE_SRCS := $(wildcard $(ICCPROFILE_SRC_DIR)/*.pf)
-ICCPROFILE_TARGET_FILES := $(subst $(ICCPROFILE_SRC_DIR),$(ICCPROFILE_DEST_DIR),$(ICCPROFILE_SRCS))
-
-$(ICCPROFILE_DEST_DIR)%.pf: $(ICCPROFILE_SRC_DIR)%.pf
-	$(call install-file)
-	$(CHMOD) 444 $@
-
-DESKTOP_CONF_FILES += $(ICCPROFILE_TARGET_FILES)
-
-################################################################################
-
 ifneq ($(FREETYPE_BUNDLE_LIB_PATH), )
   # We need to bundle the freetype library, so it will be available at runtime as well as link time.
   #
--- a/jdk/make/data/currency/CurrencyData.properties	Thu Sep 04 14:45:48 2014 -0700
+++ b/jdk/make/data/currency/CurrencyData.properties	Wed Jul 05 20:00:03 2017 +0200
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2000, 2014, 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
@@ -28,7 +28,7 @@
 # Version of the currency code information in this class.
 # It is a serial number that accompanies with each amendment.
 
-dataVersion=156
+dataVersion=159
 
 # List of all valid ISO 4217 currency codes.
 # To ensure compatibility, do not remove codes.
@@ -332,7 +332,7 @@
 # LIECHTENSTEIN
 LI=CHF
 # LITHUANIA
-LT=LTL
+LT=LTL;2014-12-31-22-00-00;EUR
 # LUXEMBOURG
 LU=EUR
 # MACAU
--- a/jdk/make/gensrc/GensrcLocaleDataMetaInfo.gmk	Thu Sep 04 14:45:48 2014 -0700
+++ b/jdk/make/gensrc/GensrcLocaleDataMetaInfo.gmk	Wed Jul 05 20:00:03 2017 +0200
@@ -58,7 +58,14 @@
 # Locales that don't have any resource files should be included here.
 ALL_NON_EN_LOCALES := ja-JP-JP nb-NO nn-NO th-TH-TH
 
-SED_ARGS := -e 's|$(HASH)warn This file is preprocessed before being compiled|// -- This file was mechanically generated: Do not edit! -- //|g'
+SED_ENARGS := -e 's|$(HASH)warn This file is preprocessed before being compiled|// -- This file was mechanically generated: Do not edit! -- //|g'
+SED_NONENARGS := $(SED_ENARGS)
+
+# Fill in the languages and package names
+SED_ENARGS += -e 's/$(HASH)Lang$(HASH)/En/' \
+    -e 's/$(HASH)Package$(HASH)/sun.util.locale.provider/'
+SED_NONENARGS += -e 's/$(HASH)Lang$(HASH)/NonEn/' \
+    -e 's/$(HASH)Package$(HASH)/sun.util.resources.provider/'
 
 # This macro creates a sed expression that substitues for example:
 # #FormatData_ENLocales# with: en% locales.
@@ -78,8 +85,8 @@
   ALL_NON_EN_LOCALES += $$($1_NON_EN_LOCALES)
 
   # Don't sed in a space if there are no locales.
-  SED_ARGS += -e 's/$$(HASH)$1_ENLocales$$(HASH)/$$(if $$($1_EN_LOCALES),$$(SPACE)$$($1_EN_LOCALES),)/g'
-  SED_ARGS += -e 's/$$(HASH)$1_NonENLocales$$(HASH)/$$(if $$($1_NON_EN_LOCALES),$$(SPACE)$$($1_NON_EN_LOCALES),)/g'
+  SED_ENARGS += -e 's/$$(HASH)$1_Locales$$(HASH)/$$(if $$($1_EN_LOCALES),$$(SPACE)$$($1_EN_LOCALES),)/g'
+  SED_NONENARGS += -e 's/$$(HASH)$1_Locales$$(HASH)/$$(if $$($1_NON_EN_LOCALES),$$(SPACE)$$($1_NON_EN_LOCALES),)/g'
 endef
 
 #sun.text.resources.FormatData
@@ -106,17 +113,25 @@
 #sun.util.resources.CalendarData
 $(eval $(call CaptureLocale,CalendarData))
 
-SED_ARGS += -e 's/$(HASH)AvailableLocales_ENLocales$(HASH)/$(sort $(ALL_EN_LOCALES))/g'
-SED_ARGS += -e 's/$(HASH)AvailableLocales_NonENLocales$(HASH)/$(sort $(ALL_NON_EN_LOCALES))/g'
+SED_ENARGS += -e 's/$(HASH)AvailableLocales_Locales$(HASH)/$(sort $(ALL_EN_LOCALES))/g'
+SED_NONENARGS += -e 's/$(HASH)AvailableLocales_Locales$(HASH)/$(sort $(ALL_NON_EN_LOCALES))/g'
 
-$(JDK_OUTPUTDIR)/gensrc/java.base/sun/util/locale/provider/LocaleDataMetaInfo.java: \
+$(JDK_OUTPUTDIR)/gensrc/java.base/sun/util/locale/provider/EnLocaleDataMetaInfo.java: \
     $(JDK_TOPDIR)/src/java.base/share/classes/sun/util/locale/provider/LocaleDataMetaInfo-XLocales.java.template
 	$(MKDIR) -p $(@D)
-	$(ECHO) Creating sun/util/LocaleDataMetaInfo.java from $(words $(LOCALE_RESOURCES)) found resources.
+	$(ECHO) Creating sun/util/locale/provider/EnLocaleDataMetaInfo.java from $(words $(LOCALE_RESOURCES)) found resources.
 	$(PRINTF) "PREV_LOCALE_RESOURCES:=$(LOCALE_RESOURCES)" > $(JDK_OUTPUTDIR)/gensrc/_the.locale_resources
-	$(SED) $(SED_ARGS) $< > $@
+	$(SED) $(SED_ENARGS) $< > $@
 
-GENSRC_LOCALEDATAMETAINFO := $(JDK_OUTPUTDIR)/gensrc/java.base/sun/util/locale/provider/LocaleDataMetaInfo.java
+$(JDK_OUTPUTDIR)/gensrc/jdk.localedata/sun/util/resources/provider/NonEnLocaleDataMetaInfo.java: \
+    $(JDK_TOPDIR)/src/java.base/share/classes/sun/util/locale/provider/LocaleDataMetaInfo-XLocales.java.template
+	$(MKDIR) -p $(@D)
+	$(ECHO) Creating sun/util/resources/provider/NonEnLocaleDataMetaInfo.java from $(words $(LOCALE_RESOURCES)) found resources.
+	$(PRINTF) "PREV_LOCALE_RESOURCES:=$(LOCALE_RESOURCES)" > $(JDK_OUTPUTDIR)/gensrc/_the.locale_resources
+	$(SED) $(SED_NONENARGS) $< > $@
+
+GENSRC_LOCALEDATAMETAINFO := $(JDK_OUTPUTDIR)/gensrc/java.base/sun/util/locale/provider/EnLocaleDataMetaInfo.java \
+    $(JDK_OUTPUTDIR)/gensrc/jdk.localedata/sun/util/resources/provider/NonEnLocaleDataMetaInfo.java
 
 ################################################################################
 
--- a/jdk/make/profile-includes.txt	Thu Sep 04 14:45:48 2014 -0700
+++ b/jdk/make/profile-includes.txt	Wed Jul 05 20:00:03 2017 +0200
@@ -168,11 +168,6 @@
     $(OPENJDK_TARGET_CPU_LEGACY_LIB)/$(LIBRARY_PREFIX)t2k$(SHARED_LIBRARY_SUFFIX) \
     $(OPENJDK_TARGET_CPU_LEGACY_LIB)/$(LIBRARY_PREFIX)unpack$(SHARED_LIBRARY_SUFFIX) \
     charsets.jar \
-    cmm/CIEXYZ.pf \
-    cmm/GRAY.pf \
-    cmm/LINEAR_RGB.pf \
-    cmm/PYCC.pf \
-    cmm/sRGB.pf \
     ext/cldrdata.jar \
     ext/dnsns.jar \
     ext/nashorn.jar \
--- a/jdk/make/src/classes/build/tools/cldrconverter/CLDRConverter.java	Thu Sep 04 14:45:48 2014 -0700
+++ b/jdk/make/src/classes/build/tools/cldrconverter/CLDRConverter.java	Wed Jul 05 20:00:03 2017 +0200
@@ -431,7 +431,7 @@
             allLocales.addAll(metaInfo.get("LocaleNames"));
             allLocales.addAll(metaInfo.get("CalendarData"));
             allLocales.addAll(metaInfo.get("FormatData"));
-            metaInfo.put("All", allLocales);
+            metaInfo.put("AvailableLocales", allLocales);
         }
 
         bundleGenerator.generateMetaInfo(metaInfo);
--- a/jdk/make/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java	Thu Sep 04 14:45:48 2014 -0700
+++ b/jdk/make/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java	Wed Jul 05 20:00:03 2017 +0200
@@ -159,8 +159,10 @@
             out.println(CopyrightHeaders.getOpenJDKCopyright());
 
             out.println("package sun.util.cldr;\n\n"
-                      + "import java.util.ListResourceBundle;\n");
-            out.printf("public class %s extends ListResourceBundle {\n", METAINFO_CLASS);
+                      + "import java.util.ListResourceBundle;\n"
+                      + "import sun.util.locale.provider.LocaleProviderAdapter;\n"
+                      + "import sun.util.locale.provider.LocaleDataMetaInfo;\n");
+            out.printf("public class %s extends ListResourceBundle implements LocaleDataMetaInfo {\n", METAINFO_CLASS);
             out.println("    @Override\n" +
                         "    protected final Object[][] getContents() {\n" +
                         "        final Object[][] data = new Object[][] {");
@@ -168,7 +170,15 @@
                 out.printf("            { \"%s\",\n", key);
                 out.printf("              \"%s\" },\n", toLocaleList(metaInfo.get(key)));
             }
-            out.println("        };\n        return data;\n    }\n}");
+            out.println("        };\n        return data;\n    }\n\n");
+
+            out.println("    public LocaleProviderAdapter.Type getType() {\n" +
+                        "        return LocaleProviderAdapter.Type.CLDR;\n" +
+                        "    }\n\n");
+
+            out.println("    public String availableLanguageTags(String category) {\n" +
+                        "        return getString(category);\n" +
+                        "    };\n}");
         }
     }
 
--- a/jdk/src/demo/share/java2d/J2DBench/Makefile	Thu Sep 04 14:45:48 2014 -0700
+++ b/jdk/src/demo/share/java2d/J2DBench/Makefile	Wed Jul 05 20:00:03 2017 +0200
@@ -72,6 +72,7 @@
 
 J2DBENCH_RESOURCES = \
 	$(CLASSES)/j2dbench/tests/iio/images \
+	$(CLASSES)/j2dbench/tests/cmm/images \
 	$(CLASSES)/j2dbench/tests/text/textdata
 
 SCM_DIRs = .hg .svn CVS RCS SCCS Codemgr_wsdata deleted_files
@@ -101,6 +102,10 @@
 	cp -r $< $@
 	cd $@ && rm -rf $(SCM_DIRs)
 
+$(CLASSES)/j2dbench/tests/cmm/images: $(RESOURCES)/cmm_images
+	cp -r $< $@
+	cd $@ && rm -rf $(SCM_DIRs)
+
 $(CLASSES)/j2dbench.manifest:
 	echo "Main-Class: j2dbench.J2DBench" > $@
 
@@ -115,7 +120,7 @@
 mkdirs: $(DIST) $(CLASSES)
 
 $(CLASSES)/j2dbench/%.class: $(SOURCEPATH)/j2dbench/%.java
-	javac -source 1.2 -target 1.2 -d $(CLASSES) -sourcepath $(SOURCEPATH) $<
+	javac -g:none -source 1.6 -target 1.6 -d $(CLASSES) -sourcepath $(SOURCEPATH) $<
 
 clean:
 	rm -rf $(CLASSES)
--- a/jdk/src/demo/share/java2d/J2DBench/README	Thu Sep 04 14:45:48 2014 -0700
+++ b/jdk/src/demo/share/java2d/J2DBench/README	Wed Jul 05 20:00:03 2017 +0200
@@ -19,10 +19,9 @@
 Minimum requirements
 -----------------------------------------------------------------------
 
-The benchmark requires at least jdk1.4 to compile and
-at least jdk1.2** to run.
-
-** Note: the goal is to make the benchmark run on 1.1.x as well.
+The benchmark requires at least jdk1.4 to compile and run. Note that
+source/target is set to 1.6 in the makefile and build.xml, because of
+support in jdk 9 compiler.
 
 -----------------------------------------------------------------------
 How To Compile
@@ -125,7 +124,7 @@
 
 After the options file is created, start J2DBench in batch mode to run
 the benchmarks for the default pipeline:
-#> java -jar dest/J2DBench.jar -batch -loadopts options/default.opt \
+#> java -jar dist/J2DBench.jar -batch -loadopts options/default.opt \
      -saveres default.res -title "Rendering - Default ppl" \
      -desc "Rendering tests with the default pipeline"
 
@@ -136,13 +135,13 @@
 "Run Tests" in the J2DBench dialog)
 
 Now run the benchmark with opengl pipeline:
-#> java -Dsun.java2d.opengl=True -jar dest/J2DBench.jar -batch \
+#> java -Dsun.java2d.opengl=True -jar dist/J2DBench.jar -batch \
      -loadopts options/default.opt \
      -saveres opengl.res -title "Rendering - OpenGL" \
      -desc "Rendering tests with OpenGL pipeline"
 
 Now let's analyze the results using J2DAnalyzer:
-#> java -jar dest/J2DAnalyzer.jar default.res opengl.res
+#> java -jar dist/J2DAnalyzer.jar default.res opengl.res
 
 Note that you can compare more than two sets of results, see
 J2DAnalyzer's help page.
--- a/jdk/src/demo/share/java2d/J2DBench/build.xml	Thu Sep 04 14:45:48 2014 -0700
+++ b/jdk/src/demo/share/java2d/J2DBench/build.xml	Wed Jul 05 20:00:03 2017 +0200
@@ -49,7 +49,7 @@
   <target name="compile" depends="init"
         description="compile the source " >
     <!-- Compile the java code from ${src} into ${build} -->
-    <javac debug="flase" source="1.5" target="1.5" srcdir="${src}" destdir="${build}"/>
+    <javac debug="off" source="1.6" target="1.6" srcdir="${src}" destdir="${build}"/>
   </target>
 
   <target name="run" depends="dist"
--- a/jdk/src/demo/share/java2d/J2DBench/src/j2dbench/tests/cmm/CMMTests.java	Thu Sep 04 14:45:48 2014 -0700
+++ b/jdk/src/demo/share/java2d/J2DBench/src/j2dbench/tests/cmm/CMMTests.java	Wed Jul 05 20:00:03 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -39,23 +39,24 @@
 
 package j2dbench.tests.cmm;
 
-import j2dbench.Group;
-import j2dbench.Option;
-import j2dbench.Result;
-import j2dbench.Test;
-import j2dbench.TestEnvironment;
 import java.awt.color.ColorSpace;
 import java.awt.color.ICC_ColorSpace;
 import java.awt.color.ICC_Profile;
 import java.io.IOException;
 import java.io.InputStream;
 
+import j2dbench.Group;
+import j2dbench.Option;
+import j2dbench.Result;
+import j2dbench.Test;
+import j2dbench.TestEnvironment;
+
 public class CMMTests extends Test {
 
     protected static Group cmmRoot;
     protected static Group cmmOptRoot;
     protected static Option csList;
-    protected static Option usePlatfromProfiles;
+    protected static Option usePlatformProfiles;
 
     public static void init() {
         cmmRoot = new Group("cmm", "Color Management Benchmarks");
@@ -64,9 +65,9 @@
         cmmOptRoot = new Group(cmmRoot, "opts", "General Options");
 
         /*
-        usePlatfromProfiles =
-                new Option.Enable(cmmOptRoot, "csPlatfrom",
-                        "Use Platfrom Profiles", false);
+        usePlatformProfiles =
+                new Option.Enable(cmmOptRoot, "csPlatform",
+                        "Use Platform Profiles", false);
         */
         int[] colorspaces = new int[] {
             ColorSpace.CS_sRGB,
@@ -92,10 +93,10 @@
 
     protected static ColorSpace getColorSpace(TestEnvironment env) {
         ColorSpace cs;
-        Boolean usePlatfrom = true; //(Boolean)env.getModifier(usePlatfromProfiles);
+        boolean usePlatform = true; //(Boolean)env.getModifier(usePlatformProfiles);
 
         int cs_code = env.getIntValue(csList);
-        if (usePlatfrom) {
+        if (usePlatform) {
             cs = ColorSpace.getInstance(cs_code);
         } else {
             String resource = "profiles/";
@@ -136,17 +137,14 @@
         addDependencies(cmmOptRoot, true);
     }
 
-    @Override
     public Object initTest(TestEnvironment te, Result result) {
         throw new UnsupportedOperationException("Not supported yet.");
     }
 
-    @Override
     public void runTest(Object o, int i) {
         throw new UnsupportedOperationException("Not supported yet.");
     }
 
-    @Override
     public void cleanupTest(TestEnvironment te, Object o) {
         throw new UnsupportedOperationException("Not supported yet.");
     }
--- a/jdk/src/demo/share/java2d/J2DBench/src/j2dbench/tests/cmm/ColorConvertOpTests.java	Thu Sep 04 14:45:48 2014 -0700
+++ b/jdk/src/demo/share/java2d/J2DBench/src/j2dbench/tests/cmm/ColorConvertOpTests.java	Wed Jul 05 20:00:03 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -39,11 +39,6 @@
 
 package j2dbench.tests.cmm;
 
-import j2dbench.Group;
-import j2dbench.Option;
-import j2dbench.Result;
-import j2dbench.TestEnvironment;
-import j2dbench.tests.iio.IIOTests;
 import java.awt.AlphaComposite;
 import java.awt.Color;
 import java.awt.Graphics2D;
@@ -53,15 +48,22 @@
 import java.awt.image.ColorConvertOp;
 import java.awt.image.Raster;
 import java.awt.image.WritableRaster;
+
 import javax.imageio.ImageIO;
 
+import j2dbench.Group;
+import j2dbench.Option;
+import j2dbench.Result;
+import j2dbench.TestEnvironment;
+import j2dbench.tests.iio.IIOTests;
+
 public class ColorConvertOpTests extends ColorConversionTests {
 
-    private static enum ImageContent {
-        BLANK("bank", "Blank (opaque black)"),
-        RANDOM("random", "Random"),
-        VECTOR("vector", "Vector Art"),
-        PHOTO("photo", "Photograph");
+    private static class ImageContent {
+        static ImageContent BLANK = new ImageContent("bank", "Blank (opaque black)");
+        static ImageContent RANDOM = new ImageContent("random", "Random");
+        static ImageContent VECTOR = new ImageContent("vector", "Vector Art");
+        static ImageContent PHOTO= new ImageContent("photo", "Photograph");
 
         public final String name;
         public final String descr;
@@ -70,15 +72,19 @@
             this.name = name;
             this.descr = descr;
         }
+
+        public static ImageContent[] values() {
+            return new ImageContent[]{BLANK, RANDOM, VECTOR, PHOTO};
+        }
     }
 
-    private static enum ImageType {
-        INT_ARGB(BufferedImage.TYPE_INT_ARGB, "INT_ARGB", "TYPE_INT_ARGB"),
-        INT_RGB(BufferedImage.TYPE_INT_RGB, "INT_RGB", "TYPE_INT_RGB"),
-        INT_BGR(BufferedImage.TYPE_INT_BGR, "INT_BGR", "TYPE_INT_BGR"),
-        BYTE_3BYTE_BGR(BufferedImage.TYPE_3BYTE_BGR, "3BYTE_BGR", "TYPE_3BYTE_BGR"),
-        BYTE_4BYTE_ABGR(BufferedImage.TYPE_4BYTE_ABGR, "4BYTE_BGR", "TYPE_4BYTE_BGR"),
-        COMPATIBLE_DST(0, "Compatible", "Compatible destination");
+    private static class ImageType {
+        static ImageType INT_ARGB = new ImageType(BufferedImage.TYPE_INT_ARGB, "INT_ARGB", "TYPE_INT_ARGB");
+        static ImageType INT_RGB = new ImageType(BufferedImage.TYPE_INT_RGB, "INT_RGB", "TYPE_INT_RGB");
+        static ImageType INT_BGR = new ImageType(BufferedImage.TYPE_INT_BGR, "INT_BGR", "TYPE_INT_BGR");
+        static ImageType BYTE_3BYTE_BGR = new ImageType(BufferedImage.TYPE_3BYTE_BGR, "3BYTE_BGR", "TYPE_3BYTE_BGR");
+        static ImageType BYTE_4BYTE_ABGR = new ImageType(BufferedImage.TYPE_4BYTE_ABGR, "4BYTE_BGR", "TYPE_4BYTE_BGR");
+        static ImageType COMPATIBLE_DST = new ImageType(0, "Compatible", "Compatible destination");
 
         private ImageType(int type, String abbr, String descr) {
             this.type = type;
@@ -89,11 +95,16 @@
         public final int type;
         public final String abbrev;
         public final String descr;
+
+        public static ImageType[] values() {
+            return new ImageType[]{INT_ARGB, INT_RGB, INT_BGR,
+                    BYTE_3BYTE_BGR, BYTE_4BYTE_ABGR, COMPATIBLE_DST};
+        }
     }
 
-    private static enum ListType {
-        SRC("srcType", "Source Images"),
-        DST("dstType", "Destination Images");
+    private static class ListType {
+        static ListType SRC = new ListType("srcType", "Source Images");
+        static ListType DST = new ListType("dstType", "Destination Images");
 
         private ListType(String name, String description) {
             this.name = name;
@@ -320,64 +331,55 @@
         BufferedImage image;
         image = new BufferedImage(width, height, type);
         boolean hasAlpha = image.getColorModel().hasAlpha();
-        switch (contentType) {
-            case RANDOM:
-                for (int y = 0; y < height; y++) {
-                    for (int x = 0; x < width; x++) {
-                        int rgb = (int)(Math.random() * 0xffffff);
-                        if (hasAlpha) {
-                            rgb |= 0x7f000000;
-                        }
-                        image.setRGB(x, y, rgb);
+        if (contentType == ImageContent.RANDOM) {
+            for (int y = 0; y < height; y++) {
+                for (int x = 0; x < width; x++) {
+                    int rgb = (int) (Math.random() * 0xffffff);
+                    if (hasAlpha) {
+                        rgb |= 0x7f000000;
                     }
+                    image.setRGB(x, y, rgb);
                 }
-                break;
-            case VECTOR:
-                {
-                    Graphics2D g = image.createGraphics();
-                    if (hasAlpha) {
-                        // fill background with a translucent color
-                        g.setComposite(AlphaComposite.getInstance(
-                                           AlphaComposite.SRC, 0.5f));
-                    }
-                    g.setColor(Color.blue);
-                    g.fillRect(0, 0, width, height);
-                    g.setComposite(AlphaComposite.Src);
-                    g.setColor(Color.yellow);
-                    g.fillOval(2, 2, width-4, height-4);
-                    g.setColor(Color.red);
-                    g.fillOval(4, 4, width-8, height-8);
-                    g.setColor(Color.green);
-                    g.fillRect(8, 8, width-16, height-16);
-                    g.setColor(Color.white);
-                    g.drawLine(0, 0, width, height);
-                    g.drawLine(0, height, width, 0);
-                    g.dispose();
-                    break;
-                }
-            case PHOTO:
-                {
-                    Image photo = null;
-                    try {
-                        photo = ImageIO.read(
-                            IIOTests.class.getResourceAsStream("images/photo.jpg"));
-                    } catch (Exception e) {
-                        System.err.println("error loading photo");
-                        e.printStackTrace();
-                    }
-                    Graphics2D g = image.createGraphics();
-                    if (hasAlpha) {
-                        g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC,
-                                                                  0.5f));
-                    }
-                    g.drawImage(photo, 0, 0, width, height, null);
-                    g.dispose();
-                    break;
-                }
-            default:
-                break;
+            }
         }
-
+        if (contentType == ImageContent.VECTOR) {
+            Graphics2D g = image.createGraphics();
+            if (hasAlpha) {
+                // fill background with a translucent color
+                g.setComposite(AlphaComposite.getInstance(
+                                   AlphaComposite.SRC, 0.5f));
+            }
+            g.setColor(Color.blue);
+            g.fillRect(0, 0, width, height);
+            g.setComposite(AlphaComposite.Src);
+            g.setColor(Color.yellow);
+            g.fillOval(2, 2, width-4, height-4);
+            g.setColor(Color.red);
+            g.fillOval(4, 4, width-8, height-8);
+            g.setColor(Color.green);
+            g.fillRect(8, 8, width-16, height-16);
+            g.setColor(Color.white);
+            g.drawLine(0, 0, width, height);
+            g.drawLine(0, height, width, 0);
+            g.dispose();
+        }
+        if (contentType == ImageContent.PHOTO) {
+            Image photo = null;
+            try {
+                photo = ImageIO.read(
+                    IIOTests.class.getResourceAsStream("images/photo.jpg"));
+            } catch (Exception e) {
+                System.err.println("error loading photo");
+                e.printStackTrace();
+            }
+            Graphics2D g = image.createGraphics();
+            if (hasAlpha) {
+                g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC,
+                                                          0.5f));
+            }
+            g.drawImage(photo, 0, 0, width, height, null);
+            g.dispose();
+        }
         return image;
     }
 }
--- a/jdk/src/demo/share/java2d/J2DBench/src/j2dbench/tests/cmm/DataConversionTests.java	Thu Sep 04 14:45:48 2014 -0700
+++ b/jdk/src/demo/share/java2d/J2DBench/src/j2dbench/tests/cmm/DataConversionTests.java	Wed Jul 05 20:00:03 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -39,10 +39,11 @@
 
 package j2dbench.tests.cmm;
 
+import java.awt.color.ColorSpace;
+
 import j2dbench.Group;
 import j2dbench.Result;
 import j2dbench.TestEnvironment;
-import java.awt.color.ColorSpace;
 
 public class DataConversionTests extends ColorConversionTests {
 
@@ -92,13 +93,11 @@
         }
     }
 
-    @Override
     public Object initTest(TestEnvironment env, Result result) {
         ColorSpace cs = getColorSpace(env);
         return new Context(env, result, cs);
     }
 
-    @Override
     public void cleanupTest(TestEnvironment te, Object o) {
     }
 
--- a/jdk/src/demo/share/java2d/J2DBench/src/j2dbench/tests/cmm/EmbeddedProfileTests.java	Thu Sep 04 14:45:48 2014 -0700
+++ b/jdk/src/demo/share/java2d/J2DBench/src/j2dbench/tests/cmm/EmbeddedProfileTests.java	Wed Jul 05 20:00:03 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -39,16 +39,18 @@
 
 package j2dbench.tests.cmm;
 
+import java.awt.image.BufferedImage;
+import java.io.IOException;
+import java.net.URL;
+
+import javax.imageio.ImageIO;
+import javax.imageio.ImageReader;
+import javax.imageio.stream.ImageInputStream;
+
 import j2dbench.Group;
 import j2dbench.Option;
 import j2dbench.Result;
 import j2dbench.TestEnvironment;
-import java.awt.image.BufferedImage;
-import java.io.IOException;
-import java.net.URL;
-import javax.imageio.ImageIO;
-import javax.imageio.ImageReader;
-import javax.imageio.stream.ImageInputStream;
 
 /* This benchmark verifies how changes in cmm library affects image decoding */
 public class EmbeddedProfileTests extends ColorConversionTests {
@@ -68,10 +70,10 @@
         new ReadImageTest();
     }
 
-    private static enum IccImageResource {
-        SMALL("images/img_icc_small.jpg", "512x512", "Small: 512x512"),
-        MEDIUM("images/img_icc_medium.jpg", "2048x2048", "Medium: 2048x2048"),
-        LARGE("images/img_icc_large.jpg", "4096x4096", "Large: 4096x4096");
+    private static class IccImageResource {
+        static IccImageResource SMALL = new IccImageResource("images/img_icc_small.jpg", "512x512", "Small: 512x512");
+        static IccImageResource MEDIUM = new IccImageResource("images/img_icc_medium.jpg", "2048x2048", "Medium: 2048x2048");
+        static IccImageResource LARGE = new IccImageResource("images/img_icc_large.jpg", "4096x4096", "Large: 4096x4096");
 
         private IccImageResource(String file, String name, String description) {
             this.url = CMMTests.class.getResource(file);
@@ -82,6 +84,10 @@
         public final URL url;
         public final String abbrev;
         public final String description;
+
+        public static IccImageResource[] values() {
+            return new IccImageResource[]{SMALL, MEDIUM, LARGE};
+        }
     }
 
     private static Option createImageList() {
@@ -145,7 +151,7 @@
 
             try {
                 iis = ImageIO.createImageInputStream(url.openStream());
-                reader = ImageIO.getImageReaders(iis).next();
+                reader = (ImageReader) ImageIO.getImageReaders(iis).next();
             } catch (IOException e) {
                 throw new RuntimeException("Unable to run the becnhmark", e);
             }
--- a/jdk/src/demo/share/java2d/J2DBench/src/j2dbench/tests/cmm/ProfileTests.java	Thu Sep 04 14:45:48 2014 -0700
+++ b/jdk/src/demo/share/java2d/J2DBench/src/j2dbench/tests/cmm/ProfileTests.java	Wed Jul 05 20:00:03 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -38,12 +38,12 @@
  */
 package j2dbench.tests.cmm;
 
+import java.awt.color.ICC_ColorSpace;
+import java.awt.color.ICC_Profile;
+
 import j2dbench.Group;
 import j2dbench.Result;
 import j2dbench.TestEnvironment;
-import java.awt.color.ColorSpace;
-import java.awt.color.ICC_ColorSpace;
-import java.awt.color.ICC_Profile;
 
 public class ProfileTests extends CMMTests {
 
@@ -73,13 +73,11 @@
         }
     }
 
-    @Override
     public Object initTest(TestEnvironment env, Result res) {
         ICC_ColorSpace cs = (ICC_ColorSpace) getColorSpace(env);
         return new Context(cs.getProfile(), env, res);
     }
 
-    @Override
     public void cleanupTest(TestEnvironment env, Object o) {
     }
 
@@ -91,7 +89,6 @@
                     "getData(icSigHead)");
         }
 
-        @Override
         public void runTest(Object ctx, int numReps) {
             final Context ictx = (Context) ctx;
             final ICC_Profile profile = ictx.profile;
@@ -115,7 +112,6 @@
                     "getNumComponents");
         }
 
-        @Override
         public void runTest(Object ctx, int numReps) {
             final Context ictx = (Context) ctx;
             final ICC_Profile profile = ictx.profile;
--- a/jdk/src/java.base/share/classes/java/util/concurrent/CompletableFuture.java	Thu Sep 04 14:45:48 2014 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/CompletableFuture.java	Wed Jul 05 20:00:03 2017 +0200
@@ -50,7 +50,6 @@
 import java.util.concurrent.CancellationException;
 import java.util.concurrent.CompletionException;
 import java.util.concurrent.CompletionStage;
-import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.locks.LockSupport;
 
 /**
@@ -77,9 +76,9 @@
  * <li>All <em>async</em> methods without an explicit Executor
  * argument are performed using the {@link ForkJoinPool#commonPool()}
  * (unless it does not support a parallelism level of at least two, in
- * which case, a new Thread is used). To simplify monitoring,
- * debugging, and tracking, all generated asynchronous tasks are
- * instances of the marker interface {@link
+ * which case, a new Thread is created to run each task).  To simplify
+ * monitoring, debugging, and tracking, all generated asynchronous
+ * tasks are instances of the marker interface {@link
  * AsynchronousCompletionTask}. </li>
  *
  * <li>All CompletionStage methods are implemented independently of
@@ -113,141 +112,1556 @@
     /*
      * Overview:
      *
-     * 1. Non-nullness of field result (set via CAS) indicates done.
-     * An AltResult is used to box null as a result, as well as to
-     * hold exceptions.  Using a single field makes completion fast
-     * and simple to detect and trigger, at the expense of a lot of
-     * encoding and decoding that infiltrates many methods. One minor
-     * simplification relies on the (static) NIL (to box null results)
-     * being the only AltResult with a null exception field, so we
-     * don't usually need explicit comparisons with NIL. The CF
-     * exception propagation mechanics surrounding decoding rely on
-     * unchecked casts of decoded results really being unchecked,
-     * where user type errors are caught at point of use, as is
-     * currently the case in Java. These are highlighted by using
-     * SuppressWarnings-annotated temporaries.
+     * A CompletableFuture may have dependent completion actions,
+     * collected in a linked stack. It atomically completes by CASing
+     * a result field, and then pops off and runs those actions. This
+     * applies across normal vs exceptional outcomes, sync vs async
+     * actions, binary triggers, and various forms of completions.
      *
-     * 2. Waiters are held in a Treiber stack similar to the one used
-     * in FutureTask, Phaser, and SynchronousQueue. See their
-     * internal documentation for algorithmic details.
+     * Non-nullness of field result (set via CAS) indicates done.  An
+     * AltResult is used to box null as a result, as well as to hold
+     * exceptions.  Using a single field makes completion simple to
+     * detect and trigger.  Encoding and decoding is straightforward
+     * but adds to the sprawl of trapping and associating exceptions
+     * with targets.  Minor simplifications rely on (static) NIL (to
+     * box null results) being the only AltResult with a null
+     * exception field, so we don't usually need explicit comparisons.
+     * Even though some of the generics casts are unchecked (see
+     * SuppressWarnings annotations), they are placed to be
+     * appropriate even if checked.
      *
-     * 3. Completions are also kept in a list/stack, and pulled off
-     * and run when completion is triggered. (We could even use the
-     * same stack as for waiters, but would give up the potential
-     * parallelism obtained because woken waiters help release/run
-     * others -- see method postComplete).  Because post-processing
-     * may race with direct calls, class Completion opportunistically
-     * extends AtomicInteger so callers can claim the action via
-     * compareAndSet(0, 1).  The Completion.run methods are all
-     * written a boringly similar uniform way (that sometimes includes
-     * unnecessary-looking checks, kept to maintain uniformity).
-     * There are enough dimensions upon which they differ that
-     * attempts to factor commonalities while maintaining efficiency
-     * require more lines of code than they would save.
+     * Dependent actions are represented by Completion objects linked
+     * as Treiber stacks headed by field "stack". There are Completion
+     * classes for each kind of action, grouped into single-input
+     * (UniCompletion), two-input (BiCompletion), projected
+     * (BiCompletions using either (not both) of two inputs), shared
+     * (CoCompletion, used by the second of two sources), zero-input
+     * source actions, and Signallers that unblock waiters. Class
+     * Completion extends ForkJoinTask to enable async execution
+     * (adding no space overhead because we exploit its "tag" methods
+     * to maintain claims). It is also declared as Runnable to allow
+     * usage with arbitrary executors.
      *
-     * 4. The exported then/and/or methods do support a bit of
-     * factoring (see doThenApply etc). They must cope with the
-     * intrinsic races surrounding addition of a dependent action
-     * versus performing the action directly because the task is
-     * already complete.  For example, a CF may not be complete upon
-     * entry, so a dependent completion is added, but by the time it
-     * is added, the target CF is complete, so must be directly
-     * executed. This is all done while avoiding unnecessary object
-     * construction in safe-bypass cases.
+     * Support for each kind of CompletionStage relies on a separate
+     * class, along with two CompletableFuture methods:
+     *
+     * * A Completion class with name X corresponding to function,
+     *   prefaced with "Uni", "Bi", or "Or". Each class contains
+     *   fields for source(s), actions, and dependent. They are
+     *   boringly similar, differing from others only with respect to
+     *   underlying functional forms. We do this so that users don't
+     *   encounter layers of adaptors in common usages. We also
+     *   include "Relay" classes/methods that don't correspond to user
+     *   methods; they copy results from one stage to another.
+     *
+     * * Boolean CompletableFuture method x(...) (for example
+     *   uniApply) takes all of the arguments needed to check that an
+     *   action is triggerable, and then either runs the action or
+     *   arranges its async execution by executing its Completion
+     *   argument, if present. The method returns true if known to be
+     *   complete.
+     *
+     * * Completion method tryFire(int mode) invokes the associated x
+     *   method with its held arguments, and on success cleans up.
+     *   The mode argument allows tryFire to be called twice (SYNC,
+     *   then ASYNC); the first to screen and trap exceptions while
+     *   arranging to execute, and the second when called from a
+     *   task. (A few classes are not used async so take slightly
+     *   different forms.)  The claim() callback suppresses function
+     *   invocation if already claimed by another thread.
+     *
+     * * CompletableFuture method xStage(...) is called from a public
+     *   stage method of CompletableFuture x. It screens user
+     *   arguments and invokes and/or creates the stage object.  If
+     *   not async and x is already complete, the action is run
+     *   immediately.  Otherwise a Completion c is created, pushed to
+     *   x's stack (unless done), and started or triggered via
+     *   c.tryFire.  This also covers races possible if x completes
+     *   while pushing.  Classes with two inputs (for example BiApply)
+     *   deal with races across both while pushing actions.  The
+     *   second completion is a CoCompletion pointing to the first,
+     *   shared so that at most one performs the action.  The
+     *   multiple-arity methods allOf and anyOf do this pairwise to
+     *   form trees of completions.
+     *
+     * Note that the generic type parameters of methods vary according
+     * to whether "this" is a source, dependent, or completion.
+     *
+     * Method postComplete is called upon completion unless the target
+     * is guaranteed not to be observable (i.e., not yet returned or
+     * linked). Multiple threads can call postComplete, which
+     * atomically pops each dependent action, and tries to trigger it
+     * via method tryFire, in NESTED mode.  Triggering can propagate
+     * recursively, so NESTED mode returns its completed dependent (if
+     * one exists) for further processing by its caller (see method
+     * postFire).
+     *
+     * Blocking methods get() and join() rely on Signaller Completions
+     * that wake up waiting threads.  The mechanics are similar to
+     * Treiber stack wait-nodes used in FutureTask, Phaser, and
+     * SynchronousQueue. See their internal documentation for
+     * algorithmic details.
+     *
+     * Without precautions, CompletableFutures would be prone to
+     * garbage accumulation as chains of Completions build up, each
+     * pointing back to its sources. So we null out fields as soon as
+     * possible (see especially method Completion.detach). The
+     * screening checks needed anyway harmlessly ignore null arguments
+     * that may have been obtained during races with threads nulling
+     * out fields.  We also try to unlink fired Completions from
+     * stacks that might never be popped (see method postFire).
+     * Completion fields need not be declared as final or volatile
+     * because they are only visible to other threads upon safe
+     * publication.
      */
 
-    // preliminaries
+    volatile Object result;       // Either the result or boxed AltResult
+    volatile Completion stack;    // Top of Treiber stack of dependent actions
 
-    static final class AltResult {
-        final Throwable ex; // null only for NIL
-        AltResult(Throwable ex) { this.ex = ex; }
+    final boolean internalComplete(Object r) { // CAS from null to r
+        return UNSAFE.compareAndSwapObject(this, RESULT, null, r);
     }
 
+    final boolean casStack(Completion cmp, Completion val) {
+        return UNSAFE.compareAndSwapObject(this, STACK, cmp, val);
+    }
+
+    /** Returns true if successfully pushed c onto stack. */
+    final boolean tryPushStack(Completion c) {
+        Completion h = stack;
+        lazySetNext(c, h);
+        return UNSAFE.compareAndSwapObject(this, STACK, h, c);
+    }
+
+    /** Unconditionally pushes c onto stack, retrying if necessary. */
+    final void pushStack(Completion c) {
+        do {} while (!tryPushStack(c));
+    }
+
+    /* ------------- Encoding and decoding outcomes -------------- */
+
+    static final class AltResult { // See above
+        final Throwable ex;        // null only for NIL
+        AltResult(Throwable x) { this.ex = x; }
+    }
+
+    /** The encoding of the null value. */
     static final AltResult NIL = new AltResult(null);
 
-    // Fields
+    /** Completes with the null value, unless already completed. */
+    final boolean completeNull() {
+        return UNSAFE.compareAndSwapObject(this, RESULT, null,
+                                           NIL);
+    }
 
-    volatile Object result;    // Either the result or boxed AltResult
-    volatile WaitNode waiters; // Treiber stack of threads blocked on get()
-    volatile CompletionNode completions; // list (Treiber stack) of completions
+    /** Returns the encoding of the given non-exceptional value. */
+    final Object encodeValue(T t) {
+        return (t == null) ? NIL : t;
+    }
 
-    // Basic utilities for triggering and processing completions
+    /** Completes with a non-exceptional result, unless already completed. */
+    final boolean completeValue(T t) {
+        return UNSAFE.compareAndSwapObject(this, RESULT, null,
+                                           (t == null) ? NIL : t);
+    }
 
     /**
-     * Removes and signals all waiting threads and runs all completions.
+     * Returns the encoding of the given (non-null) exception as a
+     * wrapped CompletionException unless it is one already.
+     */
+    static AltResult encodeThrowable(Throwable x) {
+        return new AltResult((x instanceof CompletionException) ? x :
+                             new CompletionException(x));
+    }
+
+    /** Completes with an exceptional result, unless already completed. */
+    final boolean completeThrowable(Throwable x) {
+        return UNSAFE.compareAndSwapObject(this, RESULT, null,
+                                           encodeThrowable(x));
+    }
+
+    /**
+     * Returns the encoding of the given (non-null) exception as a
+     * wrapped CompletionException unless it is one already.  May
+     * return the given Object r (which must have been the result of a
+     * source future) if it is equivalent, i.e. if this is a simple
+     * relay of an existing CompletionException.
+     */
+    static Object encodeThrowable(Throwable x, Object r) {
+        if (!(x instanceof CompletionException))
+            x = new CompletionException(x);
+        else if (r instanceof AltResult && x == ((AltResult)r).ex)
+            return r;
+        return new AltResult(x);
+    }
+
+    /**
+     * Completes with the given (non-null) exceptional result as a
+     * wrapped CompletionException unless it is one already, unless
+     * already completed.  May complete with the given Object r
+     * (which must have been the result of a source future) if it is
+     * equivalent, i.e. if this is a simple propagation of an
+     * existing CompletionException.
+     */
+    final boolean completeThrowable(Throwable x, Object r) {
+        return UNSAFE.compareAndSwapObject(this, RESULT, null,
+                                           encodeThrowable(x, r));
+    }
+
+    /**
+     * Returns the encoding of the given arguments: if the exception
+     * is non-null, encodes as AltResult.  Otherwise uses the given
+     * value, boxed as NIL if null.
+     */
+    Object encodeOutcome(T t, Throwable x) {
+        return (x == null) ? (t == null) ? NIL : t : encodeThrowable(x);
+    }
+
+    /**
+     * Returns the encoding of a copied outcome; if exceptional,
+     * rewraps as a CompletionException, else returns argument.
+     */
+    static Object encodeRelay(Object r) {
+        Throwable x;
+        return (((r instanceof AltResult) &&
+                 (x = ((AltResult)r).ex) != null &&
+                 !(x instanceof CompletionException)) ?
+                new AltResult(new CompletionException(x)) : r);
+    }
+
+    /**
+     * Completes with r or a copy of r, unless already completed.
+     * If exceptional, r is first coerced to a CompletionException.
+     */
+    final boolean completeRelay(Object r) {
+        return UNSAFE.compareAndSwapObject(this, RESULT, null,
+                                           encodeRelay(r));
+    }
+
+    /**
+     * Reports result using Future.get conventions.
+     */
+    private static <T> T reportGet(Object r)
+        throws InterruptedException, ExecutionException {
+        if (r == null) // by convention below, null means interrupted
+            throw new InterruptedException();
+        if (r instanceof AltResult) {
+            Throwable x, cause;
+            if ((x = ((AltResult)r).ex) == null)
+                return null;
+            if (x instanceof CancellationException)
+                throw (CancellationException)x;
+            if ((x instanceof CompletionException) &&
+                (cause = x.getCause()) != null)
+                x = cause;
+            throw new ExecutionException(x);
+        }
+        @SuppressWarnings("unchecked") T t = (T) r;
+        return t;
+    }
+
+    /**
+     * Decodes outcome to return result or throw unchecked exception.
+     */
+    private static <T> T reportJoin(Object r) {
+        if (r instanceof AltResult) {
+            Throwable x;
+            if ((x = ((AltResult)r).ex) == null)
+                return null;
+            if (x instanceof CancellationException)
+                throw (CancellationException)x;
+            if (x instanceof CompletionException)
+                throw (CompletionException)x;
+            throw new CompletionException(x);
+        }
+        @SuppressWarnings("unchecked") T t = (T) r;
+        return t;
+    }
+
+    /* ------------- Async task preliminaries -------------- */
+
+    /**
+     * A marker interface identifying asynchronous tasks produced by
+     * {@code async} methods. This may be useful for monitoring,
+     * debugging, and tracking asynchronous activities.
+     *
+     * @since 1.8
+     */
+    public static interface AsynchronousCompletionTask {
+    }
+
+    private static final boolean useCommonPool =
+        (ForkJoinPool.getCommonPoolParallelism() > 1);
+
+    /**
+     * Default executor -- ForkJoinPool.commonPool() unless it cannot
+     * support parallelism.
+     */
+    private static final Executor asyncPool = useCommonPool ?
+        ForkJoinPool.commonPool() : new ThreadPerTaskExecutor();
+
+    /** Fallback if ForkJoinPool.commonPool() cannot support parallelism */
+    static final class ThreadPerTaskExecutor implements Executor {
+        public void execute(Runnable r) { new Thread(r).start(); }
+    }
+
+    /**
+     * Null-checks user executor argument, and translates uses of
+     * commonPool to asyncPool in case parallelism disabled.
+     */
+    static Executor screenExecutor(Executor e) {
+        if (!useCommonPool && e == ForkJoinPool.commonPool())
+            return asyncPool;
+        if (e == null) throw new NullPointerException();
+        return e;
+    }
+
+    // Modes for Completion.tryFire. Signedness matters.
+    static final int SYNC   =  0;
+    static final int ASYNC  =  1;
+    static final int NESTED = -1;
+
+    /* ------------- Base Completion classes and operations -------------- */
+
+    @SuppressWarnings("serial")
+    abstract static class Completion extends ForkJoinTask<Void>
+        implements Runnable, AsynchronousCompletionTask {
+        volatile Completion next;      // Treiber stack link
+
+        /**
+         * Performs completion action if triggered, returning a
+         * dependent that may need propagation, if one exists.
+         *
+         * @param mode SYNC, ASYNC, or NESTED
+         */
+        abstract CompletableFuture<?> tryFire(int mode);
+
+        /** Returns true if possibly still triggerable. Used by cleanStack. */
+        abstract boolean isLive();
+
+        public final void run()                { tryFire(ASYNC); }
+        public final boolean exec()            { tryFire(ASYNC); return true; }
+        public final Void getRawResult()       { return null; }
+        public final void setRawResult(Void v) {}
+    }
+
+    static void lazySetNext(Completion c, Completion next) {
+        UNSAFE.putOrderedObject(c, NEXT, next);
+    }
+
+    /**
+     * Pops and tries to trigger all reachable dependents.  Call only
+     * when known to be done.
      */
     final void postComplete() {
-        WaitNode q; Thread t;
-        while ((q = waiters) != null) {
-            if (UNSAFE.compareAndSwapObject(this, WAITERS, q, q.next) &&
-                (t = q.thread) != null) {
-                q.thread = null;
-                LockSupport.unpark(t);
+        /*
+         * On each step, variable f holds current dependents to pop
+         * and run.  It is extended along only one path at a time,
+         * pushing others to avoid unbounded recursion.
+         */
+        CompletableFuture<?> f = this; Completion h;
+        while ((h = f.stack) != null ||
+               (f != this && (h = (f = this).stack) != null)) {
+            CompletableFuture<?> d; Completion t;
+            if (f.casStack(h, t = h.next)) {
+                if (t != null) {
+                    if (f != this) {
+                        pushStack(h);
+                        continue;
+                    }
+                    h.next = null;    // detach
+                }
+                f = (d = h.tryFire(NESTED)) == null ? this : d;
             }
         }
+    }
 
-        CompletionNode h; Completion c;
-        while ((h = completions) != null) {
-            if (UNSAFE.compareAndSwapObject(this, COMPLETIONS, h, h.next) &&
-                (c = h.completion) != null)
-                c.run();
+    /** Traverses stack and unlinks dead Completions. */
+    final void cleanStack() {
+        for (Completion p = null, q = stack; q != null;) {
+            Completion s = q.next;
+            if (q.isLive()) {
+                p = q;
+                q = s;
+            }
+            else if (p == null) {
+                casStack(q, s);
+                q = stack;
+            }
+            else {
+                p.next = s;
+                if (p.isLive())
+                    q = s;
+                else {
+                    p = null;  // restart
+                    q = stack;
+                }
+            }
+        }
+    }
+
+    /* ------------- One-input Completions -------------- */
+
+    /** A Completion with a source, dependent, and executor. */
+    @SuppressWarnings("serial")
+    abstract static class UniCompletion<T,V> extends Completion {
+        Executor executor;                 // executor to use (null if none)
+        CompletableFuture<V> dep;          // the dependent to complete
+        CompletableFuture<T> src;          // source for action
+
+        UniCompletion(Executor executor, CompletableFuture<V> dep,
+                      CompletableFuture<T> src) {
+            this.executor = executor; this.dep = dep; this.src = src;
+        }
+
+        /**
+         * Returns true if action can be run. Call only when known to
+         * be triggerable. Uses FJ tag bit to ensure that only one
+         * thread claims ownership.  If async, starts as task -- a
+         * later call to tryFire will run action.
+         */
+        final boolean claim() {
+            Executor e = executor;
+            if (compareAndSetForkJoinTaskTag((short)0, (short)1)) {
+                if (e == null)
+                    return true;
+                executor = null; // disable
+                e.execute(this);
+            }
+            return false;
+        }
+
+        final boolean isLive() { return dep != null; }
+    }
+
+    /** Pushes the given completion (if it exists) unless done. */
+    final void push(UniCompletion<?,?> c) {
+        if (c != null) {
+            while (result == null && !tryPushStack(c))
+                lazySetNext(c, null); // clear on failure
         }
     }
 
     /**
-     * Triggers completion with the encoding of the given arguments:
-     * if the exception is non-null, encodes it as a wrapped
-     * CompletionException unless it is one already.  Otherwise uses
-     * the given result, boxed as NIL if null.
+     * Post-processing by dependent after successful UniCompletion
+     * tryFire.  Tries to clean stack of source a, and then either runs
+     * postComplete or returns this to caller, depending on mode.
      */
-    final void internalComplete(T v, Throwable ex) {
-        if (result == null)
-            UNSAFE.compareAndSwapObject
-                (this, RESULT, null,
-                 (ex == null) ? (v == null) ? NIL : v :
-                 new AltResult((ex instanceof CompletionException) ? ex :
-                               new CompletionException(ex)));
-        postComplete(); // help out even if not triggered
+    final CompletableFuture<T> postFire(CompletableFuture<?> a, int mode) {
+        if (a != null && a.stack != null) {
+            if (mode < 0 || a.result == null)
+                a.cleanStack();
+            else
+                a.postComplete();
+        }
+        if (result != null && stack != null) {
+            if (mode < 0)
+                return this;
+            else
+                postComplete();
+        }
+        return null;
     }
 
-    /**
-     * If triggered, helps release and/or process completions.
-     */
-    final void helpPostComplete() {
-        if (result != null)
-            postComplete();
+    @SuppressWarnings("serial")
+    static final class UniApply<T,V> extends UniCompletion<T,V> {
+        Function<? super T,? extends V> fn;
+        UniApply(Executor executor, CompletableFuture<V> dep,
+                 CompletableFuture<T> src,
+                 Function<? super T,? extends V> fn) {
+            super(executor, dep, src); this.fn = fn;
+        }
+        final CompletableFuture<V> tryFire(int mode) {
+            CompletableFuture<V> d; CompletableFuture<T> a;
+            if ((d = dep) == null ||
+                !d.uniApply(a = src, fn, mode > 0 ? null : this))
+                return null;
+            dep = null; src = null; fn = null;
+            return d.postFire(a, mode);
+        }
     }
 
-    /* ------------- waiting for completions -------------- */
+    final <S> boolean uniApply(CompletableFuture<S> a,
+                               Function<? super S,? extends T> f,
+                               UniApply<S,T> c) {
+        Object r; Throwable x;
+        if (a == null || (r = a.result) == null || f == null)
+            return false;
+        tryComplete: if (result == null) {
+            if (r instanceof AltResult) {
+                if ((x = ((AltResult)r).ex) != null) {
+                    completeThrowable(x, r);
+                    break tryComplete;
+                }
+                r = null;
+            }
+            try {
+                if (c != null && !c.claim())
+                    return false;
+                @SuppressWarnings("unchecked") S s = (S) r;
+                completeValue(f.apply(s));
+            } catch (Throwable ex) {
+                completeThrowable(ex);
+            }
+        }
+        return true;
+    }
 
-    /** Number of processors, for spin control */
-    static final int NCPU = Runtime.getRuntime().availableProcessors();
+    private <V> CompletableFuture<V> uniApplyStage(
+        Executor e, Function<? super T,? extends V> f) {
+        if (f == null) throw new NullPointerException();
+        CompletableFuture<V> d =  new CompletableFuture<V>();
+        if (e != null || !d.uniApply(this, f, null)) {
+            UniApply<T,V> c = new UniApply<T,V>(e, d, this, f);
+            push(c);
+            c.tryFire(SYNC);
+        }
+        return d;
+    }
+
+    @SuppressWarnings("serial")
+    static final class UniAccept<T> extends UniCompletion<T,Void> {
+        Consumer<? super T> fn;
+        UniAccept(Executor executor, CompletableFuture<Void> dep,
+                  CompletableFuture<T> src, Consumer<? super T> fn) {
+            super(executor, dep, src); this.fn = fn;
+        }
+        final CompletableFuture<Void> tryFire(int mode) {
+            CompletableFuture<Void> d; CompletableFuture<T> a;
+            if ((d = dep) == null ||
+                !d.uniAccept(a = src, fn, mode > 0 ? null : this))
+                return null;
+            dep = null; src = null; fn = null;
+            return d.postFire(a, mode);
+        }
+    }
+
+    final <S> boolean uniAccept(CompletableFuture<S> a,
+                                Consumer<? super S> f, UniAccept<S> c) {
+        Object r; Throwable x;
+        if (a == null || (r = a.result) == null || f == null)
+            return false;
+        tryComplete: if (result == null) {
+            if (r instanceof AltResult) {
+                if ((x = ((AltResult)r).ex) != null) {
+                    completeThrowable(x, r);
+                    break tryComplete;
+                }
+                r = null;
+            }
+            try {
+                if (c != null && !c.claim())
+                    return false;
+                @SuppressWarnings("unchecked") S s = (S) r;
+                f.accept(s);
+                completeNull();
+            } catch (Throwable ex) {
+                completeThrowable(ex);
+            }
+        }
+        return true;
+    }
+
+    private CompletableFuture<Void> uniAcceptStage(Executor e,
+                                                   Consumer<? super T> f) {
+        if (f == null) throw new NullPointerException();
+        CompletableFuture<Void> d = new CompletableFuture<Void>();
+        if (e != null || !d.uniAccept(this, f, null)) {
+            UniAccept<T> c = new UniAccept<T>(e, d, this, f);
+            push(c);
+            c.tryFire(SYNC);
+        }
+        return d;
+    }
+
+    @SuppressWarnings("serial")
+    static final class UniRun<T> extends UniCompletion<T,Void> {
+        Runnable fn;
+        UniRun(Executor executor, CompletableFuture<Void> dep,
+               CompletableFuture<T> src, Runnable fn) {
+            super(executor, dep, src); this.fn = fn;
+        }
+        final CompletableFuture<Void> tryFire(int mode) {
+            CompletableFuture<Void> d; CompletableFuture<T> a;
+            if ((d = dep) == null ||
+                !d.uniRun(a = src, fn, mode > 0 ? null : this))
+                return null;
+            dep = null; src = null; fn = null;
+            return d.postFire(a, mode);
+        }
+    }
+
+    final boolean uniRun(CompletableFuture<?> a, Runnable f, UniRun<?> c) {
+        Object r; Throwable x;
+        if (a == null || (r = a.result) == null || f == null)
+            return false;
+        if (result == null) {
+            if (r instanceof AltResult && (x = ((AltResult)r).ex) != null)
+                completeThrowable(x, r);
+            else
+                try {
+                    if (c != null && !c.claim())
+                        return false;
+                    f.run();
+                    completeNull();
+                } catch (Throwable ex) {
+                    completeThrowable(ex);
+                }
+        }
+        return true;
+    }
+
+    private CompletableFuture<Void> uniRunStage(Executor e, Runnable f) {
+        if (f == null) throw new NullPointerException();
+        CompletableFuture<Void> d = new CompletableFuture<Void>();
+        if (e != null || !d.uniRun(this, f, null)) {
+            UniRun<T> c = new UniRun<T>(e, d, this, f);
+            push(c);
+            c.tryFire(SYNC);
+        }
+        return d;
+    }
+
+    @SuppressWarnings("serial")
+    static final class UniWhenComplete<T> extends UniCompletion<T,T> {
+        BiConsumer<? super T, ? super Throwable> fn;
+        UniWhenComplete(Executor executor, CompletableFuture<T> dep,
+                        CompletableFuture<T> src,
+                        BiConsumer<? super T, ? super Throwable> fn) {
+            super(executor, dep, src); this.fn = fn;
+        }
+        final CompletableFuture<T> tryFire(int mode) {
+            CompletableFuture<T> d; CompletableFuture<T> a;
+            if ((d = dep) == null ||
+                !d.uniWhenComplete(a = src, fn, mode > 0 ? null : this))
+                return null;
+            dep = null; src = null; fn = null;
+            return d.postFire(a, mode);
+        }
+    }
+
+    final boolean uniWhenComplete(CompletableFuture<T> a,
+                                  BiConsumer<? super T,? super Throwable> f,
+                                  UniWhenComplete<T> c) {
+        Object r; T t; Throwable x = null;
+        if (a == null || (r = a.result) == null || f == null)
+            return false;
+        if (result == null) {
+            try {
+                if (c != null && !c.claim())
+                    return false;
+                if (r instanceof AltResult) {
+                    x = ((AltResult)r).ex;
+                    t = null;
+                } else {
+                    @SuppressWarnings("unchecked") T tr = (T) r;
+                    t = tr;
+                }
+                f.accept(t, x);
+                if (x == null) {
+                    internalComplete(r);
+                    return true;
+                }
+            } catch (Throwable ex) {
+                if (x == null)
+                    x = ex;
+            }
+            completeThrowable(x, r);
+        }
+        return true;
+    }
+
+    private CompletableFuture<T> uniWhenCompleteStage(
+        Executor e, BiConsumer<? super T, ? super Throwable> f) {
+        if (f == null) throw new NullPointerException();
+        CompletableFuture<T> d = new CompletableFuture<T>();
+        if (e != null || !d.uniWhenComplete(this, f, null)) {
+            UniWhenComplete<T> c = new UniWhenComplete<T>(e, d, this, f);
+            push(c);
+            c.tryFire(SYNC);
+        }
+        return d;
+    }
+
+    @SuppressWarnings("serial")
+    static final class UniHandle<T,V> extends UniCompletion<T,V> {
+        BiFunction<? super T, Throwable, ? extends V> fn;
+        UniHandle(Executor executor, CompletableFuture<V> dep,
+                  CompletableFuture<T> src,
+                  BiFunction<? super T, Throwable, ? extends V> fn) {
+            super(executor, dep, src); this.fn = fn;
+        }
+        final CompletableFuture<V> tryFire(int mode) {
+            CompletableFuture<V> d; CompletableFuture<T> a;
+            if ((d = dep) == null ||
+                !d.uniHandle(a = src, fn, mode > 0 ? null : this))
+                return null;
+            dep = null; src = null; fn = null;
+            return d.postFire(a, mode);
+        }
+    }
+
+    final <S> boolean uniHandle(CompletableFuture<S> a,
+                                BiFunction<? super S, Throwable, ? extends T> f,
+                                UniHandle<S,T> c) {
+        Object r; S s; Throwable x;
+        if (a == null || (r = a.result) == null || f == null)
+            return false;
+        if (result == null) {
+            try {
+                if (c != null && !c.claim())
+                    return false;
+                if (r instanceof AltResult) {
+                    x = ((AltResult)r).ex;
+                    s = null;
+                } else {
+                    x = null;
+                    @SuppressWarnings("unchecked") S ss = (S) r;
+                    s = ss;
+                }
+                completeValue(f.apply(s, x));
+            } catch (Throwable ex) {
+                completeThrowable(ex);
+            }
+        }
+        return true;
+    }
+
+    private <V> CompletableFuture<V> uniHandleStage(
+        Executor e, BiFunction<? super T, Throwable, ? extends V> f) {
+        if (f == null) throw new NullPointerException();
+        CompletableFuture<V> d = new CompletableFuture<V>();
+        if (e != null || !d.uniHandle(this, f, null)) {
+            UniHandle<T,V> c = new UniHandle<T,V>(e, d, this, f);
+            push(c);
+            c.tryFire(SYNC);
+        }
+        return d;
+    }
+
+    @SuppressWarnings("serial")
+    static final class UniExceptionally<T> extends UniCompletion<T,T> {
+        Function<? super Throwable, ? extends T> fn;
+        UniExceptionally(CompletableFuture<T> dep, CompletableFuture<T> src,
+                         Function<? super Throwable, ? extends T> fn) {
+            super(null, dep, src); this.fn = fn;
+        }
+        final CompletableFuture<T> tryFire(int mode) { // never ASYNC
+            // assert mode != ASYNC;
+            CompletableFuture<T> d; CompletableFuture<T> a;
+            if ((d = dep) == null || !d.uniExceptionally(a = src, fn, this))
+                return null;
+            dep = null; src = null; fn = null;
+            return d.postFire(a, mode);
+        }
+    }
+
+    final boolean uniExceptionally(CompletableFuture<T> a,
+                                   Function<? super Throwable, ? extends T> f,
+                                   UniExceptionally<T> c) {
+        Object r; Throwable x;
+        if (a == null || (r = a.result) == null || f == null)
+            return false;
+        if (result == null) {
+            try {
+                if (r instanceof AltResult && (x = ((AltResult)r).ex) != null) {
+                    if (c != null && !c.claim())
+                        return false;
+                    completeValue(f.apply(x));
+                } else
+                    internalComplete(r);
+            } catch (Throwable ex) {
+                completeThrowable(ex);
+            }
+        }
+        return true;
+    }
+
+    private CompletableFuture<T> uniExceptionallyStage(
+        Function<Throwable, ? extends T> f) {
+        if (f == null) throw new NullPointerException();
+        CompletableFuture<T> d = new CompletableFuture<T>();
+        if (!d.uniExceptionally(this, f, null)) {
+            UniExceptionally<T> c = new UniExceptionally<T>(d, this, f);
+            push(c);
+            c.tryFire(SYNC);
+        }
+        return d;
+    }
+
+    @SuppressWarnings("serial")
+    static final class UniRelay<T> extends UniCompletion<T,T> { // for Compose
+        UniRelay(CompletableFuture<T> dep, CompletableFuture<T> src) {
+            super(null, dep, src);
+        }
+        final CompletableFuture<T> tryFire(int mode) {
+            CompletableFuture<T> d; CompletableFuture<T> a;
+            if ((d = dep) == null || !d.uniRelay(a = src))
+                return null;
+            src = null; dep = null;
+            return d.postFire(a, mode);
+        }
+    }
+
+    final boolean uniRelay(CompletableFuture<T> a) {
+        Object r;
+        if (a == null || (r = a.result) == null)
+            return false;
+        if (result == null) // no need to claim
+            completeRelay(r);
+        return true;
+    }
+
+    @SuppressWarnings("serial")
+    static final class UniCompose<T,V> extends UniCompletion<T,V> {
+        Function<? super T, ? extends CompletionStage<V>> fn;
+        UniCompose(Executor executor, CompletableFuture<V> dep,
+                   CompletableFuture<T> src,
+                   Function<? super T, ? extends CompletionStage<V>> fn) {
+            super(executor, dep, src); this.fn = fn;
+        }
+        final CompletableFuture<V> tryFire(int mode) {
+            CompletableFuture<V> d; CompletableFuture<T> a;
+            if ((d = dep) == null ||
+                !d.uniCompose(a = src, fn, mode > 0 ? null : this))
+                return null;
+            dep = null; src = null; fn = null;
+            return d.postFire(a, mode);
+        }
+    }
+
+    final <S> boolean uniCompose(
+        CompletableFuture<S> a,
+        Function<? super S, ? extends CompletionStage<T>> f,
+        UniCompose<S,T> c) {
+        Object r; Throwable x;
+        if (a == null || (r = a.result) == null || f == null)
+            return false;
+        tryComplete: if (result == null) {
+            if (r instanceof AltResult) {
+                if ((x = ((AltResult)r).ex) != null) {
+                    completeThrowable(x, r);
+                    break tryComplete;
+                }
+                r = null;
+            }
+            try {
+                if (c != null && !c.claim())
+                    return false;
+                @SuppressWarnings("unchecked") S s = (S) r;
+                CompletableFuture<T> g = f.apply(s).toCompletableFuture();
+                if (g.result == null || !uniRelay(g)) {
+                    UniRelay<T> copy = new UniRelay<T>(this, g);
+                    g.push(copy);
+                    copy.tryFire(SYNC);
+                    if (result == null)
+                        return false;
+                }
+            } catch (Throwable ex) {
+                completeThrowable(ex);
+            }
+        }
+        return true;
+    }
+
+    private <V> CompletableFuture<V> uniComposeStage(
+        Executor e, Function<? super T, ? extends CompletionStage<V>> f) {
+        if (f == null) throw new NullPointerException();
+        Object r; Throwable x;
+        if (e == null && (r = result) != null) {
+            // try to return function result directly
+            if (r instanceof AltResult) {
+                if ((x = ((AltResult)r).ex) != null) {
+                    return new CompletableFuture<V>(encodeThrowable(x, r));
+                }
+                r = null;
+            }
+            try {
+                @SuppressWarnings("unchecked") T t = (T) r;
+                return f.apply(t).toCompletableFuture();
+            } catch (Throwable ex) {
+                return new CompletableFuture<V>(encodeThrowable(ex));
+            }
+        }
+        CompletableFuture<V> d = new CompletableFuture<V>();
+        UniCompose<T,V> c = new UniCompose<T,V>(e, d, this, f);
+        push(c);
+        c.tryFire(SYNC);
+        return d;
+    }
+
+    /* ------------- Two-input Completions -------------- */
+
+    /** A Completion for an action with two sources */
+    @SuppressWarnings("serial")
+    abstract static class BiCompletion<T,U,V> extends UniCompletion<T,V> {
+        CompletableFuture<U> snd; // second source for action
+        BiCompletion(Executor executor, CompletableFuture<V> dep,
+                     CompletableFuture<T> src, CompletableFuture<U> snd) {
+            super(executor, dep, src); this.snd = snd;
+        }
+    }
+
+    /** A Completion delegating to a BiCompletion */
+    @SuppressWarnings("serial")
+    static final class CoCompletion extends Completion {
+        BiCompletion<?,?,?> base;
+        CoCompletion(BiCompletion<?,?,?> base) { this.base = base; }
+        final CompletableFuture<?> tryFire(int mode) {
+            BiCompletion<?,?,?> c; CompletableFuture<?> d;
+            if ((c = base) == null || (d = c.tryFire(mode)) == null)
+                return null;
+            base = null; // detach
+            return d;
+        }
+        final boolean isLive() {
+            BiCompletion<?,?,?> c;
+            return (c = base) != null && c.dep != null;
+        }
+    }
+
+    /** Pushes completion to this and b unless both done. */
+    final void bipush(CompletableFuture<?> b, BiCompletion<?,?,?> c) {
+        if (c != null) {
+            Object r;
+            while ((r = result) == null && !tryPushStack(c))
+                lazySetNext(c, null); // clear on failure
+            if (b != null && b != this && b.result == null) {
+                Completion q = (r != null) ? c : new CoCompletion(c);
+                while (b.result == null && !b.tryPushStack(q))
+                    lazySetNext(q, null); // clear on failure
+            }
+        }
+    }
+
+    /** Post-processing after successful BiCompletion tryFire. */
+    final CompletableFuture<T> postFire(CompletableFuture<?> a,
+                                        CompletableFuture<?> b, int mode) {
+        if (b != null && b.stack != null) { // clean second source
+            if (mode < 0 || b.result == null)
+                b.cleanStack();
+            else
+                b.postComplete();
+        }
+        return postFire(a, mode);
+    }
+
+    @SuppressWarnings("serial")
+    static final class BiApply<T,U,V> extends BiCompletion<T,U,V> {
+        BiFunction<? super T,? super U,? extends V> fn;
+        BiApply(Executor executor, CompletableFuture<V> dep,
+                CompletableFuture<T> src, CompletableFuture<U> snd,
+                BiFunction<? super T,? super U,? extends V> fn) {
+            super(executor, dep, src, snd); this.fn = fn;
+        }
+        final CompletableFuture<V> tryFire(int mode) {
+            CompletableFuture<V> d;
+            CompletableFuture<T> a;
+            CompletableFuture<U> b;
+            if ((d = dep) == null ||
+                !d.biApply(a = src, b = snd, fn, mode > 0 ? null : this))
+                return null;
+            dep = null; src = null; snd = null; fn = null;
+            return d.postFire(a, b, mode);
+        }
+    }
+
+    final <R,S> boolean biApply(CompletableFuture<R> a,
+                                CompletableFuture<S> b,
+                                BiFunction<? super R,? super S,? extends T> f,
+                                BiApply<R,S,T> c) {
+        Object r, s; Throwable x;
+        if (a == null || (r = a.result) == null ||
+            b == null || (s = b.result) == null || f == null)
+            return false;
+        tryComplete: if (result == null) {
+            if (r instanceof AltResult) {
+                if ((x = ((AltResult)r).ex) != null) {
+                    completeThrowable(x, r);
+                    break tryComplete;
+                }
+                r = null;
+            }
+            if (s instanceof AltResult) {
+                if ((x = ((AltResult)s).ex) != null) {
+                    completeThrowable(x, s);
+                    break tryComplete;
+                }
+                s = null;
+            }
+            try {
+                if (c != null && !c.claim())
+                    return false;
+                @SuppressWarnings("unchecked") R rr = (R) r;
+                @SuppressWarnings("unchecked") S ss = (S) s;
+                completeValue(f.apply(rr, ss));
+            } catch (Throwable ex) {
+                completeThrowable(ex);
+            }
+        }
+        return true;
+    }
+
+    private <U,V> CompletableFuture<V> biApplyStage(
+        Executor e, CompletionStage<U> o,
+        BiFunction<? super T,? super U,? extends V> f) {
+        CompletableFuture<U> b;
+        if (f == null || (b = o.toCompletableFuture()) == null)
+            throw new NullPointerException();
+        CompletableFuture<V> d = new CompletableFuture<V>();
+        if (e != null || !d.biApply(this, b, f, null)) {
+            BiApply<T,U,V> c = new BiApply<T,U,V>(e, d, this, b, f);
+            bipush(b, c);
+            c.tryFire(SYNC);
+        }
+        return d;
+    }
+
+    @SuppressWarnings("serial")
+    static final class BiAccept<T,U> extends BiCompletion<T,U,Void> {
+        BiConsumer<? super T,? super U> fn;
+        BiAccept(Executor executor, CompletableFuture<Void> dep,
+                 CompletableFuture<T> src, CompletableFuture<U> snd,
+                 BiConsumer<? super T,? super U> fn) {
+            super(executor, dep, src, snd); this.fn = fn;
+        }
+        final CompletableFuture<Void> tryFire(int mode) {
+            CompletableFuture<Void> d;
+            CompletableFuture<T> a;
+            CompletableFuture<U> b;
+            if ((d = dep) == null ||
+                !d.biAccept(a = src, b = snd, fn, mode > 0 ? null : this))
+                return null;
+            dep = null; src = null; snd = null; fn = null;
+            return d.postFire(a, b, mode);
+        }
+    }
+
+    final <R,S> boolean biAccept(CompletableFuture<R> a,
+                                 CompletableFuture<S> b,
+                                 BiConsumer<? super R,? super S> f,
+                                 BiAccept<R,S> c) {
+        Object r, s; Throwable x;
+        if (a == null || (r = a.result) == null ||
+            b == null || (s = b.result) == null || f == null)
+            return false;
+        tryComplete: if (result == null) {
+            if (r instanceof AltResult) {
+                if ((x = ((AltResult)r).ex) != null) {
+                    completeThrowable(x, r);
+                    break tryComplete;
+                }
+                r = null;
+            }
+            if (s instanceof AltResult) {
+                if ((x = ((AltResult)s).ex) != null) {
+                    completeThrowable(x, s);
+                    break tryComplete;
+                }
+                s = null;
+            }
+            try {
+                if (c != null && !c.claim())
+                    return false;
+                @SuppressWarnings("unchecked") R rr = (R) r;
+                @SuppressWarnings("unchecked") S ss = (S) s;
+                f.accept(rr, ss);
+                completeNull();
+            } catch (Throwable ex) {
+                completeThrowable(ex);
+            }
+        }
+        return true;
+    }
+
+    private <U> CompletableFuture<Void> biAcceptStage(
+        Executor e, CompletionStage<U> o,
+        BiConsumer<? super T,? super U> f) {
+        CompletableFuture<U> b;
+        if (f == null || (b = o.toCompletableFuture()) == null)
+            throw new NullPointerException();
+        CompletableFuture<Void> d = new CompletableFuture<Void>();
+        if (e != null || !d.biAccept(this, b, f, null)) {
+            BiAccept<T,U> c = new BiAccept<T,U>(e, d, this, b, f);
+            bipush(b, c);
+            c.tryFire(SYNC);
+        }
+        return d;
+    }
+
+    @SuppressWarnings("serial")
+    static final class BiRun<T,U> extends BiCompletion<T,U,Void> {
+        Runnable fn;
+        BiRun(Executor executor, CompletableFuture<Void> dep,
+              CompletableFuture<T> src,
+              CompletableFuture<U> snd,
+              Runnable fn) {
+            super(executor, dep, src, snd); this.fn = fn;
+        }
+        final CompletableFuture<Void> tryFire(int mode) {
+            CompletableFuture<Void> d;
+            CompletableFuture<T> a;
+            CompletableFuture<U> b;
+            if ((d = dep) == null ||
+                !d.biRun(a = src, b = snd, fn, mode > 0 ? null : this))
+                return null;
+            dep = null; src = null; snd = null; fn = null;
+            return d.postFire(a, b, mode);
+        }
+    }
+
+    final boolean biRun(CompletableFuture<?> a, CompletableFuture<?> b,
+                        Runnable f, BiRun<?,?> c) {
+        Object r, s; Throwable x;
+        if (a == null || (r = a.result) == null ||
+            b == null || (s = b.result) == null || f == null)
+            return false;
+        if (result == null) {
+            if (r instanceof AltResult && (x = ((AltResult)r).ex) != null)
+                completeThrowable(x, r);
+            else if (s instanceof AltResult && (x = ((AltResult)s).ex) != null)
+                completeThrowable(x, s);
+            else
+                try {
+                    if (c != null && !c.claim())
+                        return false;
+                    f.run();
+                    completeNull();
+                } catch (Throwable ex) {
+                    completeThrowable(ex);
+                }
+        }
+        return true;
+    }
+
+    private CompletableFuture<Void> biRunStage(Executor e, CompletionStage<?> o,
+                                               Runnable f) {
+        CompletableFuture<?> b;
+        if (f == null || (b = o.toCompletableFuture()) == null)
+            throw new NullPointerException();
+        CompletableFuture<Void> d = new CompletableFuture<Void>();
+        if (e != null || !d.biRun(this, b, f, null)) {
+            BiRun<T,?> c = new BiRun<>(e, d, this, b, f);
+            bipush(b, c);
+            c.tryFire(SYNC);
+        }
+        return d;
+    }
+
+    @SuppressWarnings("serial")
+    static final class BiRelay<T,U> extends BiCompletion<T,U,Void> { // for And
+        BiRelay(CompletableFuture<Void> dep,
+                CompletableFuture<T> src,
+                CompletableFuture<U> snd) {
+            super(null, dep, src, snd);
+        }
+        final CompletableFuture<Void> tryFire(int mode) {
+            CompletableFuture<Void> d;
+            CompletableFuture<T> a;
+            CompletableFuture<U> b;
+            if ((d = dep) == null || !d.biRelay(a = src, b = snd))
+                return null;
+            src = null; snd = null; dep = null;
+            return d.postFire(a, b, mode);
+        }
+    }
+
+    boolean biRelay(CompletableFuture<?> a, CompletableFuture<?> b) {
+        Object r, s; Throwable x;
+        if (a == null || (r = a.result) == null ||
+            b == null || (s = b.result) == null)
+            return false;
+        if (result == null) {
+            if (r instanceof AltResult && (x = ((AltResult)r).ex) != null)
+                completeThrowable(x, r);
+            else if (s instanceof AltResult && (x = ((AltResult)s).ex) != null)
+                completeThrowable(x, s);
+            else
+                completeNull();
+        }
+        return true;
+    }
+
+    /** Recursively constructs a tree of completions. */
+    static CompletableFuture<Void> andTree(CompletableFuture<?>[] cfs,
+                                           int lo, int hi) {
+        CompletableFuture<Void> d = new CompletableFuture<Void>();
+        if (lo > hi) // empty
+            d.result = NIL;
+        else {
+            CompletableFuture<?> a, b;
+            int mid = (lo + hi) >>> 1;
+            if ((a = (lo == mid ? cfs[lo] :
+                      andTree(cfs, lo, mid))) == null ||
+                (b = (lo == hi ? a : (hi == mid+1) ? cfs[hi] :
+                      andTree(cfs, mid+1, hi)))  == null)
+                throw new NullPointerException();
+            if (!d.biRelay(a, b)) {
+                BiRelay<?,?> c = new BiRelay<>(d, a, b);
+                a.bipush(b, c);
+                c.tryFire(SYNC);
+            }
+        }
+        return d;
+    }
+
+    /* ------------- Projected (Ored) BiCompletions -------------- */
+
+    /** Pushes completion to this and b unless either done. */
+    final void orpush(CompletableFuture<?> b, BiCompletion<?,?,?> c) {
+        if (c != null) {
+            while ((b == null || b.result == null) && result == null) {
+                if (tryPushStack(c)) {
+                    if (b != null && b != this && b.result == null) {
+                        Completion q = new CoCompletion(c);
+                        while (result == null && b.result == null &&
+                               !b.tryPushStack(q))
+                            lazySetNext(q, null); // clear on failure
+                    }
+                    break;
+                }
+                lazySetNext(c, null); // clear on failure
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class OrApply<T,U extends T,V> extends BiCompletion<T,U,V> {
+        Function<? super T,? extends V> fn;
+        OrApply(Executor executor, CompletableFuture<V> dep,
+                CompletableFuture<T> src,
+                CompletableFuture<U> snd,
+                Function<? super T,? extends V> fn) {
+            super(executor, dep, src, snd); this.fn = fn;
+        }
+        final CompletableFuture<V> tryFire(int mode) {
+            CompletableFuture<V> d;
+            CompletableFuture<T> a;
+            CompletableFuture<U> b;
+            if ((d = dep) == null ||
+                !d.orApply(a = src, b = snd, fn, mode > 0 ? null : this))
+                return null;
+            dep = null; src = null; snd = null; fn = null;
+            return d.postFire(a, b, mode);
+        }
+    }
+
+    final <R,S extends R> boolean orApply(CompletableFuture<R> a,
+                                          CompletableFuture<S> b,
+                                          Function<? super R, ? extends T> f,
+                                          OrApply<R,S,T> c) {
+        Object r; Throwable x;
+        if (a == null || b == null ||
+            ((r = a.result) == null && (r = b.result) == null) || f == null)
+            return false;
+        tryComplete: if (result == null) {
+            try {
+                if (c != null && !c.claim())
+                    return false;
+                if (r instanceof AltResult) {
+                    if ((x = ((AltResult)r).ex) != null) {
+                        completeThrowable(x, r);
+                        break tryComplete;
+                    }
+                    r = null;
+                }
+                @SuppressWarnings("unchecked") R rr = (R) r;
+                completeValue(f.apply(rr));
+            } catch (Throwable ex) {
+                completeThrowable(ex);
+            }
+        }
+        return true;
+    }
+
+    private <U extends T,V> CompletableFuture<V> orApplyStage(
+        Executor e, CompletionStage<U> o,
+        Function<? super T, ? extends V> f) {
+        CompletableFuture<U> b;
+        if (f == null || (b = o.toCompletableFuture()) == null)
+            throw new NullPointerException();
+        CompletableFuture<V> d = new CompletableFuture<V>();
+        if (e != null || !d.orApply(this, b, f, null)) {
+            OrApply<T,U,V> c = new OrApply<T,U,V>(e, d, this, b, f);
+            orpush(b, c);
+            c.tryFire(SYNC);
+        }
+        return d;
+    }
+
+    @SuppressWarnings("serial")
+    static final class OrAccept<T,U extends T> extends BiCompletion<T,U,Void> {
+        Consumer<? super T> fn;
+        OrAccept(Executor executor, CompletableFuture<Void> dep,
+                 CompletableFuture<T> src,
+                 CompletableFuture<U> snd,
+                 Consumer<? super T> fn) {
+            super(executor, dep, src, snd); this.fn = fn;
+        }
+        final CompletableFuture<Void> tryFire(int mode) {
+            CompletableFuture<Void> d;
+            CompletableFuture<T> a;
+            CompletableFuture<U> b;
+            if ((d = dep) == null ||
+                !d.orAccept(a = src, b = snd, fn, mode > 0 ? null : this))
+                return null;
+            dep = null; src = null; snd = null; fn = null;
+            return d.postFire(a, b, mode);
+        }
+    }
+
+    final <R,S extends R> boolean orAccept(CompletableFuture<R> a,
+                                           CompletableFuture<S> b,
+                                           Consumer<? super R> f,
+                                           OrAccept<R,S> c) {
+        Object r; Throwable x;
+        if (a == null || b == null ||
+            ((r = a.result) == null && (r = b.result) == null) || f == null)
+            return false;
+        tryComplete: if (result == null) {
+            try {
+                if (c != null && !c.claim())
+                    return false;
+                if (r instanceof AltResult) {
+                    if ((x = ((AltResult)r).ex) != null) {
+                        completeThrowable(x, r);
+                        break tryComplete;
+                    }
+                    r = null;
+                }
+                @SuppressWarnings("unchecked") R rr = (R) r;
+                f.accept(rr);
+                completeNull();
+            } catch (Throwable ex) {
+                completeThrowable(ex);
+            }
+        }
+        return true;
+    }
+
+    private <U extends T> CompletableFuture<Void> orAcceptStage(
+        Executor e, CompletionStage<U> o, Consumer<? super T> f) {
+        CompletableFuture<U> b;
+        if (f == null || (b = o.toCompletableFuture()) == null)
+            throw new NullPointerException();
+        CompletableFuture<Void> d = new CompletableFuture<Void>();
+        if (e != null || !d.orAccept(this, b, f, null)) {
+            OrAccept<T,U> c = new OrAccept<T,U>(e, d, this, b, f);
+            orpush(b, c);
+            c.tryFire(SYNC);
+        }
+        return d;
+    }
+
+    @SuppressWarnings("serial")
+    static final class OrRun<T,U> extends BiCompletion<T,U,Void> {
+        Runnable fn;
+        OrRun(Executor executor, CompletableFuture<Void> dep,
+              CompletableFuture<T> src,
+              CompletableFuture<U> snd,
+              Runnable fn) {
+            super(executor, dep, src, snd); this.fn = fn;
+        }
+        final CompletableFuture<Void> tryFire(int mode) {
+            CompletableFuture<Void> d;
+            CompletableFuture<T> a;
+            CompletableFuture<U> b;
+            if ((d = dep) == null ||
+                !d.orRun(a = src, b = snd, fn, mode > 0 ? null : this))
+                return null;
+            dep = null; src = null; snd = null; fn = null;
+            return d.postFire(a, b, mode);
+        }
+    }
+
+    final boolean orRun(CompletableFuture<?> a, CompletableFuture<?> b,
+                        Runnable f, OrRun<?,?> c) {
+        Object r; Throwable x;
+        if (a == null || b == null ||
+            ((r = a.result) == null && (r = b.result) == null) || f == null)
+            return false;
+        if (result == null) {
+            try {
+                if (c != null && !c.claim())
+                    return false;
+                if (r instanceof AltResult && (x = ((AltResult)r).ex) != null)
+                    completeThrowable(x, r);
+                else {
+                    f.run();
+                    completeNull();
+                }
+            } catch (Throwable ex) {
+                completeThrowable(ex);
+            }
+        }
+        return true;
+    }
+
+    private CompletableFuture<Void> orRunStage(Executor e, CompletionStage<?> o,
+                                               Runnable f) {
+        CompletableFuture<?> b;
+        if (f == null || (b = o.toCompletableFuture()) == null)
+            throw new NullPointerException();
+        CompletableFuture<Void> d = new CompletableFuture<Void>();
+        if (e != null || !d.orRun(this, b, f, null)) {
+            OrRun<T,?> c = new OrRun<>(e, d, this, b, f);
+            orpush(b, c);
+            c.tryFire(SYNC);
+        }
+        return d;
+    }
+
+    @SuppressWarnings("serial")
+    static final class OrRelay<T,U> extends BiCompletion<T,U,Object> { // for Or
+        OrRelay(CompletableFuture<Object> dep, CompletableFuture<T> src,
+                CompletableFuture<U> snd) {
+            super(null, dep, src, snd);
+        }
+        final CompletableFuture<Object> tryFire(int mode) {
+            CompletableFuture<Object> d;
+            CompletableFuture<T> a;
+            CompletableFuture<U> b;
+            if ((d = dep) == null || !d.orRelay(a = src, b = snd))
+                return null;
+            src = null; snd = null; dep = null;
+            return d.postFire(a, b, mode);
+        }
+    }
+
+    final boolean orRelay(CompletableFuture<?> a, CompletableFuture<?> b) {
+        Object r;
+        if (a == null || b == null ||
+            ((r = a.result) == null && (r = b.result) == null))
+            return false;
+        if (result == null)
+            completeRelay(r);
+        return true;
+    }
+
+    /** Recursively constructs a tree of completions. */
+    static CompletableFuture<Object> orTree(CompletableFuture<?>[] cfs,
+                                            int lo, int hi) {
+        CompletableFuture<Object> d = new CompletableFuture<Object>();
+        if (lo <= hi) {
+            CompletableFuture<?> a, b;
+            int mid = (lo + hi) >>> 1;
+            if ((a = (lo == mid ? cfs[lo] :
+                      orTree(cfs, lo, mid))) == null ||
+                (b = (lo == hi ? a : (hi == mid+1) ? cfs[hi] :
+                      orTree(cfs, mid+1, hi)))  == null)
+                throw new NullPointerException();
+            if (!d.orRelay(a, b)) {
+                OrRelay<?,?> c = new OrRelay<>(d, a, b);
+                a.orpush(b, c);
+                c.tryFire(SYNC);
+            }
+        }
+        return d;
+    }
+
+    /* ------------- Zero-input Async forms -------------- */
+
+    @SuppressWarnings("serial")
+    static final class AsyncSupply<T> extends ForkJoinTask<Void>
+            implements Runnable, AsynchronousCompletionTask {
+        CompletableFuture<T> dep; Supplier<T> fn;
+        AsyncSupply(CompletableFuture<T> dep, Supplier<T> fn) {
+            this.dep = dep; this.fn = fn;
+        }
+
+        public final Void getRawResult() { return null; }
+        public final void setRawResult(Void v) {}
+        public final boolean exec() { run(); return true; }
+
+        public void run() {
+            CompletableFuture<T> d; Supplier<T> f;
+            if ((d = dep) != null && (f = fn) != null) {
+                dep = null; fn = null;
+                if (d.result == null) {
+                    try {
+                        d.completeValue(f.get());
+                    } catch (Throwable ex) {
+                        d.completeThrowable(ex);
+                    }
+                }
+                d.postComplete();
+            }
+        }
+    }
+
+    static <U> CompletableFuture<U> asyncSupplyStage(Executor e,
+                                                     Supplier<U> f) {
+        if (f == null) throw new NullPointerException();
+        CompletableFuture<U> d = new CompletableFuture<U>();
+        e.execute(new AsyncSupply<U>(d, f));
+        return d;
+    }
+
+    @SuppressWarnings("serial")
+    static final class AsyncRun extends ForkJoinTask<Void>
+            implements Runnable, AsynchronousCompletionTask {
+        CompletableFuture<Void> dep; Runnable fn;
+        AsyncRun(CompletableFuture<Void> dep, Runnable fn) {
+            this.dep = dep; this.fn = fn;
+        }
+
+        public final Void getRawResult() { return null; }
+        public final void setRawResult(Void v) {}
+        public final boolean exec() { run(); return true; }
+
+        public void run() {
+            CompletableFuture<Void> d; Runnable f;
+            if ((d = dep) != null && (f = fn) != null) {
+                dep = null; fn = null;
+                if (d.result == null) {
+                    try {
+                        f.run();
+                        d.completeNull();
+                    } catch (Throwable ex) {
+                        d.completeThrowable(ex);
+                    }
+                }
+                d.postComplete();
+            }
+        }
+    }
+
+    static CompletableFuture<Void> asyncRunStage(Executor e, Runnable f) {
+        if (f == null) throw new NullPointerException();
+        CompletableFuture<Void> d = new CompletableFuture<Void>();
+        e.execute(new AsyncRun(d, f));
+        return d;
+    }
+
+    /* ------------- Signallers -------------- */
 
     /**
-     * Heuristic spin value for waitingGet() before blocking on
-     * multiprocessors
+     * Completion for recording and releasing a waiting thread.  This
+     * class implements ManagedBlocker to avoid starvation when
+     * blocking actions pile up in ForkJoinPools.
      */
-    static final int SPINS = (NCPU > 1) ? 1 << 8 : 0;
-
-    /**
-     * Linked nodes to record waiting threads in a Treiber stack.  See
-     * other classes such as Phaser and SynchronousQueue for more
-     * detailed explanation. This class implements ManagedBlocker to
-     * avoid starvation when blocking actions pile up in
-     * ForkJoinPools.
-     */
-    static final class WaitNode implements ForkJoinPool.ManagedBlocker {
-        long nanos;          // wait time if timed
-        final long deadline; // non-zero if timed
+    @SuppressWarnings("serial")
+    static final class Signaller extends Completion
+        implements ForkJoinPool.ManagedBlocker {
+        long nanos;                    // wait time if timed
+        final long deadline;           // non-zero if timed
         volatile int interruptControl; // > 0: interruptible, < 0: interrupted
         volatile Thread thread;
-        volatile WaitNode next;
-        WaitNode(boolean interruptible, long nanos, long deadline) {
+
+        Signaller(boolean interruptible, long nanos, long deadline) {
             this.thread = Thread.currentThread();
             this.interruptControl = interruptible ? 1 : 0;
             this.nanos = nanos;
             this.deadline = deadline;
         }
+        final CompletableFuture<?> tryFire(int ignore) {
+            Thread w; // no need to atomically claim
+            if ((w = thread) != null) {
+                thread = null;
+                LockSupport.unpark(w);
+            }
+            return null;
+        }
         public boolean isReleasable() {
             if (thread == null)
                 return true;
@@ -273,6 +1687,7 @@
                 LockSupport.parkNanos(this, nanos);
             return isReleasable();
         }
+        final boolean isLive() { return thread != null; }
     }
 
     /**
@@ -280,1832 +1695,89 @@
      * interrupted.
      */
     private Object waitingGet(boolean interruptible) {
-        WaitNode q = null;
+        Signaller q = null;
         boolean queued = false;
-        int spins = SPINS;
-        for (Object r;;) {
-            if ((r = result) != null) {
-                if (q != null) { // suppress unpark
-                    q.thread = null;
-                    if (q.interruptControl < 0) {
-                        if (interruptible) {
-                            removeWaiter(q);
-                            return null;
-                        }
-                        Thread.currentThread().interrupt();
-                    }
-                }
-                postComplete(); // help release others
-                return r;
-            }
+        int spins = -1;
+        Object r;
+        while ((r = result) == null) {
+            if (spins < 0)
+                spins = (Runtime.getRuntime().availableProcessors() > 1) ?
+                    1 << 8 : 0; // Use brief spin-wait on multiprocessors
             else if (spins > 0) {
-                int rnd = ThreadLocalRandom.nextSecondarySeed();
-                if (rnd == 0)
-                    rnd = ThreadLocalRandom.current().nextInt();
-                if (rnd >= 0)
+                if (ThreadLocalRandom.nextSecondarySeed() >= 0)
                     --spins;
             }
             else if (q == null)
-                q = new WaitNode(interruptible, 0L, 0L);
+                q = new Signaller(interruptible, 0L, 0L);
             else if (!queued)
-                queued = UNSAFE.compareAndSwapObject(this, WAITERS,
-                                                     q.next = waiters, q);
+                queued = tryPushStack(q);
             else if (interruptible && q.interruptControl < 0) {
-                removeWaiter(q);
+                q.thread = null;
+                cleanStack();
                 return null;
             }
             else if (q.thread != null && result == null) {
                 try {
                     ForkJoinPool.managedBlock(q);
-                } catch (InterruptedException ex) {
+                } catch (InterruptedException ie) {
                     q.interruptControl = -1;
                 }
             }
         }
+        if (q != null) {
+            q.thread = null;
+            if (q.interruptControl < 0) {
+                if (interruptible)
+                    r = null; // report interruption
+                else
+                    Thread.currentThread().interrupt();
+            }
+        }
+        postComplete();
+        return r;
     }
 
     /**
-     * Awaits completion or aborts on interrupt or timeout.
-     *
-     * @param nanos time to wait
-     * @return raw result
+     * Returns raw result after waiting, or null if interrupted, or
+     * throws TimeoutException on timeout.
      */
-    private Object timedAwaitDone(long nanos)
-        throws InterruptedException, TimeoutException {
-        WaitNode q = null;
+    private Object timedGet(long nanos) throws TimeoutException {
+        if (Thread.interrupted())
+            return null;
+        if (nanos <= 0L)
+            throw new TimeoutException();
+        long d = System.nanoTime() + nanos;
+        Signaller q = new Signaller(true, nanos, d == 0L ? 1L : d); // avoid 0
         boolean queued = false;
-        for (Object r;;) {
-            if ((r = result) != null) {
-                if (q != null) {
-                    q.thread = null;
-                    if (q.interruptControl < 0) {
-                        removeWaiter(q);
-                        throw new InterruptedException();
-                    }
-                }
-                postComplete();
-                return r;
-            }
-            else if (q == null) {
-                if (nanos <= 0L)
-                    throw new TimeoutException();
-                long d = System.nanoTime() + nanos;
-                q = new WaitNode(true, nanos, d == 0L ? 1L : d); // avoid 0
-            }
-            else if (!queued)
-                queued = UNSAFE.compareAndSwapObject(this, WAITERS,
-                                                     q.next = waiters, q);
-            else if (q.interruptControl < 0) {
-                removeWaiter(q);
-                throw new InterruptedException();
-            }
-            else if (q.nanos <= 0L) {
-                if (result == null) {
-                    removeWaiter(q);
-                    throw new TimeoutException();
-                }
+        Object r;
+        // We intentionally don't spin here (as waitingGet does) because
+        // the call to nanoTime() above acts much like a spin.
+        while ((r = result) == null) {
+            if (!queued)
+                queued = tryPushStack(q);
+            else if (q.interruptControl < 0 || q.nanos <= 0L) {
+                q.thread = null;
+                cleanStack();
+                if (q.interruptControl < 0)
+                    return null;
+                throw new TimeoutException();
             }
             else if (q.thread != null && result == null) {
                 try {
                     ForkJoinPool.managedBlock(q);
-                } catch (InterruptedException ex) {
+                } catch (InterruptedException ie) {
                     q.interruptControl = -1;
                 }
             }
         }
+        if (q.interruptControl < 0)
+            r = null;
+        q.thread = null;
+        postComplete();
+        return r;
     }
 
-    /**
-     * Tries to unlink a timed-out or interrupted wait node to avoid
-     * accumulating garbage.  Internal nodes are simply unspliced
-     * without CAS since it is harmless if they are traversed anyway
-     * by releasers.  To avoid effects of unsplicing from already
-     * removed nodes, the list is retraversed in case of an apparent
-     * race.  This is slow when there are a lot of nodes, but we don't
-     * expect lists to be long enough to outweigh higher-overhead
-     * schemes.
-     */
-    private void removeWaiter(WaitNode node) {
-        if (node != null) {
-            node.thread = null;
-            retry:
-            for (;;) {          // restart on removeWaiter race
-                for (WaitNode pred = null, q = waiters, s; q != null; q = s) {
-                    s = q.next;
-                    if (q.thread != null)
-                        pred = q;
-                    else if (pred != null) {
-                        pred.next = s;
-                        if (pred.thread == null) // check for race
-                            continue retry;
-                    }
-                    else if (!UNSAFE.compareAndSwapObject(this, WAITERS, q, s))
-                        continue retry;
-                }
-                break;
-            }
-        }
-    }
-
-    /* ------------- Async tasks -------------- */
-
-    /**
-     * A marker interface identifying asynchronous tasks produced by
-     * {@code async} methods. This may be useful for monitoring,
-     * debugging, and tracking asynchronous activities.
-     *
-     * @since 1.8
-     */
-    public static interface AsynchronousCompletionTask {
-    }
-
-    /** Base class can act as either FJ or plain Runnable */
-    @SuppressWarnings("serial")
-    abstract static class Async extends ForkJoinTask<Void>
-        implements Runnable, AsynchronousCompletionTask {
-        public final Void getRawResult() { return null; }
-        public final void setRawResult(Void v) { }
-        public final void run() { exec(); }
-    }
-
-    /**
-     * Starts the given async task using the given executor, unless
-     * the executor is ForkJoinPool.commonPool and it has been
-     * disabled, in which case starts a new thread.
-     */
-    static void execAsync(Executor e, Async r) {
-        if (e == ForkJoinPool.commonPool() &&
-            ForkJoinPool.getCommonPoolParallelism() <= 1)
-            new Thread(r).start();
-        else
-            e.execute(r);
-    }
-
-    static final class AsyncRun extends Async {
-        final Runnable fn;
-        final CompletableFuture<Void> dst;
-        AsyncRun(Runnable fn, CompletableFuture<Void> dst) {
-            this.fn = fn; this.dst = dst;
-        }
-        public final boolean exec() {
-            CompletableFuture<Void> d; Throwable ex;
-            if ((d = this.dst) != null && d.result == null) {
-                try {
-                    fn.run();
-                    ex = null;
-                } catch (Throwable rex) {
-                    ex = rex;
-                }
-                d.internalComplete(null, ex);
-            }
-            return true;
-        }
-        private static final long serialVersionUID = 5232453952276885070L;
-    }
-
-    static final class AsyncSupply<U> extends Async {
-        final Supplier<U> fn;
-        final CompletableFuture<U> dst;
-        AsyncSupply(Supplier<U> fn, CompletableFuture<U> dst) {
-            this.fn = fn; this.dst = dst;
-        }
-        public final boolean exec() {
-            CompletableFuture<U> d; U u; Throwable ex;
-            if ((d = this.dst) != null && d.result == null) {
-                try {
-                    u = fn.get();
-                    ex = null;
-                } catch (Throwable rex) {
-                    ex = rex;
-                    u = null;
-                }
-                d.internalComplete(u, ex);
-            }
-            return true;
-        }
-        private static final long serialVersionUID = 5232453952276885070L;
-    }
-
-    static final class AsyncApply<T,U> extends Async {
-        final T arg;
-        final Function<? super T,? extends U> fn;
-        final CompletableFuture<U> dst;
-        AsyncApply(T arg, Function<? super T,? extends U> fn,
-                   CompletableFuture<U> dst) {
-            this.arg = arg; this.fn = fn; this.dst = dst;
-        }
-        public final boolean exec() {
-            CompletableFuture<U> d; U u; Throwable ex;
-            if ((d = this.dst) != null && d.result == null) {
-                try {
-                    u = fn.apply(arg);
-                    ex = null;
-                } catch (Throwable rex) {
-                    ex = rex;
-                    u = null;
-                }
-                d.internalComplete(u, ex);
-            }
-            return true;
-        }
-        private static final long serialVersionUID = 5232453952276885070L;
-    }
-
-    static final class AsyncCombine<T,U,V> extends Async {
-        final T arg1;
-        final U arg2;
-        final BiFunction<? super T,? super U,? extends V> fn;
-        final CompletableFuture<V> dst;
-        AsyncCombine(T arg1, U arg2,
-                     BiFunction<? super T,? super U,? extends V> fn,
-                     CompletableFuture<V> dst) {
-            this.arg1 = arg1; this.arg2 = arg2; this.fn = fn; this.dst = dst;
-        }
-        public final boolean exec() {
-            CompletableFuture<V> d; V v; Throwable ex;
-            if ((d = this.dst) != null && d.result == null) {
-                try {
-                    v = fn.apply(arg1, arg2);
-                    ex = null;
-                } catch (Throwable rex) {
-                    ex = rex;
-                    v = null;
-                }
-                d.internalComplete(v, ex);
-            }
-            return true;
-        }
-        private static final long serialVersionUID = 5232453952276885070L;
-    }
-
-    static final class AsyncAccept<T> extends Async {
-        final T arg;
-        final Consumer<? super T> fn;
-        final CompletableFuture<?> dst;
-        AsyncAccept(T arg, Consumer<? super T> fn,
-                    CompletableFuture<?> dst) {
-            this.arg = arg; this.fn = fn; this.dst = dst;
-        }
-        public final boolean exec() {
-            CompletableFuture<?> d; Throwable ex;
-            if ((d = this.dst) != null && d.result == null) {
-                try {
-                    fn.accept(arg);
-                    ex = null;
-                } catch (Throwable rex) {
-                    ex = rex;
-                }
-                d.internalComplete(null, ex);
-            }
-            return true;
-        }
-        private static final long serialVersionUID = 5232453952276885070L;
-    }
-
-    static final class AsyncAcceptBoth<T,U> extends Async {
-        final T arg1;
-        final U arg2;
-        final BiConsumer<? super T,? super U> fn;
-        final CompletableFuture<?> dst;
-        AsyncAcceptBoth(T arg1, U arg2,
-                        BiConsumer<? super T,? super U> fn,
-                        CompletableFuture<?> dst) {
-            this.arg1 = arg1; this.arg2 = arg2; this.fn = fn; this.dst = dst;
-        }
-        public final boolean exec() {
-            CompletableFuture<?> d; Throwable ex;
-            if ((d = this.dst) != null && d.result == null) {
-                try {
-                    fn.accept(arg1, arg2);
-                    ex = null;
-                } catch (Throwable rex) {
-                    ex = rex;
-                }
-                d.internalComplete(null, ex);
-            }
-            return true;
-        }
-        private static final long serialVersionUID = 5232453952276885070L;
-    }
-
-    static final class AsyncCompose<T,U> extends Async {
-        final T arg;
-        final Function<? super T, ? extends CompletionStage<U>> fn;
-        final CompletableFuture<U> dst;
-        AsyncCompose(T arg,
-                     Function<? super T, ? extends CompletionStage<U>> fn,
-                     CompletableFuture<U> dst) {
-            this.arg = arg; this.fn = fn; this.dst = dst;
-        }
-        public final boolean exec() {
-            CompletableFuture<U> d, fr; U u; Throwable ex;
-            if ((d = this.dst) != null && d.result == null) {
-                try {
-                    CompletionStage<U> cs = fn.apply(arg);
-                    fr = (cs == null) ? null : cs.toCompletableFuture();
-                    ex = (fr == null) ? new NullPointerException() : null;
-                } catch (Throwable rex) {
-                    ex = rex;
-                    fr = null;
-                }
-                if (ex != null)
-                    u = null;
-                else {
-                    Object r = fr.result;
-                    if (r == null)
-                        r = fr.waitingGet(false);
-                    if (r instanceof AltResult) {
-                        ex = ((AltResult)r).ex;
-                        u = null;
-                    }
-                    else {
-                        @SuppressWarnings("unchecked") U ur = (U) r;
-                        u = ur;
-                    }
-                }
-                d.internalComplete(u, ex);
-            }
-            return true;
-        }
-        private static final long serialVersionUID = 5232453952276885070L;
-    }
-
-    static final class AsyncWhenComplete<T> extends Async {
-        final T arg1;
-        final Throwable arg2;
-        final BiConsumer<? super T,? super Throwable> fn;
-        final CompletableFuture<T> dst;
-        AsyncWhenComplete(T arg1, Throwable arg2,
-                          BiConsumer<? super T,? super Throwable> fn,
-                          CompletableFuture<T> dst) {
-            this.arg1 = arg1; this.arg2 = arg2; this.fn = fn; this.dst = dst;
-        }
-        public final boolean exec() {
-            CompletableFuture<T> d;
-            if ((d = this.dst) != null && d.result == null) {
-                Throwable ex = arg2;
-                try {
-                    fn.accept(arg1, ex);
-                } catch (Throwable rex) {
-                    if (ex == null)
-                        ex = rex;
-                }
-                d.internalComplete(arg1, ex);
-            }
-            return true;
-        }
-        private static final long serialVersionUID = 5232453952276885070L;
-    }
-
-    /* ------------- Completions -------------- */
-
-    /**
-     * Simple linked list nodes to record completions, used in
-     * basically the same way as WaitNodes. (We separate nodes from
-     * the Completions themselves mainly because for the And and Or
-     * methods, the same Completion object resides in two lists.)
-     */
-    static final class CompletionNode {
-        final Completion completion;
-        volatile CompletionNode next;
-        CompletionNode(Completion completion) { this.completion = completion; }
-    }
-
-    // Opportunistically subclass AtomicInteger to use compareAndSet to claim.
-    @SuppressWarnings("serial")
-    abstract static class Completion extends AtomicInteger implements Runnable {
-    }
-
-    static final class ThenApply<T,U> extends Completion {
-        final CompletableFuture<? extends T> src;
-        final Function<? super T,? extends U> fn;
-        final CompletableFuture<U> dst;
-        final Executor executor;
-        ThenApply(CompletableFuture<? extends T> src,
-                  Function<? super T,? extends U> fn,
-                  CompletableFuture<U> dst,
-                  Executor executor) {
-            this.src = src; this.fn = fn; this.dst = dst;
-            this.executor = executor;
-        }
-        public final void run() {
-            final CompletableFuture<? extends T> a;
-            final Function<? super T,? extends U> fn;
-            final CompletableFuture<U> dst;
-            Object r; T t; Throwable ex;
-            if ((dst = this.dst) != null &&
-                (fn = this.fn) != null &&
-                (a = this.src) != null &&
-                (r = a.result) != null &&
-                compareAndSet(0, 1)) {
-                if (r instanceof AltResult) {
-                    ex = ((AltResult)r).ex;
-                    t = null;
-                }
-                else {
-                    ex = null;
-                    @SuppressWarnings("unchecked") T tr = (T) r;
-                    t = tr;
-                }
-                Executor e = executor;
-                U u = null;
-                if (ex == null) {
-                    try {
-                        if (e != null)
-                            execAsync(e, new AsyncApply<T,U>(t, fn, dst));
-                        else
-                            u = fn.apply(t);
-                    } catch (Throwable rex) {
-                        ex = rex;
-                    }
-                }
-                if (e == null || ex != null)
-                    dst.internalComplete(u, ex);
-            }
-        }
-        private static final long serialVersionUID = 5232453952276885070L;
-    }
-
-    static final class ThenAccept<T> extends Completion {
-        final CompletableFuture<? extends T> src;
-        final Consumer<? super T> fn;
-        final CompletableFuture<?> dst;
-        final Executor executor;
-        ThenAccept(CompletableFuture<? extends T> src,
-                   Consumer<? super T> fn,
-                   CompletableFuture<?> dst,
-                   Executor executor) {
-            this.src = src; this.fn = fn; this.dst = dst;
-            this.executor = executor;
-        }
-        public final void run() {
-            final CompletableFuture<? extends T> a;
-            final Consumer<? super T> fn;
-            final CompletableFuture<?> dst;
-            Object r; T t; Throwable ex;
-            if ((dst = this.dst) != null &&
-                (fn = this.fn) != null &&
-                (a = this.src) != null &&
-                (r = a.result) != null &&
-                compareAndSet(0, 1)) {
-                if (r instanceof AltResult) {
-                    ex = ((AltResult)r).ex;
-                    t = null;
-                }
-                else {
-                    ex = null;
-                    @SuppressWarnings("unchecked") T tr = (T) r;
-                    t = tr;
-                }
-                Executor e = executor;
-                if (ex == null) {
-                    try {
-                        if (e != null)
-                            execAsync(e, new AsyncAccept<T>(t, fn, dst));
-                        else
-                            fn.accept(t);
-                    } catch (Throwable rex) {
-                        ex = rex;
-                    }
-                }
-                if (e == null || ex != null)
-                    dst.internalComplete(null, ex);
-            }
-        }
-        private static final long serialVersionUID = 5232453952276885070L;
-    }
-
-    static final class ThenRun extends Completion {
-        final CompletableFuture<?> src;
-        final Runnable fn;
-        final CompletableFuture<Void> dst;
-        final Executor executor;
-        ThenRun(CompletableFuture<?> src,
-                Runnable fn,
-                CompletableFuture<Void> dst,
-                Executor executor) {
-            this.src = src; this.fn = fn; this.dst = dst;
-            this.executor = executor;
-        }
-        public final void run() {
-            final CompletableFuture<?> a;
-            final Runnable fn;
-            final CompletableFuture<Void> dst;
-            Object r; Throwable ex;
-            if ((dst = this.dst) != null &&
-                (fn = this.fn) != null &&
-                (a = this.src) != null &&
-                (r = a.result) != null &&
-                compareAndSet(0, 1)) {
-                if (r instanceof AltResult)
-                    ex = ((AltResult)r).ex;
-                else
-                    ex = null;
-                Executor e = executor;
-                if (ex == null) {
-                    try {
-                        if (e != null)
-                            execAsync(e, new AsyncRun(fn, dst));
-                        else
-                            fn.run();
-                    } catch (Throwable rex) {
-                        ex = rex;
-                    }
-                }
-                if (e == null || ex != null)
-                    dst.internalComplete(null, ex);
-            }
-        }
-        private static final long serialVersionUID = 5232453952276885070L;
-    }
-
-    static final class ThenCombine<T,U,V> extends Completion {
-        final CompletableFuture<? extends T> src;
-        final CompletableFuture<? extends U> snd;
-        final BiFunction<? super T,? super U,? extends V> fn;
-        final CompletableFuture<V> dst;
-        final Executor executor;
-        ThenCombine(CompletableFuture<? extends T> src,
-                    CompletableFuture<? extends U> snd,
-                    BiFunction<? super T,? super U,? extends V> fn,
-                    CompletableFuture<V> dst,
-                    Executor executor) {
-            this.src = src; this.snd = snd;
-            this.fn = fn; this.dst = dst;
-            this.executor = executor;
-        }
-        public final void run() {
-            final CompletableFuture<? extends T> a;
-            final CompletableFuture<? extends U> b;
-            final BiFunction<? super T,? super U,? extends V> fn;
-            final CompletableFuture<V> dst;
-            Object r, s; T t; U u; Throwable ex;
-            if ((dst = this.dst) != null &&
-                (fn = this.fn) != null &&
-                (a = this.src) != null &&
-                (r = a.result) != null &&
-                (b = this.snd) != null &&
-                (s = b.result) != null &&
-                compareAndSet(0, 1)) {
-                if (r instanceof AltResult) {
-                    ex = ((AltResult)r).ex;
-                    t = null;
-                }
-                else {
-                    ex = null;
-                    @SuppressWarnings("unchecked") T tr = (T) r;
-                    t = tr;
-                }
-                if (ex != null)
-                    u = null;
-                else if (s instanceof AltResult) {
-                    ex = ((AltResult)s).ex;
-                    u = null;
-                }
-                else {
-                    @SuppressWarnings("unchecked") U us = (U) s;
-                    u = us;
-                }
-                Executor e = executor;
-                V v = null;
-                if (ex == null) {
-                    try {
-                        if (e != null)
-                            execAsync(e, new AsyncCombine<T,U,V>(t, u, fn, dst));
-                        else
-                            v = fn.apply(t, u);
-                    } catch (Throwable rex) {
-                        ex = rex;
-                    }
-                }
-                if (e == null || ex != null)
-                    dst.internalComplete(v, ex);
-            }
-        }
-        private static final long serialVersionUID = 5232453952276885070L;
-    }
-
-    static final class ThenAcceptBoth<T,U> extends Completion {
-        final CompletableFuture<? extends T> src;
-        final CompletableFuture<? extends U> snd;
-        final BiConsumer<? super T,? super U> fn;
-        final CompletableFuture<Void> dst;
-        final Executor executor;
-        ThenAcceptBoth(CompletableFuture<? extends T> src,
-                       CompletableFuture<? extends U> snd,
-                       BiConsumer<? super T,? super U> fn,
-                       CompletableFuture<Void> dst,
-                       Executor executor) {
-            this.src = src; this.snd = snd;
-            this.fn = fn; this.dst = dst;
-            this.executor = executor;
-        }
-        public final void run() {
-            final CompletableFuture<? extends T> a;
-            final CompletableFuture<? extends U> b;
-            final BiConsumer<? super T,? super U> fn;
-            final CompletableFuture<Void> dst;
-            Object r, s; T t; U u; Throwable ex;
-            if ((dst = this.dst) != null &&
-                (fn = this.fn) != null &&
-                (a = this.src) != null &&
-                (r = a.result) != null &&
-                (b = this.snd) != null &&
-                (s = b.result) != null &&
-                compareAndSet(0, 1)) {
-                if (r instanceof AltResult) {
-                    ex = ((AltResult)r).ex;
-                    t = null;
-                }
-                else {
-                    ex = null;
-                    @SuppressWarnings("unchecked") T tr = (T) r;
-                    t = tr;
-                }
-                if (ex != null)
-                    u = null;
-                else if (s instanceof AltResult) {
-                    ex = ((AltResult)s).ex;
-                    u = null;
-                }
-                else {
-                    @SuppressWarnings("unchecked") U us = (U) s;
-                    u = us;
-                }
-                Executor e = executor;
-                if (ex == null) {
-                    try {
-                        if (e != null)
-                            execAsync(e, new AsyncAcceptBoth<T,U>(t, u, fn, dst));
-                        else
-                            fn.accept(t, u);
-                    } catch (Throwable rex) {
-                        ex = rex;
-                    }
-                }
-                if (e == null || ex != null)
-                    dst.internalComplete(null, ex);
-            }
-        }
-        private static final long serialVersionUID = 5232453952276885070L;
-    }
-
-    static final class RunAfterBoth extends Completion {
-        final CompletableFuture<?> src;
-        final CompletableFuture<?> snd;
-        final Runnable fn;
-        final CompletableFuture<Void> dst;
-        final Executor executor;
-        RunAfterBoth(CompletableFuture<?> src,
-                     CompletableFuture<?> snd,
-                     Runnable fn,
-                     CompletableFuture<Void> dst,
-                     Executor executor) {
-            this.src = src; this.snd = snd;
-            this.fn = fn; this.dst = dst;
-            this.executor = executor;
-        }
-        public final void run() {
-            final CompletableFuture<?> a;
-            final CompletableFuture<?> b;
-            final Runnable fn;
-            final CompletableFuture<Void> dst;
-            Object r, s; Throwable ex;
-            if ((dst = this.dst) != null &&
-                (fn = this.fn) != null &&
-                (a = this.src) != null &&
-                (r = a.result) != null &&
-                (b = this.snd) != null &&
-                (s = b.result) != null &&
-                compareAndSet(0, 1)) {
-                if (r instanceof AltResult)
-                    ex = ((AltResult)r).ex;
-                else
-                    ex = null;
-                if (ex == null && (s instanceof AltResult))
-                    ex = ((AltResult)s).ex;
-                Executor e = executor;
-                if (ex == null) {
-                    try {
-                        if (e != null)
-                            execAsync(e, new AsyncRun(fn, dst));
-                        else
-                            fn.run();
-                    } catch (Throwable rex) {
-                        ex = rex;
-                    }
-                }
-                if (e == null || ex != null)
-                    dst.internalComplete(null, ex);
-            }
-        }
-        private static final long serialVersionUID = 5232453952276885070L;
-    }
-
-    static final class AndCompletion extends Completion {
-        final CompletableFuture<?> src;
-        final CompletableFuture<?> snd;
-        final CompletableFuture<Void> dst;
-        AndCompletion(CompletableFuture<?> src,
-                      CompletableFuture<?> snd,
-                      CompletableFuture<Void> dst) {
-            this.src = src; this.snd = snd; this.dst = dst;
-        }
-        public final void run() {
-            final CompletableFuture<?> a;
-            final CompletableFuture<?> b;
-            final CompletableFuture<Void> dst;
-            Object r, s; Throwable ex;
-            if ((dst = this.dst) != null &&
-                (a = this.src) != null &&
-                (r = a.result) != null &&
-                (b = this.snd) != null &&
-                (s = b.result) != null &&
-                compareAndSet(0, 1)) {
-                if (r instanceof AltResult)
-                    ex = ((AltResult)r).ex;
-                else
-                    ex = null;
-                if (ex == null && (s instanceof AltResult))
-                    ex = ((AltResult)s).ex;
-                dst.internalComplete(null, ex);
-            }
-        }
-        private static final long serialVersionUID = 5232453952276885070L;
-    }
-
-    static final class ApplyToEither<T,U> extends Completion {
-        final CompletableFuture<? extends T> src;
-        final CompletableFuture<? extends T> snd;
-        final Function<? super T,? extends U> fn;
-        final CompletableFuture<U> dst;
-        final Executor executor;
-        ApplyToEither(CompletableFuture<? extends T> src,
-                      CompletableFuture<? extends T> snd,
-                      Function<? super T,? extends U> fn,
-                      CompletableFuture<U> dst,
-                      Executor executor) {
-            this.src = src; this.snd = snd;
-            this.fn = fn; this.dst = dst;
-            this.executor = executor;
-        }
-        public final void run() {
-            final CompletableFuture<? extends T> a;
-            final CompletableFuture<? extends T> b;
-            final Function<? super T,? extends U> fn;
-            final CompletableFuture<U> dst;
-            Object r; T t; Throwable ex;
-            if ((