changeset 7542:c4826f8d7896

Merge
author aph
date Fri, 05 Sep 2014 06:26:44 -0400
parents a693d097790b (current diff) efbd07229e6c (diff)
children c6375c27cbfa
files .hgtags agent/src/share/classes/sun/jvm/hotspot/gc_implementation/g1/HeapRegionSeq.java make/bsd/makefiles/vm.make make/hotspot_version make/jprt.properties make/linux/makefiles/vm.make src/cpu/x86/vm/c1_LIRGenerator_x86.cpp src/os/bsd/vm/os_bsd.cpp src/os/linux/vm/os_linux.cpp src/share/vm/c1/c1_Compiler.cpp src/share/vm/c1/c1_GraphBuilder.cpp src/share/vm/c1/c1_Instruction.hpp src/share/vm/c1/c1_LIRGenerator.cpp src/share/vm/c1/c1_LIRGenerator.hpp src/share/vm/ci/ciEnv.cpp src/share/vm/classfile/classFileParser.cpp src/share/vm/classfile/dictionary.cpp src/share/vm/classfile/dictionary.hpp src/share/vm/classfile/symbolTable.cpp src/share/vm/classfile/systemDictionary.cpp src/share/vm/classfile/verifier.cpp src/share/vm/gc_implementation/concurrentMarkSweep/cmsCollectorPolicy.cpp src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp src/share/vm/gc_implementation/g1/concurrentMark.cpp src/share/vm/gc_implementation/g1/concurrentMark.inline.hpp src/share/vm/gc_implementation/g1/g1AllocRegion.hpp src/share/vm/gc_implementation/g1/g1CardCounts.cpp src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp src/share/vm/gc_implementation/g1/g1RemSet.cpp src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.cpp src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.hpp src/share/vm/gc_implementation/g1/heapRegion.cpp src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.hpp src/share/vm/gc_interface/collectedHeap.hpp src/share/vm/memory/allocation.inline.hpp src/share/vm/memory/cardTableModRefBS.cpp src/share/vm/memory/cardTableModRefBS.hpp src/share/vm/memory/collectorPolicy.cpp src/share/vm/memory/genCollectedHeap.cpp src/share/vm/memory/genCollectedHeap.hpp src/share/vm/opto/c2_globals.hpp src/share/vm/opto/callGenerator.cpp src/share/vm/opto/callGenerator.hpp src/share/vm/opto/compile.cpp src/share/vm/opto/compile.hpp src/share/vm/opto/doCall.cpp src/share/vm/opto/graphKit.cpp src/share/vm/opto/graphKit.hpp src/share/vm/opto/ifnode.cpp src/share/vm/opto/library_call.cpp src/share/vm/opto/parse.hpp src/share/vm/opto/parse1.cpp src/share/vm/opto/type.cpp src/share/vm/prims/jni.cpp src/share/vm/prims/whitebox.cpp src/share/vm/runtime/arguments.cpp src/share/vm/runtime/arguments.hpp src/share/vm/runtime/globals.hpp src/share/vm/runtime/java.cpp src/share/vm/runtime/os.hpp src/share/vm/runtime/safepoint.cpp src/share/vm/runtime/thread.cpp src/share/vm/runtime/thread.hpp src/share/vm/services/memPtr.cpp src/share/vm/services/memPtr.hpp src/share/vm/services/memPtrArray.hpp src/share/vm/services/memRecorder.cpp src/share/vm/services/memRecorder.hpp src/share/vm/services/memSnapshot.cpp src/share/vm/services/memSnapshot.hpp src/share/vm/services/memTrackWorker.cpp src/share/vm/services/memTrackWorker.hpp src/share/vm/utilities/vmError.cpp test/TEST.groups test/testlibrary/whitebox/sun/hotspot/WhiteBox.java
diffstat 187 files changed, 8541 insertions(+), 8055 deletions(-) [+]
line wrap: on
line diff
--- a/.hgtags	Thu Sep 04 13:06:04 2014 -0400
+++ b/.hgtags	Fri Sep 05 06:26:44 2014 -0400
@@ -505,6 +505,10 @@
 f7429096a202cab5c36a0f20dea33c554026010f jdk8u20-b22
 7c56530b11496459e66cb9ea933035002311672c hs25.20-b22
 f09d1f6a401e25a54dad44bb7bea482e47558af5 jdk8u20-b23
+42ddd0bbcb6630fe463ec9bc1893c838d5edff1b jdk8u20-b24
+00cf2b6f51b9560b01030e8f4c28c466f0b21fe3 hs25.20-b23
+19408d5fd31c25ce60c43dd33e92b96e8df4a4ea jdk8u20-b25
+eaa4074a7e3975cd33ec55e6b584586e2ac681bd jdk8u20-b26
 4828415ebbf11e205dcc08e97ad5ae7dd03522f9 jdk8u40-b00
 d952af8cf67dd1e7ab5fec9a299c6c6dafd1863e hs25.40-b01
 f0afba33c928ddaa2d5f003b90d683c143f78ea3 hs25.40-b02
@@ -513,3 +517,8 @@
 dc06b830ea95ed953cac02e9e67a75ab682edb97 jdk8u40-b01
 897333c7e5874625bd26d09fdaf242196024e9c2 hs25.40-b05
 c68ff41f6d5f9b43c3c07cff85584292065fb9da jdk8u40-b02
+fbc31318922c31488c0464ccd864d2cd1d9e21a7 hs25.40-b06
+38539608359a6dfc5740abb66f878af643757c3b jdk8u40-b03
+c3990b8c710e4c1996b5cd579681645d9f0408c1 hs25.40-b07
+3f1b3f2dd1cb224747a11a6788e58b5cb7683d57 hs25.40-b08
+fd4dbaff30027832dd21bcc7171ddb466ca2924f jdk8u40-b04
--- a/agent/src/share/classes/sun/jvm/hotspot/gc_implementation/g1/G1CollectedHeap.java	Thu Sep 04 13:06:04 2014 -0400
+++ b/agent/src/share/classes/sun/jvm/hotspot/gc_implementation/g1/G1CollectedHeap.java	Fri Sep 05 06:26:44 2014 -0400
@@ -45,8 +45,8 @@
 public class G1CollectedHeap extends SharedHeap {
     // HeapRegionSeq _seq;
     static private long hrsFieldOffset;
-    // MemRegion _g1_committed;
-    static private long g1CommittedFieldOffset;
+    // MemRegion _g1_reserved;
+    static private long g1ReservedFieldOffset;
     // size_t _summary_bytes_used;
     static private CIntegerField summaryBytesUsedField;
     // G1MonitoringSupport* _g1mm;
@@ -68,7 +68,6 @@
         Type type = db.lookupType("G1CollectedHeap");
 
         hrsFieldOffset = type.getField("_hrs").getOffset();
-        g1CommittedFieldOffset = type.getField("_g1_committed").getOffset();
         summaryBytesUsedField = type.getCIntegerField("_summary_bytes_used");
         g1mmField = type.getAddressField("_g1mm");
         oldSetFieldOffset = type.getField("_old_set").getOffset();
@@ -76,9 +75,7 @@
     }
 
     public long capacity() {
-        Address g1CommittedAddr = addr.addOffsetTo(g1CommittedFieldOffset);
-        MemRegion g1Committed = new MemRegion(g1CommittedAddr);
-        return g1Committed.byteSize();
+        return hrs().capacity();
     }
 
     public long used() {
--- a/agent/src/share/classes/sun/jvm/hotspot/gc_implementation/g1/G1HeapRegionTable.java	Thu Sep 04 13:06:04 2014 -0400
+++ b/agent/src/share/classes/sun/jvm/hotspot/gc_implementation/g1/G1HeapRegionTable.java	Fri Sep 05 06:26:44 2014 -0400
@@ -93,19 +93,35 @@
     private class HeapRegionIterator implements Iterator<HeapRegion> {
         private long index;
         private long length;
+        private HeapRegion next;
 
-        @Override
-        public boolean hasNext() { return index < length; }
+        public HeapRegion positionToNext() {
+          HeapRegion result = next;
+          while (index < length && at(index) == null) {
+            index++;
+          }
+          if (index < length) {
+            next = at(index);
+            index++; // restart search at next element
+          } else {
+            next = null;
+          }
+          return result;
+        }
 
         @Override
-        public HeapRegion next() { return at(index++);    }
+        public boolean hasNext() { return next != null;     }
+
+        @Override
+        public HeapRegion next() { return positionToNext(); }
 
         @Override
-        public void remove()     { /* not supported */    }
+        public void remove()     { /* not supported */      }
 
-        HeapRegionIterator(long committedLength) {
+        HeapRegionIterator(long totalLength) {
             index = 0;
-            length = committedLength;
+            length = totalLength;
+            positionToNext();
         }
     }
 
--- a/agent/src/share/classes/sun/jvm/hotspot/gc_implementation/g1/HeapRegionSeq.java	Thu Sep 04 13:06:04 2014 -0400
+++ b/agent/src/share/classes/sun/jvm/hotspot/gc_implementation/g1/HeapRegionSeq.java	Fri Sep 05 06:26:44 2014 -0400
@@ -43,7 +43,7 @@
     // G1HeapRegionTable _regions
     static private long regionsFieldOffset;
     // uint _committed_length
-    static private CIntegerField committedLengthField;
+    static private CIntegerField numCommittedField;
 
     static {
         VM.registerVMInitializedObserver(new Observer() {
@@ -57,7 +57,7 @@
         Type type = db.lookupType("HeapRegionSeq");
 
         regionsFieldOffset = type.getField("_regions").getOffset();
-        committedLengthField = type.getCIntegerField("_committed_length");
+        numCommittedField = type.getCIntegerField("_num_committed");
     }
 
     private G1HeapRegionTable regions() {
@@ -66,16 +66,20 @@
                                                              regionsAddr);
     }
 
+    public long capacity() {
+        return length() * HeapRegion.grainBytes();
+    }
+
     public long length() {
         return regions().length();
     }
 
     public long committedLength() {
-        return committedLengthField.getValue(addr);
+        return numCommittedField.getValue(addr);
     }
 
     public Iterator<HeapRegion> heapRegionIterator() {
-        return regions().heapRegionIterator(committedLength());
+        return regions().heapRegionIterator(length());
     }
 
     public HeapRegionSeq(Address addr) {
--- a/make/bsd/makefiles/vm.make	Thu Sep 04 13:06:04 2014 -0400
+++ b/make/bsd/makefiles/vm.make	Fri Sep 05 06:26:44 2014 -0400
@@ -243,10 +243,10 @@
 
 vm_version.o: $(filter-out vm_version.o,$(JVM_OBJ_FILES))
 
-mapfile : $(MAPFILE) vm.def
+mapfile : $(MAPFILE) vm.def mapfile_ext
 	rm -f $@
 	awk '{ if ($$0 ~ "INSERT VTABLE SYMBOLS HERE")	\
-                 { system ("cat vm.def"); }		\
+                 { system ("cat mapfile_ext"); system ("cat vm.def"); } \
                else					\
                  { print $$0 }				\
              }' > $@ < $(MAPFILE)
@@ -258,6 +258,13 @@
 vm.def: $(Res_Files) $(Obj_Files)
 	sh $(GAMMADIR)/make/bsd/makefiles/build_vm_def.sh *.o > $@
 
+mapfile_ext:
+	rm -f $@
+	touch $@
+	if [ -f $(HS_ALT_MAKE)/bsd/makefiles/mapfile-ext ]; then \
+	  cat $(HS_ALT_MAKE)/bsd/makefiles/mapfile-ext > $@; \
+	fi
+
 STATIC_CXX = false
 
 ifeq ($(LINK_INTO),AOUT)
--- a/make/excludeSrc.make	Thu Sep 04 13:06:04 2014 -0400
+++ b/make/excludeSrc.make	Fri Sep 05 06:26:44 2014 -0400
@@ -118,8 +118,8 @@
       CFLAGS += -DINCLUDE_NMT=0
 
       Src_Files_EXCLUDE += \
-	 memBaseline.cpp memPtr.cpp memRecorder.cpp memReporter.cpp memSnapshot.cpp memTrackWorker.cpp \
-	 memTracker.cpp nmtDCmd.cpp
+	 memBaseline.cpp memReporter.cpp mallocTracker.cpp virtualMemoryTracker.cpp nmtCommon.cpp \
+	 memTracker.cpp nmtDCmd.cpp mallocSiteTable.cpp
 endif
 
 -include $(HS_ALT_MAKE)/excludeSrc.make
--- a/make/hotspot_version	Thu Sep 04 13:06:04 2014 -0400
+++ b/make/hotspot_version	Fri Sep 05 06:26:44 2014 -0400
@@ -35,7 +35,7 @@
 
 HS_MAJOR_VER=25
 HS_MINOR_VER=40
-HS_BUILD_NUMBER=05
+HS_BUILD_NUMBER=08
 
 JDK_MAJOR_VER=1
 JDK_MINOR_VER=8
--- a/make/jprt.properties	Thu Sep 04 13:06:04 2014 -0400
+++ b/make/jprt.properties	Fri Sep 05 06:26:44 2014 -0400
@@ -33,7 +33,7 @@
 
 # This tells jprt what default release we want to build
 
-jprt.hotspot.default.release=jdk8u20
+jprt.hotspot.default.release=jdk8u40
 
 jprt.tools.default.release=${jprt.submit.option.release?${jprt.submit.option.release}:${jprt.hotspot.default.release}}
 
@@ -47,65 +47,65 @@
 #       sparc etc.
 
 # Define the Solaris platforms we want for the various releases
-jprt.my.solaris.sparcv9.jdk8u20=solaris_sparcv9_5.10
+jprt.my.solaris.sparcv9.jdk8u40=solaris_sparcv9_5.10
 jprt.my.solaris.sparcv9.jdk7=solaris_sparcv9_5.10
 jprt.my.solaris.sparcv9.jdk7u8=${jprt.my.solaris.sparcv9.jdk7}
 jprt.my.solaris.sparcv9=${jprt.my.solaris.sparcv9.${jprt.tools.default.release}}
 
-jprt.my.solaris.x64.jdk8u20=solaris_x64_5.10
+jprt.my.solaris.x64.jdk8u40=solaris_x64_5.10
 jprt.my.solaris.x64.jdk7=solaris_x64_5.10
 jprt.my.solaris.x64.jdk7u8=${jprt.my.solaris.x64.jdk7}
 jprt.my.solaris.x64=${jprt.my.solaris.x64.${jprt.tools.default.release}}
 
-jprt.my.linux.i586.jdk8u20=linux_i586_2.6
+jprt.my.linux.i586.jdk8u40=linux_i586_2.6
 jprt.my.linux.i586.jdk7=linux_i586_2.6
 jprt.my.linux.i586.jdk7u8=${jprt.my.linux.i586.jdk7}
 jprt.my.linux.i586=${jprt.my.linux.i586.${jprt.tools.default.release}}
 
-jprt.my.linux.x64.jdk8u20=linux_x64_2.6
+jprt.my.linux.x64.jdk8u40=linux_x64_2.6
 jprt.my.linux.x64.jdk7=linux_x64_2.6
 jprt.my.linux.x64.jdk7u8=${jprt.my.linux.x64.jdk7}
 jprt.my.linux.x64=${jprt.my.linux.x64.${jprt.tools.default.release}}
 
-jprt.my.linux.ppc.jdk8u20=linux_ppc_2.6
+jprt.my.linux.ppc.jdk8u40=linux_ppc_2.6
 jprt.my.linux.ppc.jdk7=linux_ppc_2.6
 jprt.my.linux.ppc.jdk7u8=${jprt.my.linux.ppc.jdk7}
 jprt.my.linux.ppc=${jprt.my.linux.ppc.${jprt.tools.default.release}}
 
-jprt.my.linux.ppcv2.jdk8u20=linux_ppcv2_2.6
+jprt.my.linux.ppcv2.jdk8u40=linux_ppcv2_2.6
 jprt.my.linux.ppcv2.jdk7=linux_ppcv2_2.6
 jprt.my.linux.ppcv2.jdk7u8=${jprt.my.linux.ppcv2.jdk7}
 jprt.my.linux.ppcv2=${jprt.my.linux.ppcv2.${jprt.tools.default.release}}
 
-jprt.my.linux.armvfpsflt.jdk8u20=linux_armvfpsflt_2.6
+jprt.my.linux.armvfpsflt.jdk8u40=linux_armvfpsflt_2.6
 jprt.my.linux.armvfpsflt=${jprt.my.linux.armvfpsflt.${jprt.tools.default.release}}
 
-jprt.my.linux.armvfphflt.jdk8u20=linux_armvfphflt_2.6
+jprt.my.linux.armvfphflt.jdk8u40=linux_armvfphflt_2.6
 jprt.my.linux.armvfphflt=${jprt.my.linux.armvfphflt.${jprt.tools.default.release}}
 
 # The ARM GP vfp-sflt build is not currently supported
-#jprt.my.linux.armvs.jdk8u20=linux_armvs_2.6
+#jprt.my.linux.armvs.jdk8u40=linux_armvs_2.6
 #jprt.my.linux.armvs=${jprt.my.linux.armvs.${jprt.tools.default.release}}
 
-jprt.my.linux.armvh.jdk8u20=linux_armvh_2.6
+jprt.my.linux.armvh.jdk8u40=linux_armvh_2.6
 jprt.my.linux.armvh=${jprt.my.linux.armvh.${jprt.tools.default.release}}
 
-jprt.my.linux.armsflt.jdk8u20=linux_armsflt_2.6
+jprt.my.linux.armsflt.jdk8u40=linux_armsflt_2.6
 jprt.my.linux.armsflt.jdk7=linux_armsflt_2.6
 jprt.my.linux.armsflt.jdk7u8=${jprt.my.linux.armsflt.jdk7}
 jprt.my.linux.armsflt=${jprt.my.linux.armsflt.${jprt.tools.default.release}}
 
-jprt.my.macosx.x64.jdk8u20=macosx_x64_10.7
+jprt.my.macosx.x64.jdk8u40=macosx_x64_10.7
 jprt.my.macosx.x64.jdk7=macosx_x64_10.7
 jprt.my.macosx.x64.jdk7u8=${jprt.my.macosx.x64.jdk7}
 jprt.my.macosx.x64=${jprt.my.macosx.x64.${jprt.tools.default.release}}
 
-jprt.my.windows.i586.jdk8u20=windows_i586_6.1
+jprt.my.windows.i586.jdk8u40=windows_i586_6.1
 jprt.my.windows.i586.jdk7=windows_i586_6.1
 jprt.my.windows.i586.jdk7u8=${jprt.my.windows.i586.jdk7}
 jprt.my.windows.i586=${jprt.my.windows.i586.${jprt.tools.default.release}}
 
-jprt.my.windows.x64.jdk8u20=windows_x64_6.1
+jprt.my.windows.x64.jdk8u40=windows_x64_6.1
 jprt.my.windows.x64.jdk7=windows_x64_6.1
 jprt.my.windows.x64.jdk7u8=${jprt.my.windows.x64.jdk7}
 jprt.my.windows.x64=${jprt.my.windows.x64.${jprt.tools.default.release}}
@@ -137,7 +137,7 @@
 jprt.build.targets.all=${jprt.build.targets.standard}, \
     ${jprt.build.targets.embedded}, ${jprt.build.targets.open}
 
-jprt.build.targets.jdk8u20=${jprt.build.targets.all}
+jprt.build.targets.jdk8u40=${jprt.build.targets.all}
 jprt.build.targets.jdk7=${jprt.build.targets.all}
 jprt.build.targets.jdk7u8=${jprt.build.targets.all}
 jprt.build.targets=${jprt.build.targets.${jprt.tools.default.release}}
@@ -343,7 +343,7 @@
   ${jprt.my.windows.i586.test.targets}, \
   ${jprt.my.windows.x64.test.targets}
 
-jprt.test.targets.jdk8u20=${jprt.test.targets.standard}
+jprt.test.targets.jdk8u40=${jprt.test.targets.standard}
 jprt.test.targets.jdk7=${jprt.test.targets.standard}
 jprt.test.targets.jdk7u8=${jprt.test.targets.jdk7}
 jprt.test.targets=${jprt.test.targets.${jprt.tools.default.release}}
@@ -393,7 +393,7 @@
 jprt.make.rule.test.targets.embedded = \
   ${jprt.make.rule.test.targets.standard.client}
 
-jprt.make.rule.test.targets.jdk8u20=${jprt.make.rule.test.targets.standard}
+jprt.make.rule.test.targets.jdk8u40=${jprt.make.rule.test.targets.standard}
 jprt.make.rule.test.targets.jdk7=${jprt.make.rule.test.targets.standard}
 jprt.make.rule.test.targets.jdk7u8=${jprt.make.rule.test.targets.jdk7}
 jprt.make.rule.test.targets=${jprt.make.rule.test.targets.${jprt.tools.default.release}}
--- a/make/linux/makefiles/vm.make	Thu Sep 04 13:06:04 2014 -0400
+++ b/make/linux/makefiles/vm.make	Fri Sep 05 06:26:44 2014 -0400
@@ -247,10 +247,10 @@
 # it also needs to provide an extra JVM API method for target JDK 7
 ifeq ($(BUILTIN_SIM), true)
   ifeq ($(JDK_MINOR_VERSION),7)
-mapfile : $(MAPFILE) vm.def
+mapfile : $(MAPFILE) vm.def mapfile_ext
 	rm -f $@
 	awk '{ if ($$0 ~ "INSERT VTABLE SYMBOLS HERE")	\
-                 { system ("cat vm.def");		\
+                 { system ("cat mapfile_ext"); system ("cat vm.def");		\
                    print "	# jdk7 support";	\
                    print "      JVM_SetProtectionDomain;"; \
                    print "	# aarch64 sim support";	\
@@ -260,10 +260,10 @@
                  { print $$0 }				\
              }' > $@ < $(MAPFILE)
   else
-mapfile : $(MAPFILE) vm.def
+mapfile : $(MAPFILE) vm.def mapfile_ext
 	rm -f $@
 	awk '{ if ($$0 ~ "INSERT VTABLE SYMBOLS HERE")	\
-                 { system ("cat vm.def");		\
+                 { system ("cat mapfile_ext"); system ("cat vm.def");		\
                    print "	# aarch64 sim support";	\
                    print "	das1;";			\
                    print "	bccheck;"; }		\
@@ -273,20 +273,20 @@
   endif
 else
   ifeq ($(JDK_MINOR_VERSION),7)
-mapfile : $(MAPFILE) vm.def
+mapfile : $(MAPFILE) vm.def mapfile_ext
 	rm -f $@
 	awk '{ if ($$0 ~ "INSERT VTABLE SYMBOLS HERE")	\
-                 { system ("cat vm.def");		\
+                 { system ("cat mapfile_ext"); system ("cat vm.def");		\
                    print "	# jdk7 support";	\
                    print "      JVM_SetProtectionDomain;"; } \
                else					\
                  { print $$0 }				\
              }' > $@ < $(MAPFILE)
   else
-mapfile : $(MAPFILE) vm.def
+mapfile : $(MAPFILE) vm.def mapfile_ext
 	rm -f $@
 	awk '{ if ($$0 ~ "INSERT VTABLE SYMBOLS HERE")	\
-                 { system ("cat vm.def"); }             \
+                 { system ("cat mapfile_ext"); system ("cat vm.def"); }             \
                else					\
                  { print $$0 }				\
              }' > $@ < $(MAPFILE)
@@ -300,6 +300,13 @@
 vm.def: $(Res_Files) $(Obj_Files)
 	sh $(GAMMADIR)/make/linux/makefiles/build_vm_def.sh *.o > $@
 
+mapfile_ext:
+	rm -f $@
+	touch $@
+	if [ -f $(HS_ALT_MAKE)/linux/makefiles/mapfile-ext ]; then \
+	  cat $(HS_ALT_MAKE)/linux/makefiles/mapfile-ext > $@; \
+	fi
+
 ifeq ($(JVM_VARIANT_ZEROSHARK), true)
   STATIC_CXX = false
 else
--- a/make/solaris/Makefile	Thu Sep 04 13:06:04 2014 -0400
+++ b/make/solaris/Makefile	Fri Sep 05 06:26:44 2014 -0400
@@ -159,6 +159,7 @@
 BUILDTREE_VARS    = GAMMADIR=$(GAMMADIR) OS_FAMILY=$(OSNAME) ARCH=$(SRCARCH) BUILDARCH=$(BUILDARCH) LIBARCH=$(LIBARCH)
 BUILDTREE_VARS   += HOTSPOT_RELEASE_VERSION=$(HOTSPOT_RELEASE_VERSION) HOTSPOT_BUILD_VERSION=$(HOTSPOT_BUILD_VERSION) JRE_RELEASE_VERSION=$(JRE_RELEASE_VERSION)
 BUILDTREE_VARS   += ENABLE_FULL_DEBUG_SYMBOLS=$(ENABLE_FULL_DEBUG_SYMBOLS) OBJCOPY=$(OBJCOPY) STRIP_POLICY=$(STRIP_POLICY) ZIP_DEBUGINFO_FILES=$(ZIP_DEBUGINFO_FILES) ZIPEXE=$(ZIPEXE)
+BUILDTREE_VARS   += HS_ALT_MAKE=$(HS_ALT_MAKE)
 
 BUILDTREE         = $(MAKE) -f $(BUILDTREE_MAKE) $(BUILDTREE_VARS)
 
--- a/make/solaris/makefiles/buildtree.make	Thu Sep 04 13:06:04 2014 -0400
+++ b/make/solaris/makefiles/buildtree.make	Fri Sep 05 06:26:44 2014 -0400
@@ -258,6 +258,8 @@
 	    echo && echo "ZIP_DEBUGINFO_FILES = $(ZIP_DEBUGINFO_FILES)"; \
 	[ -n "$(ZIPEXE)" ] && \
 	    echo && echo "ZIPEXE = $(ZIPEXE)"; \
+	[ -n "$(HS_ALT_MAKE)" ] && \
+	    echo && echo "HS_ALT_MAKE = $(HS_ALT_MAKE)"; \
 	[ -n "$(HOTSPOT_EXTRA_SYSDEFS)" ] && \
 	    echo && \
 	    echo "HOTSPOT_EXTRA_SYSDEFS\$$(HOTSPOT_EXTRA_SYSDEFS) = $(HOTSPOT_EXTRA_SYSDEFS)" && \
--- a/make/solaris/makefiles/vm.make	Thu Sep 04 13:06:04 2014 -0400
+++ b/make/solaris/makefiles/vm.make	Fri Sep 05 06:26:44 2014 -0400
@@ -247,11 +247,12 @@
 
 vm_version.o: $(filter-out vm_version.o,$(JVM_OBJ_FILES))
 
-mapfile : $(MAPFILE) $(MAPFILE_DTRACE_OPT) vm.def
+mapfile : $(MAPFILE) $(MAPFILE_DTRACE_OPT) vm.def mapfile_ext
 	rm -f $@
 	cat $(MAPFILE) $(MAPFILE_DTRACE_OPT) \
 	    | $(NAWK) '{                                         \
 	              if ($$0 ~ "INSERT VTABLE SYMBOLS HERE") {  \
+	                  system ("cat mapfile_ext");            \
 	                  system ("cat vm.def");                 \
 	              } else {                                   \
 	                  print $$0;                             \
@@ -265,6 +266,13 @@
 vm.def: $(Obj_Files)
 	sh $(GAMMADIR)/make/solaris/makefiles/build_vm_def.sh *.o > $@
 
+mapfile_ext:
+	rm -f $@
+	touch $@
+	if [ -f $(HS_ALT_MAKE)/solaris/makefiles/mapfile-ext ]; then \
+	  cat $(HS_ALT_MAKE)/solaris/makefiles/mapfile-ext > $@; \
+	fi
+
 ifeq ($(LINK_INTO),AOUT)
   LIBJVM.o                 =
   LIBJVM_MAPFILE           =
--- a/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -872,21 +872,19 @@
 
 
 void LIRGenerator::do_NewInstance(NewInstance* x) {
+  print_if_not_loaded(x);
+
   // This instruction can be deoptimized in the slow path : use
   // O0 as result register.
   const LIR_Opr reg = result_register_for(x->type());
-#ifndef PRODUCT
-  if (PrintNotLoaded && !x->klass()->is_loaded()) {
-    tty->print_cr("   ###class not loaded at new bci %d", x->printable_bci());
-  }
-#endif
+
   CodeEmitInfo* info = state_for(x, x->state());
   LIR_Opr tmp1 = FrameMap::G1_oop_opr;
   LIR_Opr tmp2 = FrameMap::G3_oop_opr;
   LIR_Opr tmp3 = FrameMap::G4_oop_opr;
   LIR_Opr tmp4 = FrameMap::O1_oop_opr;
   LIR_Opr klass_reg = FrameMap::G5_metadata_opr;
-  new_instance(reg, x->klass(), tmp1, tmp2, tmp3, tmp4, klass_reg, info);
+  new_instance(reg, x->klass(), x->is_unresolved(), tmp1, tmp2, tmp3, tmp4, klass_reg, info);
   LIR_Opr result = rlock_result(x);
   __ move(reg, result);
 }
--- a/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -1085,14 +1085,11 @@
 
 
 void LIRGenerator::do_NewInstance(NewInstance* x) {
-#ifndef PRODUCT
-  if (PrintNotLoaded && !x->klass()->is_loaded()) {
-    tty->print_cr("   ###class not loaded at new bci %d", x->printable_bci());
-  }
-#endif
+  print_if_not_loaded(x);
+
   CodeEmitInfo* info = state_for(x, x->state());
   LIR_Opr reg = result_register_for(x->type());
-  new_instance(reg, x->klass(),
+  new_instance(reg, x->klass(), x->is_unresolved(),
                        FrameMap::rcx_oop_opr,
                        FrameMap::rdi_oop_opr,
                        FrameMap::rsi_oop_opr,
--- a/src/os/bsd/vm/os_bsd.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/os/bsd/vm/os_bsd.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -2434,23 +2434,25 @@
   }
 
   // The memory is committed
-  MemTracker::record_virtual_memory_reserve_and_commit((address)addr, bytes, mtNone, CALLER_PC);
+  MemTracker::record_virtual_memory_reserve_and_commit((address)addr, bytes, CALLER_PC);
 
   return addr;
 }
 
 bool os::release_memory_special(char* base, size_t bytes) {
-  MemTracker::Tracker tkr = MemTracker::get_virtual_memory_release_tracker();
-  // detaching the SHM segment will also delete it, see reserve_memory_special()
-  int rslt = shmdt(base);
-  if (rslt == 0) {
-    tkr.record((address)base, bytes);
-    return true;
+  if (MemTracker::tracking_level() > NMT_minimal) {
+    Tracker tkr = MemTracker::get_virtual_memory_release_tracker();
+    // detaching the SHM segment will also delete it, see reserve_memory_special()
+    int rslt = shmdt(base);
+    if (rslt == 0) {
+      tkr.record((address)base, bytes);
+      return true;
+    } else {
+      return false;
+    }
   } else {
-    tkr.discard();
-    return false;
+    return shmdt(base) == 0;
   }
-
 }
 
 size_t os::large_page_size() {
--- a/src/os/bsd/vm/perfMemory_bsd.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/os/bsd/vm/perfMemory_bsd.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -753,7 +753,7 @@
   (void)::memset((void*) mapAddress, 0, size);
 
   // it does not go through os api, the operation has to record from here
-  MemTracker::record_virtual_memory_reserve((address)mapAddress, size, mtInternal, CURRENT_PC);
+  MemTracker::record_virtual_memory_reserve_and_commit((address)mapAddress, size, CURRENT_PC, mtInternal);
 
   return mapAddress;
 }
@@ -918,7 +918,7 @@
   }
 
   // it does not go through os api, the operation has to record from here
-  MemTracker::record_virtual_memory_reserve((address)mapAddress, size, mtInternal, CURRENT_PC);
+  MemTracker::record_virtual_memory_reserve_and_commit((address)mapAddress, size, CURRENT_PC, mtInternal);
 
   *addr = mapAddress;
   *sizep = size;
--- a/src/os/linux/vm/os_linux.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/os/linux/vm/os_linux.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -3516,9 +3516,12 @@
 
   assert(is_ptr_aligned(start, alignment), "Must be");
 
-  // os::reserve_memory_special will record this memory area.
-  // Need to release it here to prevent overlapping reservations.
-  MemTracker::record_virtual_memory_release((address)start, bytes);
+  if (MemTracker::tracking_level() > NMT_minimal) {
+    // os::reserve_memory_special will record this memory area.
+    // Need to release it here to prevent overlapping reservations.
+    Tracker tkr = MemTracker::get_virtual_memory_release_tracker();
+    tkr.record((address)start, bytes);
+  }
 
   char* end = start + bytes;
 
@@ -3613,7 +3616,7 @@
     }
 
     // The memory is committed
-    MemTracker::record_virtual_memory_reserve_and_commit((address)addr, bytes, mtNone, CALLER_PC);
+    MemTracker::record_virtual_memory_reserve_and_commit((address)addr, bytes, CALLER_PC);
   }
 
   return addr;
@@ -3629,24 +3632,30 @@
 }
 
 bool os::release_memory_special(char* base, size_t bytes) {
+  bool res;
+  if (MemTracker::tracking_level() > NMT_minimal) {
+    Tracker tkr = MemTracker::get_virtual_memory_release_tracker();
+    res = os::Linux::release_memory_special_impl(base, bytes);
+    if (res) {
+      tkr.record((address)base, bytes);
+    }
+
+  } else {
+    res = os::Linux::release_memory_special_impl(base, bytes);
+  }
+  return res;
+}
+
+bool os::Linux::release_memory_special_impl(char* base, size_t bytes) {
   assert(UseLargePages, "only for large pages");
-
-  MemTracker::Tracker tkr = MemTracker::get_virtual_memory_release_tracker();
-
   bool res;
+
   if (UseSHM) {
     res = os::Linux::release_memory_special_shm(base, bytes);
   } else {
     assert(UseHugeTLBFS, "must be");
     res = os::Linux::release_memory_special_huge_tlbfs(base, bytes);
   }
-
-  if (res) {
-    tkr.record((address)base, bytes);
-  } else {
-    tkr.discard();
-  }
-
   return res;
 }
 
--- a/src/os/linux/vm/os_linux.hpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/os/linux/vm/os_linux.hpp	Fri Sep 05 06:26:44 2014 -0400
@@ -108,6 +108,7 @@
   static char* reserve_memory_special_huge_tlbfs_only(size_t bytes, char* req_addr, bool exec);
   static char* reserve_memory_special_huge_tlbfs_mixed(size_t bytes, size_t alignment, char* req_addr, bool exec);
 
+  static bool release_memory_special_impl(char* base, size_t bytes);
   static bool release_memory_special_shm(char* base, size_t bytes);
   static bool release_memory_special_huge_tlbfs(char* base, size_t bytes);
 
--- a/src/os/linux/vm/perfMemory_linux.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/os/linux/vm/perfMemory_linux.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -753,7 +753,7 @@
   (void)::memset((void*) mapAddress, 0, size);
 
   // it does not go through os api, the operation has to record from here
-  MemTracker::record_virtual_memory_reserve((address)mapAddress, size, mtInternal, CURRENT_PC);
+  MemTracker::record_virtual_memory_reserve_and_commit((address)mapAddress, size, CURRENT_PC, mtInternal);
 
   return mapAddress;
 }
@@ -924,7 +924,7 @@
   }
 
   // it does not go through os api, the operation has to record from here
-  MemTracker::record_virtual_memory_reserve((address)mapAddress, size, mtInternal, CURRENT_PC);
+  MemTracker::record_virtual_memory_reserve_and_commit((address)mapAddress, size, CURRENT_PC, mtInternal);
 
   *addr = mapAddress;
   *sizep = size;
--- a/src/os/posix/vm/os_posix.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/os/posix/vm/os_posix.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -74,21 +74,41 @@
   VMError::report_coredump_status(buffer, success);
 }
 
-address os::get_caller_pc(int n) {
+int os::get_native_stack(address* stack, int frames, int toSkip) {
 #ifdef _NMT_NOINLINE_
-  n ++;
+  toSkip++;
 #endif
+
+  int frame_idx = 0;
+  int num_of_frames;  // number of frames captured
   frame fr = os::current_frame();
-  while (n > 0 && fr.pc() &&
-    !os::is_first_C_frame(&fr) && fr.sender_pc()) {
-    fr = os::get_sender_for_C_frame(&fr);
-    n --;
+  while (fr.pc() && frame_idx < frames) {
+    if (toSkip > 0) {
+      toSkip --;
+    } else {
+      stack[frame_idx ++] = fr.pc();
+    }
+    if (fr.fp() == NULL || os::is_first_C_frame(&fr)
+        ||fr.sender_pc() == NULL || fr.cb() != NULL) break;
+
+    if (fr.sender_pc() && !os::is_first_C_frame(&fr)) {
+      fr = os::get_sender_for_C_frame(&fr);
+    } else {
+      break;
+    }
   }
-  if (n == 0) {
-    return fr.pc();
-  } else {
-    return NULL;
+  num_of_frames = frame_idx;
+  for (; frame_idx < frames; frame_idx ++) {
+    stack[frame_idx] = NULL;
   }
+
+  return num_of_frames;
+}
+
+
+bool os::unsetenv(const char* name) {
+  assert(name != NULL, "Null pointer");
+  return (::unsetenv(name) == 0);
 }
 
 int os::get_last_error() {
--- a/src/os/solaris/vm/perfMemory_solaris.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/os/solaris/vm/perfMemory_solaris.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -770,7 +770,8 @@
   (void)::memset((void*) mapAddress, 0, size);
 
   // it does not go through os api, the operation has to record from here
-  MemTracker::record_virtual_memory_reserve((address)mapAddress, size, mtInternal, CURRENT_PC);
+  MemTracker::record_virtual_memory_reserve_and_commit((address)mapAddress,
+    size, CURRENT_PC, mtInternal);
 
   return mapAddress;
 }
@@ -941,7 +942,8 @@
   }
 
   // it does not go through os api, the operation has to record from here
-  MemTracker::record_virtual_memory_reserve((address)mapAddress, size, mtInternal, CURRENT_PC);
+  MemTracker::record_virtual_memory_reserve_and_commit((address)mapAddress,
+    size, CURRENT_PC, mtInternal);
 
   *addr = mapAddress;
   *sizep = size;
--- a/src/os/windows/vm/os_windows.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/os/windows/vm/os_windows.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -131,6 +131,7 @@
     case DLL_PROCESS_DETACH:
       if(ForceTimeHighResolution)
         timeEndPeriod(1L);
+
       break;
     default:
       break;
@@ -153,6 +154,10 @@
  return result > 0 && result < len;
 }
 
+bool os::unsetenv(const char* name) {
+  assert(name != NULL, "Null pointer");
+  return (SetEnvironmentVariable(name, NULL) == TRUE);
+}
 
 // No setuid programs under Windows.
 bool os::have_special_privileges() {
@@ -311,15 +316,17 @@
  * So far, this method is only used by Native Memory Tracking, which is
  * only supported on Windows XP or later.
  */
-address os::get_caller_pc(int n) {
+
+int os::get_native_stack(address* stack, int frames, int toSkip) {
 #ifdef _NMT_NOINLINE_
-  n ++;
+  toSkip ++;
 #endif
-  address pc;
-  if (os::Kernel32Dll::RtlCaptureStackBackTrace(n + 1, 1, (PVOID*)&pc, NULL) == 1) {
-    return pc;
-  }
-  return NULL;
+  int captured = Kernel32Dll::RtlCaptureStackBackTrace(toSkip + 1, frames,
+    (PVOID*)stack, NULL);
+  for (int index = captured; index < frames; index ++) {
+    stack[index] = NULL;
+  }
+  return captured;
 }
 
 
@@ -2904,7 +2911,7 @@
                                 PAGE_READWRITE);
   // If reservation failed, return NULL
   if (p_buf == NULL) return NULL;
-  MemTracker::record_virtual_memory_reserve((address)p_buf, size_of_reserve, mtNone, CALLER_PC);
+  MemTracker::record_virtual_memory_reserve((address)p_buf, size_of_reserve, CALLER_PC);
   os::release_memory(p_buf, bytes + chunk_size);
 
   // we still need to round up to a page boundary (in case we are using large pages)
@@ -2970,7 +2977,7 @@
         // need to create a dummy 'reserve' record to match
         // the release.
         MemTracker::record_virtual_memory_reserve((address)p_buf,
-          bytes_to_release, mtNone, CALLER_PC);
+          bytes_to_release, CALLER_PC);
         os::release_memory(p_buf, bytes_to_release);
       }
 #ifdef ASSERT
@@ -2989,11 +2996,10 @@
   }
   // Although the memory is allocated individually, it is returned as one.
   // NMT records it as one block.
-  address pc = CALLER_PC;
   if ((flags & MEM_COMMIT) != 0) {
-    MemTracker::record_virtual_memory_reserve_and_commit((address)p_buf, bytes, mtNone, pc);
+    MemTracker::record_virtual_memory_reserve_and_commit((address)p_buf, bytes, CALLER_PC);
   } else {
-    MemTracker::record_virtual_memory_reserve((address)p_buf, bytes, mtNone, pc);
+    MemTracker::record_virtual_memory_reserve((address)p_buf, bytes, CALLER_PC);
   }
 
   // made it this far, success
@@ -3191,8 +3197,7 @@
     DWORD flag = MEM_RESERVE | MEM_COMMIT | MEM_LARGE_PAGES;
     char * res = (char *)VirtualAlloc(addr, bytes, flag, prot);
     if (res != NULL) {
-      address pc = CALLER_PC;
-      MemTracker::record_virtual_memory_reserve_and_commit((address)res, bytes, mtNone, pc);
+      MemTracker::record_virtual_memory_reserve_and_commit((address)res, bytes, CALLER_PC);
     }
 
     return res;
--- a/src/os/windows/vm/perfMemory_windows.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/os/windows/vm/perfMemory_windows.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -1498,7 +1498,8 @@
   (void)memset(mapAddress, '\0', size);
 
   // it does not go through os api, the operation has to record from here
-  MemTracker::record_virtual_memory_reserve((address)mapAddress, size, mtInternal, CURRENT_PC);
+  MemTracker::record_virtual_memory_reserve_and_commit((address)mapAddress,
+    size, CURRENT_PC, mtInternal);
 
   return (char*) mapAddress;
 }
@@ -1680,7 +1681,8 @@
   }
 
   // it does not go through os api, the operation has to record from here
-  MemTracker::record_virtual_memory_reserve((address)mapAddress, size, mtInternal, CURRENT_PC);
+  MemTracker::record_virtual_memory_reserve_and_commit((address)mapAddress, size,
+    CURRENT_PC, mtInternal);
 
 
   *addrp = (char*)mapAddress;
@@ -1834,10 +1836,14 @@
     return;
   }
 
-  MemTracker::Tracker tkr = MemTracker::get_virtual_memory_release_tracker();
-  remove_file_mapping(addr);
-  // it does not go through os api, the operation has to record from here
-  tkr.record((address)addr, bytes);
+  if (MemTracker::tracking_level() > NMT_minimal) {
+    // it does not go through os api, the operation has to record from here
+    Tracker tkr = MemTracker::get_virtual_memory_release_tracker();
+    remove_file_mapping(addr);
+    tkr.record((address)addr, bytes);
+  } else {
+    remove_file_mapping(addr);
+  }
 }
 
 char* PerfMemory::backing_store_filename() {
--- a/src/share/vm/asm/codeBuffer.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/asm/codeBuffer.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -268,7 +268,7 @@
 
 GrowableArray<int>* CodeBuffer::create_patch_overflow() {
   if (_overflow_arena == NULL) {
-    _overflow_arena = new (mtCode) Arena();
+    _overflow_arena = new (mtCode) Arena(mtCode);
   }
   return new (_overflow_arena) GrowableArray<int>(_overflow_arena, 8, 0, 0);
 }
--- a/src/share/vm/c1/c1_Compiler.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/c1/c1_Compiler.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -47,7 +47,7 @@
 
 void Compiler::init_c1_runtime() {
   BufferBlob* buffer_blob = CompilerThread::current()->get_buffer_blob();
-  Arena* arena = new (mtCompiler) Arena();
+  Arena* arena = new (mtCompiler) Arena(mtCompiler);
   Runtime1::initialize(buffer_blob);
   FrameMap::initialize();
   // initialize data structures
--- a/src/share/vm/c1/c1_GraphBuilder.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/c1/c1_GraphBuilder.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -2061,7 +2061,7 @@
   bool will_link;
   ciKlass* klass = stream()->get_klass(will_link);
   assert(klass->is_instance_klass(), "must be an instance klass");
-  NewInstance* new_instance = new NewInstance(klass->as_instance_klass(), state_before);
+  NewInstance* new_instance = new NewInstance(klass->as_instance_klass(), state_before, stream()->is_unresolved_klass());
   _memory->new_instance(new_instance);
   apush(append_split(new_instance));
 }
--- a/src/share/vm/c1/c1_Instruction.hpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/c1/c1_Instruction.hpp	Fri Sep 05 06:26:44 2014 -0400
@@ -1291,16 +1291,18 @@
 LEAF(NewInstance, StateSplit)
  private:
   ciInstanceKlass* _klass;
+  bool _is_unresolved;
 
  public:
   // creation
-  NewInstance(ciInstanceKlass* klass, ValueStack* state_before)
+  NewInstance(ciInstanceKlass* klass, ValueStack* state_before, bool is_unresolved)
   : StateSplit(instanceType, state_before)
-  , _klass(klass)
+  , _klass(klass), _is_unresolved(is_unresolved)
   {}
 
   // accessors
   ciInstanceKlass* klass() const                 { return _klass; }
+  bool is_unresolved() const                     { return _is_unresolved; }
 
   virtual bool needs_exception_state() const     { return false; }
 
--- a/src/share/vm/c1/c1_LIRGenerator.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/c1/c1_LIRGenerator.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -466,8 +466,11 @@
 }
 
 
-void LIRGenerator::klass2reg_with_patching(LIR_Opr r, ciMetadata* obj, CodeEmitInfo* info) {
-  if (!obj->is_loaded() || PatchALot) {
+void LIRGenerator::klass2reg_with_patching(LIR_Opr r, ciMetadata* obj, CodeEmitInfo* info, bool need_resolve) {
+  /* C2 relies on constant pool entries being resolved (ciTypeFlow), so if TieredCompilation
+   * is active and the class hasn't yet been resolved we need to emit a patch that resolves
+   * the class. */
+  if ((TieredCompilation && need_resolve) || !obj->is_loaded() || PatchALot) {
     assert(info != NULL, "info must be set if class is not loaded");
     __ klass2reg_patch(NULL, r, info);
   } else {
@@ -660,9 +663,18 @@
   __ unlock_object(hdr, object, lock, scratch, slow_path);
 }
 
-
-void LIRGenerator::new_instance(LIR_Opr dst, ciInstanceKlass* klass, LIR_Opr scratch1, LIR_Opr scratch2, LIR_Opr scratch3, LIR_Opr scratch4, LIR_Opr klass_reg, CodeEmitInfo* info) {
-  klass2reg_with_patching(klass_reg, klass, info);
+#ifndef PRODUCT
+void LIRGenerator::print_if_not_loaded(const NewInstance* new_instance) {
+  if (PrintNotLoaded && !new_instance->klass()->is_loaded()) {
+    tty->print_cr("   ###class not loaded at new bci %d", new_instance->printable_bci());
+  } else if (PrintNotLoaded && (TieredCompilation && new_instance->is_unresolved())) {
+    tty->print_cr("   ###class not resolved at new bci %d", new_instance->printable_bci());
+  }
+}
+#endif
+
+void LIRGenerator::new_instance(LIR_Opr dst, ciInstanceKlass* klass, bool is_unresolved, LIR_Opr scratch1, LIR_Opr scratch2, LIR_Opr scratch3, LIR_Opr scratch4, LIR_Opr klass_reg, CodeEmitInfo* info) {
+  klass2reg_with_patching(klass_reg, klass, info, is_unresolved);
   // If klass is not loaded we do not know if the klass has finalizers:
   if (UseFastNewInstance && klass->is_loaded()
       && !Klass::layout_helper_needs_slow_path(klass->layout_helper())) {
--- a/src/share/vm/c1/c1_LIRGenerator.hpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/c1/c1_LIRGenerator.hpp	Fri Sep 05 06:26:44 2014 -0400
@@ -169,6 +169,8 @@
     return this;
   }
 
+  void print_if_not_loaded(const NewInstance* new_instance) PRODUCT_RETURN;
+
 #ifdef ASSERT
   LIR_List* lir(const char * file, int line) const {
     _lir->set_file_and_line(file, line);
@@ -307,7 +309,7 @@
 
   void store_stack_parameter (LIR_Opr opr, ByteSize offset_from_sp_in_bytes);
 
-  void klass2reg_with_patching(LIR_Opr r, ciMetadata* obj, CodeEmitInfo* info);
+  void klass2reg_with_patching(LIR_Opr r, ciMetadata* obj, CodeEmitInfo* info, bool need_resolve = false);
 
   // this loads the length and compares against the index
   void array_range_check          (LIR_Opr array, LIR_Opr index, CodeEmitInfo* null_check_info, CodeEmitInfo* range_check_info);
@@ -325,7 +327,7 @@
   void monitor_enter (LIR_Opr object, LIR_Opr lock, LIR_Opr hdr, LIR_Opr scratch, int monitor_no, CodeEmitInfo* info_for_exception, CodeEmitInfo* info);
   void monitor_exit  (LIR_Opr object, LIR_Opr lock, LIR_Opr hdr, LIR_Opr scratch, int monitor_no);
 
-  void new_instance    (LIR_Opr  dst, ciInstanceKlass* klass, LIR_Opr  scratch1, LIR_Opr  scratch2, LIR_Opr  scratch3,  LIR_Opr scratch4, LIR_Opr  klass_reg, CodeEmitInfo* info);
+  void new_instance    (LIR_Opr  dst, ciInstanceKlass* klass, bool is_unresolved, LIR_Opr  scratch1, LIR_Opr  scratch2, LIR_Opr  scratch3,  LIR_Opr scratch4, LIR_Opr  klass_reg, CodeEmitInfo* info);
 
   // machine dependent
   void cmp_mem_int(LIR_Condition condition, LIR_Opr base, int disp, int c, CodeEmitInfo* info);
--- a/src/share/vm/ci/ciEnv.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/ci/ciEnv.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -86,7 +86,8 @@
 
 // ------------------------------------------------------------------
 // ciEnv::ciEnv
-ciEnv::ciEnv(CompileTask* task, int system_dictionary_modification_counter) {
+ciEnv::ciEnv(CompileTask* task, int system_dictionary_modification_counter)
+  : _ciEnv_arena(mtCompiler) {
   VM_ENTRY_MARK;
 
   // Set up ciEnv::current immediately, for the sake of ciObjectFactory, etc.
@@ -139,7 +140,7 @@
   _the_min_jint_string = NULL;
 }
 
-ciEnv::ciEnv(Arena* arena) {
+ciEnv::ciEnv(Arena* arena) : _ciEnv_arena(mtCompiler) {
   ASSERT_IN_VM;
 
   // Set up ciEnv::current immediately, for the sake of ciObjectFactory, etc.
--- a/src/share/vm/ci/ciObjectFactory.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/ci/ciObjectFactory.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 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
@@ -112,7 +112,7 @@
   // This Arena is long lived and exists in the resource mark of the
   // compiler thread that initializes the initial ciObjectFactory which
   // creates the shared ciObjects that all later ciObjectFactories use.
-  Arena* arena = new (mtCompiler) Arena();
+  Arena* arena = new (mtCompiler) Arena(mtCompiler);
   ciEnv initial(arena);
   ciEnv* env = ciEnv::current();
   env->_factory->init_shared_objects();
--- a/src/share/vm/classfile/classFileParser.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/classfile/classFileParser.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -2780,7 +2780,7 @@
   ClassFileStream* cfs = stream();
   u1* current_start = cfs->current();
 
-  guarantee_property(attribute_byte_length > sizeof(u2),
+  guarantee_property(attribute_byte_length >= sizeof(u2),
                      "Invalid BootstrapMethods attribute length %u in class file %s",
                      attribute_byte_length,
                      CHECK);
@@ -2793,11 +2793,6 @@
                      "Short length on BootstrapMethods in class file %s",
                      CHECK);
 
-  guarantee_property(attribute_byte_length >= sizeof(u2),
-                     "Invalid BootstrapMethods attribute length %u in class file %s",
-                     attribute_byte_length,
-                     CHECK);
-
   // The attribute contains a counted array of counted tuples of shorts,
   // represending bootstrap specifiers:
   //    length*{bootstrap_method_index, argument_count*{argument_index}}
--- a/src/share/vm/classfile/dictionary.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/classfile/dictionary.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -130,15 +130,13 @@
 }
 
 
-bool Dictionary::do_unloading() {
+void Dictionary::do_unloading() {
   assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
-  bool class_was_unloaded = false;
-  int  index = 0; // Defined here for portability! Do not move
 
   // Remove unloadable entries and classes from system dictionary
   // The placeholder array has been handled in always_strong_oops_do.
   DictionaryEntry* probe = NULL;
-  for (index = 0; index < table_size(); index++) {
+  for (int index = 0; index < table_size(); index++) {
     for (DictionaryEntry** p = bucket_addr(index); *p != NULL; ) {
       probe = *p;
       Klass* e = probe->klass();
@@ -158,16 +156,8 @@
         // Do we need to delete this system dictionary entry?
         if (loader_data->is_unloading()) {
           // If the loader is not live this entry should always be
-          // removed (will never be looked up again). Note that this is
-          // not the same as unloading the referred class.
-          if (k_def_class_loader_data == loader_data) {
-            // This is the defining entry, so the referred class is about
-            // to be unloaded.
-            class_was_unloaded = true;
-          }
-          // Also remove this system dictionary entry.
+          // removed (will never be looked up again).
           purge_entry = true;
-
         } else {
           // The loader in this entry is alive. If the klass is dead,
           // (determined by checking the defining class loader)
@@ -196,7 +186,6 @@
       p = probe->next_addr();
     }
   }
-  return class_was_unloaded;
 }
 
 void Dictionary::roots_oops_do(OopClosure* strong, OopClosure* weak) {
--- a/src/share/vm/classfile/dictionary.hpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/classfile/dictionary.hpp	Fri Sep 05 06:26:44 2014 -0400
@@ -108,9 +108,8 @@
     return (loader_data->is_the_null_class_loader_data() || !ClassUnloading);
   }
 
-  // Unload (that is, break root links to) all unmarked classes and
-  // loaders.  Returns "true" iff something was unloaded.
-  bool do_unloading();
+  // Unload (that is, break root links to) all unmarked classes and loaders.
+  void do_unloading();
 
   // Protection domains
   Klass* find(int index, unsigned int hash, Symbol* name,
--- a/src/share/vm/classfile/symbolTable.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/classfile/symbolTable.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -74,9 +74,9 @@
 void SymbolTable::initialize_symbols(int arena_alloc_size) {
   // Initialize the arena for global symbols, size passed in depends on CDS.
   if (arena_alloc_size == 0) {
-    _arena = new (mtSymbol) Arena();
+    _arena = new (mtSymbol) Arena(mtSymbol);
   } else {
-    _arena = new (mtSymbol) Arena(arena_alloc_size);
+    _arena = new (mtSymbol) Arena(mtSymbol, arena_alloc_size);
   }
 }
 
--- a/src/share/vm/classfile/systemDictionary.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/classfile/systemDictionary.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -1662,10 +1662,9 @@
 // Note: anonymous classes are not in the SD.
 bool SystemDictionary::do_unloading(BoolObjectClosure* is_alive) {
   // First, mark for unload all ClassLoaderData referencing a dead class loader.
-  bool has_dead_loaders = ClassLoaderDataGraph::do_unloading(is_alive);
-  bool unloading_occurred = false;
-  if (has_dead_loaders) {
-    unloading_occurred = dictionary()->do_unloading();
+  bool unloading_occurred = ClassLoaderDataGraph::do_unloading(is_alive);
+  if (unloading_occurred) {
+    dictionary()->do_unloading();
     constraints()->purge_loader_constraints();
     resolution_errors()->purge_resolution_errors();
   }
--- a/src/share/vm/classfile/verifier.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/classfile/verifier.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -2234,6 +2234,181 @@
   }
 }
 
+// Look at the method's handlers.  If the bci is in the handler's try block
+// then check if the handler_pc is already on the stack.  If not, push it.
+void ClassVerifier::push_handlers(ExceptionTable* exhandlers,
+                                  GrowableArray<u4>* handler_stack,
+                                  u4 bci) {
+  int exlength = exhandlers->length();
+  for(int x = 0; x < exlength; x++) {
+    if (bci >= exhandlers->start_pc(x) && bci < exhandlers->end_pc(x)) {
+      handler_stack->append_if_missing(exhandlers->handler_pc(x));
+    }
+  }
+}
+
+// Return TRUE if all code paths starting with start_bc_offset end in
+// bytecode athrow or loop.
+bool ClassVerifier::ends_in_athrow(u4 start_bc_offset) {
+  ResourceMark rm;
+  // Create bytecode stream.
+  RawBytecodeStream bcs(method());
+  u4 code_length = method()->code_size();
+  bcs.set_start(start_bc_offset);
+  u4 target;
+  // Create stack for storing bytecode start offsets for if* and *switch.
+  GrowableArray<u4>* bci_stack = new GrowableArray<u4>(30);
+  // Create stack for handlers for try blocks containing this handler.
+  GrowableArray<u4>* handler_stack = new GrowableArray<u4>(30);
+  // Create list of visited branch opcodes (goto* and if*).
+  GrowableArray<u4>* visited_branches = new GrowableArray<u4>(30);
+  ExceptionTable exhandlers(_method());
+
+  while (true) {
+    if (bcs.is_last_bytecode()) {
+      // if no more starting offsets to parse or if at the end of the
+      // method then return false.
+      if ((bci_stack->is_empty()) || ((u4)bcs.end_bci() == code_length))
+        return false;
+      // Pop a bytecode starting offset and scan from there.
+      bcs.set_start(bci_stack->pop());
+    }
+    Bytecodes::Code opcode = bcs.raw_next();
+    u4 bci = bcs.bci();
+
+    // If the bytecode is in a TRY block, push its handlers so they
+    // will get parsed.
+    push_handlers(&exhandlers, handler_stack, bci);
+
+    switch (opcode) {
+      case Bytecodes::_if_icmpeq:
+      case Bytecodes::_if_icmpne:
+      case Bytecodes::_if_icmplt:
+      case Bytecodes::_if_icmpge:
+      case Bytecodes::_if_icmpgt:
+      case Bytecodes::_if_icmple:
+      case Bytecodes::_ifeq:
+      case Bytecodes::_ifne:
+      case Bytecodes::_iflt:
+      case Bytecodes::_ifge:
+      case Bytecodes::_ifgt:
+      case Bytecodes::_ifle:
+      case Bytecodes::_if_acmpeq:
+      case Bytecodes::_if_acmpne:
+      case Bytecodes::_ifnull:
+      case Bytecodes::_ifnonnull:
+        target = bcs.dest();
+        if (visited_branches->contains(bci)) {
+          if (bci_stack->is_empty()) return true;
+          // Pop a bytecode starting offset and scan from there.
+          bcs.set_start(bci_stack->pop());
+        } else {
+          if (target > bci) { // forward branch
+            if (target >= code_length) return false;
+            // Push the branch target onto the stack.
+            bci_stack->push(target);
+            // then, scan bytecodes starting with next.
+            bcs.set_start(bcs.next_bci());
+          } else { // backward branch
+            // Push bytecode offset following backward branch onto the stack.
+            bci_stack->push(bcs.next_bci());
+            // Check bytecodes starting with branch target.
+            bcs.set_start(target);
+          }
+          // Record target so we don't branch here again.
+          visited_branches->append(bci);
+        }
+        break;
+
+      case Bytecodes::_goto:
+      case Bytecodes::_goto_w:
+        target = (opcode == Bytecodes::_goto ? bcs.dest() : bcs.dest_w());
+        if (visited_branches->contains(bci)) {
+          if (bci_stack->is_empty()) return true;
+          // Been here before, pop new starting offset from stack.
+          bcs.set_start(bci_stack->pop());
+        } else {
+          if (target >= code_length) return false;
+          // Continue scanning from the target onward.
+          bcs.set_start(target);
+          // Record target so we don't branch here again.
+          visited_branches->append(bci);
+        }
+        break;
+
+      // Check that all switch alternatives end in 'athrow' bytecodes. Since it
+      // is  difficult to determine where each switch alternative ends, parse
+      // each switch alternative until either hit a 'return', 'athrow', or reach
+      // the end of the method's bytecodes.  This is gross but should be okay
+      // because:
+      // 1. tableswitch and lookupswitch byte codes in handlers for ctor explicit
+      //    constructor invocations should be rare.
+      // 2. if each switch alternative ends in an athrow then the parsing should be
+      //    short.  If there is no athrow then it is bogus code, anyway.
+      case Bytecodes::_lookupswitch:
+      case Bytecodes::_tableswitch:
+        {
+          address aligned_bcp = (address) round_to((intptr_t)(bcs.bcp() + 1), jintSize);
+          u4 default_offset = Bytes::get_Java_u4(aligned_bcp) + bci;
+          int keys, delta;
+          if (opcode == Bytecodes::_tableswitch) {
+            jint low = (jint)Bytes::get_Java_u4(aligned_bcp + jintSize);
+            jint high = (jint)Bytes::get_Java_u4(aligned_bcp + 2*jintSize);
+            // This is invalid, but let the regular bytecode verifier
+            // report this because the user will get a better error message.
+            if (low > high) return true;
+            keys = high - low + 1;
+            delta = 1;
+          } else {
+            keys = (int)Bytes::get_Java_u4(aligned_bcp + jintSize);
+            delta = 2;
+          }
+          // Invalid, let the regular bytecode verifier deal with it.
+          if (keys < 0) return true;
+
+          // Push the offset of the next bytecode onto the stack.
+          bci_stack->push(bcs.next_bci());
+
+          // Push the switch alternatives onto the stack.
+          for (int i = 0; i < keys; i++) {
+            u4 target = bci + (jint)Bytes::get_Java_u4(aligned_bcp+(3+i*delta)*jintSize);
+            if (target > code_length) return false;
+            bci_stack->push(target);
+          }
+
+          // Start bytecode parsing for the switch at the default alternative.
+          if (default_offset > code_length) return false;
+          bcs.set_start(default_offset);
+          break;
+        }
+
+      case Bytecodes::_return:
+        return false;
+
+      case Bytecodes::_athrow:
+        {
+          if (bci_stack->is_empty()) {
+            if (handler_stack->is_empty()) {
+              return true;
+            } else {
+              // Parse the catch handlers for try blocks containing athrow.
+              bcs.set_start(handler_stack->pop());
+            }
+          } else {
+            // Pop a bytecode offset and starting scanning from there.
+            bcs.set_start(bci_stack->pop());
+          }
+        }
+        break;
+
+      default:
+        ;
+    } // end switch
+  } // end while loop
+
+  return false;
+}
+
 void ClassVerifier::verify_invoke_init(
     RawBytecodeStream* bcs, u2 ref_class_index, VerificationType ref_class_type,
     StackMapFrame* current_frame, u4 code_length, bool *this_uninit,
@@ -2253,18 +2428,26 @@
       return;
     }
 
-    // Make sure that this call is not done from within a TRY block because
-    // that can result in returning an incomplete object.  Simply checking
-    // (bci >= start_pc) also ensures that this call is not done after a TRY
-    // block.  That is also illegal because this call must be the first Java
-    // statement in the constructor.
+    // Check if this call is done from inside of a TRY block.  If so, make
+    // sure that all catch clause paths end in a throw.  Otherwise, this
+    // can result in returning an incomplete object.
     ExceptionTable exhandlers(_method());
     int exlength = exhandlers.length();
     for(int i = 0; i < exlength; i++) {
-      if (bci >= exhandlers.start_pc(i)) {
-        verify_error(ErrorContext::bad_code(bci),
-                     "Bad <init> method call from after the start of a try block");
-        return;
+      u2 start_pc = exhandlers.start_pc(i);
+      u2 end_pc = exhandlers.end_pc(i);
+
+      if (bci >= start_pc && bci < end_pc) {
+        if (!ends_in_athrow(exhandlers.handler_pc(i))) {
+          verify_error(ErrorContext::bad_code(bci),
+            "Bad <init> method call from after the start of a try block");
+          return;
+        } else if (VerboseVerification) {
+          ResourceMark rm;
+          tty->print_cr(
+            "Survived call to ends_in_athrow(): %s",
+                        current_class()->name()->as_C_string());
+        }
       }
     }
 
--- a/src/share/vm/classfile/verifier.hpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/classfile/verifier.hpp	Fri Sep 05 06:26:44 2014 -0400
@@ -30,6 +30,7 @@
 #include "oops/klass.hpp"
 #include "oops/method.hpp"
 #include "runtime/handles.hpp"
+#include "utilities/growableArray.hpp"
 #include "utilities/exceptions.hpp"
 
 // The verifier class
@@ -303,6 +304,16 @@
     StackMapFrame* current_frame, u4 code_length, bool* this_uninit,
     constantPoolHandle cp, TRAPS);
 
+  // Used by ends_in_athrow() to push all handlers that contain bci onto
+  // the handler_stack, if the handler is not already on the stack.
+  void push_handlers(ExceptionTable* exhandlers,
+                     GrowableArray<u4>* handler_stack,
+                     u4 bci);
+
+  // Returns true if all paths starting with start_bc_offset end in athrow
+  // bytecode or loop.
+  bool ends_in_athrow(u4 start_bc_offset);
+
   void verify_invoke_instructions(
     RawBytecodeStream* bcs, u4 code_length, StackMapFrame* current_frame,
     bool* this_uninit, VerificationType return_type,
--- a/src/share/vm/gc_implementation/concurrentMarkSweep/cmsCollectorPolicy.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/gc_implementation/concurrentMarkSweep/cmsCollectorPolicy.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 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
@@ -53,7 +53,8 @@
 }
 
 void ConcurrentMarkSweepPolicy::initialize_generations() {
-  _generations = NEW_C_HEAP_ARRAY3(GenerationSpecPtr, number_of_generations(), mtGC, 0, AllocFailStrategy::RETURN_NULL);
+  _generations = NEW_C_HEAP_ARRAY3(GenerationSpecPtr, number_of_generations(), mtGC,
+    CURRENT_PC, AllocFailStrategy::RETURN_NULL);
   if (_generations == NULL)
     vm_exit_during_initialization("Unable to allocate gen spec");
 
--- a/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -1514,6 +1514,8 @@
     gclog_or_tty->print_cr("cms_allocation_rate=%g", stats().cms_allocation_rate());
     gclog_or_tty->print_cr("occupancy=%3.7f", _cmsGen->occupancy());
     gclog_or_tty->print_cr("initiatingOccupancy=%3.7f", _cmsGen->initiating_occupancy());
+    gclog_or_tty->print_cr("cms_time_since_begin=%3.7f", stats().cms_time_since_begin());
+    gclog_or_tty->print_cr("cms_time_since_end=%3.7f", stats().cms_time_since_end());
     gclog_or_tty->print_cr("metadata initialized %d",
       MetaspaceGC::should_concurrent_collect());
   }
@@ -1576,6 +1578,28 @@
     return true;
   }
 
+  // CMSTriggerInterval starts a CMS cycle if enough time has passed.
+  if (CMSTriggerInterval >= 0) {
+    if (CMSTriggerInterval == 0) {
+      // Trigger always
+      return true;
+    }
+
+    // Check the CMS time since begin (we do not check the stats validity
+    // as we want to be able to trigger the first CMS cycle as well)
+    if (stats().cms_time_since_begin() >= (CMSTriggerInterval / ((double) MILLIUNITS))) {
+      if (Verbose && PrintGCDetails) {
+        if (stats().valid()) {
+          gclog_or_tty->print_cr("CMSCollector: collect because of trigger interval (time since last begin %3.7f secs)",
+                                 stats().cms_time_since_begin());
+        } else {
+          gclog_or_tty->print_cr("CMSCollector: collect because of trigger interval (first collection)");
+        }
+      }
+      return true;
+    }
+  }
+
   return false;
 }
 
--- a/src/share/vm/gc_implementation/g1/concurrentG1Refine.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/gc_implementation/g1/concurrentG1Refine.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -81,8 +81,8 @@
   }
 }
 
-void ConcurrentG1Refine::init() {
-  _hot_card_cache.initialize();
+void ConcurrentG1Refine::init(G1RegionToSpaceMapper* card_counts_storage) {
+  _hot_card_cache.initialize(card_counts_storage);
 }
 
 void ConcurrentG1Refine::stop() {
--- a/src/share/vm/gc_implementation/g1/concurrentG1Refine.hpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/gc_implementation/g1/concurrentG1Refine.hpp	Fri Sep 05 06:26:44 2014 -0400
@@ -34,6 +34,7 @@
 class ConcurrentG1RefineThread;
 class G1CollectedHeap;
 class G1HotCardCache;
+class G1RegionToSpaceMapper;
 class G1RemSet;
 class DirtyCardQueue;
 
@@ -74,7 +75,7 @@
   ConcurrentG1Refine(G1CollectedHeap* g1h, CardTableEntryClosure* refine_closure);
   ~ConcurrentG1Refine();
 
-  void init(); // Accomplish some initialization that has to wait.
+  void init(G1RegionToSpaceMapper* card_counts_storage);
   void stop();
 
   void reinitialize_threads();
--- a/src/share/vm/gc_implementation/g1/concurrentMark.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/gc_implementation/g1/concurrentMark.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -36,6 +36,7 @@
 #include "gc_implementation/g1/heapRegion.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"
 #include "gc_implementation/shared/gcTrace.hpp"
@@ -98,12 +99,12 @@
 }
 
 #ifndef PRODUCT
-bool CMBitMapRO::covers(ReservedSpace heap_rs) const {
+bool CMBitMapRO::covers(MemRegion heap_rs) const {
   // assert(_bm.map() == _virtual_space.low(), "map inconsistency");
   assert(((size_t)_bm.size() * ((size_t)1 << _shifter)) == _bmWordSize,
          "size inconsistency");
-  return _bmStartWord == (HeapWord*)(heap_rs.base()) &&
-         _bmWordSize  == heap_rs.size()>>LogHeapWordSize;
+  return _bmStartWord == (HeapWord*)(heap_rs.start()) &&
+         _bmWordSize  == heap_rs.word_size();
 }
 #endif
 
@@ -111,33 +112,73 @@
   _bm.print_on_error(st, prefix);
 }
 
-bool CMBitMap::allocate(ReservedSpace heap_rs) {
-  _bmStartWord = (HeapWord*)(heap_rs.base());
-  _bmWordSize  = heap_rs.size()/HeapWordSize;    // heap_rs.size() is in bytes
-  ReservedSpace brs(ReservedSpace::allocation_align_size_up(
-                     (_bmWordSize >> (_shifter + LogBitsPerByte)) + 1));
-  if (!brs.is_reserved()) {
-    warning("ConcurrentMark marking bit map allocation failure");
+size_t CMBitMap::compute_size(size_t heap_size) {
+  return heap_size / mark_distance();
+}
+
+size_t CMBitMap::mark_distance() {
+  return MinObjAlignmentInBytes * BitsPerByte;
+}
+
+void CMBitMap::initialize(MemRegion heap, G1RegionToSpaceMapper* storage) {
+  _bmStartWord = heap.start();
+  _bmWordSize = heap.word_size();
+
+  _bm.set_map((BitMap::bm_word_t*) storage->reserved().start());
+  _bm.set_size(_bmWordSize >> _shifter);
+
+  storage->set_mapping_changed_listener(&_listener);
+}
+
+void CMBitMapMappingChangedListener::on_commit(uint start_region, size_t num_regions) {
+  // We need to clear the bitmap on commit, removing any existing information.
+  MemRegion mr(G1CollectedHeap::heap()->bottom_addr_for_region(start_region), num_regions * HeapRegion::GrainWords);
+  _bm->clearRange(mr);
+}
+
+// Closure used for clearing the given mark bitmap.
+class ClearBitmapHRClosure : public HeapRegionClosure {
+ private:
+  ConcurrentMark* _cm;
+  CMBitMap* _bitmap;
+  bool _may_yield;      // The closure may yield during iteration. If yielded, abort the iteration.
+ public:
+  ClearBitmapHRClosure(ConcurrentMark* cm, CMBitMap* bitmap, bool may_yield) : HeapRegionClosure(), _cm(cm), _bitmap(bitmap), _may_yield(may_yield) {
+    assert(!may_yield || cm != NULL, "CM must be non-NULL if this closure is expected to yield.");
+  }
+
+  virtual bool doHeapRegion(HeapRegion* r) {
+    size_t const chunk_size_in_words = M / HeapWordSize;
+
+    HeapWord* cur = r->bottom();
+    HeapWord* const end = r->end();
+
+    while (cur < end) {
+      MemRegion mr(cur, MIN2(cur + chunk_size_in_words, end));
+      _bitmap->clearRange(mr);
+
+      cur += chunk_size_in_words;
+
+      // Abort iteration if after yielding the marking has been aborted.
+      if (_may_yield && _cm->do_yield_check() && _cm->has_aborted()) {
+        return true;
+      }
+      // Repeat the asserts from before the start of the closure. We will do them
+      // as asserts here to minimize their overhead on the product. However, we
+      // will have them as guarantees at the beginning / end of the bitmap
+      // clearing to get some checking in the product.
+      assert(!_may_yield || _cm->cmThread()->during_cycle(), "invariant");
+      assert(!_may_yield || !G1CollectedHeap::heap()->mark_in_progress(), "invariant");
+    }
+
     return false;
   }
-  MemTracker::record_virtual_memory_type((address)brs.base(), mtGC);
-  // For now we'll just commit all of the bit map up front.
-  // Later on we'll try to be more parsimonious with swap.
-  if (!_virtual_space.initialize(brs, brs.size())) {
-    warning("ConcurrentMark marking bit map backing store failure");
-    return false;
-  }
-  assert(_virtual_space.committed_size() == brs.size(),
-         "didn't reserve backing store for all of concurrent marking bit map?");
-  _bm.set_map((BitMap::bm_word_t*)_virtual_space.low());
-  assert(_virtual_space.committed_size() << (_shifter + LogBitsPerByte) >=
-         _bmWordSize, "inconsistency in bit map sizing");
-  _bm.set_size(_bmWordSize >> _shifter);
-  return true;
-}
+};
 
 void CMBitMap::clearAll() {
-  _bm.clear();
+  ClearBitmapHRClosure cl(NULL, this, false /* may_yield */);
+  G1CollectedHeap::heap()->heap_region_iterate(&cl);
+  guarantee(cl.complete(), "Must have completed iteration.");
   return;
 }
 
@@ -482,10 +523,10 @@
   return MAX2((n_par_threads + 2) / 4, 1U);
 }
 
-ConcurrentMark::ConcurrentMark(G1CollectedHeap* g1h, ReservedSpace heap_rs) :
+ConcurrentMark::ConcurrentMark(G1CollectedHeap* g1h, G1RegionToSpaceMapper* prev_bitmap_storage, G1RegionToSpaceMapper* next_bitmap_storage) :
   _g1h(g1h),
-  _markBitMap1(log2_intptr(MinObjAlignment)),
-  _markBitMap2(log2_intptr(MinObjAlignment)),
+  _markBitMap1(),
+  _markBitMap2(),
   _parallel_marking_threads(0),
   _max_parallel_marking_threads(0),
   _sleep_factor(0.0),
@@ -494,7 +535,7 @@
   _cleanup_task_overhead(1.0),
   _cleanup_list("Cleanup List"),
   _region_bm((BitMap::idx_t)(g1h->max_regions()), false /* in_resource_area*/),
-  _card_bm((heap_rs.size() + CardTableModRefBS::card_size - 1) >>
+  _card_bm((g1h->reserved_region().byte_size() + CardTableModRefBS::card_size - 1) >>
             CardTableModRefBS::card_shift,
             false /* in_resource_area*/),
 
@@ -544,14 +585,8 @@
                            "heap end = " INTPTR_FORMAT, p2i(_heap_start), p2i(_heap_end));
   }
 
-  if (!_markBitMap1.allocate(heap_rs)) {
-    warning("Failed to allocate first CM bit map");
-    return;
-  }
-  if (!_markBitMap2.allocate(heap_rs)) {
-    warning("Failed to allocate second CM bit map");
-    return;
-  }
+  _markBitMap1.initialize(g1h->reserved_region(), prev_bitmap_storage);
+  _markBitMap2.initialize(g1h->reserved_region(), next_bitmap_storage);
 
   // Create & start a ConcurrentMark thread.
   _cmThread = new ConcurrentMarkThread(this);
@@ -562,8 +597,8 @@
   }
 
   assert(CGC_lock != NULL, "Where's the CGC_lock?");
-  assert(_markBitMap1.covers(heap_rs), "_markBitMap1 inconsistency");
-  assert(_markBitMap2.covers(heap_rs), "_markBitMap2 inconsistency");
+  assert(_markBitMap1.covers(g1h->reserved_region()), "_markBitMap1 inconsistency");
+  assert(_markBitMap2.covers(g1h->reserved_region()), "_markBitMap2 inconsistency");
 
   SATBMarkQueueSet& satb_qs = JavaThread::satb_mark_queue_set();
   satb_qs.set_buffer_size(G1SATBBufferSize);
@@ -723,38 +758,17 @@
   clear_all_count_data();
 
   // so that the call below can read a sensible value
-  _heap_start = (HeapWord*) heap_rs.base();
+  _heap_start = g1h->reserved_region().start();
   set_non_marking_state();
   _completed_initialization = true;
 }
 
-void ConcurrentMark::update_g1_committed(bool force) {
-  // If concurrent marking is not in progress, then we do not need to
-  // update _heap_end.
-  if (!concurrent_marking_in_progress() && !force) return;
-
-  MemRegion committed = _g1h->g1_committed();
-  assert(committed.start() == _heap_start, "start shouldn't change");
-  HeapWord* new_end = committed.end();
-  if (new_end > _heap_end) {
-    // The heap has been expanded.
-
-    _heap_end = new_end;
-  }
-  // Notice that the heap can also shrink. However, this only happens
-  // during a Full GC (at least currently) and the entire marking
-  // phase will bail out and the task will not be restarted. So, let's
-  // do nothing.
-}
-
 void ConcurrentMark::reset() {
   // Starting values for these two. This should be called in a STW
-  // phase. CM will be notified of any future g1_committed expansions
-  // will be at the end of evacuation pauses, when tasks are
-  // inactive.
-  MemRegion committed = _g1h->g1_committed();
-  _heap_start = committed.start();
-  _heap_end   = committed.end();
+  // phase.
+  MemRegion reserved = _g1h->g1_reserved();
+  _heap_start = reserved.start();
+  _heap_end   = reserved.end();
 
   // Separated the asserts so that we know which one fires.
   assert(_heap_start != NULL, "heap bounds should look ok");
@@ -826,7 +840,6 @@
     assert(out_of_regions(),
            err_msg("only way to get here: _finger: "PTR_FORMAT", _heap_end: "PTR_FORMAT,
                    p2i(_finger), p2i(_heap_end)));
-    update_g1_committed(true);
   }
 }
 
@@ -845,7 +858,6 @@
 
 void ConcurrentMark::clearNextBitmap() {
   G1CollectedHeap* g1h = G1CollectedHeap::heap();
-  G1CollectorPolicy* g1p = g1h->g1_policy();
 
   // Make sure that the concurrent mark thread looks to still be in
   // the current cycle.
@@ -857,41 +869,36 @@
   // is the case.
   guarantee(!g1h->mark_in_progress(), "invariant");
 
-  // clear the mark bitmap (no grey objects to start with).
-  // We need to do this in chunks and offer to yield in between
-  // each chunk.
-  HeapWord* start  = _nextMarkBitMap->startWord();
-  HeapWord* end    = _nextMarkBitMap->endWord();
-  HeapWord* cur    = start;
-  size_t chunkSize = M;
-  while (cur < end) {
-    HeapWord* next = cur + chunkSize;
-    if (next > end) {
-      next = end;
-    }
-    MemRegion mr(cur,next);
-    _nextMarkBitMap->clearRange(mr);
-    cur = next;
-    do_yield_check();
-
-    // Repeat the asserts from above. We'll do them as asserts here to
-    // minimize their overhead on the product. However, we'll have
-    // them as guarantees at the beginning / end of the bitmap
-    // clearing to get some checking in the product.
-    assert(cmThread()->during_cycle(), "invariant");
-    assert(!g1h->mark_in_progress(), "invariant");
+  ClearBitmapHRClosure cl(this, _nextMarkBitMap, true /* may_yield */);
+  g1h->heap_region_iterate(&cl);
+
+  // Clear the liveness counting data. If the marking has been aborted, the abort()
+  // call already did that.
+  if (cl.complete()) {
+    clear_all_count_data();
   }
 
-  // Clear the liveness counting data
-  clear_all_count_data();
-
   // Repeat the asserts from above.
   guarantee(cmThread()->during_cycle(), "invariant");
   guarantee(!g1h->mark_in_progress(), "invariant");
 }
 
+class CheckBitmapClearHRClosure : public HeapRegionClosure {
+  CMBitMap* _bitmap;
+  bool _error;
+ public:
+  CheckBitmapClearHRClosure(CMBitMap* bitmap) : _bitmap(bitmap) {
+  }
+
+  virtual bool doHeapRegion(HeapRegion* r) {
+    return _bitmap->getNextMarkedWordAddress(r->bottom(), r->end()) != r->end();
+  }
+};
+
 bool ConcurrentMark::nextMarkBitmapIsClear() {
-  return _nextMarkBitMap->getNextMarkedWordAddress(_heap_start, _heap_end) == _heap_end;
+  CheckBitmapClearHRClosure cl(_nextMarkBitMap);
+  _g1h->heap_region_iterate(&cl);
+  return cl.complete();
 }
 
 class NoteStartOfMarkHRClosure: public HeapRegionClosure {
@@ -2191,10 +2198,10 @@
                            _cleanup_list.length());
   }
 
-  // Noone else should be accessing the _cleanup_list at this point,
-  // so it's not necessary to take any locks
+  // No one else should be accessing the _cleanup_list at this point,
+  // so it is not necessary to take any locks
   while (!_cleanup_list.is_empty()) {
-    HeapRegion* hr = _cleanup_list.remove_head();
+    HeapRegion* hr = _cleanup_list.remove_region(true /* from_head */);
     assert(hr != NULL, "Got NULL from a non-empty list");
     hr->par_clear();
     tmp_free_list.add_ordered(hr);
@@ -2800,7 +2807,6 @@
       str = " O";
     } else {
       HeapRegion* hr  = _g1h->heap_region_containing(obj);
-      guarantee(hr != NULL, "invariant");
       bool over_tams = _g1h->allocated_since_marking(obj, hr, _vo);
       bool marked = _g1h->is_marked(obj, _vo);
 
@@ -2979,22 +2985,25 @@
     // claim_region() and a humongous object allocation might force us
     // to do a bit of unnecessary work (due to some unnecessary bitmap
     // iterations) but it should not introduce and correctness issues.
-    HeapRegion* curr_region   = _g1h->heap_region_containing_raw(finger);
-    HeapWord*   bottom        = curr_region->bottom();
-    HeapWord*   end           = curr_region->end();
-    HeapWord*   limit         = curr_region->next_top_at_mark_start();
-
-    if (verbose_low()) {
-      gclog_or_tty->print_cr("[%u] curr_region = "PTR_FORMAT" "
-                             "["PTR_FORMAT", "PTR_FORMAT"), "
-                             "limit = "PTR_FORMAT,
-                             worker_id, p2i(curr_region), p2i(bottom), p2i(end), p2i(limit));
-    }
+    HeapRegion* curr_region = _g1h->heap_region_containing_raw(finger);
+
+    // Above heap_region_containing_raw may return NULL as we always scan claim
+    // until the end of the heap. In this case, just jump to the next region.
+    HeapWord* end = curr_region != NULL ? curr_region->end() : finger + HeapRegion::GrainWords;
 
     // Is the gap between reading the finger and doing the CAS too long?
     HeapWord* res = (HeapWord*) Atomic::cmpxchg_ptr(end, &_finger, finger);
-    if (res == finger) {
+    if (res == finger && curr_region != NULL) {
       // we succeeded
+      HeapWord*   bottom        = curr_region->bottom();
+      HeapWord*   limit         = curr_region->next_top_at_mark_start();
+
+      if (verbose_low()) {
+        gclog_or_tty->print_cr("[%u] curr_region = "PTR_FORMAT" "
+                               "["PTR_FORMAT", "PTR_FORMAT"), "
+                               "limit = "PTR_FORMAT,
+                               worker_id, p2i(curr_region), p2i(bottom), p2i(end), p2i(limit));
+      }
 
       // notice that _finger == end cannot be guaranteed here since,
       // someone else might have moved the finger even further
@@ -3025,10 +3034,17 @@
     } else {
       assert(_finger > finger, "the finger should have moved forward");
       if (verbose_low()) {
-        gclog_or_tty->print_cr("[%u] somebody else moved the finger, "
-                               "global finger = "PTR_FORMAT", "
-                               "our finger = "PTR_FORMAT,
-                               worker_id, p2i(_finger), p2i(finger));
+        if (curr_region == NULL) {
+          gclog_or_tty->print_cr("[%u] found uncommitted region, moving finger, "
+                                 "global finger = "PTR_FORMAT", "
+                                 "our finger = "PTR_FORMAT,
+                                 worker_id, p2i(_finger), p2i(finger));
+        } else {
+          gclog_or_tty->print_cr("[%u] somebody else moved the finger, "
+                                 "global finger = "PTR_FORMAT", "
+                                 "our finger = "PTR_FORMAT,
+                                 worker_id, p2i(_finger), p2i(finger));
+        }
       }
 
       // read it again
@@ -3143,8 +3159,10 @@
       // happens, heap_region_containing() will return the bottom of the
       // corresponding starts humongous region and the check below will
       // not hold any more.
+      // Since we always iterate over all regions, we might get a NULL HeapRegion
+      // here.
       HeapRegion* global_hr = _g1h->heap_region_containing_raw(global_finger);
-      guarantee(global_finger == global_hr->bottom(),
+      guarantee(global_hr == NULL || global_finger == global_hr->bottom(),
                 err_msg("global finger: "PTR_FORMAT" region: "HR_FORMAT,
                         p2i(global_finger), HR_FORMAT_PARAMS(global_hr)));
     }
@@ -3157,7 +3175,7 @@
       if (task_finger != NULL && task_finger < _heap_end) {
         // See above note on the global finger verification.
         HeapRegion* task_hr = _g1h->heap_region_containing_raw(task_finger);
-        guarantee(task_finger == task_hr->bottom() ||
+        guarantee(task_hr == NULL || task_finger == task_hr->bottom() ||
                   !task_hr->in_collection_set(),
                   err_msg("task finger: "PTR_FORMAT" region: "HR_FORMAT,
                           p2i(task_finger), HR_FORMAT_PARAMS(task_hr)));
@@ -3565,9 +3583,8 @@
 }
 
 void CMTask::setup_for_region(HeapRegion* hr) {
-  // Separated the asserts so that we know which one fires.
   assert(hr != NULL,
-        "claim_region() should have filtered out continues humongous regions");
+        "claim_region() should have filtered out NULL regions");
   assert(!hr->continuesHumongous(),
         "claim_region() should have filtered out continues humongous regions");
 
@@ -4674,7 +4691,6 @@
     _hum_prev_live_bytes(0), _hum_next_live_bytes(0),
     _total_remset_bytes(0), _total_strong_code_roots_bytes(0) {
   G1CollectedHeap* g1h = G1CollectedHeap::heap();
-  MemRegion g1_committed = g1h->g1_committed();
   MemRegion g1_reserved = g1h->g1_reserved();
   double now = os::elapsedTime();
 
@@ -4682,10 +4698,8 @@
   _out->cr();
   _out->print_cr(G1PPRL_LINE_PREFIX" PHASE %s @ %1.3f", phase_name, now);
   _out->print_cr(G1PPRL_LINE_PREFIX" HEAP"
-                 G1PPRL_SUM_ADDR_FORMAT("committed")
                  G1PPRL_SUM_ADDR_FORMAT("reserved")
                  G1PPRL_SUM_BYTE_FORMAT("region-size"),
-                 p2i(g1_committed.start()), p2i(g1_committed.end()),
                  p2i(g1_reserved.start()), p2i(g1_reserved.end()),
                  HeapRegion::GrainBytes);
   _out->print_cr(G1PPRL_LINE_PREFIX);
--- a/src/share/vm/gc_implementation/g1/concurrentMark.hpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/gc_implementation/g1/concurrentMark.hpp	Fri Sep 05 06:26:44 2014 -0400
@@ -27,10 +27,12 @@
 
 #include "classfile/javaClasses.hpp"
 #include "gc_implementation/g1/heapRegionSet.hpp"
+#include "gc_implementation/g1/g1RegionToSpaceMapper.hpp"
 #include "gc_implementation/shared/gcId.hpp"
 #include "utilities/taskqueue.hpp"
 
 class G1CollectedHeap;
+class CMBitMap;
 class CMTask;
 typedef GenericTaskQueue<oop, mtGC>            CMTaskQueue;
 typedef GenericTaskQueueSet<CMTaskQueue, mtGC> CMTaskQueueSet;
@@ -57,7 +59,6 @@
   HeapWord* _bmStartWord;      // base address of range covered by map
   size_t    _bmWordSize;       // map size (in #HeapWords covered)
   const int _shifter;          // map to char or bit
-  VirtualSpace _virtual_space; // underlying the bit map
   BitMap    _bm;               // the bit map itself
 
  public:
@@ -115,42 +116,41 @@
   void print_on_error(outputStream* st, const char* prefix) const;
 
   // debugging
-  NOT_PRODUCT(bool covers(ReservedSpace rs) const;)
+  NOT_PRODUCT(bool covers(MemRegion rs) const;)
+};
+
+class CMBitMapMappingChangedListener : public G1MappingChangedListener {
+ private:
+  CMBitMap* _bm;
+ public:
+  CMBitMapMappingChangedListener() : _bm(NULL) {}
+
+  void set_bitmap(CMBitMap* bm) { _bm = bm; }
+
+  virtual void on_commit(uint start_idx, size_t num_regions);
 };
 
 class CMBitMap : public CMBitMapRO {
+ private:
+  CMBitMapMappingChangedListener _listener;
 
  public:
-  // constructor
-  CMBitMap(int shifter) :
-    CMBitMapRO(shifter) {}
+  static size_t compute_size(size_t heap_size);
+  // Returns the amount of bytes on the heap between two marks in the bitmap.
+  static size_t mark_distance();
 
-  // Allocates the back store for the marking bitmap
-  bool allocate(ReservedSpace heap_rs);
+  CMBitMap() : CMBitMapRO(LogMinObjAlignment), _listener() { _listener.set_bitmap(this); }
 
-  // write marks
-  void mark(HeapWord* addr) {
-    assert(_bmStartWord <= addr && addr < (_bmStartWord + _bmWordSize),
-           "outside underlying space?");
-    _bm.set_bit(heapWordToOffset(addr));
-  }
-  void clear(HeapWord* addr) {
-    assert(_bmStartWord <= addr && addr < (_bmStartWord + _bmWordSize),
-           "outside underlying space?");
-    _bm.clear_bit(heapWordToOffset(addr));
-  }
-  bool parMark(HeapWord* addr) {
-    assert(_bmStartWord <= addr && addr < (_bmStartWord + _bmWordSize),
-           "outside underlying space?");
-    return _bm.par_set_bit(heapWordToOffset(addr));
-  }
-  bool parClear(HeapWord* addr) {
-    assert(_bmStartWord <= addr && addr < (_bmStartWord + _bmWordSize),
-           "outside underlying space?");
-    return _bm.par_clear_bit(heapWordToOffset(addr));
-  }
+  // Initializes the underlying BitMap to cover the given area.
+  void initialize(MemRegion heap, G1RegionToSpaceMapper* storage);
+
+  // Write marks.
+  inline void mark(HeapWord* addr);
+  inline void clear(HeapWord* addr);
+  inline bool parMark(HeapWord* addr);
+  inline bool parClear(HeapWord* addr);
+
   void markRange(MemRegion mr);
-  void clearAll();
   void clearRange(MemRegion mr);
 
   // Starting at the bit corresponding to "addr" (inclusive), find the next
@@ -161,6 +161,9 @@
   // the run.  If there is no "1" bit at or after "addr", return an empty
   // MemRegion.
   MemRegion getAndClearMarkedRegion(HeapWord* addr, HeapWord* end_addr);
+
+  // Clear the whole mark bitmap.
+  void clearAll();
 };
 
 // Represents a marking stack used by ConcurrentMarking in the G1 collector.
@@ -680,7 +683,7 @@
     return _task_queues->steal(worker_id, hash_seed, obj);
   }
 
-  ConcurrentMark(G1CollectedHeap* g1h, ReservedSpace heap_rs);
+  ConcurrentMark(G1CollectedHeap* g1h, G1RegionToSpaceMapper* prev_bitmap_storage, G1RegionToSpaceMapper* next_bitmap_storage);
   ~ConcurrentMark();
 
   ConcurrentMarkThread* cmThread() { return _cmThread; }
@@ -736,7 +739,8 @@
   // Clear the next marking bitmap (will be called concurrently).
   void clearNextBitmap();
 
-  // Return whether the next mark bitmap has no marks set.
+  // Return whether the next mark bitmap has no marks set. To be used for assertions
+  // only. Will not yield to pause requests.
   bool nextMarkBitmapIsClear();
 
   // These two do the work that needs to be done before and after the
@@ -794,12 +798,6 @@
                            bool verify_thread_buffers,
                            bool verify_fingers) PRODUCT_RETURN;
 
-  // It is called at the end of an evacuation pause during marking so
-  // that CM is notified of where the new end of the heap is. It
-  // doesn't do anything if concurrent_marking_in_progress() is false,
-  // unless the force parameter is true.
-  void update_g1_committed(bool force = false);
-
   bool isMarked(oop p) const {
     assert(p != NULL && p->is_oop(), "expected an oop");
     HeapWord* addr = (HeapWord*)p;
--- a/src/share/vm/gc_implementation/g1/concurrentMark.inline.hpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/gc_implementation/g1/concurrentMark.inline.hpp	Fri Sep 05 06:26:44 2014 -0400
@@ -268,6 +268,36 @@
   return iterate(cl, mr);
 }
 
+#define check_mark(addr)                                                       \
+  assert(_bmStartWord <= (addr) && (addr) < (_bmStartWord + _bmWordSize),      \
+         "outside underlying space?");                                         \
+  assert(G1CollectedHeap::heap()->is_in_exact(addr),                           \
+         err_msg("Trying to access not available bitmap "PTR_FORMAT            \
+                 " corresponding to "PTR_FORMAT" (%u)",                        \
+                 p2i(this), p2i(addr), G1CollectedHeap::heap()->addr_to_region(addr)));
+
+inline void CMBitMap::mark(HeapWord* addr) {
+  check_mark(addr);
+  _bm.set_bit(heapWordToOffset(addr));
+}
+
+inline void CMBitMap::clear(HeapWord* addr) {
+  check_mark(addr);
+  _bm.clear_bit(heapWordToOffset(addr));
+}
+
+inline bool CMBitMap::parMark(HeapWord* addr) {
+  check_mark(addr);
+  return _bm.par_set_bit(heapWordToOffset(addr));
+}
+
+inline bool CMBitMap::parClear(HeapWord* addr) {
+  check_mark(addr);
+  return _bm.par_clear_bit(heapWordToOffset(addr));
+}
+
+#undef check_mark
+
 inline void CMTask::push(oop obj) {
   HeapWord* objAddr = (HeapWord*) obj;
   assert(_g1h->is_in_g1_reserved(objAddr), "invariant");
--- a/src/share/vm/gc_implementation/g1/g1AllocRegion.hpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/gc_implementation/g1/g1AllocRegion.hpp	Fri Sep 05 06:26:44 2014 -0400
@@ -173,7 +173,7 @@
 
   // Should be called when we want to release the active region which
   // is returned after it's been retired.
-  HeapRegion* release();
+  virtual HeapRegion* release();
 
 #if G1_ALLOC_REGION_TRACING
   void trace(const char* str, size_t word_size = 0, HeapWord* result = NULL);
--- a/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -32,64 +32,37 @@
 
 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
 //////////////////////////////////////////////////////////////////////
 
-G1BlockOffsetSharedArray::G1BlockOffsetSharedArray(MemRegion reserved,
-                                                   size_t init_word_size) :
-  _reserved(reserved), _end(NULL)
-{
-  size_t size = compute_size(reserved.word_size());
-  ReservedSpace rs(ReservedSpace::allocation_align_size_up(size));
-  if (!rs.is_reserved()) {
-    vm_exit_during_initialization("Could not reserve enough space for heap offset array");
-  }
-  if (!_vs.initialize(rs, 0)) {
-    vm_exit_during_initialization("Could not reserve enough space for heap offset array");
-  }
+G1BlockOffsetSharedArray::G1BlockOffsetSharedArray(MemRegion heap, G1RegionToSpaceMapper* storage) :
+  _reserved(), _end(NULL), _listener(), _offset_array(NULL) {
+
+  _reserved = heap;
+  _end = NULL;
 
-  MemTracker::record_virtual_memory_type((address)rs.base(), mtGC);
+  MemRegion bot_reserved = storage->reserved();
 
-  _offset_array = (u_char*)_vs.low_boundary();
-  resize(init_word_size);
+  _offset_array = (u_char*)bot_reserved.start();
+  _end = _reserved.end();
+
+  storage->set_mapping_changed_listener(&_listener);
+
   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,
-                  rs.base(), rs.size(), rs.base() + rs.size());
-    gclog_or_tty->print_cr("  "
-                  "  _vs.low_boundary(): " INTPTR_FORMAT
-                  "  _vs.high_boundary(): " INTPTR_FORMAT,
-                  _vs.low_boundary(),
-                  _vs.high_boundary());
-  }
-}
-
-void G1BlockOffsetSharedArray::resize(size_t new_word_size) {
-  assert(new_word_size <= _reserved.word_size(), "Resize larger than reserved");
-  size_t new_size = compute_size(new_word_size);
-  size_t old_size = _vs.committed_size();
-  size_t delta;
-  char* high = _vs.high();
-  _end = _reserved.start() + new_word_size;
-  if (new_size > old_size) {
-    delta = ReservedSpace::page_align_size_up(new_size - old_size);
-    assert(delta > 0, "just checking");
-    if (!_vs.expand_by(delta)) {
-      // Do better than this for Merlin
-      vm_exit_out_of_memory(delta, OOM_MMAP_ERROR, "offset table expansion");
-    }
-    assert(_vs.high() == high + delta, "invalid expansion");
-    // Initialization of the contents is left to the
-    // G1BlockOffsetArray that uses it.
-  } else {
-    delta = ReservedSpace::page_align_size_down(old_size - new_size);
-    if (delta == 0) return;
-    _vs.shrink_by(delta);
-    assert(_vs.high() == high - delta, "invalid expansion");
+                  bot_reserved.start(), bot_reserved.byte_size(), bot_reserved.end());
   }
 }
 
@@ -100,18 +73,7 @@
 }
 
 void G1BlockOffsetSharedArray::set_offset_array(HeapWord* left, HeapWord* right, u_char offset) {
-  check_index(index_for(right - 1), "right address out of range");
-  assert(left  < right, "Heap addresses out of order");
-  size_t num_cards = pointer_delta(right, left) >> LogN_words;
-  if (UseMemSetInBOT) {
-    memset(&_offset_array[index_for(left)], offset, num_cards);
-  } else {
-    size_t i = index_for(left);
-    const size_t end = i + num_cards;
-    for (; i < end; i++) {
-      _offset_array[i] = offset;
-    }
-  }
+  set_offset_array(index_for(left), index_for(right -1), offset);
 }
 
 //////////////////////////////////////////////////////////////////////
@@ -651,6 +613,25 @@
   _next_offset_index = 0;
 }
 
+HeapWord* G1BlockOffsetArrayContigSpace::initialize_threshold_raw() {
+  assert(!Universe::heap()->is_in_reserved(_array->_offset_array),
+         "just checking");
+  _next_offset_index = _array->index_for_raw(_bottom);
+  _next_offset_index++;
+  _next_offset_threshold =
+    _array->address_for_index_raw(_next_offset_index);
+  return _next_offset_threshold;
+}
+
+void G1BlockOffsetArrayContigSpace::zero_bottom_entry_raw() {
+  assert(!Universe::heap()->is_in_reserved(_array->_offset_array),
+         "just checking");
+  size_t bottom_index = _array->index_for_raw(_bottom);
+  assert(_array->address_for_index_raw(bottom_index) == _bottom,
+         "Precondition of call");
+  _array->set_offset_array_raw(bottom_index, 0);
+}
+
 HeapWord* G1BlockOffsetArrayContigSpace::initialize_threshold() {
   assert(!Universe::heap()->is_in_reserved(_array->_offset_array),
          "just checking");
@@ -675,8 +656,7 @@
   assert(new_top <= _end, "_end should have already been updated");
 
   // The first BOT entry should have offset 0.
-  zero_bottom_entry();
-  initialize_threshold();
+  reset_bot();
   alloc_block(_bottom, new_top);
  }
 
--- a/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.hpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.hpp	Fri Sep 05 06:26:44 2014 -0400
@@ -25,6 +25,7 @@
 #ifndef SHARE_VM_GC_IMPLEMENTATION_G1_G1BLOCKOFFSETTABLE_HPP
 #define SHARE_VM_GC_IMPLEMENTATION_G1_G1BLOCKOFFSETTABLE_HPP
 
+#include "gc_implementation/g1/g1RegionToSpaceMapper.hpp"
 #include "memory/memRegion.hpp"
 #include "runtime/virtualspace.hpp"
 #include "utilities/globalDefinitions.hpp"
@@ -106,6 +107,11 @@
   inline HeapWord* block_start_const(const void* addr) const;
 };
 
+class G1BlockOffsetSharedArrayMappingChangedListener : public G1MappingChangedListener {
+ public:
+  virtual void on_commit(uint start_idx, size_t num_regions);
+};
+
 // This implementation of "G1BlockOffsetTable" divides the covered region
 // into "N"-word subregions (where "N" = 2^"LogN".  An array with an entry
 // for each such subregion indicates how far back one must go to find the
@@ -125,6 +131,7 @@
   friend class VMStructs;
 
 private:
+  G1BlockOffsetSharedArrayMappingChangedListener _listener;
   // The reserved region covered by the shared array.
   MemRegion _reserved;
 
@@ -133,16 +140,8 @@
 
   // Array for keeping offsets for retrieving object start fast given an
   // address.
-  VirtualSpace _vs;
   u_char* _offset_array;          // byte array keeping backwards offsets
 
-  void check_index(size_t index, const char* msg) const {
-    assert(index < _vs.committed_size(),
-           err_msg("%s - "
-                   "index: " SIZE_FORMAT ", _vs.committed_size: " SIZE_FORMAT,
-                   msg, index, _vs.committed_size()));
-  }
-
   void check_offset(size_t offset, const char* msg) const {
     assert(offset <= N_words,
            err_msg("%s - "
@@ -152,63 +151,33 @@
 
   // Bounds checking accessors:
   // For performance these have to devolve to array accesses in product builds.
-  u_char offset_array(size_t index) const {
-    check_index(index, "index out of range");
-    return _offset_array[index];
-  }
+  inline u_char offset_array(size_t index) const;
 
   void set_offset_array(HeapWord* left, HeapWord* right, u_char offset);
 
-  void set_offset_array(size_t index, u_char offset) {
-    check_index(index, "index out of range");
-    check_offset(offset, "offset too large");
+  void set_offset_array_raw(size_t index, u_char offset) {
     _offset_array[index] = offset;
   }
 
-  void set_offset_array(size_t index, HeapWord* high, HeapWord* low) {
-    check_index(index, "index out of range");
-    assert(high >= low, "addresses out of order");
-    check_offset(pointer_delta(high, low), "offset too large");
-    _offset_array[index] = (u_char) pointer_delta(high, low);
-  }
+  inline void set_offset_array(size_t index, u_char offset);
+
+  inline void set_offset_array(size_t index, HeapWord* high, HeapWord* low);
 
-  void set_offset_array(size_t left, size_t right, u_char offset) {
-    check_index(right, "right index out of range");
-    assert(left <= right, "indexes out of order");
-    size_t num_cards = right - left + 1;
-    if (UseMemSetInBOT) {
-      memset(&_offset_array[left], offset, num_cards);
-    } else {
-      size_t i = left;
-      const size_t end = i + num_cards;
-      for (; i < end; i++) {
-        _offset_array[i] = offset;
-      }
-    }
-  }
+  inline void set_offset_array(size_t left, size_t right, u_char offset);
 
-  void 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");
-  }
+  inline void check_offset_array(size_t index, HeapWord* high, HeapWord* low) const;
 
   bool is_card_boundary(HeapWord* p) const;
 
+public:
+
   // Return the number of slots needed for an offset array
   // that covers mem_region_words words.
-  // We always add an extra slot because if an object
-  // ends on a card boundary we put a 0 in the next
-  // offset array slot, so we want that slot always
-  // to be reserved.
-
-  size_t compute_size(size_t mem_region_words) {
-    size_t number_of_slots = (mem_region_words / N_words) + 1;
-    return ReservedSpace::page_align_size_up(number_of_slots);
+  static size_t compute_size(size_t mem_region_words) {
+    size_t number_of_slots = (mem_region_words / N_words);
+    return ReservedSpace::allocation_align_size_up(number_of_slots);
   }
 
-public:
   enum SomePublicConstants {
     LogN = 9,
     LogN_words = LogN - LogHeapWordSize,
@@ -222,25 +191,21 @@
   // least "init_word_size".) The contents of the initial table are
   // undefined; it is the responsibility of the constituent
   // G1BlockOffsetTable(s) to initialize cards.
-  G1BlockOffsetSharedArray(MemRegion reserved, size_t init_word_size);
-
-  // Notes a change in the committed size of the region covered by the
-  // table.  The "new_word_size" may not be larger than the size of the
-  // reserved region this table covers.
-  void resize(size_t new_word_size);
+  G1BlockOffsetSharedArray(MemRegion heap, G1RegionToSpaceMapper* storage);
 
   void set_bottom(HeapWord* new_bottom);
 
-  // Updates all the BlockOffsetArray's sharing this shared array to
-  // reflect the current "top"'s of their spaces.
-  void update_offset_arrays();
-
   // 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;
 
   // Return the address indicating the start of the region corresponding to
   // "index" in "_offset_array".
   inline HeapWord* address_for_index(size_t index) const;
+  // Variant of address_for_index that does not check the index for validity.
+  inline HeapWord* address_for_index_raw(size_t index) const {
+    return _reserved.start() + (index << LogN_words);
+  }
 };
 
 // And here is the G1BlockOffsetTable subtype that uses the array.
@@ -480,6 +445,14 @@
                       blk_start, blk_end);
   }
 
+  // Variant of zero_bottom_entry that 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);
 
@@ -487,8 +460,10 @@
   // bottom of the covered region.
   HeapWord* initialize_threshold();
 
-  // Zero out the entry for _bottom (offset will be zero).
-  void      zero_bottom_entry();
+  void reset_bot() {
+    zero_bottom_entry_raw();
+    initialize_threshold_raw();
+  }
 
   // Return the next threshold, the point at which the table should be
   // updated.
--- a/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.inline.hpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.inline.hpp	Fri Sep 05 06:26:44 2014 -0400
@@ -47,14 +47,69 @@
   }
 }
 
+#define check_index(index, msg)                                                \
+  assert((index) < (_reserved.word_size() >> LogN_words),                      \
+         err_msg("%s - index: "SIZE_FORMAT", _vs.committed_size: "SIZE_FORMAT, \
+                 msg, (index), (_reserved.word_size() >> LogN_words)));        \
+  assert(G1CollectedHeap::heap()->is_in_exact(address_for_index_raw(index)),   \
+         err_msg("Index "SIZE_FORMAT" corresponding to "PTR_FORMAT             \
+                 " (%u) is not in committed area.",                            \
+                 (index),                                                      \
+                 p2i(address_for_index_raw(index)),                            \
+                 G1CollectedHeap::heap()->addr_to_region(address_for_index_raw(index))));
+
+u_char G1BlockOffsetSharedArray::offset_array(size_t index) const {
+  check_index(index, "index out of range");
+  return _offset_array[index];
+}
+
+void G1BlockOffsetSharedArray::set_offset_array(size_t index, u_char offset) {
+  check_index(index, "index out of range");
+  set_offset_array_raw(index, offset);
+}
+
+void G1BlockOffsetSharedArray::set_offset_array(size_t index, HeapWord* high, HeapWord* low) {
+  check_index(index, "index out of range");
+  assert(high >= low, "addresses out of order");
+  size_t offset = pointer_delta(high, low);
+  check_offset(offset, "offset too large");
+  set_offset_array(index, (u_char)offset);
+}
+
+void G1BlockOffsetSharedArray::set_offset_array(size_t left, size_t right, u_char offset) {
+  check_index(right, "right index out of range");
+  assert(left <= right, "indexes out of order");
+  size_t num_cards = right - left + 1;
+  if (UseMemSetInBOT) {
+    memset(&_offset_array[left], offset, num_cards);
+  } else {
+    size_t i = left;
+    const size_t end = i + num_cards;
+    for (; i < end; i++) {
+      _offset_array[i] = offset;
+    }
+  }
+}
+
+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;
+}
+
 inline size_t G1BlockOffsetSharedArray::index_for(const void* p) const {
   char* pc = (char*)p;
   assert(pc >= (char*)_reserved.start() &&
          pc <  (char*)_reserved.end(),
          err_msg("p (" PTR_FORMAT ") not in reserved [" PTR_FORMAT ", " PTR_FORMAT ")",
                  p2i(p), p2i(_reserved.start()), p2i(_reserved.end())));
-  size_t delta = pointer_delta(pc, _reserved.start(), sizeof(char));
-  size_t result = delta >> LogN;
+  size_t result = index_for_raw(p);
   check_index(result, "bad index from address");
   return result;
 }
@@ -62,7 +117,7 @@
 inline HeapWord*
 G1BlockOffsetSharedArray::address_for_index(size_t index) const {
   check_index(index, "index out of range");
-  HeapWord* result = _reserved.start() + (index << LogN_words);
+  HeapWord* result = address_for_index_raw(index);
   assert(result >= _reserved.start() && result < _reserved.end(),
          err_msg("bad address from index result " PTR_FORMAT
                  " _reserved.start() " PTR_FORMAT " _reserved.end() "
@@ -71,6 +126,8 @@
   return result;
 }
 
+#undef check_index
+
 inline size_t
 G1BlockOffsetArray::block_size(const HeapWord* p) const {
   return gsp()->block_size(p);
--- a/src/share/vm/gc_implementation/g1/g1CardCounts.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/gc_implementation/g1/g1CardCounts.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -33,31 +33,26 @@
 
 PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC
 
+void G1CardCountsMappingChangedListener::on_commit(uint start_idx, size_t num_regions) {
+  MemRegion mr(G1CollectedHeap::heap()->bottom_addr_for_region(start_idx), num_regions * HeapRegion::GrainWords);
+  _counts->clear_range(mr);
+}
+
 void G1CardCounts::clear_range(size_t from_card_num, size_t to_card_num) {
   if (has_count_table()) {
-    assert(from_card_num >= 0 && from_card_num < _committed_max_card_num,
-           err_msg("from card num out of range: "SIZE_FORMAT, from_card_num));
     assert(from_card_num < to_card_num,
            err_msg("Wrong order? from: " SIZE_FORMAT ", to: "SIZE_FORMAT,
                    from_card_num, to_card_num));
-    assert(to_card_num <= _committed_max_card_num,
-           err_msg("to card num out of range: "
-                   "to: "SIZE_FORMAT ", "
-                   "max: "SIZE_FORMAT,
-                   to_card_num, _committed_max_card_num));
-
-    to_card_num = MIN2(_committed_max_card_num, to_card_num);
-
     Copy::fill_to_bytes(&_card_counts[from_card_num], (to_card_num - from_card_num));
   }
 }
 
 G1CardCounts::G1CardCounts(G1CollectedHeap *g1h):
-  _g1h(g1h), _card_counts(NULL),
-  _reserved_max_card_num(0), _committed_max_card_num(0),
-  _committed_size(0) {}
+  _listener(), _g1h(g1h), _card_counts(NULL), _reserved_max_card_num(0) {
+  _listener.set_cardcounts(this);
+}
 
-void G1CardCounts::initialize() {
+void G1CardCounts::initialize(G1RegionToSpaceMapper* mapper) {
   assert(_g1h->max_capacity() > 0, "initialization order");
   assert(_g1h->capacity() == 0, "initialization order");
 
@@ -70,70 +65,9 @@
     _ct_bs = _g1h->g1_barrier_set();
     _ct_bot = _ct_bs->byte_for_const(_g1h->reserved_region().start());
 
-    // Allocate/Reserve the counts table
-    size_t reserved_bytes = _g1h->max_capacity();
-    _reserved_max_card_num = reserved_bytes >> CardTableModRefBS::card_shift;
-
-    size_t reserved_size = _reserved_max_card_num * sizeof(jbyte);
-    ReservedSpace rs(ReservedSpace::allocation_align_size_up(reserved_size));
-    if (!rs.is_reserved()) {
-      warning("Could not reserve enough space for the card counts table");
-      guarantee(!has_reserved_count_table(), "should be NULL");
-      return;
-    }
-
-    MemTracker::record_virtual_memory_type((address)rs.base(), mtGC);
-
-    _card_counts_storage.initialize(rs, 0);
-    _card_counts = (jubyte*) _card_counts_storage.low();
-  }
-}
-
-void G1CardCounts::resize(size_t heap_capacity) {
-  // Expand the card counts table to handle a heap with the given capacity.
-
-  if (!has_reserved_count_table()) {
-    // Don't expand if we failed to reserve the card counts table.
-    return;
-  }
-
-  assert(_committed_size ==
-         ReservedSpace::allocation_align_size_up(_committed_size),
-         err_msg("Unaligned? committed_size: " SIZE_FORMAT, _committed_size));
-
-  // Verify that the committed space for the card counts matches our
-  // committed max card num. Note for some allocation alignments, the
-  // amount of space actually committed for the counts table will be able
-  // to span more cards than the number spanned by the maximum heap.
-  size_t prev_committed_size = _committed_size;
-  size_t prev_committed_card_num = committed_to_card_num(prev_committed_size);
-
-  assert(prev_committed_card_num == _committed_max_card_num,
-         err_msg("Card mismatch: "
-                 "prev: " SIZE_FORMAT ", "
-                 "committed: "SIZE_FORMAT", "
-                 "reserved: "SIZE_FORMAT,
-                 prev_committed_card_num, _committed_max_card_num, _reserved_max_card_num));
-
-  size_t new_size = (heap_capacity >> CardTableModRefBS::card_shift) * sizeof(jbyte);
-  size_t new_committed_size = ReservedSpace::allocation_align_size_up(new_size);
-  size_t new_committed_card_num = committed_to_card_num(new_committed_size);
-
-  if (_committed_max_card_num < new_committed_card_num) {
-    // we need to expand the backing store for the card counts
-    size_t expand_size = new_committed_size - prev_committed_size;
-
-    if (!_card_counts_storage.expand_by(expand_size)) {
-      warning("Card counts table backing store commit failure");
-      return;
-    }
-    assert(_card_counts_storage.committed_size() == new_committed_size,
-           "expansion commit failure");
-
-    _committed_size = new_committed_size;
-    _committed_max_card_num = new_committed_card_num;
-
-    clear_range(prev_committed_card_num, _committed_max_card_num);
+    _card_counts = (jubyte*) mapper->reserved().start();
+    _reserved_max_card_num = mapper->reserved().byte_size();
+    mapper->set_mapping_changed_listener(&_listener);
   }
 }
 
@@ -149,12 +83,13 @@
   uint count = 0;
   if (has_count_table()) {
     size_t card_num = ptr_2_card_num(card_ptr);
-    if (card_num < _committed_max_card_num) {
-      count = (uint) _card_counts[card_num];
-      if (count < G1ConcRSHotCardLimit) {
-        _card_counts[card_num] =
-          (jubyte)(MIN2((uintx)(_card_counts[card_num] + 1), G1ConcRSHotCardLimit));
-      }
+    assert(card_num < _reserved_max_card_num,
+           err_msg("Card "SIZE_FORMAT" outside of card counts table (max size "SIZE_FORMAT")",
+                   card_num, _reserved_max_card_num));
+    count = (uint) _card_counts[card_num];
+    if (count < G1ConcRSHotCardLimit) {
+      _card_counts[card_num] =
+        (jubyte)(MIN2((uintx)(_card_counts[card_num] + 1), G1ConcRSHotCardLimit));
     }
   }
   return count;
@@ -165,31 +100,23 @@
 }
 
 void G1CardCounts::clear_region(HeapRegion* hr) {
-  assert(!hr->isHumongous(), "Should have been cleared");
-  if (has_count_table()) {
-    HeapWord* bottom = hr->bottom();
+  MemRegion mr(hr->bottom(), hr->end());
+  clear_range(mr);
+}
 
-    // We use the last address in hr as hr could be the
-    // last region in the heap. In which case trying to find
-    // the card for hr->end() will be an OOB accesss to the
-    // card table.
-    HeapWord* last = hr->end() - 1;
-    assert(_g1h->g1_committed().contains(last),
-           err_msg("last not in committed: "
-                   "last: " PTR_FORMAT ", "
-                   "committed: [" PTR_FORMAT ", " PTR_FORMAT ")",
-                   last,
-                   _g1h->g1_committed().start(),
-                   _g1h->g1_committed().end()));
-
-    const jbyte* from_card_ptr = _ct_bs->byte_for_const(bottom);
-    const jbyte* last_card_ptr = _ct_bs->byte_for_const(last);
+void G1CardCounts::clear_range(MemRegion mr) {
+  if (has_count_table()) {
+    const jbyte* from_card_ptr = _ct_bs->byte_for_const(mr.start());
+    // We use the last address in the range as the range could represent the
+    // last region in the heap. In which case trying to find the card will be an
+    // OOB access to the card table.
+    const jbyte* last_card_ptr = _ct_bs->byte_for_const(mr.last());
 
 #ifdef ASSERT
     HeapWord* start_addr = _ct_bs->addr_for(from_card_ptr);
-    assert(start_addr == hr->bottom(), "alignment");
+    assert(start_addr == mr.start(), "MemRegion start must be aligned to a card.");
     HeapWord* last_addr = _ct_bs->addr_for(last_card_ptr);
-    assert((last_addr + CardTableModRefBS::card_size_in_words) == hr->end(), "alignment");
+    assert((last_addr + CardTableModRefBS::card_size_in_words) == mr.end(), "MemRegion end must be aligned to a card.");
 #endif // ASSERT
 
     // Clear the counts for the (exclusive) card range.
@@ -199,14 +126,22 @@
   }
 }
 
+class G1CardCountsClearClosure : public HeapRegionClosure {
+ private:
+  G1CardCounts* _card_counts;
+ public:
+  G1CardCountsClearClosure(G1CardCounts* card_counts) :
+    HeapRegionClosure(), _card_counts(card_counts) { }
+
+
+  virtual bool doHeapRegion(HeapRegion* r) {
+    _card_counts->clear_region(r);
+    return false;
+  }
+};
+
 void G1CardCounts::clear_all() {
   assert(SafepointSynchronize::is_at_safepoint(), "don't call this otherwise");
-  clear_range((size_t)0, _committed_max_card_num);
+  G1CardCountsClearClosure cl(this);
+  _g1h->heap_region_iterate(&cl);
 }
-
-G1CardCounts::~G1CardCounts() {
-  if (has_reserved_count_table()) {
-    _card_counts_storage.release();
-  }
-}
-
--- a/src/share/vm/gc_implementation/g1/g1CardCounts.hpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/gc_implementation/g1/g1CardCounts.hpp	Fri Sep 05 06:26:44 2014 -0400
@@ -25,14 +25,26 @@
 #ifndef SHARE_VM_GC_IMPLEMENTATION_G1_G1CARDCOUNTS_HPP
 #define SHARE_VM_GC_IMPLEMENTATION_G1_G1CARDCOUNTS_HPP
 
+#include "gc_implementation/g1/g1RegionToSpaceMapper.hpp"
 #include "memory/allocation.hpp"
 #include "runtime/virtualspace.hpp"
 #include "utilities/globalDefinitions.hpp"
 
 class CardTableModRefBS;
+class G1CardCounts;
 class G1CollectedHeap;
+class G1RegionToSpaceMapper;
 class HeapRegion;
 
+class G1CardCountsMappingChangedListener : public G1MappingChangedListener {
+ private:
+  G1CardCounts* _counts;
+ public:
+  void set_cardcounts(G1CardCounts* counts) { _counts = counts; }
+
+  virtual void on_commit(uint start_idx, size_t num_regions);
+};
+
 // Table to track the number of times a card has been refined. Once
 // a card has been refined a certain number of times, it is
 // considered 'hot' and its refinement is delayed by inserting the
@@ -41,6 +53,8 @@
 // is 'drained' during the next evacuation pause.
 
 class G1CardCounts: public CHeapObj<mtGC> {
+  G1CardCountsMappingChangedListener _listener;
+
   G1CollectedHeap* _g1h;
 
   // The table of counts
@@ -49,27 +63,18 @@
   // Max capacity of the reserved space for the counts table
   size_t _reserved_max_card_num;
 
-  // Max capacity of the committed space for the counts table
-  size_t _committed_max_card_num;
-
-  // Size of committed space for the counts table
-  size_t _committed_size;
-
   // CardTable bottom.
   const jbyte* _ct_bot;
 
   // Barrier set
   CardTableModRefBS* _ct_bs;
 
-  // The virtual memory backing the counts table
-  VirtualSpace _card_counts_storage;
-
   // Returns true if the card counts table has been reserved.
   bool has_reserved_count_table() { return _card_counts != NULL; }
 
   // Returns true if the card counts table has been reserved and committed.
   bool has_count_table() {
-    return has_reserved_count_table() && _committed_max_card_num > 0;
+    return has_reserved_count_table();
   }
 
   size_t ptr_2_card_num(const jbyte* card_ptr) {
@@ -79,37 +84,24 @@
                    "_ct_bot: " PTR_FORMAT,
                    p2i(card_ptr), p2i(_ct_bot)));
     size_t card_num = pointer_delta(card_ptr, _ct_bot, sizeof(jbyte));
-    assert(card_num >= 0 && card_num < _committed_max_card_num,
+    assert(card_num >= 0 && card_num < _reserved_max_card_num,
            err_msg("card pointer out of range: " PTR_FORMAT, p2i(card_ptr)));
     return card_num;
   }
 
   jbyte* card_num_2_ptr(size_t card_num) {
-    assert(card_num >= 0 && card_num < _committed_max_card_num,
+    assert(card_num >= 0 && card_num < _reserved_max_card_num,
            err_msg("card num out of range: "SIZE_FORMAT, card_num));
     return (jbyte*) (_ct_bot + card_num);
   }
 
-  // Helper routine.
-  // Returns the number of cards that can be counted by the given committed
-  // table size, with a maximum of the number of cards spanned by the max
-  // capacity of the heap.
-  size_t committed_to_card_num(size_t committed_size) {
-    return MIN2(_reserved_max_card_num, committed_size / sizeof(jbyte));
-  }
-
   // Clear the counts table for the given (exclusive) index range.
   void clear_range(size_t from_card_num, size_t to_card_num);
 
  public:
   G1CardCounts(G1CollectedHeap* g1h);
-  ~G1CardCounts();
 
-  void initialize();
-
-  // Resize the committed space for the card counts table in
-  // response to a resize of the committed space for the heap.
-  void resize(size_t heap_capacity);
+  void initialize(G1RegionToSpaceMapper* mapper);
 
   // Increments the refinement count for the given card.
   // Returns the pre-increment count value.
@@ -122,8 +114,10 @@
   // Clears the card counts for the cards spanned by the region
   void clear_region(HeapRegion* hr);
 
+  // Clears the card counts for the cards spanned by the MemRegion
+  void clear_range(MemRegion mr);
+
   // Clear the entire card counts table during GC.
-  // Updates the policy stats with the duration.
   void clear_all();
 };
 
--- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -43,12 +43,13 @@
 #include "gc_implementation/g1/g1MarkSweep.hpp"
 #include "gc_implementation/g1/g1OopClosures.inline.hpp"
 #include "gc_implementation/g1/g1ParScanThreadState.inline.hpp"
+#include "gc_implementation/g1/g1RegionToSpaceMapper.hpp"
 #include "gc_implementation/g1/g1RemSet.inline.hpp"
 #include "gc_implementation/g1/g1StringDedup.hpp"
 #include "gc_implementation/g1/g1YCTypes.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/heapRegionSet.inline.hpp"
 #include "gc_implementation/g1/vm_operations_g1.hpp"
 #include "gc_implementation/shared/gcHeapSummary.hpp"
 #include "gc_implementation/shared/gcTimer.hpp"
@@ -377,6 +378,14 @@
   gclog_or_tty->cr();
 }
 
+void G1RegionMappingChangedListener::reset_from_card_cache(uint start_idx, size_t num_regions) {
+  OtherRegionsTable::invalidate(start_idx, num_regions);
+}
+
+void G1RegionMappingChangedListener::on_commit(uint start_idx, size_t num_regions) {
+  reset_from_card_cache(start_idx, num_regions);
+}
+
 void G1CollectedHeap::push_dirty_cards_region(HeapRegion* hr)
 {
   // Claim the right to put the region on the dirty cards region list
@@ -442,24 +451,18 @@
 // implementation of is_scavengable() for G1 will indicate that
 // all nmethods must be scanned during a partial collection.
 bool G1CollectedHeap::is_in_partial_collection(const void* p) {
-  HeapRegion* hr = heap_region_containing(p);
-  return hr != NULL && hr->in_collection_set();
+  if (p == NULL) {
+    return false;
+  }
+  return heap_region_containing(p)->in_collection_set();
 }
 #endif
 
 // Returns true if the reference points to an object that
 // can move in an incremental collection.
 bool G1CollectedHeap::is_scavengable(const void* p) {
-  G1CollectedHeap* g1h = G1CollectedHeap::heap();
-  G1CollectorPolicy* g1p = g1h->g1_policy();
   HeapRegion* hr = heap_region_containing(p);
-  if (hr == NULL) {
-     // null
-     assert(p == NULL, err_msg("Not NULL " PTR_FORMAT ,p));
-     return false;
-  } else {
-    return !hr->isHumongous();
-  }
+  return !hr->isHumongous();
 }
 
 void G1CollectedHeap::check_ct_logs_at_safepoint() {
@@ -525,9 +528,9 @@
       // again to allocate from it.
       append_secondary_free_list();
 
-      assert(!_free_list.is_empty(), "if the secondary_free_list was not "
+      assert(_hrs.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 = _free_list.remove_region(is_old);
+      HeapRegion* res = _hrs.allocate_free_region(is_old);
       if (G1ConcRegionFreeingVerbose) {
         gclog_or_tty->print_cr("G1ConcRegionFreeing [region alloc] : "
                                "allocated "HR_FORMAT" from secondary_free_list",
@@ -568,7 +571,7 @@
     }
   }
 
-  res = _free_list.remove_region(is_old);
+  res = _hrs.allocate_free_region(is_old);
 
   if (res == NULL) {
     if (G1ConcRegionFreeingVerbose) {
@@ -593,8 +596,8 @@
       // Given that expand() succeeded in expanding the heap, and we
       // 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 remove_region() will check for NULL.
-      res = _free_list.remove_region(is_old);
+      // In either case allocate_free_region() will check for NULL.
+      res = _hrs.allocate_free_region(is_old);
     } else {
       _expand_heap_after_alloc_failure = false;
     }
@@ -602,55 +605,11 @@
   return res;
 }
 
-uint G1CollectedHeap::humongous_obj_allocate_find_first(uint num_regions,
-                                                        size_t word_size) {
-  assert(isHumongous(word_size), "word_size should be humongous");
-  assert(num_regions * HeapRegion::GrainWords >= word_size, "pre-condition");
-
-  uint first = G1_NULL_HRS_INDEX;
-  if (num_regions == 1) {
-    // Only one region to allocate, no need to go through the slower
-    // path. The caller will attempt the expansion if this fails, so
-    // let's not try to expand here too.
-    HeapRegion* hr = new_region(word_size, true /* is_old */, false /* do_expand */);
-    if (hr != NULL) {
-      first = hr->hrs_index();
-    } else {
-      first = G1_NULL_HRS_INDEX;
-    }
-  } else {
-    // We can't allocate humongous regions while cleanupComplete() is
-    // running, since some of the regions we find to be empty might not
-    // yet be added to the free list and it is not straightforward to
-    // know which list they are on so that we can remove them. Note
-    // that we only need to do this if we need to allocate more than
-    // one region to satisfy the current humongous allocation
-    // request. If we are only allocating one region we use the common
-    // region allocation code (see above).
-    wait_while_free_regions_coming();
-    append_secondary_free_list_if_not_empty_with_lock();
-
-    if (free_regions() >= num_regions) {
-      first = _hrs.find_contiguous(num_regions);
-      if (first != G1_NULL_HRS_INDEX) {
-        for (uint i = first; i < first + num_regions; ++i) {
-          HeapRegion* hr = region_at(i);
-          assert(hr->is_empty(), "sanity");
-          assert(is_on_master_free_list(hr), "sanity");
-          hr->set_pending_removal(true);
-        }
-        _free_list.remove_all_pending(num_regions);
-      }
-    }
-  }
-  return first;
-}
-
 HeapWord*
 G1CollectedHeap::humongous_obj_allocate_initialize_regions(uint first,
                                                            uint num_regions,
                                                            size_t word_size) {
-  assert(first != G1_NULL_HRS_INDEX, "pre-condition");
+  assert(first != G1_NO_HRS_INDEX, "pre-condition");
   assert(isHumongous(word_size), "word_size should be humongous");
   assert(num_regions * HeapRegion::GrainWords >= word_size, "pre-condition");
 
@@ -788,42 +747,70 @@
 
   verify_region_sets_optional();
 
-  size_t word_size_rounded = round_to(word_size, HeapRegion::GrainWords);
-  uint num_regions = (uint) (word_size_rounded / HeapRegion::GrainWords);
-  uint x_num = expansion_regions();
-  uint fs = _hrs.free_suffix();
-  uint first = humongous_obj_allocate_find_first(num_regions, word_size);
-  if (first == G1_NULL_HRS_INDEX) {
-    // The only thing we can do now is attempt expansion.
-    if (fs + x_num >= num_regions) {
-      // If the number of regions we're trying to allocate for this
-      // object is at most the number of regions in the free suffix,
-      // then the call to humongous_obj_allocate_find_first() above
-      // should have succeeded and we wouldn't be here.
-      //
-      // We should only be trying to expand when the free suffix is
-      // not sufficient for the object _and_ we have some expansion
-      // room available.
-      assert(num_regions > fs, "earlier allocation should have succeeded");
-
+  uint first = G1_NO_HRS_INDEX;
+  uint obj_regions = (uint)(align_size_up_(word_size, HeapRegion::GrainWords) / HeapRegion::GrainWords);
+
+  if (obj_regions == 1) {
+    // Only one region to allocate, try to use a fast path by directly allocating
+    // from the free lists. Do not try to expand here, we will potentially do that
+    // later.
+    HeapRegion* hr = new_region(word_size, true /* is_old */, false /* do_expand */);
+    if (hr != NULL) {
+      first = hr->hrs_index();
+    }
+  } else {
+    // We can't allocate humongous regions spanning more than one region while
+    // cleanupComplete() is running, since some of the regions we find to be
+    // empty might not yet be added to the free list. It is not straightforward
+    // to know in which list they are on so that we can remove them. We only
+    // need to do this if we need to allocate more than one region to satisfy the
+    // current humongous allocation request. If we are only allocating one region
+    // we use the one-region region allocation code (see above), that already
+    // potentially waits for regions from the secondary free list.
+    wait_while_free_regions_coming();
+    append_secondary_free_list_if_not_empty_with_lock();
+
+    // 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) {
+    // 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) {
+      // We found something. Make sure these regions are committed, i.e. expand
+      // the heap. Alternatively we could do a defragmentation GC.
       ergo_verbose1(ErgoHeapSizing,
                     "attempt heap expansion",
                     ergo_format_reason("humongous allocation request failed")
                     ergo_format_byte("allocation request"),
                     word_size * HeapWordSize);
-      if (expand((num_regions - fs) * HeapRegion::GrainBytes)) {
-        // Even though the heap was expanded, it might not have
-        // reached the desired size. So, we cannot assume that the
-        // allocation will succeed.
-        first = humongous_obj_allocate_find_first(num_regions, word_size);
+
+      _hrs.expand_at(first, obj_regions);
+      g1_policy()->record_new_heap_size(num_regions());
+
+#ifdef ASSERT
+      for (uint i = first; i < first + obj_regions; ++i) {
+        HeapRegion* hr = region_at(i);
+        assert(hr->is_empty(), "sanity");
+        assert(is_on_master_free_list(hr), "sanity");
       }
+#endif
+      _hrs.allocate_free_regions_starting_at(first, obj_regions);
+    } else {
+      // Policy: Potentially trigger a defragmentation GC.
     }
   }
 
   HeapWord* result = NULL;
-  if (first != G1_NULL_HRS_INDEX) {
-    result =
-      humongous_obj_allocate_initialize_regions(first, num_regions, word_size);
+  if (first != G1_NO_HRS_INDEX) {
+    result = humongous_obj_allocate_initialize_regions(first, obj_regions, word_size);
     assert(result != NULL, "it should always return a valid result");
 
     // A successful humongous object allocation changes the used space
@@ -1386,7 +1373,7 @@
         G1MarkSweep::invoke_at_safepoint(ref_processor_stw(), do_clear_all_soft_refs);
       }
 
-      assert(free_regions() == 0, "we should not have added any free regions");
+      assert(num_free_regions() == 0, "we should not have added any free regions");
       rebuild_region_sets(false /* free_list_only */);
 
       // Enqueue any discovered reference objects that have
@@ -1751,21 +1738,6 @@
   return NULL;
 }
 
-void G1CollectedHeap::update_committed_space(HeapWord* old_end,
-                                             HeapWord* new_end) {
-  assert(old_end != new_end, "don't call this otherwise");
-  assert((HeapWord*) _g1_storage.high() == new_end, "invariant");
-
-  // Update the committed mem region.
-  _g1_committed.set_end(new_end);
-  // Tell the card table about the update.
-  Universe::heap()->barrier_set()->resize_covered_region(_g1_committed);
-  // Tell the BOT about the update.
-  _bot_shared->resize(_g1_committed.word_size());
-  // Tell the hot card cache about the update
-  _cg1r->hot_card_cache()->resize_card_counts(capacity());
-}
-
 bool G1CollectedHeap::expand(size_t expand_bytes) {
   size_t aligned_expand_bytes = ReservedSpace::page_align_size_up(expand_bytes);
   aligned_expand_bytes = align_size_up(aligned_expand_bytes,
@@ -1776,55 +1748,22 @@
                 ergo_format_byte("attempted expansion amount"),
                 expand_bytes, aligned_expand_bytes);
 
-  if (_g1_storage.uncommitted_size() == 0) {
+  if (is_maximal_no_gc()) {
     ergo_verbose0(ErgoHeapSizing,
                       "did not expand the heap",
                       ergo_format_reason("heap already fully expanded"));
     return false;
   }
 
-  // First commit the memory.
-  HeapWord* old_end = (HeapWord*) _g1_storage.high();
-  bool successful = _g1_storage.expand_by(aligned_expand_bytes);
-  if (successful) {
-    // Then propagate this update to the necessary data structures.
-    HeapWord* new_end = (HeapWord*) _g1_storage.high();
-    update_committed_space(old_end, new_end);
-
-    FreeRegionList expansion_list("Local Expansion List");
-    MemRegion mr = _hrs.expand_by(old_end, new_end, &expansion_list);
-    assert(mr.start() == old_end, "post-condition");
-    // mr might be a smaller region than what was requested if
-    // expand_by() was unable to allocate the HeapRegion instances
-    assert(mr.end() <= new_end, "post-condition");
-
-    size_t actual_expand_bytes = mr.byte_size();
+  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);
+
+  if (expanded_by > 0) {
+    size_t actual_expand_bytes = expanded_by * HeapRegion::GrainBytes;
     assert(actual_expand_bytes <= aligned_expand_bytes, "post-condition");
-    assert(actual_expand_bytes == expansion_list.total_capacity_bytes(),
-           "post-condition");
-    if (actual_expand_bytes < aligned_expand_bytes) {
-      // We could not expand _hrs to the desired size. In this case we
-      // need to shrink the committed space accordingly.
-      assert(mr.end() < new_end, "invariant");
-
-      size_t diff_bytes = aligned_expand_bytes - actual_expand_bytes;
-      // First uncommit the memory.
-      _g1_storage.shrink_by(diff_bytes);
-      // Then propagate this update to the necessary data structures.
-      update_committed_space(new_end, mr.end());
-    }
-    _free_list.add_as_tail(&expansion_list);
-
-    if (_hr_printer.is_active()) {
-      HeapWord* curr = mr.start();
-      while (curr < mr.end()) {
-        HeapWord* curr_end = curr + HeapRegion::GrainWords;
-        _hr_printer.commit(curr, curr_end);
-        curr = curr_end;
-      }
-      assert(curr == mr.end(), "post-condition");
-    }
-    g1_policy()->record_new_heap_size(n_regions());
+    g1_policy()->record_new_heap_size(num_regions());
   } else {
     ergo_verbose0(ErgoHeapSizing,
                   "did not expand the heap",
@@ -1832,12 +1771,12 @@
     // The expansion of the virtual storage space was unsuccessful.
     // Let's see if it was because we ran out of swap.
     if (G1ExitOnExpansionFailure &&
-        _g1_storage.uncommitted_size() >= aligned_expand_bytes) {
+        _hrs.available() >= regions_to_expand) {
       // We had head room...
       vm_exit_out_of_memory(aligned_expand_bytes, OOM_MMAP_ERROR, "G1 heap expansion");
     }
   }
-  return successful;
+  return regions_to_expand > 0;
 }
 
 void G1CollectedHeap::shrink_helper(size_t shrink_bytes) {
@@ -1848,7 +1787,6 @@
   uint num_regions_to_remove = (uint)(shrink_bytes / HeapRegion::GrainBytes);
 
   uint num_regions_removed = _hrs.shrink_by(num_regions_to_remove);
-  HeapWord* old_end = (HeapWord*) _g1_storage.high();
   size_t shrunk_bytes = num_regions_removed * HeapRegion::GrainBytes;
 
   ergo_verbose3(ErgoHeapSizing,
@@ -1858,22 +1796,7 @@
                 ergo_format_byte("attempted shrinking amount"),
                 shrink_bytes, aligned_shrink_bytes, shrunk_bytes);
   if (num_regions_removed > 0) {
-    _g1_storage.shrink_by(shrunk_bytes);
-    HeapWord* new_end = (HeapWord*) _g1_storage.high();
-
-    if (_hr_printer.is_active()) {
-      HeapWord* curr = old_end;
-      while (curr > new_end) {
-        HeapWord* curr_end = curr;
-        curr -= HeapRegion::GrainWords;
-        _hr_printer.uncommit(curr, curr_end);
-      }
-    }
-
-    _expansion_regions += num_regions_removed;
-    update_committed_space(old_end, new_end);
-    HeapRegionRemSet::shrink_heap(n_regions());
-    g1_policy()->record_new_heap_size(n_regions());
+    g1_policy()->record_new_heap_size(num_regions());
   } else {
     ergo_verbose0(ErgoHeapSizing,
                   "did not shrink the heap",
@@ -1924,7 +1847,6 @@
   _g1mm(NULL),
   _refine_cte_cl(NULL),
   _full_collection(false),
-  _free_list("Master Free List", new MasterFreeRegionListMtSafeChecker()),
   _secondary_free_list("Secondary Free List", new SecondaryFreeRegionListMtSafeChecker()),
   _old_set("Old Set", false /* humongous */, new OldRegionSetMtSafeChecker()),
   _humongous_set("Master Humongous Set", true /* humongous */, new HumongousRegionSetMtSafeChecker()),
@@ -2038,8 +1960,6 @@
   _reserved.set_start((HeapWord*)heap_rs.base());
   _reserved.set_end((HeapWord*)(heap_rs.base() + heap_rs.size()));
 
-  _expansion_regions = (uint) (max_byte_size / HeapRegion::GrainBytes);
-
   // Create the gen rem set (and barrier set) for the entire reserved region.
   _rem_set = collector_policy()->create_rem_set(_reserved, 2);
   set_barrier_set(rem_set()->bs());
@@ -2053,20 +1973,65 @@
 
   // Carve out the G1 part of the heap.
 
-  ReservedSpace g1_rs   = heap_rs.first_part(max_byte_size);
-  _g1_reserved = MemRegion((HeapWord*)g1_rs.base(),
-                           g1_rs.size()/HeapWordSize);
-
-  _g1_storage.initialize(g1_rs, 0);
-  _g1_committed = MemRegion((HeapWord*)_g1_storage.low(), (size_t) 0);
-  _hrs.initialize((HeapWord*) _g1_reserved.start(),
-                  (HeapWord*) _g1_reserved.end());
-  assert(_hrs.max_length() == _expansion_regions,
-         err_msg("max length: %u expansion regions: %u",
-                 _hrs.max_length(), _expansion_regions));
-
-  // Do later initialization work for concurrent refinement.
-  _cg1r->init();
+  ReservedSpace g1_rs = heap_rs.first_part(max_byte_size);
+  G1RegionToSpaceMapper* heap_storage =
+    G1RegionToSpaceMapper::create_mapper(g1_rs,
+                                         UseLargePages ? os::large_page_size() : os::vm_page_size(),
+                                         HeapRegion::GrainBytes,
+                                         1,
+                                         mtJavaHeap);
+  heap_storage->set_mapping_changed_listener(&_listener);
+
+  // Reserve space for the block offset table. We do not support automatic uncommit
+  // for the card table at this time. BOT only.
+  ReservedSpace bot_rs(G1BlockOffsetSharedArray::compute_size(g1_rs.size() / HeapWordSize));
+  G1RegionToSpaceMapper* bot_storage =
+    G1RegionToSpaceMapper::create_mapper(bot_rs,
+                                         os::vm_page_size(),
+                                         HeapRegion::GrainBytes,
+                                         G1BlockOffsetSharedArray::N_bytes,
+                                         mtGC);
+
+  ReservedSpace cardtable_rs(G1SATBCardTableLoggingModRefBS::compute_size(g1_rs.size() / HeapWordSize));
+  G1RegionToSpaceMapper* cardtable_storage =
+    G1RegionToSpaceMapper::create_mapper(cardtable_rs,
+                                         os::vm_page_size(),
+                                         HeapRegion::GrainBytes,
+                                         G1BlockOffsetSharedArray::N_bytes,
+                                         mtGC);
+
+  // Reserve space for the card counts table.
+  ReservedSpace card_counts_rs(G1BlockOffsetSharedArray::compute_size(g1_rs.size() / HeapWordSize));
+  G1RegionToSpaceMapper* card_counts_storage =
+    G1RegionToSpaceMapper::create_mapper(card_counts_rs,
+                                         os::vm_page_size(),
+                                         HeapRegion::GrainBytes,
+                                         G1BlockOffsetSharedArray::N_bytes,
+                                         mtGC);
+
+  // Reserve space for prev and next bitmap.
+  size_t bitmap_size = CMBitMap::compute_size(g1_rs.size());
+
+  ReservedSpace prev_bitmap_rs(ReservedSpace::allocation_align_size_up(bitmap_size));
+  G1RegionToSpaceMapper* prev_bitmap_storage =
+    G1RegionToSpaceMapper::create_mapper(prev_bitmap_rs,
+                                         os::vm_page_size(),
+                                         HeapRegion::GrainBytes,
+                                         CMBitMap::mark_distance(),
+                                         mtGC);
+
+  ReservedSpace next_bitmap_rs(ReservedSpace::allocation_align_size_up(bitmap_size));
+  G1RegionToSpaceMapper* next_bitmap_storage =
+    G1RegionToSpaceMapper::create_mapper(next_bitmap_rs,
+                                         os::vm_page_size(),
+                                         HeapRegion::GrainBytes,
+                                         CMBitMap::mark_distance(),
+                                         mtGC);
+
+  _hrs.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);
 
   // 6843694 - ensure that the maximum region index can fit
   // in the remembered set structures.
@@ -2080,17 +2045,16 @@
 
   FreeRegionList::set_unrealistically_long_length(max_regions() + 1);
 
-  _bot_shared = new G1BlockOffsetSharedArray(_reserved,
-                                             heap_word_size(init_byte_size));
+  _bot_shared = new G1BlockOffsetSharedArray(_reserved, bot_storage);
 
   _g1h = this;
 
-  _in_cset_fast_test.initialize(_g1_reserved.start(), _g1_reserved.end(), HeapRegion::GrainBytes);
-  _humongous_is_live.initialize(_g1_reserved.start(), _g1_reserved.end(), HeapRegion::GrainBytes);
+  _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);
 
   // Create the ConcurrentMark data structure and thread.
   // (Must do this late, so that "max_regions" is defined.)
-  _cm = new ConcurrentMark(this, heap_rs);
+  _cm = new ConcurrentMark(this, prev_bitmap_storage, next_bitmap_storage);
   if (_cm == NULL || !_cm->completed_initialization()) {
     vm_shutdown_during_initialization("Could not create/initialize ConcurrentMark");
     return JNI_ENOMEM;
@@ -2145,12 +2109,10 @@
   // counts and that mechanism.
   SpecializationStats::clear();
 
-  // Here we allocate the dummy full region that is required by the
-  // G1AllocRegion class. If we don't pass an address in the reserved
-  // space here, lots of asserts fire.
-
-  HeapRegion* dummy_region = new_heap_region(0 /* index of bottom region */,
-                                             _g1_reserved.start());
+  // Here we allocate the dummy HeapRegion that is required by the
+  // G1AllocRegion class.
+  HeapRegion* dummy_region = _hrs.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
   // region will complain that it cannot support allocations without
@@ -2266,7 +2228,7 @@
 }
 
 size_t G1CollectedHeap::capacity() const {
-  return _g1_committed.byte_size();
+  return _hrs.length() * HeapRegion::GrainBytes;
 }
 
 void G1CollectedHeap::reset_gc_time_stamps(HeapRegion* hr) {
@@ -2374,25 +2336,6 @@
   return blk.result();
 }
 
-size_t G1CollectedHeap::unsafe_max_alloc() {
-  if (free_regions() > 0) return HeapRegion::GrainBytes;
-  // otherwise, is there space in the current allocation region?
-
-  // We need to store the current allocation region in a local variable
-  // here. The problem is that this method doesn't take any locks and
-  // there may be other threads which overwrite the current allocation
-  // region field. attempt_allocation(), for example, sets it to NULL
-  // and this can happen *after* the NULL check here but before the call
-  // to free(), resulting in a SIGSEGV. Note that this doesn't appear
-  // to be a problem in the optimized build, since the two loads of the
-  // current allocation region field are optimized away.
-  HeapRegion* hr = _mutator_alloc_region.get();
-  if (hr == NULL) {
-    return 0;
-  }
-  return hr->free();
-}
-
 bool G1CollectedHeap::should_do_concurrent_full_gc(GCCause::Cause cause) {
   switch (cause) {
     case GCCause::_gc_locker:               return GCLockerInvokesConcurrent;
@@ -2569,7 +2512,7 @@
         }
       }
     } else {
-      if (cause == GCCause::_gc_locker
+      if (cause == GCCause::_gc_locker || cause == GCCause::_wb_young_gc
           DEBUG_ONLY(|| cause == GCCause::_scavenge_alot)) {
 
         // Schedule a standard evacuation pause. We're setting word_size
@@ -2590,8 +2533,8 @@
 }
 
 bool G1CollectedHeap::is_in(const void* p) const {
-  if (_g1_committed.contains(p)) {
-    // Given that we know that p is in the committed space,
+  if (_hrs.reserved().contains(p)) {
+    // Given that we know that p is in the reserved space,
     // heap_region_containing_raw() should successfully
     // return the containing region.
     HeapRegion* hr = heap_region_containing_raw(p);
@@ -2601,6 +2544,18 @@
   }
 }
 
+#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));
+  if (contains && available) {
+    return true;
+  } else {
+    return false;
+  }
+}
+#endif
+
 // Iteration functions.
 
 // Applies an ExtendedOopClosure onto all references of objects within a HeapRegion.
@@ -2665,83 +2620,9 @@
 void
 G1CollectedHeap::heap_region_par_iterate_chunked(HeapRegionClosure* cl,
                                                  uint worker_id,
-                                                 uint no_of_par_workers,
-                                                 jint claim_value) {
-  const uint regions = n_regions();
-  const uint max_workers = (G1CollectedHeap::use_parallel_gc_threads() ?
-                             no_of_par_workers :
-                             1);
-  assert(UseDynamicNumberOfGCThreads ||
-         no_of_par_workers == workers()->total_workers(),
-         "Non dynamic should use fixed number of workers");
-  // try to spread out the starting points of the workers
-  const HeapRegion* start_hr =
-                        start_region_for_worker(worker_id, no_of_par_workers);
-  const uint start_index = start_hr->hrs_index();
-
-  // each worker will actually look at all regions
-  for (uint count = 0; count < regions; ++count) {
-    const uint index = (start_index + count) % regions;
-    assert(0 <= index && index < regions, "sanity");
-    HeapRegion* r = region_at(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)) {
-      // success!
-      assert(!r->continuesHumongous(), "sanity");
-      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 on 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 (notice: most closures will ignore them anyway) and
-        // then we'll do the "starts humongous" region.
-        for (uint ch_index = index + 1; ch_index < regions; ++ch_index) {
-          HeapRegion* chr = region_at(ch_index);
-
-          // if the region has already been claimed or it's not
-          // "continues humongous" we're done
-          if (chr->claim_value() == claim_value ||
-              !chr->continuesHumongous()) {
-            break;
-          }
-
-          // No one should have claimed it directly. We can given
-          // that we claimed its "starts humongous" region.
-          assert(chr->claim_value() != claim_value, "sanity");
-          assert(chr->humongous_start_region() == r, "sanity");
-
-          if (chr->claimHeapRegion(claim_value)) {
-            // we should always be able to claim it; no one else should
-            // be trying to claim this region
-
-            bool res2 = cl->doHeapRegion(chr);
-            assert(!res2, "Should not abort");
-
-            // 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");
-          } else {
-            guarantee(false, "we should not reach here");
-          }
-        }
-      }
-
-      assert(!r->continuesHumongous(), "sanity");
-      bool res = cl->doHeapRegion(r);
-      assert(!res, "Should not abort");
-    }
-  }
+                                                 uint num_workers,
+                                                 jint claim_value) const {
+  _hrs.par_iterate(cl, worker_id, num_workers, claim_value);
 }
 
 class ResetClaimValuesClosure: public HeapRegionClosure {
@@ -2919,17 +2800,6 @@
   return result;
 }
 
-HeapRegion* G1CollectedHeap::start_region_for_worker(uint worker_i,
-                                                     uint no_of_par_workers) {
-  uint worker_num =
-           G1CollectedHeap::use_parallel_gc_threads() ? no_of_par_workers : 1U;
-  assert(UseDynamicNumberOfGCThreads ||
-         no_of_par_workers == workers()->total_workers(),
-         "Non dynamic should use fixed number of workers");
-  const uint start_index = n_regions() * worker_i / worker_num;
-  return region_at(start_index);
-}
-
 void G1CollectedHeap::collection_set_iterate(HeapRegionClosure* cl) {
   HeapRegion* r = g1_policy()->collection_set();
   while (r != NULL) {
@@ -2972,33 +2842,24 @@
 }
 
 HeapRegion* G1CollectedHeap::next_compaction_region(const HeapRegion* from) const {
-  // We're not using an iterator given that it will wrap around when
-  // it reaches the last region and this is not what we want here.
-  for (uint index = from->hrs_index() + 1; index < n_regions(); index++) {
-    HeapRegion* hr = region_at(index);
-    if (!hr->isHumongous()) {
-      return hr;
-    }
-  }
-  return NULL;
+  HeapRegion* result = _hrs.next_region_in_heap(from);
+  while (result != NULL && result->isHumongous()) {
+    result = _hrs.next_region_in_heap(result);
+  }
+  return result;
 }
 
 Space* G1CollectedHeap::space_containing(const void* addr) const {
-  Space* res = heap_region_containing(addr);
-  return res;
+  return heap_region_containing(addr);
 }
 
 HeapWord* G1CollectedHeap::block_start(const void* addr) const {
   Space* sp = space_containing(addr);
-  if (sp != NULL) {
-    return sp->block_start(addr);
-  }
-  return NULL;
+  return sp->block_start(addr);
 }
 
 size_t G1CollectedHeap::block_size(const HeapWord* addr) const {
   Space* sp = space_containing(addr);
-  assert(sp != NULL, "block_size of address outside of heap");
   return sp->block_size(addr);
 }
 
@@ -3043,7 +2904,7 @@
 }
 
 size_t G1CollectedHeap::max_capacity() const {
-  return _g1_reserved.byte_size();
+  return _hrs.reserved().byte_size();
 }
 
 jlong G1CollectedHeap::millis_since_last_gc() {
@@ -3572,9 +3433,9 @@
   st->print(" total " SIZE_FORMAT "K, used " SIZE_FORMAT "K",
             capacity()/K, used_unlocked()/K);
   st->print(" [" INTPTR_FORMAT ", " INTPTR_FORMAT ", " INTPTR_FORMAT ")",
-            _g1_storage.low_boundary(),
-            _g1_storage.high(),
-            _g1_storage.high_boundary());
+            _hrs.reserved().start(),
+            _hrs.reserved().start() + _hrs.length() + HeapRegion::GrainWords,
+            _hrs.reserved().end());
   st->cr();
   st->print("  region size " SIZE_FORMAT "K, ", HeapRegion::GrainBytes / K);
   uint young_regions = _young_list->length();
@@ -4264,10 +4125,7 @@
             // No need for an ergo verbose message here,
             // expansion_amount() does this when it returns a value > 0.
             if (!expand(expand_bytes)) {
-              // We failed to expand the heap so let's verify that
-              // committed/uncommitted amount match the backing store
-              assert(capacity() == _g1_storage.committed_size(), "committed size mismatch");
-              assert(max_capacity() == _g1_storage.reserved_size(), "reserved size mismatch");
+              // We failed to expand the heap. Cannot do anything about it.
             }
           }
         }
@@ -4327,10 +4185,6 @@
       // RETIRE events are generated before the end GC event.
       _hr_printer.end_gc(false /* full */, (size_t) total_collections());
 
-      if (mark_in_progress()) {
-        concurrent_mark()->update_g1_committed();
-      }
-
 #ifdef TRACESPINNING
       ParallelTaskTerminator::print_termination_counts();
 #endif
@@ -4652,30 +4506,19 @@
   ParGCAllocBuffer(gclab_word_size), _retired(true) { }
 
 void G1ParCopyHelper::mark_object(oop obj) {
-#ifdef ASSERT
-  HeapRegion* hr = _g1->heap_region_containing(obj);
-  assert(hr != NULL, "sanity");
-  assert(!hr->in_collection_set(), "should not mark objects in the CSet");
-#endif // ASSERT
+  assert(!_g1->heap_region_containing(obj)->in_collection_set(), "should not mark objects in the CSet");
 
   // We know that the object is not moving so it's safe to read its size.
   _cm->grayRoot(obj, (size_t) obj->size(), _worker_id);
 }
 
 void G1ParCopyHelper::mark_forwarded_object(oop from_obj, oop to_obj) {
-#ifdef ASSERT
   assert(from_obj->is_forwarded(), "from obj should be forwarded");
   assert(from_obj->forwardee() == to_obj, "to obj should be the forwardee");
   assert(from_obj != to_obj, "should not be self-forwarded");
 
-  HeapRegion* from_hr = _g1->heap_region_containing(from_obj);
-  assert(from_hr != NULL, "sanity");
-  assert(from_hr->in_collection_set(), "from obj should be in the CSet");
-
-  HeapRegion* to_hr = _g1->heap_region_containing(to_obj);
-  assert(to_hr != NULL, "sanity");
-  assert(!to_hr->in_collection_set(), "should not mark objects in the CSet");
-#endif // ASSERT
+  assert(_g1->heap_region_containing(from_obj)->in_collection_set(), "from obj should be in the CSet");
+  assert(!_g1->heap_region_containing(to_obj)->in_collection_set(), "should not mark objects in the CSet");
 
   // The object might be in the process of being copied by another
   // worker so we cannot trust that its to-space image is
@@ -6176,6 +6019,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(free_list != NULL, "pre-condition");
 
   if (G1VerifyBitmaps) {
@@ -6230,7 +6074,7 @@
   assert(list != NULL, "list can't be null");
   if (!list->is_empty()) {
     MutexLockerEx x(FreeList_lock, Mutex::_no_safepoint_check_flag);
-    _free_list.add_ordered(list);
+    _hrs.insert_list_into_free_list(list);
   }
 }
 
@@ -6838,22 +6682,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.
   }
-  _free_list.remove_all();
+  _hrs.remove_all_free_regions();
 }
 
 class RebuildRegionSetsClosure : public HeapRegionClosure {
 private:
   bool            _free_list_only;
   HeapRegionSet*   _old_set;
-  FreeRegionList* _free_list;
+  HeapRegionSeq*   _hrs;
   size_t          _total_used;
 
 public:
   RebuildRegionSetsClosure(bool free_list_only,
-                           HeapRegionSet* old_set, FreeRegionList* free_list) :
+                           HeapRegionSet* old_set, HeapRegionSeq* hrs) :
     _free_list_only(free_list_only),
-    _old_set(old_set), _free_list(free_list), _total_used(0) {
-    assert(_free_list->is_empty(), "pre-condition");
+    _old_set(old_set), _hrs(hrs), _total_used(0) {
+    assert(_hrs->num_free_regions() == 0, "pre-condition");
     if (!free_list_only) {
       assert(_old_set->is_empty(), "pre-condition");
     }
@@ -6866,7 +6710,7 @@
 
     if (r->is_empty()) {
       // Add free regions to the free list
-      _free_list->add_as_tail(r);
+      _hrs->insert_into_free_list(r);
     } else if (!_free_list_only) {
       assert(!r->is_young(), "we should not come across young regions");
 
@@ -6894,7 +6738,7 @@
     _young_list->empty_list();
   }
 
-  RebuildRegionSetsClosure cl(free_list_only, &_old_set, &_free_list);
+  RebuildRegionSetsClosure cl(free_list_only, &_old_set, &_hrs);
   heap_region_iterate(&cl);
 
   if (!free_list_only) {
@@ -6912,11 +6756,7 @@
 
 bool G1CollectedHeap::is_in_closed_subset(const void* p) const {
   HeapRegion* hr = heap_region_containing(p);
-  if (hr == NULL) {
-    return false;
-  } else {
-    return hr->is_in(p);
-  }
+  return hr->is_in(p);
 }
 
 // Methods for the mutator alloc region
@@ -7053,13 +6893,42 @@
   _g1h->retire_gc_alloc_region(alloc_region, allocated_bytes,
                                GCAllocForTenured);
 }
+
+HeapRegion* OldGCAllocRegion::release() {
+  HeapRegion* cur = get();
+  if (cur != NULL) {
+    // Determine how far we are from the next card boundary. If it is smaller than
+    // the minimum object size we can allocate into, expand into the next card.
+    HeapWord* top = cur->top();
+    HeapWord* aligned_top = (HeapWord*)align_ptr_up(top, G1BlockOffsetSharedArray::N_bytes);
+
+    size_t to_allocate_words = pointer_delta(aligned_top, top, HeapWordSize);
+
+    if (to_allocate_words != 0) {
+      // We are not at a card boundary. Fill up, possibly into the next, taking the
+      // end of the region and the minimum object size into account.
+      to_allocate_words = MIN2(pointer_delta(cur->end(), cur->top(), HeapWordSize),
+                               MAX2(to_allocate_words, G1CollectedHeap::min_fill_size()));
+
+      // Skip allocation if there is not enough space to allocate even the smallest
+      // possible object. In this case this region will not be retained, so the
+      // original problem cannot occur.
+      if (to_allocate_words >= G1CollectedHeap::min_fill_size()) {
+        HeapWord* dummy = attempt_allocation(to_allocate_words, true /* bot_updates */);
+        CollectedHeap::fill_with_object(dummy, to_allocate_words);
+      }
+    }
+  }
+  return G1AllocRegion::release();
+}
+
 // Heap region set verification
 
 class VerifyRegionListsClosure : public HeapRegionClosure {
 private:
   HeapRegionSet*   _old_set;
   HeapRegionSet*   _humongous_set;
-  FreeRegionList*  _free_list;
+  HeapRegionSeq*   _hrs;
 
 public:
   HeapRegionSetCount _old_count;
@@ -7068,8 +6937,8 @@
 
   VerifyRegionListsClosure(HeapRegionSet* old_set,
                            HeapRegionSet* humongous_set,
-                           FreeRegionList* free_list) :
-    _old_set(old_set), _humongous_set(humongous_set), _free_list(free_list),
+                           HeapRegionSeq* hrs) :
+    _old_set(old_set), _humongous_set(humongous_set), _hrs(hrs),
     _old_count(), _humongous_count(), _free_count(){ }
 
   bool doHeapRegion(HeapRegion* hr) {
@@ -7080,19 +6949,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->region_num()));
+      assert(hr->containing_set() == _humongous_set, err_msg("Heap region %u is starts humongous but not in humongous set.", hr->hrs_index()));
       _humongous_count.increment(1u, hr->capacity());
     } else if (hr->is_empty()) {
-      assert(hr->containing_set() == _free_list, err_msg("Heap region %u is empty but not on the free list.", hr->region_num()));
+      assert(_hrs->is_free(hr), err_msg("Heap region %u is empty but not on the free list.", hr->hrs_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->region_num()));
+      assert(hr->containing_set() == _old_set, err_msg("Heap region %u is old but not in the old set.", hr->hrs_index()));
       _old_count.increment(1u, hr->capacity());
     }
     return false;
   }
 
-  void verify_counts(HeapRegionSet* old_set, HeapRegionSet* humongous_set, FreeRegionList* free_list) {
+  void verify_counts(HeapRegionSet* old_set, HeapRegionSet* humongous_set, HeapRegionSeq* 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()));
@@ -7101,26 +6970,17 @@
     guarantee(humongous_set->total_capacity_bytes() == _humongous_count.capacity(), err_msg("Hum set capacity mismatch. Expected " SIZE_FORMAT ", actual " SIZE_FORMAT,
         humongous_set->total_capacity_bytes(), _humongous_count.capacity()));
 
-    guarantee(free_list->length() == _free_count.length(), err_msg("Free list count mismatch. Expected %u, actual %u.", free_list->length(), _free_count.length()));
+    guarantee(free_list->num_free_regions() == _free_count.length(), err_msg("Free list count mismatch. Expected %u, actual %u.", free_list->num_free_regions(), _free_count.length()));
     guarantee(free_list->total_capacity_bytes() == _free_count.capacity(), err_msg("Free list capacity mismatch. Expected " SIZE_FORMAT ", actual " SIZE_FORMAT,
         free_list->total_capacity_bytes(), _free_count.capacity()));
   }
 };
 
-HeapRegion* G1CollectedHeap::new_heap_region(uint hrs_index,
-                                             HeapWord* bottom) {
-  HeapWord* end = bottom + HeapRegion::GrainWords;
-  MemRegion mr(bottom, end);
-  assert(_g1_reserved.contains(mr), "invariant");
-  // This might return NULL if the allocation fails
-  return new HeapRegion(hrs_index, _bot_shared, mr);
-}
-
 void G1CollectedHeap::verify_region_sets() {
   assert_heap_locked_or_at_safepoint(true /* should_be_vm_thread */);
 
   // First, check the explicit lists.
-  _free_list.verify_list();
+  _hrs.verify();
   {
     // Given that a concurrent operation might be adding regions to
     // the secondary free list we have to take the lock before
@@ -7151,9 +7011,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, &_free_list);
+  VerifyRegionListsClosure cl(&_old_set, &_humongous_set, &_hrs);
   heap_region_iterate(&cl);
-  cl.verify_counts(&_old_set, &_humongous_set, &_free_list);
+  cl.verify_counts(&_old_set, &_humongous_set, &_hrs);
 }
 
 // Optimized nmethod scanning
--- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp	Fri Sep 05 06:26:44 2014 -0400
@@ -183,6 +183,13 @@
 public:
   OldGCAllocRegion()
   : G1AllocRegion("Old GC Alloc Region", true /* bot_updates */) { }
+
+  // This specialization of release() makes sure that the last card that has been
+  // allocated into has been completely filled by a dummy object.
+  // This avoids races when remembered set scanning wants to update the BOT of the
+  // last card in the retained old gc alloc region, and allocation threads
+  // allocating into that card at the same time.
+  virtual HeapRegion* release();
 };
 
 // The G1 STW is alive closure.
@@ -199,6 +206,13 @@
 
 class RefineCardTableEntryClosure;
 
+class G1RegionMappingChangedListener : public G1MappingChangedListener {
+ private:
+  void reset_from_card_cache(uint start_idx, size_t num_regions);
+ public:
+  virtual void on_commit(uint start_idx, size_t num_regions);
+};
+
 class G1CollectedHeap : public SharedHeap {
   friend class VM_CollectForMetadataAllocation;
   friend class VM_G1CollectForAllocation;
@@ -237,19 +251,9 @@
 
   static size_t _humongous_object_threshold_in_words;
 
-  // Storage for the G1 heap.
-  VirtualSpace _g1_storage;
-  MemRegion    _g1_reserved;
-
-  // The part of _g1_storage that is currently committed.
-  MemRegion _g1_committed;
-
-  // The master free list. It will satisfy all new region allocations.
-  FreeRegionList _free_list;
-
   // The secondary free list which contains regions that have been
-  // freed up during the cleanup process. This will be appended to the
-  // master free list when appropriate.
+  // freed up during the cleanup process. This will be appended to
+  // the master free list when appropriate.
   FreeRegionList _secondary_free_list;
 
   // It keeps track of the old regions.
@@ -283,6 +287,9 @@
   // after heap shrinking (free_list_only == true).
   void rebuild_region_sets(bool free_list_only);
 
+  // Callback for region mapping changed events.
+  G1RegionMappingChangedListener _listener;
+
   // The sequence of all heap regions in the heap.
   HeapRegionSeq _hrs;
 
@@ -513,14 +520,6 @@
   // humongous object, set is_old to true. If not, to false.
   HeapRegion* new_region(size_t word_size, bool is_old, bool do_expand);
 
-  // Attempt to satisfy a humongous allocation request of the given
-  // size by finding a contiguous set of free regions of num_regions
-  // length and remove them from the master free list. Return the
-  // index of the first region or G1_NULL_HRS_INDEX if the search
-  // was unsuccessful.
-  uint humongous_obj_allocate_find_first(uint num_regions,
-                                         size_t word_size);
-
   // Initialize a contiguous set of free regions of length num_regions
   // and starting at index first so that they appear as a single
   // humongous region.
@@ -862,11 +861,6 @@
                         CodeBlobClosure* scan_strong_code,
                         uint worker_i);
 
-  // Notifies all the necessary spaces that the committed space has
-  // been updated (either expanded or shrunk). It should be called
-  // after _g1_storage is updated.
-  void update_committed_space(HeapWord* old_end, HeapWord* new_end);
-
   // The concurrent marker (and the thread it runs in.)
   ConcurrentMark* _cm;
   ConcurrentMarkThread* _cmThread;
@@ -1176,37 +1170,21 @@
   // end fields defining the extent of the contiguous allocation region.)
   // But G1CollectedHeap doesn't yet support this.
 
-  // Return an estimate of the maximum allocation that could be performed
-  // without triggering any collection or expansion activity.  In a
-  // generational collector, for example, this is probably the largest
-  // allocation that could be supported (without expansion) in the youngest
-  // generation.  It is "unsafe" because no locks are taken; the result
-  // should be treated as an approximation, not a guarantee, for use in
-  // heuristic resizing decisions.
-  virtual size_t unsafe_max_alloc();
-
   virtual bool is_maximal_no_gc() const {
-    return _g1_storage.uncommitted_size() == 0;
+    return _hrs.available() == 0;
   }
 
-  // The total number of regions in the heap.
-  uint n_regions() const { return _hrs.length(); }
+  // The current number of regions in the heap.
+  uint num_regions() const { return _hrs.length(); }
 
   // The max number of regions in the heap.
   uint max_regions() const { return _hrs.max_length(); }
 
   // The number of regions that are completely free.
-  uint free_regions() const { return _free_list.length(); }
+  uint num_free_regions() const { return _hrs.num_free_regions(); }
 
   // The number of regions that are not completely free.
-  uint used_regions() const { return n_regions() - free_regions(); }
-
-  // The number of regions available for "regular" expansion.
-  uint expansion_regions() const { return _expansion_regions; }
-
-  // Factory method for HeapRegion instances. It will return NULL if
-  // the allocation fails.
-  HeapRegion* new_heap_region(uint hrs_index, HeapWord* bottom);
+  uint num_used_regions() const { return num_regions() - num_free_regions(); }
 
   void verify_not_dirty_region(HeapRegion* hr) PRODUCT_RETURN;
   void verify_dirty_region(HeapRegion* hr) PRODUCT_RETURN;
@@ -1255,7 +1233,7 @@
 
 #ifdef ASSERT
   bool is_on_master_free_list(HeapRegion* hr) {
-    return hr->containing_set() == &_free_list;
+    return _hrs.is_free(hr);
   }
 #endif // ASSERT
 
@@ -1267,7 +1245,7 @@
   }
 
   void append_secondary_free_list() {
-    _free_list.add_ordered(&_secondary_free_list);
+    _hrs.insert_list_into_free_list(&_secondary_free_list);
   }
 
   void append_secondary_free_list_if_not_empty_with_lock() {
@@ -1313,6 +1291,11 @@
 
   // Returns "TRUE" iff "p" points into the committed areas of the heap.
   virtual bool is_in(const void* p) const;
+#ifdef ASSERT
+  // Returns whether p is in one of the available areas of the heap. Slow but
+  // extensive version.
+  bool is_in_exact(const void* p) const;
+#endif
 
   // Return "TRUE" iff the given object address is within the collection
   // set. Slow implementation.
@@ -1373,25 +1356,19 @@
   // Return "TRUE" iff the given object address is in the reserved
   // region of g1.
   bool is_in_g1_reserved(const void* p) const {
-    return _g1_reserved.contains(p);
+    return _hrs.reserved().contains(p);
   }
 
   // Returns a MemRegion that corresponds to the space that has been
   // reserved for the heap
-  MemRegion g1_reserved() {
-    return _g1_reserved;
-  }
-
-  // Returns a MemRegion that corresponds to the space that has been
-  // committed in the heap
-  MemRegion g1_committed() {
-    return _g1_committed;
+  MemRegion g1_reserved() const {
+    return _hrs.reserved();
   }
 
   virtual bool is_in_closed_subset(const void* p) const;
 
-  G1SATBCardTableModRefBS* g1_barrier_set() {
-    return (G1SATBCardTableModRefBS*) barrier_set();
+  G1SATBCardTableLoggingModRefBS* g1_barrier_set() {
+    return (G1SATBCardTableLoggingModRefBS*) barrier_set();
   }
 
   // This resets the card table to all zeros.  It is used after
@@ -1425,6 +1402,8 @@
   // within the heap.
   inline uint addr_to_region(HeapWord* addr) const;
 
+  inline HeapWord* bottom_addr_for_region(uint index) const;
+
   // Divide the heap region sequence into "chunks" of some size (the number
   // of regions divided by the number of parallel threads times some
   // overpartition factor, currently 4).  Assumes that this will be called
@@ -1438,10 +1417,10 @@
   // setting the claim value of the second and subsequent regions of the
   // chunk.)  For now requires that "doHeapRegion" always returns "false",
   // i.e., that a closure never attempt to abort a traversal.
-  void heap_region_par_iterate_chunked(HeapRegionClosure* blk,
-                                       uint worker,
-                                       uint no_of_par_workers,
-                                       jint claim_value);
+  void heap_region_par_iterate_chunked(HeapRegionClosure* cl,
+                                       uint worker_id,
+                                       uint num_workers,
+                                       jint claim_value) const;
 
   // It resets all the region claim values to the default.
   void reset_heap_region_claim_values();
@@ -1466,11 +1445,6 @@
   // starting region for iterating over the current collection set.
   HeapRegion* start_cset_region_for_worker(uint worker_i);
 
-  // This is a convenience method that is used by the
-  // HeapRegionIterator classes to calculate the starting region for
-  // each worker so that they do not all start from the same region.
-  HeapRegion* start_region_for_worker(uint worker_i, uint no_of_par_workers);
-
   // Iterate over the regions (if any) in the current collection set.
   void collection_set_iterate(HeapRegionClosure* blk);
 
@@ -1483,17 +1457,15 @@
   // space containing a given address, or else returns NULL.
   virtual Space* space_containing(const void* addr) const;
 
-  // A G1CollectedHeap will contain some number of heap regions.  This
-  // finds the region containing a given address, or else returns NULL.
+  // Returns the HeapRegion that contains addr. addr must not be NULL.
+  template <class T>
+  inline HeapRegion* heap_region_containing_raw(const T addr) const;
+
+  // Returns the HeapRegion that contains addr. addr must not be NULL.
+  // If addr is within a humongous continues region, it returns its humongous start region.
   template <class T>
   inline HeapRegion* heap_region_containing(const T addr) const;
 
-  // Like the above, but requires "addr" to be in the heap (to avoid a
-  // null-check), and unlike the above, may return an continuing humongous
-  // region.
-  template <class T>
-  inline HeapRegion* heap_region_containing_raw(const T addr) const;
-
   // A CollectedHeap is divided into a dense sequence of "blocks"; that is,
   // each address in the (reserved) heap is a member of exactly
   // one block.  The defining characteristic of a block is that it is
@@ -1635,7 +1607,6 @@
   // the region to which the object belongs. An object is dead
   // iff a) it was not allocated since the last mark and b) it
   // is not marked.
-
   bool is_obj_dead(const oop obj, const HeapRegion* hr) const {
     return
       !hr->obj_allocated_since_prev_marking(obj) &&
@@ -1645,7 +1616,6 @@
   // This function returns true when an object has been
   // around since the previous marking and hasn't yet
   // been marked during this marking.
-
   bool is_obj_ill(const oop obj, const HeapRegion* hr) const {
     return
       !hr->obj_allocated_since_next_marking(obj) &&
--- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp	Fri Sep 05 06:26:44 2014 -0400
@@ -47,23 +47,26 @@
   return (uint)(pointer_delta(addr, _reserved.start(), sizeof(uint8_t)) >> HeapRegion::LogOfHRGrainBytes);
 }
 
-template <class T>
-inline HeapRegion*
-G1CollectedHeap::heap_region_containing(const T addr) const {
-  HeapRegion* hr = _hrs.addr_to_region((HeapWord*) addr);
-  // hr can be null if addr in perm_gen
-  if (hr != NULL && hr->continuesHumongous()) {
-    hr = hr->humongous_start_region();
-  }
-  return hr;
+inline HeapWord* G1CollectedHeap::bottom_addr_for_region(uint index) const {
+  return _hrs.reserved().start() + index * HeapRegion::GrainWords;
 }
 
 template <class T>
-inline HeapRegion*
-G1CollectedHeap::heap_region_containing_raw(const T addr) const {
-  assert(_g1_reserved.contains((const void*) addr), "invariant");
-  HeapRegion* res = _hrs.addr_to_region_unsafe((HeapWord*) addr);
-  return res;
+inline HeapRegion* G1CollectedHeap::heap_region_containing_raw(const T addr) const {
+  assert(addr != NULL, "invariant");
+  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);
+}
+
+template <class T>
+inline HeapRegion* G1CollectedHeap::heap_region_containing(const T addr) const {
+  HeapRegion* hr = heap_region_containing_raw(addr);
+  if (hr->continuesHumongous()) {
+    return hr->humongous_start_region();
+  }
+  return hr;
 }
 
 inline void G1CollectedHeap::reset_gc_time_stamp() {
@@ -88,10 +91,9 @@
   return r != NULL && r->in_collection_set();
 }
 
-inline HeapWord*
-G1CollectedHeap::attempt_allocation(size_t word_size,
-                                    unsigned int* gc_count_before_ret,
-                                    int* gclocker_retry_count_ret) {
+inline HeapWord* G1CollectedHeap::attempt_allocation(size_t word_size,
+                                                     unsigned int* gc_count_before_ret,
+                                                     int* gclocker_retry_count_ret) {
   assert_heap_not_locked_and_not_at_safepoint();
   assert(!isHumongous(word_size), "attempt_allocation() should not "
          "be called for humongous allocation requests");
@@ -154,8 +156,7 @@
   // have to keep calling heap_region_containing_raw() in the
   // asserts below.
   DEBUG_ONLY(HeapRegion* containing_hr = heap_region_containing_raw(start);)
-  assert(containing_hr != NULL && start != NULL && word_size > 0,
-         "pre-condition");
+  assert(word_size > 0, "pre-condition");
   assert(containing_hr->is_in(start), "it should contain start");
   assert(containing_hr->is_young(), "it should be young");
   assert(!containing_hr->isHumongous(), "it should not be humongous");
@@ -252,8 +253,7 @@
   }
 }
 
-inline bool
-G1CollectedHeap::evacuation_should_fail() {
+inline bool G1CollectedHeap::evacuation_should_fail() {
   if (!G1EvacuationFailureALot || !_evacuation_failure_alot_for_current_gc) {
     return false;
   }
@@ -277,8 +277,10 @@
 #endif  // #ifndef PRODUCT
 
 inline bool G1CollectedHeap::is_in_young(const oop obj) {
-  HeapRegion* hr = heap_region_containing(obj);
-  return hr != NULL && hr->is_young();
+  if (obj == NULL) {
+    return false;
+  }
+  return heap_region_containing(obj)->is_young();
 }
 
 // We don't need barriers for initializing stores to objects
@@ -291,21 +293,17 @@
 }
 
 inline bool G1CollectedHeap::is_obj_dead(const oop obj) const {
-  const HeapRegion* hr = heap_region_containing(obj);
-  if (hr == NULL) {
-    if (obj == NULL) return false;
-    else return true;
+  if (obj == NULL) {
+    return false;
   }
-  else return is_obj_dead(obj, hr);
+  return is_obj_dead(obj, heap_region_containing(obj));
 }
 
 inline bool G1CollectedHeap::is_obj_ill(const oop obj) const {
-  const HeapRegion* hr = heap_region_containing(obj);
-  if (hr == NULL) {
-    if (obj == NULL) return false;
-    else return true;
+  if (obj == NULL) {
+    return false;
   }
-  else return is_obj_ill(obj, hr);
+  return is_obj_ill(obj, heap_region_containing(obj));
 }
 
 inline void G1CollectedHeap::set_humongous_is_live(oop obj) {
--- a/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -455,7 +455,7 @@
   } else {
     _young_list_fixed_length = _young_gen_sizer->min_desired_young_length();
   }
-  _free_regions_at_end_of_collection = _g1->free_regions();
+  _free_regions_at_end_of_collection = _g1->num_free_regions();
   update_young_list_target_length();
 
   // We may immediately start allocating regions and placing them on the
@@ -828,7 +828,7 @@
 
   record_survivor_regions(0, NULL, NULL);
 
-  _free_regions_at_end_of_collection = _g1->free_regions();
+  _free_regions_at_end_of_collection = _g1->num_free_regions();
   // Reset survivors SurvRateGroup.
   _survivor_surv_rate_group->reset();
   update_young_list_target_length();
@@ -1180,7 +1180,7 @@
 
   _in_marking_window = new_in_marking_window;
   _in_marking_window_im = new_in_marking_window_im;
-  _free_regions_at_end_of_collection = _g1->free_regions();
+  _free_regions_at_end_of_collection = _g1->num_free_regions();
   update_young_list_target_length();
 
   // Note that _mmu_tracker->max_gc_time() returns the time in seconds.
@@ -1202,7 +1202,7 @@
   _survivor_used_bytes_before_gc = young_list->survivor_used_bytes();
   _heap_capacity_bytes_before_gc = _g1->capacity();
   _heap_used_bytes_before_gc = _g1->used();
-  _cur_collection_pause_used_regions_at_start = _g1->used_regions();
+  _cur_collection_pause_used_regions_at_start = _g1->num_used_regions();
 
   _eden_capacity_bytes_before_gc =
          (_young_list_target_length * HeapRegion::GrainBytes) - _survivor_used_bytes_before_gc;
@@ -1617,7 +1617,7 @@
 G1CollectorPolicy::record_concurrent_mark_cleanup_end(int no_of_gc_threads) {
   _collectionSetChooser->clear();
 
-  uint region_num = _g1->n_regions();
+  uint region_num = _g1->num_regions();
   if (G1CollectedHeap::use_parallel_gc_threads()) {
     const uint OverpartitionFactor = 4;
     uint WorkUnit;
@@ -1638,7 +1638,7 @@
         MAX2(region_num / (uint) (ParallelGCThreads * OverpartitionFactor),
              MinWorkUnit);
     }
-    _collectionSetChooser->prepare_for_par_region_addition(_g1->n_regions(),
+    _collectionSetChooser->prepare_for_par_region_addition(_g1->num_regions(),
                                                            WorkUnit);
     ParKnownGarbageTask parKnownGarbageTask(_collectionSetChooser,
                                             (int) WorkUnit);
@@ -1935,7 +1935,7 @@
   // of them are available.
 
   G1CollectedHeap* g1h = G1CollectedHeap::heap();
-  const size_t region_num = g1h->n_regions();
+  const size_t region_num = g1h->num_regions();
   const size_t perc = (size_t) G1OldCSetRegionThresholdPercent;
   size_t result = region_num * perc / 100;
   // emulate ceiling
--- a/src/share/vm/gc_implementation/g1/g1HotCardCache.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/gc_implementation/g1/g1HotCardCache.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -33,7 +33,7 @@
 G1HotCardCache::G1HotCardCache(G1CollectedHeap *g1h):
   _g1h(g1h), _hot_cache(NULL), _use_cache(false), _card_counts(g1h) {}
 
-void G1HotCardCache::initialize() {
+void G1HotCardCache::initialize(G1RegionToSpaceMapper* card_counts_storage) {
   if (default_use_cache()) {
     _use_cache = true;
 
@@ -49,7 +49,7 @@
     _hot_cache_par_chunk_size = MAX2(1, _hot_cache_size / (int)n_workers);
     _hot_cache_par_claimed_idx = 0;
 
-    _card_counts.initialize();
+    _card_counts.initialize(card_counts_storage);
   }
 }
 
@@ -135,11 +135,8 @@
   // above, are discarded prior to re-enabling the cache near the end of the GC.
 }
 
-void G1HotCardCache::resize_card_counts(size_t heap_capacity) {
-  _card_counts.resize(heap_capacity);
-}
-
 void G1HotCardCache::reset_card_counts(HeapRegion* hr) {
+  assert(!hr->isHumongous(), "Should have been cleared");
   _card_counts.clear_region(hr);
 }
 
--- a/src/share/vm/gc_implementation/g1/g1HotCardCache.hpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/gc_implementation/g1/g1HotCardCache.hpp	Fri Sep 05 06:26:44 2014 -0400
@@ -78,7 +78,7 @@
   G1HotCardCache(G1CollectedHeap* g1h);
   ~G1HotCardCache();
 
-  void initialize();
+  void initialize(G1RegionToSpaceMapper* card_counts_storage);
 
   bool use_cache() { return _use_cache; }
 
@@ -115,9 +115,6 @@
 
   bool hot_cache_is_empty() { return _n_hot == 0; }
 
-  // Resizes the card counts table to match the given capacity
-  void resize_card_counts(size_t heap_capacity);
-
   // Zeros the values in the card counts table for entire committed heap
   void reset_card_counts();
 
--- a/src/share/vm/gc_implementation/g1/g1OopClosures.inline.hpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/gc_implementation/g1/g1OopClosures.inline.hpp	Fri Sep 05 06:26:44 2014 -0400
@@ -130,9 +130,7 @@
   if (!oopDesc::is_null(heap_oop)) {
     oop obj = oopDesc::decode_heap_oop_not_null(heap_oop);
     HeapRegion* hr = _g1h->heap_region_containing((HeapWord*) obj);
-    if (hr != NULL) {
-      _cm->grayRoot(obj, obj->size(), _worker_id, hr);
-    }
+    _cm->grayRoot(obj, obj->size(), _worker_id, hr);
   }
 }
 
@@ -159,57 +157,61 @@
 template <class T>
 inline void G1UpdateRSOrPushRefOopClosure::do_oop_nv(T* p) {
   oop obj = oopDesc::load_decode_heap_oop(p);
+  if (obj == NULL) {
+    return;
+  }
 #ifdef ASSERT
   // can't do because of races
   // assert(obj == NULL || obj->is_oop(), "expected an oop");
 
   // Do the safe subset of is_oop
-  if (obj != NULL) {
 #ifdef CHECK_UNHANDLED_OOPS
-    oopDesc* o = obj.obj();
+  oopDesc* o = obj.obj();
 #else
-    oopDesc* o = obj;
+  oopDesc* o = obj;
 #endif // CHECK_UNHANDLED_OOPS
-    assert((intptr_t)o % MinObjAlignmentInBytes == 0, "not oop aligned");
-    assert(Universe::heap()->is_in_reserved(obj), "must be in heap");
-  }
+  assert((intptr_t)o % MinObjAlignmentInBytes == 0, "not oop aligned");
+  assert(Universe::heap()->is_in_reserved(obj), "must be in heap");
 #endif // ASSERT
 
   assert(_from != NULL, "from region must be non-NULL");
   assert(_from->is_in_reserved(p), "p is not in from");
 
   HeapRegion* to = _g1->heap_region_containing(obj);
-  if (to != NULL && _from != to) {
-    // The _record_refs_into_cset flag is true during the RSet
-    // updating part of an evacuation pause. It is false at all
-    // other times:
-    //  * rebuilding the rembered sets after a full GC
-    //  * during concurrent refinement.
-    //  * updating the remembered sets of regions in the collection
-    //    set in the event of an evacuation failure (when deferred
-    //    updates are enabled).
+  if (_from == to) {
+    // Normally this closure should only be called with cross-region references.
+    // But since Java threads are manipulating the references concurrently and we
+    // reload the values things may have changed.
+    return;
+  }
+  // The _record_refs_into_cset flag is true during the RSet
+  // updating part of an evacuation pause. It is false at all
+  // other times:
+  //  * rebuilding the remembered sets after a full GC
+  //  * during concurrent refinement.
+  //  * updating the remembered sets of regions in the collection
+  //    set in the event of an evacuation failure (when deferred
+  //    updates are enabled).
 
-    if (_record_refs_into_cset && to->in_collection_set()) {
-      // We are recording references that point into the collection
-      // set and this particular reference does exactly that...
-      // If the referenced object has already been forwarded
-      // to itself, we are handling an evacuation failure and
-      // we have already visited/tried to copy this object
-      // there is no need to retry.
-      if (!self_forwarded(obj)) {
-        assert(_push_ref_cl != NULL, "should not be null");
-        // Push the reference in the refs queue of the G1ParScanThreadState
-        // instance for this worker thread.
-        _push_ref_cl->do_oop(p);
-      }
+  if (_record_refs_into_cset && to->in_collection_set()) {
+    // We are recording references that point into the collection
+    // set and this particular reference does exactly that...
+    // If the referenced object has already been forwarded
+    // to itself, we are handling an evacuation failure and
+    // we have already visited/tried to copy this object
+    // there is no need to retry.
+    if (!self_forwarded(obj)) {
+      assert(_push_ref_cl != NULL, "should not be null");
+      // Push the reference in the refs queue of the G1ParScanThreadState
+      // instance for this worker thread.
+      _push_ref_cl->do_oop(p);
+     }
 
-      // Deferred updates to the CSet are either discarded (in the normal case),
-      // or processed (if an evacuation failure occurs) at the end
-      // of the collection.
-      // See G1RemSet::cleanup_after_oops_into_collection_set_do().
-      return;
-    }
-
+    // Deferred updates to the CSet are either discarded (in the normal case),
+    // or processed (if an evacuation failure occurs) at the end
+    // of the collection.
+    // See G1RemSet::cleanup_after_oops_into_collection_set_do().
+  } else {
     // We either don't care about pushing references that point into the
     // collection set (i.e. we're not during an evacuation pause) _or_
     // the reference doesn't point into the collection set. Either way
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/vm/gc_implementation/g1/g1PageBasedVirtualSpace.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -0,0 +1,167 @@
+/*
+ * 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.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "gc_implementation/g1/g1PageBasedVirtualSpace.hpp"
+#include "oops/markOop.hpp"
+#include "oops/oop.inline.hpp"
+#include "services/memTracker.hpp"
+#ifdef TARGET_OS_FAMILY_linux
+# include "os_linux.inline.hpp"
+#endif
+#ifdef TARGET_OS_FAMILY_solaris
+# include "os_solaris.inline.hpp"
+#endif
+#ifdef TARGET_OS_FAMILY_windows
+# include "os_windows.inline.hpp"
+#endif
+#ifdef TARGET_OS_FAMILY_aix
+# include "os_aix.inline.hpp"
+#endif
+#ifdef TARGET_OS_FAMILY_bsd
+# include "os_bsd.inline.hpp"
+#endif
+#include "utilities/bitMap.inline.hpp"
+
+G1PageBasedVirtualSpace::G1PageBasedVirtualSpace() : _low_boundary(NULL),
+  _high_boundary(NULL), _committed(), _page_size(0), _special(false), _executable(false) {
+}
+
+bool G1PageBasedVirtualSpace::initialize_with_granularity(ReservedSpace rs, size_t page_size) {
+  if (!rs.is_reserved()) {
+    return false;  // Allocation failed.
+  }
+  assert(_low_boundary == NULL, "VirtualSpace already initialized");
+  assert(page_size > 0, "Granularity must be non-zero.");
+
+  _low_boundary  = rs.base();
+  _high_boundary = _low_boundary + rs.size();
+
+  _special = rs.special();
+  _executable = rs.executable();
+
+  _page_size = page_size;
+
+  assert(_committed.size() == 0, "virtual space initialized more than once");
+  uintx size_in_bits = rs.size() / page_size;
+  _committed.resize(size_in_bits, /* in_resource_area */ false);
+
+  return true;
+}
+
+
+G1PageBasedVirtualSpace::~G1PageBasedVirtualSpace() {
+  release();
+}
+
+void G1PageBasedVirtualSpace::release() {
+  // This does not release memory it never reserved.
+  // Caller must release via rs.release();
+  _low_boundary           = NULL;
+  _high_boundary          = NULL;
+  _special                = false;
+  _executable             = false;
+  _page_size              = 0;
+  _committed.resize(0, false);
+}
+
+size_t G1PageBasedVirtualSpace::committed_size() const {
+  return _committed.count_one_bits() * _page_size;
+}
+
+size_t G1PageBasedVirtualSpace::reserved_size() const {
+  return pointer_delta(_high_boundary, _low_boundary, sizeof(char));
+}
+
+size_t G1PageBasedVirtualSpace::uncommitted_size()  const {
+  return reserved_size() - committed_size();
+}
+
+uintptr_t G1PageBasedVirtualSpace::addr_to_page_index(char* addr) const {
+  return (addr - _low_boundary) / _page_size;
+}
+
+bool G1PageBasedVirtualSpace::is_area_committed(uintptr_t start, size_t size_in_pages) const {
+  uintptr_t end = start + size_in_pages;
+  return _committed.get_next_zero_offset(start, end) >= end;
+}
+
+bool G1PageBasedVirtualSpace::is_area_uncommitted(uintptr_t start, size_t size_in_pages) const {
+  uintptr_t end = start + size_in_pages;
+  return _committed.get_next_one_offset(start, end) >= end;
+}
+
+char* G1PageBasedVirtualSpace::page_start(uintptr_t index) {
+  return _low_boundary + index * _page_size;
+}
+
+size_t G1PageBasedVirtualSpace::byte_size_for_pages(size_t num) {
+  return num * _page_size;
+}
+
+MemRegion G1PageBasedVirtualSpace::commit(uintptr_t start, size_t size_in_pages) {
+  // We need to make sure to commit all pages covered by the given area.
+  guarantee(is_area_uncommitted(start, size_in_pages), "Specified area is not uncommitted");
+
+  if (!_special) {
+    os::commit_memory_or_exit(page_start(start), byte_size_for_pages(size_in_pages), _executable,
+                              err_msg("Failed to commit pages from "SIZE_FORMAT" of length "SIZE_FORMAT, start, size_in_pages));
+  }
+  _committed.set_range(start, start + size_in_pages);
+
+  MemRegion result((HeapWord*)page_start(start), byte_size_for_pages(size_in_pages) / HeapWordSize);
+  return result;
+}
+
+MemRegion G1PageBasedVirtualSpace::uncommit(uintptr_t start, size_t size_in_pages) {
+  guarantee(is_area_committed(start, size_in_pages), "checking");
+
+  if (!_special) {
+    os::uncommit_memory(page_start(start), byte_size_for_pages(size_in_pages));
+  }
+
+  _committed.clear_range(start, start + size_in_pages);
+
+  MemRegion result((HeapWord*)page_start(start), byte_size_for_pages(size_in_pages) / HeapWordSize);
+  return result;
+}
+
+bool G1PageBasedVirtualSpace::contains(const void* p) const {
+  return _low_boundary <= (const char*) p && (const char*) p < _high_boundary;
+}
+
+#ifndef PRODUCT
+void G1PageBasedVirtualSpace::print_on(outputStream* out) {
+  out->print   ("Virtual space:");
+  if (special()) out->print(" (pinned in memory)");
+  out->cr();
+  out->print_cr(" - committed: " SIZE_FORMAT, committed_size());
+  out->print_cr(" - reserved:  " SIZE_FORMAT, reserved_size());
+  out->print_cr(" - [low_b, high_b]: [" INTPTR_FORMAT ", " INTPTR_FORMAT "]",  p2i(_low_boundary), p2i(_high_boundary));
+}
+
+void G1PageBasedVirtualSpace::print() {
+  print_on(tty);
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/vm/gc_implementation/g1/g1PageBasedVirtualSpace.hpp	Fri Sep 05 06:26:44 2014 -0400
@@ -0,0 +1,111 @@
+/*
+ * 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.
+ *
+ */
+
+#ifndef SHARE_VM_GC_IMPLEMENTATION_G1_G1PAGEBASEDVIRTUALSPACE_HPP
+#define SHARE_VM_GC_IMPLEMENTATION_G1_G1PAGEBASEDVIRTUALSPACE_HPP
+
+#include "memory/allocation.hpp"
+#include "memory/memRegion.hpp"
+#include "runtime/virtualspace.hpp"
+#include "utilities/bitMap.hpp"
+
+// Virtual space management helper for a virtual space with an OS page allocation
+// granularity.
+// (De-)Allocation requests are always OS page aligned by passing a page index
+// and multiples of pages.
+// The implementation gives an error when trying to commit or uncommit pages that
+// have already been committed or uncommitted.
+class G1PageBasedVirtualSpace VALUE_OBJ_CLASS_SPEC {
+  friend class VMStructs;
+ private:
+  // Reserved area addresses.
+  char* _low_boundary;
+  char* _high_boundary;
+
+  // The commit/uncommit granularity in bytes.
+  size_t _page_size;
+
+  // Bitmap used for verification of commit/uncommit operations.
+  BitMap _committed;
+
+  // Indicates that the entire space has been committed and pinned in memory,
+  // os::commit_memory() or os::uncommit_memory() have no function.
+  bool _special;
+
+  // Indicates whether the committed space should be executable.
+  bool _executable;
+
+  // Returns the index of the page which contains the given address.
+  uintptr_t  addr_to_page_index(char* addr) const;
+  // Returns the address of the given page index.
+  char*  page_start(uintptr_t index);
+  // Returns the byte size of the given number of pages.
+  size_t byte_size_for_pages(size_t num);
+
+  // Returns true if the entire area is backed by committed memory.
+  bool is_area_committed(uintptr_t start, size_t size_in_pages) const;
+  // Returns true if the entire area is not backed by committed memory.
+  bool is_area_uncommitted(uintptr_t start, size_t size_in_pages) const;
+
+ public:
+
+  // Commit the given area of pages starting at start being size_in_pages large.
+  MemRegion commit(uintptr_t start, size_t size_in_pages);
+
+  // Uncommit the given area of pages starting at start being size_in_pages large.
+  MemRegion uncommit(uintptr_t start, size_t size_in_pages);
+
+  bool special() const { return _special; }
+
+  // Initialization
+  G1PageBasedVirtualSpace();
+  bool initialize_with_granularity(ReservedSpace rs, size_t page_size);
+
+  // Destruction
+  ~G1PageBasedVirtualSpace();
+
+  // Amount of reserved memory.
+  size_t reserved_size() const;
+  // Memory used in this virtual space.
+  size_t committed_size() const;
+  // Memory left to use/expand in this virtual space.
+  size_t uncommitted_size() const;
+
+  bool contains(const void* p) const;
+
+  MemRegion reserved() {
+    MemRegion x((HeapWord*)_low_boundary, reserved_size() / HeapWordSize);
+    return x;
+  }
+
+  void release();
+
+  void check_for_contiguity() PRODUCT_RETURN;
+
+  // Debugging
+  void print_on(outputStream* out) PRODUCT_RETURN;
+  void print();
+};
+
+#endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1PAGEBASEDVIRTUALSPACE_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/vm/gc_implementation/g1/g1RegionToSpaceMapper.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -0,0 +1,159 @@
+/*
+ * 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.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "gc_implementation/g1/g1BiasedArray.hpp"
+#include "gc_implementation/g1/g1RegionToSpaceMapper.hpp"
+#include "memory/allocation.inline.hpp"
+#include "runtime/virtualspace.hpp"
+#include "services/memTracker.hpp"
+#include "utilities/bitMap.inline.hpp"
+
+G1RegionToSpaceMapper::G1RegionToSpaceMapper(ReservedSpace rs,
+                                             size_t commit_granularity,
+                                             size_t region_granularity,
+                                             MemoryType type) :
+  _storage(),
+  _commit_granularity(commit_granularity),
+  _region_granularity(region_granularity),
+  _listener(NULL),
+  _commit_map() {
+  guarantee(is_power_of_2(commit_granularity), "must be");
+  guarantee(is_power_of_2(region_granularity), "must be");
+  _storage.initialize_with_granularity(rs, commit_granularity);
+
+  MemTracker::record_virtual_memory_type((address)rs.base(), type);
+}
+
+// G1RegionToSpaceMapper implementation where the region granularity is larger than
+// or the same as the commit granularity.
+// Basically, the space corresponding to one region region spans several OS pages.
+class G1RegionsLargerThanCommitSizeMapper : public G1RegionToSpaceMapper {
+ private:
+  size_t _pages_per_region;
+
+ public:
+  G1RegionsLargerThanCommitSizeMapper(ReservedSpace rs,
+                                      size_t os_commit_granularity,
+                                      size_t alloc_granularity,
+                                      size_t commit_factor,
+                                      MemoryType type) :
+     G1RegionToSpaceMapper(rs, os_commit_granularity, alloc_granularity, type),
+    _pages_per_region(alloc_granularity / (os_commit_granularity * commit_factor)) {
+
+    guarantee(alloc_granularity >= os_commit_granularity, "allocation granularity smaller than commit granularity");
+    _commit_map.resize(rs.size() * commit_factor / alloc_granularity, /* in_resource_area */ false);
+  }
+
+  virtual void commit_regions(uintptr_t start_idx, size_t num_regions) {
+    _storage.commit(start_idx * _pages_per_region, num_regions * _pages_per_region);
+    _commit_map.set_range(start_idx, start_idx + num_regions);
+    fire_on_commit(start_idx, num_regions);
+  }
+
+  virtual void uncommit_regions(uintptr_t start_idx, size_t num_regions) {
+    _storage.uncommit(start_idx * _pages_per_region, num_regions * _pages_per_region);
+    _commit_map.clear_range(start_idx, start_idx + num_regions);
+  }
+};
+
+// G1RegionToSpaceMapper implementation where the region granularity is smaller
+// than the commit granularity.
+// Basically, the contents of one OS page span several regions.
+class G1RegionsSmallerThanCommitSizeMapper : public G1RegionToSpaceMapper {
+ private:
+  class CommitRefcountArray : public G1BiasedMappedArray<uint> {
+   protected:
+     virtual uint default_value() const { return 0; }
+  };
+
+  size_t _regions_per_page;
+
+  CommitRefcountArray _refcounts;
+
+  uintptr_t region_idx_to_page_idx(uint region) const {
+    return region / _regions_per_page;
+  }
+
+ public:
+  G1RegionsSmallerThanCommitSizeMapper(ReservedSpace rs,
+                                       size_t os_commit_granularity,
+                                       size_t alloc_granularity,
+                                       size_t commit_factor,
+                                       MemoryType type) :
+     G1RegionToSpaceMapper(rs, os_commit_granularity, alloc_granularity, type),
+    _regions_per_page((os_commit_granularity * commit_factor) / alloc_granularity), _refcounts() {
+
+    guarantee((os_commit_granularity * commit_factor) >= alloc_granularity, "allocation granularity smaller than commit granularity");
+    _refcounts.initialize((HeapWord*)rs.base(), (HeapWord*)(rs.base() + rs.size()), os_commit_granularity);
+    _commit_map.resize(rs.size() * commit_factor / alloc_granularity, /* in_resource_area */ false);
+  }
+
+  virtual void commit_regions(uintptr_t start_idx, size_t num_regions) {
+    for (uintptr_t i = start_idx; i < start_idx + num_regions; i++) {
+      assert(!_commit_map.at(i), err_msg("Trying to commit storage at region "INTPTR_FORMAT" that is already committed", i));
+      uintptr_t idx = region_idx_to_page_idx(i);
+      uint old_refcount = _refcounts.get_by_index(idx);
+      if (old_refcount == 0) {
+        _storage.commit(idx, 1);
+      }
+      _refcounts.set_by_index(idx, old_refcount + 1);
+      _commit_map.set_bit(i);
+      fire_on_commit(i, 1);
+    }
+  }
+
+  virtual void uncommit_regions(uintptr_t start_idx, size_t num_regions) {
+    for (uintptr_t i = start_idx; i < start_idx + num_regions; i++) {
+      assert(_commit_map.at(i), err_msg("Trying to uncommit storage at region "INTPTR_FORMAT" that is not committed", i));
+      uintptr_t idx = region_idx_to_page_idx(i);
+      uint old_refcount = _refcounts.get_by_index(idx);
+      assert(old_refcount > 0, "must be");
+      if (old_refcount == 1) {
+        _storage.uncommit(idx, 1);
+      }
+      _refcounts.set_by_index(idx, old_refcount - 1);
+      _commit_map.clear_bit(i);
+    }
+  }
+};
+
+void G1RegionToSpaceMapper::fire_on_commit(uint start_idx, size_t num_regions) {
+  if (_listener != NULL) {
+    _listener->on_commit(start_idx, num_regions);
+  }
+}
+
+G1RegionToSpaceMapper* G1RegionToSpaceMapper::create_mapper(ReservedSpace rs,
+                                                            size_t os_commit_granularity,
+                                                            size_t region_granularity,
+                                                            size_t commit_factor,
+                                                            MemoryType type) {
+
+  if (region_granularity >= (os_commit_granularity * commit_factor)) {
+    return new G1RegionsLargerThanCommitSizeMapper(rs, os_commit_granularity, region_granularity, commit_factor, type);
+  } else {
+    return new G1RegionsSmallerThanCommitSizeMapper(rs, os_commit_granularity, region_granularity, commit_factor, type);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/vm/gc_implementation/g1/g1RegionToSpaceMapper.hpp	Fri Sep 05 06:26:44 2014 -0400
@@ -0,0 +1,83 @@
+/*
+ * 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.
+ *
+ */
+
+#ifndef SHARE_VM_GC_IMPLEMENTATION_G1_G1REGIONTOSPACEMAPPER_HPP
+#define SHARE_VM_GC_IMPLEMENTATION_G1_G1REGIONTOSPACEMAPPER_HPP
+
+#include "gc_implementation/g1/g1PageBasedVirtualSpace.hpp"
+#include "memory/allocation.hpp"
+#include "utilities/debug.hpp"
+
+class G1MappingChangedListener VALUE_OBJ_CLASS_SPEC {
+ public:
+  // Fired after commit of the memory, i.e. the memory this listener is registered
+  // for can be accessed.
+  virtual void on_commit(uint start_idx, size_t num_regions) = 0;
+};
+
+// Maps region based commit/uncommit requests to the underlying page sized virtual
+// space.
+class G1RegionToSpaceMapper : public CHeapObj<mtGC> {
+ private:
+  G1MappingChangedListener* _listener;
+ protected:
+  // Backing storage.
+  G1PageBasedVirtualSpace _storage;
+  size_t _commit_granularity;
+  size_t _region_granularity;
+  // Mapping management
+  BitMap _commit_map;
+
+  G1RegionToSpaceMapper(ReservedSpace rs, size_t commit_granularity, size_t region_granularity, MemoryType type);
+
+  void fire_on_commit(uint start_idx, size_t num_regions);
+ public:
+  MemRegion reserved() { return _storage.reserved(); }
+
+  void set_mapping_changed_listener(G1MappingChangedListener* listener) { _listener = listener; }
+
+  virtual ~G1RegionToSpaceMapper() {
+    _commit_map.resize(0, /* in_resource_area */ false);
+  }
+
+  bool is_committed(uintptr_t idx) const {
+    return _commit_map.at(idx);
+  }
+
+  virtual void commit_regions(uintptr_t start_idx, size_t num_regions = 1) = 0;
+  virtual void uncommit_regions(uintptr_t start_idx, size_t num_regions = 1) = 0;
+
+  // Creates an appropriate G1RegionToSpaceMapper for the given parameters.
+  // The byte_translation_factor defines how many bytes in a region correspond to
+  // a single byte in the data structure this mapper is for.
+  // Eg. in the card table, this value corresponds to the size a single card
+  // table entry corresponds to.
+  static G1RegionToSpaceMapper* create_mapper(ReservedSpace rs,
+                                              size_t os_commit_granularity,
+                                              size_t region_granularity,
+                                              size_t byte_translation_factor,
+                                              MemoryType type);
+};
+
+#endif /* SHARE_VM_GC_IMPLEMENTATION_G1_G1REGIONTOSPACEMAPPER_HPP */
--- a/src/share/vm/gc_implementation/g1/g1RemSet.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/gc_implementation/g1/g1RemSet.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -211,7 +211,6 @@
 #endif
 
       HeapRegion* card_region = _g1h->heap_region_containing(card_start);
-      assert(card_region != NULL, "Yielding cards not in the heap?");
       _cards++;
 
       if (!card_region->is_on_dirty_cards_region_list()) {
@@ -406,7 +405,6 @@
     HeapWord* start = _ct_bs->addr_for(card_ptr);
     // And find the region containing it.
     HeapRegion* r = _g1->heap_region_containing(start);
-    assert(r != NULL, "unexpected null");
 
     // Scan oops in the card looking for references into the collection set
     // Don't use addr_for(card_ptr + 1) which can ask for
@@ -556,6 +554,12 @@
 
 bool G1RemSet::refine_card(jbyte* card_ptr, uint worker_i,
                            bool check_for_refs_into_cset) {
+  assert(_g1->is_in_exact(_ct_bs->addr_for(card_ptr)),
+         err_msg("Card at "PTR_FORMAT" index "SIZE_FORMAT" representing heap at "PTR_FORMAT" (%u) must be in committed heap",
+                 p2i(card_ptr),
+                 _ct_bs->index_for(_ct_bs->addr_for(card_ptr)),
+                 _ct_bs->addr_for(card_ptr),
+                 _g1->addr_to_region(_ct_bs->addr_for(card_ptr))));
 
   // If the card is no longer dirty, nothing to do.
   if (*card_ptr != CardTableModRefBS::dirty_card_val()) {
@@ -568,11 +572,6 @@
   HeapWord* start = _ct_bs->addr_for(card_ptr);
   // And find the region containing it.
   HeapRegion* r = _g1->heap_region_containing(start);
-  if (r == NULL) {
-    // Again no need to return that this card contains refs that
-    // point into the collection set.
-    return false;  // Not in the G1 heap (might be in perm, for example.)
-  }
 
   // Why do we have to check here whether a card is on a young region,
   // given that we dirty young regions and, as a result, the
@@ -625,10 +624,6 @@
 
     start = _ct_bs->addr_for(card_ptr);
     r = _g1->heap_region_containing(start);
-    if (r == NULL) {
-      // Not in the G1 heap
-      return false;
-    }
 
     // Checking whether the region we got back from the cache
     // is young here is inappropriate. The region could have been
--- a/src/share/vm/gc_implementation/g1/g1RemSet.inline.hpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/gc_implementation/g1/g1RemSet.inline.hpp	Fri Sep 05 06:26:44 2014 -0400
@@ -46,26 +46,28 @@
 template <class T>
 inline void G1RemSet::par_write_ref(HeapRegion* from, T* p, int tid) {
   oop obj = oopDesc::load_decode_heap_oop(p);
+  if (obj == NULL) {
+    return;
+  }
+
 #ifdef ASSERT
   // can't do because of races
   // assert(obj == NULL || obj->is_oop(), "expected an oop");
 
   // Do the safe subset of is_oop
-  if (obj != NULL) {
 #ifdef CHECK_UNHANDLED_OOPS
-    oopDesc* o = obj.obj();
+  oopDesc* o = obj.obj();
 #else
-    oopDesc* o = obj;
+  oopDesc* o = obj;
 #endif // CHECK_UNHANDLED_OOPS
-    assert((intptr_t)o % MinObjAlignmentInBytes == 0, "not oop aligned");
-    assert(Universe::heap()->is_in_reserved(obj), "must be in heap");
-  }
+  assert((intptr_t)o % MinObjAlignmentInBytes == 0, "not oop aligned");
+  assert(Universe::heap()->is_in_reserved(obj), "must be in heap");
 #endif // ASSERT
 
   assert(from == NULL || from->is_in_reserved(p), "p is not in from");
 
   HeapRegion* to = _g1->heap_region_containing(obj);
-  if (to != NULL && from != to) {
+  if (from != to) {
     assert(to->rem_set() != NULL, "Need per-region 'into' remsets.");
     to->rem_set()->add_reference(p, tid);
   }
--- a/src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -23,6 +23,7 @@
  */
 
 #include "precompiled.hpp"
+#include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
 #include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp"
 #include "gc_implementation/g1/heapRegion.hpp"
 #include "gc_implementation/g1/satbQueue.hpp"
@@ -37,7 +38,6 @@
   _kind = G1SATBCT;
 }
 
-
 void G1SATBCardTableModRefBS::enqueue(oop pre_val) {
   // Nulls should have been already filtered.
   assert(pre_val->is_oop(true), "Error");
@@ -124,13 +124,52 @@
 }
 #endif
 
+void G1SATBCardTableLoggingModRefBSChangedListener::on_commit(uint start_idx, size_t num_regions) {
+  MemRegion mr(G1CollectedHeap::heap()->bottom_addr_for_region(start_idx), num_regions * HeapRegion::GrainWords);
+  _card_table->clear(mr);
+}
+
 G1SATBCardTableLoggingModRefBS::
 G1SATBCardTableLoggingModRefBS(MemRegion whole_heap,
                                int max_covered_regions) :
   G1SATBCardTableModRefBS(whole_heap, max_covered_regions),
-  _dcqs(JavaThread::dirty_card_queue_set())
+  _dcqs(JavaThread::dirty_card_queue_set()),
+  _listener()
 {
   _kind = G1SATBCTLogging;
+  _listener.set_card_table(this);
+}
+
+void G1SATBCardTableLoggingModRefBS::initialize(G1RegionToSpaceMapper* mapper) {
+  mapper->set_mapping_changed_listener(&_listener);
+
+  _byte_map_size = mapper->reserved().byte_size();
+
+  _guard_index = cards_required(_whole_heap.word_size()) - 1;
+  _last_valid_index = _guard_index - 1;
+
+  HeapWord* low_bound  = _whole_heap.start();
+  HeapWord* high_bound = _whole_heap.end();
+
+  _cur_covered_regions = 1;
+  _covered[0] = _whole_heap;
+
+  _byte_map = (jbyte*) mapper->reserved().start();
+  byte_map_base = _byte_map - (uintptr_t(low_bound) >> card_shift);
+  assert(byte_for(low_bound) == &_byte_map[0], "Checking start of map");
+  assert(byte_for(high_bound-1) <= &_byte_map[_last_valid_index], "Checking end of map");
+
+  if (TraceCardTableModRefBS) {
+    gclog_or_tty->print_cr("G1SATBCardTableModRefBS::G1SATBCardTableModRefBS: ");
+    gclog_or_tty->print_cr("  "
+                  "  &_byte_map[0]: " INTPTR_FORMAT
+                  "  &_byte_map[_last_valid_index]: " INTPTR_FORMAT,
+                  p2i(&_byte_map[0]),
+                  p2i(&_byte_map[_last_valid_index]));
+    gclog_or_tty->print_cr("  "
+                  "  byte_map_base: " INTPTR_FORMAT,
+                  p2i(byte_map_base));
+  }
 }
 
 void
--- a/src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.hpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.hpp	Fri Sep 05 06:26:44 2014 -0400
@@ -25,6 +25,7 @@
 #ifndef SHARE_VM_GC_IMPLEMENTATION_G1_G1SATBCARDTABLEMODREFBS_HPP
 #define SHARE_VM_GC_IMPLEMENTATION_G1_G1SATBCARDTABLEMODREFBS_HPP
 
+#include "gc_implementation/g1/g1RegionToSpaceMapper.hpp"
 #include "memory/cardTableModRefBS.hpp"
 #include "memory/memRegion.hpp"
 #include "oops/oop.inline.hpp"
@@ -33,6 +34,7 @@
 #if INCLUDE_ALL_GCS
 
 class DirtyCardQueueSet;
+class G1SATBCardTableLoggingModRefBS;
 
 // This barrier is specialized to use a logging barrier to support
 // snapshot-at-the-beginning marking.
@@ -126,18 +128,40 @@
     jbyte val = _byte_map[card_index];
     return (val & (clean_card_mask_val() | deferred_card_val())) == deferred_card_val();
   }
+};
 
+class G1SATBCardTableLoggingModRefBSChangedListener : public G1MappingChangedListener {
+ private:
+  G1SATBCardTableLoggingModRefBS* _card_table;
+ public:
+  G1SATBCardTableLoggingModRefBSChangedListener() : _card_table(NULL) { }
+
+  void set_card_table(G1SATBCardTableLoggingModRefBS* card_table) { _card_table = card_table; }
+
+  virtual void on_commit(uint start_idx, size_t num_regions);
 };
 
 // Adds card-table logging to the post-barrier.
 // Usual invariant: all dirty cards are logged in the DirtyCardQueueSet.
 class G1SATBCardTableLoggingModRefBS: public G1SATBCardTableModRefBS {
+  friend class G1SATBCardTableLoggingModRefBSChangedListener;
  private:
+  G1SATBCardTableLoggingModRefBSChangedListener _listener;
   DirtyCardQueueSet& _dcqs;
  public:
+  static size_t compute_size(size_t mem_region_size_in_words) {
+    size_t number_of_slots = (mem_region_size_in_words / card_size_in_words);
+    return ReservedSpace::allocation_align_size_up(number_of_slots);
+  }
+
   G1SATBCardTableLoggingModRefBS(MemRegion whole_heap,
                                  int max_covered_regions);
 
+  virtual void initialize() { }
+  virtual void initialize(G1RegionToSpaceMapper* mapper);
+
+  virtual void resize_covered_region(MemRegion new_region) { ShouldNotReachHere(); }
+
   bool is_a(BarrierSet::Name bsn) {
     return bsn == BarrierSet::G1SATBCTLogging ||
       G1SATBCardTableModRefBS::is_a(bsn);
@@ -154,8 +178,6 @@
 
   void write_region_work(MemRegion mr)    { invalidate(mr); }
   void write_ref_array_work(MemRegion mr) { invalidate(mr); }
-
-
 };
 
 
--- a/src/share/vm/gc_implementation/g1/heapRegion.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/gc_implementation/g1/heapRegion.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -344,11 +344,6 @@
   return low;
 }
 
-#ifdef _MSC_VER // the use of 'this' below gets a warning, make it go away
-#pragma warning( disable:4355 ) // 'this' : used in base member initializer list
-#endif // _MSC_VER
-
-
 HeapRegion::HeapRegion(uint hrs_index,
                        G1BlockOffsetSharedArray* sharedOffsetArray,
                        MemRegion mr) :
@@ -360,7 +355,7 @@
     _claimed(InitialClaimValue), _evacuation_failed(false),
     _prev_marked_bytes(0), _next_marked_bytes(0), _gc_efficiency(0.0),
     _young_type(NotYoung), _next_young_region(NULL),
-    _next_dirty_cards_region(NULL), _next(NULL), _prev(NULL), _pending_removal(false),
+    _next_dirty_cards_region(NULL), _next(NULL), _prev(NULL),
 #ifdef ASSERT
     _containing_set(NULL),
 #endif // ASSERT
@@ -369,14 +364,20 @@
     _predicted_bytes_to_copy(0)
 {
   _rem_set = new HeapRegionRemSet(sharedOffsetArray, this);
+  assert(HeapRegionRemSet::num_par_rem_sets() > 0, "Invariant.");
+
+  initialize(mr);
+}
+
+void HeapRegion::initialize(MemRegion mr, bool clear_space, bool mangle_space) {
+  assert(_rem_set->is_empty(), "Remembered set must be empty");
+
+  G1OffsetTableContigSpace::initialize(mr, clear_space, mangle_space);
+
   _orig_end = mr.end();
-  // Note that initialize() will set the start of the unmarked area of the
-  // region.
   hr_clear(false /*par*/, false /*clear_space*/);
   set_top(bottom());
   record_top_and_timestamp();
-
-  assert(HeapRegionRemSet::num_par_rem_sets() > 0, "Invariant.");
 }
 
 CompactibleSpace* HeapRegion::next_compaction_space() const {
@@ -907,7 +908,7 @@
     }
 
     // If it returns false, verify_for_object() will output the
-    // appropriate messasge.
+    // appropriate message.
     if (do_bot_verify &&
         !g1->is_obj_dead(obj, this) &&
         !_offsets.verify_for_object(p, obj_size)) {
@@ -1038,8 +1039,7 @@
   set_top(bottom());
   set_saved_mark_word(bottom());
   CompactibleSpace::clear(mangle_space);
-  _offsets.zero_bottom_entry();
-  _offsets.initialize_threshold();
+  reset_bot();
 }
 
 void G1OffsetTableContigSpace::set_bottom(HeapWord* new_bottom) {
@@ -1129,9 +1129,11 @@
   _gc_time_stamp(0)
 {
   _offsets.set_space(this);
-  // false ==> we'll do the clearing if there's clearing to be done.
-  CompactibleSpace::initialize(mr, false, SpaceDecorator::Mangle);
+}
+
+void G1OffsetTableContigSpace::initialize(MemRegion mr, bool clear_space, bool mangle_space) {
+  CompactibleSpace::initialize(mr, clear_space, mangle_space);
   _top = bottom();
-  _offsets.zero_bottom_entry();
-  _offsets.initialize_threshold();
+  reset_bot();
 }
+
--- a/src/share/vm/gc_implementation/g1/heapRegion.hpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/gc_implementation/g1/heapRegion.hpp	Fri Sep 05 06:26:44 2014 -0400
@@ -62,7 +62,7 @@
                 p2i((_hr_)->bottom()), p2i((_hr_)->top()), p2i((_hr_)->end())
 
 // sentinel value for hrs_index
-#define G1_NULL_HRS_INDEX ((uint) -1)
+#define G1_NO_HRS_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
@@ -146,6 +146,9 @@
   HeapWord* top() const { return _top; }
 
  protected:
+  // Reset the G1OffsetTableContigSpace.
+  virtual void initialize(MemRegion mr, bool clear_space, bool mangle_space);
+
   HeapWord** top_addr() { return &_top; }
   // Allocation helpers (return NULL if full).
   inline HeapWord* allocate_impl(size_t word_size, HeapWord* end_value);
@@ -200,8 +203,7 @@
   virtual void print() const;
 
   void reset_bot() {
-    _offsets.zero_bottom_entry();
-    _offsets.initialize_threshold();
+    _offsets.reset_bot();
   }
 
   void update_bot_for_object(HeapWord* start, size_t word_size) {
@@ -264,7 +266,6 @@
 #ifdef ASSERT
   HeapRegionSetBase* _containing_set;
 #endif // ASSERT
-  bool _pending_removal;
 
   // For parallel heapRegion traversal.
   jint _claimed;
@@ -333,6 +334,12 @@
              G1BlockOffsetSharedArray* sharedOffsetArray,
              MemRegion mr);
 
+  // Initializing the HeapRegion not only resets the data structure, but also
+  // resets the BOT for that heap region.
+  // The default values for clear_space means that we will do the clearing if
+  // there's clearing to be done ourselves. We also always mangle the space.
+  virtual void initialize(MemRegion mr, bool clear_space = false, bool mangle_space = SpaceDecorator::Mangle);
+
   static int    LogOfHRGrainBytes;
   static int    LogOfHRGrainWords;
 
@@ -553,26 +560,6 @@
   // to provide a dummy version of it.
 #endif // ASSERT
 
-  // If we want to remove regions from a list in bulk we can simply tag
-  // them with the pending_removal tag and call the
-  // remove_all_pending() method on the list.
-
-  bool pending_removal() { return _pending_removal; }
-
-  void set_pending_removal(bool pending_removal) {
-    if (pending_removal) {
-      assert(!_pending_removal && containing_set() != NULL,
-             "can only set pending removal to true if it's false and "
-             "the region belongs to a region set");
-    } else {
-      assert( _pending_removal && containing_set() == NULL,
-              "can only set pending removal to false if it's true and "
-              "the region does not belong to a region set");
-    }
-
-    _pending_removal = pending_removal;
-  }
-
   HeapRegion* get_next_young_region() { return _next_young_region; }
   void set_next_young_region(HeapRegion* hr) {
     _next_young_region = hr;
--- a/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -288,7 +288,7 @@
   }
 
   _fine_grain_regions = NEW_C_HEAP_ARRAY3(PerRegionTablePtr, _max_fine_entries,
-                        mtGC, 0, AllocFailStrategy::RETURN_NULL);
+                        mtGC, CURRENT_PC, AllocFailStrategy::RETURN_NULL);
 
   if (_fine_grain_regions == NULL) {
     vm_exit_out_of_memory(sizeof(void*)*_max_fine_entries, OOM_MALLOC_ERROR,
@@ -372,17 +372,17 @@
                                                        _max_regions,
                                                        &_static_mem_size);
 
-  for (uint i = 0; i < n_par_rs; i++) {
-    for (uint j = 0; j < _max_regions; j++) {
-      set(i, j, InvalidCard);
-    }
-  }
+  invalidate(0, _max_regions);
 }
 
-void FromCardCache::shrink(uint new_num_regions) {
+void FromCardCache::invalidate(uint start_idx, size_t new_num_regions) {
+  guarantee((size_t)start_idx + new_num_regions <= max_uintx,
+            err_msg("Trying to invalidate beyond maximum region, from %u size "SIZE_FORMAT,
+                    start_idx, new_num_regions));
   for (uint i = 0; i < HeapRegionRemSet::num_par_rem_sets(); i++) {
-    assert(new_num_regions <= _max_regions, "Must be within max.");
-    for (uint j = new_num_regions; j < _max_regions; j++) {
+    uint end_idx = (start_idx + (uint)new_num_regions);
+    assert(end_idx <= _max_regions, "Must be within max.");
+    for (uint j = start_idx; j < end_idx; j++) {
       set(i, j, InvalidCard);
     }
   }
@@ -406,12 +406,12 @@
   }
 }
 
-void OtherRegionsTable::init_from_card_cache(uint max_regions) {
+void OtherRegionsTable::initialize(uint max_regions) {
   FromCardCache::initialize(HeapRegionRemSet::num_par_rem_sets(), max_regions);
 }
 
-void OtherRegionsTable::shrink_from_card_cache(uint new_num_regions) {
-  FromCardCache::shrink(new_num_regions);
+void OtherRegionsTable::invalidate(uint start_idx, size_t num_regions) {
+  FromCardCache::invalidate(start_idx, num_regions);
 }
 
 void OtherRegionsTable::print_from_card_cache() {
@@ -802,7 +802,6 @@
 
 bool OtherRegionsTable::contains_reference_locked(OopOrNarrowOopStar from) const {
   HeapRegion* hr = _g1h->heap_region_containing_raw(from);
-  if (hr == NULL) return false;
   RegionIdx_t hr_ind = (RegionIdx_t) hr->hrs_index();
   // Is this region in the coarse map?
   if (_coarse_map.at(hr_ind)) return true;
@@ -840,8 +839,8 @@
 HeapRegionRemSet::HeapRegionRemSet(G1BlockOffsetSharedArray* bosa,
                                    HeapRegion* hr)
   : _bosa(bosa),
-    _m(Mutex::leaf, FormatBuffer<128>("HeapRegionRemSet lock #"UINT32_FORMAT, hr->hrs_index()), true),
-    _code_roots(), _other_regions(hr, &_m) {
+    _m(Mutex::leaf, FormatBuffer<128>("HeapRegionRemSet lock #%u", hr->hrs_index()), true),
+    _code_roots(), _other_regions(hr, &_m), _iter_state(Unclaimed), _iter_claimed(0) {
   reset_for_par_iteration();
 }
 
--- a/src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp	Fri Sep 05 06:26:44 2014 -0400
@@ -84,7 +84,7 @@
 
   static void initialize(uint n_par_rs, uint max_num_regions);
 
-  static void shrink(uint new_num_regions);
+  static void invalidate(uint start_idx, size_t num_regions);
 
   static void print(outputStream* out = gclog_or_tty) PRODUCT_RETURN;
 
@@ -213,11 +213,11 @@
 
   // Declare the heap size (in # of regions) to the OtherRegionsTable.
   // (Uses it to initialize from_card_cache).
-  static void init_from_card_cache(uint max_regions);
+  static void initialize(uint max_regions);
 
-  // Declares that only regions i s.t. 0 <= i < new_n_regs are in use.
-  // Make sure any entries for higher regions are invalid.
-  static void shrink_from_card_cache(uint new_num_regions);
+  // Declares that regions between start_idx <= i < start_idx + num_regions are
+  // not in use. Make sure that any entries for these regions are invalid.
+  static void invalidate(uint start_idx, size_t num_regions);
 
   static void print_from_card_cache();
 };
@@ -404,12 +404,11 @@
   // Declare the heap size (in # of regions) to the HeapRegionRemSet(s).
   // (Uses it to initialize from_card_cache).
   static void init_heap(uint max_regions) {
-    OtherRegionsTable::init_from_card_cache(max_regions);
+    OtherRegionsTable::initialize(max_regions);
   }
 
-  // Declares that only regions i s.t. 0 <= i < new_n_regs are in use.
-  static void shrink_heap(uint new_n_regs) {
-    OtherRegionsTable::shrink_from_card_cache(new_n_regs);
+  static void invalidate(uint start_idx, uint num_regions) {
+    OtherRegionsTable::invalidate(start_idx, num_regions);
   }
 
 #ifndef PRODUCT
--- a/src/share/vm/gc_implementation/g1/heapRegionSeq.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/gc_implementation/g1/heapRegionSeq.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -25,163 +25,204 @@
 #include "precompiled.hpp"
 #include "gc_implementation/g1/heapRegion.hpp"
 #include "gc_implementation/g1/heapRegionSeq.inline.hpp"
-#include "gc_implementation/g1/heapRegionSet.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"
 
-// Private
+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();
+}
 
-uint HeapRegionSeq::find_contiguous_from(uint from, uint num) {
-  uint len = length();
-  assert(num > 1, "use this only for sequences of length 2 or greater");
-  assert(from <= len,
-         err_msg("from: %u should be valid and <= than %u", from, len));
+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);
 
-  uint curr = from;
-  uint first = G1_NULL_HRS_INDEX;
-  uint num_so_far = 0;
-  while (curr < len && num_so_far < num) {
-    if (at(curr)->is_empty()) {
-      if (first == G1_NULL_HRS_INDEX) {
-        first = curr;
-        num_so_far = 1;
-      } else {
-        num_so_far += 1;
-      }
-    } else {
-      first = G1_NULL_HRS_INDEX;
-      num_so_far = 0;
+  _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());
     }
-    curr += 1;
   }
-  assert(num_so_far <= num, "post-condition");
-  if (num_so_far == num) {
-    // we found enough space for the humongous object
-    assert(from <= first && first < len, "post-condition");
-    assert(first < curr && (curr - first) == num, "post-condition");
-    for (uint i = first; i < first + num; ++i) {
-      assert(at(i)->is_empty(), "post-condition");
+
+  _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);
     }
-    return first;
-  } else {
-    // we failed to find enough space for the humongous object
-    return G1_NULL_HRS_INDEX;
+  }
+
+  _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));
   }
 }
 
-// Public
+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;
 
-void HeapRegionSeq::initialize(HeapWord* bottom, HeapWord* end) {
-  assert((uintptr_t) bottom % HeapRegion::GrainBytes == 0,
-         "bottom should be heap region aligned");
-  assert((uintptr_t) end % HeapRegion::GrainBytes == 0,
-         "end should be heap region aligned");
+  uint expanded = 0;
 
-  _next_search_index = 0;
-  _allocated_length = 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;
+  }
 
-  _regions.initialize(bottom, end, HeapRegion::GrainBytes);
+  verify_optional();
+  return expanded;
 }
 
-MemRegion HeapRegionSeq::expand_by(HeapWord* old_end,
-                                   HeapWord* new_end,
-                                   FreeRegionList* list) {
-  assert(old_end < new_end, "don't call it otherwise");
-  G1CollectedHeap* g1h = G1CollectedHeap::heap();
-
-  HeapWord* next_bottom = old_end;
-  assert(heap_bottom() <= next_bottom, "invariant");
-  while (next_bottom < new_end) {
-    assert(next_bottom < heap_end(), "invariant");
-    uint index = length();
-
-    assert(index < max_length(), "otherwise we cannot expand further");
-    if (index == 0) {
-      // We have not allocated any regions so far
-      assert(next_bottom == heap_bottom(), "invariant");
-    } else {
-      // next_bottom should match the end of the last/previous region
-      assert(next_bottom == at(index - 1)->end(), "invariant");
-    }
+uint HeapRegionSeq::find_contiguous(size_t num, bool empty_only) {
+  uint found = 0;
+  size_t length_found = 0;
+  uint cur = 0;
 
-    if (index == _allocated_length) {
-      // We have to allocate a new HeapRegion.
-      HeapRegion* new_hr = g1h->new_heap_region(index, next_bottom);
-      if (new_hr == NULL) {
-        // allocation failed, we bail out and return what we have done so far
-        return MemRegion(old_end, next_bottom);
-      }
-      assert(_regions.get_by_index(index) == NULL, "invariant");
-      _regions.set_by_index(index, new_hr);
-      increment_allocated_length();
+  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;
     }
-    // Have to increment the length first, otherwise we will get an
-    // assert failure at(index) below.
-    increment_length();
-    HeapRegion* hr = at(index);
-    list->add_as_tail(hr);
+    cur++;
+  }
 
-    next_bottom = hr->end();
+  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;
   }
-  assert(next_bottom == new_end, "post-condition");
-  return MemRegion(old_end, next_bottom);
 }
 
-uint HeapRegionSeq::free_suffix() {
-  uint res = 0;
-  uint index = length();
-  while (index > 0) {
-    index -= 1;
-    if (!at(index)->is_empty()) {
-      break;
+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;
     }
-    res += 1;
   }
-  return res;
-}
-
-uint HeapRegionSeq::find_contiguous(uint num) {
-  assert(num > 1, "use this only for sequences of length 2 or greater");
-  assert(_next_search_index <= length(),
-         err_msg("_next_search_index: %u should be valid and <= than %u",
-                 _next_search_index, length()));
-
-  uint start = _next_search_index;
-  uint res = find_contiguous_from(start, num);
-  if (res == G1_NULL_HRS_INDEX && start > 0) {
-    // Try starting from the beginning. If _next_search_index was 0,
-    // no point in doing this again.
-    res = find_contiguous_from(0, num);
-  }
-  if (res != G1_NULL_HRS_INDEX) {
-    assert(res < length(), err_msg("res: %u should be valid", res));
-    _next_search_index = res + num;
-    assert(_next_search_index <= length(),
-           err_msg("_next_search_index: %u should be valid and <= than %u",
-                   _next_search_index, length()));
-  }
-  return res;
+  return NULL;
 }
 
 void HeapRegionSeq::iterate(HeapRegionClosure* blk) const {
-  iterate_from((HeapRegion*) NULL, blk);
-}
-
-void HeapRegionSeq::iterate_from(HeapRegion* hr, HeapRegionClosure* blk) const {
-  uint hr_index = 0;
-  if (hr != NULL) {
-    hr_index = hr->hrs_index();
-  }
+  uint len = max_length();
 
-  uint len = length();
-  for (uint i = hr_index; i < len; i += 1) {
-    bool res = blk->doHeapRegion(at(i));
-    if (res) {
-      blk->incomplete();
-      return;
+  for (uint i = 0; i < len; i++) {
+    if (!is_available(i)) {
+      continue;
     }
-  }
-  for (uint i = 0; i < hr_index; i += 1) {
+    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();
@@ -190,72 +231,220 @@
   }
 }
 
+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) {
-  // Reset this in case it's currently pointing into the regions that
-  // we just removed.
-  _next_search_index = 0;
-
   assert(length() > 0, "the region sequence should not be empty");
-  assert(length() <= _allocated_length, "invariant");
-  assert(_allocated_length > 0, "we should have at least one region committed");
+  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");
 
-  uint i = 0;
-  for (; i < num_regions_to_remove; i++) {
-    HeapRegion* cur = at(length() - 1);
+  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;
 
-    if (!cur->is_empty()) {
-      // We have to give up if the region can not be moved
-      break;
+  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;
   }
-    assert(!cur->isHumongous(), "Humongous regions should not be empty");
 
-    decrement_length();
-  }
-  return i;
+  verify_optional();
+
+  return removed;
 }
 
-#ifndef PRODUCT
-void HeapRegionSeq::verify_optional() {
-  guarantee(length() <= _allocated_length,
+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_length));
-  guarantee(_allocated_length <= max_length(),
+                    length(), _allocated_heapregions_length));
+  guarantee(_allocated_heapregions_length <= max_length(),
             err_msg("invariant: _allocated_length: %u _max_length: %u",
-                    _allocated_length, max_length()));
-  guarantee(_next_search_index <= length(),
-            err_msg("invariant: _next_search_index: %u _length: %u",
-                    _next_search_index, length()));
+                    _allocated_heapregions_length, max_length()));
 
+  bool prev_committed = true;
+  uint num_committed = 0;
   HeapWord* prev_end = heap_bottom();
-  for (uint i = 0; i < _allocated_length; i += 1) {
+  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(hr->bottom() == prev_end,
+    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()));
-    if (i < length()) {
-      // Asserts will fire if i is >= _length
-      HeapWord* addr = hr->bottom();
-      guarantee(addr_to_region(addr) == hr, "sanity");
-      guarantee(addr_to_region_unsafe(addr) == hr, "sanity");
-    } else {
-      guarantee(hr->is_empty(), "sanity");
-      guarantee(!hr->isHumongous(), "sanity");
-      // using assert instead of guarantee here since containing_set()
-      // is only available in non-product builds.
-      assert(hr->containing_set() == NULL, "sanity");
-    }
+    // 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_length; i < max_length(); i += 1) {
+  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/src/share/vm/gc_implementation/g1/heapRegionSeq.hpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/gc_implementation/g1/heapRegionSeq.hpp	Fri Sep 05 06:26:44 2014 -0400
@@ -26,6 +26,8 @@
 #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;
@@ -33,16 +35,20 @@
 
 class G1HeapRegionTable : public G1BiasedMappedArray<HeapRegion*> {
  protected:
-   virtual HeapRegion* default_value() const { return NULL; }
+  virtual HeapRegion* default_value() const { return NULL; }
 };
 
-// This class keeps track of the region metadata (i.e., HeapRegion
-// instances). They 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().
+// 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
@@ -51,56 +57,94 @@
 //
 // We keep track of three lengths:
 //
-// * _committed_length (returned by length()) is the number of currently
-//   committed regions.
-// * _allocated_length (not exposed outside this class) is the
-//   number of regions for which we have HeapRegions.
+// * _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.
 //
-// and maintain that: _committed_length <= _allocated_length <= max_length()
 
 class HeapRegionSeq: public CHeapObj<mtGC> {
   friend class VMStructs;
 
   G1HeapRegionTable _regions;
 
-  // The number of regions committed in the heap.
-  uint _committed_length;
+  G1RegionToSpaceMapper* _heap_mapper;
+  G1RegionToSpaceMapper* _prev_bitmap_mapper;
+  G1RegionToSpaceMapper* _next_bitmap_mapper;
+  G1RegionToSpaceMapper* _bot_mapper;
+  G1RegionToSpaceMapper* _cardtable_mapper;
+  G1RegionToSpaceMapper* _card_counts_mapper;
 
-  // A hint for which index to start searching from for humongous
-  // allocations.
-  uint _next_search_index;
+  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;
 
-  // The number of regions for which we have allocated HeapRegions for.
-  uint _allocated_length;
+  // 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);
 
-  // Find a contiguous set of empty regions of length num, starting
-  // from the given index.
-  uint find_contiguous_from(uint from, uint num);
+  // 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);
 
-  void increment_allocated_length() {
-    assert(_allocated_length < max_length(), "pre-condition");
-    _allocated_length++;
-  }
+  // 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;
 
-  void increment_length() {
-    assert(length() < max_length(), "pre-condition");
-    _committed_length++;
-  }
+  // 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;
 
-  void decrement_length() {
-    assert(length() > 0, "pre-condition");
-    _committed_length--;
-  }
+  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())
+  { }
 
-  HeapWord* heap_bottom() const { return _regions.bottom_address_mapped(); }
-  HeapWord* heap_end() const {return _regions.end_address_mapped(); }
+  void initialize(G1RegionToSpaceMapper* heap_storage,
+                  G1RegionToSpaceMapper* prev_bitmap,
+                  G1RegionToSpaceMapper* next_bitmap,
+                  G1RegionToSpaceMapper* bot,
+                  G1RegionToSpaceMapper* cardtable,
+                  G1RegionToSpaceMapper* card_counts);
 
- public:
-  // Empty contructor, we'll initialize it with the initialize() method.
-  HeapRegionSeq() : _regions(), _committed_length(0), _next_search_index(0), _allocated_length(0) { }
-
-  void initialize(HeapWord* bottom, HeapWord* end);
+  // 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.
@@ -110,47 +154,83 @@
   // HeapRegion, otherwise return NULL.
   inline HeapRegion* addr_to_region(HeapWord* addr) const;
 
-  // Return the HeapRegion that corresponds to the given
-  // address. Assume the address is valid.
-  inline HeapRegion* addr_to_region_unsafe(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 _committed_length; }
+  uint length() const { return _num_committed; }
 
   // Return the maximum number of regions in the heap.
   uint max_length() const { return (uint)_regions.length(); }
 
-  // Expand the sequence to reflect that the heap has grown from
-  // old_end to new_end. Either create new HeapRegions, or re-use
-  // existing ones, and return them in the given list. Returns the
-  // memory region that covers the newly-created regions. If a
-  // HeapRegion allocation fails, the result memory region might be
-  // smaller than the desired one.
-  MemRegion expand_by(HeapWord* old_end, HeapWord* new_end,
-                      FreeRegionList* list);
+  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);
 
-  // Return the number of contiguous regions at the end of the sequence
-  // that are available for allocation.
-  uint free_suffix();
+  // 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 and return
-  // the index of the first region or G1_NULL_HRS_INDEX if the
-  // search was unsuccessful.
-  uint find_contiguous(uint num);
+  // 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;
 
-  // As above, but start the iteration from hr and loop around. If hr
-  // is NULL, we start from the first region in the heap.
-  void iterate_from(HeapRegion* hr, HeapRegionClosure* blk) const;
+  void par_iterate(HeapRegionClosure* blk, uint worker_id, uint no_of_par_workers, jint claim_value) const;
 
-  // Tag as uncommitted as many regions that are completely free as
-  // possible, up to num_regions_to_remove, from the suffix of the committed
-  // sequence. Return the actual number of removed regions.
+  // 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;
 };
--- a/src/share/vm/gc_implementation/g1/heapRegionSeq.inline.hpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/gc_implementation/g1/heapRegionSeq.inline.hpp	Fri Sep 05 06:26:44 2014 -0400
@@ -27,28 +27,32 @@
 
 #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_unsafe(HeapWord* addr) const {
+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);
-  assert(hr != NULL, "invariant");
   return hr;
 }
 
-inline HeapRegion* HeapRegionSeq::addr_to_region(HeapWord* addr) const {
-  if (addr != NULL && addr < heap_end()) {
-    assert(addr >= heap_bottom(),
-          err_msg("addr: " PTR_FORMAT " bottom: " PTR_FORMAT, p2i(addr), p2i(heap_bottom())));
-    return addr_to_region_unsafe(addr);
-  }
-  return NULL;
-}
-
 inline HeapRegion* HeapRegionSeq::at(uint index) const {
-  assert(index < length(), "pre-condition");
+  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/src/share/vm/gc_implementation/g1/heapRegionSet.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/gc_implementation/g1/heapRegionSet.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -23,6 +23,7 @@
  */
 
 #include "precompiled.hpp"
+#include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
 #include "gc_implementation/g1/heapRegionRemSet.hpp"
 #include "gc_implementation/g1/heapRegionSet.inline.hpp"
 
@@ -67,7 +68,7 @@
   // Do the basic verification first before we do the checks over the regions.
   HeapRegionSetBase::verify();
 
-  _verify_in_progress        = true;
+  _verify_in_progress = true;
 }
 
 void HeapRegionSetBase::verify_end() {
@@ -103,62 +104,7 @@
 }
 
 void FreeRegionList::fill_in_ext_msg_extra(hrs_ext_msg* msg) {
-  msg->append(" hd: "PTR_FORMAT" tl: "PTR_FORMAT, head(), tail());
-}
-
-void FreeRegionList::add_as_head_or_tail(FreeRegionList* from_list, bool as_head) {
-  check_mt_safety();
-  from_list->check_mt_safety();
-
-  verify_optional();
-  from_list->verify_optional();
-
-  if (from_list->is_empty()) {
-    return;
-  }
-
-#ifdef ASSERT
-  FreeRegionListIterator iter(from_list);
-  while (iter.more_available()) {
-    HeapRegion* hr = iter.get_next();
-    // In set_containing_set() we check that we either set the value
-    // from NULL to non-NULL or vice versa to catch bugs. So, we have
-    // to NULL it first before setting it to the value.
-    hr->set_containing_set(NULL);
-    hr->set_containing_set(this);
-  }
-#endif // ASSERT
-
-  if (_head == NULL) {
-    assert(length() == 0 && _tail == NULL, hrs_ext_msg(this, "invariant"));
-    _head = from_list->_head;
-    _tail = from_list->_tail;
-  } else {
-    assert(length() > 0 && _tail != NULL, hrs_ext_msg(this, "invariant"));
-    if (as_head) {
-      from_list->_tail->set_next(_head);
-      _head->set_prev(from_list->_tail);
-      _head = from_list->_head;
-    } else {
-      _tail->set_next(from_list->_head);
-      from_list->_head->set_prev(_tail);
-      _tail = from_list->_tail;
-    }
-  }
-
-  _count.increment(from_list->length(), from_list->total_capacity_bytes());
-  from_list->clear();
-
-  verify_optional();
-  from_list->verify_optional();
-}
-
-void FreeRegionList::add_as_head(FreeRegionList* from_list) {
-  add_as_head_or_tail(from_list, true /* as_head */);
-}
-
-void FreeRegionList::add_as_tail(FreeRegionList* from_list) {
-  add_as_head_or_tail(from_list, false /* as_head */);
+  msg->append(" hd: "PTR_FORMAT" tl: "PTR_FORMAT, _head, _tail);
 }
 
 void FreeRegionList::remove_all() {
@@ -191,11 +137,6 @@
     return;
   }
 
-  if (is_empty()) {
-    add_as_head(from_list);
-    return;
-  }
-
   #ifdef ASSERT
   FreeRegionListIterator iter(from_list);
   while (iter.more_available()) {
@@ -208,39 +149,45 @@
   }
   #endif // ASSERT
 
-  HeapRegion* curr_to = _head;
-  HeapRegion* curr_from = from_list->_head;
+  if (is_empty()) {
+    assert(length() == 0 && _tail == NULL, hrs_ext_msg(this, "invariant"));
+    _head = from_list->_head;
+    _tail = from_list->_tail;
+  } else {
+    HeapRegion* curr_to = _head;
+    HeapRegion* curr_from = from_list->_head;
+
+    while (curr_from != NULL) {
+      while (curr_to != NULL && curr_to->hrs_index() < curr_from->hrs_index()) {
+        curr_to = curr_to->next();
+      }
 
-  while (curr_from != NULL) {
-    while (curr_to != NULL && curr_to->hrs_index() < curr_from->hrs_index()) {
-      curr_to = curr_to->next();
+      if (curr_to == NULL) {
+        // The rest of the from list should be added as tail
+        _tail->set_next(curr_from);
+        curr_from->set_prev(_tail);
+        curr_from = NULL;
+      } else {
+        HeapRegion* next_from = curr_from->next();
+
+        curr_from->set_next(curr_to);
+        curr_from->set_prev(curr_to->prev());
+        if (curr_to->prev() == NULL) {
+          _head = curr_from;
+        } else {
+          curr_to->prev()->set_next(curr_from);
+        }
+        curr_to->set_prev(curr_from);
+
+        curr_from = next_from;
+      }
     }
 
-    if (curr_to == NULL) {
-      // The rest of the from list should be added as tail
-      _tail->set_next(curr_from);
-      curr_from->set_prev(_tail);
-      curr_from = NULL;
-    } else {
-      HeapRegion* next_from = curr_from->next();
-
-      curr_from->set_next(curr_to);
-      curr_from->set_prev(curr_to->prev());
-      if (curr_to->prev() == NULL) {
-        _head = curr_from;
-      } else {
-        curr_to->prev()->set_next(curr_from);
-      }
-      curr_to->set_prev(curr_from);
-
-      curr_from = next_from;
+    if (_tail->hrs_index() < from_list->_tail->hrs_index()) {
+      _tail = from_list->_tail;
     }
   }
 
-  if (_tail->hrs_index() < from_list->_tail->hrs_index()) {
-    _tail = from_list->_tail;
-  }
-
   _count.increment(from_list->length(), from_list->total_capacity_bytes());
   from_list->clear();
 
@@ -248,68 +195,59 @@
   from_list->verify_optional();
 }
 
-void FreeRegionList::remove_all_pending(uint target_count) {
+void FreeRegionList::remove_starting_at(HeapRegion* first, uint num_regions) {
   check_mt_safety();
-  assert(target_count > 1, hrs_ext_msg(this, "pre-condition"));
+  assert(num_regions >= 1, hrs_ext_msg(this, "pre-condition"));
   assert(!is_empty(), hrs_ext_msg(this, "pre-condition"));
 
   verify_optional();
   DEBUG_ONLY(uint old_length = length();)
 
-  HeapRegion* curr = _head;
+  HeapRegion* curr = first;
   uint count = 0;
-  while (curr != NULL) {
+  while (count < num_regions) {
     verify_region(curr);
     HeapRegion* next = curr->next();
     HeapRegion* prev = curr->prev();
 
-    if (curr->pending_removal()) {
-      assert(count < target_count,
-             hrs_err_msg("[%s] should not come across more regions "
-                         "pending for removal than target_count: %u",
-                         name(), target_count));
+    assert(count < num_regions,
+           hrs_err_msg("[%s] should not come across more regions "
+                       "pending for removal than num_regions: %u",
+                       name(), num_regions));
 
-      if (prev == NULL) {
-        assert(_head == curr, hrs_ext_msg(this, "invariant"));
-        _head = next;
-      } else {
-        assert(_head != curr, hrs_ext_msg(this, "invariant"));
-        prev->set_next(next);
-      }
-      if (next == NULL) {
-        assert(_tail == curr, hrs_ext_msg(this, "invariant"));
-        _tail = prev;
-      } else {
-        assert(_tail != curr, hrs_ext_msg(this, "invariant"));
-        next->set_prev(prev);
-      }
-      if (_last = curr) {
-        _last = NULL;
-      }
+    if (prev == NULL) {
+      assert(_head == curr, hrs_ext_msg(this, "invariant"));
+      _head = next;
+    } else {
+      assert(_head != curr, hrs_ext_msg(this, "invariant"));
+      prev->set_next(next);
+    }
+    if (next == NULL) {
+      assert(_tail == curr, hrs_ext_msg(this, "invariant"));
+      _tail = prev;
+    } else {
+      assert(_tail != curr, hrs_ext_msg(this, "invariant"));
+      next->set_prev(prev);
+    }
+    if (_last = curr) {
+      _last = NULL;
+    }
 
-      curr->set_next(NULL);
-      curr->set_prev(NULL);
-      remove(curr);
-      curr->set_pending_removal(false);
-
-      count += 1;
+    curr->set_next(NULL);
+    curr->set_prev(NULL);
+    remove(curr);
 
-      // If we have come across the target number of regions we can
-      // just bail out. However, for debugging purposes, we can just
-      // carry on iterating to make sure there are not more regions
-      // tagged with pending removal.
-      DEBUG_ONLY(if (count == target_count) break;)
-    }
+    count++;
     curr = next;
   }
 
-  assert(count == target_count,
-         hrs_err_msg("[%s] count: %u should be == target_count: %u",
-                     name(), count, target_count));
-  assert(length() + target_count == old_length,
+  assert(count == num_regions,
+         hrs_err_msg("[%s] count: %u should be == num_regions: %u",
+                     name(), count, num_regions));
+  assert(length() + num_regions == old_length,
          hrs_err_msg("[%s] new length should be consistent "
-                     "new length: %u old length: %u target_count: %u",
-                     name(), length(), old_length, target_count));
+                     "new length: %u old length: %u num_regions: %u",
+                     name(), length(), old_length, num_regions));
 
   verify_optional();
 }
@@ -348,10 +286,12 @@
       hr->print_on(out);
     }
   }
+
+  out->cr();
 }
 
 void FreeRegionList::verify_list() {
-  HeapRegion* curr = head();
+  HeapRegion* curr = _head;
   HeapRegion* prev1 = NULL;
   HeapRegion* prev0 = NULL;
   uint count = 0;
@@ -379,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->hrs_index(), prev0->hrs_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,
@@ -463,3 +403,41 @@
               "master humongous set MT safety protocol outside a safepoint");
   }
 }
+
+void FreeRegionList_test() {
+  FreeRegionList l("test");
+
+  const uint num_regions_in_test = 5;
+  // Create a fake heap. It does not need to be valid, as the HeapRegion constructor
+  // does not access it.
+  MemRegion heap(NULL, num_regions_in_test * HeapRegion::GrainWords);
+  // Allocate a fake BOT because the HeapRegion constructor initializes
+  // the BOT.
+  size_t bot_size = G1BlockOffsetSharedArray::compute_size(heap.word_size());
+  HeapWord* bot_data = NEW_C_HEAP_ARRAY(HeapWord, bot_size, mtGC);
+  ReservedSpace bot_rs(G1BlockOffsetSharedArray::compute_size(heap.word_size()));
+  G1RegionToSpaceMapper* bot_storage =
+    G1RegionToSpaceMapper::create_mapper(bot_rs,
+                                         os::vm_page_size(),
+                                         HeapRegion::GrainBytes,
+                                         G1BlockOffsetSharedArray::N_bytes,
+                                         mtGC);
+  G1BlockOffsetSharedArray oa(heap, bot_storage);
+  bot_storage->commit_regions(0, num_regions_in_test);
+  HeapRegion hr0(0, &oa, heap);
+  HeapRegion hr1(1, &oa, heap);
+  HeapRegion hr2(2, &oa, heap);
+  HeapRegion hr3(3, &oa, heap);
+  HeapRegion hr4(4, &oa, heap);
+  l.add_ordered(&hr1);
+  l.add_ordered(&hr0);
+  l.add_ordered(&hr3);
+  l.add_ordered(&hr4);
+  l.add_ordered(&hr2);
+  assert(l.length() == num_regions_in_test, "wrong length");
+  l.verify_list();
+
+  bot_storage->uncommit_regions(0, num_regions_in_test);
+  delete bot_storage;
+  FREE_C_HEAP_ARRAY(HeapWord, bot_data, mtGC);
+}
--- a/src/share/vm/gc_implementation/g1/heapRegionSet.hpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/gc_implementation/g1/heapRegionSet.hpp	Fri Sep 05 06:26:44 2014 -0400
@@ -162,7 +162,7 @@
 // diagnosing failures.
 class hrs_ext_msg : public hrs_err_msg {
 public:
-  hrs_ext_msg(HeapRegionSetBase* set, const char* message) : hrs_err_msg("%s","") {
+  hrs_ext_msg(HeapRegionSetBase* set, const char* message) : hrs_err_msg("%s", "") {
     set->fill_in_ext_msg(this, message);
   }
 };
@@ -192,13 +192,9 @@
 };
 
 // A set that links all the regions added to it in a doubly-linked
-// list. We should try to avoid doing operations that iterate over
+// sorted list. We should try to avoid doing operations that iterate over
 // such lists in performance critical paths. Typically we should
-// add / remove one region at a time or concatenate two lists. There are
-// two ways to treat your lists, ordered and un-ordered. All un-ordered
-// operations are done in constant time. To keep a list ordered only use
-// add_ordered() to add elements to the list. If a list is not ordered
-// from start, there is no way to sort it later.
+// add / remove one region at a time or concatenate two lists.
 
 class FreeRegionListIterator;
 
@@ -210,13 +206,13 @@
   HeapRegion* _tail;
 
   // _last is used to keep track of where we added an element the last
-  // time in ordered lists. It helps to improve performance when adding
-  // several ordered items in a row.
+  // time. It helps to improve performance when adding several ordered items in a row.
   HeapRegion* _last;
 
   static uint _unrealistically_long_length;
 
-  void add_as_head_or_tail(FreeRegionList* from_list, bool as_head);
+  inline HeapRegion* remove_from_head_impl();
+  inline HeapRegion* remove_from_tail_impl();
 
 protected:
   virtual void fill_in_ext_msg_extra(hrs_ext_msg* msg);
@@ -232,8 +228,11 @@
 
   void verify_list();
 
-  HeapRegion* head() { return _head; }
-  HeapRegion* tail() { return _tail; }
+#ifdef ASSERT
+  bool contains(HeapRegion* hr) const {
+    return hr->containing_set() == this;
+  }
+#endif
 
   static void set_unrealistically_long_length(uint len);
 
@@ -242,55 +241,20 @@
   // is determined by hrs_index.
   inline void add_ordered(HeapRegion* hr);
 
-  // It adds hr to the list as the new head. The region should not be
-  // a member of another set.
-  inline void add_as_head(HeapRegion* hr);
-
-  // It adds hr to the list as the new tail. The region should not be
-  // a member of another set.
-  inline void add_as_tail(HeapRegion* hr);
-
-  // It removes and returns the head of the list. It assumes that the
-  // list is not empty so it will return a non-NULL value.
-  inline HeapRegion* remove_head();
-
-  // Convenience method.
-  inline HeapRegion* remove_head_or_null();
-
-  // Removes and returns the last element (_tail) of the list. It assumes
-  // that the list isn't empty so that it can return a non-NULL value.
-  inline HeapRegion* remove_tail();
-
-  // Convenience method
-  inline HeapRegion* remove_tail_or_null();
-
   // Removes from head or tail based on the given argument.
-  inline HeapRegion* remove_region(bool from_head);
+  HeapRegion* remove_region(bool from_head);
 
   // Merge two ordered lists. The result is also ordered. The order is
   // determined by hrs_index.
   void add_ordered(FreeRegionList* from_list);
 
-  // It moves the regions from from_list to this list and empties
-  // from_list. The new regions will appear in the same order as they
-  // were in from_list and be linked in the beginning of this list.
-  void add_as_head(FreeRegionList* from_list);
-
-  // It moves the regions from from_list to this list and empties
-  // from_list. The new regions will appear in the same order as they
-  // were in from_list and be linked in the end of this list.
-  void add_as_tail(FreeRegionList* from_list);
-
   // It empties the list by removing all regions from it.
   void remove_all();
 
-  // It removes all regions in the list that are pending for removal
-  // (i.e., they have been tagged with "pending_removal"). The list
-  // must not be empty, target_count should reflect the exact number
-  // of regions that are pending for removal in the list, and
-  // target_count should be > 1 (currently, we never need to remove a
-  // single region using this).
-  void remove_all_pending(uint target_count);
+  // Remove all (contiguous) regions from first to first + num_regions -1 from
+  // this list.
+  // Num_regions must be > 1.
+  void remove_starting_at(HeapRegion* first, uint num_regions);
 
   virtual void verify();
 
@@ -298,7 +262,7 @@
 };
 
 // Iterator class that provides a convenient way to iterate over the
-// regions of a HeapRegionLinkedList instance.
+// regions of a FreeRegionList.
 
 class FreeRegionListIterator : public StackObj {
 private:
@@ -324,7 +288,7 @@
   }
 
   FreeRegionListIterator(FreeRegionList* list) : _curr(NULL), _list(list) {
-    _curr = list->head();
+    _curr = list->_head;
   }
 };
 
--- a/src/share/vm/gc_implementation/g1/heapRegionSet.inline.hpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/gc_implementation/g1/heapRegionSet.inline.hpp	Fri Sep 05 06:26:44 2014 -0400
@@ -30,7 +30,8 @@
 inline void HeapRegionSetBase::add(HeapRegion* hr) {
   check_mt_safety();
   assert(hr->containing_set() == NULL, hrs_ext_msg(this, "should not already have a containing set %u"));
-  assert(hr->next() == NULL && hr->prev() == NULL, hrs_ext_msg(this, "should not already be linked"));
+  assert(hr->next() == NULL, hrs_ext_msg(this, "should not already be linked"));
+  assert(hr->prev() == NULL, hrs_ext_msg(this, "should not already be linked"));
 
   _count.increment(1u, hr->capacity());
   hr->set_containing_set(this);
@@ -40,7 +41,8 @@
 inline void HeapRegionSetBase::remove(HeapRegion* hr) {
   check_mt_safety();
   verify_region(hr);
-  assert(hr->next() == NULL && hr->prev() == NULL, hrs_ext_msg(this, "should already be unlinked"));
+  assert(hr->next() == NULL, hrs_ext_msg(this, "should already be unlinked"));
+  assert(hr->prev() == NULL, hrs_ext_msg(this, "should already be unlinked"));
 
   hr->set_containing_set(NULL);
   assert(_count.length() > 0, hrs_ext_msg(this, "pre-condition"));
@@ -48,8 +50,7 @@
 }
 
 inline void FreeRegionList::add_ordered(HeapRegion* hr) {
-  check_mt_safety();
-  assert((length() == 0 && _head == NULL && _tail == NULL) ||
+  assert((length() == 0 && _head == NULL && _tail == NULL && _last == NULL) ||
          (length() >  0 && _head != NULL && _tail != NULL),
          hrs_ext_msg(this, "invariant"));
   // add() will verify the region and check mt safety.
@@ -95,55 +96,48 @@
   _last = hr;
 }
 
-inline void FreeRegionList::add_as_head(HeapRegion* hr) {
-  assert((length() == 0 && _head == NULL && _tail == NULL) ||
-         (length() >  0 && _head != NULL && _tail != NULL),
-         hrs_ext_msg(this, "invariant"));
-  // add() will verify the region and check mt safety.
-  add(hr);
-
-  // Now link the region.
-  if (_head != NULL) {
-    hr->set_next(_head);
-    _head->set_prev(hr);
-  } else {
-    _tail = hr;
-  }
-  _head = hr;
-}
-
-inline void FreeRegionList::add_as_tail(HeapRegion* hr) {
-  check_mt_safety();
-  assert((length() == 0 && _head == NULL && _tail == NULL) ||
-         (length() >  0 && _head != NULL && _tail != NULL),
-         hrs_ext_msg(this, "invariant"));
-  // add() will verify the region and check mt safety.
-  add(hr);
-
-  // Now link the region.
-  if (_tail != NULL) {
-    _tail->set_next(hr);
-    hr->set_prev(_tail);
-  } else {
-    _head = hr;
-  }
-  _tail = hr;
-}
-
-inline HeapRegion* FreeRegionList::remove_head() {
-  assert(!is_empty(), hrs_ext_msg(this, "the list should not be empty"));
-  assert(length() > 0 && _head != NULL && _tail != NULL,
-         hrs_ext_msg(this, "invariant"));
-
-  // We need to unlink it first.
-  HeapRegion* hr = _head;
-  _head = hr->next();
+inline HeapRegion* FreeRegionList::remove_from_head_impl() {
+  HeapRegion* result = _head;
+  _head = result->next();
   if (_head == NULL) {
     _tail = NULL;
   } else {
     _head->set_prev(NULL);
   }
-  hr->set_next(NULL);
+  result->set_next(NULL);
+  return result;
+}
+
+inline HeapRegion* FreeRegionList::remove_from_tail_impl() {
+  HeapRegion* result = _tail;
+
+  _tail = result->prev();
+  if (_tail == NULL) {
+    _head = NULL;
+  } else {
+    _tail->set_next(NULL);
+  }
+  result->set_prev(NULL);
+  return result;
+}
+
+inline HeapRegion* FreeRegionList::remove_region(bool from_head) {
+  check_mt_safety();
+  verify_optional();
+
+  if (is_empty()) {
+    return NULL;
+  }
+  assert(length() > 0 && _head != NULL && _tail != NULL,
+         hrs_ext_msg(this, "invariant"));
+
+  HeapRegion* hr;
+
+  if (from_head) {
+    hr = remove_from_head_impl();
+  } else {
+    hr = remove_from_tail_impl();
+  }
 
   if (_last == hr) {
     _last = NULL;
@@ -154,56 +148,5 @@
   return hr;
 }
 
-inline HeapRegion* FreeRegionList::remove_head_or_null() {
-  check_mt_safety();
-  if (!is_empty()) {
-    return remove_head();
-  } else {
-    return NULL;
-  }
-}
-
-inline HeapRegion* FreeRegionList::remove_tail() {
-  assert(!is_empty(), hrs_ext_msg(this, "The list should not be empty"));
-  assert(length() > 0 && _head != NULL && _tail != NULL,
-         hrs_ext_msg(this, "invariant"));
-
-  // We need to unlink it first
-  HeapRegion* hr = _tail;
-
-  _tail = hr->prev();
-  if (_tail == NULL) {
-    _head = NULL;
-  } else {
-    _tail->set_next(NULL);
-  }
-  hr->set_prev(NULL);
+#endif // SHARE_VM_GC_IMPLEMENTATION_G1_HEAPREGIONSET_INLINE_HPP
 
-  if (_last == hr) {
-    _last = NULL;
-  }
-
-  // remove() will verify the region and check mt safety.
-  remove(hr);
-  return hr;
-}
-
-inline HeapRegion* FreeRegionList::remove_tail_or_null() {
-  check_mt_safety();
-
-  if (!is_empty()) {
-    return remove_tail();
-  } else {
-    return NULL;
-  }
-}
-
-inline HeapRegion* FreeRegionList::remove_region(bool from_head) {
-  if (from_head) {
-    return remove_head_or_null();
-  } else {
-    return remove_tail_or_null();
-  }
-}
-
-#endif // SHARE_VM_GC_IMPLEMENTATION_G1_HEAPREGIONSET_INLINE_HPP
--- a/src/share/vm/gc_implementation/g1/vmStructs_g1.hpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/gc_implementation/g1/vmStructs_g1.hpp	Fri Sep 05 06:26:44 2014 -0400
@@ -43,10 +43,9 @@
   nonstatic_field(G1HeapRegionTable, _shift_by,         uint)                 \
                                                                               \
   nonstatic_field(HeapRegionSeq,   _regions,            G1HeapRegionTable)    \
-  nonstatic_field(HeapRegionSeq,   _committed_length,   uint)                 \
+  nonstatic_field(HeapRegionSeq,   _num_committed,      uint)                 \
                                                                               \
   nonstatic_field(G1CollectedHeap, _hrs,                HeapRegionSeq)        \
-  nonstatic_field(G1CollectedHeap, _g1_committed,       MemRegion)            \
   nonstatic_field(G1CollectedHeap, _summary_bytes_used, size_t)               \
   nonstatic_field(G1CollectedHeap, _g1mm,               G1MonitoringSupport*) \
   nonstatic_field(G1CollectedHeap, _old_set,            HeapRegionSetBase)    \
--- a/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -78,6 +78,7 @@
                         (HeapWord*)(heap_rs.base() + heap_rs.size()));
 
   CardTableExtension* const barrier_set = new CardTableExtension(_reserved, 3);
+  barrier_set->initialize();
   _barrier_set = barrier_set;
   oopDesc::set_bs(_barrier_set);
   if (_barrier_set == NULL) {
@@ -484,10 +485,6 @@
   young_gen()->eden_space()->ensure_parsability();
 }
 
-size_t ParallelScavengeHeap::unsafe_max_alloc() {
-  return young_gen()->eden_space()->free_in_bytes();
-}
-
 size_t ParallelScavengeHeap::tlab_capacity(Thread* thr) const {
   return young_gen()->eden_space()->tlab_capacity(thr);
 }
--- a/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.hpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.hpp	Fri Sep 05 06:26:44 2014 -0400
@@ -184,8 +184,6 @@
   void accumulate_statistics_all_tlabs();
   void resize_all_tlabs();
 
-  size_t unsafe_max_alloc();
-
   bool supports_tlab_allocation() const { return true; }
 
   size_t tlab_capacity(Thread* thr) const;
--- a/src/share/vm/gc_implementation/parallelScavenge/vmPSOperations.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/gc_implementation/parallelScavenge/vmPSOperations.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -70,7 +70,7 @@
     "must be a ParallelScavengeHeap");
 
   GCCauseSetter gccs(heap, _gc_cause);
-  if (_gc_cause == GCCause::_gc_locker
+  if (_gc_cause == GCCause::_gc_locker || _gc_cause == GCCause::_wb_young_gc
       DEBUG_ONLY(|| _gc_cause == GCCause::_scavenge_alot)) {
     // If (and only if) the scavenge fails, this will invoke a full gc.
     heap->invoke_scavenge();
--- a/src/share/vm/gc_interface/collectedHeap.hpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/gc_interface/collectedHeap.hpp	Fri Sep 05 06:26:44 2014 -0400
@@ -395,15 +395,6 @@
   // allocation from them and necessitating allocation of new TLABs.
   virtual void ensure_parsability(bool retire_tlabs);
 
-  // Return an estimate of the maximum allocation that could be performed
-  // without triggering any collection or expansion activity.  In a
-  // generational collector, for example, this is probably the largest
-  // allocation that could be supported (without expansion) in the youngest
-  // generation.  It is "unsafe" because no locks are taken; the result
-  // should be treated as an approximation, not a guarantee, for use in
-  // heuristic resizing decisions.
-  virtual size_t unsafe_max_alloc() = 0;
-
   // Section on thread-local allocation buffers (TLABs)
   // If the heap supports thread-local allocation buffers, it should override
   // the following methods:
--- a/src/share/vm/gc_interface/gcCause.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/gc_interface/gcCause.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -51,6 +51,9 @@
     case _heap_dump:
       return "Heap Dump Initiated GC";
 
+    case _wb_young_gc:
+      return "WhiteBox Initiated Young GC";
+
     case _no_gc:
       return "No GC";
 
--- a/src/share/vm/gc_interface/gcCause.hpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/gc_interface/gcCause.hpp	Fri Sep 05 06:26:44 2014 -0400
@@ -46,6 +46,7 @@
     _gc_locker,
     _heap_inspection,
     _heap_dump,
+    _wb_young_gc,
 
     /* implementation independent, but reserved for GC use */
     _no_gc,
--- a/src/share/vm/memory/allocation.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/memory/allocation.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -438,24 +438,22 @@
 }
 
 //------------------------------Arena------------------------------------------
-NOT_PRODUCT(volatile jint Arena::_instance_count = 0;)
-
-Arena::Arena(size_t init_size) {
+Arena::Arena(MEMFLAGS flag, size_t init_size) : _flags(flag), _size_in_bytes(0)  {
   size_t round_size = (sizeof (char *)) - 1;
   init_size = (init_size+round_size) & ~round_size;
   _first = _chunk = new (AllocFailStrategy::EXIT_OOM, init_size) Chunk(init_size);
   _hwm = _chunk->bottom();      // Save the cached hwm, max
   _max = _chunk->top();
+  MemTracker::record_new_arena(flag);
   set_size_in_bytes(init_size);
-  NOT_PRODUCT(Atomic::inc(&_instance_count);)
 }
 
-Arena::Arena() {
+Arena::Arena(MEMFLAGS flag) : _flags(flag), _size_in_bytes(0) {
   _first = _chunk = new (AllocFailStrategy::EXIT_OOM, Chunk::init_size) Chunk(Chunk::init_size);
   _hwm = _chunk->bottom();      // Save the cached hwm, max
   _max = _chunk->top();
+  MemTracker::record_new_arena(flag);
   set_size_in_bytes(Chunk::init_size);
-  NOT_PRODUCT(Atomic::inc(&_instance_count);)
 }
 
 Arena *Arena::move_contents(Arena *copy) {
@@ -477,7 +475,7 @@
 
 Arena::~Arena() {
   destruct_contents();
-  NOT_PRODUCT(Atomic::dec(&_instance_count);)
+  MemTracker::record_arena_free(_flags);
 }
 
 void* Arena::operator new(size_t size) throw() {
@@ -493,21 +491,21 @@
   // dynamic memory type binding
 void* Arena::operator new(size_t size, MEMFLAGS flags) throw() {
 #ifdef ASSERT
-  void* p = (void*)AllocateHeap(size, flags|otArena, CALLER_PC);
+  void* p = (void*)AllocateHeap(size, flags, CALLER_PC);
   if (PrintMallocFree) trace_heap_malloc(size, "Arena-new", p);
   return p;
 #else
-  return (void *) AllocateHeap(size, flags|otArena, CALLER_PC);
+  return (void *) AllocateHeap(size, flags, CALLER_PC);
 #endif
 }
 
 void* Arena::operator new(size_t size, const std::nothrow_t& nothrow_constant, MEMFLAGS flags) throw() {
 #ifdef ASSERT
-  void* p = os::malloc(size, flags|otArena, CALLER_PC);
+  void* p = os::malloc(size, flags, CALLER_PC);
   if (PrintMallocFree) trace_heap_malloc(size, "Arena-new", p);
   return p;
 #else
-  return os::malloc(size, flags|otArena, CALLER_PC);
+  return os::malloc(size, flags, CALLER_PC);
 #endif
 }
 
@@ -532,8 +530,9 @@
 // change the size
 void Arena::set_size_in_bytes(size_t size) {
   if (_size_in_bytes != size) {
+    long delta = (long)(size - size_in_bytes());
     _size_in_bytes = size;
-    MemTracker::record_arena_size((address)this, size);
+    MemTracker::record_arena_size_change(delta, _flags);
   }
 }
 
--- a/src/share/vm/memory/allocation.hpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/memory/allocation.hpp	Fri Sep 05 06:26:44 2014 -0400
@@ -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
@@ -133,51 +133,34 @@
 
 
 /*
- * MemoryType bitmap layout:
- * | 16 15 14 13 12 11 10 09 | 08 07 06 05 | 04 03 02 01 |
- * |      memory type        |   object    | reserved    |
- * |                         |     type    |             |
+ * Memory types
  */
 enum MemoryType {
   // Memory type by sub systems. It occupies lower byte.
-  mtNone              = 0x0000,  // undefined
-  mtClass             = 0x0100,  // memory class for Java classes
-  mtThread            = 0x0200,  // memory for thread objects
-  mtThreadStack       = 0x0300,
-  mtCode              = 0x0400,  // memory for generated code
-  mtGC                = 0x0500,  // memory for GC
-  mtCompiler          = 0x0600,  // memory for compiler
-  mtInternal          = 0x0700,  // memory used by VM, but does not belong to
+  mtJavaHeap          = 0x00,  // Java heap
+  mtClass             = 0x01,  // memory class for Java classes
+  mtThread            = 0x02,  // memory for thread objects
+  mtThreadStack       = 0x03,
+  mtCode              = 0x04,  // memory for generated code
+  mtGC                = 0x05,  // memory for GC
+  mtCompiler          = 0x06,  // memory for compiler
+  mtInternal          = 0x07,  // memory used by VM, but does not belong to
                                  // any of above categories, and not used for
                                  // native memory tracking
-  mtOther             = 0x0800,  // memory not used by VM
-  mtSymbol            = 0x0900,  // symbol
-  mtNMT               = 0x0A00,  // memory used by native memory tracking
-  mtChunk             = 0x0B00,  // chunk that holds content of arenas
-  mtJavaHeap          = 0x0C00,  // Java heap
-  mtClassShared       = 0x0D00,  // class data sharing
-  mtTest              = 0x0E00,  // Test type for verifying NMT
-  mtTracing           = 0x0F00,  // memory used for Tracing
-  mt_number_of_types  = 0x000F,  // number of memory types (mtDontTrack
+  mtOther             = 0x08,  // memory not used by VM
+  mtSymbol            = 0x09,  // symbol
+  mtNMT               = 0x0A,  // memory used by native memory tracking
+  mtClassShared       = 0x0B,  // class data sharing
+  mtChunk             = 0x0C,  // chunk that holds content of arenas
+  mtTest              = 0x0D,  // Test type for verifying NMT
+  mtTracing           = 0x0E,  // memory used for Tracing
+  mtNone              = 0x0F,  // undefined
+  mt_number_of_types  = 0x10   // number of memory types (mtDontTrack
                                  // is not included as validate type)
-  mtDontTrack         = 0x0F00,  // memory we do not or cannot track
-  mt_masks            = 0x7F00,
-
-  // object type mask
-  otArena             = 0x0010, // an arena object
-  otNMTRecorder       = 0x0020, // memory recorder object
-  ot_masks            = 0x00F0
 };
 
-#define IS_MEMORY_TYPE(flags, type) ((flags & mt_masks) == type)
-#define HAS_VALID_MEMORY_TYPE(flags)((flags & mt_masks) != mtNone)
-#define FLAGS_TO_MEMORY_TYPE(flags) (flags & mt_masks)
+typedef MemoryType MEMFLAGS;
 
-#define IS_ARENA_OBJ(flags)         ((flags & ot_masks) == otArena)
-#define IS_NMT_RECORDER(flags)      ((flags & ot_masks) == otNMTRecorder)
-#define NMT_CAN_TRACK(flags)        (!IS_NMT_RECORDER(flags) && !(IS_MEMORY_TYPE(flags, mtDontTrack)))
-
-typedef unsigned short MEMFLAGS;
 
 #if INCLUDE_NMT
 
@@ -189,27 +172,23 @@
 
 #endif // INCLUDE_NMT
 
-// debug build does not inline
-#if defined(_NMT_NOINLINE_)
-  #define CURRENT_PC       (NMT_track_callsite ? os::get_caller_pc(1) : 0)
-  #define CALLER_PC        (NMT_track_callsite ? os::get_caller_pc(2) : 0)
-  #define CALLER_CALLER_PC (NMT_track_callsite ? os::get_caller_pc(3) : 0)
-#else
-  #define CURRENT_PC      (NMT_track_callsite? os::get_caller_pc(0) : 0)
-  #define CALLER_PC       (NMT_track_callsite ? os::get_caller_pc(1) : 0)
-  #define CALLER_CALLER_PC (NMT_track_callsite ? os::get_caller_pc(2) : 0)
-#endif
-
+class NativeCallStack;
 
 
 template <MEMFLAGS F> class CHeapObj ALLOCATION_SUPER_CLASS_SPEC {
  public:
-  _NOINLINE_ void* operator new(size_t size, address caller_pc = 0) throw();
+  _NOINLINE_ void* operator new(size_t size, const NativeCallStack& stack) throw();
+  _NOINLINE_ void* operator new(size_t size) throw();
   _NOINLINE_ void* operator new (size_t size, const std::nothrow_t&  nothrow_constant,
-                               address caller_pc = 0) throw();
-  _NOINLINE_ void* operator new [](size_t size, address caller_pc = 0) throw();
+                               const NativeCallStack& stack) throw();
+  _NOINLINE_ void* operator new (size_t size, const std::nothrow_t&  nothrow_constant)
+                               throw();
+  _NOINLINE_ void* operator new [](size_t size, const NativeCallStack& stack) throw();
+  _NOINLINE_ void* operator new [](size_t size) throw();
   _NOINLINE_ void* operator new [](size_t size, const std::nothrow_t&  nothrow_constant,
-                               address caller_pc = 0) throw();
+                               const NativeCallStack& stack) throw();
+  _NOINLINE_ void* operator new [](size_t size, const std::nothrow_t&  nothrow_constant)
+                               throw();
   void  operator delete(void* p);
   void  operator delete [] (void* p);
 };
@@ -384,13 +363,15 @@
 
 //------------------------------Arena------------------------------------------
 // Fast allocation of memory
-class Arena : public CHeapObj<mtNone|otArena> {
+class Arena : public CHeapObj<mtNone> {
 protected:
   friend class ResourceMark;
   friend class HandleMark;
   friend class NoHandleMark;
   friend class VMStructs;
 
+  MEMFLAGS    _flags;           // Memory tracking flags
+
   Chunk *_first;                // First chunk
   Chunk *_chunk;                // current chunk
   char *_hwm, *_max;            // High water mark and max in current chunk
@@ -418,8 +399,8 @@
  }
 
  public:
-  Arena();
-  Arena(size_t init_size);
+  Arena(MEMFLAGS memflag);
+  Arena(MEMFLAGS memflag, size_t init_size);
   ~Arena();
   void  destruct_contents();
   char* hwm() const             { return _hwm; }
@@ -518,8 +499,6 @@
   static void free_malloced_objects(Chunk* chunk, char* hwm, char* max, char* hwm2)  PRODUCT_RETURN;
   static void free_all(char** start, char** end)                                     PRODUCT_RETURN;
 
-  // how many arena instances
-  NOT_PRODUCT(static volatile jint _instance_count;)
 private:
   // Reset this Arena to empty, access will trigger grow if necessary
   void   reset(void) {
@@ -681,7 +660,7 @@
   NEW_C_HEAP_ARRAY3(type, (size), memflags, pc, AllocFailStrategy::RETURN_NULL)
 
 #define NEW_C_HEAP_ARRAY_RETURN_NULL(type, size, memflags)\
-  NEW_C_HEAP_ARRAY3(type, (size), memflags, (address)0, AllocFailStrategy::RETURN_NULL)
+  NEW_C_HEAP_ARRAY3(type, (size), memflags, CURRENT_PC, AllocFailStrategy::RETURN_NULL)
 
 #define REALLOC_C_HEAP_ARRAY(type, old, size, memflags)\
   (type*) (ReallocateHeap((char*)(old), (size) * sizeof(type), memflags))
--- a/src/share/vm/memory/allocation.inline.hpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/memory/allocation.inline.hpp	Fri Sep 05 06:26:44 2014 -0400
@@ -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
@@ -27,6 +27,7 @@
 
 #include "runtime/atomic.inline.hpp"
 #include "runtime/os.hpp"
+#include "services/memTracker.hpp"
 
 // Explicit C-heap memory management
 
@@ -49,12 +50,10 @@
 #endif
 
 // allocate using malloc; will fail if no memory available
-inline char* AllocateHeap(size_t size, MEMFLAGS flags, address pc = 0,
+inline char* AllocateHeap(size_t size, MEMFLAGS flags,
+    const NativeCallStack& stack,
     AllocFailType alloc_failmode = AllocFailStrategy::EXIT_OOM) {
-  if (pc == 0) {
-    pc = CURRENT_PC;
-  }
-  char* p = (char*) os::malloc(size, flags, pc);
+  char* p = (char*) os::malloc(size, flags, stack);
   #ifdef ASSERT
   if (PrintMallocFree) trace_heap_malloc(size, "AllocateHeap", p);
   #endif
@@ -63,10 +62,14 @@
   }
   return p;
 }
+inline char* AllocateHeap(size_t size, MEMFLAGS flags,
+    AllocFailType alloc_failmode = AllocFailStrategy::EXIT_OOM) {
+  return AllocateHeap(size, flags, CURRENT_PC, alloc_failmode);
+}
 
-inline char* ReallocateHeap(char *old, size_t size, MEMFLAGS flags,
+inline char* ReallocateHeap(char *old, size_t size, MEMFLAGS flag,
     AllocFailType alloc_failmode = AllocFailStrategy::EXIT_OOM) {
-  char* p = (char*) os::realloc(old, size, flags, CURRENT_PC);
+  char* p = (char*) os::realloc(old, size, flag, CURRENT_PC);
   #ifdef ASSERT
   if (PrintMallocFree) trace_heap_malloc(size, "ReallocateHeap", p);
   #endif
@@ -85,8 +88,22 @@
 
 
 template <MEMFLAGS F> void* CHeapObj<F>::operator new(size_t size,
-      address caller_pc) throw() {
-    void* p = (void*)AllocateHeap(size, F, (caller_pc != 0 ? caller_pc : CALLER_PC));
+      const NativeCallStack& stack) throw() {
+  void* p = (void*)AllocateHeap(size, F, stack);
+#ifdef ASSERT
+  if (PrintMallocFree) trace_heap_malloc(size, "CHeapObj-new", p);
+#endif
+  return p;
+}
+
+template <MEMFLAGS F> void* CHeapObj<F>::operator new(size_t size) throw() {
+  return CHeapObj<F>::operator new(size, CALLER_PC);
+}
+
+template <MEMFLAGS F> void* CHeapObj<F>::operator new (size_t size,
+  const std::nothrow_t&  nothrow_constant, const NativeCallStack& stack) throw() {
+  void* p = (void*)AllocateHeap(size, F, stack,
+      AllocFailStrategy::RETURN_NULL);
 #ifdef ASSERT
     if (PrintMallocFree) trace_heap_malloc(size, "CHeapObj-new", p);
 #endif
@@ -94,23 +111,28 @@
   }
 
 template <MEMFLAGS F> void* CHeapObj<F>::operator new (size_t size,
-  const std::nothrow_t&  nothrow_constant, address caller_pc) throw() {
-  void* p = (void*)AllocateHeap(size, F, (caller_pc != 0 ? caller_pc : CALLER_PC),
-      AllocFailStrategy::RETURN_NULL);
-#ifdef ASSERT
-    if (PrintMallocFree) trace_heap_malloc(size, "CHeapObj-new", p);
-#endif
-    return p;
+  const std::nothrow_t& nothrow_constant) throw() {
+  return CHeapObj<F>::operator new(size, nothrow_constant, CALLER_PC);
 }
 
 template <MEMFLAGS F> void* CHeapObj<F>::operator new [](size_t size,
-      address caller_pc) throw() {
-    return CHeapObj<F>::operator new(size, caller_pc);
+      const NativeCallStack& stack) throw() {
+  return CHeapObj<F>::operator new(size, stack);
+}
+
+template <MEMFLAGS F> void* CHeapObj<F>::operator new [](size_t size)
+  throw() {
+  return CHeapObj<F>::operator new(size, CALLER_PC);
 }
 
 template <MEMFLAGS F> void* CHeapObj<F>::operator new [](size_t size,
-  const std::nothrow_t&  nothrow_constant, address caller_pc) throw() {
-    return CHeapObj<F>::operator new(size, nothrow_constant, caller_pc);
+  const std::nothrow_t&  nothrow_constant, const NativeCallStack& stack) throw() {
+  return CHeapObj<F>::operator new(size, nothrow_constant, stack);
+}
+
+template <MEMFLAGS F> void* CHeapObj<F>::operator new [](size_t size,
+  const std::nothrow_t& nothrow_constant) throw() {
+  return CHeapObj<F>::operator new(size, nothrow_constant, CALLER_PC);
 }
 
 template <MEMFLAGS F> void CHeapObj<F>::operator delete(void* p){
--- a/src/share/vm/memory/cardTableModRefBS.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/memory/cardTableModRefBS.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -44,13 +44,6 @@
 // enumerate ref fields that have been modified (since the last
 // enumeration.)
 
-size_t CardTableModRefBS::cards_required(size_t covered_words)
-{
-  // Add one for a guard card, used to detect errors.
-  const size_t words = align_size_up(covered_words, card_size_in_words);
-  return words / card_size_in_words + 1;
-}
-
 size_t CardTableModRefBS::compute_byte_map_size()
 {
   assert(_guard_index == cards_required(_whole_heap.word_size()) - 1,
@@ -64,27 +57,50 @@
                                      int max_covered_regions):
   ModRefBarrierSet(max_covered_regions),
   _whole_heap(whole_heap),
-  _guard_index(cards_required(whole_heap.word_size()) - 1),
-  _last_valid_index(_guard_index - 1),
+  _guard_index(0),
+  _guard_region(),
+  _last_valid_index(0),
   _page_size(os::vm_page_size()),
-  _byte_map_size(compute_byte_map_size())
+  _byte_map_size(0),
+  _covered(NULL),
+  _committed(NULL),
+  _cur_covered_regions(0),
+  _byte_map(NULL),
+  byte_map_base(NULL),
+  // LNC functionality
+  _lowest_non_clean(NULL),
+  _lowest_non_clean_chunk_size(NULL),
+  _lowest_non_clean_base_chunk_index(NULL),
+  _last_LNC_resizing_collection(NULL)
 {
   _kind = BarrierSet::CardTableModRef;
 
+  assert((uintptr_t(_whole_heap.start())  & (card_size - 1))  == 0, "heap must start at card boundary");
+  assert((uintptr_t(_whole_heap.end()) & (card_size - 1))  == 0, "heap must end at card boundary");
+
+  assert(card_size <= 512, "card_size must be less than 512"); // why?
+
+  _covered   = new MemRegion[_max_covered_regions];
+  if (_covered == NULL) {
+    vm_exit_during_initialization("Could not allocate card table covered region set.");
+  }
+}
+
+void CardTableModRefBS::initialize() {
+  _guard_index = cards_required(_whole_heap.word_size()) - 1;
+  _last_valid_index = _guard_index - 1;
+
+  _byte_map_size = compute_byte_map_size();
+
   HeapWord* low_bound  = _whole_heap.start();
   HeapWord* high_bound = _whole_heap.end();
-  assert((uintptr_t(low_bound)  & (card_size - 1))  == 0, "heap must start at card boundary");
-  assert((uintptr_t(high_bound) & (card_size - 1))  == 0, "heap must end at card boundary");
 
-  assert(card_size <= 512, "card_size must be less than 512"); // why?
-
-  _covered   = new MemRegion[max_covered_regions];
-  _committed = new MemRegion[max_covered_regions];
-  if (_covered == NULL || _committed == NULL) {
-    vm_exit_during_initialization("couldn't alloc card table covered region set.");
+  _cur_covered_regions = 0;
+  _committed = new MemRegion[_max_covered_regions];
+  if (_committed == NULL) {
+    vm_exit_during_initialization("Could not allocate card table committed region set.");
   }
 
-  _cur_covered_regions = 0;
   const size_t rs_align = _page_size == (size_t) os::vm_page_size() ? 0 :
     MAX2(_page_size, (size_t) os::vm_allocation_granularity());
   ReservedSpace heap_rs(_byte_map_size, rs_align, false);
@@ -114,20 +130,20 @@
                             !ExecMem, "card table last card");
   *guard_card = last_card;
 
-   _lowest_non_clean =
-    NEW_C_HEAP_ARRAY(CardArr, max_covered_regions, mtGC);
+  _lowest_non_clean =
+    NEW_C_HEAP_ARRAY(CardArr, _max_covered_regions, mtGC);
   _lowest_non_clean_chunk_size =
-    NEW_C_HEAP_ARRAY(size_t, max_covered_regions, mtGC);
+    NEW_C_HEAP_ARRAY(size_t, _max_covered_regions, mtGC);
   _lowest_non_clean_base_chunk_index =
-    NEW_C_HEAP_ARRAY(uintptr_t, max_covered_regions, mtGC);
+    NEW_C_HEAP_ARRAY(uintptr_t, _max_covered_regions, mtGC);
   _last_LNC_resizing_collection =
-    NEW_C_HEAP_ARRAY(int, max_covered_regions, mtGC);
+    NEW_C_HEAP_ARRAY(int, _max_covered_regions, mtGC);
   if (_lowest_non_clean == NULL
       || _lowest_non_clean_chunk_size == NULL
       || _lowest_non_clean_base_chunk_index == NULL
       || _last_LNC_resizing_collection == NULL)
     vm_exit_during_initialization("couldn't allocate an LNC array.");
-  for (int i = 0; i < max_covered_regions; i++) {
+  for (int i = 0; i < _max_covered_regions; i++) {
     _lowest_non_clean[i] = NULL;
     _lowest_non_clean_chunk_size[i] = 0;
     _last_LNC_resizing_collection[i] = -1;
@@ -650,7 +666,7 @@
                                       jbyte val, bool val_equals) {
   jbyte* start    = byte_for(mr.start());
   jbyte* end      = byte_for(mr.last());
-  bool   failures = false;
+  bool failures = false;
   for (jbyte* curr = start; curr <= end; ++curr) {
     jbyte curr_val = *curr;
     bool failed = (val_equals) ? (curr_val != val) : (curr_val == val);
--- a/src/share/vm/memory/cardTableModRefBS.hpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/memory/cardTableModRefBS.hpp	Fri Sep 05 06:26:44 2014 -0400
@@ -96,12 +96,12 @@
   // The declaration order of these const fields is important; see the
   // constructor before changing.
   const MemRegion _whole_heap;       // the region covered by the card table
-  const size_t    _guard_index;      // index of very last element in the card
+  size_t          _guard_index;      // index of very last element in the card
                                      // table; it is set to a guard value
                                      // (last_card) and should never be modified
-  const size_t    _last_valid_index; // index of the last valid element
+  size_t          _last_valid_index; // index of the last valid element
   const size_t    _page_size;        // page size used when mapping _byte_map
-  const size_t    _byte_map_size;    // in bytes
+  size_t          _byte_map_size;    // in bytes
   jbyte*          _byte_map;         // the card marking array
 
   int _cur_covered_regions;
@@ -123,7 +123,12 @@
  protected:
   // Initialization utilities; covered_words is the size of the covered region
   // in, um, words.
-  inline size_t cards_required(size_t covered_words);
+  inline size_t cards_required(size_t covered_words) {
+    // Add one for a guard card, used to detect errors.
+    const size_t words = align_size_up(covered_words, card_size_in_words);
+    return words / card_size_in_words + 1;
+  }
+
   inline size_t compute_byte_map_size();
 
   // Finds and return the index of the region, if any, to which the given
@@ -137,7 +142,7 @@
   int find_covering_region_containing(HeapWord* addr);
 
   // Resize one of the regions covered by the remembered set.
-  void resize_covered_region(MemRegion new_region);
+  virtual void resize_covered_region(MemRegion new_region);
 
   // Returns the leftmost end of a committed region corresponding to a
   // covered region before covered region "ind", or else "NULL" if "ind" is
@@ -282,6 +287,8 @@
   CardTableModRefBS(MemRegion whole_heap, int max_covered_regions);
   ~CardTableModRefBS();
 
+  virtual void initialize();
+
   // *** Barrier set functions.
 
   bool has_write_ref_pre_barrier() { return false; }
--- a/src/share/vm/memory/cardTableRS.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/memory/cardTableRS.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -53,9 +53,10 @@
 #else
   _ct_bs = new CardTableModRefBSForCTRS(whole_heap, max_covered_regions);
 #endif
+  _ct_bs->initialize();
   set_bs(_ct_bs);
   _last_cur_val_in_gen = NEW_C_HEAP_ARRAY3(jbyte, GenCollectedHeap::max_gens + 1,
-                         mtGC, 0, AllocFailStrategy::RETURN_NULL);
+                         mtGC, CURRENT_PC, AllocFailStrategy::RETURN_NULL);
   if (_last_cur_val_in_gen == NULL) {
     vm_exit_during_initialization("Could not create last_cur_val_in_gen array.");
   }
--- a/src/share/vm/memory/collectorPolicy.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/memory/collectorPolicy.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -969,7 +969,8 @@
 }
 
 void MarkSweepPolicy::initialize_generations() {
-  _generations = NEW_C_HEAP_ARRAY3(GenerationSpecPtr, number_of_generations(), mtGC, 0, AllocFailStrategy::RETURN_NULL);
+  _generations = NEW_C_HEAP_ARRAY3(GenerationSpecPtr, number_of_generations(), mtGC, CURRENT_PC,
+    AllocFailStrategy::RETURN_NULL);
   if (_generations == NULL) {
     vm_exit_during_initialization("Unable to allocate gen spec");
   }
--- a/src/share/vm/memory/genCollectedHeap.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/memory/genCollectedHeap.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -704,10 +704,6 @@
   return _gens[0]->end_addr();
 }
 
-size_t GenCollectedHeap::unsafe_max_alloc() {
-  return _gens[0]->unsafe_max_alloc_nogc();
-}
-
 // public collection interfaces
 
 void GenCollectedHeap::collect(GCCause::Cause cause) {
@@ -718,15 +714,18 @@
 #else  // INCLUDE_ALL_GCS
     ShouldNotReachHere();
 #endif // INCLUDE_ALL_GCS
+  } else if (cause == GCCause::_wb_young_gc) {
+    // minor collection for WhiteBox API
+    collect(cause, 0);
   } else {
 #ifdef ASSERT
-    if (cause == GCCause::_scavenge_alot) {
-      // minor collection only
-      collect(cause, 0);
-    } else {
-      // Stop-the-world full collection
-      collect(cause, n_gens() - 1);
-    }
+  if (cause == GCCause::_scavenge_alot) {
+    // minor collection only
+    collect(cause, 0);
+  } else {
+    // Stop-the-world full collection
+    collect(cause, n_gens() - 1);
+  }
 #else
     // Stop-the-world full collection
     collect(cause, n_gens() - 1);
--- a/src/share/vm/memory/genCollectedHeap.hpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/memory/genCollectedHeap.hpp	Fri Sep 05 06:26:44 2014 -0400
@@ -166,14 +166,6 @@
   HeapWord** top_addr() const;
   HeapWord** end_addr() const;
 
-  // Return an estimate of the maximum allocation that could be performed
-  // without triggering any collection activity.  In a generational
-  // collector, for example, this is probably the largest allocation that
-  // could be supported in the youngest generation.  It is "unsafe" because
-  // no locks are taken; the result should be treated as an approximation,
-  // not a guarantee.
-  size_t unsafe_max_alloc();
-
   // Does this heap support heap inspection? (+PrintClassHistogram)
   virtual bool supports_heap_inspection() const { return true; }
 
--- a/src/share/vm/memory/heapInspection.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/memory/heapInspection.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -135,7 +135,7 @@
   _ref = (HeapWord*) Universe::boolArrayKlassObj();
   _buckets =
     (KlassInfoBucket*)  AllocateHeap(sizeof(KlassInfoBucket) * _num_buckets,
-                                            mtInternal, 0, AllocFailStrategy::RETURN_NULL);
+       mtInternal, CURRENT_PC, AllocFailStrategy::RETURN_NULL);
   if (_buckets != NULL) {
     _size = _num_buckets;
     for (int index = 0; index < _size; index++) {
--- a/src/share/vm/memory/memRegion.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/memory/memRegion.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -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
@@ -103,11 +103,13 @@
 }
 
 void* MemRegion::operator new(size_t size) throw() {
-  return (address)AllocateHeap(size, mtGC, 0, AllocFailStrategy::RETURN_NULL);
+  return (address)AllocateHeap(size, mtGC, CURRENT_PC,
+    AllocFailStrategy::RETURN_NULL);
 }
 
 void* MemRegion::operator new [](size_t size) throw() {
-  return (address)AllocateHeap(size, mtGC, 0, AllocFailStrategy::RETURN_NULL);
+  return (address)AllocateHeap(size, mtGC, CURRENT_PC,
+    AllocFailStrategy::RETURN_NULL);
 }
 void  MemRegion::operator delete(void* p) {
   FreeHeap(p, mtGC);
--- a/src/share/vm/memory/resourceArea.hpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/memory/resourceArea.hpp	Fri Sep 05 06:26:44 2014 -0400
@@ -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
@@ -49,11 +49,11 @@
   debug_only(static int _warned;)       // to suppress multiple warnings
 
 public:
-  ResourceArea() {
+  ResourceArea() : Arena(mtThread) {
     debug_only(_nesting = 0;)
   }
 
-  ResourceArea(size_t init_size) : Arena(init_size) {
+  ResourceArea(size_t init_size) : Arena(mtThread, init_size) {
     debug_only(_nesting = 0;);
   }
 
@@ -64,7 +64,7 @@
     if (UseMallocOnly) {
       // use malloc, but save pointer in res. area for later freeing
       char** save = (char**)internal_malloc_4(sizeof(char*));
-      return (*save = (char*)os::malloc(size, mtThread));
+      return (*save = (char*)os::malloc(size, mtThread, CURRENT_PC));
     }
 #endif
     return (char*)Amalloc(size, alloc_failmode);
--- a/src/share/vm/opto/c2_globals.hpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/opto/c2_globals.hpp	Fri Sep 05 06:26:44 2014 -0400
@@ -656,9 +656,6 @@
   product(bool, UseMathExactIntrinsics, true,                               \
           "Enables intrinsification of various java.lang.Math functions")   \
                                                                             \
-  experimental(bool, ReplaceInParentMaps, false,                            \
-          "Propagate type improvements in callers of inlinee if possible")  \
-                                                                            \
   product(bool, UseTypeSpeculation, true,                                   \
           "Speculatively propagate types from profiles")                    \
                                                                             \
--- a/src/share/vm/opto/callGenerator.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/opto/callGenerator.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -63,12 +63,12 @@
   }
 
   virtual bool      is_parse() const           { return true; }
-  virtual JVMState* generate(JVMState* jvms, Parse* parent_parser);
+  virtual JVMState* generate(JVMState* jvms);
   int is_osr() { return _is_osr; }
 
 };
 
-JVMState* ParseGenerator::generate(JVMState* jvms, Parse* parent_parser) {
+JVMState* ParseGenerator::generate(JVMState* jvms) {
   Compile* C = Compile::current();
 
   if (is_osr()) {
@@ -80,7 +80,7 @@
     return NULL;  // bailing out of the compile; do not try to parse
   }
 
-  Parse parser(jvms, method(), _expected_uses, parent_parser);
+  Parse parser(jvms, method(), _expected_uses);
   // Grab signature for matching/allocation
 #ifdef ASSERT
   if (parser.tf() != (parser.depth() == 1 ? C->tf() : tf())) {
@@ -119,12 +119,12 @@
       _separate_io_proj(separate_io_proj)
   {
   }
-  virtual JVMState* generate(JVMState* jvms, Parse* parent_parser);
+  virtual JVMState* generate(JVMState* jvms);
 
   CallStaticJavaNode* call_node() const { return _call_node; }
 };
 
-JVMState* DirectCallGenerator::generate(JVMState* jvms, Parse* parent_parser) {
+JVMState* DirectCallGenerator::generate(JVMState* jvms) {
   GraphKit kit(jvms);
   bool is_static = method()->is_static();
   address target = is_static ? SharedRuntime::get_resolve_static_call_stub()
@@ -171,10 +171,10 @@
            vtable_index >= 0, "either invalid or usable");
   }
   virtual bool      is_virtual() const          { return true; }
-  virtual JVMState* generate(JVMState* jvms, Parse* parent_parser);
+  virtual JVMState* generate(JVMState* jvms);
 };
 
-JVMState* VirtualCallGenerator::generate(JVMState* jvms, Parse* parent_parser) {
+JVMState* VirtualCallGenerator::generate(JVMState* jvms) {
   GraphKit kit(jvms);
   Node* receiver = kit.argument(0);
 
@@ -276,7 +276,7 @@
   // Convert the CallStaticJava into an inline
   virtual void do_late_inline();
 
-  virtual JVMState* generate(JVMState* jvms, Parse* parent_parser) {
+  virtual JVMState* generate(JVMState* jvms) {
     Compile *C = Compile::current();
     C->print_inlining_skip(this);
 
@@ -290,7 +290,7 @@
     // that the late inlining logic can distinguish between fall
     // through and exceptional uses of the memory and io projections
     // as is done for allocations and macro expansion.
-    return DirectCallGenerator::generate(jvms, parent_parser);
+    return DirectCallGenerator::generate(jvms);
   }
 
   virtual void print_inlining_late(const char* msg) {
@@ -389,7 +389,7 @@
   }
 
   // Now perform the inling using the synthesized JVMState
-  JVMState* new_jvms = _inline_cg->generate(jvms, NULL);
+  JVMState* new_jvms = _inline_cg->generate(jvms);
   if (new_jvms == NULL)  return;  // no change
   if (C->failing())      return;
 
@@ -407,7 +407,7 @@
   C->env()->notice_inlined_method(_inline_cg->method());
   C->set_inlining_progress(true);
 
-  kit.replace_call(call, result);
+  kit.replace_call(call, result, true);
 }
 
 
@@ -429,8 +429,8 @@
 
   virtual bool is_mh_late_inline() const { return true; }
 
-  virtual JVMState* generate(JVMState* jvms, Parse* parent_parser) {
-    JVMState* new_jvms = LateInlineCallGenerator::generate(jvms, parent_parser);
+  virtual JVMState* generate(JVMState* jvms) {
+    JVMState* new_jvms = LateInlineCallGenerator::generate(jvms);
     if (_input_not_const) {
       // inlining won't be possible so no need to enqueue right now.
       call_node()->set_generator(this);
@@ -477,13 +477,13 @@
   LateInlineStringCallGenerator(ciMethod* method, CallGenerator* inline_cg) :
     LateInlineCallGenerator(method, inline_cg) {}
 
-  virtual JVMState* generate(JVMState* jvms, Parse* parent_parser) {
+  virtual JVMState* generate(JVMState* jvms) {
     Compile *C = Compile::current();
     C->print_inlining_skip(this);
 
     C->add_string_late_inline(this);
 
-    JVMState* new_jvms =  DirectCallGenerator::generate(jvms, parent_parser);
+    JVMState* new_jvms =  DirectCallGenerator::generate(jvms);
     return new_jvms;
   }
 
@@ -500,13 +500,13 @@
   LateInlineBoxingCallGenerator(ciMethod* method, CallGenerator* inline_cg) :
     LateInlineCallGenerator(method, inline_cg) {}
 
-  virtual JVMState* generate(JVMState* jvms, Parse* parent_parser) {
+  virtual JVMState* generate(JVMState* jvms) {
     Compile *C = Compile::current();
     C->print_inlining_skip(this);
 
     C->add_boxing_late_inline(this);
 
-    JVMState* new_jvms =  DirectCallGenerator::generate(jvms, parent_parser);
+    JVMState* new_jvms =  DirectCallGenerator::generate(jvms);
     return new_jvms;
   }
 };
@@ -542,7 +542,7 @@
   virtual bool      is_virtual() const          { return _is_virtual; }
   virtual bool      is_deferred() const         { return true; }
 
-  virtual JVMState* generate(JVMState* jvms, Parse* parent_parser);
+  virtual JVMState* generate(JVMState* jvms);
 };
 
 
@@ -552,12 +552,12 @@
   return new WarmCallGenerator(ci, if_cold, if_hot);
 }
 
-JVMState* WarmCallGenerator::generate(JVMState* jvms, Parse* parent_parser) {
+JVMState* WarmCallGenerator::generate(JVMState* jvms) {
   Compile* C = Compile::current();
   if (C->log() != NULL) {
     C->log()->elem("warm_call bci='%d'", jvms->bci());
   }
-  jvms = _if_cold->generate(jvms, parent_parser);
+  jvms = _if_cold->generate(jvms);
   if (jvms != NULL) {
     Node* m = jvms->map()->control();
     if (m->is_CatchProj()) m = m->in(0);  else m = C->top();
@@ -618,7 +618,7 @@
   virtual bool      is_inline()    const    { return _if_hit->is_inline(); }
   virtual bool      is_deferred()  const    { return _if_hit->is_deferred(); }
 
-  virtual JVMState* generate(JVMState* jvms, Parse* parent_parser);
+  virtual JVMState* generate(JVMState* jvms);
 };
 
 
@@ -630,7 +630,7 @@
 }
 
 
-JVMState* PredictedCallGenerator::generate(JVMState* jvms, Parse* parent_parser) {
+JVMState* PredictedCallGenerator::generate(JVMState* jvms) {
   GraphKit kit(jvms);
   PhaseGVN& gvn = kit.gvn();
   // We need an explicit receiver null_check before checking its type.
@@ -648,6 +648,10 @@
     return kit.transfer_exceptions_into_jvms();
   }
 
+  // Make a copy of the replaced nodes in case we need to restore them
+  ReplacedNodes replaced_nodes = kit.map()->replaced_nodes();
+  replaced_nodes.clone();
+
   Node* exact_receiver = receiver;  // will get updated in place...
   Node* slow_ctl = kit.type_check_receiver(receiver,
                                            _predicted_receiver, _hit_prob,
@@ -658,7 +662,7 @@
   { PreserveJVMState pjvms(&kit);
     kit.set_control(slow_ctl);
     if (!kit.stopped()) {
-      slow_jvms = _if_missed->generate(kit.sync_jvms(), parent_parser);
+      slow_jvms = _if_missed->generate(kit.sync_jvms());
       if (kit.failing())
         return NULL;  // might happen because of NodeCountInliningCutoff
       assert(slow_jvms != NULL, "must be");
@@ -679,12 +683,12 @@
   kit.replace_in_map(receiver, exact_receiver);
 
   // Make the hot call:
-  JVMState* new_jvms = _if_hit->generate(kit.sync_jvms(), parent_parser);
+  JVMState* new_jvms = _if_hit->generate(kit.sync_jvms());
   if (new_jvms == NULL) {
     // Inline failed, so make a direct call.
     assert(_if_hit->is_inline(), "must have been a failed inline");
     CallGenerator* cg = CallGenerator::for_direct_call(_if_hit->method());
-    new_jvms = cg->generate(kit.sync_jvms(), parent_parser);
+    new_jvms = cg->generate(kit.sync_jvms());
   }
   kit.add_exception_states_from(new_jvms);
   kit.set_jvms(new_jvms);
@@ -701,6 +705,11 @@
     return kit.transfer_exceptions_into_jvms();
   }
 
+  // There are 2 branches and the replaced nodes are only valid on
+  // one: restore the replaced nodes to what they were before the
+  // branch.
+  kit.map()->set_replaced_nodes(replaced_nodes);
+
   // Finish the diamond.
   kit.C->set_has_split_ifs(true); // Has chance for split-if optimization
   RegionNode* region = new (kit.C) RegionNode(3);
@@ -891,7 +900,7 @@
   virtual bool      is_inlined()   const    { return true; }
   virtual bool      is_intrinsic() const    { return true; }
 
-  virtual JVMState* generate(JVMState* jvms, Parse* parent_parser);
+  virtual JVMState* generate(JVMState* jvms);
 };
 
 
@@ -901,7 +910,7 @@
 }
 
 
-JVMState* PredicatedIntrinsicGenerator::generate(JVMState* jvms, Parse* parent_parser) {
+JVMState* PredicatedIntrinsicGenerator::generate(JVMState* jvms) {
   // The code we want to generate here is:
   //    if (receiver == NULL)
   //        uncommon_Trap
@@ -961,7 +970,7 @@
     if (!kit.stopped()) {
       PreserveJVMState pjvms(&kit);
       // Generate intrinsic code:
-      JVMState* new_jvms = _intrinsic->generate(kit.sync_jvms(), parent_parser);
+      JVMState* new_jvms = _intrinsic->generate(kit.sync_jvms());
       if (new_jvms == NULL) {
         // Intrinsic failed, use normal compilation path for this predicate.
         slow_region->add_req(kit.control());
@@ -986,7 +995,7 @@
     PreserveJVMState pjvms(&kit);
     // Generate normal compilation code:
     kit.set_control(gvn.transform(slow_region));
-    JVMState* new_jvms = _cg->generate(kit.sync_jvms(), parent_parser);
+    JVMState* new_jvms = _cg->generate(kit.sync_jvms());
     if (kit.failing())
       return NULL;  // might happen because of NodeCountInliningCutoff
     assert(new_jvms != NULL, "must be");
@@ -1093,7 +1102,7 @@
   virtual bool      is_virtual() const          { ShouldNotReachHere(); return false; }
   virtual bool      is_trap() const             { return true; }
 
-  virtual JVMState* generate(JVMState* jvms, Parse* parent_parser);
+  virtual JVMState* generate(JVMState* jvms);
 };
 
 
@@ -1105,7 +1114,7 @@
 }
 
 
-JVMState* UncommonTrapCallGenerator::generate(JVMState* jvms, Parse* parent_parser) {
+JVMState* UncommonTrapCallGenerator::generate(JVMState* jvms) {
   GraphKit kit(jvms);
   // Take the trap with arguments pushed on the stack.  (Cf. null_check_receiver).
   int nargs = method()->arg_size();
--- a/src/share/vm/opto/callGenerator.hpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/opto/callGenerator.hpp	Fri Sep 05 06:26:44 2014 -0400
@@ -31,8 +31,6 @@
 #include "opto/type.hpp"
 #include "runtime/deoptimization.hpp"
 
-class Parse;
-
 //---------------------------CallGenerator-------------------------------------
 // The subclasses of this class handle generation of ideal nodes for
 // call sites and method entry points.
@@ -112,7 +110,7 @@
   //
   // If the result is NULL, it means that this CallGenerator was unable
   // to handle the given call, and another CallGenerator should be consulted.
-  virtual JVMState* generate(JVMState* jvms, Parse* parent_parser) = 0;
+  virtual JVMState* generate(JVMState* jvms) = 0;
 
   // How to generate a call site that is inlined:
   static CallGenerator* for_inline(ciMethod* m, float expected_uses = -1);
--- a/src/share/vm/opto/callnode.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/opto/callnode.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -1089,6 +1089,7 @@
 #ifndef PRODUCT
 void SafePointNode::dump_spec(outputStream *st) const {
   st->print(" SafePoint ");
+  _replaced_nodes.dump(st);
 }
 #endif
 
--- a/src/share/vm/opto/callnode.hpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/opto/callnode.hpp	Fri Sep 05 06:26:44 2014 -0400
@@ -30,6 +30,7 @@
 #include "opto/multnode.hpp"
 #include "opto/opcodes.hpp"
 #include "opto/phaseX.hpp"
+#include "opto/replacednodes.hpp"
 #include "opto/type.hpp"
 
 // Portions of code courtesy of Clifford Click
@@ -335,6 +336,7 @@
   OopMap*         _oop_map;   // Array of OopMap info (8-bit char) for GC
   JVMState* const _jvms;      // Pointer to list of JVM State objects
   const TypePtr*  _adr_type;  // What type of memory does this node produce?
+  ReplacedNodes   _replaced_nodes; // During parsing: list of pair of nodes from calls to GraphKit::replace_in_map()
 
   // Many calls take *all* of memory as input,
   // but some produce a limited subset of that memory as output.
@@ -426,6 +428,37 @@
   void               set_next_exception(SafePointNode* n);
   bool                   has_exceptions() const { return next_exception() != NULL; }
 
+  // Helper methods to operate on replaced nodes
+  ReplacedNodes replaced_nodes() const {
+    return _replaced_nodes;
+  }
+
+  void set_replaced_nodes(ReplacedNodes replaced_nodes) {
+    _replaced_nodes = replaced_nodes;
+  }
+
+  void clone_replaced_nodes() {
+    _replaced_nodes.clone();
+  }
+  void record_replaced_node(Node* initial, Node* improved) {
+    _replaced_nodes.record(initial, improved);
+  }
+  void transfer_replaced_nodes_from(SafePointNode* sfpt, uint idx = 0) {
+    _replaced_nodes.transfer_from(sfpt->_replaced_nodes, idx);
+  }
+  void delete_replaced_nodes() {
+    _replaced_nodes.reset();
+  }
+  void apply_replaced_nodes() {
+    _replaced_nodes.apply(this);
+  }
+  void merge_replaced_nodes_with(SafePointNode* sfpt) {
+    _replaced_nodes.merge_with(sfpt->_replaced_nodes);
+  }
+  bool has_replaced_nodes() const {
+    return !_replaced_nodes.is_empty();
+  }
+
   // Standard Node stuff
   virtual int            Opcode() const;
   virtual bool           pinned() const { return true; }
--- a/src/share/vm/opto/compile.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/opto/compile.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -397,6 +397,11 @@
   uint next = 0;
   while (next < useful.size()) {
     Node *n = useful.at(next++);
+    if (n->is_SafePoint()) {
+      // We're done with a parsing phase. Replaced nodes are not valid
+      // beyond that point.
+      n->as_SafePoint()->delete_replaced_nodes();
+    }
     // Use raw traversal of out edges since this code removes out edges
     int max = n->outcnt();
     for (int j = 0; j < max; ++j) {
@@ -666,6 +671,10 @@
                   _printer(IdealGraphPrinter::printer()),
 #endif
                   _congraph(NULL),
+                  _comp_arena(mtCompiler),
+                  _node_arena(mtCompiler),
+                  _old_arena(mtCompiler),
+                  _Compile_types(mtCompiler),
                   _replay_inline_data(NULL),
                   _late_inlines(comp_arena(), 2, 0, NULL),
                   _string_late_inlines(comp_arena(), 2, 0, NULL),
@@ -676,7 +685,6 @@
                   _inlining_incrementally(false),
                   _print_inlining_list(NULL),
                   _print_inlining_idx(0),
-                  _preserve_jvm_state(0),
                   _interpreter_frame_size(0) {
   C = this;
 
@@ -788,7 +796,7 @@
       return;
     }
     JVMState* jvms = build_start_state(start(), tf());
-    if ((jvms = cg->generate(jvms, NULL)) == NULL) {
+    if ((jvms = cg->generate(jvms)) == NULL) {
       record_method_not_compilable("method parse failed");
       return;
     }
@@ -1005,6 +1013,10 @@
     _in_dump_cnt(0),
     _printer(NULL),
 #endif
+    _comp_arena(mtCompiler),
+    _node_arena(mtCompiler),
+    _old_arena(mtCompiler),
+    _Compile_types(mtCompiler),
     _dead_node_list(comp_arena()),
     _dead_node_count(0),
     _congraph(NULL),
@@ -1014,7 +1026,6 @@
     _inlining_incrementally(false),
     _print_inlining_list(NULL),
     _print_inlining_idx(0),
-    _preserve_jvm_state(0),
     _allowed_reasons(0),
     _interpreter_frame_size(0) {
   C = this;
@@ -1947,6 +1958,8 @@
     for_igvn()->clear();
     gvn->replace_with(&igvn);
 
+    _late_inlines_pos = _late_inlines.length();
+
     while (_boxing_late_inlines.length() > 0) {
       CallGenerator* cg = _boxing_late_inlines.pop();
       cg->do_late_inline();
@@ -2010,8 +2023,8 @@
     if (live_nodes() > (uint)LiveNodeCountInliningCutoff) {
       if (low_live_nodes < (uint)LiveNodeCountInliningCutoff * 8 / 10) {
         // PhaseIdealLoop is expensive so we only try it once we are
-        // out of loop and we only try it again if the previous helped
-        // got the number of nodes down significantly
+        // out of live nodes and we only try it again if the previous
+        // helped got the number of nodes down significantly
         PhaseIdealLoop ideal_loop( igvn, false, true );
         if (failing())  return;
         low_live_nodes = live_nodes();
@@ -2103,6 +2116,10 @@
     // Inline valueOf() methods now.
     inline_boxing_calls(igvn);
 
+    if (AlwaysIncrementalInline) {
+      inline_incrementally(igvn);
+    }
+
     print_method(PHASE_INCREMENTAL_BOXING_INLINE, 2);
 
     if (failing())  return;
--- a/src/share/vm/opto/compile.hpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/opto/compile.hpp	Fri Sep 05 06:26:44 2014 -0400
@@ -429,9 +429,6 @@
   // Remove the speculative part of types and clean up the graph
   void remove_speculative_types(PhaseIterGVN &igvn);
 
-  // Are we within a PreserveJVMState block?
-  int _preserve_jvm_state;
-
   void* _replay_inline_data; // Pointer to data loaded from file
 
  public:
@@ -1196,21 +1193,6 @@
 
   // Auxiliary method for randomized fuzzing/stressing
   static bool randomized_select(int count);
-
-  // enter a PreserveJVMState block
-  void inc_preserve_jvm_state() {
-    _preserve_jvm_state++;
-  }
-
-  // exit a PreserveJVMState block
-  void dec_preserve_jvm_state() {
-    _preserve_jvm_state--;
-    assert(_preserve_jvm_state >= 0, "_preserve_jvm_state shouldn't be negative");
-  }
-
-  bool has_preserve_jvm_state() const {
-    return _preserve_jvm_state > 0;
-  }
 };
 
 #endif // SHARE_VM_OPTO_COMPILE_HPP
--- a/src/share/vm/opto/doCall.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/opto/doCall.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -523,7 +523,7 @@
   // because exceptions don't return to the call site.)
   profile_call(receiver);
 
-  JVMState* new_jvms = cg->generate(jvms, this);
+  JVMState* new_jvms = cg->generate(jvms);
   if (new_jvms == NULL) {
     // When inlining attempt fails (e.g., too many arguments),
     // it may contaminate the current compile state, making it
@@ -537,7 +537,7 @@
     // intrinsic was expecting to optimize. Should always be possible to
     // get a normal java call that may inline in that case
     cg = C->call_generator(cg->method(), vtable_index, call_does_dispatch, jvms, try_inline, prof_factor(), speculative_receiver_type, /* allow_intrinsics= */ false);
-    if ((new_jvms = cg->generate(jvms, this)) == NULL) {
+    if ((new_jvms = cg->generate(jvms)) == NULL) {
       guarantee(failing(), "call failed to generate:  calls should work");
       return;
     }
--- a/src/share/vm/opto/graphKit.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/opto/graphKit.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -428,6 +428,7 @@
       }
     }
   }
+  phi_map->merge_replaced_nodes_with(ex_map);
 }
 
 //--------------------------use_exception_state--------------------------------
@@ -641,7 +642,6 @@
   _map    = kit->map();   // preserve the map
   _sp     = kit->sp();
   kit->set_map(clone_map ? kit->clone_map() : NULL);
-  Compile::current()->inc_preserve_jvm_state();
 #ifdef ASSERT
   _bci    = kit->bci();
   Parse* parser = kit->is_Parse();
@@ -659,7 +659,6 @@
 #endif
   kit->set_map(_map);
   kit->set_sp(_sp);
-  Compile::current()->dec_preserve_jvm_state();
 }
 
 
@@ -1398,60 +1397,17 @@
   // on the map.  This includes locals, stack, and monitors
   // of the current (innermost) JVM state.
 
-  if (!ReplaceInParentMaps) {
-    return;
-  }
-
-  // PreserveJVMState doesn't do a deep copy so we can't modify
-  // parents
-  if (Compile::current()->has_preserve_jvm_state()) {
+  // don't let inconsistent types from profiling escape this
+  // method
+
+  const Type* told = _gvn.type(old);
+  const Type* tnew = _gvn.type(neww);
+
+  if (!tnew->higher_equal(told)) {
     return;
   }
 
-  Parse* parser = is_Parse();
-  bool progress = true;
-  Node* ctrl = map()->in(0);
-  // Follow the chain of parsers and see whether the update can be
-  // done in the map of callers. We can do the replace for a caller if
-  // the current control post dominates the control of a caller.
-  while (parser != NULL && parser->caller() != NULL && progress) {
-    progress = false;
-    Node* parent_map = parser->caller()->map();
-    assert(parser->exits().map()->jvms()->depth() == parser->caller()->depth(), "map mismatch");
-
-    Node* parent_ctrl = parent_map->in(0);
-
-    while (parent_ctrl->is_Region()) {
-      Node* n = parent_ctrl->as_Region()->is_copy();
-      if (n == NULL) {
-        break;
-      }
-      parent_ctrl = n;
-    }
-
-    for (;;) {
-      if (ctrl == parent_ctrl) {
-        // update the map of the exits which is the one that will be
-        // used when compilation resume after inlining
-        parser->exits().map()->replace_edge(old, neww);
-        progress = true;
-        break;
-      }
-      if (ctrl->is_Proj() && ctrl->as_Proj()->is_uncommon_trap_if_pattern(Deoptimization::Reason_none)) {
-        ctrl = ctrl->in(0)->in(0);
-      } else if (ctrl->is_Region()) {
-        Node* n = ctrl->as_Region()->is_copy();
-        if (n == NULL) {
-          break;
-        }
-        ctrl = n;
-      } else {
-        break;
-      }
-    }
-
-    parser = parser->parent_parser();
-  }
+  map()->record_replaced_node(old, neww);
 }
 
 
@@ -1855,12 +1811,16 @@
 
 
 // Replace the call with the current state of the kit.
-void GraphKit::replace_call(CallNode* call, Node* result) {
+void GraphKit::replace_call(CallNode* call, Node* result, bool do_replaced_nodes) {
   JVMState* ejvms = NULL;
   if (has_exceptions()) {
     ejvms = transfer_exceptions_into_jvms();
   }
 
+  ReplacedNodes replaced_nodes = map()->replaced_nodes();
+  ReplacedNodes replaced_nodes_exception;
+  Node* ex_ctl = top();
+
   SafePointNode* final_state = stop();
 
   // Find all the needed outputs of this call
@@ -1877,6 +1837,10 @@
     C->gvn_replace_by(callprojs.fallthrough_catchproj, final_ctl);
   }
   if (callprojs.fallthrough_memproj != NULL) {
+    if (final_mem->is_MergeMem()) {
+      // Parser's exits MergeMem was not transformed but may be optimized
+      final_mem = _gvn.transform(final_mem);
+    }
     C->gvn_replace_by(callprojs.fallthrough_memproj,   final_mem);
   }
   if (callprojs.fallthrough_ioproj != NULL) {
@@ -1908,10 +1872,13 @@
 
     // Load my combined exception state into the kit, with all phis transformed:
     SafePointNode* ex_map = ekit.combine_and_pop_all_exception_states();
+    replaced_nodes_exception = ex_map->replaced_nodes();
 
     Node* ex_oop = ekit.use_exception_state(ex_map);
+
     if (callprojs.catchall_catchproj != NULL) {
       C->gvn_replace_by(callprojs.catchall_catchproj, ekit.control());
+      ex_ctl = ekit.control();
     }
     if (callprojs.catchall_memproj != NULL) {
       C->gvn_replace_by(callprojs.catchall_memproj,   ekit.reset_memory());
@@ -1944,6 +1911,13 @@
       _gvn.transform(wl.pop());
     }
   }
+
+  if (callprojs.fallthrough_catchproj != NULL && !final_ctl->is_top() && do_replaced_nodes) {
+    replaced_nodes.apply(C, final_ctl);
+  }
+  if (!ex_ctl->is_top() && do_replaced_nodes) {
+    replaced_nodes_exception.apply(C, ex_ctl);
+  }
 }
 
 
--- a/src/share/vm/opto/graphKit.hpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/opto/graphKit.hpp	Fri Sep 05 06:26:44 2014 -0400
@@ -685,7 +685,7 @@
   // Replace the call with the current state of the kit.  Requires
   // that the call was generated with separate io_projs so that
   // exceptional control flow can be handled properly.
-  void replace_call(CallNode* call, Node* result);
+  void replace_call(CallNode* call, Node* result, bool do_replaced_nodes = false);
 
   // helper functions for statistics
   void increment_counter(address counter_addr);   // increment a debug counter
--- a/src/share/vm/opto/ifnode.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/opto/ifnode.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -503,7 +503,7 @@
   jint  off = 0;
   if (l->is_top()) {
     return 0;
-  } else if (l->is_Add()) {
+  } else if (l->Opcode() == Op_AddI) {
     if ((off = l->in(1)->find_int_con(0)) != 0) {
       ind = l->in(2);
     } else if ((off = l->in(2)->find_int_con(0)) != 0) {
--- a/src/share/vm/opto/library_call.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/opto/library_call.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -66,7 +66,7 @@
   virtual bool is_predicated() const { return _predicates_count > 0; }
   virtual int  predicates_count() const { return _predicates_count; }
   virtual bool does_virtual_dispatch()   const { return _does_virtual_dispatch; }
-  virtual JVMState* generate(JVMState* jvms, Parse* parent_parser);
+  virtual JVMState* generate(JVMState* jvms);
   virtual Node* generate_predicate(JVMState* jvms, int predicate);
   vmIntrinsics::ID intrinsic_id() const { return _intrinsic_id; }
 };
@@ -614,7 +614,7 @@
   // Nothing to do here.
 }
 
-JVMState* LibraryIntrinsic::generate(JVMState* jvms, Parse* parent_parser) {
+JVMState* LibraryIntrinsic::generate(JVMState* jvms) {
   LibraryCallKit kit(jvms, this);
   Compile* C = kit.C;
   int nodes = C->unique();
--- a/src/share/vm/opto/node.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/opto/node.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -527,6 +527,9 @@
   if (n->is_Call()) {
     n->as_Call()->clone_jvms(C);
   }
+  if (n->is_SafePoint()) {
+    n->as_SafePoint()->clone_replaced_nodes();
+  }
   return n;                     // Return the clone
 }
 
@@ -622,6 +625,9 @@
   if (is_expensive()) {
     compile->remove_expensive_node(this);
   }
+  if (is_SafePoint()) {
+    as_SafePoint()->delete_replaced_nodes();
+  }
 #ifdef ASSERT
   // We will not actually delete the storage, but we'll make the node unusable.
   *(address*)this = badAddress;  // smash the C++ vtbl, probably
--- a/src/share/vm/opto/parse.hpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/opto/parse.hpp	Fri Sep 05 06:26:44 2014 -0400
@@ -357,12 +357,13 @@
   int _est_switch_depth;        // Debugging SwitchRanges.
 #endif
 
-  // parser for the caller of the method of this object
-  Parse* const _parent;
+  bool         _first_return;                  // true if return is the first to be parsed
+  bool         _replaced_nodes_for_exceptions; // needs processing of replaced nodes in exception paths?
+  uint         _new_idx;                       // any node with _idx above were new during this parsing. Used to trim the replaced nodes list.
 
  public:
   // Constructor
-  Parse(JVMState* caller, ciMethod* parse_method, float expected_uses, Parse* parent);
+  Parse(JVMState* caller, ciMethod* parse_method, float expected_uses);
 
   virtual Parse* is_Parse() const { return (Parse*)this; }
 
@@ -419,8 +420,6 @@
     return block()->successor_for_bci(bci);
   }
 
-  Parse* parent_parser() const { return _parent; }
-
  private:
   // Create a JVMS & map for the initial state of this method.
   SafePointNode* create_entry_map();
--- a/src/share/vm/opto/parse1.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/opto/parse1.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -381,8 +381,8 @@
 
 //------------------------------Parse------------------------------------------
 // Main parser constructor.
-Parse::Parse(JVMState* caller, ciMethod* parse_method, float expected_uses, Parse* parent)
-  : _exits(caller), _parent(parent)
+Parse::Parse(JVMState* caller, ciMethod* parse_method, float expected_uses)
+  : _exits(caller)
 {
   // Init some variables
   _caller = caller;
@@ -395,6 +395,9 @@
   _entry_bci = InvocationEntryBci;
   _tf = NULL;
   _block = NULL;
+  _first_return = true;
+  _replaced_nodes_for_exceptions = false;
+  _new_idx = C->unique();
   debug_only(_block_count = -1);
   debug_only(_blocks = (Block*)-1);
 #ifndef PRODUCT
@@ -895,6 +898,10 @@
   for (uint i = 0; i < TypeFunc::Parms; i++) {
     caller.map()->set_req(i, ex_map->in(i));
   }
+  if (ex_map->has_replaced_nodes()) {
+    _replaced_nodes_for_exceptions = true;
+  }
+  caller.map()->transfer_replaced_nodes_from(ex_map, _new_idx);
   // ...and the exception:
   Node*          ex_oop        = saved_ex_oop(ex_map);
   SafePointNode* caller_ex_map = caller.make_exception_state(ex_oop);
@@ -963,7 +970,7 @@
   bool do_synch = method()->is_synchronized() && GenerateSynchronizationCode;
 
   // record exit from a method if compiled while Dtrace is turned on.
-  if (do_synch || C->env()->dtrace_method_probes()) {
+  if (do_synch || C->env()->dtrace_method_probes() || _replaced_nodes_for_exceptions) {
     // First move the exception list out of _exits:
     GraphKit kit(_exits.transfer_exceptions_into_jvms());
     SafePointNode* normal_map = kit.map();  // keep this guy safe
@@ -988,6 +995,9 @@
       if (C->env()->dtrace_method_probes()) {
         kit.make_dtrace_method_exit(method());
       }
+      if (_replaced_nodes_for_exceptions) {
+        kit.map()->apply_replaced_nodes();
+      }
       // Done with exception-path processing.
       ex_map = kit.make_exception_state(ex_oop);
       assert(ex_jvms->same_calls_as(ex_map->jvms()), "sanity");
@@ -1007,6 +1017,7 @@
       _exits.add_exception_state(ex_map);
     }
   }
+  _exits.map()->apply_replaced_nodes();
 }
 
 //-----------------------------create_entry_map-------------------------------
@@ -1021,6 +1032,9 @@
     return NULL;
   }
 
+  // clear current replaced nodes that are of no use from here on (map was cloned in build_exits).
+  _caller->map()->delete_replaced_nodes();
+
   // If this is an inlined method, we may have to do a receiver null check.
   if (_caller->has_method() && is_normal_parse() && !method()->is_static()) {
     GraphKit kit(_caller);
@@ -1044,6 +1058,8 @@
 
   SafePointNode* inmap = _caller->map();
   assert(inmap != NULL, "must have inmap");
+  // In case of null check on receiver above
+  map()->transfer_replaced_nodes_from(inmap, _new_idx);
 
   uint i;
 
@@ -1673,6 +1689,8 @@
       set_control(r->nonnull_req());
     }
 
+    map()->merge_replaced_nodes_with(newin);
+
     // newin has been subsumed into the lazy merge, and is now dead.
     set_block(save_block);
 
@@ -2077,6 +2095,13 @@
     phi->add_req(value);
   }
 
+  if (_first_return) {
+    _exits.map()->transfer_replaced_nodes_from(map(), _new_idx);
+    _first_return = false;
+  } else {
+    _exits.map()->merge_replaced_nodes_with(map());
+  }
+
   stop_and_kill_map();          // This CFG path dies here
 }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/vm/opto/replacednodes.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -0,0 +1,219 @@
+/*
+ * 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.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "opto/cfgnode.hpp"
+#include "opto/phaseX.hpp"
+#include "opto/replacednodes.hpp"
+
+void ReplacedNodes::allocate_if_necessary() {
+  if (_replaced_nodes == NULL) {
+    _replaced_nodes = new GrowableArray<ReplacedNode>();
+  }
+}
+
+bool ReplacedNodes::is_empty() const {
+  return _replaced_nodes == NULL || _replaced_nodes->length() == 0;
+}
+
+bool ReplacedNodes::has_node(const ReplacedNode& r) const {
+  return _replaced_nodes->find(r) != -1;
+}
+
+bool ReplacedNodes::has_target_node(Node* n) const {
+  for (int i = 0; i < _replaced_nodes->length(); i++) {
+    if (_replaced_nodes->at(i).improved() == n) {
+      return true;
+    }
+  }
+  return false;
+}
+
+// Record replaced node if not seen before
+void ReplacedNodes::record(Node* initial, Node* improved) {
+  allocate_if_necessary();
+  ReplacedNode r(initial, improved);
+  if (!has_node(r)) {
+    _replaced_nodes->push(r);
+  }
+}
+
+// Copy replaced nodes from one map to another. idx is used to
+// identify nodes that are too new to be of interest in the target
+// node list.
+void ReplacedNodes::transfer_from(const ReplacedNodes& other, uint idx) {
+  if (other.is_empty()) {
+    return;
+  }
+  allocate_if_necessary();
+  for (int i = 0; i < other._replaced_nodes->length(); i++) {
+    ReplacedNode replaced = other._replaced_nodes->at(i);
+    // Only transfer the nodes that can actually be useful
+    if (!has_node(replaced) && (replaced.initial()->_idx < idx || has_target_node(replaced.initial()))) {
+      _replaced_nodes->push(replaced);
+    }
+  }
+}
+
+void ReplacedNodes::clone() {
+  if (_replaced_nodes != NULL) {
+    GrowableArray<ReplacedNode>* replaced_nodes_clone = new GrowableArray<ReplacedNode>();
+    replaced_nodes_clone->appendAll(_replaced_nodes);
+    _replaced_nodes = replaced_nodes_clone;
+  }
+}
+
+void ReplacedNodes::reset() {
+  if (_replaced_nodes != NULL) {
+    _replaced_nodes->clear();
+  }
+}
+
+// Perfom node replacement (used when returning to caller)
+void ReplacedNodes::apply(Node* n) {
+  if (is_empty()) {
+    return;
+  }
+  for (int i = 0; i < _replaced_nodes->length(); i++) {
+    ReplacedNode replaced = _replaced_nodes->at(i);
+    n->replace_edge(replaced.initial(), replaced.improved());
+  }
+}
+
+static void enqueue_use(Node* n, Node* use, Unique_Node_List& work) {
+  if (use->is_Phi()) {
+    Node* r = use->in(0);
+    assert(r->is_Region(), "Phi should have Region");
+    for (uint i = 1; i < use->req(); i++) {
+      if (use->in(i) == n) {
+        work.push(r->in(i));
+      }
+    }
+  } else {
+    work.push(use);
+  }
+}
+
+// Perfom node replacement following late inlining
+void ReplacedNodes::apply(Compile* C, Node* ctl) {
+  // ctl is the control on exit of the method that was late inlined
+  if (is_empty()) {
+    return;
+  }
+  for (int i = 0; i < _replaced_nodes->length(); i++) {
+    ReplacedNode replaced = _replaced_nodes->at(i);
+    Node* initial = replaced.initial();
+    Node* improved = replaced.improved();
+    assert (ctl != NULL && !ctl->is_top(), "replaced node should have actual control");
+
+    ResourceMark rm;
+    Unique_Node_List work;
+    // Go over all the uses of the node that is considered for replacement...
+    for (DUIterator j = initial->outs(); initial->has_out(j); j++) {
+      Node* use = initial->out(j);
+
+      if (use == improved || use->outcnt() == 0) {
+        continue;
+      }
+      work.clear();
+      enqueue_use(initial, use, work);
+      bool replace = true;
+      // Check that this use is dominated by ctl. Go ahead with the
+      // replacement if it is.
+      while (work.size() != 0 && replace) {
+        Node* n = work.pop();
+        if (use->outcnt() == 0) {
+          continue;
+        }
+        if (n->is_CFG() || (n->in(0) != NULL && !n->in(0)->is_top())) {
+          int depth = 0;
+          Node *m = n;
+          if (!n->is_CFG()) {
+            n = n->in(0);
+          }
+          assert(n->is_CFG(), "should be CFG now");
+          while(n != ctl) {
+            n = IfNode::up_one_dom(n);
+            depth++;
+            // limit search depth
+            if (depth >= 100 || n == NULL) {
+              replace = false;
+              break;
+            }
+          }
+        } else {
+          for (DUIterator k = n->outs(); n->has_out(k); k++) {
+            enqueue_use(n, n->out(k), work);
+          }
+        }
+      }
+      if (replace) {
+        bool is_in_table = C->initial_gvn()->hash_delete(use);
+        int replaced = use->replace_edge(initial, improved);
+        if (is_in_table) {
+          C->initial_gvn()->hash_find_insert(use);
+        }
+        C->record_for_igvn(use);
+
+        assert(replaced > 0, "inconsistent");
+        --j;
+      }
+    }
+  }
+}
+
+void ReplacedNodes::dump(outputStream *st) const {
+  if (!is_empty()) {
+    tty->print("replaced nodes: ");
+    for (int i = 0; i < _replaced_nodes->length(); i++) {
+      tty->print("%d->%d", _replaced_nodes->at(i).initial()->_idx, _replaced_nodes->at(i).improved()->_idx);
+      if (i < _replaced_nodes->length()-1) {
+        tty->print(",");
+      }
+    }
+  }
+}
+
+// Merge 2 list of replaced node at a point where control flow paths merge
+void ReplacedNodes::merge_with(const ReplacedNodes& other) {
+  if (is_empty()) {
+    return;
+  }
+  if (other.is_empty()) {
+    reset();
+    return;
+  }
+  int shift = 0;
+  int len = _replaced_nodes->length();
+  for (int i = 0; i < len; i++) {
+    if (!other.has_node(_replaced_nodes->at(i))) {
+      shift++;
+    } else if (shift > 0) {
+      _replaced_nodes->at_put(i-shift, _replaced_nodes->at(i));
+    }
+  }
+  if (shift > 0) {
+    _replaced_nodes->trunc_to(len - shift);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/vm/opto/replacednodes.hpp	Fri Sep 05 06:26:44 2014 -0400
@@ -0,0 +1,81 @@
+/*
+ * 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.
+ *
+ */
+
+#ifndef SHARE_VM_OPTO_REPLACEDNODES_HPP
+#define SHARE_VM_OPTO_REPLACEDNODES_HPP
+
+#include "opto/connode.hpp"
+
+// During parsing, when a node is "improved",
+// GraphKit::replace_in_map() is called to update the current map so
+// that the improved node is used from that point
+// on. GraphKit::replace_in_map() doesn't operate on the callers maps
+// and so some optimization opportunities may be lost. The
+// ReplacedNodes class addresses that problem.
+//
+// A ReplacedNodes object is a list of pair of nodes. Every
+// SafePointNode carries a ReplacedNodes object. Every time
+// GraphKit::replace_in_map() is called, a new pair of nodes is pushed
+// on the list of replaced nodes. When control flow paths merge, their
+// replaced nodes are also merged. When parsing exits a method to
+// return to a caller, the replaced nodes on the exit path are used to
+// update the caller's map.
+class ReplacedNodes VALUE_OBJ_CLASS_SPEC {
+ private:
+  class ReplacedNode VALUE_OBJ_CLASS_SPEC {
+  private:
+    Node* _initial;
+    Node* _improved;
+  public:
+    ReplacedNode() : _initial(NULL), _improved(NULL) {}
+    ReplacedNode(Node* initial, Node* improved) : _initial(initial), _improved(improved) {}
+    Node* initial() const  { return _initial; }
+    Node* improved() const { return _improved; }
+
+    bool operator==(const ReplacedNode& other) {
+      return _initial == other._initial && _improved == other._improved;
+    }
+  };
+  GrowableArray<ReplacedNode>* _replaced_nodes;
+
+  void allocate_if_necessary();
+  bool has_node(const ReplacedNode& r) const;
+  bool has_target_node(Node* n) const;
+
+ public:
+  ReplacedNodes()
+    : _replaced_nodes(NULL) {}
+
+  void clone();
+  void record(Node* initial, Node* improved);
+  void transfer_from(const ReplacedNodes& other, uint idx);
+  void reset();
+  void apply(Node* n);
+  void merge_with(const ReplacedNodes& other);
+  bool is_empty() const;
+  void dump(outputStream *st) const;
+  void apply(Compile* C, Node* ctl);
+};
+
+#endif // SHARE_VM_OPTO_REPLACEDNODES_HPP
--- a/src/share/vm/opto/type.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/opto/type.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -265,7 +265,7 @@
   // locking.
 
   Arena* save = current->type_arena();
-  Arena* shared_type_arena = new (mtCompiler)Arena();
+  Arena* shared_type_arena = new (mtCompiler)Arena(mtCompiler);
 
   current->set_type_arena(shared_type_arena);
   _shared_type_dict =
--- a/src/share/vm/precompiled/precompiled.hpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/precompiled/precompiled.hpp	Fri Sep 05 06:26:44 2014 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 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
@@ -220,10 +220,17 @@
 # include "runtime/vmThread.hpp"
 # include "runtime/vm_operations.hpp"
 # include "runtime/vm_version.hpp"
+# include "services/allocationSite.hpp"
 # include "services/lowMemoryDetector.hpp"
+# include "services/mallocTracker.hpp"
+# include "services/memBaseline.hpp"
 # include "services/memoryPool.hpp"
 # include "services/memoryService.hpp"
 # include "services/memoryUsage.hpp"
+# include "services/memReporter.hpp"
+# include "services/memTracker.hpp"
+# include "services/nmtCommon.hpp"
+# include "services/virtualMemoryTracker.hpp"
 # include "utilities/accessFlags.hpp"
 # include "utilities/array.hpp"
 # include "utilities/bitMap.hpp"
@@ -237,6 +244,7 @@
 # include "utilities/hashtable.hpp"
 # include "utilities/histogram.hpp"
 # include "utilities/macros.hpp"
+# include "utilities/nativeCallStack.hpp"
 # include "utilities/numberSeq.hpp"
 # include "utilities/ostream.hpp"
 # include "utilities/preserveException.hpp"
--- a/src/share/vm/prims/jni.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/prims/jni.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -73,6 +73,7 @@
 #include "runtime/signature.hpp"
 #include "runtime/thread.inline.hpp"
 #include "runtime/vm_operations.hpp"
+#include "services/memTracker.hpp"
 #include "services/runtimeService.hpp"
 #include "trace/tracing.hpp"
 #include "utilities/defaultStream.hpp"
@@ -292,15 +293,6 @@
       "Bug in native code: jfieldID offset must address interior of object");
 }
 
-// Pick a reasonable higher bound for local capacity requested
-// for EnsureLocalCapacity and PushLocalFrame.  We don't want it too
-// high because a test (or very unusual application) may try to allocate
-// that many handles and run out of swap space.  An implementation is
-// permitted to allocate more handles than the ensured capacity, so this
-// value is set high enough to prevent compatibility problems.
-const int MAX_REASONABLE_LOCAL_CAPACITY = 4*K;
-
-
 // Wrapper to trace JNI functions
 
 #ifdef ASSERT
@@ -880,7 +872,8 @@
                                    env, capacity);
 #endif /* USDT2 */
   //%note jni_11
-  if (capacity < 0 || capacity > MAX_REASONABLE_LOCAL_CAPACITY) {
+  if (capacity < 0 ||
+      ((MaxJNILocalCapacity > 0) && (capacity > MaxJNILocalCapacity))) {
 #ifndef USDT2
     DTRACE_PROBE1(hotspot_jni, PushLocalFrame__return, JNI_ERR);
 #else /* USDT2 */
@@ -1039,7 +1032,8 @@
                                         env, capacity);
 #endif /* USDT2 */
   jint ret;
-  if (capacity >= 0 && capacity <= MAX_REASONABLE_LOCAL_CAPACITY) {
+  if (capacity >= 0 &&
+      ((MaxJNILocalCapacity <= 0) || (capacity <= MaxJNILocalCapacity))) {
     ret = JNI_OK;
   } else {
     ret = JNI_ERR;
@@ -3589,6 +3583,7 @@
     if (bad_address != NULL) {
       os::protect_memory(bad_address, size, os::MEM_PROT_READ,
                          /*is_committed*/false);
+      MemTracker::record_virtual_memory_type((void*)bad_address, mtInternal);
     }
   }
   return bad_address;
@@ -5084,11 +5079,13 @@
 void TestVirtualSpaceNode_test();
 void TestNewSize_test();
 void TestKlass_test();
+void Test_linked_list();
 #if INCLUDE_ALL_GCS
 void TestOldFreeSpaceCalculation_test();
 void TestG1BiasedArray_test();
 void TestBufferingOopClosure_test();
 void TestCodeCacheRemSet_test();
+void FreeRegionList_test();
 #endif
 
 void execute_internal_vm_tests() {
@@ -5110,6 +5107,7 @@
     run_unit_test(test_loggc_filename());
     run_unit_test(TestNewSize_test());
     run_unit_test(TestKlass_test());
+    run_unit_test(Test_linked_list());
 #if INCLUDE_VM_STRUCTS
     run_unit_test(VMStructs::test());
 #endif
@@ -5119,6 +5117,9 @@
     run_unit_test(HeapRegionRemSet::test_prt());
     run_unit_test(TestBufferingOopClosure_test());
     run_unit_test(TestCodeCacheRemSet_test());
+    if (UseG1GC) {
+      run_unit_test(FreeRegionList_test());
+    }
 #endif
     tty->print_cr("All internal VM tests passed");
   }
--- a/src/share/vm/prims/whitebox.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/prims/whitebox.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -43,13 +43,16 @@
 #include "utilities/exceptions.hpp"
 
 #if INCLUDE_ALL_GCS
+#include "gc_implementation/parallelScavenge/parallelScavengeHeap.inline.hpp"
 #include "gc_implementation/g1/concurrentMark.hpp"
 #include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
 #include "gc_implementation/g1/heapRegionRemSet.hpp"
 #endif // INCLUDE_ALL_GCS
 
-#ifdef INCLUDE_NMT
+#if INCLUDE_NMT
+#include "services/mallocSiteTable.hpp"
 #include "services/memTracker.hpp"
+#include "utilities/nativeCallStack.hpp"
 #endif // INCLUDE_NMT
 
 #include "compiler/compileBroker.hpp"
@@ -221,6 +224,30 @@
                                         (size_t) magnitude, (size_t) iterations);
 WB_END
 
+WB_ENTRY(jboolean, WB_isObjectInOldGen(JNIEnv* env, jobject o, jobject obj))
+  oop p = JNIHandles::resolve(obj);
+#if INCLUDE_ALL_GCS
+  if (UseG1GC) {
+    G1CollectedHeap* g1 = G1CollectedHeap::heap();
+    const HeapRegion* hr = g1->heap_region_containing(p);
+    if (hr == NULL) {
+      return false;
+    }
+    return !(hr->is_young());
+  } else if (UseParallelGC) {
+    ParallelScavengeHeap* psh = ParallelScavengeHeap::heap();
+    return !psh->is_in_young(p);
+  }
+#endif // INCLUDE_ALL_GCS
+  GenCollectedHeap* gch = GenCollectedHeap::heap();
+  return !gch->is_in_young(p);
+WB_END
+
+WB_ENTRY(jlong, WB_GetObjectSize(JNIEnv* env, jobject o, jobject obj))
+  oop p = JNIHandles::resolve(obj);
+  return p->size() * HeapWordSize;
+WB_END
+
 #if INCLUDE_ALL_GCS
 WB_ENTRY(jboolean, WB_G1IsHumongous(JNIEnv* env, jobject o, jobject obj))
   G1CollectedHeap* g1 = G1CollectedHeap::heap();
@@ -231,7 +258,7 @@
 
 WB_ENTRY(jlong, WB_G1NumFreeRegions(JNIEnv* env, jobject o))
   G1CollectedHeap* g1 = G1CollectedHeap::heap();
-  size_t nr = g1->free_regions();
+  size_t nr = g1->num_free_regions();
   return (jlong)nr;
 WB_END
 
@@ -251,12 +278,16 @@
 // NMT picks it up correctly
 WB_ENTRY(jlong, WB_NMTMalloc(JNIEnv* env, jobject o, jlong size))
   jlong addr = 0;
+    addr = (jlong)(uintptr_t)os::malloc(size, mtTest);
+  return addr;
+WB_END
 
-  if (MemTracker::is_on() && !MemTracker::shutdown_in_progress()) {
-    addr = (jlong)(uintptr_t)os::malloc(size, mtTest);
-  }
-
-  return addr;
+// Alloc memory with pseudo call stack. The test can create psudo malloc
+// allocation site to stress the malloc tracking.
+WB_ENTRY(jlong, WB_NMTMallocWithPseudoStack(JNIEnv* env, jobject o, jlong size, jint pseudo_stack))
+  address pc = (address)(size_t)pseudo_stack;
+  NativeCallStack stack(&pc, 1);
+  return (jlong)os::malloc(size, mtTest, stack);
 WB_END
 
 // Free the memory allocated by NMTAllocTest
@@ -267,10 +298,8 @@
 WB_ENTRY(jlong, WB_NMTReserveMemory(JNIEnv* env, jobject o, jlong size))
   jlong addr = 0;
 
-  if (MemTracker::is_on() && !MemTracker::shutdown_in_progress()) {
     addr = (jlong)(uintptr_t)os::reserve_memory(size);
     MemTracker::record_virtual_memory_type((address)addr, mtTest);
-  }
 
   return addr;
 WB_END
@@ -289,20 +318,20 @@
   os::release_memory((char *)(uintptr_t)addr, size);
 WB_END
 
-// Block until the current generation of NMT data to be merged, used to reliably test the NMT feature
-WB_ENTRY(jboolean, WB_NMTWaitForDataMerge(JNIEnv* env))
-
-  if (!MemTracker::is_on() || MemTracker::shutdown_in_progress()) {
-    return false;
-  }
-
-  return MemTracker::wbtest_wait_for_data_merge();
+WB_ENTRY(jboolean, WB_NMTIsDetailSupported(JNIEnv* env))
+  return MemTracker::tracking_level() == NMT_detail;
 WB_END
 
-WB_ENTRY(jboolean, WB_NMTIsDetailSupported(JNIEnv* env))
-  return MemTracker::tracking_level() == MemTracker::NMT_detail;
+WB_ENTRY(void, WB_NMTOverflowHashBucket(JNIEnv* env, jobject o, jlong num))
+  address pc = (address)1;
+  for (jlong index = 0; index < num; index ++) {
+    NativeCallStack stack(&pc, 1);
+    os::malloc(0, mtTest, stack);
+    pc += MallocSiteTable::hash_buckets();
+  }
 WB_END
 
+
 #endif // INCLUDE_NMT
 
 static jmethodID reflected_method_to_jmid(JavaThread* thread, JNIEnv* env, jobject method) {
@@ -668,6 +697,9 @@
   Universe::heap()->collect(GCCause::_last_ditch_collection);
 WB_END
 
+WB_ENTRY(void, WB_YoungGC(JNIEnv* env, jobject o))
+  Universe::heap()->collect(GCCause::_wb_young_gc);
+WB_END
 
 WB_ENTRY(void, WB_ReadReservedMemory(JNIEnv* env, jobject o))
   // static+volatile in order to force the read to happen
@@ -811,6 +843,8 @@
 
 static JNINativeMethod methods[] = {
   {CC"getObjectAddress",   CC"(Ljava/lang/Object;)J", (void*)&WB_GetObjectAddress  },
+  {CC"getObjectSize",      CC"(Ljava/lang/Object;)J", (void*)&WB_GetObjectSize     },
+  {CC"isObjectInOldGen",   CC"(Ljava/lang/Object;)Z", (void*)&WB_isObjectInOldGen  },
   {CC"getHeapOopSize",     CC"()I",                   (void*)&WB_GetHeapOopSize    },
   {CC"isClassAlive0",      CC"(Ljava/lang/String;)Z", (void*)&WB_IsClassAlive      },
   {CC"parseCommandLine",
@@ -831,12 +865,13 @@
 #endif // INCLUDE_ALL_GCS
 #if INCLUDE_NMT
   {CC"NMTMalloc",           CC"(J)J",                 (void*)&WB_NMTMalloc          },
+  {CC"NMTMallocWithPseudoStack", CC"(JI)J",           (void*)&WB_NMTMallocWithPseudoStack},
   {CC"NMTFree",             CC"(J)V",                 (void*)&WB_NMTFree            },
   {CC"NMTReserveMemory",    CC"(J)J",                 (void*)&WB_NMTReserveMemory   },
   {CC"NMTCommitMemory",     CC"(JJ)V",                (void*)&WB_NMTCommitMemory    },
   {CC"NMTUncommitMemory",   CC"(JJ)V",                (void*)&WB_NMTUncommitMemory  },
   {CC"NMTReleaseMemory",    CC"(JJ)V",                (void*)&WB_NMTReleaseMemory   },
-  {CC"NMTWaitForDataMerge", CC"()Z",                  (void*)&WB_NMTWaitForDataMerge},
+  {CC"NMTOverflowHashBucket", CC"(J)V",               (void*)&WB_NMTOverflowHashBucket},
   {CC"NMTIsDetailSupported",CC"()Z",                  (void*)&WB_NMTIsDetailSupported},
 #endif // INCLUDE_NMT
   {CC"deoptimizeAll",      CC"()V",                   (void*)&WB_DeoptimizeAll     },
@@ -885,6 +920,7 @@
                                                       (void*)&WB_GetStringVMFlag},
   {CC"isInStringTable",    CC"(Ljava/lang/String;)Z", (void*)&WB_IsInStringTable  },
   {CC"fullGC",   CC"()V",                             (void*)&WB_FullGC },
+  {CC"youngGC",  CC"()V",                             (void*)&WB_YoungGC },
   {CC"readReservedMemory", CC"()V",                   (void*)&WB_ReadReservedMemory },
   {CC"allocateMetaspace",
      CC"(Ljava/lang/ClassLoader;J)J",                 (void*)&WB_AllocateMetaspace },
--- a/src/share/vm/runtime/arguments.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/runtime/arguments.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -98,6 +98,8 @@
 bool   Arguments::_has_profile                  = false;
 size_t Arguments::_conservative_max_heap_alignment = 0;
 uintx  Arguments::_min_heap_size                = 0;
+uintx  Arguments::_min_heap_free_ratio          = 0;
+uintx  Arguments::_max_heap_free_ratio          = 0;
 Arguments::Mode Arguments::_mode                = _mixed;
 bool   Arguments::_java_compiler                = false;
 bool   Arguments::_xdebug_mode                  = false;
@@ -294,6 +296,7 @@
   { "UseMPSS",                       JDK_Version::jdk(8), JDK_Version::jdk(9) },
   { "UseStringCache",                JDK_Version::jdk(8), JDK_Version::jdk(9) },
   { "UseOldInlining",                JDK_Version::jdk(9), JDK_Version::jdk(10) },
+  { "AutoShutdownNMT",               JDK_Version::jdk(9), JDK_Version::jdk(10) },
 #ifdef PRODUCT
   { "DesiredMethodLimit",
                            JDK_Version::jdk_update(7, 2), JDK_Version::jdk(8) },
@@ -1597,9 +1600,11 @@
     // unless the user actually sets these flags.
     if (FLAG_IS_DEFAULT(MinHeapFreeRatio)) {
       FLAG_SET_DEFAULT(MinHeapFreeRatio, 0);
+      _min_heap_free_ratio = MinHeapFreeRatio;
     }
     if (FLAG_IS_DEFAULT(MaxHeapFreeRatio)) {
       FLAG_SET_DEFAULT(MaxHeapFreeRatio, 100);
+      _max_heap_free_ratio = MaxHeapFreeRatio;
     }
   }
 
@@ -1974,6 +1979,8 @@
                   MaxHeapFreeRatio);
     return false;
   }
+  // This does not set the flag itself, but stores the value in a safe place for later usage.
+  _min_heap_free_ratio = min_heap_free_ratio;
   return true;
 }
 
@@ -1988,6 +1995,8 @@
                   MinHeapFreeRatio);
     return false;
   }
+  // This does not set the flag itself, but stores the value in a safe place for later usage.
+  _max_heap_free_ratio = max_heap_free_ratio;
   return true;
 }
 
@@ -2344,7 +2353,7 @@
 
   if (PrintNMTStatistics) {
 #if INCLUDE_NMT
-    if (MemTracker::tracking_level() == MemTracker::NMT_off) {
+    if (MemTracker::tracking_level() == NMT_off) {
 #endif // INCLUDE_NMT
       warning("PrintNMTStatistics is disabled, because native memory tracking is not enabled");
       PrintNMTStatistics = false;
@@ -3534,15 +3543,24 @@
       CommandLineFlags::printFlags(tty, false);
       vm_exit(0);
     }
+#if INCLUDE_NMT
     if (match_option(option, "-XX:NativeMemoryTracking", &tail)) {
-#if INCLUDE_NMT
-      MemTracker::init_tracking_options(tail);
-#else
-      jio_fprintf(defaultStream::error_stream(),
-        "Native Memory Tracking is not supported in this VM\n");
-      return JNI_ERR;
+      // The launcher did not setup nmt environment variable properly.
+//      if (!MemTracker::check_launcher_nmt_support(tail)) {
+//        warning("Native Memory Tracking did not setup properly, using wrong launcher?");
+//      }
+
+      // Verify if nmt option is valid.
+      if (MemTracker::verify_nmt_option()) {
+        // Late initialization, still in single-threaded mode.
+        if (MemTracker::tracking_level() >= NMT_summary) {
+          MemTracker::init();
+        }
+      } else {
+        vm_exit_during_initialization("Syntax error, expecting -XX:NativeMemoryTracking=[off|summary|detail]", NULL);
+      }
+    }
 #endif
-    }
 
 
 #ifndef PRODUCT
@@ -3793,10 +3811,6 @@
     // nothing to use the profiling, turn if off
     FLAG_SET_DEFAULT(TypeProfileLevel, 0);
   }
-  if (UseTypeSpeculation && FLAG_IS_DEFAULT(ReplaceInParentMaps)) {
-    // Doing the replace in parent maps helps speculation
-    FLAG_SET_DEFAULT(ReplaceInParentMaps, true);
-  }
 #endif
 
   if (PrintAssembly && FLAG_IS_DEFAULT(DebugNonSafepoints)) {
--- a/src/share/vm/runtime/arguments.hpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/runtime/arguments.hpp	Fri Sep 05 06:26:44 2014 -0400
@@ -284,7 +284,11 @@
   // Value of the conservative maximum heap alignment needed
   static size_t  _conservative_max_heap_alignment;
 
-  static uintx  _min_heap_size;
+  static uintx _min_heap_size;
+
+  // Used to store original flag values
+  static uintx _min_heap_free_ratio;
+  static uintx _max_heap_free_ratio;
 
   // -Xrun arguments
   static AgentLibraryList _libraryList;
@@ -514,6 +518,10 @@
   static uintx min_heap_size()              { return _min_heap_size; }
   static void  set_min_heap_size(uintx v)   { _min_heap_size = v;  }
 
+  // Returns the original values of -XX:MinHeapFreeRatio and -XX:MaxHeapFreeRatio
+  static uintx min_heap_free_ratio()        { return _min_heap_free_ratio; }
+  static uintx max_heap_free_ratio()        { return _max_heap_free_ratio; }
+
   // -Xrun
   static AgentLibrary* libraries()          { return _libraryList.first(); }
   static bool init_libraries_at_startup()   { return !_libraryList.is_empty(); }
--- a/src/share/vm/runtime/globals.hpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/runtime/globals.hpp	Fri Sep 05 06:26:44 2014 -0400
@@ -955,11 +955,6 @@
   diagnostic(bool, PrintNMTStatistics, false,                               \
           "Print native memory tracking summary data if it is on")          \
                                                                             \
-  diagnostic(bool, AutoShutdownNMT, true,                                   \
-          "Automatically shutdown native memory tracking under stress "     \
-          "situations. When set to false, native memory tracking tries to " \
-          "stay alive at the expense of JVM performance")                   \
-                                                                            \
   diagnostic(bool, LogCompilation, false,                                   \
           "Log compilation activity in detail to LogFile")                  \
                                                                             \
@@ -1228,6 +1223,11 @@
   product(bool, UseFastJNIAccessors, false,                                 \
           "Use optimized versions of Get<Primitive>Field")                  \
                                                                             \
+  product(intx, MaxJNILocalCapacity, 65536,                                 \
+          "Maximum allowable local JNI handle capacity to "                 \
+          "EnsureLocalCapacity() and PushLocalFrame(), "                    \
+          "where <= 0 is unlimited, default: 65536")                        \
+                                                                            \
   product(bool, EagerXrunInit, false,                                       \
           "Eagerly initialize -Xrun libraries; allows startup profiling, "  \
           "but not all -Xrun libraries may support the state of the VM "    \
@@ -1952,6 +1952,10 @@
           "not just one of the generations (e.g., G1). A value of 0 "       \
           "denotes 'do constant GC cycles'.")                               \
                                                                             \
+  manageable(intx, CMSTriggerInterval, -1,                                  \
+          "Commence a CMS collection cycle (at least) every so many "       \
+          "milliseconds (0 permanently, -1 disabled)")                      \
+                                                                            \
   product(bool, UseCMSInitiatingOccupancyOnly, false,                       \
           "Only use occupancy as a criterion for starting a CMS collection")\
                                                                             \
--- a/src/share/vm/runtime/handles.hpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/runtime/handles.hpp	Fri Sep 05 06:26:44 2014 -0400
@@ -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
@@ -227,7 +227,7 @@
   HandleArea* _prev;          // link to outer (older) area
  public:
   // Constructor
-  HandleArea(HandleArea* prev) : Arena(Chunk::tiny_size) {
+  HandleArea(HandleArea* prev) : Arena(mtThread, Chunk::tiny_size) {
     debug_only(_handle_mark_nesting    = 0);
     debug_only(_no_handle_mark_nesting = 0);
     _prev = prev;
--- a/src/share/vm/runtime/init.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/runtime/init.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -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
@@ -34,8 +34,10 @@
 #include "runtime/init.hpp"
 #include "runtime/safepoint.hpp"
 #include "runtime/sharedRuntime.hpp"
+#include "services/memTracker.hpp"
 #include "utilities/macros.hpp"
 
+
 // Initialization done by VM thread in vm_init_globals()
 void check_ThreadShadow();
 void eventlog_init();
@@ -131,6 +133,12 @@
   javaClasses_init();   // must happen after vtable initialization
   stubRoutines_init2(); // note: StubRoutines need 2-phase init
 
+#if INCLUDE_NMT
+  // Solaris stack is walkable only after stubRoutines are set up.
+  // On Other platforms, the stack is always walkable.
+  NMT_stack_walkable = true;
+#endif // INCLUDE_NMT
+
   // All the flags that get adjusted by VM_Version_init and os::init_2
   // have been set so dump the flags now.
   if (PrintFlagsFinal) {
--- a/src/share/vm/runtime/java.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/runtime/java.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -57,7 +57,6 @@
 #include "runtime/thread.inline.hpp"
 #include "runtime/timer.hpp"
 #include "runtime/vm_operations.hpp"
-#include "services/memReporter.hpp"
 #include "services/memTracker.hpp"
 #include "trace/tracing.hpp"
 #include "utilities/dtrace.hpp"
@@ -367,12 +366,7 @@
 #endif // ENABLE_ZAP_DEAD_LOCALS
   // Native memory tracking data
   if (PrintNMTStatistics) {
-    if (MemTracker::is_on()) {
-      BaselineTTYOutputer outputer(tty);
-      MemTracker::print_memory_usage(outputer, K, false);
-    } else {
-      tty->print_cr("%s", MemTracker::reason());
-    }
+    MemTracker::final_report(tty);
   }
 }
 
@@ -404,12 +398,7 @@
 
   // Native memory tracking data
   if (PrintNMTStatistics) {
-    if (MemTracker::is_on()) {
-      BaselineTTYOutputer outputer(tty);
-      MemTracker::print_memory_usage(outputer, K, false);
-    } else {
-      tty->print_cr("%s", MemTracker::reason());
-    }
+    MemTracker::final_report(tty);
   }
 }
 
@@ -558,10 +547,6 @@
     BeforeExit_lock->notify_all();
   }
 
-  // Shutdown NMT before exit. Otherwise,
-  // it will run into trouble when system destroys static variables.
-  MemTracker::shutdown(MemTracker::NMT_normal);
-
   if (VerifyStringTableAtExit) {
     int fail_cnt = 0;
     {
--- a/src/share/vm/runtime/os.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/runtime/os.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -49,6 +49,7 @@
 #include "runtime/stubRoutines.hpp"
 #include "runtime/thread.inline.hpp"
 #include "services/attachListener.hpp"
+#include "services/nmtCommon.hpp"
 #include "services/memTracker.hpp"
 #include "services/threadService.hpp"
 #include "utilities/defaultStream.hpp"
@@ -561,7 +562,11 @@
   return ptr;
 }
 
-void* os::malloc(size_t size, MEMFLAGS memflags, address caller) {
+void* os::malloc(size_t size, MEMFLAGS flags) {
+  return os::malloc(size, flags, CALLER_PC);
+}
+
+void* os::malloc(size_t size, MEMFLAGS memflags, const NativeCallStack& stack) {
   NOT_PRODUCT(inc_stat_counter(&num_mallocs, 1));
   NOT_PRODUCT(inc_stat_counter(&alloc_bytes, size));
 
@@ -587,11 +592,15 @@
     size = 1;
   }
 
+  // NMT support
+  NMT_TrackingLevel level = MemTracker::tracking_level();
+  size_t            nmt_header_size = MemTracker::malloc_header_size(level);
+
 #ifndef ASSERT
-  const size_t alloc_size = size;
+  const size_t alloc_size = size + nmt_header_size;
 #else
-  const size_t alloc_size = GuardedMemory::get_total_size(size);
-  if (size > alloc_size) { // Check for rollover.
+  const size_t alloc_size = GuardedMemory::get_total_size(size + nmt_header_size);
+  if (size + nmt_header_size > alloc_size) { // Check for rollover.
     return NULL;
   }
 #endif
@@ -610,7 +619,7 @@
     return NULL;
   }
   // Wrap memory with guard
-  GuardedMemory guarded(ptr, size);
+  GuardedMemory guarded(ptr, size + nmt_header_size);
   ptr = guarded.get_user_ptr();
 #endif
   if ((intptr_t)ptr == (intptr_t)MallocCatchPtr) {
@@ -623,48 +632,50 @@
   }
 
   // we do not track guard memory
-  MemTracker::record_malloc((address)ptr, size, memflags, caller == 0 ? CALLER_PC : caller);
-
-  return ptr;
+  return MemTracker::record_malloc((address)ptr, size, memflags, stack, level);
 }
 
+void* os::realloc(void *memblock, size_t size, MEMFLAGS flags) {
+  return os::realloc(memblock, size, flags, CALLER_PC);
+}
 
-void* os::realloc(void *memblock, size_t size, MEMFLAGS memflags, address caller) {
+void* os::realloc(void *memblock, size_t size, MEMFLAGS memflags, const NativeCallStack& stack) {
 #ifndef ASSERT
   NOT_PRODUCT(inc_stat_counter(&num_mallocs, 1));
   NOT_PRODUCT(inc_stat_counter(&alloc_bytes, size));
-  MemTracker::Tracker tkr = MemTracker::get_realloc_tracker();
-  void* ptr = ::realloc(memblock, size);
-  if (ptr != NULL) {
-    tkr.record((address)memblock, (address)ptr, size, memflags,
-     caller == 0 ? CALLER_PC : caller);
-  } else {
-    tkr.discard();
-  }
-  return ptr;
+   // NMT support
+  void* membase = MemTracker::record_free(memblock);
+  NMT_TrackingLevel level = MemTracker::tracking_level();
+  size_t  nmt_header_size = MemTracker::malloc_header_size(level);
+  void* ptr = ::realloc(membase, size + nmt_header_size);
+  return MemTracker::record_malloc(ptr, size, memflags, stack, level);
 #else
   if (memblock == NULL) {
-    return os::malloc(size, memflags, (caller == 0 ? CALLER_PC : caller));
+    return os::malloc(size, memflags, stack);
   }
   if ((intptr_t)memblock == (intptr_t)MallocCatchPtr) {
     tty->print_cr("os::realloc caught " PTR_FORMAT, memblock);
     breakpoint();
   }
-  verify_memory(memblock);
+  // NMT support
+  void* membase = MemTracker::malloc_base(memblock);
+  verify_memory(membase);
   NOT_PRODUCT(if (MallocVerifyInterval > 0) check_heap());
   if (size == 0) {
     return NULL;
   }
   // always move the block
-  void* ptr = os::malloc(size, memflags, caller == 0 ? CALLER_PC : caller);
+  void* ptr = os::malloc(size, memflags, stack);
   if (PrintMalloc) {
     tty->print_cr("os::remalloc " SIZE_FORMAT " bytes, " PTR_FORMAT " --> " PTR_FORMAT, size, memblock, ptr);
   }
   // Copy to new memory if malloc didn't fail
   if ( ptr != NULL ) {
-    GuardedMemory guarded(memblock);
-    memcpy(ptr, memblock, MIN2(size, guarded.get_user_size()));
-    if (paranoid) verify_memory(ptr);
+    GuardedMemory guarded(MemTracker::malloc_base(memblock));
+    // Guard's user data contains NMT header
+    size_t memblock_size = guarded.get_user_size() - MemTracker::malloc_header_size(memblock);
+    memcpy(ptr, memblock, MIN2(size, memblock_size));
+    if (paranoid) verify_memory(MemTracker::malloc_base(ptr));
     if ((intptr_t)ptr == (intptr_t)MallocCatchPtr) {
       tty->print_cr("os::realloc caught, " SIZE_FORMAT " bytes --> " PTR_FORMAT, size, ptr);
       breakpoint();
@@ -677,7 +688,6 @@
 
 
 void  os::free(void *memblock, MEMFLAGS memflags) {
-  address trackp = (address) memblock;
   NOT_PRODUCT(inc_stat_counter(&num_frees, 1));
 #ifdef ASSERT
   if (memblock == NULL) return;
@@ -685,20 +695,22 @@
     if (tty != NULL) tty->print_cr("os::free caught " PTR_FORMAT, memblock);
     breakpoint();
   }
-  verify_memory(memblock);
+  void* membase = MemTracker::record_free(memblock);
+  verify_memory(membase);
   NOT_PRODUCT(if (MallocVerifyInterval > 0) check_heap());
 
-  GuardedMemory guarded(memblock);
+  GuardedMemory guarded(membase);
   size_t size = guarded.get_user_size();
   inc_stat_counter(&free_bytes, size);
-  memblock = guarded.release_for_freeing();
+  membase = guarded.release_for_freeing();
   if (PrintMalloc && tty != NULL) {
-      fprintf(stderr, "os::free " SIZE_FORMAT " bytes --> " PTR_FORMAT "\n", size, (uintptr_t)memblock);
+      fprintf(stderr, "os::free " SIZE_FORMAT " bytes --> " PTR_FORMAT "\n", size, (uintptr_t)membase);
   }
+  ::free(membase);
+#else
+  void* membase = MemTracker::record_free(memblock);
+  ::free(membase);
 #endif
-  MemTracker::record_free(trackp, memflags);
-
-  ::free(memblock);
 }
 
 void os::init_random(long initval) {
@@ -1412,7 +1424,7 @@
 char* os::reserve_memory(size_t bytes, char* addr, size_t alignment_hint) {
   char* result = pd_reserve_memory(bytes, addr, alignment_hint);
   if (result != NULL) {
-    MemTracker::record_virtual_memory_reserve((address)result, bytes, mtNone, CALLER_PC);
+    MemTracker::record_virtual_memory_reserve((address)result, bytes, CALLER_PC);
   }
 
   return result;
@@ -1422,7 +1434,7 @@
    MEMFLAGS flags) {
   char* result = pd_reserve_memory(bytes, addr, alignment_hint);
   if (result != NULL) {
-    MemTracker::record_virtual_memory_reserve((address)result, bytes, mtNone, CALLER_PC);
+    MemTracker::record_virtual_memory_reserve((address)result, bytes, CALLER_PC);
     MemTracker::record_virtual_memory_type((address)result, flags);
   }
 
@@ -1432,7 +1444,7 @@
 char* os::attempt_reserve_memory_at(size_t bytes, char* addr) {
   char* result = pd_attempt_reserve_memory_at(bytes, addr);
   if (result != NULL) {
-    MemTracker::record_virtual_memory_reserve((address)result, bytes, mtNone, CALLER_PC);
+    MemTracker::record_virtual_memory_reserve((address)result, bytes, CALLER_PC);
   }
   return result;
 }
@@ -1472,23 +1484,29 @@
 }
 
 bool os::uncommit_memory(char* addr, size_t bytes) {
-  MemTracker::Tracker tkr = MemTracker::get_virtual_memory_uncommit_tracker();
-  bool res = pd_uncommit_memory(addr, bytes);
-  if (res) {
-    tkr.record((address)addr, bytes);
+  bool res;
+  if (MemTracker::tracking_level() > NMT_minimal) {
+    Tracker tkr = MemTracker::get_virtual_memory_uncommit_tracker();
+    res = pd_uncommit_memory(addr, bytes);
+    if (res) {
+      tkr.record((address)addr, bytes);
+    }
   } else {
-    tkr.discard();
+    res = pd_uncommit_memory(addr, bytes);
   }
   return res;
 }
 
 bool os::release_memory(char* addr, size_t bytes) {
-  MemTracker::Tracker tkr = MemTracker::get_virtual_memory_release_tracker();
-  bool res = pd_release_memory(addr, bytes);
-  if (res) {
-    tkr.record((address)addr, bytes);
+  bool res;
+  if (MemTracker::tracking_level() > NMT_minimal) {
+    Tracker tkr = MemTracker::get_virtual_memory_release_tracker();
+    res = pd_release_memory(addr, bytes);
+    if (res) {
+      tkr.record((address)addr, bytes);
+    }
   } else {
-    tkr.discard();
+    res = pd_release_memory(addr, bytes);
   }
   return res;
 }
@@ -1499,7 +1517,7 @@
                            bool allow_exec) {
   char* result = pd_map_memory(fd, file_name, file_offset, addr, bytes, read_only, allow_exec);
   if (result != NULL) {
-    MemTracker::record_virtual_memory_reserve_and_commit((address)result, bytes, mtNone, CALLER_PC);
+    MemTracker::record_virtual_memory_reserve_and_commit((address)result, bytes, CALLER_PC);
   }
   return result;
 }
@@ -1512,12 +1530,15 @@
 }
 
 bool os::unmap_memory(char *addr, size_t bytes) {
-  MemTracker::Tracker tkr = MemTracker::get_virtual_memory_release_tracker();
-  bool result = pd_unmap_memory(addr, bytes);
-  if (result) {
-    tkr.record((address)addr, bytes);
+  bool result;
+  if (MemTracker::tracking_level() > NMT_minimal) {
+    Tracker tkr = MemTracker::get_virtual_memory_release_tracker();
+    result = pd_unmap_memory(addr, bytes);
+    if (result) {
+      tkr.record((address)addr, bytes);
+    }
   } else {
-    tkr.discard();
+    result = pd_unmap_memory(addr, bytes);
   }
   return result;
 }
--- a/src/share/vm/runtime/os.hpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/runtime/os.hpp	Fri Sep 05 06:26:44 2014 -0400
@@ -66,6 +66,8 @@
 class Event;
 class DLL;
 class FileHandle;
+class NativeCallStack;
+
 template<class E> class GrowableArray;
 
 // %%%%% Moved ThreadState, START_FN, OSThread to new osThread.hpp. -- Rose
@@ -97,9 +99,11 @@
 // Typedef for structured exception handling support
 typedef void (*java_call_t)(JavaValue* value, methodHandle* method, JavaCallArguments* args, Thread* thread);
 
+class MallocTracker;
+
 class os: AllStatic {
   friend class VMStructs;
-
+  friend class MallocTracker;
  public:
   enum { page_sizes_max = 9 }; // Size of _page_sizes array (8 plus a sentinel)
 
@@ -161,7 +165,10 @@
   // Override me as needed
   static int    file_name_strcmp(const char* s1, const char* s2);
 
+  // get/unset environment variable
   static bool getenv(const char* name, char* buffer, int len);
+  static bool unsetenv(const char* name);
+
   static bool have_special_privileges();
 
   static jlong  javaTimeMillis();
@@ -207,8 +214,13 @@
 
   // Interface for detecting multiprocessor system
   static inline bool is_MP() {
+#if !INCLUDE_NMT
     assert(_processor_count > 0, "invalid processor count");
     return _processor_count > 1 || AssumeMP;
+#else
+    // NMT needs atomic operations before this initialization.
+    return true;
+#endif
   }
   static julong available_memory();
   static julong physical_memory();
@@ -651,12 +663,20 @@
   static void* thread_local_storage_at(int index);
   static void  free_thread_local_storage(int index);
 
-  // Stack walk
-  static address get_caller_pc(int n = 0);
+  // Retrieve native stack frames.
+  // Parameter:
+  //   stack:  an array to storage stack pointers.
+  //   frames: size of above array.
+  //   toSkip: number of stack frames to skip at the beginning.
+  // Return: number of stack frames captured.
+  static int get_native_stack(address* stack, int size, int toSkip = 0);
 
   // General allocation (must be MT-safe)
-  static void* malloc  (size_t size, MEMFLAGS flags, address caller_pc = 0);
-  static void* realloc (void *memblock, size_t size, MEMFLAGS flags, address caller_pc = 0);
+  static void* malloc  (size_t size, MEMFLAGS flags, const NativeCallStack& stack);
+  static void* malloc  (size_t size, MEMFLAGS flags);
+  static void* realloc (void *memblock, size_t size, MEMFLAGS flag, const NativeCallStack& stack);
+  static void* realloc (void *memblock, size_t size, MEMFLAGS flag);
+
   static void  free    (void *memblock, MEMFLAGS flags = mtNone);
   static bool  check_heap(bool force = false);      // verify C heap integrity
   static char* strdup(const char *, MEMFLAGS flags = mtInternal);  // Like strdup
--- a/src/share/vm/runtime/safepoint.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/runtime/safepoint.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -50,7 +50,6 @@
 #include "runtime/sweeper.hpp"
 #include "runtime/synchronizer.hpp"
 #include "runtime/thread.inline.hpp"
-#include "services/memTracker.hpp"
 #include "services/runtimeService.hpp"
 #include "utilities/events.hpp"
 #include "utilities/macros.hpp"
@@ -551,10 +550,6 @@
     TraceTime t7("purging class loader data graph", TraceSafepointCleanupTime);
     ClassLoaderDataGraph::purge_if_needed();
   }
-
-  if (MemTracker::is_on()) {
-    MemTracker::sync();
-  }
 }
 
 
--- a/src/share/vm/runtime/thread.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/runtime/thread.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -331,8 +331,7 @@
 #if INCLUDE_NMT
   // record thread's native stack, stack grows downward
   address stack_low_addr = stack_base() - stack_size();
-  MemTracker::record_thread_stack(stack_low_addr, stack_size(), this,
-      CURRENT_PC);
+  MemTracker::record_thread_stack(stack_low_addr, stack_size());
 #endif // INCLUDE_NMT
 }
 
@@ -350,7 +349,7 @@
 #if INCLUDE_NMT
   if (_stack_base != NULL) {
     address low_stack_addr = stack_base() - stack_size();
-    MemTracker::release_thread_stack(low_stack_addr, stack_size(), this);
+    MemTracker::release_thread_stack(low_stack_addr, stack_size());
 #ifdef ASSERT
     set_stack_base(NULL);
 #endif
@@ -1442,9 +1441,6 @@
   set_monitor_chunks(NULL);
   set_next(NULL);
   set_thread_state(_thread_new);
-#if INCLUDE_NMT
-  set_recorder(NULL);
-#endif
   _terminated = _not_terminated;
   _privileged_stack_top = NULL;
   _array_for_gc = NULL;
@@ -1519,7 +1515,6 @@
     _jni_attach_state = _not_attaching_via_jni;
   }
   assert(deferred_card_mark().is_empty(), "Default MemRegion ctor");
-  _safepoint_visible = false;
 }
 
 bool JavaThread::reguard_stack(address cur_sp) {
@@ -1582,7 +1577,6 @@
   thr_type = entry_point == &compiler_thread_entry ? os::compiler_thread :
                                                      os::java_thread;
   os::create_thread(this, thr_type, stack_sz);
-  _safepoint_visible = false;
   // The _osthread may be NULL here because we ran out of memory (too many threads active).
   // We need to throw and OutOfMemoryError - however we cannot do this here because the caller
   // may hold a lock and all locks must be unlocked before throwing the exception (throwing
@@ -1600,13 +1594,6 @@
       tty->print_cr("terminate thread %p", this);
   }
 
-  // By now, this thread should already be invisible to safepoint,
-  // and its per-thread recorder also collected.
-  assert(!is_safepoint_visible(), "wrong state");
-#if INCLUDE_NMT
-  assert(get_recorder() == NULL, "Already collected");
-#endif // INCLUDE_NMT
-
   // JSR166 -- return the parker to the free list
   Parker::Release(_parker);
   _parker = NULL ;
@@ -3370,11 +3357,6 @@
   // intialize TLS
   ThreadLocalStorage::init();
 
-  // Bootstrap native memory tracking, so it can start recording memory
-  // activities before worker thread is started. This is the first phase
-  // of bootstrapping, VM is currently running in single-thread mode.
-  MemTracker::bootstrap_single_thread();
-
   // Initialize output stream logging
   ostream_init_log();
 
@@ -3425,9 +3407,6 @@
   // Initialize Java-Level synchronization subsystem
   ObjectMonitor::Initialize() ;
 
-  // Second phase of bootstrapping, VM is about entering multi-thread mode
-  MemTracker::bootstrap_multi_thread();
-
   // Initialize global modules
   jint status = init_globals();
   if (status != JNI_OK) {
@@ -3449,9 +3428,6 @@
   // real raw monitor. VM is setup enough here for raw monitor enter.
   JvmtiExport::transition_pending_onload_raw_monitors();
 
-  // Fully start NMT
-  MemTracker::start();
-
   // Create the VMThread
   { TraceTime timer("Start VMThread", TraceStartupTime);
     VMThread::create();
@@ -4089,8 +4065,6 @@
     daemon = false;
   }
 
-  p->set_safepoint_visible(true);
-
   ThreadService::add_thread(p, daemon);
 
   // Possible GC point.
@@ -4136,13 +4110,6 @@
     // to do callbacks into the safepoint code. However, the safepoint code is not aware
     // of this thread since it is removed from the queue.
     p->set_terminated_value();
-
-    // Now, this thread is not visible to safepoint
-    p->set_safepoint_visible(false);
-    // once the thread becomes safepoint invisible, we can not use its per-thread
-    // recorder. And Threads::do_threads() no longer walks this thread, so we have
-    // to release its per-thread recorder here.
-    MemTracker::thread_exiting(p);
   } // unlock Threads_lock
 
   // Since Events::log uses a lock, we grab it outside the Threads_lock
--- a/src/share/vm/runtime/thread.hpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/runtime/thread.hpp	Fri Sep 05 06:26:44 2014 -0400
@@ -43,10 +43,6 @@
 #include "runtime/unhandledOops.hpp"
 #include "utilities/macros.hpp"
 
-#if INCLUDE_NMT
-#include "services/memRecorder.hpp"
-#endif // INCLUDE_NMT
-
 #include "trace/traceBackend.hpp"
 #include "trace/traceMacros.hpp"
 #include "utilities/exceptions.hpp"
@@ -1059,16 +1055,6 @@
   bool do_not_unlock_if_synchronized()             { return _do_not_unlock_if_synchronized; }
   void set_do_not_unlock_if_synchronized(bool val) { _do_not_unlock_if_synchronized = val; }
 
-#if INCLUDE_NMT
-  // native memory tracking
-  inline MemRecorder* get_recorder() const          { return (MemRecorder*)_recorder; }
-  inline void         set_recorder(MemRecorder* rc) { _recorder = rc; }
-
- private:
-  // per-thread memory recorder
-  MemRecorder* volatile _recorder;
-#endif // INCLUDE_NMT
-
   // Suspend/resume support for JavaThread
  private:
   void set_ext_suspended()       { set_suspend_flag (_ext_suspended);  }
@@ -1511,19 +1497,6 @@
      return result;
    }
 
- // NMT (Native memory tracking) support.
- // This flag helps NMT to determine if this JavaThread will be blocked
- // at safepoint. If not, ThreadCritical is needed for writing memory records.
- // JavaThread is only safepoint visible when it is in Threads' thread list,
- // it is not visible until it is added to the list and becomes invisible
- // once it is removed from the list.
- public:
-  bool is_safepoint_visible() const { return _safepoint_visible; }
-  void set_safepoint_visible(bool visible) { _safepoint_visible = visible; }
- private:
-  bool _safepoint_visible;
-
-  // Static operations
  public:
   // Returns the running thread as a JavaThread
   static inline JavaThread* current();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/vm/services/allocationSite.hpp	Fri Sep 05 06:26:44 2014 -0400
@@ -0,0 +1,57 @@
+/*
+ * 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.
+ *
+ */
+
+#ifndef SHARE_VM_SERVICES_ALLOCATION_SITE_HPP
+#define SHARE_VM_SERVICES_ALLOCATION_SITE_HPP
+
+#include "memory/allocation.hpp"
+#include "utilities/nativeCallStack.hpp"
+
+// Allocation site represents a code path that makes a memory
+// allocation
+template <class E> class AllocationSite VALUE_OBJ_CLASS_SPEC {
+ private:
+  NativeCallStack  _call_stack;
+  E                e;
+ public:
+  AllocationSite(const NativeCallStack& stack) : _call_stack(stack) { }
+  int hash() const { return _call_stack.hash(); }
+  bool equals(const NativeCallStack& stack) const {
+    return _call_stack.equals(stack);
+  }
+
+  bool equals(const AllocationSite<E>& other) const {
+    return other.equals(_call_stack);
+  }
+
+  const NativeCallStack* call_stack() const {
+    return &_call_stack;
+  }
+
+  // Information regarding this allocation
+  E* data()             { return &e; }
+  const E* peek() const { return &e; }
+};
+
+#endif  // SHARE_VM_SERVICES_ALLOCATION_SITE_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/vm/services/mallocSiteTable.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -0,0 +1,261 @@
+/*
+ * 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.
+ *
+ */
+#include "precompiled.hpp"
+
+
+#include "memory/allocation.inline.hpp"
+#include "runtime/atomic.hpp"
+#include "services/mallocSiteTable.hpp"
+
+/*
+ * Early os::malloc() calls come from initializations of static variables, long before entering any
+ * VM code. Upon the arrival of the first os::malloc() call, malloc site hashtable has to be
+ * initialized, along with the allocation site for the hashtable entries.
+ * To ensure that malloc site hashtable can be initialized without triggering any additional os::malloc()
+ * call, the hashtable bucket array and hashtable entry allocation site have to be static.
+ * It is not a problem for hashtable bucket, since it is an array of pointer type, C runtime just
+ * allocates a block memory and zero the memory for it.
+ * But for hashtable entry allocation site object, things get tricky. C runtime not only allocates
+ * memory for it, but also calls its constructor at some later time. If we initialize the allocation site
+ * at the first os::malloc() call, the object will be reinitialized when its constructor is called
+ * by C runtime.
+ * To workaround above issue, we declare a static size_t array with the size of the CallsiteHashtableEntry,
+ * the memory is used to instantiate CallsiteHashtableEntry for the hashtable entry allocation site.
+ * Given it is a primitive type array, C runtime will do nothing other than assign the memory block for the variable,
+ * which is exactly what we want.
+ * The same trick is also applied to create NativeCallStack object for CallsiteHashtableEntry memory allocation.
+ *
+ * Note: C++ object usually aligns to particular alignment, depends on compiler implementation, we declare
+ * the memory as size_t arrays, to ensure the memory is aligned to native machine word alignment.
+ */
+
+// Reserve enough memory for NativeCallStack and MallocSiteHashtableEntry objects
+size_t MallocSiteTable::_hash_entry_allocation_stack[CALC_OBJ_SIZE_IN_TYPE(NativeCallStack, size_t)];
+size_t MallocSiteTable::_hash_entry_allocation_site[CALC_OBJ_SIZE_IN_TYPE(MallocSiteHashtableEntry, size_t)];
+
+// Malloc site hashtable buckets
+MallocSiteHashtableEntry*  MallocSiteTable::_table[MallocSiteTable::table_size];
+
+// concurrent access counter
+volatile int MallocSiteTable::_access_count = 0;
+
+// Tracking hashtable contention
+NOT_PRODUCT(int MallocSiteTable::_peak_count = 0;)
+
+
+/*
+ * Initialize malloc site table.
+ * Hashtable entry is malloc'd, so it can cause infinite recursion.
+ * To avoid above problem, we pre-initialize a hash entry for
+ * this allocation site.
+ * The method is called during C runtime static variable initialization
+ * time, it is in single-threaded mode from JVM perspective.
+ */
+bool MallocSiteTable::initialize() {
+  assert(sizeof(_hash_entry_allocation_stack) >= sizeof(NativeCallStack), "Sanity Check");
+  assert(sizeof(_hash_entry_allocation_site) >= sizeof(MallocSiteHashtableEntry),
+    "Sanity Check");
+  assert((size_t)table_size <= MAX_MALLOCSITE_TABLE_SIZE, "Hashtable overflow");
+
+  // Fake the call stack for hashtable entry allocation
+  assert(NMT_TrackingStackDepth > 1, "At least one tracking stack");
+
+  // Create pseudo call stack for hashtable entry allocation
+  address pc[3];
+  if (NMT_TrackingStackDepth >= 3) {
+    pc[2] = (address)MallocSiteTable::allocation_at;
+  }
+  if (NMT_TrackingStackDepth >= 2) {
+    pc[1] = (address)MallocSiteTable::lookup_or_add;
+  }
+  pc[0] = (address)MallocSiteTable::new_entry;
+
+  // Instantiate NativeCallStack object, have to use placement new operator. (see comments above)
+  NativeCallStack* stack = ::new ((void*)_hash_entry_allocation_stack)
+    NativeCallStack(pc, MIN2(((int)(sizeof(pc) / sizeof(address))), ((int)NMT_TrackingStackDepth)));
+
+  // Instantiate hash entry for hashtable entry allocation callsite
+  MallocSiteHashtableEntry* entry = ::new ((void*)_hash_entry_allocation_site)
+    MallocSiteHashtableEntry(*stack);
+
+  // Add the allocation site to hashtable.
+  int index = hash_to_index(stack->hash());
+  _table[index] = entry;
+
+  return true;
+}
+
+// Walks entries in the hashtable.
+// It stops walk if the walker returns false.
+bool MallocSiteTable::walk(MallocSiteWalker* walker) {
+  MallocSiteHashtableEntry* head;
+  for (int index = 0; index < table_size; index ++) {
+    head = _table[index];
+    while (head != NULL) {
+      if (!walker->do_malloc_site(head->peek())) {
+        return false;
+      }
+      head = (MallocSiteHashtableEntry*)head->next();
+    }
+  }
+  return true;
+}
+
+/*
+ *  The hashtable does not have deletion policy on individual entry,
+ *  and each linked list node is inserted via compare-and-swap,
+ *  so each linked list is stable, the contention only happens
+ *  at the end of linked list.
+ *  This method should not return NULL under normal circumstance.
+ *  If NULL is returned, it indicates:
+ *    1. Out of memory, it cannot allocate new hash entry.
+ *    2. Overflow hash bucket.
+ *  Under any of above circumstances, caller should handle the situation.
+ */
+MallocSite* MallocSiteTable::lookup_or_add(const NativeCallStack& key, size_t* bucket_idx,
+  size_t* pos_idx) {
+  int index = hash_to_index(key.hash());
+  assert(index >= 0, "Negative index");
+  *bucket_idx = (size_t)index;
+  *pos_idx = 0;
+
+  // First entry for this hash bucket
+  if (_table[index] == NULL) {
+    MallocSiteHashtableEntry* entry = new_entry(key);
+    // OOM check
+    if (entry == NULL) return NULL;
+
+    // swap in the head
+    if (Atomic::cmpxchg_ptr((void*)entry, (volatile void *)&_table[index], NULL) == NULL) {
+      return entry->data();
+    }
+
+    delete entry;
+  }
+
+  MallocSiteHashtableEntry* head = _table[index];
+  while (head != NULL && (*pos_idx) <= MAX_BUCKET_LENGTH) {
+    MallocSite* site = head->data();
+    if (site->equals(key)) {
+      // found matched entry
+      return head->data();
+    }
+
+    if (head->next() == NULL && (*pos_idx) < MAX_BUCKET_LENGTH) {
+      MallocSiteHashtableEntry* entry = new_entry(key);
+      // OOM check
+      if (entry == NULL) return NULL;
+      if (head->atomic_insert(entry)) {
+        (*pos_idx) ++;
+        return entry->data();
+      }
+      // contended, other thread won
+      delete entry;
+    }
+    head = (MallocSiteHashtableEntry*)head->next();
+    (*pos_idx) ++;
+  }
+  return NULL;
+}
+
+// Access malloc site
+MallocSite* MallocSiteTable::malloc_site(size_t bucket_idx, size_t pos_idx) {
+  assert(bucket_idx < table_size, "Invalid bucket index");
+  MallocSiteHashtableEntry* head = _table[bucket_idx];
+  for (size_t index = 0; index < pos_idx && head != NULL;
+    index ++, head = (MallocSiteHashtableEntry*)head->next());
+  assert(head != NULL, "Invalid position index");
+  return head->data();
+}
+
+// Allocates MallocSiteHashtableEntry object. Special call stack
+// (pre-installed allocation site) has to be used to avoid infinite
+// recursion.
+MallocSiteHashtableEntry* MallocSiteTable::new_entry(const NativeCallStack& key) {
+  void* p = AllocateHeap(sizeof(MallocSiteHashtableEntry), mtNMT,
+    *hash_entry_allocation_stack(), AllocFailStrategy::RETURN_NULL);
+  return ::new (p) MallocSiteHashtableEntry(key);
+}
+
+void MallocSiteTable::reset() {
+  for (int index = 0; index < table_size; index ++) {
+    MallocSiteHashtableEntry* head = _table[index];
+    _table[index] = NULL;
+    delete_linked_list(head);
+  }
+}
+
+void MallocSiteTable::delete_linked_list(MallocSiteHashtableEntry* head) {
+  MallocSiteHashtableEntry* p;
+  while (head != NULL) {
+    p = head;
+    head = (MallocSiteHashtableEntry*)head->next();
+    if (p != (MallocSiteHashtableEntry*)_hash_entry_allocation_site) {
+      delete p;
+    }
+  }
+}
+
+void MallocSiteTable::shutdown() {
+  AccessLock locker(&_access_count);
+  locker.exclusiveLock();
+  reset();
+}
+
+bool MallocSiteTable::walk_malloc_site(MallocSiteWalker* walker) {
+  assert(walker != NULL, "NuLL walker");
+  AccessLock locker(&_access_count);
+  if (locker.sharedLock()) {
+    NOT_PRODUCT(_peak_count = MAX2(_peak_count, _access_count);)
+    return walk(walker);
+  }
+  return false;
+}
+
+
+void MallocSiteTable::AccessLock::exclusiveLock() {
+  jint target;
+  jint val;
+
+  assert(_lock_state != ExclusiveLock, "Can only call once");
+  assert(*_lock >= 0, "Can not content exclusive lock");
+
+  // make counter negative to block out shared locks
+  do {
+    val = *_lock;
+    target = _MAGIC_ + *_lock;
+  } while (Atomic::cmpxchg(target, _lock, val) != val);
+
+  // wait for all readers to exit
+  while (*_lock != _MAGIC_) {
+#ifdef _WINDOWS
+    os::naked_short_sleep(1);
+#else
+    os::NakedYield();
+#endif
+  }
+  _lock_state = ExclusiveLock;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/vm/services/mallocSiteTable.hpp	Fri Sep 05 06:26:44 2014 -0400
@@ -0,0 +1,269 @@
+/*
+ * 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.
+ *
+ */
+
+#ifndef SHARE_VM_SERVICES_MALLOC_SITE_TABLE_HPP
+#define SHARE_VM_SERVICES_MALLOC_SITE_TABLE_HPP
+
+#if INCLUDE_NMT
+
+#include "memory/allocation.hpp"
+#include "runtime/atomic.hpp"
+#include "services/allocationSite.hpp"
+#include "services/mallocTracker.hpp"
+#include "services/nmtCommon.hpp"
+#include "utilities/nativeCallStack.hpp"
+
+// MallocSite represents a code path that eventually calls
+// os::malloc() to allocate memory
+class MallocSite : public AllocationSite<MemoryCounter> {
+ public:
+  MallocSite() :
+    AllocationSite<MemoryCounter>(NativeCallStack::EMPTY_STACK) { }
+
+  MallocSite(const NativeCallStack& stack) :
+    AllocationSite<MemoryCounter>(stack) { }
+
+  void allocate(size_t size)      { data()->allocate(size);   }
+  void deallocate(size_t size)    { data()->deallocate(size); }
+
+  // Memory allocated from this code path
+  size_t size()  const { return peek()->size(); }
+  // The number of calls were made
+  size_t count() const { return peek()->count(); }
+};
+
+// Malloc site hashtable entry
+class MallocSiteHashtableEntry : public CHeapObj<mtNMT> {
+ private:
+  MallocSite                _malloc_site;
+  MallocSiteHashtableEntry* _next;
+
+ public:
+  MallocSiteHashtableEntry() : _next(NULL) { }
+
+  MallocSiteHashtableEntry(NativeCallStack stack):
+    _malloc_site(stack), _next(NULL) { }
+
+  inline const MallocSiteHashtableEntry* next() const {
+    return _next;
+  }
+
+  // Insert an entry atomically.
+  // Return true if the entry is inserted successfully.
+  // The operation can be failed due to contention from other thread.
+  bool atomic_insert(const MallocSiteHashtableEntry* entry) {
+    return (Atomic::cmpxchg_ptr((void*)entry, (volatile void*)&_next,
+      NULL) == NULL);
+  }
+
+  void set_callsite(const MallocSite& site) {
+    _malloc_site = site;
+  }
+
+  inline const MallocSite* peek() const { return &_malloc_site; }
+  inline MallocSite* data()             { return &_malloc_site; }
+
+  inline long hash() const { return _malloc_site.hash(); }
+  inline bool equals(const NativeCallStack& stack) const {
+    return _malloc_site.equals(stack);
+  }
+  // Allocation/deallocation on this allocation site
+  inline void allocate(size_t size)   { _malloc_site.allocate(size);   }
+  inline void deallocate(size_t size) { _malloc_site.deallocate(size); }
+  // Memory counters
+  inline size_t size() const  { return _malloc_site.size();  }
+  inline size_t count() const { return _malloc_site.count(); }
+};
+
+// The walker walks every entry on MallocSiteTable
+class MallocSiteWalker : public StackObj {
+ public:
+   virtual bool do_malloc_site(const MallocSite* e) { return false; }
+};
+
+/*
+ * Native memory tracking call site table.
+ * The table is only needed when detail tracking is enabled.
+ */
+class MallocSiteTable : AllStatic {
+ private:
+  // The number of hash bucket in this hashtable. The number should
+  // be tuned if malloc activities changed significantly.
+  // The statistics data can be obtained via Jcmd
+  // jcmd <pid> VM.native_memory statistics.
+
+  // Currently, (number of buckets / number of entires) ratio is
+  // about 1 / 6
+  enum {
+    table_base_size = 128,   // The base size is calculated from statistics to give
+                             // table ratio around 1:6
+    table_size = (table_base_size * NMT_TrackingStackDepth - 1)
+  };
+
+
+  // This is a very special lock, that allows multiple shared accesses (sharedLock), but
+  // once exclusive access (exclusiveLock) is requested, all shared accesses are
+  // rejected forever.
+  class AccessLock : public StackObj {
+    enum LockState {
+      NoLock,
+      SharedLock,
+      ExclusiveLock
+    };
+
+   private:
+    // A very large negative number. The only possibility to "overflow"
+    // this number is when there are more than -min_jint threads in
+    // this process, which is not going to happen in foreseeable future.
+    const static int _MAGIC_ = min_jint;
+
+    LockState      _lock_state;
+    volatile int*  _lock;
+   public:
+    AccessLock(volatile int* lock) :
+      _lock(lock), _lock_state(NoLock) {
+    }
+
+    ~AccessLock() {
+      if (_lock_state == SharedLock) {
+        Atomic::dec((volatile jint*)_lock);
+      }
+    }
+    // Acquire shared lock.
+    // Return true if shared access is granted.
+    inline bool sharedLock() {
+      jint res = Atomic::add(1, _lock);
+      if (res < 0) {
+        Atomic::add(-1, _lock);
+        return false;
+      }
+      _lock_state = SharedLock;
+      return true;
+    }
+    // Acquire exclusive lock
+    void exclusiveLock();
+ };
+
+ public:
+  static bool initialize();
+  static void shutdown();
+
+  NOT_PRODUCT(static int access_peak_count() { return _peak_count; })
+
+  // Number of hash buckets
+  static inline int hash_buckets()      { return (int)table_size; }
+
+  // Access and copy a call stack from this table. Shared lock should be
+  // acquired before access the entry.
+  static inline bool access_stack(NativeCallStack& stack, size_t bucket_idx,
+    size_t pos_idx) {
+    AccessLock locker(&_access_count);
+    if (locker.sharedLock()) {
+      NOT_PRODUCT(_peak_count = MAX2(_peak_count, _access_count);)
+      MallocSite* site = malloc_site(bucket_idx, pos_idx);
+      if (site != NULL) {
+        stack = *site->call_stack();
+        return true;
+      }
+    }
+    return false;
+  }
+
+  // Record a new allocation from specified call path.
+  // Return true if the allocation is recorded successfully, bucket_idx
+  // and pos_idx are also updated to indicate the entry where the allocation
+  // information was recorded.
+  // Return false only occurs under rare scenarios:
+  //  1. out of memory
+  //  2. overflow hash bucket
+  static inline bool allocation_at(const NativeCallStack& stack, size_t size,
+    size_t* bucket_idx, size_t* pos_idx) {
+    AccessLock locker(&_access_count);
+    if (locker.sharedLock()) {
+      NOT_PRODUCT(_peak_count = MAX2(_peak_count, _access_count);)
+      MallocSite* site = lookup_or_add(stack, bucket_idx, pos_idx);
+      if (site != NULL) site->allocate(size);
+      return site != NULL;
+    }
+    return false;
+  }
+
+  // Record memory deallocation. bucket_idx and pos_idx indicate where the allocation
+  // information was recorded.
+  static inline bool deallocation_at(size_t size, size_t bucket_idx, size_t pos_idx) {
+    AccessLock locker(&_access_count);
+    if (locker.sharedLock()) {
+      NOT_PRODUCT(_peak_count = MAX2(_peak_count, _access_count);)
+      MallocSite* site = malloc_site(bucket_idx, pos_idx);
+      if (site != NULL) {
+        site->deallocate(size);
+        return true;
+      }
+    }
+    return false;
+  }
+
+  // Walk this table.
+  static bool walk_malloc_site(MallocSiteWalker* walker);
+
+ private:
+  static MallocSiteHashtableEntry* new_entry(const NativeCallStack& key);
+  static void reset();
+
+  // Delete a bucket linked list
+  static void delete_linked_list(MallocSiteHashtableEntry* head);
+
+  static MallocSite* lookup_or_add(const NativeCallStack& key, size_t* bucket_idx, size_t* pos_idx);
+  static MallocSite* malloc_site(size_t bucket_idx, size_t pos_idx);
+  static bool walk(MallocSiteWalker* walker);
+
+  static inline int hash_to_index(int  hash) {
+    hash = (hash > 0) ? hash : (-hash);
+    return (hash % table_size);
+  }
+
+  static inline const NativeCallStack* hash_entry_allocation_stack() {
+    return (NativeCallStack*)_hash_entry_allocation_stack;
+  }
+
+ private:
+  // Counter for counting concurrent access
+  static volatile int                _access_count;
+
+  // The callsite hashtable. It has to be a static table,
+  // since malloc call can come from C runtime linker.
+  static MallocSiteHashtableEntry*   _table[table_size];
+
+
+  // Reserve enough memory for placing the objects
+
+  // The memory for hashtable entry allocation stack object
+  static size_t _hash_entry_allocation_stack[CALC_OBJ_SIZE_IN_TYPE(NativeCallStack, size_t)];
+  // The memory for hashtable entry allocation callsite object
+  static size_t _hash_entry_allocation_site[CALC_OBJ_SIZE_IN_TYPE(MallocSiteHashtableEntry, size_t)];
+  NOT_PRODUCT(static int     _peak_count;)
+};
+
+#endif // INCLUDE_NMT
+#endif // SHARE_VM_SERVICES_MALLOC_SITE_TABLE_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/vm/services/mallocTracker.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -0,0 +1,200 @@
+/*
+ * 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.
+ *
+ */
+#include "precompiled.hpp"
+
+#include "runtime/atomic.hpp"
+#include "runtime/atomic.inline.hpp"
+#include "services/mallocSiteTable.hpp"
+#include "services/mallocTracker.hpp"
+#include "services/mallocTracker.inline.hpp"
+#include "services/memTracker.hpp"
+
+size_t MallocMemorySummary::_snapshot[CALC_OBJ_SIZE_IN_TYPE(MallocMemorySnapshot, size_t)];
+
+// Total malloc'd memory amount
+size_t MallocMemorySnapshot::total() const {
+  size_t amount = 0;
+  for (int index = 0; index < mt_number_of_types; index ++) {
+    amount += _malloc[index].malloc_size();
+  }
+  amount += _tracking_header.size() + total_arena();
+  return amount;
+}
+
+// Total malloc'd memory used by arenas
+size_t MallocMemorySnapshot::total_arena() const {
+  size_t amount = 0;
+  for (int index = 0; index < mt_number_of_types; index ++) {
+    amount += _malloc[index].arena_size();
+  }
+  return amount;
+}
+
+
+void MallocMemorySnapshot::reset() {
+  _tracking_header.reset();
+  for (int index = 0; index < mt_number_of_types; index ++) {
+    _malloc[index].reset();
+  }
+}
+
+// Make adjustment by subtracting chunks used by arenas
+// from total chunks to get total free chunck size
+void MallocMemorySnapshot::make_adjustment() {
+  size_t arena_size = total_arena();
+  int chunk_idx = NMTUtil::flag_to_index(mtChunk);
+  _malloc[chunk_idx].record_free(arena_size);
+}
+
+
+void MallocMemorySummary::initialize() {
+  assert(sizeof(_snapshot) >= sizeof(MallocMemorySnapshot), "Sanity Check");
+  // Uses placement new operator to initialize static area.
+  ::new ((void*)_snapshot)MallocMemorySnapshot();
+}
+
+void MallocHeader::release() const {
+  // Tracking already shutdown, no housekeeping is needed anymore
+  if (MemTracker::tracking_level() <= NMT_minimal) return;
+
+  MallocMemorySummary::record_free(size(), flags());
+  MallocMemorySummary::record_free_malloc_header(sizeof(MallocHeader));
+  if (tracking_level() == NMT_detail) {
+    MallocSiteTable::deallocation_at(size(), _bucket_idx, _pos_idx);
+  }
+}
+
+bool MallocHeader::record_malloc_site(const NativeCallStack& stack, size_t size,
+  size_t* bucket_idx, size_t* pos_idx) const {
+  bool ret =  MallocSiteTable::allocation_at(stack, size, bucket_idx, pos_idx);
+
+  // Something went wrong, could be OOM or overflow malloc site table.
+  // We want to keep tracking data under OOM circumstance, so transition to
+  // summary tracking.
+  if (!ret) {
+    MemTracker::transition_to(NMT_summary);
+  }
+  return ret;
+}
+
+bool MallocHeader::get_stack(NativeCallStack& stack) const {
+  return MallocSiteTable::access_stack(stack, _bucket_idx, _pos_idx);
+}
+
+bool MallocTracker::initialize(NMT_TrackingLevel level) {
+  if (level >= NMT_summary) {
+    MallocMemorySummary::initialize();
+  }
+
+  if (level == NMT_detail) {
+    return MallocSiteTable::initialize();
+  }
+  return true;
+}
+
+bool MallocTracker::transition(NMT_TrackingLevel from, NMT_TrackingLevel to) {
+  assert(from != NMT_off, "Can not transition from off state");
+  assert(to != NMT_off, "Can not transition to off state");
+  if (from == NMT_minimal) {
+    MallocMemorySummary::reset();
+  }
+
+  if (to == NMT_detail) {
+    assert(from == NMT_minimal || from == NMT_summary, "Just check");
+    return MallocSiteTable::initialize();
+  } else if (from == NMT_detail) {
+    assert(to == NMT_minimal || to == NMT_summary, "Just check");
+    MallocSiteTable::shutdown();
+  }
+  return true;
+}
+
+// Record a malloc memory allocation
+void* MallocTracker::record_malloc(void* malloc_base, size_t size, MEMFLAGS flags,
+  const NativeCallStack& stack, NMT_TrackingLevel level) {
+  void*         memblock;      // the address for user data
+  MallocHeader* header = NULL;
+
+  if (malloc_base == NULL) {
+    return NULL;
+  }
+
+  // Check malloc size, size has to <= MAX_MALLOC_SIZE. This is only possible on 32-bit
+  // systems, when malloc size >= 1GB, but is is safe to assume it won't happen.
+  if (size > MAX_MALLOC_SIZE) {
+    fatal("Should not use malloc for big memory block, use virtual memory instead");
+  }
+  // Uses placement global new operator to initialize malloc header
+  switch(level) {
+    case NMT_off:
+      return malloc_base;
+    case NMT_minimal: {
+      MallocHeader* hdr = ::new (malloc_base) MallocHeader();
+      break;
+    }
+    case NMT_summary: {
+      header = ::new (malloc_base) MallocHeader(size, flags);
+      break;
+    }
+    case NMT_detail: {
+      header = ::new (malloc_base) MallocHeader(size, flags, stack);
+      break;
+    }
+    default:
+      ShouldNotReachHere();
+  }
+  memblock = (void*)((char*)malloc_base + sizeof(MallocHeader));
+
+  // The alignment check: 8 bytes alignment for 32 bit systems.
+  //                      16 bytes alignment for 64-bit systems.
+  assert(((size_t)memblock & (sizeof(size_t) * 2 - 1)) == 0, "Alignment check");
+
+  // Sanity check
+  assert(get_memory_tracking_level(memblock) == level,
+    "Wrong tracking level");
+
+#ifdef ASSERT
+  if (level > NMT_minimal) {
+    // Read back
+    assert(get_size(memblock) == size,   "Wrong size");
+    assert(get_flags(memblock) == flags, "Wrong flags");
+  }
+#endif
+
+  return memblock;
+}
+
+void* MallocTracker::record_free(void* memblock) {
+  // Never turned on
+  if (MemTracker::tracking_level() == NMT_off ||
+      memblock == NULL) {
+    return memblock;
+  }
+  MallocHeader* header = malloc_header(memblock);
+  header->release();
+
+  return (void*)header;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/vm/services/mallocTracker.hpp	Fri Sep 05 06:26:44 2014 -0400
@@ -0,0 +1,425 @@
+/*
+ * 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.
+ *
+ */
+
+#ifndef SHARE_VM_SERVICES_MALLOC_TRACKER_HPP
+#define SHARE_VM_SERVICES_MALLOC_TRACKER_HPP
+
+#if INCLUDE_NMT
+
+#include "memory/allocation.hpp"
+#include "runtime/atomic.hpp"
+#include "services/nmtCommon.hpp"
+#include "utilities/nativeCallStack.hpp"
+
+/*
+ * This counter class counts memory allocation and deallocation,
+ * records total memory allocation size and number of allocations.
+ * The counters are updated atomically.
+ */
+class MemoryCounter VALUE_OBJ_CLASS_SPEC {
+ private:
+  size_t   _count;
+  size_t   _size;
+
+  DEBUG_ONLY(size_t   _peak_count;)
+  DEBUG_ONLY(size_t   _peak_size; )
+
+ public:
+  MemoryCounter() : _count(0), _size(0) {
+    DEBUG_ONLY(_peak_count = 0;)
+    DEBUG_ONLY(_peak_size  = 0;)
+  }
+
+  // Reset counters
+  void reset() {
+    _size  = 0;
+    _count = 0;
+    DEBUG_ONLY(_peak_size = 0;)
+    DEBUG_ONLY(_peak_count = 0;)
+  }
+
+  inline void allocate(size_t sz) {
+    Atomic::add(1, (volatile MemoryCounterType*)&_count);
+    if (sz > 0) {
+      Atomic::add((MemoryCounterType)sz, (volatile MemoryCounterType*)&_size);
+      DEBUG_ONLY(_peak_size = MAX2(_peak_size, _size));
+    }
+    DEBUG_ONLY(_peak_count = MAX2(_peak_count, _count);)
+  }
+
+  inline void deallocate(size_t sz) {
+    assert(_count > 0, "Negative counter");
+    assert(_size >= sz, "Negative size");
+    Atomic::add(-1, (volatile MemoryCounterType*)&_count);
+    if (sz > 0) {
+      Atomic::add(-(MemoryCounterType)sz, (volatile MemoryCounterType*)&_size);
+    }
+  }
+
+  inline void resize(long sz) {
+    if (sz != 0) {
+      Atomic::add((MemoryCounterType)sz, (volatile MemoryCounterType*)&_size);
+      DEBUG_ONLY(_peak_size = MAX2(_size, _peak_size);)
+    }
+  }
+
+  inline size_t count() const { return _count; }
+  inline size_t size()  const { return _size;  }
+  DEBUG_ONLY(inline size_t peak_count() const { return _peak_count; })
+  DEBUG_ONLY(inline size_t peak_size()  const { return _peak_size; })
+
+};
+
+/*
+ * Malloc memory used by a particular subsystem.
+ * It includes the memory acquired through os::malloc()
+ * call and arena's backing memory.
+ */
+class MallocMemory VALUE_OBJ_CLASS_SPEC {
+ private:
+  MemoryCounter _malloc;
+  MemoryCounter _arena;
+
+ public:
+  MallocMemory() { }
+
+  inline void record_malloc(size_t sz) {
+    _malloc.allocate(sz);
+  }
+
+  inline void record_free(size_t sz) {
+    _malloc.deallocate(sz);
+  }
+
+  inline void record_new_arena() {
+    _arena.allocate(0);
+  }
+
+  inline void record_arena_free() {
+    _arena.deallocate(0);
+  }
+
+  inline void record_arena_size_change(long sz) {
+    _arena.resize(sz);
+  }
+
+  void reset() {
+    _malloc.reset();
+    _arena.reset();
+  }
+
+  inline size_t malloc_size()  const { return _malloc.size(); }
+  inline size_t malloc_count() const { return _malloc.count();}
+  inline size_t arena_size()   const { return _arena.size();  }
+  inline size_t arena_count()  const { return _arena.count(); }
+
+  DEBUG_ONLY(inline const MemoryCounter& malloc_counter() const { return _malloc; })
+  DEBUG_ONLY(inline const MemoryCounter& arena_counter()  const { return _arena;  })
+};
+
+class MallocMemorySummary;
+
+// A snapshot of malloc'd memory, includes malloc memory
+// usage by types and memory used by tracking itself.
+class MallocMemorySnapshot : public ResourceObj {
+  friend class MallocMemorySummary;
+
+ private:
+  MallocMemory      _malloc[mt_number_of_types];
+  MemoryCounter     _tracking_header;
+
+
+ public:
+  inline MallocMemory*  by_type(MEMFLAGS flags) {
+    int index = NMTUtil::flag_to_index(flags);
+    return &_malloc[index];
+  }
+
+  inline MallocMemory* by_index(int index) {
+    assert(index >= 0, "Index out of bound");
+    assert(index < mt_number_of_types, "Index out of bound");
+    return &_malloc[index];
+  }
+
+  inline MemoryCounter* malloc_overhead() {
+    return &_tracking_header;
+  }
+
+  // Total malloc'd memory amount
+  size_t total() const;
+  // Total malloc'd memory used by arenas
+  size_t total_arena() const;
+
+  inline size_t thread_count() const {
+    MallocMemorySnapshot* s = const_cast<MallocMemorySnapshot*>(this);
+    return s->by_type(mtThreadStack)->malloc_count();
+  }
+
+  void reset();
+
+  void copy_to(MallocMemorySnapshot* s) {
+    s->_tracking_header = _tracking_header;
+    for (int index = 0; index < mt_number_of_types; index ++) {
+      s->_malloc[index] = _malloc[index];
+    }
+  }
+
+  // Make adjustment by subtracting chunks used by arenas
+  // from total chunks to get total free chunk size
+  void make_adjustment();
+};
+
+/*
+ * This class is for collecting malloc statistics at summary level
+ */
+class MallocMemorySummary : AllStatic {
+ private:
+  // Reserve memory for placement of MallocMemorySnapshot object
+  static size_t _snapshot[CALC_OBJ_SIZE_IN_TYPE(MallocMemorySnapshot, size_t)];
+
+ public:
+   static void initialize();
+
+   static inline void record_malloc(size_t size, MEMFLAGS flag) {
+     as_snapshot()->by_type(flag)->record_malloc(size);
+   }
+
+   static inline void record_free(size_t size, MEMFLAGS flag) {
+     as_snapshot()->by_type(flag)->record_free(size);
+   }
+
+   static inline void record_new_arena(MEMFLAGS flag) {
+     as_snapshot()->by_type(flag)->record_new_arena();
+   }
+
+   static inline void record_arena_free(MEMFLAGS flag) {
+     as_snapshot()->by_type(flag)->record_arena_free();
+   }
+
+   static inline void record_arena_size_change(long size, MEMFLAGS flag) {
+     as_snapshot()->by_type(flag)->record_arena_size_change(size);
+   }
+
+   static void snapshot(MallocMemorySnapshot* s) {
+     as_snapshot()->copy_to(s);
+     s->make_adjustment();
+   }
+
+   // Record memory used by malloc tracking header
+   static inline void record_new_malloc_header(size_t sz) {
+     as_snapshot()->malloc_overhead()->allocate(sz);
+   }
+
+   static inline void record_free_malloc_header(size_t sz) {
+     as_snapshot()->malloc_overhead()->deallocate(sz);
+   }
+
+   // The memory used by malloc tracking headers
+   static inline size_t tracking_overhead() {
+     return as_snapshot()->malloc_overhead()->size();
+   }
+
+   // Reset all counters to zero
+   static void reset() {
+     as_snapshot()->reset();
+   }
+
+  static MallocMemorySnapshot* as_snapshot() {
+    return (MallocMemorySnapshot*)_snapshot;
+  }
+};
+
+
+/*
+ * Malloc tracking header.
+ * To satisfy malloc alignment requirement, NMT uses 2 machine words for tracking purpose,
+ * which ensures 8-bytes alignment on 32-bit systems and 16-bytes on 64-bit systems (Product build).
+ */
+
+class MallocHeader VALUE_OBJ_CLASS_SPEC {
+#ifdef _LP64
+  size_t           _size      : 62;
+  size_t           _level     : 2;
+  size_t           _flags     : 8;
+  size_t           _pos_idx   : 16;
+  size_t           _bucket_idx: 40;
+#define MAX_MALLOCSITE_TABLE_SIZE ((size_t)1 << 40)
+#define MAX_BUCKET_LENGTH         ((size_t)(1 << 16))
+#define MAX_MALLOC_SIZE           (((size_t)1 << 62) - 1)
+#else
+  size_t           _size      : 30;
+  size_t           _level     : 2;
+  size_t           _flags     : 8;
+  size_t           _pos_idx   : 8;
+  size_t           _bucket_idx: 16;
+#define MAX_MALLOCSITE_TABLE_SIZE  ((size_t)(1 << 16))
+#define MAX_BUCKET_LENGTH          ((size_t)(1 << 8))
+// Max malloc size = 1GB - 1 on 32 bit system, such has total 4GB memory
+#define MAX_MALLOC_SIZE            ((size_t)(1 << 30) - 1)
+#endif  // _LP64
+
+ public:
+  // Summary tracking header
+  MallocHeader(size_t size, MEMFLAGS flags) {
+    assert(sizeof(MallocHeader) == sizeof(void*) * 2,
+      "Wrong header size");
+
+    _level = NMT_summary;
+    _flags = flags;
+    set_size(size);
+    MallocMemorySummary::record_malloc(size, flags);
+    MallocMemorySummary::record_new_malloc_header(sizeof(MallocHeader));
+  }
+  // Detail tracking header
+  MallocHeader(size_t size, MEMFLAGS flags, const NativeCallStack& stack) {
+    assert(sizeof(MallocHeader) == sizeof(void*) * 2,
+      "Wrong header size");
+
+    _level = NMT_detail;
+    _flags = flags;
+    set_size(size);
+    size_t bucket_idx;
+    size_t pos_idx;
+    if (record_malloc_site(stack, size, &bucket_idx, &pos_idx)) {
+      assert(bucket_idx <= MAX_MALLOCSITE_TABLE_SIZE, "Overflow bucket index");
+      assert(pos_idx <= MAX_BUCKET_LENGTH, "Overflow bucket position index");
+      _bucket_idx = bucket_idx;
+      _pos_idx = pos_idx;
+    }
+    MallocMemorySummary::record_malloc(size, flags);
+    MallocMemorySummary::record_new_malloc_header(sizeof(MallocHeader));
+  }
+  // Minimal tracking header
+  MallocHeader() {
+    assert(sizeof(MallocHeader) == sizeof(void*) * 2,
+      "Wrong header size");
+
+    _level = (unsigned short)NMT_minimal;
+  }
+
+  inline NMT_TrackingLevel tracking_level() const {
+    return (NMT_TrackingLevel)_level;
+  }
+
+  inline size_t   size()  const { return _size; }
+  inline MEMFLAGS flags() const { return (MEMFLAGS)_flags; }
+  bool get_stack(NativeCallStack& stack) const;
+
+  // Cleanup tracking information before the memory is released.
+  void release() const;
+
+ private:
+  inline void set_size(size_t size) {
+    assert(size <= MAX_MALLOC_SIZE, "Malloc size too large, should use virtual memory?");
+    _size = size;
+  }
+  bool record_malloc_site(const NativeCallStack& stack, size_t size,
+    size_t* bucket_idx, size_t* pos_idx) const;
+};
+
+
+// Main class called from MemTracker to track malloc activities
+class MallocTracker : AllStatic {
+ public:
+  // Initialize malloc tracker for specific tracking level
+  static bool initialize(NMT_TrackingLevel level);
+
+  static bool transition(NMT_TrackingLevel from, NMT_TrackingLevel to);
+
+  // malloc tracking header size for specific tracking level
+  static inline size_t malloc_header_size(NMT_TrackingLevel level) {
+    return (level == NMT_off) ? 0 : sizeof(MallocHeader);
+  }
+
+  // Parameter name convention:
+  // memblock :   the beginning address for user data
+  // malloc_base: the beginning address that includes malloc tracking header
+  //
+  // The relationship:
+  // memblock = (char*)malloc_base + sizeof(nmt header)
+  //
+
+  // Record  malloc on specified memory block
+  static void* record_malloc(void* malloc_base, size_t size, MEMFLAGS flags,
+    const NativeCallStack& stack, NMT_TrackingLevel level);
+
+  // Record free on specified memory block
+  static void* record_free(void* memblock);
+
+  // Get tracking level of specified memory block
+  static inline NMT_TrackingLevel get_memory_tracking_level(void* memblock);
+
+
+  // Offset memory address to header address
+  static inline void* get_base(void* memblock);
+  static inline void* get_base(void* memblock, NMT_TrackingLevel level) {
+    if (memblock == NULL || level == NMT_off) return memblock;
+    return (char*)memblock - malloc_header_size(level);
+  }
+
+  // Get memory size
+  static inline size_t get_size(void* memblock) {
+    MallocHeader* header = malloc_header(memblock);
+    assert(header->tracking_level() >= NMT_summary,
+      "Wrong tracking level");
+    return header->size();
+  }
+
+  // Get memory type
+  static inline MEMFLAGS get_flags(void* memblock) {
+    MallocHeader* header = malloc_header(memblock);
+    assert(header->tracking_level() >= NMT_summary,
+      "Wrong tracking level");
+    return header->flags();
+  }
+
+  // Get header size
+  static inline size_t get_header_size(void* memblock) {
+    return (memblock == NULL) ? 0 : sizeof(MallocHeader);
+  }
+
+  static inline void record_new_arena(MEMFLAGS flags) {
+    MallocMemorySummary::record_new_arena(flags);
+  }
+
+  static inline void record_arena_free(MEMFLAGS flags) {
+    MallocMemorySummary::record_arena_free(flags);
+  }
+
+  static inline void record_arena_size_change(int size, MEMFLAGS flags) {
+    MallocMemorySummary::record_arena_size_change(size, flags);
+  }
+ private:
+  static inline MallocHeader* malloc_header(void *memblock) {
+    assert(memblock != NULL, "NULL pointer");
+    MallocHeader* header = (MallocHeader*)((char*)memblock - sizeof(MallocHeader));
+    assert(header->tracking_level() >= NMT_minimal, "Bad header");
+    return header;
+  }
+};
+
+#endif // INCLUDE_NMT
+
+
+#endif //SHARE_VM_SERVICES_MALLOC_TRACKER_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/vm/services/mallocTracker.inline.hpp	Fri Sep 05 06:26:44 2014 -0400
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ *
+ */
+
+#ifndef SHARE_VM_SERVICES_MALLOC_TRACKER_INLINE_HPP
+#define SHARE_VM_SERVICES_MALLOC_TRACKER_INLINE_HPP
+
+#include "services/mallocTracker.hpp"
+#include "services/memTracker.hpp"
+
+inline NMT_TrackingLevel MallocTracker::get_memory_tracking_level(void* memblock) {
+  assert(memblock != NULL, "Sanity check");
+  if (MemTracker::tracking_level() == NMT_off) return NMT_off;
+  MallocHeader* header = malloc_header(memblock);
+  return header->tracking_level();
+}
+
+inline void* MallocTracker::get_base(void* memblock){
+  return get_base(memblock, MemTracker::tracking_level());
+}
+
+#endif // SHARE_VM_SERVICES_MALLOC_TRACKER_INLINE_HPP
+
--- a/src/share/vm/services/memBaseline.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/services/memBaseline.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 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
@@ -22,471 +22,279 @@
  *
  */
 #include "precompiled.hpp"
+
 #include "memory/allocation.hpp"
 #include "runtime/safepoint.hpp"
 #include "runtime/thread.inline.hpp"
 #include "services/memBaseline.hpp"
 #include "services/memTracker.hpp"
 
-
-MemType2Name MemBaseline::MemType2NameMap[NUMBER_OF_MEMORY_TYPE] = {
-  {mtJavaHeap,   "Java Heap"},
-  {mtClass,      "Class"},
-  {mtThreadStack,"Thread Stack"},
-  {mtThread,     "Thread"},
-  {mtCode,       "Code"},
-  {mtGC,         "GC"},
-  {mtCompiler,   "Compiler"},
-  {mtInternal,   "Internal"},
-  {mtOther,      "Other"},
-  {mtSymbol,     "Symbol"},
-  {mtNMT,        "Memory Tracking"},
-  {mtTracing,    "Tracing"},
-  {mtChunk,      "Pooled Free Chunks"},
-  {mtClassShared,"Shared spaces for classes"},
-  {mtTest,       "Test"},
-  {mtNone,       "Unknown"}  // It can happen when type tagging records are lagging
-                             // behind
-};
-
-MemBaseline::MemBaseline() {
-  _baselined = false;
-
-  for (int index = 0; index < NUMBER_OF_MEMORY_TYPE; index ++) {
-    _malloc_data[index].set_type(MemType2NameMap[index]._flag);
-    _vm_data[index].set_type(MemType2NameMap[index]._flag);
-    _arena_data[index].set_type(MemType2NameMap[index]._flag);
+/*
+ * Sizes are sorted in descenting order for reporting
+ */
+int compare_malloc_size(const MallocSite& s1, const MallocSite& s2) {
+  if (s1.size() == s2.size()) {
+    return 0;
+  } else if (s1.size() > s2.size()) {
+    return -1;
+  } else {
+    return 1;
   }
-
-  _malloc_cs = NULL;
-  _vm_cs = NULL;
-  _vm_map = NULL;
-
-  _number_of_classes = 0;
-  _number_of_threads = 0;
 }
 
 
-void MemBaseline::clear() {
-  if (_malloc_cs != NULL) {
-    delete _malloc_cs;
-    _malloc_cs = NULL;
+int compare_virtual_memory_size(const VirtualMemoryAllocationSite& s1,
+  const VirtualMemoryAllocationSite& s2) {
+  if (s1.reserved() == s2.reserved()) {
+    return 0;
+  } else if (s1.reserved() > s2.reserved()) {
+    return -1;
+  } else {
+    return 1;
   }
+}
 
-  if (_vm_cs != NULL) {
-    delete _vm_cs;
-    _vm_cs = NULL;
-  }
-
-  if (_vm_map != NULL) {
-    delete _vm_map;
-    _vm_map = NULL;
-  }
-
-  reset();
+// Sort into allocation site addresses order for baseline comparison
+int compare_malloc_site(const MallocSite& s1, const MallocSite& s2) {
+  return s1.call_stack()->compare(*s2.call_stack());
 }
 
 
-void MemBaseline::reset() {
-  _baselined = false;
-  _total_vm_reserved = 0;
-  _total_vm_committed = 0;
-  _total_malloced = 0;
-  _number_of_classes = 0;
-
-  if (_malloc_cs != NULL) _malloc_cs->clear();
-  if (_vm_cs != NULL) _vm_cs->clear();
-  if (_vm_map != NULL) _vm_map->clear();
-
-  for (int index = 0; index < NUMBER_OF_MEMORY_TYPE; index ++) {
-    _malloc_data[index].clear();
-    _vm_data[index].clear();
-    _arena_data[index].clear();
-  }
+int compare_virtual_memory_site(const VirtualMemoryAllocationSite& s1,
+  const VirtualMemoryAllocationSite& s2) {
+  return s1.call_stack()->compare(*s2.call_stack());
 }
 
-MemBaseline::~MemBaseline() {
-  clear();
+/*
+ * Walker to walk malloc allocation site table
+ */
+class MallocAllocationSiteWalker : public MallocSiteWalker {
+ private:
+  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() : _count(0) { }
+
+  inline size_t count() const { return _count; }
+
+  LinkedList<MallocSite>* malloc_sites() {
+    return &_malloc_sites;
+  }
+
+  bool do_malloc_site(const MallocSite* site) {
+    if (site->size() >= MemBaseline::SIZE_THRESHOLD) {
+      if (_malloc_sites.add(*site) != NULL) {
+        _count++;
+        return true;
+      } else {
+        return false;  // OOM
+      }
+    } else {
+      // malloc site does not meet threshold, ignore and continue
+      return true;
+    }
+  }
+};
+
+// Compare virtual memory region's base address
+int compare_virtual_memory_base(const ReservedMemoryRegion& r1, const ReservedMemoryRegion& r2) {
+  return r1.compare(r2);
 }
 
-// baseline malloc'd memory records, generate overall summary and summaries by
-// memory types
-bool MemBaseline::baseline_malloc_summary(const MemPointerArray* malloc_records) {
-  MemPointerArrayIteratorImpl malloc_itr((MemPointerArray*)malloc_records);
-  MemPointerRecord* malloc_ptr = (MemPointerRecord*)malloc_itr.current();
-  size_t used_arena_size = 0;
-  int index;
-  while (malloc_ptr != NULL) {
-    index = flag2index(FLAGS_TO_MEMORY_TYPE(malloc_ptr->flags()));
-    size_t size = malloc_ptr->size();
-    if (malloc_ptr->is_arena_memory_record()) {
-      // We do have anonymous arenas, they are either used as value objects,
-      // which are embedded inside other objects, or used as stack objects.
-      _arena_data[index].inc(size);
-      used_arena_size += size;
-    } else {
-      _total_malloced += size;
-      _malloc_data[index].inc(size);
-      if (malloc_ptr->is_arena_record()) {
-        // see if arena memory record present
-        MemPointerRecord* next_malloc_ptr = (MemPointerRecordEx*)malloc_itr.peek_next();
-        if (next_malloc_ptr != NULL && next_malloc_ptr->is_arena_memory_record()) {
-          assert(next_malloc_ptr->is_memory_record_of_arena(malloc_ptr),
-             "Arena records do not match");
-          size = next_malloc_ptr->size();
-          _arena_data[index].inc(size);
-          used_arena_size += size;
-          malloc_itr.next();
-        }
+// Walk all virtual memory regions for baselining
+class VirtualMemoryAllocationWalker : public VirtualMemoryWalker {
+ private:
+  SortedLinkedList<ReservedMemoryRegion, compare_virtual_memory_base>
+                _virtual_memory_regions;
+  size_t        _count;
+
+ public:
+  VirtualMemoryAllocationWalker() : _count(0) { }
+
+  bool do_allocation_site(const ReservedMemoryRegion* rgn)  {
+    if (rgn->size() >= MemBaseline::SIZE_THRESHOLD) {
+      if (_virtual_memory_regions.add(*rgn) != NULL) {
+        _count ++;
+        return true;
+      } else {
+        return false;
       }
     }
-    malloc_ptr = (MemPointerRecordEx*)malloc_itr.next();
+    return true;
   }
 
-  // substract used arena size to get size of arena chunk in free list
-  index = flag2index(mtChunk);
-  _malloc_data[index].reduce(used_arena_size);
-  // we really don't know how many chunks in free list, so just set to
-  // 0
-  _malloc_data[index].overwrite_counter(0);
+  LinkedList<ReservedMemoryRegion>* virtual_memory_allocations() {
+    return &_virtual_memory_regions;
+  }
+};
+
+
+bool MemBaseline::baseline_summary() {
+  MallocMemorySummary::snapshot(&_malloc_memory_snapshot);
+  VirtualMemorySummary::snapshot(&_virtual_memory_snapshot);
+  return true;
+}
+
+bool MemBaseline::baseline_allocation_sites() {
+  // Malloc allocation sites
+  MallocAllocationSiteWalker malloc_walker;
+  if (!MallocSiteTable::walk_malloc_site(&malloc_walker)) {
+    return false;
+  }
+
+  _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;
+  if (!VirtualMemoryTracker::walk_virtual_memory(&virtual_memory_walker)) {
+    return false;
+  }
+
+  // Virtual memory allocations are collected in call stack order
+  _virtual_memory_allocations.move(virtual_memory_walker.virtual_memory_allocations());
+
+  if (!aggregate_virtual_memory_allocation_sites()) {
+    return false;
+  }
+  // Virtual memory allocation sites are aggregrated in call stack order
+  _virtual_memory_sites_order = by_address;
 
   return true;
 }
 
-// check if there is a safepoint in progress, if so, block the thread
-// for the safepoint
-void MemBaseline::check_safepoint(JavaThread* thr) {
-  if (SafepointSynchronize::is_synchronizing()) {
-    // grab and drop the SR_lock to honor the safepoint protocol
-    MutexLocker ml(thr->SR_lock());
-  }
-}
-
-// baseline mmap'd memory records, generate overall summary and summaries by
-// memory types
-bool MemBaseline::baseline_vm_summary(const MemPointerArray* vm_records) {
-  MemPointerArrayIteratorImpl vm_itr((MemPointerArray*)vm_records);
-  VMMemRegion* vm_ptr = (VMMemRegion*)vm_itr.current();
-  int index;
-  while (vm_ptr != NULL) {
-    if (vm_ptr->is_reserved_region()) {
-      index = flag2index(FLAGS_TO_MEMORY_TYPE(vm_ptr->flags()));
-    // we use the number of thread stack to count threads
-      if (IS_MEMORY_TYPE(vm_ptr->flags(), mtThreadStack)) {
-      _number_of_threads ++;
-    }
-      _total_vm_reserved += vm_ptr->size();
-      _vm_data[index].inc(vm_ptr->size(), 0);
-    } else {
-      _total_vm_committed += vm_ptr->size();
-      _vm_data[index].inc(0, vm_ptr->size());
-    }
-    vm_ptr = (VMMemRegion*)vm_itr.next();
-  }
-  return true;
-}
-
-// baseline malloc'd memory by callsites, but only the callsites with memory allocation
-// over 1KB are stored.
-bool MemBaseline::baseline_malloc_details(const MemPointerArray* malloc_records) {
-  assert(MemTracker::track_callsite(), "detail tracking is off");
-
-  MemPointerArrayIteratorImpl malloc_itr(const_cast<MemPointerArray*>(malloc_records));
-  MemPointerRecordEx* malloc_ptr = (MemPointerRecordEx*)malloc_itr.current();
-  MallocCallsitePointer malloc_callsite;
-
-  // initailize malloc callsite array
-  if (_malloc_cs == NULL) {
-    _malloc_cs = new (std::nothrow) MemPointerArrayImpl<MallocCallsitePointer>(64);
-    // out of native memory
-    if (_malloc_cs == NULL || _malloc_cs->out_of_memory()) {
-      return false;
-    }
-  } else {
-    _malloc_cs->clear();
-  }
-
-  MemPointerArray* malloc_data = const_cast<MemPointerArray*>(malloc_records);
-
-  // sort into callsite pc order. Details are aggregated by callsites
-  malloc_data->sort((FN_SORT)malloc_sort_by_pc);
-  bool ret = true;
-
-  // baseline memory that is totaled over 1 KB
-  while (malloc_ptr != NULL) {
-    if (!MemPointerRecord::is_arena_memory_record(malloc_ptr->flags())) {
-      // skip thread stacks
-      if (!IS_MEMORY_TYPE(malloc_ptr->flags(), mtThreadStack)) {
-        if (malloc_callsite.addr() != malloc_ptr->pc()) {
-          if ((malloc_callsite.amount()/K) > 0) {
-            if (!_malloc_cs->append(&malloc_callsite)) {
-              ret = false;
-              break;
-            }
-          }
-          malloc_callsite = MallocCallsitePointer(malloc_ptr->pc());
-        }
-        malloc_callsite.inc(malloc_ptr->size());
-      }
-    }
-    malloc_ptr = (MemPointerRecordEx*)malloc_itr.next();
-  }
-
-  // restore to address order. Snapshot malloc data is maintained in memory
-  // address order.
-  malloc_data->sort((FN_SORT)malloc_sort_by_addr);
+bool MemBaseline::baseline(bool summaryOnly) {
+  reset();
 
-  if (!ret) {
-              return false;
-            }
-  // deal with last record
-  if (malloc_callsite.addr() != 0 && (malloc_callsite.amount()/K) > 0) {
-    if (!_malloc_cs->append(&malloc_callsite)) {
-      return false;
-    }
-  }
-  return true;
-}
-
-// baseline mmap'd memory by callsites
-bool MemBaseline::baseline_vm_details(const MemPointerArray* vm_records) {
-  assert(MemTracker::track_callsite(), "detail tracking is off");
-
-  VMCallsitePointer  vm_callsite;
-  VMCallsitePointer* cur_callsite = NULL;
-  MemPointerArrayIteratorImpl vm_itr((MemPointerArray*)vm_records);
-  VMMemRegionEx* vm_ptr = (VMMemRegionEx*)vm_itr.current();
-
-  // initialize virtual memory map array
-  if (_vm_map == NULL) {
-    _vm_map = new (std::nothrow) MemPointerArrayImpl<VMMemRegionEx>(vm_records->length());
-   if (_vm_map == NULL || _vm_map->out_of_memory()) {
-     return false;
-   }
-  } else {
-    _vm_map->clear();
-  }
-
-  // initialize virtual memory callsite array
-  if (_vm_cs == NULL) {
-    _vm_cs = new (std::nothrow) MemPointerArrayImpl<VMCallsitePointer>(64);
-    if (_vm_cs == NULL || _vm_cs->out_of_memory()) {
-      return false;
-    }
-  } else {
-    _vm_cs->clear();
-  }
-
-  // consolidate virtual memory data
-  VMMemRegionEx*     reserved_rec = NULL;
-  VMMemRegionEx*     committed_rec = NULL;
+  _class_count = InstanceKlass::number_of_instance_classes();
 
-  // vm_ptr is coming in increasing base address order
-  while (vm_ptr != NULL) {
-    if (vm_ptr->is_reserved_region()) {
-      // consolidate reserved memory regions for virtual memory map.
-      // The criteria for consolidation is:
-      // 1. two adjacent reserved memory regions
-      // 2. belong to the same memory type
-      // 3. reserved from the same callsite
-      if (reserved_rec == NULL ||
-        reserved_rec->base() + reserved_rec->size() != vm_ptr->addr() ||
-        FLAGS_TO_MEMORY_TYPE(reserved_rec->flags()) != FLAGS_TO_MEMORY_TYPE(vm_ptr->flags()) ||
-        reserved_rec->pc() != vm_ptr->pc()) {
-        if (!_vm_map->append(vm_ptr)) {
-        return false;
-      }
-        // inserted reserved region, we need the pointer to the element in virtual
-        // memory map array.
-        reserved_rec = (VMMemRegionEx*)_vm_map->at(_vm_map->length() - 1);
-      } else {
-        reserved_rec->expand_region(vm_ptr->addr(), vm_ptr->size());
-    }
-
-      if (cur_callsite != NULL && !_vm_cs->append(cur_callsite)) {
-      return false;
-    }
-      vm_callsite = VMCallsitePointer(vm_ptr->pc());
-      cur_callsite = &vm_callsite;
-      vm_callsite.inc(vm_ptr->size(), 0);
-    } else {
-      // consolidate committed memory regions for virtual memory map
-      // The criterial is:
-      // 1. two adjacent committed memory regions
-      // 2. committed from the same callsite
-      if (committed_rec == NULL ||
-        committed_rec->base() + committed_rec->size() != vm_ptr->addr() ||
-        committed_rec->pc() != vm_ptr->pc()) {
-        if (!_vm_map->append(vm_ptr)) {
-          return false;
-        }
-        committed_rec = (VMMemRegionEx*)_vm_map->at(_vm_map->length() - 1);
-    } else {
-        committed_rec->expand_region(vm_ptr->addr(), vm_ptr->size());
-      }
-      vm_callsite.inc(0, vm_ptr->size());
-    }
-    vm_ptr = (VMMemRegionEx*)vm_itr.next();
-  }
-  // deal with last record
-  if (cur_callsite != NULL && !_vm_cs->append(cur_callsite)) {
+  if (!baseline_summary()) {
     return false;
   }
 
-  // sort it into callsite pc order. Details are aggregated by callsites
-  _vm_cs->sort((FN_SORT)bl_vm_sort_by_pc);
+  _baseline_type = Summary_baselined;
 
-  // walk the array to consolidate record by pc
-  MemPointerArrayIteratorImpl itr(_vm_cs);
-  VMCallsitePointer* callsite_rec = (VMCallsitePointer*)itr.current();
-  VMCallsitePointer* next_rec = (VMCallsitePointer*)itr.next();
-  while (next_rec != NULL) {
-    assert(callsite_rec != NULL, "Sanity check");
-    if (next_rec->addr() == callsite_rec->addr()) {
-      callsite_rec->inc(next_rec->reserved_amount(), next_rec->committed_amount());
-      itr.remove();
-      next_rec = (VMCallsitePointer*)itr.current();
-    } else {
-      callsite_rec = next_rec;
-      next_rec = (VMCallsitePointer*)itr.next();
-    }
+  // baseline details
+  if (!summaryOnly &&
+      MemTracker::tracking_level() == NMT_detail) {
+    baseline_allocation_sites();
+    _baseline_type = Detail_baselined;
   }
 
   return true;
 }
 
-// baseline a snapshot. If summary_only = false, memory usages aggregated by
-// callsites are also baselined.
-// The method call can be lengthy, especially when detail tracking info is
-// requested. So the method checks for safepoint explicitly.
-bool MemBaseline::baseline(MemSnapshot& snapshot, bool summary_only) {
-  Thread* THREAD = Thread::current();
-  assert(THREAD->is_Java_thread(), "must be a JavaThread");
-  MutexLocker snapshot_locker(snapshot._lock);
-  reset();
-  _baselined = baseline_malloc_summary(snapshot._alloc_ptrs);
-  if (_baselined) {
-    check_safepoint((JavaThread*)THREAD);
-    _baselined = baseline_vm_summary(snapshot._vm_ptrs);
+int compare_allocation_site(const VirtualMemoryAllocationSite& s1,
+  const VirtualMemoryAllocationSite& s2) {
+  return s1.call_stack()->compare(*s2.call_stack());
+}
+
+bool MemBaseline::aggregate_virtual_memory_allocation_sites() {
+  SortedLinkedList<VirtualMemoryAllocationSite, compare_allocation_site> allocation_sites;
+
+  VirtualMemoryAllocationIterator itr = virtual_memory_allocations();
+  const ReservedMemoryRegion* rgn;
+  VirtualMemoryAllocationSite* site;
+  while ((rgn = itr.next()) != NULL) {
+    VirtualMemoryAllocationSite tmp(*rgn->call_stack());
+    site = allocation_sites.find(tmp);
+    if (site == NULL) {
+      LinkedListNode<VirtualMemoryAllocationSite>* node =
+        allocation_sites.add(tmp);
+      if (node == NULL) return false;
+      site = node->data();
+    }
+    site->reserve_memory(rgn->size());
+    site->commit_memory(rgn->committed_size());
   }
-  _number_of_classes = snapshot.number_of_classes();
 
-  if (!summary_only && MemTracker::track_callsite() && _baselined) {
-    check_safepoint((JavaThread*)THREAD);
-    _baselined =  baseline_malloc_details(snapshot._alloc_ptrs);
-    if (_baselined) {
-      check_safepoint((JavaThread*)THREAD);
-      _baselined =  baseline_vm_details(snapshot._vm_ptrs);
-    }
-  }
-  return _baselined;
+  _virtual_memory_sites.move(&allocation_sites);
+  return true;
 }
 
-
-int MemBaseline::flag2index(MEMFLAGS flag) const {
-  for (int index = 0; index < NUMBER_OF_MEMORY_TYPE; index ++) {
-    if (MemType2NameMap[index]._flag == flag) {
-      return index;
-    }
+MallocSiteIterator MemBaseline::malloc_sites(SortingOrder order) {
+  assert(!_malloc_sites.is_empty(), "Not detail baseline");
+  switch(order) {
+    case by_size:
+      malloc_sites_to_size_order();
+      break;
+    case by_site:
+      malloc_sites_to_allocation_site_order();
+      break;
+    case by_address:
+    default:
+      ShouldNotReachHere();
   }
-  assert(false, "no type");
-  return -1;
+  return MallocSiteIterator(_malloc_sites.head());
 }
 
-const char* MemBaseline::type2name(MEMFLAGS type) {
-  for (int index = 0; index < NUMBER_OF_MEMORY_TYPE; index ++) {
-    if (MemType2NameMap[index]._flag == type) {
-      return MemType2NameMap[index]._name;
-    }
+VirtualMemorySiteIterator MemBaseline::virtual_memory_sites(SortingOrder order) {
+  assert(!_virtual_memory_sites.is_empty(), "Not detail baseline");
+  switch(order) {
+    case by_size:
+      virtual_memory_sites_to_size_order();
+      break;
+    case by_site:
+      virtual_memory_sites_to_reservation_site_order();
+      break;
+    case by_address:
+    default:
+      ShouldNotReachHere();
   }
-  assert(false, err_msg("bad type %x", type));
-  return NULL;
+  return VirtualMemorySiteIterator(_virtual_memory_sites.head());
 }
 
 
-MemBaseline& MemBaseline::operator=(const MemBaseline& other) {
-  _total_malloced = other._total_malloced;
-  _total_vm_reserved = other._total_vm_reserved;
-  _total_vm_committed = other._total_vm_committed;
-
-  _baselined = other._baselined;
-  _number_of_classes = other._number_of_classes;
-
-  for (int index = 0; index < NUMBER_OF_MEMORY_TYPE; index ++) {
-    _malloc_data[index] = other._malloc_data[index];
-    _vm_data[index] = other._vm_data[index];
-    _arena_data[index] = other._arena_data[index];
-  }
+// Sorting allocations sites in different orders
+void MemBaseline::malloc_sites_to_size_order() {
+  if (_malloc_sites_order != by_size) {
+    SortedLinkedList<MallocSite, compare_malloc_size> tmp;
 
-  if (MemTracker::track_callsite()) {
-    assert(_malloc_cs != NULL && _vm_cs != NULL, "out of memory");
-    assert(other._malloc_cs != NULL && other._vm_cs != NULL,
-           "not properly baselined");
-    _malloc_cs->clear();
-    _vm_cs->clear();
-    int index;
-    for (index = 0; index < other._malloc_cs->length(); index ++) {
-      _malloc_cs->append(other._malloc_cs->at(index));
-    }
-
-    for (index = 0; index < other._vm_cs->length(); index ++) {
-      _vm_cs->append(other._vm_cs->at(index));
-    }
+    // Add malloc sites to sorted linked list to sort into size order
+    tmp.move(&_malloc_sites);
+    _malloc_sites.set_head(tmp.head());
+    tmp.set_head(NULL);
+    _malloc_sites_order = by_size;
   }
-  return *this;
 }
 
-/* compare functions for sorting */
-
-// sort snapshot malloc'd records in callsite pc order
-int MemBaseline::malloc_sort_by_pc(const void* p1, const void* p2) {
-  assert(MemTracker::track_callsite(),"Just check");
-  const MemPointerRecordEx* mp1 = (const MemPointerRecordEx*)p1;
-  const MemPointerRecordEx* mp2 = (const MemPointerRecordEx*)p2;
-  return UNSIGNED_COMPARE(mp1->pc(), mp2->pc());
+void MemBaseline::malloc_sites_to_allocation_site_order() {
+  if (_malloc_sites_order != by_site) {
+    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());
+    tmp.set_head(NULL);
+    _malloc_sites_order = by_site;
+  }
 }
 
-// sort baselined malloc'd records in size order
-int MemBaseline::bl_malloc_sort_by_size(const void* p1, const void* p2) {
-  assert(MemTracker::is_on(), "Just check");
-  const MallocCallsitePointer* mp1 = (const MallocCallsitePointer*)p1;
-  const MallocCallsitePointer* mp2 = (const MallocCallsitePointer*)p2;
-  return UNSIGNED_COMPARE(mp2->amount(), mp1->amount());
-}
+void MemBaseline::virtual_memory_sites_to_size_order() {
+  if (_virtual_memory_sites_order != by_size) {
+    SortedLinkedList<VirtualMemoryAllocationSite, compare_virtual_memory_size> tmp;
 
-// sort baselined malloc'd records in callsite pc order
-int MemBaseline::bl_malloc_sort_by_pc(const void* p1, const void* p2) {
-  assert(MemTracker::is_on(), "Just check");
-  const MallocCallsitePointer* mp1 = (const MallocCallsitePointer*)p1;
-  const MallocCallsitePointer* mp2 = (const MallocCallsitePointer*)p2;
-  return UNSIGNED_COMPARE(mp1->addr(), mp2->addr());
+    tmp.move(&_virtual_memory_sites);
+
+    _virtual_memory_sites.set_head(tmp.head());
+    tmp.set_head(NULL);
+    _virtual_memory_sites_order = by_size;
+  }
 }
 
+void MemBaseline::virtual_memory_sites_to_reservation_site_order() {
+  if (_virtual_memory_sites_order != by_size) {
+    SortedLinkedList<VirtualMemoryAllocationSite, compare_virtual_memory_site> tmp;
 
-// sort baselined mmap'd records in size (reserved size) order
-int MemBaseline::bl_vm_sort_by_size(const void* p1, const void* p2) {
-  assert(MemTracker::is_on(), "Just check");
-  const VMCallsitePointer* mp1 = (const VMCallsitePointer*)p1;
-  const VMCallsitePointer* mp2 = (const VMCallsitePointer*)p2;
-  return UNSIGNED_COMPARE(mp2->reserved_amount(), mp1->reserved_amount());
+    tmp.move(&_virtual_memory_sites);
+
+    _virtual_memory_sites.set_head(tmp.head());
+    tmp.set_head(NULL);
+
+    _virtual_memory_sites_order = by_size;
+  }
 }
 
-// sort baselined mmap'd records in callsite pc order
-int MemBaseline::bl_vm_sort_by_pc(const void* p1, const void* p2) {
-  assert(MemTracker::is_on(), "Just check");
-  const VMCallsitePointer* mp1 = (const VMCallsitePointer*)p1;
-  const VMCallsitePointer* mp2 = (const VMCallsitePointer*)p2;
-  return UNSIGNED_COMPARE(mp1->addr(), mp2->addr());
-}
-
-
-// sort snapshot malloc'd records in memory block address order
-int MemBaseline::malloc_sort_by_addr(const void* p1, const void* p2) {
-  assert(MemTracker::is_on(), "Just check");
-  const MemPointerRecord* mp1 = (const MemPointerRecord*)p1;
-  const MemPointerRecord* mp2 = (const MemPointerRecord*)p2;
-  int delta = UNSIGNED_COMPARE(mp1->addr(), mp2->addr());
-  assert(p1 == p2 || delta != 0, "dup pointer");
-  return delta;
-}
-
--- a/src/share/vm/services/memBaseline.hpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/services/memBaseline.hpp	Fri Sep 05 06:26:44 2014 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 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
@@ -25,425 +25,181 @@
 #ifndef SHARE_VM_SERVICES_MEM_BASELINE_HPP
 #define SHARE_VM_SERVICES_MEM_BASELINE_HPP
 
+#if INCLUDE_NMT
+
 #include "memory/allocation.hpp"
 #include "runtime/mutex.hpp"
-#include "services/memPtr.hpp"
-#include "services/memSnapshot.hpp"
+#include "services/mallocSiteTable.hpp"
+#include "services/mallocTracker.hpp"
+#include "services/nmtCommon.hpp"
+#include "services/virtualMemoryTracker.hpp"
+#include "utilities/linkedlist.hpp"
 
-// compare unsigned number
-#define UNSIGNED_COMPARE(a, b)  ((a > b) ? 1 : ((a == b) ? 0 : -1))
+typedef LinkedListIterator<MallocSite>                   MallocSiteIterator;
+typedef LinkedListIterator<VirtualMemoryAllocationSite>  VirtualMemorySiteIterator;
+typedef LinkedListIterator<ReservedMemoryRegion>         VirtualMemoryAllocationIterator;
 
 /*
- * MallocCallsitePointer and VMCallsitePointer are used
- * to baseline memory blocks with their callsite information.
- * They are only available when detail tracking is turned
- * on.
+ * Baseline a memory snapshot
  */
-
-/* baselined malloc record aggregated by callsite */
-class MallocCallsitePointer : public MemPointer {
- private:
-  size_t    _count;   // number of malloc invocation from this callsite
-  size_t    _amount;  // total amount of memory malloc-ed from this callsite
-
+class MemBaseline VALUE_OBJ_CLASS_SPEC {
  public:
-  MallocCallsitePointer() {
-    _count = 0;
-    _amount = 0;
-  }
-
-  MallocCallsitePointer(address pc) : MemPointer(pc) {
-    _count = 0;
-    _amount = 0;
-  }
+  enum BaselineThreshold {
+    SIZE_THRESHOLD = K        // Only allocation size over this threshold will be baselined.
+  };
 
-  MallocCallsitePointer& operator=(const MallocCallsitePointer& p) {
-    MemPointer::operator=(p);
-    _count = p.count();
-    _amount = p.amount();
-    return *this;
-  }
-
-  inline void inc(size_t size) {
-    _count ++;
-    _amount += size;
+  enum BaselineType {
+    Not_baselined,
+    Summary_baselined,
+    Detail_baselined
   };
 
-  inline size_t count() const {
-    return _count;
-  }
+  enum SortingOrder {
+    by_address,   // by memory address
+    by_size,      // by memory size
+    by_site       // by call site where the memory is allocated from
+  };
+
+ private:
+  // Summary information
+  MallocMemorySnapshot   _malloc_memory_snapshot;
+  VirtualMemorySnapshot  _virtual_memory_snapshot;
+
+  size_t               _class_count;
 
-  inline size_t amount() const {
-    return _amount;
-  }
-};
+  // Allocation sites information
+  // Malloc allocation sites
+  LinkedListImpl<MallocSite>                  _malloc_sites;
+
+  // All virtual memory allocations
+  LinkedListImpl<ReservedMemoryRegion>        _virtual_memory_allocations;
 
-// baselined virtual memory record aggregated by callsite
-class VMCallsitePointer : public MemPointer {
- private:
-  size_t     _count;              // number of invocation from this callsite
-  size_t     _reserved_amount;    // total reserved amount
-  size_t     _committed_amount;   // total committed amount
+  // Virtual memory allocations by allocation sites, always in by_address
+  // order
+  LinkedListImpl<VirtualMemoryAllocationSite> _virtual_memory_sites;
+
+  SortingOrder         _malloc_sites_order;
+  SortingOrder         _virtual_memory_sites_order;
+
+  BaselineType         _baseline_type;
 
  public:
-  VMCallsitePointer() {
-    _count = 0;
-    _reserved_amount = 0;
-    _committed_amount = 0;
-  }
-
-  VMCallsitePointer(address pc) : MemPointer(pc) {
-    _count = 0;
-    _reserved_amount = 0;
-    _committed_amount = 0;
-  }
-
-  VMCallsitePointer& operator=(const VMCallsitePointer& p) {
-    MemPointer::operator=(p);
-    _count = p.count();
-    _reserved_amount = p.reserved_amount();
-    _committed_amount = p.committed_amount();
-    return *this;
-  }
-
-  inline void inc(size_t reserved, size_t committed) {
-    _count ++;
-    _reserved_amount += reserved;
-    _committed_amount += committed;
-  }
-
-  inline size_t count() const {
-    return _count;
-  }
-
-  inline size_t reserved_amount() const {
-    return _reserved_amount;
+  // create a memory baseline
+  MemBaseline():
+    _baseline_type(Not_baselined),
+    _class_count(0) {
   }
 
-  inline size_t committed_amount() const {
-    return _committed_amount;
+  ~MemBaseline() {
+    reset();
   }
-};
-
-// maps a memory type flag to readable name
-typedef struct _memType2Name {
-  MEMFLAGS     _flag;
-  const char*  _name;
-} MemType2Name;
-
 
-// This class aggregates malloc'd records by memory type
-class MallocMem VALUE_OBJ_CLASS_SPEC {
- private:
-  MEMFLAGS       _type;
+  bool baseline(bool summaryOnly = true);
 
-  size_t         _count;
-  size_t         _amount;
+  BaselineType baseline_type() const { return _baseline_type; }
 
- public:
-  MallocMem() {
-    _type = mtNone;
-    _count = 0;
-    _amount = 0;
+  MallocMemorySnapshot* malloc_memory_snapshot() {
+    return &_malloc_memory_snapshot;
   }
 
-  MallocMem(MEMFLAGS flags) {
-    assert(HAS_VALID_MEMORY_TYPE(flags), "no type");
-    _type = FLAGS_TO_MEMORY_TYPE(flags);
-    _count = 0;
-    _amount = 0;
-  }
-
-  inline void set_type(MEMFLAGS flag) {
-    _type = flag;
-  }
-
-  inline void clear() {
-    _count = 0;
-    _amount = 0;
-    _type = mtNone;
+  VirtualMemorySnapshot* virtual_memory_snapshot() {
+    return &_virtual_memory_snapshot;
   }
 
-  MallocMem& operator=(const MallocMem& m) {
-    assert(_type == m.type(), "different type");
-    _count = m.count();
-    _amount = m.amount();
-    return *this;
-  }
+  MallocSiteIterator malloc_sites(SortingOrder order);
+  VirtualMemorySiteIterator virtual_memory_sites(SortingOrder order);
 
-  inline void inc(size_t amt) {
-    _amount += amt;
-    _count ++;
-  }
-
-  inline void reduce(size_t amt) {
-    assert(_amount >= amt, "Just check");
-    _amount -= amt;
-  }
-
-  inline void overwrite_counter(size_t count) {
-    _count = count;
+  // Virtual memory allocation iterator always returns in virtual memory
+  // base address order.
+  VirtualMemoryAllocationIterator virtual_memory_allocations() {
+    assert(!_virtual_memory_allocations.is_empty(), "Not detail baseline");
+    return VirtualMemoryAllocationIterator(_virtual_memory_allocations.head());
   }
 
-  inline MEMFLAGS type() const {
-    return _type;
+  // Total reserved memory = total malloc'd memory + total reserved virtual
+  // memory
+  size_t total_reserved_memory() const {
+    assert(baseline_type() != Not_baselined, "Not yet baselined");
+    size_t amount = _malloc_memory_snapshot.total() +
+           _virtual_memory_snapshot.total_reserved();
+    return amount;
   }
 
-  inline bool is_type(MEMFLAGS flags) const {
-    return FLAGS_TO_MEMORY_TYPE(flags) == _type;
-  }
-
-  inline size_t count() const {
-    return _count;
+  // Total committed memory = total malloc'd memory + total committed
+  // virtual memory
+  size_t total_committed_memory() const {
+    assert(baseline_type() != Not_baselined, "Not yet baselined");
+    size_t amount = _malloc_memory_snapshot.total() +
+           _virtual_memory_snapshot.total_committed();
+    return amount;
   }
 
-  inline size_t amount() const {
-    return _amount;
-  }
-};
-
-// This class records live arena's memory usage
-class ArenaMem : public MallocMem {
- public:
-  ArenaMem(MEMFLAGS typeflag): MallocMem(typeflag) {
-  }
-  ArenaMem() { }
-};
-
-// This class aggregates virtual memory by its memory type
-class VMMem VALUE_OBJ_CLASS_SPEC {
- private:
-  MEMFLAGS       _type;
-
-  size_t         _count;
-  size_t         _reserved_amount;
-  size_t         _committed_amount;
-
- public:
-  VMMem() {
-    _type = mtNone;
-    _count = 0;
-    _reserved_amount = 0;
-    _committed_amount = 0;
+  size_t total_arena_memory() const {
+    assert(baseline_type() != Not_baselined, "Not yet baselined");
+    return _malloc_memory_snapshot.total_arena();
   }
 
-  VMMem(MEMFLAGS flags) {
-    assert(HAS_VALID_MEMORY_TYPE(flags), "no type");
-    _type = FLAGS_TO_MEMORY_TYPE(flags);
-    _count = 0;
-    _reserved_amount = 0;
-    _committed_amount = 0;
+  size_t malloc_tracking_overhead() const {
+    assert(baseline_type() != Not_baselined, "Not yet baselined");
+    MemBaseline* bl = const_cast<MemBaseline*>(this);
+    return bl->_malloc_memory_snapshot.malloc_overhead()->size();
   }
 
-  inline void clear() {
-    _type = mtNone;
-    _count = 0;
-    _reserved_amount = 0;
-    _committed_amount = 0;
+  MallocMemory* malloc_memory(MEMFLAGS flag) {
+    assert(baseline_type() != Not_baselined, "Not yet baselined");
+    return _malloc_memory_snapshot.by_type(flag);
   }
 
-  inline void set_type(MEMFLAGS flags) {
-    _type = FLAGS_TO_MEMORY_TYPE(flags);
-  }
-
-  VMMem& operator=(const VMMem& m) {
-    assert(_type == m.type(), "different type");
-
-    _count = m.count();
-    _reserved_amount = m.reserved_amount();
-    _committed_amount = m.committed_amount();
-    return *this;
+  VirtualMemory* virtual_memory(MEMFLAGS flag) {
+    assert(baseline_type() != Not_baselined, "Not yet baselined");
+    return _virtual_memory_snapshot.by_type(flag);
   }
 
 
-  inline MEMFLAGS type() const {
-    return _type;
-  }
-
-  inline bool is_type(MEMFLAGS flags) const {
-    return FLAGS_TO_MEMORY_TYPE(flags) == _type;
-  }
-
-  inline void inc(size_t reserved_amt, size_t committed_amt) {
-    _reserved_amount += reserved_amt;
-    _committed_amount += committed_amt;
-    _count ++;
-  }
-
-  inline size_t count() const {
-    return _count;
-  }
-
-  inline size_t reserved_amount() const {
-    return _reserved_amount;
+  size_t class_count() const {
+    assert(baseline_type() != Not_baselined, "Not yet baselined");
+    return _class_count;
   }
 
-  inline size_t committed_amount() const {
-    return _committed_amount;
+  size_t thread_count() const {
+    assert(baseline_type() != Not_baselined, "Not yet baselined");
+    return _malloc_memory_snapshot.thread_count();
   }
-};
-
-
-
-#define NUMBER_OF_MEMORY_TYPE    (mt_number_of_types + 1)
-
-class BaselineReporter;
-class BaselineComparisonReporter;
-
-/*
- * This class baselines current memory snapshot.
- * A memory baseline summarizes memory usage by memory type,
- * aggregates memory usage by callsites when detail tracking
- * is on.
- */
-class MemBaseline VALUE_OBJ_CLASS_SPEC {
-  friend class BaselineReporter;
-  friend class BaselineComparisonReporter;
-
- private:
-  // overall summaries
-  size_t        _total_malloced;
-  size_t        _total_vm_reserved;
-  size_t        _total_vm_committed;
-  size_t        _number_of_classes;
-  size_t        _number_of_threads;
-
-  // if it has properly baselined
-  bool          _baselined;
-
-  // we categorize memory into three categories within the memory type
-  MallocMem     _malloc_data[NUMBER_OF_MEMORY_TYPE];
-  VMMem         _vm_data[NUMBER_OF_MEMORY_TYPE];
-  ArenaMem      _arena_data[NUMBER_OF_MEMORY_TYPE];
-
-  // memory records that aggregate memory usage by callsites.
-  // only available when detail tracking is on.
-  MemPointerArray*  _malloc_cs;
-  MemPointerArray*  _vm_cs;
-  // virtual memory map
-  MemPointerArray*  _vm_map;
-
- private:
-  static MemType2Name  MemType2NameMap[NUMBER_OF_MEMORY_TYPE];
-
- private:
-  // should not use copy constructor
-  MemBaseline(MemBaseline& copy) { ShouldNotReachHere(); }
-
-  // check and block at a safepoint
-  static inline void check_safepoint(JavaThread* thr);
-
- public:
-  // create a memory baseline
-  MemBaseline();
-
-  ~MemBaseline();
-
-  inline bool baselined() const {
-    return _baselined;
-  }
-
-  MemBaseline& operator=(const MemBaseline& other);
 
   // reset the baseline for reuse
-  void clear();
-
-  // baseline the snapshot
-  bool baseline(MemSnapshot& snapshot, bool summary_only = true);
-
-  bool baseline(const MemPointerArray* malloc_records,
-                const MemPointerArray* vm_records,
-                bool summary_only = true);
+  void reset() {
+    _baseline_type = Not_baselined;
+    _malloc_memory_snapshot.reset();
+    _virtual_memory_snapshot.reset();
+    _class_count  = 0;
 
-  // total malloc'd memory of specified memory type
-  inline size_t malloc_amount(MEMFLAGS flag) const {
-    return _malloc_data[flag2index(flag)].amount();
-  }
-  // number of malloc'd memory blocks of specified memory type
-  inline size_t malloc_count(MEMFLAGS flag) const {
-    return _malloc_data[flag2index(flag)].count();
-  }
-  // total memory used by arenas of specified memory type
-  inline size_t arena_amount(MEMFLAGS flag) const {
-    return _arena_data[flag2index(flag)].amount();
-  }
-  // number of arenas of specified memory type
-  inline size_t arena_count(MEMFLAGS flag) const {
-    return _arena_data[flag2index(flag)].count();
-  }
-  // total reserved memory of specified memory type
-  inline size_t reserved_amount(MEMFLAGS flag) const {
-    return _vm_data[flag2index(flag)].reserved_amount();
-  }
-  // total committed memory of specified memory type
-  inline size_t committed_amount(MEMFLAGS flag) const {
-    return _vm_data[flag2index(flag)].committed_amount();
-  }
-  // total memory (malloc'd + mmap'd + arena) of specified
-  // memory type
-  inline size_t total_amount(MEMFLAGS flag) const {
-    int index = flag2index(flag);
-    return _malloc_data[index].amount() +
-           _vm_data[index].reserved_amount() +
-           _arena_data[index].amount();
+    _malloc_sites.clear();
+    _virtual_memory_sites.clear();
+    _virtual_memory_allocations.clear();
   }
 
-  /* overall summaries */
+ private:
+  // Baseline summary information
+  bool baseline_summary();
 
-  // total malloc'd memory in snapshot
-  inline size_t total_malloc_amount() const {
-    return _total_malloced;
-  }
-  // total mmap'd memory in snapshot
-  inline size_t total_reserved_amount() const {
-    return _total_vm_reserved;
-  }
-  // total committed memory in snapshot
-  inline size_t total_committed_amount() const {
-    return _total_vm_committed;
-  }
-  // number of loaded classes
-  inline size_t number_of_classes() const {
-    return _number_of_classes;
-  }
-  // number of running threads
-  inline size_t number_of_threads() const {
-    return _number_of_threads;
-  }
-  // lookup human readable name of a memory type
-  static const char* type2name(MEMFLAGS type);
+  // Baseline allocation sites (detail tracking only)
+  bool baseline_allocation_sites();
+
+  // Aggregate virtual memory allocation by allocation sites
+  bool aggregate_virtual_memory_allocation_sites();
 
- private:
-  // convert memory flag to the index to mapping table
-  int         flag2index(MEMFLAGS flag) const;
-
-  // reset baseline values
-  void reset();
-
-  // summarize the records in global snapshot
-  bool baseline_malloc_summary(const MemPointerArray* malloc_records);
-  bool baseline_vm_summary(const MemPointerArray* vm_records);
-  bool baseline_malloc_details(const MemPointerArray* malloc_records);
-  bool baseline_vm_details(const MemPointerArray* vm_records);
+  // Sorting allocation sites in different orders
+  // Sort allocation sites in size order
+  void malloc_sites_to_size_order();
+  // Sort allocation sites in call site address order
+  void malloc_sites_to_allocation_site_order();
 
-  // print a line of malloc'd memory aggregated by callsite
-  void print_malloc_callsite(outputStream* st, address pc, size_t size,
-    size_t count, int diff_amt, int diff_count) const;
-  // print a line of mmap'd memory aggregated by callsite
-  void print_vm_callsite(outputStream* st, address pc, size_t rsz,
-    size_t csz, int diff_rsz, int diff_csz) const;
-
-  // sorting functions for raw records
-  static int malloc_sort_by_pc(const void* p1, const void* p2);
-  static int malloc_sort_by_addr(const void* p1, const void* p2);
-
- private:
-  // sorting functions for baselined records
-  static int bl_malloc_sort_by_size(const void* p1, const void* p2);
-  static int bl_vm_sort_by_size(const void* p1, const void* p2);
-  static int bl_malloc_sort_by_pc(const void* p1, const void* p2);
-  static int bl_vm_sort_by_pc(const void* p1, const void* p2);
+  // Sort allocation sites in reserved size order
+  void virtual_memory_sites_to_size_order();
+  // Sort allocation sites in call site address order
+  void virtual_memory_sites_to_reservation_site_order();
 };
 
+#endif // INCLUDE_NMT
 
 #endif // SHARE_VM_SERVICES_MEM_BASELINE_HPP
--- a/src/share/vm/services/memPtr.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 2012, 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.
- *
- */
-
-#include "precompiled.hpp"
-#include "services/memPtr.hpp"
-#include "services/memTracker.hpp"
-
-volatile jint SequenceGenerator::_seq_number = 1;
-volatile unsigned long SequenceGenerator::_generation = 1;
-NOT_PRODUCT(jint SequenceGenerator::_max_seq_number = 1;)
-
-jint SequenceGenerator::next() {
-  jint seq = Atomic::add(1, &_seq_number);
-  if (seq < 0) {
-    MemTracker::shutdown(MemTracker::NMT_sequence_overflow);
-  } else {
-    NOT_PRODUCT(_max_seq_number = (seq > _max_seq_number) ? seq : _max_seq_number;)
-  }
-  return seq;
-}
-
--- a/src/share/vm/services/memPtr.hpp	Thu Sep 04 13:06:04 2014 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,510 +0,0 @@
-/*
- * Copyright (c) 2012, 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_SERVICES_MEM_PTR_HPP
-#define SHARE_VM_SERVICES_MEM_PTR_HPP
-
-#include "memory/allocation.hpp"
-#include "runtime/atomic.hpp"
-#include "runtime/os.hpp"
-#include "runtime/safepoint.hpp"
-
-/*
- * global sequence generator that generates sequence numbers to serialize
- * memory records.
- */
-class SequenceGenerator : AllStatic {
- public:
-  static jint next();
-
-  // peek last sequence number
-  static jint peek() {
-    return _seq_number;
-  }
-
-  // reset sequence number
-  static void reset() {
-    assert(SafepointSynchronize::is_at_safepoint(), "Safepoint required");
-    _seq_number = 1;
-    _generation ++;
-  };
-
-  static unsigned long current_generation() { return _generation; }
-  NOT_PRODUCT(static jint max_seq_num() { return _max_seq_number; })
-
- private:
-  static volatile jint             _seq_number;
-  static volatile unsigned long    _generation;
-  NOT_PRODUCT(static jint          _max_seq_number; )
-};
-
-/*
- * followings are the classes that are used to hold memory activity records in different stages.
- *   MemPointer
- *     |--------MemPointerRecord
- *                     |
- *                     |----MemPointerRecordEx
- *                     |           |
- *                     |           |-------SeqMemPointerRecordEx
- *                     |
- *                     |----SeqMemPointerRecord
- *                     |
- *                     |----VMMemRegion
- *                               |
- *                               |-----VMMemRegionEx
- *
- *
- *  prefix 'Seq' - sequenced, the record contains a sequence number
- *  surfix 'Ex'  - extension, the record contains a caller's pc
- *
- *  per-thread recorder : SeqMemPointerRecord(Ex)
- *  snapshot staging    : SeqMemPointerRecord(Ex)
- *  snapshot            : MemPointerRecord(Ex) and VMMemRegion(Ex)
- *
- */
-
-/*
- * class that wraps an address to a memory block,
- * the memory pointer either points to a malloc'd
- * memory block, or a mmap'd memory block
- */
-class MemPointer VALUE_OBJ_CLASS_SPEC {
- public:
-  MemPointer(): _addr(0) { }
-  MemPointer(address addr): _addr(addr) { }
-
-  MemPointer(const MemPointer& copy_from) {
-    _addr = copy_from.addr();
-  }
-
-  inline address addr() const {
-    return _addr;
-  }
-
-  inline operator address() const {
-    return addr();
-  }
-
-  inline bool operator == (const MemPointer& other) const {
-    return addr() == other.addr();
-  }
-
-  inline MemPointer& operator = (const MemPointer& other) {
-    _addr = other.addr();
-    return *this;
-  }
-
- protected:
-  inline void set_addr(address addr) { _addr = addr; }
-
- protected:
-  // memory address
-  address    _addr;
-};
-
-/* MemPointerRecord records an activityand associated
- * attributes on a memory block.
- */
-class MemPointerRecord : public MemPointer {
- private:
-  MEMFLAGS       _flags;
-  size_t         _size;
-
-public:
-  /* extension of MemoryType enum
-   * see share/vm/memory/allocation.hpp for details.
-   *
-   * The tag values are associated to sorting orders, so be
-   * careful if changes are needed.
-   * The allocation records should be sorted ahead of tagging
-   * records, which in turn ahead of deallocation records
-   */
-  enum MemPointerTags {
-    tag_alloc            = 0x0001, // malloc or reserve record
-    tag_commit           = 0x0002, // commit record
-    tag_type             = 0x0003, // tag virtual memory to a memory type
-    tag_uncommit         = 0x0004, // uncommit record
-    tag_release          = 0x0005, // free or release record
-    tag_size             = 0x0006, // arena size
-    tag_masks            = 0x0007, // all tag bits
-    vmBit                = 0x0008
-  };
-
-  /* helper functions to interpret the tagging flags */
-
-  inline static bool is_allocation_record(MEMFLAGS flags) {
-    return (flags & tag_masks) == tag_alloc;
-  }
-
-  inline static bool is_deallocation_record(MEMFLAGS flags) {
-    return (flags & tag_masks) == tag_release;
-  }
-
-  inline static bool is_arena_record(MEMFLAGS flags) {
-    return (flags & (otArena | tag_size)) == otArena;
-  }
-
-  inline static bool is_arena_memory_record(MEMFLAGS flags) {
-    return (flags & (otArena | tag_size)) == (otArena | tag_size);
-  }
-
-  inline static bool is_virtual_memory_record(MEMFLAGS flags) {
-    return (flags & vmBit) != 0;
-  }
-
-  inline static bool is_virtual_memory_reserve_record(MEMFLAGS flags) {
-    return (flags & 0x0F) == (tag_alloc | vmBit);
-  }
-
-  inline static bool is_virtual_memory_commit_record(MEMFLAGS flags) {
-    return (flags & 0x0F) == (tag_commit | vmBit);
-  }
-
-  inline static bool is_virtual_memory_uncommit_record(MEMFLAGS flags) {
-    return (flags & 0x0F) == (tag_uncommit | vmBit);
-  }
-
-  inline static bool is_virtual_memory_release_record(MEMFLAGS flags) {
-    return (flags & 0x0F) == (tag_release | vmBit);
-  }
-
-  inline static bool is_virtual_memory_type_record(MEMFLAGS flags) {
-    return (flags & 0x0F) == (tag_type | vmBit);
-  }
-
-  /* tagging flags */
-  inline static MEMFLAGS malloc_tag()                 { return tag_alloc;   }
-  inline static MEMFLAGS free_tag()                   { return tag_release; }
-  inline static MEMFLAGS arena_size_tag()             { return tag_size | otArena; }
-  inline static MEMFLAGS virtual_memory_tag()         { return vmBit; }
-  inline static MEMFLAGS virtual_memory_reserve_tag() { return (tag_alloc | vmBit); }
-  inline static MEMFLAGS virtual_memory_commit_tag()  { return (tag_commit | vmBit); }
-  inline static MEMFLAGS virtual_memory_uncommit_tag(){ return (tag_uncommit | vmBit); }
-  inline static MEMFLAGS virtual_memory_release_tag() { return (tag_release | vmBit); }
-  inline static MEMFLAGS virtual_memory_type_tag()    { return (tag_type | vmBit); }
-
- public:
-  MemPointerRecord(): _size(0), _flags(mtNone) { }
-
-  MemPointerRecord(address addr, MEMFLAGS memflags, size_t size = 0):
-      MemPointer(addr), _flags(memflags), _size(size) { }
-
-  MemPointerRecord(const MemPointerRecord& copy_from):
-    MemPointer(copy_from), _flags(copy_from.flags()),
-    _size(copy_from.size()) {
-  }
-
-  /* MemPointerRecord is not sequenced, it always return
-   * 0 to indicate non-sequenced
-   */
-  virtual jint seq() const               { return 0; }
-
-  inline size_t   size()  const          { return _size; }
-  inline void set_size(size_t size)      { _size = size; }
-
-  inline MEMFLAGS flags() const          { return _flags; }
-  inline void set_flags(MEMFLAGS flags)  { _flags = flags; }
-
-  MemPointerRecord& operator= (const MemPointerRecord& ptr) {
-    MemPointer::operator=(ptr);
-    _flags = ptr.flags();
-#ifdef ASSERT
-    if (IS_ARENA_OBJ(_flags)) {
-      assert(!is_vm_pointer(), "wrong flags");
-      assert((_flags & ot_masks) == otArena, "wrong flags");
-    }
-#endif
-    _size = ptr.size();
-    return *this;
-  }
-
-  // if the pointer represents a malloc-ed memory address
-  inline bool is_malloced_pointer() const {
-    return !is_vm_pointer();
-  }
-
-  // if the pointer represents a virtual memory address
-  inline bool is_vm_pointer() const {
-    return is_virtual_memory_record(_flags);
-  }
-
-  // if this record records a 'malloc' or virtual memory
-  // 'reserve' call
-  inline bool is_allocation_record() const {
-    return is_allocation_record(_flags);
-  }
-
-  // if this record records a size information of an arena
-  inline bool is_arena_memory_record() const {
-    return is_arena_memory_record(_flags);
-  }
-
-  // if this pointer represents an address to an arena object
-  inline bool is_arena_record() const {
-    return is_arena_record(_flags);
-  }
-
-  // if this record represents a size information of specific arena
-  inline bool is_memory_record_of_arena(const MemPointerRecord* arena_rc) {
-    assert(is_arena_memory_record(), "not size record");
-    assert(arena_rc->is_arena_record(), "not arena record");
-    return (arena_rc->addr() + sizeof(void*)) == addr();
-  }
-
-  // if this record records a 'free' or virtual memory 'free' call
-  inline bool is_deallocation_record() const {
-    return is_deallocation_record(_flags);
-  }
-
-  // if this record records a virtual memory 'commit' call
-  inline bool is_commit_record() const {
-    return is_virtual_memory_commit_record(_flags);
-  }
-
-  // if this record records a virtual memory 'uncommit' call
-  inline bool is_uncommit_record() const {
-    return is_virtual_memory_uncommit_record(_flags);
-  }
-
-  // if this record is a tagging record of a virtual memory block
-  inline bool is_type_tagging_record() const {
-    return is_virtual_memory_type_record(_flags);
-  }
-
-  // if the two memory pointer records actually represent the same
-  // memory block
-  inline bool is_same_region(const MemPointerRecord* other) const {
-    return (addr() == other->addr() && size() == other->size());
-  }
-
-  // if this memory region fully contains another one
-  inline bool contains_region(const MemPointerRecord* other) const {
-    return contains_region(other->addr(), other->size());
-  }
-
-  // if this memory region fully contains specified memory range
-  inline bool contains_region(address add, size_t sz) const {
-    return (addr() <= add && addr() + size() >= add + sz);
-  }
-
-  inline bool contains_address(address add) const {
-    return (addr() <= add && addr() + size() > add);
-  }
-
-  // if this memory region overlaps another region
-  inline bool overlaps_region(const MemPointerRecord* other) const {
-    assert(other != NULL, "Just check");
-    assert(size() > 0 && other->size() > 0, "empty range");
-    return contains_address(other->addr()) ||
-           contains_address(other->addr() + other->size() - 1) || // exclude end address
-           other->contains_address(addr()) ||
-           other->contains_address(addr() + size() - 1); // exclude end address
-  }
-
-};
-
-// MemPointerRecordEx also records callsite pc, from where
-// the memory block is allocated
-class MemPointerRecordEx : public MemPointerRecord {
- private:
-  address      _pc;  // callsite pc
-
- public:
-  MemPointerRecordEx(): _pc(0) { }
-
-  MemPointerRecordEx(address addr, MEMFLAGS memflags, size_t size = 0, address pc = 0):
-    MemPointerRecord(addr, memflags, size), _pc(pc) {}
-
-  MemPointerRecordEx(const MemPointerRecordEx& copy_from):
-    MemPointerRecord(copy_from), _pc(copy_from.pc()) {}
-
-  inline address pc() const { return _pc; }
-
-  void init(const MemPointerRecordEx* mpe) {
-    MemPointerRecord::operator=(*mpe);
-    _pc = mpe->pc();
-  }
-
-  void init(const MemPointerRecord* mp) {
-    MemPointerRecord::operator=(*mp);
-    _pc = 0;
-  }
-};
-
-// a virtual memory region. The region can represent a reserved
-// virtual memory region or a committed memory region
-class VMMemRegion : public MemPointerRecord {
-public:
-  VMMemRegion() { }
-
-  void init(const MemPointerRecord* mp) {
-    assert(mp->is_vm_pointer(), "Sanity check");
-    _addr = mp->addr();
-      set_size(mp->size());
-    set_flags(mp->flags());
-  }
-
-  VMMemRegion& operator=(const VMMemRegion& other) {
-    MemPointerRecord::operator=(other);
-    return *this;
-  }
-
-  inline bool is_reserved_region() const {
-    return is_allocation_record();
-  }
-
-  inline bool is_committed_region() const {
-    return is_commit_record();
-  }
-
-  /* base address of this virtual memory range */
-  inline address base() const {
-    return addr();
-  }
-
-  /* tag this virtual memory range to the specified memory type */
-  inline void tag(MEMFLAGS f) {
-    set_flags(flags() | (f & mt_masks));
-  }
-
-  // expand this region to also cover specified range.
-  // The range has to be on either end of the memory region.
-  void expand_region(address addr, size_t sz) {
-    if (addr < base()) {
-      assert(addr + sz == base(), "Sanity check");
-      _addr = addr;
-      set_size(size() + sz);
-    } else {
-      assert(base() + size() == addr, "Sanity check");
-      set_size(size() + sz);
-    }
-  }
-
-  // exclude the specified address range from this region.
-  // The excluded memory range has to be on either end of this memory
-  // region.
-  inline void exclude_region(address add, size_t sz) {
-    assert(is_reserved_region() || is_committed_region(), "Sanity check");
-    assert(addr() != NULL && size() != 0, "Sanity check");
-    assert(add >= addr() && add < addr() + size(), "Sanity check");
-    assert(add == addr() || (add + sz) == (addr() + size()),
-      "exclude in the middle");
-    if (add == addr()) {
-      set_addr(add + sz);
-      set_size(size() - sz);
-    } else {
-      set_size(size() - sz);
-    }
-  }
-};
-
-class VMMemRegionEx : public VMMemRegion {
- private:
-  jint   _seq;  // sequence number
-
- public:
-  VMMemRegionEx(): _pc(0) { }
-
-  void init(const MemPointerRecordEx* mpe) {
-    VMMemRegion::init(mpe);
-    _pc = mpe->pc();
-  }
-
-  void init(const MemPointerRecord* mpe) {
-    VMMemRegion::init(mpe);
-    _pc = 0;
-  }
-
-  VMMemRegionEx& operator=(const VMMemRegionEx& other) {
-    VMMemRegion::operator=(other);
-    _pc = other.pc();
-    return *this;
-  }
-
-  inline address pc() const { return _pc; }
- private:
-  address   _pc;
-};
-
-/*
- * Sequenced memory record
- */
-class SeqMemPointerRecord : public MemPointerRecord {
- private:
-   jint _seq;  // sequence number
-
- public:
-  SeqMemPointerRecord(): _seq(0){ }
-
-  SeqMemPointerRecord(address addr, MEMFLAGS flags, size_t size, jint seq)
-    : MemPointerRecord(addr, flags, size), _seq(seq)  {
-  }
-
-  SeqMemPointerRecord(const SeqMemPointerRecord& copy_from)
-    : MemPointerRecord(copy_from) {
-    _seq = copy_from.seq();
-  }
-
-  SeqMemPointerRecord& operator= (const SeqMemPointerRecord& ptr) {
-    MemPointerRecord::operator=(ptr);
-    _seq = ptr.seq();
-    return *this;
-  }
-
-  inline jint seq() const {
-    return _seq;
-  }
-};
-
-
-
-class SeqMemPointerRecordEx : public MemPointerRecordEx {
- private:
-  jint    _seq;  // sequence number
-
- public:
-  SeqMemPointerRecordEx(): _seq(0) { }
-
-  SeqMemPointerRecordEx(address addr, MEMFLAGS flags, size_t size,
-    jint seq, address pc):
-    MemPointerRecordEx(addr, flags, size, pc), _seq(seq)  {
-  }
-
-  SeqMemPointerRecordEx(const SeqMemPointerRecordEx& copy_from)
-    : MemPointerRecordEx(copy_from) {
-    _seq = copy_from.seq();
-  }
-
-  SeqMemPointerRecordEx& operator= (const SeqMemPointerRecordEx& ptr) {
-    MemPointerRecordEx::operator=(ptr);
-    _seq = ptr.seq();
-    return *this;
-  }
-
-  inline jint seq() const {
-    return _seq;
-  }
-};
-
-#endif // SHARE_VM_SERVICES_MEM_PTR_HPP
--- a/src/share/vm/services/memPtrArray.hpp	Thu Sep 04 13:06:04 2014 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,306 +0,0 @@
-/*
- * Copyright (c) 2012, 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_UTILITIES_MEM_PTR_ARRAY_HPP
-#define SHARE_VM_UTILITIES_MEM_PTR_ARRAY_HPP
-
-#include "memory/allocation.hpp"
-#include "services/memPtr.hpp"
-
-class MemPtr;
-class MemRecorder;
-class ArenaInfo;
-class MemSnapshot;
-
-extern "C" {
-  typedef int (*FN_SORT)(const void *, const void *);
-}
-
-
-// Memory pointer array interface. This array is used by NMT to hold
-// various memory block information.
-// The memory pointer arrays are usually walked with their iterators.
-
-class MemPointerArray : public CHeapObj<mtNMT> {
- public:
-  virtual ~MemPointerArray() { }
-
-  // return true if it can not allocate storage for the data
-  virtual bool out_of_memory() const = 0;
-  virtual bool is_empty() const = 0;
-  virtual bool is_full() = 0;
-  virtual int  length() const = 0;
-  virtual void clear() = 0;
-  virtual bool append(MemPointer* ptr) = 0;
-  virtual bool insert_at(MemPointer* ptr, int pos) = 0;
-  virtual bool remove_at(int pos) = 0;
-  virtual MemPointer* at(int index) const = 0;
-  virtual void sort(FN_SORT fn) = 0;
-  virtual size_t instance_size() const = 0;
-  virtual bool shrink() = 0;
-
-  NOT_PRODUCT(virtual int capacity() const = 0;)
-};
-
-// Iterator interface
-class MemPointerArrayIterator VALUE_OBJ_CLASS_SPEC {
- public:
-  // return the pointer at current position
-  virtual MemPointer* current() const = 0;
-  // return the next pointer and advance current position
-  virtual MemPointer* next() = 0;
-  // return next pointer without advancing current position
-  virtual MemPointer* peek_next() const = 0;
-  // return previous pointer without changing current position
-  virtual MemPointer* peek_prev() const = 0;
-  // remove the pointer at current position
-  virtual void        remove() = 0;
-  // insert the pointer at current position
-  virtual bool        insert(MemPointer* ptr) = 0;
-  // insert specified element after current position and
-  // move current position to newly inserted position
-  virtual bool        insert_after(MemPointer* ptr) = 0;
-};
-
-// implementation class
-class MemPointerArrayIteratorImpl : public MemPointerArrayIterator {
- protected:
-  MemPointerArray*  _array;
-  int               _pos;
-
- public:
-  MemPointerArrayIteratorImpl(MemPointerArray* arr) {
-    assert(arr != NULL, "Parameter check");
-    _array = arr;
-    _pos = 0;
-  }
-
-  virtual MemPointer* current() const {
-    if (_pos < _array->length()) {
-      return _array->at(_pos);
-    }
-    return NULL;
-  }
-
-  virtual MemPointer* next() {
-    if (_pos + 1 < _array->length()) {
-      return _array->at(++_pos);
-    }
-    _pos = _array->length();
-    return NULL;
-  }
-
-  virtual MemPointer* peek_next() const {
-    if (_pos + 1 < _array->length()) {
-      return _array->at(_pos + 1);
-    }
-    return NULL;
-  }
-
-  virtual MemPointer* peek_prev() const {
-    if (_pos > 0) {
-      return _array->at(_pos - 1);
-    }
-    return NULL;
-  }
-
-  virtual void remove() {
-    if (_pos < _array->length()) {
-      _array->remove_at(_pos);
-    }
-  }
-
-  virtual bool insert(MemPointer* ptr) {
-    return _array->insert_at(ptr, _pos);
-  }
-
-  virtual bool insert_after(MemPointer* ptr) {
-    if (_array->insert_at(ptr, _pos + 1)) {
-      _pos ++;
-      return true;
-    }
-    return false;
-  }
-};
-
-
-
-// Memory pointer array implementation.
-// This implementation implements expandable array
-#define DEFAULT_PTR_ARRAY_SIZE 1024
-
-template <class E> class MemPointerArrayImpl : public MemPointerArray {
- private:
-  int                   _max_size;
-  int                   _size;
-  bool                  _init_elements;
-  E*                    _data;
-
- public:
-  MemPointerArrayImpl(int initial_size = DEFAULT_PTR_ARRAY_SIZE, bool init_elements = true):
-   _max_size(initial_size), _size(0), _init_elements(init_elements) {
-    _data = (E*)raw_allocate(sizeof(E), initial_size);
-    if (_init_elements) {
-      for (int index = 0; index < _max_size; index ++) {
-        ::new ((void*)&_data[index]) E();
-      }
-    }
-  }
-
-  virtual ~MemPointerArrayImpl() {
-    if (_data != NULL) {
-      raw_free(_data);
-    }
-  }
-
- public:
-  bool out_of_memory() const {
-    return (_data == NULL);
-  }
-
-  size_t instance_size() const {
-    return sizeof(MemPointerArrayImpl<E>) + _max_size * sizeof(E);
-  }
-
-  bool is_empty() const {
-    assert(_data != NULL, "Just check");
-    return _size == 0;
-  }
-
-  bool is_full() {
-    assert(_data != NULL, "Just check");
-    if (_size < _max_size) {
-      return false;
-    } else {
-      return !expand_array();
-    }
-  }
-
-  int length() const {
-    assert(_data != NULL, "Just check");
-    return _size;
-  }
-
-  NOT_PRODUCT(int capacity() const { return _max_size; })
-
-  void clear() {
-    assert(_data != NULL, "Just check");
-    _size = 0;
-  }
-
-  bool append(MemPointer* ptr) {
-    assert(_data != NULL, "Just check");
-    if (is_full()) {
-      return false;
-    }
-    _data[_size ++] = *(E*)ptr;
-    return true;
-  }
-
-  bool insert_at(MemPointer* ptr, int pos) {
-    assert(_data != NULL, "Just check");
-    if (is_full()) {
-      return false;
-    }
-    for (int index = _size; index > pos; index --) {
-      _data[index] = _data[index - 1];
-    }
-    _data[pos] = *(E*)ptr;
-    _size ++;
-    return true;
-  }
-
-  bool remove_at(int pos) {
-    assert(_data != NULL, "Just check");
-    if (_size <= pos && pos >= 0) {
-      return false;
-    }
-    -- _size;
-
-    for (int index = pos; index < _size; index ++) {
-      _data[index] = _data[index + 1];
-    }
-    return true;
-  }
-
-  MemPointer* at(int index) const {
-    assert(_data != NULL, "Just check");
-    assert(index >= 0 && index < _size, "illegal index");
-    return &_data[index];
-  }
-
-  bool shrink() {
-    float used = ((float)_size) / ((float)_max_size);
-    if (used < 0.40) {
-      E* old_ptr = _data;
-      int new_size = ((_max_size) / (2 * DEFAULT_PTR_ARRAY_SIZE) + 1) * DEFAULT_PTR_ARRAY_SIZE;
-      _data = (E*)raw_reallocate(_data, sizeof(E), new_size);
-      if (_data == NULL) {
-        _data = old_ptr;
-        return false;
-      } else {
-        _max_size = new_size;
-        return true;
-      }
-    }
-    return false;
-  }
-
-  void sort(FN_SORT fn) {
-    assert(_data != NULL, "Just check");
-    qsort((void*)_data, _size, sizeof(E), fn);
-  }
-
- private:
-  bool  expand_array() {
-    assert(_data != NULL, "Not yet allocated");
-    E* old_ptr = _data;
-    if ((_data = (E*)raw_reallocate((void*)_data, sizeof(E),
-      _max_size + DEFAULT_PTR_ARRAY_SIZE)) == NULL) {
-      _data = old_ptr;
-      return false;
-    } else {
-      _max_size += DEFAULT_PTR_ARRAY_SIZE;
-      if (_init_elements) {
-        for (int index = _size; index < _max_size; index ++) {
-          ::new ((void*)&_data[index]) E();
-        }
-      }
-      return true;
-    }
-  }
-
-  void* raw_allocate(size_t elementSize, int items) {
-    return os::malloc(elementSize * items, mtNMT);
-  }
-
-  void* raw_reallocate(void* ptr, size_t elementSize, int items) {
-    return os::realloc(ptr, elementSize * items, mtNMT);
-  }
-
-  void  raw_free(void* ptr) {
-    os::free(ptr, mtNMT);
-  }
-};
-
-#endif // SHARE_VM_UTILITIES_MEM_PTR_ARRAY_HPP
--- a/src/share/vm/services/memRecorder.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,171 +0,0 @@
-/*
- * Copyright (c) 2012, 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.
- *
- */
-
-#include "precompiled.hpp"
-
-#include "runtime/atomic.hpp"
-#include "services/memBaseline.hpp"
-#include "services/memRecorder.hpp"
-#include "services/memPtr.hpp"
-#include "services/memTracker.hpp"
-
-MemPointer* SequencedRecordIterator::next_record() {
-  MemPointerRecord* itr_cur = (MemPointerRecord*)_itr.current();
-  if (itr_cur == NULL)  {
-    return itr_cur;
-  }
-
-  MemPointerRecord* itr_next = (MemPointerRecord*)_itr.next();
-
-  // don't collapse virtual memory records
-  while (itr_next != NULL && !itr_cur->is_vm_pointer() &&
-    !itr_next->is_vm_pointer() &&
-    same_kind(itr_cur, itr_next)) {
-    itr_cur = itr_next;
-    itr_next = (MemPointerRecord*)_itr.next();
-  }
-
-  return itr_cur;
-}
-
-
-volatile jint MemRecorder::_instance_count = 0;
-
-MemRecorder::MemRecorder() {
-  assert(MemTracker::is_on(), "Native memory tracking is off");
-  Atomic::inc(&_instance_count);
-  set_generation();
-
-  if (MemTracker::track_callsite()) {
-    _pointer_records = new (std::nothrow)FixedSizeMemPointerArray<SeqMemPointerRecordEx,
-        DEFAULT_RECORDER_PTR_ARRAY_SIZE>();
-  } else {
-    _pointer_records = new (std::nothrow)FixedSizeMemPointerArray<SeqMemPointerRecord,
-        DEFAULT_RECORDER_PTR_ARRAY_SIZE>();
-  }
-  _next = NULL;
-
-
-  if (_pointer_records != NULL) {
-    // recode itself
-    address pc = CURRENT_PC;
-    record((address)this, (MemPointerRecord::malloc_tag()|mtNMT|otNMTRecorder),
-        sizeof(MemRecorder), SequenceGenerator::next(), pc);
-    record((address)_pointer_records, (MemPointerRecord::malloc_tag()|mtNMT|otNMTRecorder),
-        _pointer_records->instance_size(), SequenceGenerator::next(), pc);
-  }
-}
-
-MemRecorder::~MemRecorder() {
-  if (_pointer_records != NULL) {
-    if (MemTracker::is_on()) {
-      MemTracker::record_free((address)_pointer_records, mtNMT);
-      MemTracker::record_free((address)this, mtNMT);
-    }
-    delete _pointer_records;
-  }
-  // delete all linked recorders
-  while (_next != NULL) {
-    MemRecorder* tmp = _next;
-    _next = _next->next();
-    tmp->set_next(NULL);
-    delete tmp;
-  }
-  Atomic::dec(&_instance_count);
-}
-
-// Sorting order:
-//   1. memory block address
-//   2. mem pointer record tags
-//   3. sequence number
-int MemRecorder::sort_record_fn(const void* e1, const void* e2) {
-  const MemPointerRecord* p1 = (const MemPointerRecord*)e1;
-  const MemPointerRecord* p2 = (const MemPointerRecord*)e2;
-  int delta = UNSIGNED_COMPARE(p1->addr(), p2->addr());
-  if (delta == 0) {
-    int df = UNSIGNED_COMPARE((p1->flags() & MemPointerRecord::tag_masks),
-                              (p2->flags() & MemPointerRecord::tag_masks));
-    if (df == 0) {
-      assert(p1->seq() != p2->seq(), "dup seq");
-      return p1->seq() - p2->seq();
-    } else {
-      return df;
-    }
-  } else {
-    return delta;
-  }
-}
-
-bool MemRecorder::record(address p, MEMFLAGS flags, size_t size, jint seq, address pc) {
-  assert(seq > 0, "No sequence number");
-#ifdef ASSERT
-  if (MemPointerRecord::is_virtual_memory_record(flags)) {
-    assert((flags & MemPointerRecord::tag_masks) != 0, "bad virtual memory record");
-  } else {
-    assert((flags & MemPointerRecord::tag_masks) == MemPointerRecord::malloc_tag() ||
-           (flags & MemPointerRecord::tag_masks) == MemPointerRecord::free_tag() ||
-           IS_ARENA_OBJ(flags),
-           "bad malloc record");
-  }
-  // a recorder should only hold records within the same generation
-  unsigned long cur_generation = SequenceGenerator::current_generation();
-  assert(cur_generation == _generation,
-         "this thread did not enter sync point");
-#endif
-
-  if (MemTracker::track_callsite()) {
-    SeqMemPointerRecordEx ap(p, flags, size, seq, pc);
-    debug_only(check_dup_seq(ap.seq());)
-    return _pointer_records->append(&ap);
-  } else {
-    SeqMemPointerRecord ap(p, flags, size, seq);
-    debug_only(check_dup_seq(ap.seq());)
-    return _pointer_records->append(&ap);
-  }
-}
-
-  // iterator for alloc pointers
-SequencedRecordIterator MemRecorder::pointer_itr() {
-  assert(_pointer_records != NULL, "just check");
-  _pointer_records->sort((FN_SORT)sort_record_fn);
-  return SequencedRecordIterator(_pointer_records);
-}
-
-
-void MemRecorder::set_generation() {
-  _generation = SequenceGenerator::current_generation();
-}
-
-#ifdef ASSERT
-
-void MemRecorder::check_dup_seq(jint seq) const {
-  MemPointerArrayIteratorImpl itr(_pointer_records);
-  MemPointerRecord* rc = (MemPointerRecord*)itr.current();
-  while (rc != NULL) {
-    assert(rc->seq() != seq, "dup seq");
-    rc = (MemPointerRecord*)itr.next();
-  }
-}
-
-#endif
--- a/src/share/vm/services/memRecorder.hpp	Thu Sep 04 13:06:04 2014 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,271 +0,0 @@
-/*
- * Copyright (c) 2012, 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_SERVICES_MEM_RECORDER_HPP
-#define SHARE_VM_SERVICES_MEM_RECORDER_HPP
-
-#include "memory/allocation.hpp"
-#include "runtime/os.hpp"
-#include "services/memPtrArray.hpp"
-
-class MemSnapshot;
-class MemTracker;
-class MemTrackWorker;
-
-// Fixed size memory pointer array implementation
-template <class E, int SIZE> class FixedSizeMemPointerArray :
-  public MemPointerArray {
-  // This implementation is for memory recorder only
-  friend class MemRecorder;
-
- private:
-  E      _data[SIZE];
-  int    _size;
-
- protected:
-  FixedSizeMemPointerArray(bool init_elements = false):
-   _size(0){
-    if (init_elements) {
-      for (int index = 0; index < SIZE; index ++) {
-        ::new ((void*)&_data[index]) E();
-      }
-    }
-  }
-
-  void* operator new(size_t size, const std::nothrow_t& nothrow_constant) throw() {
-    // the instance is part of memRecorder, needs to be tagged with 'otNMTRecorder'
-    // to avoid recursion
-    return os::malloc(size, (mtNMT | otNMTRecorder));
-  }
-
-  void* operator new(size_t size) throw() {
-    assert(false, "use nothrow version");
-    return NULL;
-  }
-
-  void operator delete(void* p) {
-    os::free(p, (mtNMT | otNMTRecorder));
-  }
-
-  // instance size
-  inline size_t instance_size() const {
-    return sizeof(FixedSizeMemPointerArray<E, SIZE>);
-  }
-
-  NOT_PRODUCT(int capacity() const { return SIZE; })
-
- public:
-  // implementation of public interface
-  bool out_of_memory() const { return false; }
-  bool is_empty()      const { return _size == 0; }
-  bool is_full()             { return length() >= SIZE; }
-  int  length()        const { return _size; }
-
-  void clear() {
-    _size = 0;
-  }
-
-  bool append(MemPointer* ptr) {
-    if (is_full()) return false;
-    _data[_size ++] = *(E*)ptr;
-    return true;
-  }
-
-  virtual bool insert_at(MemPointer* p, int pos) {
-    assert(false, "append only");
-    return false;
-  }
-
-  virtual bool remove_at(int pos) {
-    assert(false, "not supported");
-    return false;
-  }
-
-  MemPointer* at(int index) const {
-    assert(index >= 0 && index < length(),
-      "parameter check");
-    return ((E*)&_data[index]);
-  }
-
-  void sort(FN_SORT fn) {
-    qsort((void*)_data, _size, sizeof(E), fn);
-  }
-
-  bool shrink() {
-    return false;
-  }
-};
-
-
-// This iterator requires pre-sorted MemPointerArray, which is sorted by:
-//  1. address
-//  2. allocation type
-//  3. sequence number
-// During the array walking, iterator collapses pointers with the same
-// address and allocation type, and only returns the one with highest
-// sequence number.
-//
-// This is read-only iterator, update methods are asserted.
-class SequencedRecordIterator : public MemPointerArrayIterator {
- private:
-   MemPointerArrayIteratorImpl _itr;
-   MemPointer*                 _cur;
-
- public:
-  SequencedRecordIterator(const MemPointerArray* arr):
-    _itr(const_cast<MemPointerArray*>(arr)) {
-    _cur = next_record();
-  }
-
-  SequencedRecordIterator(const SequencedRecordIterator& itr):
-    _itr(itr._itr) {
-    _cur = next_record();
-  }
-
-  // return the pointer at current position
-  virtual MemPointer* current() const {
-    return _cur;
-  };
-
-  // return the next pointer and advance current position
-  virtual MemPointer* next() {
-    _cur = next_record();
-    return _cur;
-  }
-
-  // return the next pointer without advancing current position
-  virtual MemPointer* peek_next() const {
-    assert(false, "not implemented");
-    return NULL;
-
-  }
-  // return the previous pointer without changing current position
-  virtual MemPointer* peek_prev() const {
-    assert(false, "not implemented");
-    return NULL;
-  }
-
-  // remove the pointer at current position
-  virtual void remove() {
-    assert(false, "read-only iterator");
-  };
-  // insert the pointer at current position
-  virtual bool insert(MemPointer* ptr) {
-    assert(false, "read-only iterator");
-    return false;
-  }
-
-  virtual bool insert_after(MemPointer* ptr) {
-    assert(false, "read-only iterator");
-    return false;
-  }
- private:
-  // collapse the 'same kind' of records, and return this 'kind' of
-  // record with highest sequence number
-  MemPointer* next_record();
-
-  // Test if the two records are the same kind: the same memory block and allocation
-  // type.
-  inline bool same_kind(const MemPointerRecord* p1, const MemPointerRecord* p2) const {
-    assert(!p1->is_vm_pointer() && !p2->is_vm_pointer(), "malloc pointer only");
-    return (p1->addr() == p2->addr() &&
-      (p1->flags() &MemPointerRecord::tag_masks) ==
-      (p2->flags() & MemPointerRecord::tag_masks));
-  }
-};
-
-
-
-#define DEFAULT_RECORDER_PTR_ARRAY_SIZE 512
-
-class MemRecorder : public CHeapObj<mtNMT|otNMTRecorder> {
-  friend class MemSnapshot;
-  friend class MemTracker;
-  friend class MemTrackWorker;
-  friend class GenerationData;
-
- protected:
-  // the array that holds memory records
-  MemPointerArray*         _pointer_records;
-
- private:
-  // used for linked list
-  MemRecorder*             _next;
-  // active recorder can only record a certain generation data
-  unsigned long            _generation;
-
- protected:
-  _NOINLINE_ MemRecorder();
-  ~MemRecorder();
-
-  // record a memory operation
-  bool record(address addr, MEMFLAGS flags, size_t size, jint seq, address caller_pc = 0);
-
-  // linked list support
-  inline void set_next(MemRecorder* rec) {
-    _next = rec;
-  }
-
-  inline MemRecorder* next() const {
-    return _next;
-  }
-
-  // if the recorder is full
-  inline bool is_full() const {
-    assert(_pointer_records != NULL, "just check");
-    return _pointer_records->is_full();
-  }
-
-  // if running out of memory when initializing recorder's internal
-  // data
-  inline bool out_of_memory() const {
-    return (_pointer_records == NULL ||
-      _pointer_records->out_of_memory());
-  }
-
-  inline void clear() {
-    assert(_pointer_records != NULL, "Just check");
-    _pointer_records->clear();
-  }
-
-  SequencedRecordIterator pointer_itr();
-
-  // return the generation of this recorder which it belongs to
-  unsigned long get_generation() const { return _generation; }
- protected:
-  // number of MemRecorder instance
-  static volatile jint _instance_count;
-
- private:
-  // sorting function, sort records into following order
-  // 1. memory address
-  // 2. allocation type
-  // 3. sequence number
-  static int sort_record_fn(const void* e1, const void* e2);
-
-  debug_only(void check_dup_seq(jint seq) const;)
-  void set_generation();
-};
-
-#endif // SHARE_VM_SERVICES_MEM_RECORDER_HPP
--- a/src/share/vm/services/memReporter.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/services/memReporter.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -22,618 +22,595 @@
  *
  */
 #include "precompiled.hpp"
-#include "classfile/systemDictionary.hpp"
-#include "runtime/os.hpp"
+
+#include "memory/allocation.hpp"
+#include "services/mallocTracker.hpp"
 #include "services/memReporter.hpp"
-#include "services/memPtrArray.hpp"
-#include "services/memTracker.hpp"
+#include "services/virtualMemoryTracker.hpp"
+#include "utilities/globalDefinitions.hpp"
+
+size_t MemReporterBase::reserved_total(const MallocMemory* malloc, const VirtualMemory* vm) const {
+  return malloc->malloc_size() + malloc->arena_size() + vm->reserved();
+}
+
+size_t MemReporterBase::committed_total(const MallocMemory* malloc, const VirtualMemory* vm) const {
+  return malloc->malloc_size() + malloc->arena_size() + vm->committed();
+}
 
-PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC
+void MemReporterBase::print_total(size_t reserved, size_t committed) const {
+  const char* scale = current_scale();
+  output()->print("reserved=" SIZE_FORMAT "%s, committed=" SIZE_FORMAT "%s",
+    amount_in_current_scale(reserved), scale, amount_in_current_scale(committed), scale);
+}
+
+void MemReporterBase::print_malloc(size_t amount, size_t count) const {
+  const char* scale = current_scale();
+  outputStream* out = output();
+  out->print("(malloc=" SIZE_FORMAT "%s",
+    amount_in_current_scale(amount), scale);
+
+  if (count > 0) {
+    out->print(" #" SIZE_FORMAT "", count);
+  }
 
-const char* BaselineOutputer::memory_unit(size_t scale) {
-  switch(scale) {
-    case K: return "KB";
-    case M: return "MB";
-    case G: return "GB";
-  }
-  ShouldNotReachHere();
-  return NULL;
+  out->print(")");
+}
+
+void MemReporterBase::print_virtual_memory(size_t reserved, size_t committed) const {
+  const char* scale = current_scale();
+  output()->print("(mmap: reserved=" SIZE_FORMAT "%s, committed=" SIZE_FORMAT "%s)",
+    amount_in_current_scale(reserved), scale, amount_in_current_scale(committed), scale);
+}
+
+void MemReporterBase::print_malloc_line(size_t amount, size_t count) const {
+  output()->print("%28s", " ");
+  print_malloc(amount, count);
+  output()->print_cr(" ");
+}
+
+void MemReporterBase::print_virtual_memory_line(size_t reserved, size_t committed) const {
+  output()->print("%28s", " ");
+  print_virtual_memory(reserved, committed);
+  output()->print_cr(" ");
+}
+
+void MemReporterBase::print_arena_line(size_t amount, size_t count) const {
+  const char* scale = current_scale();
+  output()->print_cr("%27s (arena=" SIZE_FORMAT "%s #" SIZE_FORMAT ")", " ",
+    amount_in_current_scale(amount), scale, count);
+}
+
+void MemReporterBase::print_virtual_memory_region(const char* type, address base, size_t size) const {
+  const char* scale = current_scale();
+  output()->print("[" PTR_FORMAT " - " PTR_FORMAT "] %s " SIZE_FORMAT "%s",
+    p2i(base), p2i(base + size), type, amount_in_current_scale(size), scale);
 }
 
 
-void BaselineReporter::report_baseline(const MemBaseline& baseline, bool summary_only) {
-  assert(MemTracker::is_on(), "Native memory tracking is off");
-  _outputer.start(scale());
-  _outputer.total_usage(
-    amount_in_current_scale(baseline.total_malloc_amount() + baseline.total_reserved_amount()),
-    amount_in_current_scale(baseline.total_malloc_amount() + baseline.total_committed_amount()));
-
-  _outputer.num_of_classes(baseline.number_of_classes());
-  _outputer.num_of_threads(baseline.number_of_threads());
-
-  report_summaries(baseline);
-  if (!summary_only && MemTracker::track_callsite()) {
-    report_virtual_memory_map(baseline);
-    report_callsites(baseline);
-  }
-  _outputer.done();
-}
-
-void BaselineReporter::report_summaries(const MemBaseline& baseline) {
-  _outputer.start_category_summary();
-  MEMFLAGS type;
+void MemSummaryReporter::report() {
+  const char* scale = current_scale();
+  outputStream* out = output();
+  size_t total_reserved_amount = _malloc_snapshot->total() +
+    _vm_snapshot->total_reserved();
+  size_t total_committed_amount = _malloc_snapshot->total() +
+    _vm_snapshot->total_committed();
 
-  for (int index = 0; index < NUMBER_OF_MEMORY_TYPE; index ++) {
-    type = MemBaseline::MemType2NameMap[index]._flag;
-    _outputer.category_summary(type,
-      amount_in_current_scale(baseline.reserved_amount(type)),
-      amount_in_current_scale(baseline.committed_amount(type)),
-      amount_in_current_scale(baseline.malloc_amount(type)),
-      baseline.malloc_count(type),
-      amount_in_current_scale(baseline.arena_amount(type)),
-      baseline.arena_count(type));
-  }
-
-  _outputer.done_category_summary();
-}
+  // Overall total
+  out->print_cr("\nNative Memory Tracking:\n");
+  out->print("Total: ");
+  print_total(total_reserved_amount, total_committed_amount);
+  out->print("\n");
 
-void BaselineReporter::report_virtual_memory_map(const MemBaseline& baseline) {
-  _outputer.start_virtual_memory_map();
-  MemBaseline* pBL = const_cast<MemBaseline*>(&baseline);
-  MemPointerArrayIteratorImpl itr = MemPointerArrayIteratorImpl(pBL->_vm_map);
-  VMMemRegionEx* rgn = (VMMemRegionEx*)itr.current();
-  while (rgn != NULL) {
-    if (rgn->is_reserved_region()) {
-      _outputer.reserved_memory_region(FLAGS_TO_MEMORY_TYPE(rgn->flags()),
-        rgn->base(), rgn->base() + rgn->size(), amount_in_current_scale(rgn->size()), rgn->pc());
-    } else {
-      _outputer.committed_memory_region(rgn->base(), rgn->base() + rgn->size(),
-        amount_in_current_scale(rgn->size()), rgn->pc());
-    }
-    rgn = (VMMemRegionEx*)itr.next();
+  // Summary by memory type
+  for (int index = 0; index < mt_number_of_types; index ++) {
+    MEMFLAGS flag = NMTUtil::index_to_flag(index);
+    // thread stack is reported as part of thread category
+    if (flag == mtThreadStack) continue;
+    MallocMemory* malloc_memory = _malloc_snapshot->by_type(flag);
+    VirtualMemory* virtual_memory = _vm_snapshot->by_type(flag);
+
+    report_summary_of_type(flag, malloc_memory, virtual_memory);
   }
-
-  _outputer.done_virtual_memory_map();
 }
 
-void BaselineReporter::report_callsites(const MemBaseline& baseline) {
-  _outputer.start_callsite();
-  MemBaseline* pBL = const_cast<MemBaseline*>(&baseline);
+void MemSummaryReporter::report_summary_of_type(MEMFLAGS flag,
+  MallocMemory*  malloc_memory, VirtualMemory* virtual_memory) {
 
-  pBL->_malloc_cs->sort((FN_SORT)MemBaseline::bl_malloc_sort_by_size);
-  pBL->_vm_cs->sort((FN_SORT)MemBaseline::bl_vm_sort_by_size);
+  size_t reserved_amount  = reserved_total (malloc_memory, virtual_memory);
+  size_t committed_amount = committed_total(malloc_memory, virtual_memory);
 
-  // walk malloc callsites
-  MemPointerArrayIteratorImpl malloc_itr(pBL->_malloc_cs);
-  MallocCallsitePointer*      malloc_callsite =
-                  (MallocCallsitePointer*)malloc_itr.current();
-  while (malloc_callsite != NULL) {
-    _outputer.malloc_callsite(malloc_callsite->addr(),
-        amount_in_current_scale(malloc_callsite->amount()), malloc_callsite->count());
-    malloc_callsite = (MallocCallsitePointer*)malloc_itr.next();
+  // Count thread's native stack in "Thread" category
+  if (flag == mtThread) {
+    const VirtualMemory* thread_stack_usage =
+      (const VirtualMemory*)_vm_snapshot->by_type(mtThreadStack);
+    reserved_amount  += thread_stack_usage->reserved();
+    committed_amount += thread_stack_usage->committed();
+  } else if (flag == mtNMT) {
+    // Count malloc headers in "NMT" category
+    reserved_amount  += _malloc_snapshot->malloc_overhead()->size();
+    committed_amount += _malloc_snapshot->malloc_overhead()->size();
   }
 
-  // walk virtual memory callsite
-  MemPointerArrayIteratorImpl vm_itr(pBL->_vm_cs);
-  VMCallsitePointer*          vm_callsite = (VMCallsitePointer*)vm_itr.current();
-  while (vm_callsite != NULL) {
-    _outputer.virtual_memory_callsite(vm_callsite->addr(),
-      amount_in_current_scale(vm_callsite->reserved_amount()),
-      amount_in_current_scale(vm_callsite->committed_amount()));
-    vm_callsite = (VMCallsitePointer*)vm_itr.next();
-  }
-  pBL->_malloc_cs->sort((FN_SORT)MemBaseline::bl_malloc_sort_by_pc);
-  pBL->_vm_cs->sort((FN_SORT)MemBaseline::bl_vm_sort_by_pc);
-  _outputer.done_callsite();
-}
+  if (amount_in_current_scale(reserved_amount) > 0) {
+    outputStream* out   = output();
+    const char*   scale = current_scale();
+    out->print("-%26s (", NMTUtil::flag_to_name(flag));
+    print_total(reserved_amount, committed_amount);
+    out->print_cr(")");
 
-void BaselineReporter::diff_baselines(const MemBaseline& cur, const MemBaseline& prev,
-  bool summary_only) {
-  assert(MemTracker::is_on(), "Native memory tracking is off");
-  _outputer.start(scale());
-  size_t total_reserved = cur.total_malloc_amount() + cur.total_reserved_amount();
-  size_t total_committed = cur.total_malloc_amount() + cur.total_committed_amount();
-
-  _outputer.diff_total_usage(
-    amount_in_current_scale(total_reserved), amount_in_current_scale(total_committed),
-    diff_in_current_scale(total_reserved,  (prev.total_malloc_amount() + prev.total_reserved_amount())),
-    diff_in_current_scale(total_committed, (prev.total_committed_amount() + prev.total_malloc_amount())));
+    if (flag == mtClass) {
+      // report class count
+      out->print_cr("%27s (classes #" SIZE_FORMAT ")", " ", _class_count);
+    } else if (flag == mtThread) {
+      // report thread count
+      out->print_cr("%27s (thread #" SIZE_FORMAT ")", " ", _malloc_snapshot->thread_count());
+      const VirtualMemory* thread_stack_usage =
+       _vm_snapshot->by_type(mtThreadStack);
+      out->print("%27s (stack: ", " ");
+      print_total(thread_stack_usage->reserved(), thread_stack_usage->committed());
+      out->print_cr(")");
+    }
 
-  _outputer.diff_num_of_classes(cur.number_of_classes(),
-       diff(cur.number_of_classes(), prev.number_of_classes()));
-  _outputer.diff_num_of_threads(cur.number_of_threads(),
-       diff(cur.number_of_threads(), prev.number_of_threads()));
+     // report malloc'd memory
+    if (amount_in_current_scale(malloc_memory->malloc_size()) > 0) {
+      // We don't know how many arena chunks are in used, so don't report the count
+      size_t count = (flag == mtChunk) ? 0 : malloc_memory->malloc_count();
+      print_malloc_line(malloc_memory->malloc_size(), count);
+    }
 
-  diff_summaries(cur, prev);
-  if (!summary_only && MemTracker::track_callsite()) {
-    diff_callsites(cur, prev);
-  }
-  _outputer.done();
-}
-
-void BaselineReporter::diff_summaries(const MemBaseline& cur, const MemBaseline& prev) {
-  _outputer.start_category_summary();
-  MEMFLAGS type;
+    if (amount_in_current_scale(virtual_memory->reserved()) > 0) {
+      print_virtual_memory_line(virtual_memory->reserved(), virtual_memory->committed());
+    }
 
-  for (int index = 0; index < NUMBER_OF_MEMORY_TYPE; index ++) {
-    type = MemBaseline::MemType2NameMap[index]._flag;
-    _outputer.diff_category_summary(type,
-      amount_in_current_scale(cur.reserved_amount(type)),
-      amount_in_current_scale(cur.committed_amount(type)),
-      amount_in_current_scale(cur.malloc_amount(type)),
-      cur.malloc_count(type),
-      amount_in_current_scale(cur.arena_amount(type)),
-      cur.arena_count(type),
-      diff_in_current_scale(cur.reserved_amount(type), prev.reserved_amount(type)),
-      diff_in_current_scale(cur.committed_amount(type), prev.committed_amount(type)),
-      diff_in_current_scale(cur.malloc_amount(type), prev.malloc_amount(type)),
-      diff(cur.malloc_count(type), prev.malloc_count(type)),
-      diff_in_current_scale(cur.arena_amount(type), prev.arena_amount(type)),
-      diff(cur.arena_count(type), prev.arena_count(type)));
+    if (amount_in_current_scale(malloc_memory->arena_size()) > 0) {
+      print_arena_line(malloc_memory->arena_size(), malloc_memory->arena_count());
+    }
+
+    if (flag == mtNMT &&
+      amount_in_current_scale(_malloc_snapshot->malloc_overhead()->size()) > 0) {
+      out->print_cr("%27s (tracking overhead=" SIZE_FORMAT "%s)", " ",
+        amount_in_current_scale(_malloc_snapshot->malloc_overhead()->size()), scale);
+    }
+
+    out->print_cr(" ");
   }
-
-  _outputer.done_category_summary();
 }
 
-void BaselineReporter::diff_callsites(const MemBaseline& cur, const MemBaseline& prev) {
-  _outputer.start_callsite();
-  MemBaseline* pBL_cur = const_cast<MemBaseline*>(&cur);
-  MemBaseline* pBL_prev = const_cast<MemBaseline*>(&prev);
+void MemDetailReporter::report_detail() {
+  // Start detail report
+  outputStream* out = output();
+  out->print_cr("Details:\n");
+
+  report_malloc_sites();
+  report_virtual_memory_allocation_sites();
+}
+
+void MemDetailReporter::report_malloc_sites() {
+  MallocSiteIterator         malloc_itr = _baseline.malloc_sites(MemBaseline::by_size);
+  if (malloc_itr.is_empty()) return;
+
+  outputStream* out = output();
 
-  // walk malloc callsites
-  MemPointerArrayIteratorImpl cur_malloc_itr(pBL_cur->_malloc_cs);
-  MemPointerArrayIteratorImpl prev_malloc_itr(pBL_prev->_malloc_cs);
+  const MallocSite* malloc_site;
+  while ((malloc_site = malloc_itr.next()) != NULL) {
+    // Don't report if size is too small
+    if (amount_in_current_scale(malloc_site->size()) == 0)
+      continue;
 
-  MallocCallsitePointer*      cur_malloc_callsite =
-                  (MallocCallsitePointer*)cur_malloc_itr.current();
-  MallocCallsitePointer*      prev_malloc_callsite =
-                  (MallocCallsitePointer*)prev_malloc_itr.current();
+    const NativeCallStack* stack = malloc_site->call_stack();
+    stack->print_on(out);
+    out->print("%29s", " ");
+    print_malloc(malloc_site->size(), malloc_site->count());
+    out->print_cr("\n");
+  }
+}
+
+void MemDetailReporter::report_virtual_memory_allocation_sites()  {
+  VirtualMemorySiteIterator  virtual_memory_itr =
+    _baseline.virtual_memory_sites(MemBaseline::by_size);
+
+  if (virtual_memory_itr.is_empty()) return;
+
+  outputStream* out = output();
+  const VirtualMemoryAllocationSite*  virtual_memory_site;
 
-  while (cur_malloc_callsite != NULL || prev_malloc_callsite != NULL) {
-    if (prev_malloc_callsite == NULL) {
-      assert(cur_malloc_callsite != NULL, "sanity check");
-      // this is a new callsite
-      _outputer.diff_malloc_callsite(cur_malloc_callsite->addr(),
-        amount_in_current_scale(cur_malloc_callsite->amount()),
-        cur_malloc_callsite->count(),
-        diff_in_current_scale(cur_malloc_callsite->amount(), 0),
-        diff(cur_malloc_callsite->count(), 0));
-      cur_malloc_callsite = (MallocCallsitePointer*)cur_malloc_itr.next();
-    } else if (cur_malloc_callsite == NULL) {
-      assert(prev_malloc_callsite != NULL, "Sanity check");
-      // this callsite is already gone
-      _outputer.diff_malloc_callsite(prev_malloc_callsite->addr(),
-        0, 0,
-        diff_in_current_scale(0, prev_malloc_callsite->amount()),
-        diff(0, prev_malloc_callsite->count()));
-      prev_malloc_callsite = (MallocCallsitePointer*)prev_malloc_itr.next();
-    } else {
-      assert(cur_malloc_callsite  != NULL,  "Sanity check");
-      assert(prev_malloc_callsite != NULL,  "Sanity check");
-      if (cur_malloc_callsite->addr() < prev_malloc_callsite->addr()) {
-        // this is a new callsite
-        _outputer.diff_malloc_callsite(cur_malloc_callsite->addr(),
-          amount_in_current_scale(cur_malloc_callsite->amount()),
-          cur_malloc_callsite->count(),
-          diff_in_current_scale(cur_malloc_callsite->amount(), 0),
-          diff(cur_malloc_callsite->count(), 0));
-          cur_malloc_callsite = (MallocCallsitePointer*)cur_malloc_itr.next();
-      } else if (cur_malloc_callsite->addr() > prev_malloc_callsite->addr()) {
-        // this callsite is already gone
-        _outputer.diff_malloc_callsite(prev_malloc_callsite->addr(),
-          0, 0,
-          diff_in_current_scale(0, prev_malloc_callsite->amount()),
-          diff(0, prev_malloc_callsite->count()));
-        prev_malloc_callsite = (MallocCallsitePointer*)prev_malloc_itr.next();
-      } else {
-        // the same callsite
-        _outputer.diff_malloc_callsite(cur_malloc_callsite->addr(),
-          amount_in_current_scale(cur_malloc_callsite->amount()),
-          cur_malloc_callsite->count(),
-          diff_in_current_scale(cur_malloc_callsite->amount(), prev_malloc_callsite->amount()),
-          diff(cur_malloc_callsite->count(), prev_malloc_callsite->count()));
-        cur_malloc_callsite = (MallocCallsitePointer*)cur_malloc_itr.next();
-        prev_malloc_callsite = (MallocCallsitePointer*)prev_malloc_itr.next();
-      }
-    }
+  while ((virtual_memory_site = virtual_memory_itr.next()) != NULL) {
+    // Don't report if size is too small
+    if (amount_in_current_scale(virtual_memory_site->reserved()) == 0)
+      continue;
+
+    const NativeCallStack* stack = virtual_memory_site->call_stack();
+    stack->print_on(out);
+    out->print("%28s (", " ");
+    print_total(virtual_memory_site->reserved(), virtual_memory_site->committed());
+    out->print_cr(")\n");
+  }
+}
+
+
+void MemDetailReporter::report_virtual_memory_map() {
+  // Virtual memory map always in base address order
+  VirtualMemoryAllocationIterator itr = _baseline.virtual_memory_allocations();
+  const ReservedMemoryRegion* rgn;
+
+  output()->print_cr("Virtual memory map:");
+  while ((rgn = itr.next()) != NULL) {
+    report_virtual_memory_region(rgn);
+  }
+}
+
+void MemDetailReporter::report_virtual_memory_region(const ReservedMemoryRegion* reserved_rgn) {
+  assert(reserved_rgn != NULL, "NULL pointer");
+
+  // Don't report if size is too small
+  if (amount_in_current_scale(reserved_rgn->size()) == 0) return;
+
+  outputStream* out = output();
+  const char* scale = current_scale();
+  const NativeCallStack*  stack = reserved_rgn->call_stack();
+  bool all_committed = reserved_rgn->all_committed();
+  const char* region_type = (all_committed ? "reserved and committed" : "reserved");
+  out->print_cr(" ");
+  print_virtual_memory_region(region_type, reserved_rgn->base(), reserved_rgn->size());
+  out->print(" for %s", NMTUtil::flag_to_name(reserved_rgn->flag()));
+  if (stack->is_empty()) {
+    out->print_cr(" ");
+  } else {
+    out->print_cr(" from");
+    stack->print_on(out, 4);
   }
 
-  // walk virtual memory callsite
-  MemPointerArrayIteratorImpl cur_vm_itr(pBL_cur->_vm_cs);
-  MemPointerArrayIteratorImpl prev_vm_itr(pBL_prev->_vm_cs);
-  VMCallsitePointer*          cur_vm_callsite = (VMCallsitePointer*)cur_vm_itr.current();
-  VMCallsitePointer*          prev_vm_callsite = (VMCallsitePointer*)prev_vm_itr.current();
-  while (cur_vm_callsite != NULL || prev_vm_callsite != NULL) {
-    if (prev_vm_callsite == NULL || cur_vm_callsite->addr() < prev_vm_callsite->addr()) {
-      // this is a new callsite
-      _outputer.diff_virtual_memory_callsite(cur_vm_callsite->addr(),
-        amount_in_current_scale(cur_vm_callsite->reserved_amount()),
-        amount_in_current_scale(cur_vm_callsite->committed_amount()),
-        diff_in_current_scale(cur_vm_callsite->reserved_amount(), 0),
-        diff_in_current_scale(cur_vm_callsite->committed_amount(), 0));
-      cur_vm_callsite = (VMCallsitePointer*)cur_vm_itr.next();
-    } else if (cur_vm_callsite == NULL || cur_vm_callsite->addr() > prev_vm_callsite->addr()) {
-      // this callsite is already gone
-      _outputer.diff_virtual_memory_callsite(prev_vm_callsite->addr(),
-        amount_in_current_scale(0),
-        amount_in_current_scale(0),
-        diff_in_current_scale(0, prev_vm_callsite->reserved_amount()),
-        diff_in_current_scale(0, prev_vm_callsite->committed_amount()));
-      prev_vm_callsite = (VMCallsitePointer*)prev_vm_itr.next();
-    } else { // the same callsite
-      _outputer.diff_virtual_memory_callsite(cur_vm_callsite->addr(),
-        amount_in_current_scale(cur_vm_callsite->reserved_amount()),
-        amount_in_current_scale(cur_vm_callsite->committed_amount()),
-        diff_in_current_scale(cur_vm_callsite->reserved_amount(), prev_vm_callsite->reserved_amount()),
-        diff_in_current_scale(cur_vm_callsite->committed_amount(), prev_vm_callsite->committed_amount()));
-      cur_vm_callsite  = (VMCallsitePointer*)cur_vm_itr.next();
-      prev_vm_callsite = (VMCallsitePointer*)prev_vm_itr.next();
-    }
-  }
-
-  _outputer.done_callsite();
-}
-
-size_t BaselineReporter::amount_in_current_scale(size_t amt) const {
-  return (size_t)(((float)amt/(float)_scale) + 0.5);
-}
-
-int BaselineReporter::diff_in_current_scale(size_t value1, size_t value2) const {
-  return (int)(((float)value1 - (float)value2)/((float)_scale) + 0.5);
-}
-
-int BaselineReporter::diff(size_t value1, size_t value2) const {
-  return ((int)value1 - (int)value2);
-}
-
-void BaselineTTYOutputer::start(size_t scale, bool report_diff) {
-  _scale = scale;
-  _output->print_cr(" ");
-  _output->print_cr("Native Memory Tracking:");
-  _output->print_cr(" ");
-}
-
-void BaselineTTYOutputer::done() {
-
-}
+  if (all_committed) return;
 
-void BaselineTTYOutputer::total_usage(size_t total_reserved, size_t total_committed) {
-  const char* unit = memory_unit(_scale);
-  _output->print_cr("Total:  reserved=%d%s,  committed=%d%s",
-    total_reserved, unit, total_committed, unit);
-}
-
-void BaselineTTYOutputer::start_category_summary() {
-  _output->print_cr(" ");
-}
-
-/**
- * report a summary of memory type
- */
-void BaselineTTYOutputer::category_summary(MEMFLAGS type,
-  size_t reserved_amt, size_t committed_amt, size_t malloc_amt,
-  size_t malloc_count, size_t arena_amt, size_t arena_count) {
-
-  // we report mtThreadStack under mtThread category
-  if (type == mtThreadStack) {
-    assert(malloc_amt == 0 && malloc_count == 0 && arena_amt == 0,
-      "Just check");
-    _thread_stack_reserved = reserved_amt;
-    _thread_stack_committed = committed_amt;
-  } else {
-    const char* unit = memory_unit(_scale);
-    size_t total_reserved = (reserved_amt + malloc_amt + arena_amt);
-    size_t total_committed = (committed_amt + malloc_amt + arena_amt);
-    if (type == mtThread) {
-      total_reserved += _thread_stack_reserved;
-      total_committed += _thread_stack_committed;
-    }
-
-    if (total_reserved > 0) {
-      _output->print_cr("-%26s (reserved=%d%s, committed=%d%s)",
-        MemBaseline::type2name(type), total_reserved, unit,
-        total_committed, unit);
-
-      if (type == mtClass) {
-        _output->print_cr("%27s (classes #%d)", " ", _num_of_classes);
-      } else if (type == mtThread) {
-        _output->print_cr("%27s (thread #%d)", " ", _num_of_threads);
-        _output->print_cr("%27s (stack: reserved=%d%s, committed=%d%s)", " ",
-          _thread_stack_reserved, unit, _thread_stack_committed, unit);
-      }
-
-      if (malloc_amt > 0) {
-        if (type != mtChunk) {
-          _output->print_cr("%27s (malloc=%d%s, #%d)", " ", malloc_amt, unit,
-            malloc_count);
-        } else {
-          _output->print_cr("%27s (malloc=%d%s)", " ", malloc_amt, unit);
-        }
-      }
-
-      if (reserved_amt > 0) {
-        _output->print_cr("%27s (mmap: reserved=%d%s, committed=%d%s)",
-          " ", reserved_amt, unit, committed_amt, unit);
-      }
-
-      if (arena_amt > 0) {
-        _output->print_cr("%27s (arena=%d%s, #%d)", " ", arena_amt, unit, arena_count);
-      }
-
-      _output->print_cr(" ");
+  CommittedRegionIterator itr = reserved_rgn->iterate_committed_regions();
+  const CommittedMemoryRegion* committed_rgn;
+  while ((committed_rgn = itr.next()) != NULL) {
+    // Don't report if size is too small
+    if (amount_in_current_scale(committed_rgn->size()) == 0) continue;
+    stack = committed_rgn->call_stack();
+    out->print("\n\t");
+    print_virtual_memory_region("committed", committed_rgn->base(), committed_rgn->size());
+    if (stack->is_empty()) {
+      out->print_cr(" ");
+    } else {
+      out->print_cr(" from");
+      stack->print_on(out, 12);
     }
   }
 }
 
-void BaselineTTYOutputer::done_category_summary() {
-  _output->print_cr(" ");
-}
+void MemSummaryDiffReporter::report_diff() {
+  const char* scale = current_scale();
+  outputStream* out = output();
+  out->print_cr("\nNative Memory Tracking:\n");
 
-
-void BaselineTTYOutputer::start_virtual_memory_map() {
-  _output->print_cr("Virtual memory map:");
-}
+  // Overall diff
+  out->print("Total: ");
+  print_virtual_memory_diff(_current_baseline.total_reserved_memory(),
+    _current_baseline.total_committed_memory(), _early_baseline.total_reserved_memory(),
+    _early_baseline.total_committed_memory());
 
-void BaselineTTYOutputer::reserved_memory_region(MEMFLAGS type, address base, address end,
-                                                 size_t size, address pc) {
-  const char* unit = memory_unit(_scale);
-  char buf[128];
-  int  offset;
-  _output->print_cr(" ");
-  _output->print_cr("[" PTR_FORMAT " - " PTR_FORMAT "] reserved %d%s for %s", base, end, size, unit,
-            MemBaseline::type2name(type));
-  if (os::dll_address_to_function_name(pc, buf, sizeof(buf), &offset)) {
-      _output->print_cr("\t\tfrom [%s+0x%x]", buf, offset);
-  }
-}
+  out->print_cr("\n");
 
-void BaselineTTYOutputer::committed_memory_region(address base, address end, size_t size, address pc) {
-  const char* unit = memory_unit(_scale);
-  char buf[128];
-  int  offset;
-  _output->print("\t[" PTR_FORMAT " - " PTR_FORMAT "] committed %d%s", base, end, size, unit);
-  if (os::dll_address_to_function_name(pc, buf, sizeof(buf), &offset)) {
-      _output->print_cr(" from [%s+0x%x]", buf, offset);
+  // Summary diff by memory type
+  for (int index = 0; index < mt_number_of_types; index ++) {
+    MEMFLAGS flag = NMTUtil::index_to_flag(index);
+    // thread stack is reported as part of thread category
+    if (flag == mtThreadStack) continue;
+    diff_summary_of_type(flag, _early_baseline.malloc_memory(flag),
+      _early_baseline.virtual_memory(flag), _current_baseline.malloc_memory(flag),
+      _current_baseline.virtual_memory(flag));
   }
 }
 
-void BaselineTTYOutputer::done_virtual_memory_map() {
-  _output->print_cr(" ");
-}
-
-
-
-void BaselineTTYOutputer::start_callsite() {
-  _output->print_cr("Details:");
-  _output->print_cr(" ");
-}
-
-void BaselineTTYOutputer::done_callsite() {
-  _output->print_cr(" ");
-}
+void MemSummaryDiffReporter::print_malloc_diff(size_t current_amount, size_t current_count,
+    size_t early_amount, size_t early_count) const {
+  const char* scale = current_scale();
+  outputStream* out = output();
 
-void BaselineTTYOutputer::malloc_callsite(address pc, size_t malloc_amt,
-  size_t malloc_count) {
-  if (malloc_amt > 0) {
-    const char* unit = memory_unit(_scale);
-    char buf[128];
-    int  offset;
-    if (pc == 0) {
-      _output->print("[BOOTSTRAP]%18s", " ");
-    } else if (os::dll_address_to_function_name(pc, buf, sizeof(buf), &offset)) {
-      _output->print_cr("[" PTR_FORMAT "] %s+0x%x", pc, buf, offset);
-      _output->print("%28s", " ");
-    } else {
-      _output->print("[" PTR_FORMAT "]%18s", pc, " ");
+  out->print("malloc=" SIZE_FORMAT "%s", amount_in_current_scale(current_amount), scale);
+  long amount_diff = diff_in_current_scale(current_amount, early_amount);
+  if (amount_diff != 0) {
+    out->print(" %+ld%s", amount_diff, scale);
+  }
+  if (current_count > 0) {
+    out->print(" #" SIZE_FORMAT "", current_count);
+    if (current_count != early_count) {
+      out->print(" %+d", (int)(current_count - early_count));
     }
-
-    _output->print_cr("(malloc=%d%s #%d)", malloc_amt, unit, malloc_count);
-    _output->print_cr(" ");
   }
 }
 
-void BaselineTTYOutputer::virtual_memory_callsite(address pc, size_t reserved_amt,
-  size_t committed_amt) {
-  if (reserved_amt > 0) {
-    const char* unit = memory_unit(_scale);
-    char buf[128];
-    int  offset;
-    if (pc == 0) {
-      _output->print("[BOOTSTRAP]%18s", " ");
-    } else if (os::dll_address_to_function_name(pc, buf, sizeof(buf), &offset)) {
-      _output->print_cr("[" PTR_FORMAT "] %s+0x%x", pc, buf, offset);
-      _output->print("%28s", " ");
-    } else {
-      _output->print("[" PTR_FORMAT "]%18s", pc, " ");
-    }
+void MemSummaryDiffReporter::print_arena_diff(size_t current_amount, size_t current_count,
+  size_t early_amount, size_t early_count) const {
+  const char* scale = current_scale();
+  outputStream* out = output();
+  out->print("arena=" SIZE_FORMAT "%s", amount_in_current_scale(current_amount), scale);
+  if (diff_in_current_scale(current_amount, early_amount) != 0) {
+    out->print(" %+ld", diff_in_current_scale(current_amount, early_amount));
+  }
+
+  out->print(" #" SIZE_FORMAT "", current_count);
+  if (current_count != early_count) {
+    out->print(" %+d", (int)(current_count - early_count));
+  }
+}
 
-    _output->print_cr("(mmap: reserved=%d%s, committed=%d%s)",
-      reserved_amt, unit, committed_amt, unit);
-    _output->print_cr(" ");
+void MemSummaryDiffReporter::print_virtual_memory_diff(size_t current_reserved, size_t current_committed,
+    size_t early_reserved, size_t early_committed) const {
+  const char* scale = current_scale();
+  outputStream* out = output();
+  out->print("reserved=" SIZE_FORMAT "%s", amount_in_current_scale(current_reserved), scale);
+  long reserved_diff = diff_in_current_scale(current_reserved, early_reserved);
+  if (reserved_diff != 0) {
+    out->print(" %+ld%s", reserved_diff, scale);
+  }
+
+  out->print(", committed=" SIZE_FORMAT "%s", amount_in_current_scale(current_committed), scale);
+  long committed_diff = diff_in_current_scale(current_committed, early_committed);
+  if (committed_diff != 0) {
+    out->print(" %+ld%s", committed_diff, scale);
   }
 }
 
-void BaselineTTYOutputer::diff_total_usage(size_t total_reserved,
-  size_t total_committed, int reserved_diff, int committed_diff) {
-  const char* unit = memory_unit(_scale);
-  _output->print_cr("Total:  reserved=%d%s  %+d%s, committed=%d%s %+d%s",
-    total_reserved, unit, reserved_diff, unit, total_committed, unit,
-    committed_diff, unit);
-}
+
+void MemSummaryDiffReporter::diff_summary_of_type(MEMFLAGS flag, const MallocMemory* early_malloc,
+  const VirtualMemory* early_vm, const MallocMemory* current_malloc,
+  const VirtualMemory* current_vm) const {
+
+  outputStream* out = output();
+  const char* scale = current_scale();
+
+  // Total reserved and committed memory in current baseline
+  size_t current_reserved_amount  = reserved_total (current_malloc, current_vm);
+  size_t current_committed_amount = committed_total(current_malloc, current_vm);
+
+  // Total reserved and committed memory in early baseline
+  size_t early_reserved_amount  = reserved_total(early_malloc, early_vm);
+  size_t early_committed_amount = committed_total(early_malloc, early_vm);
 
-void BaselineTTYOutputer::diff_category_summary(MEMFLAGS type,
-  size_t cur_reserved_amt, size_t cur_committed_amt,
-  size_t cur_malloc_amt, size_t cur_malloc_count,
-  size_t cur_arena_amt, size_t cur_arena_count,
-  int reserved_diff, int committed_diff, int malloc_diff,
-  int malloc_count_diff, int arena_diff, int arena_count_diff) {
+  // Adjust virtual memory total
+  if (flag == mtThread) {
+    const VirtualMemory* early_thread_stack_usage =
+      _early_baseline.virtual_memory(mtThreadStack);
+    const VirtualMemory* current_thread_stack_usage =
+      _current_baseline.virtual_memory(mtThreadStack);
+
+    early_reserved_amount  += early_thread_stack_usage->reserved();
+    early_committed_amount += early_thread_stack_usage->committed();
+
+    current_reserved_amount  += current_thread_stack_usage->reserved();
+    current_committed_amount += current_thread_stack_usage->committed();
+  } else if (flag == mtNMT) {
+    early_reserved_amount  += _early_baseline.malloc_tracking_overhead();
+    early_committed_amount += _early_baseline.malloc_tracking_overhead();
+
+    current_reserved_amount  += _current_baseline.malloc_tracking_overhead();
+    current_committed_amount += _current_baseline.malloc_tracking_overhead();
+  }
 
-  if (type == mtThreadStack) {
-    assert(cur_malloc_amt == 0 && cur_malloc_count == 0 &&
-      cur_arena_amt == 0, "Just check");
-    _thread_stack_reserved = cur_reserved_amt;
-    _thread_stack_committed = cur_committed_amt;
-    _thread_stack_reserved_diff = reserved_diff;
-    _thread_stack_committed_diff = committed_diff;
-  } else {
-    const char* unit = memory_unit(_scale);
-    size_t total_reserved = (cur_reserved_amt + cur_malloc_amt + cur_arena_amt);
-    // nothing to report in this category
-    if (total_reserved == 0) {
-      return;
-    }
-    int    diff_reserved = (reserved_diff + malloc_diff + arena_diff);
+  if (amount_in_current_scale(current_reserved_amount) > 0 ||
+      diff_in_current_scale(current_reserved_amount, early_reserved_amount) != 0) {
+
+    // print summary line
+    out->print("-%26s (", NMTUtil::flag_to_name(flag));
+    print_virtual_memory_diff(current_reserved_amount, current_committed_amount,
+      early_reserved_amount, early_committed_amount);
+    out->print_cr(")");
 
-    // category summary
-    _output->print("-%26s (reserved=%d%s", MemBaseline::type2name(type),
-      total_reserved, unit);
+    // detail lines
+    if (flag == mtClass) {
+      // report class count
+      out->print("%27s (classes #" SIZE_FORMAT "", " ", _current_baseline.class_count());
+      int class_count_diff = (int)(_current_baseline.class_count() -
+        _early_baseline.class_count());
+      if (_current_baseline.class_count() != _early_baseline.class_count()) {
+        out->print(" %+d", (int)(_current_baseline.class_count() - _early_baseline.class_count()));
+      }
+      out->print_cr(")");
+    } else if (flag == mtThread) {
+      // report thread count
+      out->print("%27s (thread #" SIZE_FORMAT "", " ", _current_baseline.thread_count());
+      int thread_count_diff = (int)(_current_baseline.thread_count() -
+          _early_baseline.thread_count());
+      if (thread_count_diff != 0) {
+        out->print(" %+d", thread_count_diff);
+      }
+      out->print_cr(")");
 
-    if (diff_reserved != 0) {
-      _output->print(" %+d%s", diff_reserved, unit);
-    }
+      // report thread stack
+      const VirtualMemory* current_thread_stack =
+          _current_baseline.virtual_memory(mtThreadStack);
+      const VirtualMemory* early_thread_stack =
+        _early_baseline.virtual_memory(mtThreadStack);
 
-    size_t total_committed = cur_committed_amt + cur_malloc_amt + cur_arena_amt;
-    _output->print(", committed=%d%s", total_committed, unit);
-
-    int total_committed_diff = committed_diff + malloc_diff + arena_diff;
-    if (total_committed_diff != 0) {
-      _output->print(" %+d%s", total_committed_diff, unit);
+      out->print("%27s (stack: ", " ");
+      print_virtual_memory_diff(current_thread_stack->reserved(), current_thread_stack->committed(),
+        early_thread_stack->reserved(), early_thread_stack->committed());
+      out->print_cr(")");
     }
 
-    _output->print_cr(")");
+    // Report malloc'd memory
+    size_t current_malloc_amount = current_malloc->malloc_size();
+    size_t early_malloc_amount   = early_malloc->malloc_size();
+    if (amount_in_current_scale(current_malloc_amount) > 0 ||
+        diff_in_current_scale(current_malloc_amount, early_malloc_amount) != 0) {
+      out->print("%28s(", " ");
+      print_malloc_diff(current_malloc_amount, (flag == mtChunk) ? 0 : current_malloc->malloc_count(),
+        early_malloc_amount, early_malloc->malloc_count());
+      out->print_cr(")");
+    }
 
-    // special cases
-    if (type == mtClass) {
-      _output->print("%27s (classes #%d", " ", _num_of_classes);
-      if (_num_of_classes_diff != 0) {
-        _output->print(" %+d", _num_of_classes_diff);
-      }
-      _output->print_cr(")");
-    } else if (type == mtThread) {
-      // thread count
-      _output->print("%27s (thread #%d", " ", _num_of_threads);
-      if (_num_of_threads_diff != 0) {
-        _output->print_cr(" %+d)", _num_of_threads_diff);
-      } else {
-        _output->print_cr(")");
-      }
-      _output->print("%27s (stack: reserved=%d%s", " ", _thread_stack_reserved, unit);
-      if (_thread_stack_reserved_diff != 0) {
-        _output->print(" %+d%s", _thread_stack_reserved_diff, unit);
-      }
-
-      _output->print(", committed=%d%s", _thread_stack_committed, unit);
-      if (_thread_stack_committed_diff != 0) {
-        _output->print(" %+d%s",_thread_stack_committed_diff, unit);
-      }
-
-      _output->print_cr(")");
+    // Report virtual memory
+    if (amount_in_current_scale(current_vm->reserved()) > 0 ||
+        diff_in_current_scale(current_vm->reserved(), early_vm->reserved()) != 0) {
+      out->print("%27s (mmap: ", " ");
+      print_virtual_memory_diff(current_vm->reserved(), current_vm->committed(),
+        early_vm->reserved(), early_vm->committed());
+      out->print_cr(")");
     }
 
-    // malloc'd memory
-    if (cur_malloc_amt > 0) {
-      _output->print("%27s (malloc=%d%s", " ", cur_malloc_amt, unit);
-      if (malloc_diff != 0) {
-        _output->print(" %+d%s", malloc_diff, unit);
-      }
-      if (type != mtChunk) {
-        _output->print(", #%d", cur_malloc_count);
-        if (malloc_count_diff) {
-          _output->print(" %+d", malloc_count_diff);
-        }
-      }
-      _output->print_cr(")");
+    // Report arena memory
+    if (amount_in_current_scale(current_malloc->arena_size()) > 0 ||
+        diff_in_current_scale(current_malloc->arena_size(), early_malloc->arena_size()) != 0) {
+      out->print("%28s(", " ");
+      print_arena_diff(current_malloc->arena_size(), current_malloc->arena_count(),
+        early_malloc->arena_size(), early_malloc->arena_count());
+      out->print_cr(")");
     }
 
-    // mmap'd memory
-    if (cur_reserved_amt > 0) {
-      _output->print("%27s (mmap: reserved=%d%s", " ", cur_reserved_amt, unit);
-      if (reserved_diff != 0) {
-        _output->print(" %+d%s", reserved_diff, unit);
-      }
+    // Report native memory tracking overhead
+    if (flag == mtNMT) {
+      size_t current_tracking_overhead = amount_in_current_scale(_current_baseline.malloc_tracking_overhead());
+      size_t early_tracking_overhead   = amount_in_current_scale(_early_baseline.malloc_tracking_overhead());
 
-      _output->print(", committed=%d%s", cur_committed_amt, unit);
-      if (committed_diff != 0) {
-        _output->print(" %+d%s", committed_diff, unit);
-      }
-      _output->print_cr(")");
-    }
+      out->print("%27s (tracking overhead=" SIZE_FORMAT "%s", " ",
+        amount_in_current_scale(_current_baseline.malloc_tracking_overhead()), scale);
 
-    // arena memory
-    if (cur_arena_amt > 0) {
-      _output->print("%27s (arena=%d%s", " ", cur_arena_amt, unit);
-      if (arena_diff != 0) {
-        _output->print(" %+d%s", arena_diff, unit);
+      long overhead_diff = diff_in_current_scale(_current_baseline.malloc_tracking_overhead(),
+           _early_baseline.malloc_tracking_overhead());
+      if (overhead_diff != 0) {
+        out->print(" %+ld%s", overhead_diff, scale);
       }
-      _output->print(", #%d", cur_arena_count);
-      if (arena_count_diff != 0) {
-        _output->print(" %+d", arena_count_diff);
-      }
-      _output->print_cr(")");
+      out->print_cr(")");
     }
-
-    _output->print_cr(" ");
+    out->print_cr(" ");
   }
 }
 
-void BaselineTTYOutputer::diff_malloc_callsite(address pc,
-    size_t cur_malloc_amt, size_t cur_malloc_count,
-    int malloc_diff, int malloc_count_diff) {
-  if (malloc_diff != 0) {
-    const char* unit = memory_unit(_scale);
-    char buf[128];
-    int  offset;
-    if (pc == 0) {
-      _output->print_cr("[BOOTSTRAP]%18s", " ");
+void MemDetailDiffReporter::report_diff() {
+  MemSummaryDiffReporter::report_diff();
+  diff_malloc_sites();
+  diff_virtual_memory_sites();
+}
+
+void MemDetailDiffReporter::diff_malloc_sites() const {
+  MallocSiteIterator early_itr = _early_baseline.malloc_sites(MemBaseline::by_site);
+  MallocSiteIterator current_itr = _current_baseline.malloc_sites(MemBaseline::by_site);
+
+  const MallocSite* early_site   = early_itr.next();
+  const MallocSite* current_site = current_itr.next();
+
+  while (early_site != NULL || current_site != NULL) {
+    if (early_site == NULL) {
+      new_malloc_site(current_site);
+      current_site = current_itr.next();
+    } else if (current_site == NULL) {
+      old_malloc_site(early_site);
+      early_site = early_itr.next();
     } else {
-      if (os::dll_address_to_function_name(pc, buf, sizeof(buf), &offset)) {
-        _output->print_cr("[" PTR_FORMAT "] %s+0x%x", pc, buf, offset);
-        _output->print("%28s", " ");
+      int compVal = current_site->call_stack()->compare(*early_site->call_stack());
+      if (compVal < 0) {
+        new_malloc_site(current_site);
+        current_site = current_itr.next();
+      } else if (compVal > 0) {
+        old_malloc_site(early_site);
+        early_site = early_itr.next();
       } else {
-        _output->print("[" PTR_FORMAT "]%18s", pc, " ");
+        diff_malloc_site(early_site, current_site);
+        early_site   = early_itr.next();
+        current_site = current_itr.next();
       }
     }
+  }
+}
 
-    _output->print("(malloc=%d%s", cur_malloc_amt, unit);
-    if (malloc_diff != 0) {
-      _output->print(" %+d%s", malloc_diff, unit);
+void MemDetailDiffReporter::diff_virtual_memory_sites() const {
+  VirtualMemorySiteIterator early_itr = _early_baseline.virtual_memory_sites(MemBaseline::by_site);
+  VirtualMemorySiteIterator current_itr = _current_baseline.virtual_memory_sites(MemBaseline::by_site);
+
+  const VirtualMemoryAllocationSite* early_site   = early_itr.next();
+  const VirtualMemoryAllocationSite* current_site = current_itr.next();
+
+  while (early_site != NULL || current_site != NULL) {
+    if (early_site == NULL) {
+      new_virtual_memory_site(current_site);
+      current_site = current_itr.next();
+    } else if (current_site == NULL) {
+      old_virtual_memory_site(early_site);
+      early_site = early_itr.next();
+    } else {
+      int compVal = current_site->call_stack()->compare(*early_site->call_stack());
+      if (compVal < 0) {
+        new_virtual_memory_site(current_site);
+        current_site = current_itr.next();
+      } else if (compVal > 0) {
+        old_virtual_memory_site(early_site);
+        early_site = early_itr.next();
+      } else {
+        diff_virtual_memory_site(early_site, current_site);
+        early_site   = early_itr.next();
+        current_site = current_itr.next();
+      }
     }
-    _output->print(", #%d", cur_malloc_count);
-    if (malloc_count_diff != 0) {
-      _output->print(" %+d", malloc_count_diff);
-    }
-    _output->print_cr(")");
-    _output->print_cr(" ");
   }
 }
 
-void BaselineTTYOutputer::diff_virtual_memory_callsite(address pc,
-    size_t cur_reserved_amt, size_t cur_committed_amt,
-    int reserved_diff, int committed_diff) {
-  if (reserved_diff != 0 || committed_diff != 0) {
-    const char* unit = memory_unit(_scale);
-    char buf[64];
-    int  offset;
-    if (pc == 0) {
-      _output->print_cr("[BOOSTRAP]%18s", " ");
-    } else {
-      if (os::dll_address_to_function_name(pc, buf, sizeof(buf), &offset)) {
-        _output->print_cr("[" PTR_FORMAT "] %s+0x%x", pc, buf, offset);
-        _output->print("%28s", " ");
-      } else {
-        _output->print("[" PTR_FORMAT "]%18s", pc, " ");
-      }
-    }
+
+void MemDetailDiffReporter::new_malloc_site(const MallocSite* malloc_site) const {
+  diff_malloc_site(malloc_site->call_stack(), malloc_site->size(), malloc_site->count(),
+    0, 0);
+}
+
+void MemDetailDiffReporter::old_malloc_site(const MallocSite* malloc_site) const {
+  diff_malloc_site(malloc_site->call_stack(), 0, 0, malloc_site->size(),
+    malloc_site->count());
+}
+
+void MemDetailDiffReporter::diff_malloc_site(const MallocSite* early,
+  const MallocSite* current)  const {
+  diff_malloc_site(current->call_stack(), current->size(), current->count(),
+    early->size(), early->count());
+}
+
+void MemDetailDiffReporter::diff_malloc_site(const NativeCallStack* stack, size_t current_size,
+  size_t current_count, size_t early_size, size_t early_count) const {
+  outputStream* out = output();
+
+  assert(stack != NULL, "NULL stack");
+
+  if (diff_in_current_scale(current_size, early_size) == 0) {
+      return;
+  }
+
+  stack->print_on(out);
+  out->print("%28s (", " ");
+  print_malloc_diff(current_size, current_count,
+    early_size, early_count);
 
-    _output->print("(mmap: reserved=%d%s", cur_reserved_amt, unit);
-    if (reserved_diff != 0) {
-      _output->print(" %+d%s", reserved_diff, unit);
-    }
-    _output->print(", committed=%d%s", cur_committed_amt, unit);
-    if (committed_diff != 0) {
-      _output->print(" %+d%s", committed_diff, unit);
-    }
-    _output->print_cr(")");
-    _output->print_cr(" ");
+  out->print_cr(")\n");
+}
+
+
+void MemDetailDiffReporter::new_virtual_memory_site(const VirtualMemoryAllocationSite* site) const {
+  diff_virtual_memory_site(site->call_stack(), site->reserved(), site->committed(), 0, 0);
+}
+
+void MemDetailDiffReporter::old_virtual_memory_site(const VirtualMemoryAllocationSite* site) const {
+  diff_virtual_memory_site(site->call_stack(), 0, 0, site->reserved(), site->committed());
+}
+
+void MemDetailDiffReporter::diff_virtual_memory_site(const VirtualMemoryAllocationSite* early,
+  const VirtualMemoryAllocationSite* current) const {
+  diff_virtual_memory_site(current->call_stack(), current->reserved(), current->committed(),
+    early->reserved(), early->committed());
+}
+
+void MemDetailDiffReporter::diff_virtual_memory_site(const NativeCallStack* stack, size_t current_reserved,
+  size_t current_committed, size_t early_reserved, size_t early_committed) const  {
+  outputStream* out = output();
+
+  // no change
+  if (diff_in_current_scale(current_reserved, early_reserved) == 0 &&
+      diff_in_current_scale(current_committed, early_committed) == 0) {
+    return;
   }
-}
+
+  stack->print_on(out);
+  out->print("%28s (mmap: ", " ");
+  print_virtual_memory_diff(current_reserved, current_committed,
+    early_reserved, early_committed);
+
+  out->print_cr(")\n");
+ }
+
--- a/src/share/vm/services/memReporter.hpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/services/memReporter.hpp	Fri Sep 05 06:26:44 2014 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 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
@@ -25,262 +25,217 @@
 #ifndef SHARE_VM_SERVICES_MEM_REPORTER_HPP
 #define SHARE_VM_SERVICES_MEM_REPORTER_HPP
 
-#include "runtime/mutexLocker.hpp"
+#if INCLUDE_NMT
+
+#include "oops/instanceKlass.hpp"
 #include "services/memBaseline.hpp"
-#include "services/memTracker.hpp"
-#include "utilities/ostream.hpp"
-#include "utilities/macros.hpp"
-
-#if INCLUDE_NMT
+#include "services/nmtCommon.hpp"
+#include "services/mallocTracker.hpp"
+#include "services/virtualMemoryTracker.hpp"
 
 /*
- * MemBaselineReporter reports data to this outputer class,
- * ReportOutputer is responsible for format, store and redirect
- * the data to the final destination.
- */
-class BaselineOutputer : public StackObj {
+ * Base class that provides helpers
+*/
+class MemReporterBase : public StackObj {
+ private:
+  size_t        _scale;  // report in this scale
+  outputStream* _output; // destination
+
  public:
-  // start to report memory usage in specified scale.
-  // if report_diff = true, the reporter reports baseline comparison
-  // information.
-
-  virtual void start(size_t scale, bool report_diff = false) = 0;
-  // Done reporting
-  virtual void done() = 0;
+  MemReporterBase(outputStream* out = NULL, size_t scale = K)
+    : _scale(scale) {
+    _output = (out == NULL) ? tty : out;
+  }
 
-  /* report baseline summary information */
-  virtual void total_usage(size_t total_reserved,
-                           size_t total_committed) = 0;
-  virtual void num_of_classes(size_t classes) = 0;
-  virtual void num_of_threads(size_t threads) = 0;
-
-  virtual void thread_info(size_t stack_reserved_amt, size_t stack_committed_amt) = 0;
+ protected:
+  inline outputStream* output() const {
+    return _output;
+  }
+  // Current reporting scale
+  inline const char* current_scale() const {
+    return NMTUtil::scale_name(_scale);
+  }
+  // Convert memory amount in bytes to current reporting scale
+  inline size_t amount_in_current_scale(size_t amount) const {
+    return NMTUtil::amount_in_scale(amount, _scale);
+  }
 
-  /* report baseline summary comparison */
-  virtual void diff_total_usage(size_t total_reserved,
-                                size_t total_committed,
-                                int reserved_diff,
-                                int committed_diff) = 0;
-  virtual void diff_num_of_classes(size_t classes, int diff) = 0;
-  virtual void diff_num_of_threads(size_t threads, int diff) = 0;
+  // Convert diff amount in bytes to current reporting scale
+  inline long diff_in_current_scale(size_t s1, size_t s2) const {
+    long amount = (long)(s1 - s2);
+    long scale = (long)_scale;
+    amount = (amount > 0) ? (amount + scale / 2) : (amount - scale / 2);
+    return amount / scale;
+  }
 
-  virtual void diff_thread_info(size_t stack_reserved, size_t stack_committed,
-        int stack_reserved_diff, int stack_committed_diff) = 0;
+  // Helper functions
+  // Calculate total reserved and committed amount
+  size_t reserved_total(const MallocMemory* malloc, const VirtualMemory* vm) const;
+  size_t committed_total(const MallocMemory* malloc, const VirtualMemory* vm) const;
 
 
-  /*
-   * memory summary by memory types.
-   * for each memory type, following summaries are reported:
-   *  - reserved amount, committed amount
-   *  - malloc'd amount, malloc count
-   *  - arena amount, arena count
-   */
+  // Print summary total, malloc and virtual memory
+  void print_total(size_t reserved, size_t committed) const;
+  void print_malloc(size_t amount, size_t count) const;
+  void print_virtual_memory(size_t reserved, size_t committed) const;
 
-  // start reporting memory summary by memory type
-  virtual void start_category_summary() = 0;
+  void print_malloc_line(size_t amount, size_t count) const;
+  void print_virtual_memory_line(size_t reserved, size_t committed) const;
+  void print_arena_line(size_t amount, size_t count) const;
 
-  virtual void category_summary(MEMFLAGS type, size_t reserved_amt,
-                                size_t committed_amt,
-                                size_t malloc_amt, size_t malloc_count,
-                                size_t arena_amt, size_t arena_count) = 0;
+  void print_virtual_memory_region(const char* type, address base, size_t size) const;
+};
 
-  virtual void diff_category_summary(MEMFLAGS type, size_t cur_reserved_amt,
-                                size_t cur_committed_amt,
-                                size_t cur_malloc_amt, size_t cur_malloc_count,
-                                size_t cur_arena_amt, size_t cur_arena_count,
-                                int reserved_diff, int committed_diff, int malloc_diff,
-                                int malloc_count_diff, int arena_diff,
-                                int arena_count_diff) = 0;
+/*
+ * The class is for generating summary tracking report.
+ */
+class MemSummaryReporter : public MemReporterBase {
+ private:
+  MallocMemorySnapshot*   _malloc_snapshot;
+  VirtualMemorySnapshot*  _vm_snapshot;
+  size_t                  _class_count;
 
-  virtual void done_category_summary() = 0;
-
-  virtual void start_virtual_memory_map() = 0;
-  virtual void reserved_memory_region(MEMFLAGS type, address base, address end, size_t size, address pc) = 0;
-  virtual void committed_memory_region(address base, address end, size_t size, address pc) = 0;
-  virtual void done_virtual_memory_map() = 0;
+ public:
+  // Report summary tracking data from global snapshots directly.
+  // This constructor is used for final reporting and hs_err reporting.
+  MemSummaryReporter(MallocMemorySnapshot* malloc_snapshot,
+    VirtualMemorySnapshot* vm_snapshot, outputStream* output,
+    size_t class_count = 0, size_t scale = K) :
+    MemReporterBase(output, scale),
+    _malloc_snapshot(malloc_snapshot),
+    _vm_snapshot(vm_snapshot) {
+    if (class_count == 0) {
+      _class_count = InstanceKlass::number_of_instance_classes();
+    } else {
+      _class_count = class_count;
+    }
+  }
+  // This constructor is for normal reporting from a recent baseline.
+  MemSummaryReporter(MemBaseline& baseline, outputStream* output,
+    size_t scale = K) : MemReporterBase(output, scale),
+    _malloc_snapshot(baseline.malloc_memory_snapshot()),
+    _vm_snapshot(baseline.virtual_memory_snapshot()),
+    _class_count(baseline.class_count()) { }
 
-  /*
-   *  Report callsite information
-   */
-  virtual void start_callsite() = 0;
-  virtual void malloc_callsite(address pc, size_t malloc_amt, size_t malloc_count) = 0;
-  virtual void virtual_memory_callsite(address pc, size_t reserved_amt, size_t committed_amt) = 0;
 
-  virtual void diff_malloc_callsite(address pc, size_t cur_malloc_amt, size_t cur_malloc_count,
-              int malloc_diff, int malloc_count_diff) = 0;
-  virtual void diff_virtual_memory_callsite(address pc, size_t cur_reserved_amt, size_t cur_committed_amt,
-              int reserved_diff, int committed_diff) = 0;
-
-  virtual void done_callsite() = 0;
-
-  // return current scale in "KB", "MB" or "GB"
-  static const char* memory_unit(size_t scale);
+  // Generate summary report
+  virtual void report();
+ private:
+  // Report summary for each memory type
+  void report_summary_of_type(MEMFLAGS type, MallocMemory* malloc_memory,
+    VirtualMemory* virtual_memory);
 };
 
 /*
- * This class reports processed data from a baseline or
- * the changes between the two baseline.
+ * The class is for generating detail tracking report.
  */
-class BaselineReporter : public StackObj {
+class MemDetailReporter : public MemSummaryReporter {
  private:
-  BaselineOutputer&  _outputer;
-  size_t             _scale;
+  MemBaseline&   _baseline;
 
  public:
-  // construct a reporter that reports memory usage
-  // in specified scale
-  BaselineReporter(BaselineOutputer& outputer, size_t scale = K):
-    _outputer(outputer) {
-    _scale = scale;
+  MemDetailReporter(MemBaseline& baseline, outputStream* output, size_t scale = K) :
+    MemSummaryReporter(baseline, output, scale),
+     _baseline(baseline) { }
+
+  // Generate detail report.
+  // The report contains summary and detail sections.
+  virtual void report() {
+    MemSummaryReporter::report();
+    report_virtual_memory_map();
+    report_detail();
   }
-  virtual void report_baseline(const MemBaseline& baseline, bool summary_only = false);
-  virtual void diff_baselines(const MemBaseline& cur, const MemBaseline& prev,
-                              bool summary_only = false);
-
-  void set_scale(size_t scale);
-  size_t scale() const { return _scale; }
 
  private:
-  void report_summaries(const MemBaseline& baseline);
-  void report_virtual_memory_map(const MemBaseline& baseline);
-  void report_callsites(const MemBaseline& baseline);
-
-  void diff_summaries(const MemBaseline& cur, const MemBaseline& prev);
-  void diff_callsites(const MemBaseline& cur, const MemBaseline& prev);
+  // Report detail tracking data.
+  void report_detail();
+  // Report virtual memory map
+  void report_virtual_memory_map();
+  // Report malloc allocation sites
+  void report_malloc_sites();
+  // Report virtual memory reservation sites
+  void report_virtual_memory_allocation_sites();
 
-  // calculate memory size in current memory scale
-  size_t amount_in_current_scale(size_t amt) const;
-  // diff two unsigned values in current memory scale
-  int    diff_in_current_scale(size_t value1, size_t value2) const;
-  // diff two unsigned value
-  int    diff(size_t value1, size_t value2) const;
+  // Report a virtual memory region
+  void report_virtual_memory_region(const ReservedMemoryRegion* rgn);
 };
 
 /*
- * tty output implementation. Native memory tracking
- * DCmd uses this outputer.
+ * The class is for generating summary comparison report.
+ * It compares current memory baseline against an early baseline.
  */
-class BaselineTTYOutputer : public BaselineOutputer {
- private:
-  size_t         _scale;
-
-  size_t         _num_of_classes;
-  size_t         _num_of_threads;
-  size_t         _thread_stack_reserved;
-  size_t         _thread_stack_committed;
-
-  int            _num_of_classes_diff;
-  int            _num_of_threads_diff;
-  int            _thread_stack_reserved_diff;
-  int            _thread_stack_committed_diff;
-
-  outputStream*  _output;
+class MemSummaryDiffReporter : public MemReporterBase {
+ protected:
+  MemBaseline&      _early_baseline;
+  MemBaseline&      _current_baseline;
 
  public:
-  BaselineTTYOutputer(outputStream* st) {
-    _scale = K;
-    _num_of_classes = 0;
-    _num_of_threads = 0;
-    _thread_stack_reserved = 0;
-    _thread_stack_committed = 0;
-    _num_of_classes_diff = 0;
-    _num_of_threads_diff = 0;
-    _thread_stack_reserved_diff = 0;
-    _thread_stack_committed_diff = 0;
-    _output = st;
-  }
-
-  // begin reporting memory usage in specified scale
-  void start(size_t scale, bool report_diff = false);
-  // done reporting
-  void done();
-
-  // total memory usage
-  void total_usage(size_t total_reserved,
-                   size_t total_committed);
-  // report total loaded classes
-  void num_of_classes(size_t classes) {
-    _num_of_classes = classes;
-  }
-
-  void num_of_threads(size_t threads) {
-    _num_of_threads = threads;
-  }
-
-  void thread_info(size_t stack_reserved_amt, size_t stack_committed_amt) {
-    _thread_stack_reserved = stack_reserved_amt;
-    _thread_stack_committed = stack_committed_amt;
+  MemSummaryDiffReporter(MemBaseline& early_baseline, MemBaseline& current_baseline,
+    outputStream* output, size_t scale = K) : MemReporterBase(output, scale),
+    _early_baseline(early_baseline), _current_baseline(current_baseline) {
+    assert(early_baseline.baseline_type()   != MemBaseline::Not_baselined, "Not baselined");
+    assert(current_baseline.baseline_type() != MemBaseline::Not_baselined, "Not baselined");
   }
 
-  void diff_total_usage(size_t total_reserved,
-                        size_t total_committed,
-                        int reserved_diff,
-                        int committed_diff);
-
-  void diff_num_of_classes(size_t classes, int diff) {
-    _num_of_classes = classes;
-    _num_of_classes_diff = diff;
-  }
-
-  void diff_num_of_threads(size_t threads, int diff) {
-    _num_of_threads = threads;
-    _num_of_threads_diff = diff;
-  }
-
-  void diff_thread_info(size_t stack_reserved_amt, size_t stack_committed_amt,
-               int stack_reserved_diff, int stack_committed_diff) {
-    _thread_stack_reserved = stack_reserved_amt;
-    _thread_stack_committed = stack_committed_amt;
-    _thread_stack_reserved_diff = stack_reserved_diff;
-    _thread_stack_committed_diff = stack_committed_diff;
-  }
+  // Generate summary comparison report
+  virtual void report_diff();
 
-  /*
-   * Report memory summary categoriuzed by memory types.
-   * For each memory type, following summaries are reported:
-   *  - reserved amount, committed amount
-   *  - malloc-ed amount, malloc count
-   *  - arena amount, arena count
-   */
-  // start reporting memory summary by memory type
-  void start_category_summary();
-  void category_summary(MEMFLAGS type, size_t reserved_amt, size_t committed_amt,
-                               size_t malloc_amt, size_t malloc_count,
-                               size_t arena_amt, size_t arena_count);
-
-  void diff_category_summary(MEMFLAGS type, size_t cur_reserved_amt,
-                          size_t cur_committed_amt,
-                          size_t cur_malloc_amt, size_t cur_malloc_count,
-                          size_t cur_arena_amt, size_t cur_arena_count,
-                          int reserved_diff, int committed_diff, int malloc_diff,
-                          int malloc_count_diff, int arena_diff,
-                          int arena_count_diff);
+ private:
+  // report the comparison of each memory type
+  void diff_summary_of_type(MEMFLAGS type,
+    const MallocMemory* early_malloc, const VirtualMemory* early_vm,
+    const MallocMemory* current_malloc, const VirtualMemory* current_vm) const;
 
-  void done_category_summary();
-
-  // virtual memory map
-  void start_virtual_memory_map();
-  void reserved_memory_region(MEMFLAGS type, address base, address end, size_t size, address pc);
-  void committed_memory_region(address base, address end, size_t size, address pc);
-  void done_virtual_memory_map();
-
-
-  /*
-   *  Report callsite information
-   */
-  void start_callsite();
-  void malloc_callsite(address pc, size_t malloc_amt, size_t malloc_count);
-  void virtual_memory_callsite(address pc, size_t reserved_amt, size_t committed_amt);
-
-  void diff_malloc_callsite(address pc, size_t cur_malloc_amt, size_t cur_malloc_count,
-              int malloc_diff, int malloc_count_diff);
-  void diff_virtual_memory_callsite(address pc, size_t cur_reserved_amt, size_t cur_committed_amt,
-              int reserved_diff, int committed_diff);
-
-  void done_callsite();
+ protected:
+  void print_malloc_diff(size_t current_amount, size_t current_count,
+    size_t early_amount, size_t early_count) const;
+  void print_virtual_memory_diff(size_t current_reserved, size_t current_committed,
+    size_t early_reserved, size_t early_committed) const;
+  void print_arena_diff(size_t current_amount, size_t current_count,
+    size_t early_amount, size_t early_count) const;
 };
 
+/*
+ * The class is for generating detail comparison report.
+ * It compares current memory baseline against an early baseline,
+ * both baselines have to be detail baseline.
+ */
+class MemDetailDiffReporter : public MemSummaryDiffReporter {
+ public:
+  MemDetailDiffReporter(MemBaseline& early_baseline, MemBaseline& current_baseline,
+    outputStream* output, size_t scale = K) :
+    MemSummaryDiffReporter(early_baseline, current_baseline, output, scale) { }
+
+  // Generate detail comparison report
+  virtual void report_diff();
+
+  // Malloc allocation site comparison
+  void diff_malloc_sites() const;
+  // Virutal memory reservation site comparison
+  void diff_virtual_memory_sites() const;
+
+  // New malloc allocation site in recent baseline
+  void new_malloc_site (const MallocSite* site) const;
+  // The malloc allocation site is not in recent baseline
+  void old_malloc_site (const MallocSite* site) const;
+  // Compare malloc allocation site, it is in both baselines
+  void diff_malloc_site(const MallocSite* early, const MallocSite* current)  const;
+
+  // New virtual memory allocation site in recent baseline
+  void new_virtual_memory_site (const VirtualMemoryAllocationSite* callsite) const;
+  // The virtual memory allocation site is not in recent baseline
+  void old_virtual_memory_site (const VirtualMemoryAllocationSite* callsite) const;
+  // Compare virtual memory allocation site, it is in both baseline
+  void diff_virtual_memory_site(const VirtualMemoryAllocationSite* early,
+                                const VirtualMemoryAllocationSite* current)  const;
+
+  void diff_malloc_site(const NativeCallStack* stack, size_t current_size,
+    size_t currrent_count, size_t early_size, size_t early_count) const;
+  void diff_virtual_memory_site(const NativeCallStack* stack, size_t current_reserved,
+    size_t current_committed, size_t early_reserved, size_t early_committed) const;
+};
 
 #endif // INCLUDE_NMT
 
-#endif // SHARE_VM_SERVICES_MEM_REPORTER_HPP
+#endif
+
--- a/src/share/vm/services/memSnapshot.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,748 +0,0 @@
-/*
- * Copyright (c) 2012, 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 "runtime/mutexLocker.hpp"
-#include "utilities/decoder.hpp"
-#include "services/memBaseline.hpp"
-#include "services/memPtr.hpp"
-#include "services/memPtrArray.hpp"
-#include "services/memSnapshot.hpp"
-#include "services/memTracker.hpp"
-
-PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC
-
-#ifdef ASSERT
-
-void decode_pointer_record(MemPointerRecord* rec) {
-  tty->print("Pointer: [" PTR_FORMAT " - " PTR_FORMAT  "] size = %d bytes", rec->addr(),
-    rec->addr() + rec->size(), (int)rec->size());
-  tty->print(" type = %s", MemBaseline::type2name(FLAGS_TO_MEMORY_TYPE(rec->flags())));
-  if (rec->is_vm_pointer()) {
-    if (rec->is_allocation_record()) {
-      tty->print_cr(" (reserve)");
-    } else if (rec->is_commit_record()) {
-      tty->print_cr(" (commit)");
-    } else if (rec->is_uncommit_record()) {
-      tty->print_cr(" (uncommit)");
-    } else if (rec->is_deallocation_record()) {
-      tty->print_cr(" (release)");
-    } else {
-      tty->print_cr(" (tag)");
-    }
-  } else {
-    if (rec->is_arena_memory_record()) {
-      tty->print_cr(" (arena size)");
-    } else if (rec->is_allocation_record()) {
-      tty->print_cr(" (malloc)");
-    } else {
-      tty->print_cr(" (free)");
-    }
-  }
-  if (MemTracker::track_callsite()) {
-    char buf[1024];
-    address pc = ((MemPointerRecordEx*)rec)->pc();
-    if (pc != NULL && os::dll_address_to_function_name(pc, buf, sizeof(buf), NULL)) {
-      tty->print_cr("\tfrom %s", buf);
-    } else {
-      tty->print_cr("\tcould not decode pc = " PTR_FORMAT "", pc);
-    }
-  }
-}
-
-void decode_vm_region_record(VMMemRegion* rec) {
-  tty->print("VM Region [" PTR_FORMAT " - " PTR_FORMAT "]", rec->addr(),
-    rec->addr() + rec->size());
-  tty->print(" type = %s", MemBaseline::type2name(FLAGS_TO_MEMORY_TYPE(rec->flags())));
-  if (rec->is_allocation_record()) {
-    tty->print_cr(" (reserved)");
-  } else if (rec->is_commit_record()) {
-    tty->print_cr(" (committed)");
-  } else {
-    ShouldNotReachHere();
-  }
-  if (MemTracker::track_callsite()) {
-    char buf[1024];
-    address pc = ((VMMemRegionEx*)rec)->pc();
-    if (pc != NULL && os::dll_address_to_function_name(pc, buf, sizeof(buf), NULL)) {
-      tty->print_cr("\tfrom %s", buf);
-    } else {
-      tty->print_cr("\tcould not decode pc = " PTR_FORMAT "", pc);
-    }
-
-  }
-}
-
-#endif
-
-
-bool VMMemPointerIterator::insert_record(MemPointerRecord* rec) {
-  VMMemRegionEx new_rec;
-  assert(rec->is_allocation_record() || rec->is_commit_record(),
-    "Sanity check");
-  if (MemTracker::track_callsite()) {
-    new_rec.init((MemPointerRecordEx*)rec);
-  } else {
-    new_rec.init(rec);
-  }
-  return insert(&new_rec);
-}
-
-bool VMMemPointerIterator::insert_record_after(MemPointerRecord* rec) {
-  VMMemRegionEx new_rec;
-  assert(rec->is_allocation_record() || rec->is_commit_record(),
-    "Sanity check");
-  if (MemTracker::track_callsite()) {
-    new_rec.init((MemPointerRecordEx*)rec);
-  } else {
-    new_rec.init(rec);
-  }
-  return insert_after(&new_rec);
-}
-
-// we don't consolidate reserved regions, since they may be categorized
-// in different types.
-bool VMMemPointerIterator::add_reserved_region(MemPointerRecord* rec) {
-  assert(rec->is_allocation_record(), "Sanity check");
-  VMMemRegion* reserved_region = (VMMemRegion*)current();
-
-  // we don't have anything yet
-  if (reserved_region == NULL) {
-    return insert_record(rec);
-  }
-
-  assert(reserved_region->is_reserved_region(), "Sanity check");
-  // duplicated records
-  if (reserved_region->is_same_region(rec)) {
-    return true;
-  }
-  // Overlapping stack regions indicate that a JNI thread failed to
-  // detach from the VM before exiting. This leaks the JavaThread object.
-  if (CheckJNICalls)  {
-      guarantee(FLAGS_TO_MEMORY_TYPE(reserved_region->flags()) != mtThreadStack ||
-         !reserved_region->overlaps_region(rec),
-         "Attached JNI thread exited without being detached");
-  }
-  // otherwise, we should not have overlapping reserved regions
-  assert(FLAGS_TO_MEMORY_TYPE(reserved_region->flags()) == mtThreadStack ||
-    reserved_region->base() > rec->addr(), "Just check: locate()");
-  assert(FLAGS_TO_MEMORY_TYPE(reserved_region->flags()) == mtThreadStack ||
-    !reserved_region->overlaps_region(rec), "overlapping reserved regions");
-
-  return insert_record(rec);
-}
-
-// we do consolidate committed regions
-bool VMMemPointerIterator::add_committed_region(MemPointerRecord* rec) {
-  assert(rec->is_commit_record(), "Sanity check");
-  VMMemRegion* reserved_rgn = (VMMemRegion*)current();
-  assert(reserved_rgn->is_reserved_region() && reserved_rgn->contains_region(rec),
-    "Sanity check");
-
-  // thread's native stack is always marked as "committed", ignore
-  // the "commit" operation for creating stack guard pages
-  if (FLAGS_TO_MEMORY_TYPE(reserved_rgn->flags()) == mtThreadStack &&
-      FLAGS_TO_MEMORY_TYPE(rec->flags()) != mtThreadStack) {
-    return true;
-  }
-
-  // if the reserved region has any committed regions
-  VMMemRegion* committed_rgn  = (VMMemRegion*)next();
-  while (committed_rgn != NULL && committed_rgn->is_committed_region()) {
-    // duplicated commit records
-    if(committed_rgn->contains_region(rec)) {
-      return true;
-    } else if (committed_rgn->overlaps_region(rec)) {
-      // overlaps front part
-      if (rec->addr() < committed_rgn->addr()) {
-        committed_rgn->expand_region(rec->addr(),
-          committed_rgn->addr() - rec->addr());
-      } else {
-        // overlaps tail part
-        address committed_rgn_end = committed_rgn->addr() +
-              committed_rgn->size();
-        assert(committed_rgn_end < rec->addr() + rec->size(),
-             "overlap tail part");
-        committed_rgn->expand_region(committed_rgn_end,
-          (rec->addr() + rec->size()) - committed_rgn_end);
-      }
-    } else if (committed_rgn->base() + committed_rgn->size() == rec->addr()) {
-      // adjunct each other
-      committed_rgn->expand_region(rec->addr(), rec->size());
-      VMMemRegion* next_reg = (VMMemRegion*)next();
-      // see if we can consolidate next committed region
-      if (next_reg != NULL && next_reg->is_committed_region() &&
-        next_reg->base() == committed_rgn->base() + committed_rgn->size()) {
-          committed_rgn->expand_region(next_reg->base(), next_reg->size());
-          // delete merged region
-          remove();
-      }
-      return true;
-    } else if (committed_rgn->base() > rec->addr()) {
-      // found the location, insert this committed region
-      return insert_record(rec);
-    }
-    committed_rgn = (VMMemRegion*)next();
-  }
-  return insert_record(rec);
-}
-
-bool VMMemPointerIterator::remove_uncommitted_region(MemPointerRecord* rec) {
-  assert(rec->is_uncommit_record(), "sanity check");
-  VMMemRegion* cur;
-  cur = (VMMemRegion*)current();
-  assert(cur->is_reserved_region() && cur->contains_region(rec),
-    "Sanity check");
-  // thread's native stack is always marked as "committed", ignore
-  // the "commit" operation for creating stack guard pages
-  if (FLAGS_TO_MEMORY_TYPE(cur->flags()) == mtThreadStack &&
-      FLAGS_TO_MEMORY_TYPE(rec->flags()) != mtThreadStack) {
-    return true;
-  }
-
-  cur = (VMMemRegion*)next();
-  while (cur != NULL && cur->is_committed_region()) {
-    // region already uncommitted, must be due to duplicated record
-    if (cur->addr() >= rec->addr() + rec->size()) {
-      break;
-    } else if (cur->contains_region(rec)) {
-      // uncommit whole region
-      if (cur->is_same_region(rec)) {
-        remove();
-        break;
-      } else if (rec->addr() == cur->addr() ||
-        rec->addr() + rec->size() == cur->addr() + cur->size()) {
-        // uncommitted from either end of current memory region.
-        cur->exclude_region(rec->addr(), rec->size());
-        break;
-      } else { // split the committed region and release the middle
-        address high_addr = cur->addr() + cur->size();
-        size_t sz = high_addr - rec->addr();
-        cur->exclude_region(rec->addr(), sz);
-        sz = high_addr - (rec->addr() + rec->size());
-        if (MemTracker::track_callsite()) {
-          MemPointerRecordEx tmp(rec->addr() + rec->size(), cur->flags(), sz,
-             ((VMMemRegionEx*)cur)->pc());
-          return insert_record_after(&tmp);
-        } else {
-          MemPointerRecord tmp(rec->addr() + rec->size(), cur->flags(), sz);
-          return insert_record_after(&tmp);
-        }
-      }
-    }
-    cur = (VMMemRegion*)next();
-  }
-
-  // we may not find committed record due to duplicated records
-  return true;
-}
-
-bool VMMemPointerIterator::remove_released_region(MemPointerRecord* rec) {
-  assert(rec->is_deallocation_record(), "Sanity check");
-  VMMemRegion* cur = (VMMemRegion*)current();
-  assert(cur->is_reserved_region() && cur->contains_region(rec),
-    "Sanity check");
-  if (rec->is_same_region(cur)) {
-
-    // In snapshot, the virtual memory records are sorted in following orders:
-    // 1. virtual memory's base address
-    // 2. virtual memory reservation record, followed by commit records within this reservation.
-    //    The commit records are also in base address order.
-    // When a reserved region is released, we want to remove the reservation record and all
-    // commit records following it.
-#ifdef ASSERT
-    address low_addr = cur->addr();
-    address high_addr = low_addr + cur->size();
-#endif
-    // remove virtual memory reservation record
-    remove();
-    // remove committed regions within above reservation
-    VMMemRegion* next_region = (VMMemRegion*)current();
-    while (next_region != NULL && next_region->is_committed_region()) {
-      assert(next_region->addr() >= low_addr &&
-             next_region->addr() + next_region->size() <= high_addr,
-            "Range check");
-      remove();
-      next_region = (VMMemRegion*)current();
-    }
-  } else if (rec->addr() == cur->addr() ||
-    rec->addr() + rec->size() == cur->addr() + cur->size()) {
-    // released region is at either end of this region
-    cur->exclude_region(rec->addr(), rec->size());
-    assert(check_reserved_region(), "Integrity check");
-  } else { // split the reserved region and release the middle
-    address high_addr = cur->addr() + cur->size();
-    size_t sz = high_addr - rec->addr();
-    cur->exclude_region(rec->addr(), sz);
-    sz = high_addr - rec->addr() - rec->size();
-    if (MemTracker::track_callsite()) {
-      MemPointerRecordEx tmp(rec->addr() + rec->size(), cur->flags(), sz,
-        ((VMMemRegionEx*)cur)->pc());
-      bool ret = insert_reserved_region(&tmp);
-      assert(!ret || check_reserved_region(), "Integrity check");
-      return ret;
-    } else {
-      MemPointerRecord tmp(rec->addr() + rec->size(), cur->flags(), sz);
-      bool ret = insert_reserved_region(&tmp);
-      assert(!ret || check_reserved_region(), "Integrity check");
-      return ret;
-    }
-  }
-  return true;
-}
-
-bool VMMemPointerIterator::insert_reserved_region(MemPointerRecord* rec) {
-  // skip all 'commit' records associated with previous reserved region
-  VMMemRegion* p = (VMMemRegion*)next();
-  while (p != NULL && p->is_committed_region() &&
-         p->base() + p->size() < rec->addr()) {
-    p = (VMMemRegion*)next();
-  }
-  return insert_record(rec);
-}
-
-bool VMMemPointerIterator::split_reserved_region(VMMemRegion* rgn, address new_rgn_addr, size_t new_rgn_size) {
-  assert(rgn->contains_region(new_rgn_addr, new_rgn_size), "Not fully contained");
-  address pc = (MemTracker::track_callsite() ? ((VMMemRegionEx*)rgn)->pc() : NULL);
-  if (rgn->base() == new_rgn_addr) { // new region is at the beginning of the region
-    size_t sz = rgn->size() - new_rgn_size;
-    // the original region becomes 'new' region
-    rgn->exclude_region(new_rgn_addr + new_rgn_size, sz);
-     // remaining becomes next region
-    MemPointerRecordEx next_rgn(new_rgn_addr + new_rgn_size, rgn->flags(), sz, pc);
-    return insert_reserved_region(&next_rgn);
-  } else if (rgn->base() + rgn->size() == new_rgn_addr + new_rgn_size) {
-    rgn->exclude_region(new_rgn_addr, new_rgn_size);
-    MemPointerRecordEx next_rgn(new_rgn_addr, rgn->flags(), new_rgn_size, pc);
-    return insert_reserved_region(&next_rgn);
-  } else {
-    // the orginal region will be split into three
-    address rgn_high_addr = rgn->base() + rgn->size();
-    // first region
-    rgn->exclude_region(new_rgn_addr, (rgn_high_addr - new_rgn_addr));
-    // the second region is the new region
-    MemPointerRecordEx new_rgn(new_rgn_addr, rgn->flags(), new_rgn_size, pc);
-    if (!insert_reserved_region(&new_rgn)) return false;
-    // the remaining region
-    MemPointerRecordEx rem_rgn(new_rgn_addr + new_rgn_size, rgn->flags(),
-      rgn_high_addr - (new_rgn_addr + new_rgn_size), pc);
-    return insert_reserved_region(&rem_rgn);
-  }
-}
-
-static int sort_in_seq_order(const void* p1, const void* p2) {
-  assert(p1 != NULL && p2 != NULL, "Sanity check");
-  const MemPointerRecord* mp1 = (MemPointerRecord*)p1;
-  const MemPointerRecord* mp2 = (MemPointerRecord*)p2;
-  return (mp1->seq() - mp2->seq());
-}
-
-bool StagingArea::init() {
-  if (MemTracker::track_callsite()) {
-    _malloc_data = new (std::nothrow)MemPointerArrayImpl<SeqMemPointerRecordEx>();
-    _vm_data = new (std::nothrow)MemPointerArrayImpl<SeqMemPointerRecordEx>();
-  } else {
-    _malloc_data = new (std::nothrow)MemPointerArrayImpl<SeqMemPointerRecord>();
-    _vm_data = new (std::nothrow)MemPointerArrayImpl<SeqMemPointerRecord>();
-  }
-
-  if (_malloc_data != NULL && _vm_data != NULL &&
-      !_malloc_data->out_of_memory() &&
-      !_vm_data->out_of_memory()) {
-    return true;
-  } else {
-    if (_malloc_data != NULL) delete _malloc_data;
-    if (_vm_data != NULL) delete _vm_data;
-    _malloc_data = NULL;
-    _vm_data = NULL;
-    return false;
-  }
-}
-
-
-VMRecordIterator StagingArea::virtual_memory_record_walker() {
-  MemPointerArray* arr = vm_data();
-  // sort into seq number order
-  arr->sort((FN_SORT)sort_in_seq_order);
-  return VMRecordIterator(arr);
-}
-
-
-MemSnapshot::MemSnapshot() {
-  if (MemTracker::track_callsite()) {
-    _alloc_ptrs = new (std::nothrow) MemPointerArrayImpl<MemPointerRecordEx>();
-    _vm_ptrs = new (std::nothrow)MemPointerArrayImpl<VMMemRegionEx>(64, true);
-  } else {
-    _alloc_ptrs = new (std::nothrow) MemPointerArrayImpl<MemPointerRecord>();
-    _vm_ptrs = new (std::nothrow)MemPointerArrayImpl<VMMemRegion>(64, true);
-  }
-
-  _staging_area.init();
-  _lock = new (std::nothrow) Mutex(Monitor::max_nonleaf - 1, "memSnapshotLock");
-  NOT_PRODUCT(_untracked_count = 0;)
-  _number_of_classes = 0;
-}
-
-MemSnapshot::~MemSnapshot() {
-  assert(MemTracker::shutdown_in_progress(), "native memory tracking still on");
-  {
-    MutexLockerEx locker(_lock);
-    if (_alloc_ptrs != NULL) {
-      delete _alloc_ptrs;
-      _alloc_ptrs = NULL;
-    }
-
-    if (_vm_ptrs != NULL) {
-      delete _vm_ptrs;
-      _vm_ptrs = NULL;
-    }
-  }
-
-  if (_lock != NULL) {
-    delete _lock;
-    _lock = NULL;
-  }
-}
-
-
-void MemSnapshot::copy_seq_pointer(MemPointerRecord* dest, const MemPointerRecord* src) {
-  assert(dest != NULL && src != NULL, "Just check");
-  assert(dest->addr() == src->addr(), "Just check");
-  assert(dest->seq() > 0 && src->seq() > 0, "not sequenced");
-
-  if (MemTracker::track_callsite()) {
-    *(SeqMemPointerRecordEx*)dest = *(SeqMemPointerRecordEx*)src;
-  } else {
-    *(SeqMemPointerRecord*)dest = *(SeqMemPointerRecord*)src;
-  }
-}
-
-void MemSnapshot::assign_pointer(MemPointerRecord*dest, const MemPointerRecord* src) {
-  assert(src != NULL && dest != NULL, "Just check");
-  assert(dest->seq() == 0 && src->seq() >0, "cast away sequence");
-
-  if (MemTracker::track_callsite()) {
-    *(MemPointerRecordEx*)dest = *(MemPointerRecordEx*)src;
-  } else {
-    *(MemPointerRecord*)dest = *(MemPointerRecord*)src;
-  }
-}
-
-// merge a recorder to the staging area
-bool MemSnapshot::merge(MemRecorder* rec) {
-  assert(rec != NULL && !rec->out_of_memory(), "Just check");
-
-  SequencedRecordIterator itr(rec->pointer_itr());
-
-  MutexLockerEx lock(_lock, true);
-  MemPointerIterator malloc_staging_itr(_staging_area.malloc_data());
-  MemPointerRecord* incoming_rec = (MemPointerRecord*) itr.current();
-  MemPointerRecord* matched_rec;
-
-  while (incoming_rec != NULL) {
-    if (incoming_rec->is_vm_pointer()) {
-      // we don't do anything with virtual memory records during merge
-      if (!_staging_area.vm_data()->append(incoming_rec)) {
-        return false;
-      }
-    } else {
-      // locate matched record and/or also position the iterator to proper
-      // location for this incoming record.
-      matched_rec = (MemPointerRecord*)malloc_staging_itr.locate(incoming_rec->addr());
-      // we have not seen this memory block in this generation,
-      // so just add to staging area
-      if (matched_rec == NULL) {
-        if (!malloc_staging_itr.insert(incoming_rec)) {
-          return false;
-        }
-      } else if (incoming_rec->addr() == matched_rec->addr()) {
-        // whoever has higher sequence number wins
-        if (incoming_rec->seq() > matched_rec->seq()) {
-          copy_seq_pointer(matched_rec, incoming_rec);
-        }
-      } else if (incoming_rec->addr() < matched_rec->addr()) {
-        if (!malloc_staging_itr.insert(incoming_rec)) {
-          return false;
-        }
-      } else {
-        ShouldNotReachHere();
-      }
-    }
-    incoming_rec = (MemPointerRecord*)itr.next();
-  }
-  NOT_PRODUCT(void check_staging_data();)
-  return true;
-}
-
-
-// promote data to next generation
-bool MemSnapshot::promote(int number_of_classes) {
-  assert(_alloc_ptrs != NULL && _vm_ptrs != NULL, "Just check");
-  assert(_staging_area.malloc_data() != NULL && _staging_area.vm_data() != NULL,
-         "Just check");
-  MutexLockerEx lock(_lock, true);
-
-  MallocRecordIterator  malloc_itr = _staging_area.malloc_record_walker();
-  bool promoted = false;
-  if (promote_malloc_records(&malloc_itr)) {
-    VMRecordIterator vm_itr = _staging_area.virtual_memory_record_walker();
-    if (promote_virtual_memory_records(&vm_itr)) {
-      promoted = true;
-    }
-  }
-
-  NOT_PRODUCT(check_malloc_pointers();)
-  _staging_area.clear();
-  _number_of_classes = number_of_classes;
-  return promoted;
-}
-
-bool MemSnapshot::promote_malloc_records(MemPointerArrayIterator* itr) {
-  MemPointerIterator malloc_snapshot_itr(_alloc_ptrs);
-  MemPointerRecord* new_rec = (MemPointerRecord*)itr->current();
-  MemPointerRecord* matched_rec;
-  while (new_rec != NULL) {
-    matched_rec = (MemPointerRecord*)malloc_snapshot_itr.locate(new_rec->addr());
-    // found matched memory block
-    if (matched_rec != NULL && new_rec->addr() == matched_rec->addr()) {
-      // snapshot already contains 'live' records
-      assert(matched_rec->is_allocation_record() || matched_rec->is_arena_memory_record(),
-             "Sanity check");
-      // update block states
-      if (new_rec->is_allocation_record()) {
-        assign_pointer(matched_rec, new_rec);
-      } else if (new_rec->is_arena_memory_record()) {
-        if (new_rec->size() == 0) {
-          // remove size record once size drops to 0
-          malloc_snapshot_itr.remove();
-        } else {
-          assign_pointer(matched_rec, new_rec);
-        }
-      } else {
-        // a deallocation record
-        assert(new_rec->is_deallocation_record(), "Sanity check");
-        // an arena record can be followed by a size record, we need to remove both
-        if (matched_rec->is_arena_record()) {
-          MemPointerRecord* next = (MemPointerRecord*)malloc_snapshot_itr.peek_next();
-          if (next != NULL && next->is_arena_memory_record() &&
-              next->is_memory_record_of_arena(matched_rec)) {
-            malloc_snapshot_itr.remove();
-          }
-        }
-        // the memory is deallocated, remove related record(s)
-        malloc_snapshot_itr.remove();
-      }
-    } else {
-      // don't insert size 0 record
-      if (new_rec->is_arena_memory_record() && new_rec->size() == 0) {
-        new_rec = NULL;
-      }
-
-      if (new_rec != NULL) {
-        if  (new_rec->is_allocation_record() || new_rec->is_arena_memory_record()) {
-          if (matched_rec != NULL && new_rec->addr() > matched_rec->addr()) {
-            if (!malloc_snapshot_itr.insert_after(new_rec)) {
-              return false;
-            }
-          } else {
-            if (!malloc_snapshot_itr.insert(new_rec)) {
-              return false;
-            }
-          }
-        }
-#ifndef PRODUCT
-        else if (!has_allocation_record(new_rec->addr())) {
-          // NMT can not track some startup memory, which is allocated before NMT is on
-          _untracked_count ++;
-        }
-#endif
-      }
-    }
-    new_rec = (MemPointerRecord*)itr->next();
-  }
-  return true;
-}
-
-bool MemSnapshot::promote_virtual_memory_records(MemPointerArrayIterator* itr) {
-  VMMemPointerIterator vm_snapshot_itr(_vm_ptrs);
-  MemPointerRecord* new_rec = (MemPointerRecord*)itr->current();
-  VMMemRegion*  reserved_rec;
-  while (new_rec != NULL) {
-    assert(new_rec->is_vm_pointer(), "Sanity check");
-
-    // locate a reserved region that contains the specified address, or
-    // the nearest reserved region has base address just above the specified
-    // address
-    reserved_rec = (VMMemRegion*)vm_snapshot_itr.locate(new_rec->addr());
-    if (reserved_rec != NULL && reserved_rec->contains_region(new_rec)) {
-      // snapshot can only have 'live' records
-      assert(reserved_rec->is_reserved_region(), "Sanity check");
-      if (new_rec->is_allocation_record()) {
-        if (!reserved_rec->is_same_region(new_rec)) {
-          // only deal with split a bigger reserved region into smaller regions.
-          // So far, CDS is the only use case.
-          if (!vm_snapshot_itr.split_reserved_region(reserved_rec, new_rec->addr(), new_rec->size())) {
-            return false;
-          }
-        }
-      } else if (new_rec->is_uncommit_record()) {
-        if (!vm_snapshot_itr.remove_uncommitted_region(new_rec)) {
-          return false;
-        }
-      } else if (new_rec->is_commit_record()) {
-        // insert or expand existing committed region to cover this
-        // newly committed region
-        if (!vm_snapshot_itr.add_committed_region(new_rec)) {
-          return false;
-        }
-      } else if (new_rec->is_deallocation_record()) {
-        // release part or all memory region
-        if (!vm_snapshot_itr.remove_released_region(new_rec)) {
-          return false;
-        }
-      } else if (new_rec->is_type_tagging_record()) {
-        // tag this reserved virtual memory range to a memory type. Can not re-tag a memory range
-        // to different type.
-        assert(FLAGS_TO_MEMORY_TYPE(reserved_rec->flags()) == mtNone ||
-               FLAGS_TO_MEMORY_TYPE(reserved_rec->flags()) == FLAGS_TO_MEMORY_TYPE(new_rec->flags()),
-               "Sanity check");
-        reserved_rec->tag(new_rec->flags());
-    } else {
-        ShouldNotReachHere();
-          }
-        } else {
-      /*
-       * The assertion failure indicates mis-matched virtual memory records. The likely
-       * scenario is, that some virtual memory operations are not going through os::xxxx_memory()
-       * api, which have to be tracked manually. (perfMemory is an example).
-      */
-      assert(new_rec->is_allocation_record(), "Sanity check");
-      if (!vm_snapshot_itr.add_reserved_region(new_rec)) {
-            return false;
-          }
-  }
-    new_rec = (MemPointerRecord*)itr->next();
-  }
-  return true;
-}
-
-#ifndef PRODUCT
-void MemSnapshot::print_snapshot_stats(outputStream* st) {
-  st->print_cr("Snapshot:");
-  st->print_cr("\tMalloced: %d/%d [%5.2f%%]  %dKB", _alloc_ptrs->length(), _alloc_ptrs->capacity(),
-    (100.0 * (float)_alloc_ptrs->length()) / (float)_alloc_ptrs->capacity(), _alloc_ptrs->instance_size()/K);
-
-  st->print_cr("\tVM: %d/%d [%5.2f%%] %dKB", _vm_ptrs->length(), _vm_ptrs->capacity(),
-    (100.0 * (float)_vm_ptrs->length()) / (float)_vm_ptrs->capacity(), _vm_ptrs->instance_size()/K);
-
-  st->print_cr("\tMalloc staging Area:     %d/%d [%5.2f%%] %dKB", _staging_area.malloc_data()->length(),
-    _staging_area.malloc_data()->capacity(),
-    (100.0 * (float)_staging_area.malloc_data()->length()) / (float)_staging_area.malloc_data()->capacity(),
-    _staging_area.malloc_data()->instance_size()/K);
-
-  st->print_cr("\tVirtual memory staging Area:     %d/%d [%5.2f%%] %dKB", _staging_area.vm_data()->length(),
-    _staging_area.vm_data()->capacity(),
-    (100.0 * (float)_staging_area.vm_data()->length()) / (float)_staging_area.vm_data()->capacity(),
-    _staging_area.vm_data()->instance_size()/K);
-
-  st->print_cr("\tUntracked allocation: %d", _untracked_count);
-}
-
-void MemSnapshot::check_malloc_pointers() {
-  MemPointerArrayIteratorImpl mItr(_alloc_ptrs);
-  MemPointerRecord* p = (MemPointerRecord*)mItr.current();
-  MemPointerRecord* prev = NULL;
-  while (p != NULL) {
-    if (prev != NULL) {
-      assert(p->addr() >= prev->addr(), "sorting order");
-    }
-    prev = p;
-    p = (MemPointerRecord*)mItr.next();
-  }
-}
-
-bool MemSnapshot::has_allocation_record(address addr) {
-  MemPointerArrayIteratorImpl itr(_staging_area.malloc_data());
-  MemPointerRecord* cur = (MemPointerRecord*)itr.current();
-  while (cur != NULL) {
-    if (cur->addr() == addr && cur->is_allocation_record()) {
-      return true;
-    }
-    cur = (MemPointerRecord*)itr.next();
-  }
-  return false;
-}
-#endif // PRODUCT
-
-#ifdef ASSERT
-void MemSnapshot::check_staging_data() {
-  MemPointerArrayIteratorImpl itr(_staging_area.malloc_data());
-  MemPointerRecord* cur = (MemPointerRecord*)itr.current();
-  MemPointerRecord* next = (MemPointerRecord*)itr.next();
-  while (next != NULL) {
-    assert((next->addr() > cur->addr()) ||
-      ((next->flags() & MemPointerRecord::tag_masks) >
-       (cur->flags() & MemPointerRecord::tag_masks)),
-       "sorting order");
-    cur = next;
-    next = (MemPointerRecord*)itr.next();
-  }
-
-  MemPointerArrayIteratorImpl vm_itr(_staging_area.vm_data());
-  cur = (MemPointerRecord*)vm_itr.current();
-  while (cur != NULL) {
-    assert(cur->is_vm_pointer(), "virtual memory pointer only");
-    cur = (MemPointerRecord*)vm_itr.next();
-  }
-}
-
-void MemSnapshot::dump_all_vm_pointers() {
-  MemPointerArrayIteratorImpl itr(_vm_ptrs);
-  VMMemRegion* ptr = (VMMemRegion*)itr.current();
-  tty->print_cr("dump virtual memory pointers:");
-  while (ptr != NULL) {
-    if (ptr->is_committed_region()) {
-      tty->print("\t");
-    }
-    tty->print("[" PTR_FORMAT " - " PTR_FORMAT "] [%x]", ptr->addr(),
-      (ptr->addr() + ptr->size()), ptr->flags());
-
-    if (MemTracker::track_callsite()) {
-      VMMemRegionEx* ex = (VMMemRegionEx*)ptr;
-      if (ex->pc() != NULL) {
-        char buf[1024];
-        if (os::dll_address_to_function_name(ex->pc(), buf, sizeof(buf), NULL)) {
-          tty->print_cr("\t%s", buf);
-        } else {
-          tty->cr();
-        }
-      }
-    }
-
-    ptr = (VMMemRegion*)itr.next();
-  }
-  tty->flush();
-}
-#endif // ASSERT
-
--- a/src/share/vm/services/memSnapshot.hpp	Thu Sep 04 13:06:04 2014 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,408 +0,0 @@
-/*
- * Copyright (c) 2012, 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_SERVICES_MEM_SNAPSHOT_HPP
-#define SHARE_VM_SERVICES_MEM_SNAPSHOT_HPP
-
-#include "memory/allocation.hpp"
-#include "runtime/mutex.hpp"
-#include "runtime/mutexLocker.hpp"
-#include "services/memBaseline.hpp"
-#include "services/memPtrArray.hpp"
-
-// Snapshot pointer array iterator
-
-// The pointer array contains malloc-ed pointers
-class MemPointerIterator : public MemPointerArrayIteratorImpl {
- public:
-  MemPointerIterator(MemPointerArray* arr):
-    MemPointerArrayIteratorImpl(arr) {
-    assert(arr != NULL, "null array");
-  }
-
-#ifdef ASSERT
-  virtual bool is_dup_pointer(const MemPointer* ptr1,
-    const MemPointer* ptr2) const {
-    MemPointerRecord* p1 = (MemPointerRecord*)ptr1;
-    MemPointerRecord* p2 = (MemPointerRecord*)ptr2;
-
-    if (p1->addr() != p2->addr()) return false;
-    if ((p1->flags() & MemPointerRecord::tag_masks) !=
-        (p2->flags() & MemPointerRecord::tag_masks)) {
-      return false;
-    }
-    // we do see multiple commit/uncommit on the same memory, it is ok
-    return (p1->flags() & MemPointerRecord::tag_masks) == MemPointerRecord::tag_alloc ||
-           (p1->flags() & MemPointerRecord::tag_masks) == MemPointerRecord::tag_release;
-  }
-
-  virtual bool insert(MemPointer* ptr) {
-    if (_pos > 0) {
-      MemPointer* p1 = (MemPointer*)ptr;
-      MemPointer* p2 = (MemPointer*)_array->at(_pos - 1);
-      assert(!is_dup_pointer(p1, p2),
-        err_msg("duplicated pointer, flag = [%x]", (unsigned int)((MemPointerRecord*)p1)->flags()));
-    }
-     if (_pos < _array->length() -1) {
-      MemPointer* p1 = (MemPointer*)ptr;
-      MemPointer* p2 = (MemPointer*)_array->at(_pos + 1);
-      assert(!is_dup_pointer(p1, p2),
-        err_msg("duplicated pointer, flag = [%x]", (unsigned int)((MemPointerRecord*)p1)->flags()));
-     }
-    return _array->insert_at(ptr, _pos);
-  }
-
-  virtual bool insert_after(MemPointer* ptr) {
-    if (_pos > 0) {
-      MemPointer* p1 = (MemPointer*)ptr;
-      MemPointer* p2 = (MemPointer*)_array->at(_pos - 1);
-      assert(!is_dup_pointer(p1, p2),
-        err_msg("duplicated pointer, flag = [%x]", (unsigned int)((MemPointerRecord*)p1)->flags()));
-    }
-    if (_pos < _array->length() - 1) {
-      MemPointer* p1 = (MemPointer*)ptr;
-      MemPointer* p2 = (MemPointer*)_array->at(_pos + 1);
-
-      assert(!is_dup_pointer(p1, p2),
-        err_msg("duplicated pointer, flag = [%x]", (unsigned int)((MemPointerRecord*)p1)->flags()));
-     }
-    if (_array->insert_at(ptr, _pos + 1)) {
-      _pos ++;
-      return true;
-    }
-    return false;
-  }
-#endif
-
-  virtual MemPointer* locate(address addr) {
-    MemPointer* cur = current();
-    while (cur != NULL && cur->addr() < addr) {
-      cur = next();
-    }
-    return cur;
-  }
-};
-
-class VMMemPointerIterator : public MemPointerIterator {
- public:
-  VMMemPointerIterator(MemPointerArray* arr):
-      MemPointerIterator(arr) {
-  }
-
-  // locate an existing reserved memory region that contains specified address,
-  // or the reserved region just above this address, where the incoming
-  // reserved region should be inserted.
-  virtual MemPointer* locate(address addr) {
-    reset();
-    VMMemRegion* reg = (VMMemRegion*)current();
-    while (reg != NULL) {
-      if (reg->is_reserved_region()) {
-        if (reg->contains_address(addr) || addr < reg->base()) {
-          return reg;
-      }
-    }
-      reg = (VMMemRegion*)next();
-    }
-      return NULL;
-    }
-
-  // following methods update virtual memory in the context
-  // of 'current' position, which is properly positioned by
-  // callers via locate method.
-  bool add_reserved_region(MemPointerRecord* rec);
-  bool add_committed_region(MemPointerRecord* rec);
-  bool remove_uncommitted_region(MemPointerRecord* rec);
-  bool remove_released_region(MemPointerRecord* rec);
-
-  // split a reserved region to create a new memory region with specified base and size
-  bool split_reserved_region(VMMemRegion* rgn, address new_rgn_addr, size_t new_rgn_size);
- private:
-  bool insert_record(MemPointerRecord* rec);
-  bool insert_record_after(MemPointerRecord* rec);
-
-  bool insert_reserved_region(MemPointerRecord* rec);
-
-  // reset current position
-  inline void reset() { _pos = 0; }
-#ifdef ASSERT
-  // check integrity of records on current reserved memory region.
-  bool check_reserved_region() {
-    VMMemRegion* reserved_region = (VMMemRegion*)current();
-    assert(reserved_region != NULL && reserved_region->is_reserved_region(),
-          "Sanity check");
-    // all committed regions that follow current reserved region, should all
-    // belong to the reserved region.
-    VMMemRegion* next_region = (VMMemRegion*)next();
-    for (; next_region != NULL && next_region->is_committed_region();
-         next_region = (VMMemRegion*)next() ) {
-      if(!reserved_region->contains_region(next_region)) {
-        return false;
-      }
-    }
-    return true;
-  }
-
-  virtual bool is_dup_pointer(const MemPointer* ptr1,
-    const MemPointer* ptr2) const {
-    VMMemRegion* p1 = (VMMemRegion*)ptr1;
-    VMMemRegion* p2 = (VMMemRegion*)ptr2;
-
-    if (p1->addr() != p2->addr()) return false;
-    if ((p1->flags() & MemPointerRecord::tag_masks) !=
-        (p2->flags() & MemPointerRecord::tag_masks)) {
-      return false;
-    }
-    // we do see multiple commit/uncommit on the same memory, it is ok
-    return (p1->flags() & MemPointerRecord::tag_masks) == MemPointerRecord::tag_alloc ||
-           (p1->flags() & MemPointerRecord::tag_masks) == MemPointerRecord::tag_release;
-  }
-#endif
-};
-
-class MallocRecordIterator : public MemPointerArrayIterator {
- private:
-  MemPointerArrayIteratorImpl  _itr;
-
-
-
- public:
-  MallocRecordIterator(MemPointerArray* arr) : _itr(arr) {
-  }
-
-  virtual MemPointer* current() const {
-#ifdef ASSERT
-    MemPointer* cur_rec = _itr.current();
-    if (cur_rec != NULL) {
-      MemPointer* prev_rec = _itr.peek_prev();
-      MemPointer* next_rec = _itr.peek_next();
-      assert(prev_rec == NULL || prev_rec->addr() < cur_rec->addr(), "Sorting order");
-      assert(next_rec == NULL || next_rec->addr() > cur_rec->addr(), "Sorting order");
-    }
-#endif
-    return _itr.current();
-  }
-  virtual MemPointer* next() {
-    MemPointerRecord* next_rec = (MemPointerRecord*)_itr.next();
-    // arena memory record is a special case, which we have to compare
-    // sequence number against its associated arena record.
-    if (next_rec != NULL && next_rec->is_arena_memory_record()) {
-      MemPointerRecord* prev_rec = (MemPointerRecord*)_itr.peek_prev();
-      // if there is an associated arena record, it has to be previous
-      // record because of sorting order (by address) - NMT generates a pseudo address
-      // for arena's size record by offsetting arena's address, that guarantees
-      // the order of arena record and it's size record.
-      if (prev_rec != NULL && prev_rec->is_arena_record() &&
-        next_rec->is_memory_record_of_arena(prev_rec)) {
-        if (prev_rec->seq() > next_rec->seq()) {
-          // Skip this arena memory record
-          // Two scenarios:
-          //   - if the arena record is an allocation record, this early
-          //     size record must be leftover by previous arena,
-          //     and the last size record should have size = 0.
-          //   - if the arena record is a deallocation record, this
-          //     size record should be its cleanup record, which should
-          //     also have size = 0. In other world, arena alway reset
-          //     its size before gone (see Arena's destructor)
-          assert(next_rec->size() == 0, "size not reset");
-          return _itr.next();
-        } else {
-          assert(prev_rec->is_allocation_record(),
-            "Arena size record ahead of allocation record");
-        }
-      }
-    }
-    return next_rec;
-  }
-
-  MemPointer* peek_next() const      { ShouldNotReachHere(); return NULL; }
-  MemPointer* peek_prev() const      { ShouldNotReachHere(); return NULL; }
-  void remove()                      { ShouldNotReachHere(); }
-  bool insert(MemPointer* ptr)       { ShouldNotReachHere(); return false; }
-  bool insert_after(MemPointer* ptr) { ShouldNotReachHere(); return false; }
-};
-
-// collapse duplicated records. Eliminating duplicated records here, is much
-// cheaper than during promotion phase. However, it does have limitation - it
-// can only eliminate duplicated records within the generation, there are
-// still chances seeing duplicated records during promotion.
-// We want to use the record with higher sequence number, because it has
-// more accurate callsite pc.
-class VMRecordIterator : public MemPointerArrayIterator {
- private:
-  MemPointerArrayIteratorImpl  _itr;
-
- public:
-  VMRecordIterator(MemPointerArray* arr) : _itr(arr) {
-    MemPointerRecord* cur = (MemPointerRecord*)_itr.current();
-    MemPointerRecord* next = (MemPointerRecord*)_itr.peek_next();
-    while (next != NULL) {
-      assert(cur != NULL, "Sanity check");
-      assert(((SeqMemPointerRecord*)next)->seq() > ((SeqMemPointerRecord*)cur)->seq(),
-        "pre-sort order");
-
-      if (is_duplicated_record(cur, next)) {
-        _itr.next();
-        next = (MemPointerRecord*)_itr.peek_next();
-      } else {
-        break;
-      }
-    }
-  }
-
-  virtual MemPointer* current() const {
-    return _itr.current();
-  }
-
-  // get next record, but skip the duplicated records
-  virtual MemPointer* next() {
-    MemPointerRecord* cur = (MemPointerRecord*)_itr.next();
-    MemPointerRecord* next = (MemPointerRecord*)_itr.peek_next();
-    while (next != NULL) {
-      assert(cur != NULL, "Sanity check");
-      assert(((SeqMemPointerRecord*)next)->seq() > ((SeqMemPointerRecord*)cur)->seq(),
-        "pre-sort order");
-
-      if (is_duplicated_record(cur, next)) {
-        _itr.next();
-        cur = next;
-        next = (MemPointerRecord*)_itr.peek_next();
-      } else {
-        break;
-      }
-    }
-    return cur;
-  }
-
-  MemPointer* peek_next() const      { ShouldNotReachHere(); return NULL; }
-  MemPointer* peek_prev() const      { ShouldNotReachHere(); return NULL; }
-  void remove()                      { ShouldNotReachHere(); }
-  bool insert(MemPointer* ptr)       { ShouldNotReachHere(); return false; }
-  bool insert_after(MemPointer* ptr) { ShouldNotReachHere(); return false; }
-
- private:
-  bool is_duplicated_record(MemPointerRecord* p1, MemPointerRecord* p2) const {
-    bool ret = (p1->addr() == p2->addr() && p1->size() == p2->size() && p1->flags() == p2->flags());
-    assert(!(ret && FLAGS_TO_MEMORY_TYPE(p1->flags()) == mtThreadStack), "dup on stack record");
-    return ret;
-  }
-};
-
-class StagingArea VALUE_OBJ_CLASS_SPEC {
- private:
-  MemPointerArray*   _malloc_data;
-  MemPointerArray*   _vm_data;
-
- public:
-  StagingArea() : _malloc_data(NULL), _vm_data(NULL) {
-    init();
-  }
-
-  ~StagingArea() {
-    if (_malloc_data != NULL) delete _malloc_data;
-    if (_vm_data != NULL) delete _vm_data;
-  }
-
-  MallocRecordIterator malloc_record_walker() {
-    return MallocRecordIterator(malloc_data());
-  }
-
-  VMRecordIterator virtual_memory_record_walker();
-
-  bool init();
-  void clear() {
-    assert(_malloc_data != NULL && _vm_data != NULL, "Just check");
-    _malloc_data->shrink();
-    _malloc_data->clear();
-    _vm_data->clear();
-  }
-
-  inline MemPointerArray* malloc_data() { return _malloc_data; }
-  inline MemPointerArray* vm_data()     { return _vm_data; }
-};
-
-class MemBaseline;
-class MemSnapshot : public CHeapObj<mtNMT> {
- private:
-  // the following two arrays contain records of all known lived memory blocks
-  // live malloc-ed memory pointers
-  MemPointerArray*      _alloc_ptrs;
-  // live virtual memory pointers
-  MemPointerArray*      _vm_ptrs;
-
-  StagingArea           _staging_area;
-
-  // the lock to protect this snapshot
-  Monitor*              _lock;
-
-  // the number of instance classes
-  int                   _number_of_classes;
-
-  NOT_PRODUCT(size_t    _untracked_count;)
-  friend class MemBaseline;
-
- public:
-  MemSnapshot();
-  virtual ~MemSnapshot();
-
-  // if we are running out of native memory
-  bool out_of_memory() {
-    return (_alloc_ptrs == NULL ||
-      _staging_area.malloc_data() == NULL ||
-      _staging_area.vm_data() == NULL ||
-      _vm_ptrs == NULL || _lock == NULL ||
-      _alloc_ptrs->out_of_memory() ||
-      _vm_ptrs->out_of_memory());
-  }
-
-  // merge a per-thread memory recorder into staging area
-  bool merge(MemRecorder* rec);
-  // promote staged data to snapshot
-  bool promote(int number_of_classes);
-
-  int  number_of_classes() const { return _number_of_classes; }
-
-  void wait(long timeout) {
-    assert(_lock != NULL, "Just check");
-    MonitorLockerEx locker(_lock);
-    locker.wait(true, timeout);
-  }
-
-  NOT_PRODUCT(void print_snapshot_stats(outputStream* st);)
-  NOT_PRODUCT(void check_staging_data();)
-  NOT_PRODUCT(void check_malloc_pointers();)
-  NOT_PRODUCT(bool has_allocation_record(address addr);)
-  // dump all virtual memory pointers in snapshot
-  DEBUG_ONLY( void dump_all_vm_pointers();)
-
- private:
-   // copy sequenced pointer from src to dest
-   void copy_seq_pointer(MemPointerRecord* dest, const MemPointerRecord* src);
-   // assign a sequenced pointer to non-sequenced pointer
-   void assign_pointer(MemPointerRecord*dest, const MemPointerRecord* src);
-
-   bool promote_malloc_records(MemPointerArrayIterator* itr);
-   bool promote_virtual_memory_records(MemPointerArrayIterator* itr);
-};
-
-#endif // SHARE_VM_SERVICES_MEM_SNAPSHOT_HPP
--- a/src/share/vm/services/memTrackWorker.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,212 +0,0 @@
-/*
- * Copyright (c) 2013, 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 "runtime/threadCritical.hpp"
-#include "services/memTracker.hpp"
-#include "services/memTrackWorker.hpp"
-#include "utilities/decoder.hpp"
-#include "utilities/vmError.hpp"
-
-
-void GenerationData::reset() {
-  _number_of_classes = 0;
-  while (_recorder_list != NULL) {
-    MemRecorder* tmp = _recorder_list;
-    _recorder_list = _recorder_list->next();
-    MemTracker::release_thread_recorder(tmp);
-  }
-}
-
-MemTrackWorker::MemTrackWorker(MemSnapshot* snapshot): _snapshot(snapshot) {
-  // create thread uses cgc thread type for now. We should revisit
-  // the option, or create new thread type.
-  _has_error = !os::create_thread(this, os::cgc_thread);
-  set_name("MemTrackWorker");
-
-  // initial generation circuit buffer
-  if (!has_error()) {
-    _head = _tail = 0;
-    for(int index = 0; index < MAX_GENERATIONS; index ++) {
-      ::new ((void*)&_gen[index]) GenerationData();
-    }
-  }
-  NOT_PRODUCT(_sync_point_count = 0;)
-  NOT_PRODUCT(_merge_count = 0;)
-  NOT_PRODUCT(_last_gen_in_use = 0;)
-}
-
-MemTrackWorker::~MemTrackWorker() {
-  for (int index = 0; index < MAX_GENERATIONS; index ++) {
-    _gen[index].reset();
-  }
-}
-
-void* MemTrackWorker::operator new(size_t size) throw() {
-  assert(false, "use nothrow version");
-  return NULL;
-}
-
-void* MemTrackWorker::operator new(size_t size, const std::nothrow_t& nothrow_constant) throw() {
-  return allocate(size, false, mtNMT);
-}
-
-void MemTrackWorker::start() {
-  os::start_thread(this);
-}
-
-/*
- * Native memory tracking worker thread loop:
- *   1. merge one generation of memory recorders to staging area
- *   2. promote staging data to memory snapshot
- *
- * This thread can run through safepoint.
- */
-
-void MemTrackWorker::run() {
-  assert(MemTracker::is_on(), "native memory tracking is off");
-  this->initialize_thread_local_storage();
-  this->record_stack_base_and_size();
-  assert(_snapshot != NULL, "Worker should not be started");
-  MemRecorder* rec;
-  unsigned long processing_generation = 0;
-  bool          worker_idle = false;
-
-  while (!MemTracker::shutdown_in_progress()) {
-    NOT_PRODUCT(_last_gen_in_use = generations_in_use();)
-    {
-      // take a recorder from earliest generation in buffer
-      ThreadCritical tc;
-      rec = _gen[_head].next_recorder();
-    }
-    if (rec != NULL) {
-      if (rec->get_generation() != processing_generation || worker_idle) {
-        processing_generation = rec->get_generation();
-        worker_idle = false;
-        MemTracker::set_current_processing_generation(processing_generation);
-      }
-
-      // merge the recorder into staging area
-      if (!_snapshot->merge(rec)) {
-        MemTracker::shutdown(MemTracker::NMT_out_of_memory);
-      } else {
-        NOT_PRODUCT(_merge_count ++;)
-      }
-      MemTracker::release_thread_recorder(rec);
-    } else {
-      // no more recorder to merge, promote staging area
-      // to snapshot
-      if (_head != _tail) {
-        long number_of_classes;
-        {
-          ThreadCritical tc;
-          if (_gen[_head].has_more_recorder() || _head == _tail) {
-            continue;
-          }
-          number_of_classes = _gen[_head].number_of_classes();
-          _gen[_head].reset();
-
-          // done with this generation, increment _head pointer
-          _head = (_head + 1) % MAX_GENERATIONS;
-        }
-        // promote this generation data to snapshot
-        if (!_snapshot->promote(number_of_classes)) {
-          // failed to promote, means out of memory
-          MemTracker::shutdown(MemTracker::NMT_out_of_memory);
-        }
-      } else {
-        // worker thread is idle
-        worker_idle = true;
-        MemTracker::report_worker_idle();
-        _snapshot->wait(1000);
-        ThreadCritical tc;
-        // check if more data arrived
-        if (!_gen[_head].has_more_recorder()) {
-          _gen[_head].add_recorders(MemTracker::get_pending_recorders());
-        }
-      }
-    }
-  }
-  assert(MemTracker::shutdown_in_progress(), "just check");
-
-  // transits to final shutdown
-  MemTracker::final_shutdown();
-}
-
-// at synchronization point, where 'safepoint visible' Java threads are blocked
-// at a safepoint, and the rest of threads are blocked on ThreadCritical lock.
-// The caller MemTracker::sync() already takes ThreadCritical before calling this
-// method.
-//
-// Following tasks are performed:
-//   1. add all recorders in pending queue to current generation
-//   2. increase generation
-
-void MemTrackWorker::at_sync_point(MemRecorder* rec, int number_of_classes) {
-  NOT_PRODUCT(_sync_point_count ++;)
-  assert(count_recorder(rec) <= MemRecorder::_instance_count,
-    "pending queue has infinite loop");
-
-  bool out_of_generation_buffer = false;
-  // check shutdown state inside ThreadCritical
-  if (MemTracker::shutdown_in_progress()) return;
-
-  _gen[_tail].set_number_of_classes(number_of_classes);
-  // append the recorders to the end of the generation
-  _gen[_tail].add_recorders(rec);
-  assert(count_recorder(_gen[_tail].peek()) <= MemRecorder::_instance_count,
-    "after add to current generation has infinite loop");
-  // we have collected all recorders for this generation. If there is data,
-  // we need to increment _tail to start a new generation.
-  if (_gen[_tail].has_more_recorder()  || _head == _tail) {
-    _tail = (_tail + 1) % MAX_GENERATIONS;
-    out_of_generation_buffer = (_tail == _head);
-  }
-
-  if (out_of_generation_buffer) {
-    MemTracker::shutdown(MemTracker::NMT_out_of_generation);
-  }
-}
-
-#ifndef PRODUCT
-int MemTrackWorker::count_recorder(const MemRecorder* head) {
-  int count = 0;
-  while(head != NULL) {
-    count ++;
-    head = head->next();
-  }
-  return count;
-}
-
-int MemTrackWorker::count_pending_recorders() const {
-  int count = 0;
-  for (int index = 0; index < MAX_GENERATIONS; index ++) {
-    MemRecorder* head = _gen[index].peek();
-    if (head != NULL) {
-      count += count_recorder(head);
-    }
-  }
-  return count;
-}
-#endif
--- a/src/share/vm/services/memTrackWorker.hpp	Thu Sep 04 13:06:04 2014 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,118 +0,0 @@
-/*
- * Copyright (c) 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_SERVICES_MEM_TRACK_WORKER_HPP
-#define SHARE_VM_SERVICES_MEM_TRACK_WORKER_HPP
-
-#include "memory/allocation.hpp"
-#include "runtime/thread.hpp"
-#include "services/memRecorder.hpp"
-
-// Maximum MAX_GENERATIONS generation data can be tracked.
-#define MAX_GENERATIONS  512
-
-class GenerationData VALUE_OBJ_CLASS_SPEC {
- private:
-  int           _number_of_classes;
-  MemRecorder*  _recorder_list;
-
- public:
-  GenerationData(): _number_of_classes(0), _recorder_list(NULL) { }
-
-  inline int  number_of_classes() const { return _number_of_classes; }
-  inline void set_number_of_classes(long num) { _number_of_classes = num; }
-
-  inline MemRecorder* next_recorder() {
-    if (_recorder_list == NULL) {
-      return NULL;
-    } else {
-      MemRecorder* tmp = _recorder_list;
-      _recorder_list = _recorder_list->next();
-      return tmp;
-    }
-  }
-
-  inline bool has_more_recorder() const {
-    return (_recorder_list != NULL);
-  }
-
-  // add recorders to this generation
-  void add_recorders(MemRecorder* head) {
-    if (head != NULL) {
-      if (_recorder_list == NULL) {
-        _recorder_list = head;
-      } else {
-        MemRecorder* tmp = _recorder_list;
-        for (; tmp->next() != NULL; tmp = tmp->next());
-        tmp->set_next(head);
-      }
-    }
-  }
-
-  void reset();
-
-  NOT_PRODUCT(MemRecorder* peek() const { return _recorder_list; })
-};
-
-class MemTrackWorker : public NamedThread {
- private:
-  // circular buffer. This buffer contains generation data to be merged into global
-  // snaphsot.
-  // Each slot holds a generation
-  GenerationData  _gen[MAX_GENERATIONS];
-  int             _head, _tail; // head and tail pointers to above circular buffer
-
-  bool            _has_error;
-
-  MemSnapshot*    _snapshot;
-
- public:
-  MemTrackWorker(MemSnapshot* snapshot);
-  ~MemTrackWorker();
-  _NOINLINE_ void* operator new(size_t size) throw();
-  _NOINLINE_ void* operator new(size_t size, const std::nothrow_t& nothrow_constant) throw();
-
-  void start();
-  void run();
-
-  inline bool has_error() const { return _has_error; }
-
-  // task at synchronization point
-  void at_sync_point(MemRecorder* pending_recorders, int number_of_classes);
-
-  // for debugging purpose, they are not thread safe.
-  NOT_PRODUCT(static int count_recorder(const MemRecorder* head);)
-  NOT_PRODUCT(int count_pending_recorders() const;)
-
-  NOT_PRODUCT(int _sync_point_count;)
-  NOT_PRODUCT(int _merge_count;)
-  NOT_PRODUCT(int _last_gen_in_use;)
-
-  // how many generations are queued
-  inline int generations_in_use() const {
-    return (_tail >= _head ? (_tail - _head + 1) : (MAX_GENERATIONS - (_head - _tail) + 1));
-  }
-};
-
-#endif // SHARE_VM_SERVICES_MEM_TRACK_WORKER_HPP
--- a/src/share/vm/services/memTracker.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/services/memTracker.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 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
@@ -23,862 +23,315 @@
  */
 #include "precompiled.hpp"
 
-#include "oops/instanceKlass.hpp"
-#include "runtime/atomic.hpp"
-#include "runtime/interfaceSupport.hpp"
-#include "runtime/mutexLocker.hpp"
-#include "runtime/safepoint.hpp"
-#include "runtime/threadCritical.hpp"
-#include "runtime/thread.inline.hpp"
-#include "runtime/vm_operations.hpp"
-#include "services/memPtr.hpp"
+#include "runtime/mutex.hpp"
+#include "services/memBaseline.hpp"
 #include "services/memReporter.hpp"
+#include "services/mallocTracker.inline.hpp"
 #include "services/memTracker.hpp"
-#include "utilities/decoder.hpp"
 #include "utilities/defaultStream.hpp"
-#include "utilities/globalDefinitions.hpp"
 
-bool NMT_track_callsite = false;
+#ifdef SOLARIS
+  volatile bool NMT_stack_walkable = false;
+#else
+  volatile bool NMT_stack_walkable = true;
+#endif
 
-// walk all 'known' threads at NMT sync point, and collect their recorders
-void SyncThreadRecorderClosure::do_thread(Thread* thread) {
-  assert(SafepointSynchronize::is_at_safepoint(), "Safepoint required");
-  if (thread->is_Java_thread()) {
-    JavaThread* javaThread = (JavaThread*)thread;
-    MemRecorder* recorder = javaThread->get_recorder();
-    if (recorder != NULL) {
-      MemTracker::enqueue_pending_recorder(recorder);
-      javaThread->set_recorder(NULL);
-    }
-  }
-  _thread_count ++;
-}
+volatile NMT_TrackingLevel MemTracker::_tracking_level = NMT_unknown;
+NMT_TrackingLevel MemTracker::_cmdline_tracking_level = NMT_unknown;
+
+MemBaseline MemTracker::_baseline;
+Mutex*      MemTracker::_query_lock = NULL;
+bool MemTracker::_is_nmt_env_valid = true;
 
 
-MemRecorder* volatile           MemTracker::_global_recorder = NULL;
-MemSnapshot*                    MemTracker::_snapshot = NULL;
-MemBaseline                     MemTracker::_baseline;
-Mutex*                          MemTracker::_query_lock = NULL;
-MemRecorder* volatile           MemTracker::_merge_pending_queue = NULL;
-MemRecorder* volatile           MemTracker::_pooled_recorders = NULL;
-MemTrackWorker*                 MemTracker::_worker_thread = NULL;
-int                             MemTracker::_sync_point_skip_count = 0;
-MemTracker::NMTLevel            MemTracker::_tracking_level = MemTracker::NMT_off;
-volatile MemTracker::NMTStates  MemTracker::_state = NMT_uninited;
-MemTracker::ShutdownReason      MemTracker::_reason = NMT_shutdown_none;
-int                             MemTracker::_thread_count = 255;
-volatile jint                   MemTracker::_pooled_recorder_count = 0;
-volatile unsigned long          MemTracker::_processing_generation = 0;
-volatile bool                   MemTracker::_worker_thread_idle = false;
-volatile jint                   MemTracker::_pending_op_count = 0;
-volatile bool                   MemTracker::_slowdown_calling_thread = false;
-debug_only(intx                 MemTracker::_main_thread_tid = 0;)
-NOT_PRODUCT(volatile jint       MemTracker::_pending_recorder_count = 0;)
-
-void MemTracker::init_tracking_options(const char* option_line) {
-  _tracking_level = NMT_off;
-  if (strcmp(option_line, "=summary") == 0) {
-    _tracking_level = NMT_summary;
-  } else if (strcmp(option_line, "=detail") == 0) {
-    // detail relies on a stack-walking ability that may not
-    // be available depending on platform and/or compiler flags
+NMT_TrackingLevel MemTracker::init_tracking_level() {
+  NMT_TrackingLevel level = NMT_off;
+  char buf[64];
+  char nmt_option[64];
+  jio_snprintf(buf, sizeof(buf), "NMT_LEVEL_%d", os::current_process_id());
+  if (os::getenv(buf, nmt_option, sizeof(nmt_option))) {
+    if (strcmp(nmt_option, "summary") == 0) {
+      level = NMT_summary;
+    } else if (strcmp(nmt_option, "detail") == 0) {
 #if PLATFORM_NATIVE_STACK_WALKING_SUPPORTED
-      _tracking_level = NMT_detail;
+      level = NMT_detail;
 #else
-      jio_fprintf(defaultStream::error_stream(),
-        "NMT detail is not supported on this platform.  Using NMT summary instead.\n");
-      _tracking_level = NMT_summary;
-#endif
-  } else if (strcmp(option_line, "=off") != 0) {
-    vm_exit_during_initialization("Syntax error, expecting -XX:NativeMemoryTracking=[off|summary|detail]", NULL);
-  }
-}
-
-// first phase of bootstrapping, when VM is still in single-threaded mode.
-void MemTracker::bootstrap_single_thread() {
-  if (_tracking_level > NMT_off) {
-    assert(_state == NMT_uninited, "wrong state");
-
-    // NMT is not supported with UseMallocOnly is on. NMT can NOT
-    // handle the amount of malloc data without significantly impacting
-    // runtime performance when this flag is on.
-    if (UseMallocOnly) {
-      shutdown(NMT_use_malloc_only);
-      return;
+      level = NMT_summary;
+#endif // PLATFORM_NATIVE_STACK_WALKING_SUPPORTED
+    } else if (strcmp(nmt_option, "off") != 0) {
+      // The option value is invalid
+      _is_nmt_env_valid = false;
     }
 
-    _query_lock = new (std::nothrow) Mutex(Monitor::max_nonleaf, "NMT_queryLock");
-    if (_query_lock == NULL) {
-      shutdown(NMT_out_of_memory);
-      return;
-    }
+    // Remove the environment variable to avoid leaking to child processes
+    os::unsetenv(buf);
+  }
 
-    debug_only(_main_thread_tid = os::current_thread_id();)
-    _state = NMT_bootstrapping_single_thread;
-    NMT_track_callsite = (_tracking_level == NMT_detail && can_walk_stack());
+  // Construct NativeCallStack::EMPTY_STACK. It may get constructed twice,
+  // but it is benign, the results are the same.
+  ::new ((void*)&NativeCallStack::EMPTY_STACK) NativeCallStack(0, false);
+
+  if (!MallocTracker::initialize(level) ||
+      !VirtualMemoryTracker::initialize(level)) {
+    level = NMT_off;
   }
+  return level;
 }
 
-// second phase of bootstrapping, when VM is about to or already entered multi-theaded mode.
-void MemTracker::bootstrap_multi_thread() {
-  if (_tracking_level > NMT_off && _state == NMT_bootstrapping_single_thread) {
-  // create nmt lock for multi-thread execution
-    assert(_main_thread_tid == os::current_thread_id(), "wrong thread");
-    _state = NMT_bootstrapping_multi_thread;
-    NMT_track_callsite = (_tracking_level == NMT_detail && can_walk_stack());
-  }
-}
-
-// fully start nmt
-void MemTracker::start() {
-  // Native memory tracking is off from command line option
-  if (_tracking_level == NMT_off || shutdown_in_progress()) return;
-
-  assert(_main_thread_tid == os::current_thread_id(), "wrong thread");
-  assert(_state == NMT_bootstrapping_multi_thread, "wrong state");
-
-  _snapshot = new (std::nothrow)MemSnapshot();
-  if (_snapshot != NULL) {
-    if (!_snapshot->out_of_memory() && start_worker(_snapshot)) {
-      _state = NMT_started;
-      NMT_track_callsite = (_tracking_level == NMT_detail && can_walk_stack());
+void MemTracker::init() {
+  NMT_TrackingLevel level = tracking_level();
+  if (level >= NMT_summary) {
+    if (!VirtualMemoryTracker::late_initialize(level)) {
+      shutdown();
       return;
     }
-
-    delete _snapshot;
-    _snapshot = NULL;
-  }
-
-  // fail to start native memory tracking, shut it down
-  shutdown(NMT_initialization);
-}
-
-/**
- * Shutting down native memory tracking.
- * We can not shutdown native memory tracking immediately, so we just
- * setup shutdown pending flag, every native memory tracking component
- * should orderly shut itself down.
- *
- * The shutdown sequences:
- *  1. MemTracker::shutdown() sets MemTracker to shutdown pending state
- *  2. Worker thread calls MemTracker::final_shutdown(), which transites
- *     MemTracker to final shutdown state.
- *  3. At sync point, MemTracker does final cleanup, before sets memory
- *     tracking level to off to complete shutdown.
- */
-void MemTracker::shutdown(ShutdownReason reason) {
-  if (_tracking_level == NMT_off) return;
-
-  if (_state <= NMT_bootstrapping_single_thread) {
-    // we still in single thread mode, there is not contention
-    _state = NMT_shutdown_pending;
-    _reason = reason;
-  } else {
-    // we want to know who initialized shutdown
-    if ((jint)NMT_started == Atomic::cmpxchg((jint)NMT_shutdown_pending,
-                                       (jint*)&_state, (jint)NMT_started)) {
-        _reason = reason;
-    }
-  }
-}
-
-// final phase of shutdown
-void MemTracker::final_shutdown() {
-  // delete all pending recorders and pooled recorders
-  delete_all_pending_recorders();
-  delete_all_pooled_recorders();
-
-  {
-    // shared baseline and snapshot are the only objects needed to
-    // create query results
-    MutexLockerEx locker(_query_lock, true);
-    // cleanup baseline data and snapshot
-    _baseline.clear();
-    delete _snapshot;
-    _snapshot = NULL;
-  }
-
-  // shutdown shared decoder instance, since it is only
-  // used by native memory tracking so far.
-  Decoder::shutdown();
-
-  MemTrackWorker* worker = NULL;
-  {
-    ThreadCritical tc;
-    // can not delete worker inside the thread critical
-    if (_worker_thread != NULL && Thread::current() == _worker_thread) {
-      worker = _worker_thread;
-      _worker_thread = NULL;
-    }
-  }
-  if (worker != NULL) {
-    delete worker;
-  }
-  _state = NMT_final_shutdown;
-}
-
-// delete all pooled recorders
-void MemTracker::delete_all_pooled_recorders() {
-  // free all pooled recorders
-  MemRecorder* volatile cur_head = _pooled_recorders;
-  if (cur_head != NULL) {
-    MemRecorder* null_ptr = NULL;
-    while (cur_head != NULL && (void*)cur_head != Atomic::cmpxchg_ptr((void*)null_ptr,
-      (void*)&_pooled_recorders, (void*)cur_head)) {
-      cur_head = _pooled_recorders;
-    }
-    if (cur_head != NULL) {
-      delete cur_head;
-      _pooled_recorder_count = 0;
+    _query_lock = new (std::nothrow) Mutex(Monitor::max_nonleaf, "NMT_queryLock");
+    // Already OOM. It is unlikely, but still have to handle it.
+    if (_query_lock == NULL) {
+      shutdown();
     }
   }
 }
 
-// delete all recorders in pending queue
-void MemTracker::delete_all_pending_recorders() {
-  // free all pending recorders
-  MemRecorder* pending_head = get_pending_recorders();
-  if (pending_head != NULL) {
-    delete pending_head;
+bool MemTracker::check_launcher_nmt_support(const char* value) {
+  if (strcmp(value, "=detail") == 0) {
+#if !PLATFORM_NATIVE_STACK_WALKING_SUPPORTED
+      jio_fprintf(defaultStream::error_stream(),
+        "NMT detail is not supported on this platform.  Using NMT summary instead.\n");
+    if (MemTracker::tracking_level() != NMT_summary) {
+    return false;
+  }
+#else
+    if (MemTracker::tracking_level() != NMT_detail) {
+      return false;
+    }
+#endif
+  } else if (strcmp(value, "=summary") == 0) {
+    if (MemTracker::tracking_level() != NMT_summary) {
+      return false;
+    }
+  } else if (strcmp(value, "=off") == 0) {
+    if (MemTracker::tracking_level() != NMT_off) {
+      return false;
+    }
+  } else {
+    _is_nmt_env_valid = false;
+  }
+
+  return true;
+}
+
+bool MemTracker::verify_nmt_option() {
+  return _is_nmt_env_valid;
+}
+
+void* MemTracker::malloc_base(void* memblock) {
+  return MallocTracker::get_base(memblock);
+}
+
+void Tracker::record(address addr, size_t size) {
+  if (MemTracker::tracking_level() < NMT_summary) return;
+  switch(_type) {
+    case uncommit:
+      VirtualMemoryTracker::remove_uncommitted_region(addr, size);
+      break;
+    case release:
+      VirtualMemoryTracker::remove_released_region(addr, size);
+        break;
+    default:
+      ShouldNotReachHere();
   }
 }
 
-/*
- * retrieve per-thread recorder of specified thread.
- * if thread == NULL, it means global recorder
- */
-MemRecorder* MemTracker::get_thread_recorder(JavaThread* thread) {
-  if (shutdown_in_progress()) return NULL;
+
+// Shutdown can only be issued via JCmd, and NMT JCmd is serialized
+// by lock
+void MemTracker::shutdown() {
+  // We can only shutdown NMT to minimal tracking level if it is
+  // ever on.
+  if (tracking_level () > NMT_minimal) {
+    transition_to(NMT_minimal);
+  }
+}
+
+bool MemTracker::transition_to(NMT_TrackingLevel level) {
+  NMT_TrackingLevel current_level = tracking_level();
 
-  MemRecorder* rc;
-  if (thread == NULL) {
-    rc = _global_recorder;
+  if (current_level == level) {
+    return true;
+  } else if (current_level > level) {
+    // Downgrade tracking level, we want to lower the tracking
+    // level first
+    _tracking_level = level;
+    // Make _tracking_level visible immediately.
+    OrderAccess::fence();
+    VirtualMemoryTracker::transition(current_level, level);
+    MallocTracker::transition(current_level, level);
+
+    if (level == NMT_minimal) _baseline.reset();
   } else {
-    rc = thread->get_recorder();
-  }
+    VirtualMemoryTracker::transition(current_level, level);
+    MallocTracker::transition(current_level, level);
 
-  if (rc != NULL && rc->is_full()) {
-    enqueue_pending_recorder(rc);
-    rc = NULL;
+    _tracking_level = level;
+    // Make _tracking_level visible immediately.
+    OrderAccess::fence();
   }
 
-  if (rc == NULL) {
-    rc = get_new_or_pooled_instance();
-    if (thread == NULL) {
-      _global_recorder = rc;
-    } else {
-      thread->set_recorder(rc);
-    }
-  }
-  return rc;
+  return true;
 }
 
-/*
- * get a per-thread recorder from pool, or create a new one if
- * there is not one available.
- */
-MemRecorder* MemTracker::get_new_or_pooled_instance() {
-   MemRecorder* cur_head = const_cast<MemRecorder*> (_pooled_recorders);
-   if (cur_head == NULL) {
-     MemRecorder* rec = new (std::nothrow)MemRecorder();
-     if (rec == NULL || rec->out_of_memory()) {
-       shutdown(NMT_out_of_memory);
-       if (rec != NULL) {
-         delete rec;
-         rec = NULL;
-       }
-     }
-     return rec;
-   } else {
-     MemRecorder* next_head = cur_head->next();
-     if ((void*)cur_head != Atomic::cmpxchg_ptr((void*)next_head, (void*)&_pooled_recorders,
-       (void*)cur_head)) {
-       return get_new_or_pooled_instance();
-     }
-     cur_head->set_next(NULL);
-     Atomic::dec(&_pooled_recorder_count);
-     cur_head->set_generation();
-     return cur_head;
+void MemTracker::final_report(outputStream* output) {
+  assert(output != NULL, "No output stream");
+  if (tracking_level() >= NMT_summary) {
+    MallocMemorySnapshot* malloc_memory_snapshot =
+      MallocMemorySummary::as_snapshot();
+    malloc_memory_snapshot->make_adjustment();
+
+    VirtualMemorySnapshot* virtual_memory_snapshot =
+      VirtualMemorySummary::as_snapshot();
+
+    MemSummaryReporter rptr(malloc_memory_snapshot,
+      virtual_memory_snapshot, output);
+    rptr.report();
+    // shutdown NMT, the data no longer accurate
+    shutdown();
   }
 }
 
-/*
- * retrieve all recorders in pending queue, and empty the queue
- */
-MemRecorder* MemTracker::get_pending_recorders() {
-  MemRecorder* cur_head = const_cast<MemRecorder*>(_merge_pending_queue);
-  MemRecorder* null_ptr = NULL;
-  while ((void*)cur_head != Atomic::cmpxchg_ptr((void*)null_ptr, (void*)&_merge_pending_queue,
-    (void*)cur_head)) {
-    cur_head = const_cast<MemRecorder*>(_merge_pending_queue);
-  }
-  NOT_PRODUCT(Atomic::store(0, &_pending_recorder_count));
-  return cur_head;
-}
+// This is a walker to gather malloc site hashtable statistics,
+// the result is used for tuning.
+class StatisticsWalker : public MallocSiteWalker {
+ private:
+  enum Threshold {
+    // aggregates statistics over this threshold into one
+    // line item.
+    report_threshold = 20
+  };
 
-/*
- * release a recorder to recorder pool.
- */
-void MemTracker::release_thread_recorder(MemRecorder* rec) {
-  assert(rec != NULL, "null recorder");
-  // we don't want to pool too many recorders
-  rec->set_next(NULL);
-  if (shutdown_in_progress() || _pooled_recorder_count > _thread_count * 2) {
-    delete rec;
-    return;
-  }
+ private:
+  // Number of allocation sites that have all memory freed
+  int   _empty_entries;
+  // Total number of allocation sites, include empty sites
+  int   _total_entries;
+  // Number of captured call stack distribution
+  int   _stack_depth_distribution[NMT_TrackingStackDepth];
+  // Hash distribution
+  int   _hash_distribution[report_threshold];
+  // Number of hash buckets that have entries over the threshold
+  int   _bucket_over_threshold;
 
-  rec->clear();
-  MemRecorder* cur_head = const_cast<MemRecorder*>(_pooled_recorders);
-  rec->set_next(cur_head);
-  while ((void*)cur_head != Atomic::cmpxchg_ptr((void*)rec, (void*)&_pooled_recorders,
-    (void*)cur_head)) {
-    cur_head = const_cast<MemRecorder*>(_pooled_recorders);
-    rec->set_next(cur_head);
-  }
-  Atomic::inc(&_pooled_recorder_count);
-}
-
-// write a record to proper recorder. No lock can be taken from this method
-// down.
-void MemTracker::write_tracking_record(address addr, MEMFLAGS flags,
-    size_t size, jint seq, address pc, JavaThread* thread) {
+  // The hash bucket that walker is currently walking
+  int   _current_hash_bucket;
+  // The length of current hash bucket
+  int   _current_bucket_length;
+  // Number of hash buckets that are not empty
+  int   _used_buckets;
+  // Longest hash bucket length
+  int   _longest_bucket_length;
 
-    MemRecorder* rc = get_thread_recorder(thread);
-    if (rc != NULL) {
-      rc->record(addr, flags, size, seq, pc);
+ public:
+  StatisticsWalker() : _empty_entries(0), _total_entries(0) {
+    int index = 0;
+    for (index = 0; index < NMT_TrackingStackDepth; index ++) {
+      _stack_depth_distribution[index] = 0;
     }
-}
-
-/**
- * enqueue a recorder to pending queue
- */
-void MemTracker::enqueue_pending_recorder(MemRecorder* rec) {
-  assert(rec != NULL, "null recorder");
-
-  // we are shutting down, so just delete it
-  if (shutdown_in_progress()) {
-    rec->set_next(NULL);
-    delete rec;
-    return;
+    for (index = 0; index < report_threshold; index ++) {
+      _hash_distribution[index] = 0;
+    }
+    _bucket_over_threshold = 0;
+    _longest_bucket_length = 0;
+    _current_hash_bucket = -1;
+    _current_bucket_length = 0;
+    _used_buckets = 0;
   }
 
-  MemRecorder* cur_head = const_cast<MemRecorder*>(_merge_pending_queue);
-  rec->set_next(cur_head);
-  while ((void*)cur_head != Atomic::cmpxchg_ptr((void*)rec, (void*)&_merge_pending_queue,
-    (void*)cur_head)) {
-    cur_head = const_cast<MemRecorder*>(_merge_pending_queue);
-    rec->set_next(cur_head);
+  virtual bool at(const MallocSite* e) {
+    if (e->size() == 0) _empty_entries ++;
+    _total_entries ++;
+
+    // stack depth distrubution
+    int frames = e->call_stack()->frames();
+    _stack_depth_distribution[frames - 1] ++;
+
+    // hash distribution
+    int hash_bucket = e->hash() % MallocSiteTable::hash_buckets();
+    if (_current_hash_bucket == -1) {
+      _current_hash_bucket = hash_bucket;
+      _current_bucket_length = 1;
+    } else if (_current_hash_bucket == hash_bucket) {
+      _current_bucket_length ++;
+    } else {
+      record_bucket_length(_current_bucket_length);
+      _current_hash_bucket = hash_bucket;
+      _current_bucket_length = 1;
+    }
+    return true;
   }
-  NOT_PRODUCT(Atomic::inc(&_pending_recorder_count);)
-}
 
-/*
- * The method is called at global safepoint
- * during it synchronization process.
- *   1. enqueue all JavaThreads' per-thread recorders
- *   2. enqueue global recorder
- *   3. retrieve all pending recorders
- *   4. reset global sequence number generator
- *   5. call worker's sync
- */
-#define MAX_SAFEPOINTS_TO_SKIP     128
-#define SAFE_SEQUENCE_THRESHOLD    30
-#define HIGH_GENERATION_THRESHOLD  60
-#define MAX_RECORDER_THREAD_RATIO  30
-#define MAX_RECORDER_PER_THREAD    100
-
-void MemTracker::sync() {
-  assert(_tracking_level > NMT_off, "NMT is not enabled");
-  assert(SafepointSynchronize::is_at_safepoint(), "Safepoint required");
+  // walk completed
+  void completed() {
+    record_bucket_length(_current_bucket_length);
+  }
 
-  // Some GC tests hit large number of safepoints in short period of time
-  // without meaningful activities. We should prevent going to
-  // sync point in these cases, which can potentially exhaust generation buffer.
-  // Here is the factots to determine if we should go into sync point:
-  // 1. not to overflow sequence number
-  // 2. if we are in danger to overflow generation buffer
-  // 3. how many safepoints we already skipped sync point
-  if (_state == NMT_started) {
-    // worker thread is not ready, no one can manage generation
-    // buffer, so skip this safepoint
-    if (_worker_thread == NULL) return;
-
-    if (_sync_point_skip_count < MAX_SAFEPOINTS_TO_SKIP) {
-      int per_seq_in_use = SequenceGenerator::peek() * 100 / max_jint;
-      int per_gen_in_use = _worker_thread->generations_in_use() * 100 / MAX_GENERATIONS;
-      if (per_seq_in_use < SAFE_SEQUENCE_THRESHOLD && per_gen_in_use >= HIGH_GENERATION_THRESHOLD) {
-        _sync_point_skip_count ++;
-        return;
+  void report_statistics(outputStream* out) {
+    int index;
+    out->print_cr("Malloc allocation site table:");
+    out->print_cr("\tTotal entries: %d", _total_entries);
+    out->print_cr("\tEmpty entries: %d (%2.2f%%)", _empty_entries, ((float)_empty_entries * 100) / _total_entries);
+    out->print_cr(" ");
+    out->print_cr("Hash distribution:");
+    if (_used_buckets < MallocSiteTable::hash_buckets()) {
+      out->print_cr("empty bucket: %d", (MallocSiteTable::hash_buckets() - _used_buckets));
+    }
+    for (index = 0; index < report_threshold; index ++) {
+      if (_hash_distribution[index] != 0) {
+        if (index == 0) {
+          out->print_cr("  %d    entry: %d", 1, _hash_distribution[0]);
+        } else if (index < 9) { // single digit
+          out->print_cr("  %d  entries: %d", (index + 1), _hash_distribution[index]);
+        } else {
+          out->print_cr(" %d entries: %d", (index + 1), _hash_distribution[index]);
+        }
       }
     }
-    {
-      // This method is running at safepoint, with ThreadCritical lock,
-      // it should guarantee that NMT is fully sync-ed.
-      ThreadCritical tc;
-
-      // We can NOT execute NMT sync-point if there are pending tracking ops.
-      if (_pending_op_count == 0) {
-        SequenceGenerator::reset();
-        _sync_point_skip_count = 0;
-
-        // walk all JavaThreads to collect recorders
-        SyncThreadRecorderClosure stc;
-        Threads::threads_do(&stc);
-
-        _thread_count = stc.get_thread_count();
-        MemRecorder* pending_recorders = get_pending_recorders();
-
-        if (_global_recorder != NULL) {
-          _global_recorder->set_next(pending_recorders);
-          pending_recorders = _global_recorder;
-          _global_recorder = NULL;
-        }
-
-        // see if NMT has too many outstanding recorder instances, it usually
-        // means that worker thread is lagging behind in processing them.
-        if (!AutoShutdownNMT) {
-          _slowdown_calling_thread = (MemRecorder::_instance_count > MAX_RECORDER_THREAD_RATIO * _thread_count);
-        } else {
-          // If auto shutdown is on, enforce MAX_RECORDER_PER_THREAD threshold to prevent OOM
-          if (MemRecorder::_instance_count >= _thread_count * MAX_RECORDER_PER_THREAD) {
-            shutdown(NMT_out_of_memory);
-          }
-        }
-
-        // check _worker_thread with lock to avoid racing condition
-        if (_worker_thread != NULL) {
-          _worker_thread->at_sync_point(pending_recorders, InstanceKlass::number_of_instance_classes());
-        }
-        assert(SequenceGenerator::peek() == 1, "Should not have memory activities during sync-point");
-      } else {
-        _sync_point_skip_count ++;
+    if (_bucket_over_threshold > 0) {
+      out->print_cr(" >%d entries: %d", report_threshold,  _bucket_over_threshold);
+    }
+    out->print_cr("most entries: %d", _longest_bucket_length);
+    out->print_cr(" ");
+    out->print_cr("Call stack depth distribution:");
+    for (index = 0; index < NMT_TrackingStackDepth; index ++) {
+      if (_stack_depth_distribution[index] > 0) {
+        out->print_cr("\t%d: %d", index + 1, _stack_depth_distribution[index]);
       }
     }
   }
 
-  // now, it is the time to shut whole things off
-  if (_state == NMT_final_shutdown) {
-    // walk all JavaThreads to delete all recorders
-    SyncThreadRecorderClosure stc;
-    Threads::threads_do(&stc);
-    // delete global recorder
-    {
-      ThreadCritical tc;
-      if (_global_recorder != NULL) {
-        delete _global_recorder;
-        _global_recorder = NULL;
-      }
-    }
-    MemRecorder* pending_recorders = get_pending_recorders();
-    if (pending_recorders != NULL) {
-      delete pending_recorders;
-    }
-    // try at a later sync point to ensure MemRecorder instance drops to zero to
-    // completely shutdown NMT
-    if (MemRecorder::_instance_count == 0) {
-      _state = NMT_shutdown;
-      _tracking_level = NMT_off;
+ private:
+  void record_bucket_length(int length) {
+    _used_buckets ++;
+    if (length <= report_threshold) {
+      _hash_distribution[length - 1] ++;
+    } else {
+      _bucket_over_threshold ++;
     }
-  }
-}
-
-/*
- * Start worker thread.
- */
-bool MemTracker::start_worker(MemSnapshot* snapshot) {
-  assert(_worker_thread == NULL && _snapshot != NULL, "Just Check");
-  _worker_thread = new (std::nothrow) MemTrackWorker(snapshot);
-  if (_worker_thread == NULL) {
-    return false;
-  } else if (_worker_thread->has_error()) {
-    delete _worker_thread;
-    _worker_thread = NULL;
-    return false;
-  }
-  _worker_thread->start();
-  return true;
-}
-
-/*
- * We need to collect a JavaThread's per-thread recorder
- * before it exits.
- */
-void MemTracker::thread_exiting(JavaThread* thread) {
-  if (is_on()) {
-    MemRecorder* rec = thread->get_recorder();
-    if (rec != NULL) {
-      enqueue_pending_recorder(rec);
-      thread->set_recorder(NULL);
-    }
-  }
-}
-
-// baseline current memory snapshot
-bool MemTracker::baseline() {
-  MutexLocker lock(_query_lock);
-  MemSnapshot* snapshot = get_snapshot();
-  if (snapshot != NULL) {
-    return _baseline.baseline(*snapshot, false);
-  }
-  return false;
-}
-
-// print memory usage from current snapshot
-bool MemTracker::print_memory_usage(BaselineOutputer& out, size_t unit, bool summary_only) {
-  MemBaseline  baseline;
-  MutexLocker  lock(_query_lock);
-  MemSnapshot* snapshot = get_snapshot();
-  if (snapshot != NULL && baseline.baseline(*snapshot, summary_only)) {
-    BaselineReporter reporter(out, unit);
-    reporter.report_baseline(baseline, summary_only);
-    return true;
+    _longest_bucket_length = MAX2(_longest_bucket_length, length);
   }
-  return false;
-}
-
-// Whitebox API for blocking until the current generation of NMT data has been merged
-bool MemTracker::wbtest_wait_for_data_merge() {
-  // NMT can't be shutdown while we're holding _query_lock
-  MutexLocker lock(_query_lock);
-  assert(_worker_thread != NULL, "Invalid query");
-  // the generation at query time, so NMT will spin till this generation is processed
-  unsigned long generation_at_query_time = SequenceGenerator::current_generation();
-  unsigned long current_processing_generation = _processing_generation;
-  // if generation counter overflown
-  bool generation_overflown = (generation_at_query_time < current_processing_generation);
-  long generations_to_wrap = MAX_UNSIGNED_LONG - current_processing_generation;
-  // spin
-  while (!shutdown_in_progress()) {
-    if (!generation_overflown) {
-      if (current_processing_generation > generation_at_query_time) {
-        return true;
-      }
-    } else {
-      assert(generations_to_wrap >= 0, "Sanity check");
-      long current_generations_to_wrap = MAX_UNSIGNED_LONG - current_processing_generation;
-      assert(current_generations_to_wrap >= 0, "Sanity check");
-      // to overflow an unsigned long should take long time, so to_wrap check should be sufficient
-      if (current_generations_to_wrap > generations_to_wrap &&
-          current_processing_generation > generation_at_query_time) {
-        return true;
-      }
-    }
-
-    // if worker thread is idle, but generation is not advancing, that means
-    // there is not safepoint to let NMT advance generation, force one.
-    if (_worker_thread_idle) {
-      VM_ForceSafepoint vfs;
-      VMThread::execute(&vfs);
-    }
-    MemSnapshot* snapshot = get_snapshot();
-    if (snapshot == NULL) {
-      return false;
-    }
-    snapshot->wait(1000);
-    current_processing_generation = _processing_generation;
-  }
-  // We end up here if NMT is shutting down before our data has been merged
-  return false;
-}
-
-// compare memory usage between current snapshot and baseline
-bool MemTracker::compare_memory_usage(BaselineOutputer& out, size_t unit, bool summary_only) {
-  MutexLocker lock(_query_lock);
-  if (_baseline.baselined()) {
-    MemBaseline baseline;
-    MemSnapshot* snapshot = get_snapshot();
-    if (snapshot != NULL && baseline.baseline(*snapshot, summary_only)) {
-      BaselineReporter reporter(out, unit);
-      reporter.diff_baselines(baseline, _baseline, summary_only);
-      return true;
-    }
-  }
-  return false;
-}
-
-#ifndef PRODUCT
-void MemTracker::walk_stack(int toSkip, char* buf, int len) {
-  int cur_len = 0;
-  char tmp[1024];
-  address pc;
-
-  while (cur_len < len) {
-    pc = os::get_caller_pc(toSkip + 1);
-    if (pc != NULL && os::dll_address_to_function_name(pc, tmp, sizeof(tmp), NULL)) {
-      jio_snprintf(&buf[cur_len], (len - cur_len), "%s\n", tmp);
-      cur_len = (int)strlen(buf);
-    } else {
-      buf[cur_len] = '\0';
-      break;
-    }
-    toSkip ++;
-  }
-}
-
-void MemTracker::print_tracker_stats(outputStream* st) {
-  st->print_cr("\nMemory Tracker Stats:");
-  st->print_cr("\tMax sequence number = %d", SequenceGenerator::max_seq_num());
-  st->print_cr("\tthead count = %d", _thread_count);
-  st->print_cr("\tArena instance = %d", Arena::_instance_count);
-  st->print_cr("\tpooled recorder count = %d", _pooled_recorder_count);
-  st->print_cr("\tqueued recorder count = %d", _pending_recorder_count);
-  st->print_cr("\tmemory recorder instance count = %d", MemRecorder::_instance_count);
-  if (_worker_thread != NULL) {
-    st->print_cr("\tWorker thread:");
-    st->print_cr("\t\tSync point count = %d", _worker_thread->_sync_point_count);
-    st->print_cr("\t\tpending recorder count = %d", _worker_thread->count_pending_recorders());
-    st->print_cr("\t\tmerge count = %d", _worker_thread->_merge_count);
-  } else {
-    st->print_cr("\tWorker thread is not started");
-  }
-  st->print_cr(" ");
-
-  if (_snapshot != NULL) {
-    _snapshot->print_snapshot_stats(st);
-  } else {
-    st->print_cr("No snapshot");
-  }
-}
-#endif
+};
 
 
-// Tracker Implementation
+void MemTracker::tuning_statistics(outputStream* out) {
+  // NMT statistics
+  StatisticsWalker walker;
+  MallocSiteTable::walk_malloc_site(&walker);
+  walker.completed();
 
-/*
- * Create a tracker.
- * This is a fairly complicated constructor, as it has to make two important decisions:
- *   1) Does it need to take ThreadCritical lock to write tracking record
- *   2) Does it need to pre-reserve a sequence number for the tracking record
- *
- * The rules to determine if ThreadCritical is needed:
- *   1. When nmt is in single-threaded bootstrapping mode, no lock is needed as VM
- *      still in single thread mode.
- *   2. For all threads other than JavaThread, ThreadCritical is needed
- *      to write to recorders to global recorder.
- *   3. For JavaThreads that are no longer visible by safepoint, also
- *      need to take ThreadCritical and records are written to global
- *      recorders, since these threads are NOT walked by Threads.do_thread().
- *   4. JavaThreads that are running in safepoint-safe states do not stop
- *      for safepoints, ThreadCritical lock should be taken to write
- *      memory records.
- *   5. JavaThreads that are running in VM state do not need any lock and
- *      records are written to per-thread recorders.
- *   6. For a thread has yet to attach VM 'Thread', they need to take
- *      ThreadCritical to write to global recorder.
- *
- *  The memory operations that need pre-reserve sequence numbers:
- *    The memory operations that "release" memory blocks and the
- *    operations can fail, need to pre-reserve sequence number. They
- *    are realloc, uncommit and release.
- *
- *  The reason for pre-reserve sequence number, is to prevent race condition:
- *    Thread 1                      Thread 2
- *    <release>
- *                                  <allocate>
- *                                  <write allocate record>
- *   <write release record>
- *   if Thread 2 happens to obtain the memory address Thread 1 just released,
- *   then NMT can mistakenly report the memory is free.
- *
- *  Noticeably, free() does not need pre-reserve sequence number, because the call
- *  does not fail, so we can alway write "release" record before the memory is actaully
- *  freed.
- *
- *  For realloc, uncommit and release, following coding pattern should be used:
- *
- *     MemTracker::Tracker tkr = MemTracker::get_realloc_tracker();
- *     ptr = ::realloc(...);
- *     if (ptr == NULL) {
- *       tkr.record(...)
- *     } else {
- *       tkr.discard();
- *     }
- *
- *     MemTracker::Tracker tkr = MemTracker::get_virtual_memory_uncommit_tracker();
- *     if (uncommit(...)) {
- *       tkr.record(...);
- *     } else {
- *       tkr.discard();
- *     }
- *
- *     MemTracker::Tracker tkr = MemTracker::get_virtual_memory_release_tracker();
- *     if (release(...)) {
- *       tkr.record(...);
- *     } else {
- *       tkr.discard();
- *     }
- *
- * Since pre-reserved sequence number is only good for the generation that it is acquired,
- * when there is pending Tracker that reserved sequence number, NMT sync-point has
- * to be skipped to prevent from advancing generation. This is done by inc and dec
- * MemTracker::_pending_op_count, when MemTracker::_pending_op_count > 0, NMT sync-point is skipped.
- * Not all pre-reservation of sequence number will increment pending op count. For JavaThreads
- * that honor safepoints, safepoint can not occur during the memory operations, so the
- * pre-reserved sequence number won't cross the generation boundry.
- */
-MemTracker::Tracker::Tracker(MemoryOperation op, Thread* thr) {
-  _op = NoOp;
-  _seq = 0;
-  if (MemTracker::is_on()) {
-    _java_thread = NULL;
-    _op = op;
-
-    // figure out if ThreadCritical lock is needed to write this operation
-    // to MemTracker
-    if (MemTracker::is_single_threaded_bootstrap()) {
-      thr = NULL;
-    } else if (thr == NULL) {
-      // don't use Thread::current(), since it is possible that
-      // the calling thread has yet to attach to VM 'Thread',
-      // which will result assertion failure
-      thr = ThreadLocalStorage::thread();
-    }
-
-    if (thr != NULL) {
-      // Check NMT load
-      MemTracker::check_NMT_load(thr);
-
-      if (thr->is_Java_thread() && ((JavaThread*)thr)->is_safepoint_visible()) {
-        _java_thread = (JavaThread*)thr;
-        JavaThreadState  state = _java_thread->thread_state();
-        // JavaThreads that are safepoint safe, can run through safepoint,
-        // so ThreadCritical is needed to ensure no threads at safepoint create
-        // new records while the records are being gathered and the sequence number is changing
-        _need_thread_critical_lock =
-          SafepointSynchronize::safepoint_safe(_java_thread, state);
-      } else {
-        _need_thread_critical_lock = true;
-      }
-    } else {
-       _need_thread_critical_lock
-         = !MemTracker::is_single_threaded_bootstrap();
-    }
-
-    // see if we need to pre-reserve sequence number for this operation
-    if (_op == Realloc || _op == Uncommit || _op == Release) {
-      if (_need_thread_critical_lock) {
-        ThreadCritical tc;
-        MemTracker::inc_pending_op_count();
-        _seq = SequenceGenerator::next();
-      } else {
-        // for the threads that honor safepoints, no safepoint can occur
-        // during the lifespan of tracker, so we don't need to increase
-        // pending op count.
-        _seq = SequenceGenerator::next();
-      }
-    }
-  }
+  out->print_cr("Native Memory Tracking Statistics:");
+  out->print_cr("Malloc allocation site table size: %d", MallocSiteTable::hash_buckets());
+  out->print_cr("             Tracking stack depth: %d", NMT_TrackingStackDepth);
+  NOT_PRODUCT(out->print_cr("Peak concurrent access: %d", MallocSiteTable::access_peak_count());)
+  out->print_cr(" ");
+  walker.report_statistics(out);
 }
 
-void MemTracker::Tracker::discard() {
-  if (MemTracker::is_on() && _seq != 0) {
-    if (_need_thread_critical_lock) {
-      ThreadCritical tc;
-      MemTracker::dec_pending_op_count();
-    }
-    _seq = 0;
-  }
-}
-
-
-void MemTracker::Tracker::record(address old_addr, address new_addr, size_t size,
-  MEMFLAGS flags, address pc) {
-  assert(old_addr != NULL && new_addr != NULL, "Sanity check");
-  assert(_op == Realloc || _op == NoOp, "Wrong call");
-  if (MemTracker::is_on() && NMT_CAN_TRACK(flags) && _op != NoOp) {
-    assert(_seq > 0, "Need pre-reserve sequence number");
-    if (_need_thread_critical_lock) {
-      ThreadCritical tc;
-      // free old address, use pre-reserved sequence number
-      MemTracker::write_tracking_record(old_addr, MemPointerRecord::free_tag(),
-        0, _seq, pc, _java_thread);
-      MemTracker::write_tracking_record(new_addr, flags | MemPointerRecord::malloc_tag(),
-        size, SequenceGenerator::next(), pc, _java_thread);
-      // decrement MemTracker pending_op_count
-      MemTracker::dec_pending_op_count();
-    } else {
-      // free old address, use pre-reserved sequence number
-      MemTracker::write_tracking_record(old_addr, MemPointerRecord::free_tag(),
-        0, _seq, pc, _java_thread);
-      MemTracker::write_tracking_record(new_addr, flags | MemPointerRecord::malloc_tag(),
-        size, SequenceGenerator::next(), pc, _java_thread);
-    }
-    _seq = 0;
-  }
-}
-
-void MemTracker::Tracker::record(address addr, size_t size, MEMFLAGS flags, address pc) {
-  // OOM already?
-  if (addr == NULL) return;
-
-  if (MemTracker::is_on() && NMT_CAN_TRACK(flags) && _op != NoOp) {
-    bool pre_reserved_seq = (_seq != 0);
-    address  pc = CALLER_CALLER_PC;
-    MEMFLAGS orig_flags = flags;
-
-    // or the tagging flags
-    switch(_op) {
-      case Malloc:
-        flags |= MemPointerRecord::malloc_tag();
-        break;
-      case Free:
-        flags = MemPointerRecord::free_tag();
-        break;
-      case Realloc:
-        fatal("Use the other Tracker::record()");
-        break;
-      case Reserve:
-      case ReserveAndCommit:
-        flags |= MemPointerRecord::virtual_memory_reserve_tag();
-        break;
-      case Commit:
-        flags = MemPointerRecord::virtual_memory_commit_tag();
-        break;
-      case Type:
-        flags |= MemPointerRecord::virtual_memory_type_tag();
-        break;
-      case Uncommit:
-        assert(pre_reserved_seq, "Need pre-reserve sequence number");
-        flags = MemPointerRecord::virtual_memory_uncommit_tag();
-        break;
-      case Release:
-        assert(pre_reserved_seq, "Need pre-reserve sequence number");
-        flags = MemPointerRecord::virtual_memory_release_tag();
-        break;
-      case ArenaSize:
-        // a bit of hack here, add a small postive offset to arena
-        // address for its size record, so the size record is sorted
-        // right after arena record.
-        flags = MemPointerRecord::arena_size_tag();
-        addr += sizeof(void*);
-        break;
-      case StackRelease:
-        flags = MemPointerRecord::virtual_memory_release_tag();
-        break;
-      default:
-        ShouldNotReachHere();
-    }
-
-    // write memory tracking record
-    if (_need_thread_critical_lock) {
-      ThreadCritical tc;
-      if (_seq == 0) _seq = SequenceGenerator::next();
-      MemTracker::write_tracking_record(addr, flags, size, _seq, pc, _java_thread);
-      if (_op == ReserveAndCommit) {
-        MemTracker::write_tracking_record(addr, orig_flags | MemPointerRecord::virtual_memory_commit_tag(),
-          size, SequenceGenerator::next(), pc, _java_thread);
-      }
-      if (pre_reserved_seq) MemTracker::dec_pending_op_count();
-    } else {
-      if (_seq == 0) _seq = SequenceGenerator::next();
-      MemTracker::write_tracking_record(addr, flags, size, _seq, pc, _java_thread);
-      if (_op == ReserveAndCommit) {
-        MemTracker::write_tracking_record(addr, orig_flags | MemPointerRecord::virtual_memory_commit_tag(),
-          size, SequenceGenerator::next(), pc, _java_thread);
-      }
-    }
-    _seq = 0;
-  }
-}
-
--- a/src/share/vm/services/memTracker.hpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/services/memTracker.hpp	Fri Sep 05 06:26:44 2014 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -25,574 +25,288 @@
 #ifndef SHARE_VM_SERVICES_MEM_TRACKER_HPP
 #define SHARE_VM_SERVICES_MEM_TRACKER_HPP
 
-#include "utilities/macros.hpp"
+#include "services/nmtCommon.hpp"
+#include "utilities/nativeCallStack.hpp"
+
 
 #if !INCLUDE_NMT
 
-#include "utilities/ostream.hpp"
+#define CURRENT_PC   NativeCallStack::EMPTY_STACK
+#define CALLER_PC    NativeCallStack::EMPTY_STACK
 
-class BaselineOutputer : public StackObj {
-
+class Tracker : public StackObj {
+ public:
+  Tracker() { }
+  void record(address addr, size_t size) { }
 };
 
-class BaselineTTYOutputer : public BaselineOutputer {
-  public:
-    BaselineTTYOutputer(outputStream* st) { }
+class MemTracker : AllStatic {
+ public:
+  static inline NMT_TrackingLevel tracking_level() { return NMT_off; }
+  static inline void shutdown() { }
+  static inline void init() { }
+  static bool check_launcher_nmt_support(const char* value) { return true; }
+  static bool verify_nmt_option() { return true; }
+
+  static inline void* record_malloc(void* mem_base, size_t size, MEMFLAGS flag,
+    const NativeCallStack& stack, NMT_TrackingLevel level) { return mem_base; }
+  static inline size_t malloc_header_size(NMT_TrackingLevel level) { return 0; }
+  static inline size_t malloc_header_size(void* memblock) { return 0; }
+  static inline void* malloc_base(void* memblock) { return memblock; }
+  static inline void* record_free(void* memblock) { return memblock; }
+
+  static inline void record_new_arena(MEMFLAGS flag) { }
+  static inline void record_arena_free(MEMFLAGS flag) { }
+  static inline void record_arena_size_change(int diff, MEMFLAGS flag) { }
+  static inline void record_virtual_memory_reserve(void* addr, size_t size, const NativeCallStack& stack,
+                       MEMFLAGS flag = mtNone) { }
+  static inline void record_virtual_memory_reserve_and_commit(void* addr, size_t size,
+    const NativeCallStack& stack, MEMFLAGS flag = mtNone) { }
+  static inline void record_virtual_memory_commit(void* addr, size_t size, const NativeCallStack& stack) { }
+  static inline Tracker get_virtual_memory_uncommit_tracker() { return Tracker(); }
+  static inline Tracker get_virtual_memory_release_tracker() { }
+  static inline void record_virtual_memory_type(void* addr, MEMFLAGS flag) { }
+  static inline void record_thread_stack(void* addr, size_t size) { }
+  static inline void release_thread_stack(void* addr, size_t size) { }
+
+  static void final_report(outputStream*) { }
+};
+
+#else
+
+#include "runtime/atomic.hpp"
+#include "runtime/threadCritical.hpp"
+#include "services/mallocTracker.hpp"
+#include "services/virtualMemoryTracker.hpp"
+
+extern volatile bool NMT_stack_walkable;
+
+#define CURRENT_PC ((MemTracker::tracking_level() == NMT_detail && NMT_stack_walkable) ? \
+                    NativeCallStack(0, true) : NativeCallStack::EMPTY_STACK)
+#define CALLER_PC  ((MemTracker::tracking_level() == NMT_detail && NMT_stack_walkable) ?  \
+                    NativeCallStack(1, true) : NativeCallStack::EMPTY_STACK)
+
+class MemBaseline;
+class Mutex;
+
+// Tracker is used for guarding 'release' semantics of virtual memory operation, to avoid
+// the other thread obtains and records the same region that is just 'released' by current
+// thread but before it can record the operation.
+class Tracker : public StackObj {
+ public:
+  enum TrackerType {
+     uncommit,
+     release
+  };
+
+ public:
+  Tracker(enum TrackerType type) : _type(type) { }
+  void record(address addr, size_t size);
+ private:
+  enum TrackerType  _type;
+  // Virtual memory tracking data structures are protected by ThreadCritical lock.
+  ThreadCritical    _tc;
 };
 
 class MemTracker : AllStatic {
-  public:
-   enum ShutdownReason {
-      NMT_shutdown_none,     // no shutdown requested
-      NMT_shutdown_user,     // user requested shutdown
-      NMT_normal,            // normal shutdown, process exit
-      NMT_out_of_memory,     // shutdown due to out of memory
-      NMT_initialization,    // shutdown due to initialization failure
-      NMT_use_malloc_only,   // can not combine NMT with UseMallocOnly flag
-      NMT_error_reporting,   // shutdown by vmError::report_and_die()
-      NMT_out_of_generation, // running out of generation queue
-      NMT_sequence_overflow  // overflow the sequence number
-   };
-
-  class Tracker {
-   public:
-    void discard() { }
-
-    void record(address addr, size_t size = 0, MEMFLAGS flags = mtNone, address pc = NULL) { }
-    void record(address old_addr, address new_addr, size_t size,
-      MEMFLAGS flags, address pc = NULL) { }
-  };
-
-  private:
-   static Tracker  _tkr;
-
-
-  public:
-   static inline void init_tracking_options(const char* option_line) { }
-   static inline bool is_on()   { return false; }
-   static const char* reason()  { return "Native memory tracking is not implemented"; }
-   static inline bool can_walk_stack() { return false; }
-
-   static inline void bootstrap_single_thread() { }
-   static inline void bootstrap_multi_thread() { }
-   static inline void start() { }
-
-   static inline void record_malloc(address addr, size_t size, MEMFLAGS flags,
-        address pc = 0, Thread* thread = NULL) { }
-   static inline void record_free(address addr, MEMFLAGS flags, Thread* thread = NULL) { }
-   static inline void record_arena_size(address addr, size_t size) { }
-   static inline void record_virtual_memory_reserve(address addr, size_t size,
-        MEMFLAGS flags, address pc = 0, Thread* thread = NULL) { }
-   static inline void record_virtual_memory_reserve_and_commit(address addr, size_t size,
-        MEMFLAGS flags, address pc = 0, Thread* thread = NULL) { }
-   static inline void record_virtual_memory_commit(address addr, size_t size,
-        address pc = 0, Thread* thread = NULL) { }
-   static inline void record_virtual_memory_release(address addr, size_t size,
-        Thread* thread = NULL) { }
-   static inline void record_virtual_memory_type(address base, MEMFLAGS flags,
-        Thread* thread = NULL) { }
-   static inline Tracker get_realloc_tracker() { return _tkr; }
-   static inline Tracker get_virtual_memory_uncommit_tracker() { return _tkr; }
-   static inline Tracker get_virtual_memory_release_tracker()  { return _tkr; }
-   static inline bool baseline() { return false; }
-   static inline bool has_baseline() { return false; }
-
-   static inline void set_autoShutdown(bool value) { }
-   static void shutdown(ShutdownReason reason) { }
-   static inline bool shutdown_in_progress() { return false; }
-   static bool print_memory_usage(BaselineOutputer& out, size_t unit,
-            bool summary_only = true) { return false; }
-   static bool compare_memory_usage(BaselineOutputer& out, size_t unit,
-            bool summary_only = true) { return false; }
-
-   static bool wbtest_wait_for_data_merge() { return false; }
-
-   static inline void sync() { }
-   static inline void thread_exiting(JavaThread* thread) { }
-};
-
-
-#else // !INCLUDE_NMT
-
-#include "memory/allocation.hpp"
-#include "runtime/globals.hpp"
-#include "runtime/mutex.hpp"
-#include "runtime/os.hpp"
-#include "runtime/thread.hpp"
-#include "services/memPtr.hpp"
-#include "services/memRecorder.hpp"
-#include "services/memSnapshot.hpp"
-#include "services/memTrackWorker.hpp"
-
-extern bool NMT_track_callsite;
-
-#ifndef MAX_UNSIGNED_LONG
-#define MAX_UNSIGNED_LONG    (unsigned long)(-1)
-#endif
-
-#ifdef ASSERT
-  #define DEBUG_CALLER_PC  (NMT_track_callsite ? os::get_caller_pc(2) : 0)
-#else
-  #define DEBUG_CALLER_PC  0
-#endif
-
-// The thread closure walks threads to collect per-thread
-// memory recorders at NMT sync point
-class SyncThreadRecorderClosure : public ThreadClosure {
- private:
-  int _thread_count;
-
  public:
-  SyncThreadRecorderClosure() {
-    _thread_count =0;
-  }
-
-  void do_thread(Thread* thread);
-  int  get_thread_count() const {
-    return _thread_count;
-  }
-};
-
-class BaselineOutputer;
-class MemSnapshot;
-class MemTrackWorker;
-class Thread;
-/*
- * MemTracker is the 'gate' class to native memory tracking runtime.
- */
-class MemTracker : AllStatic {
-  friend class GenerationData;
-  friend class MemTrackWorker;
-  friend class MemSnapshot;
-  friend class SyncThreadRecorderClosure;
-
-  // NMT state
-  enum NMTStates {
-    NMT_uninited,                        // not yet initialized
-    NMT_bootstrapping_single_thread,     // bootstrapping, VM is in single thread mode
-    NMT_bootstrapping_multi_thread,      // bootstrapping, VM is about to enter multi-thread mode
-    NMT_started,                         // NMT fully started
-    NMT_shutdown_pending,                // shutdown pending
-    NMT_final_shutdown,                  // in final phase of shutdown
-    NMT_shutdown                         // shutdown
-  };
-
- public:
-  class Tracker : public StackObj {
-    friend class MemTracker;
-   public:
-    enum MemoryOperation {
-      NoOp,                   // no op
-      Malloc,                 // malloc
-      Realloc,                // realloc
-      Free,                   // free
-      Reserve,                // virtual memory reserve
-      Commit,                 // virtual memory commit
-      ReserveAndCommit,       // virtual memory reserve and commit
-      StackAlloc = ReserveAndCommit, // allocate thread stack
-      Type,                   // assign virtual memory type
-      Uncommit,               // virtual memory uncommit
-      Release,                // virtual memory release
-      ArenaSize,              // set arena size
-      StackRelease            // release thread stack
-    };
-
-
-   protected:
-    Tracker(MemoryOperation op, Thread* thr = NULL);
-
-   public:
-    void discard();
-
-    void record(address addr, size_t size = 0, MEMFLAGS flags = mtNone, address pc = NULL);
-    void record(address old_addr, address new_addr, size_t size,
-      MEMFLAGS flags, address pc = NULL);
-
-   private:
-    bool            _need_thread_critical_lock;
-    JavaThread*     _java_thread;
-    MemoryOperation _op;          // memory operation
-    jint            _seq;         // reserved sequence number
-  };
-
-
- public:
-  // native memory tracking level
-  enum NMTLevel {
-    NMT_off,              // native memory tracking is off
-    NMT_summary,          // don't track callsite
-    NMT_detail            // track callsite also
-  };
-
-   enum ShutdownReason {
-     NMT_shutdown_none,     // no shutdown requested
-     NMT_shutdown_user,     // user requested shutdown
-     NMT_normal,            // normal shutdown, process exit
-     NMT_out_of_memory,     // shutdown due to out of memory
-     NMT_initialization,    // shutdown due to initialization failure
-     NMT_use_malloc_only,   // can not combine NMT with UseMallocOnly flag
-     NMT_error_reporting,   // shutdown by vmError::report_and_die()
-     NMT_out_of_generation, // running out of generation queue
-     NMT_sequence_overflow  // overflow the sequence number
-   };
-
- public:
-  // initialize NMT tracking level from command line options, called
-   // from VM command line parsing code
-  static void init_tracking_options(const char* option_line);
-
-  // if NMT is enabled to record memory activities
-  static inline bool is_on() {
-    return (_tracking_level >= NMT_summary &&
-      _state >= NMT_bootstrapping_single_thread);
-  }
-
-  static inline enum NMTLevel tracking_level() {
+  static inline NMT_TrackingLevel tracking_level() {
+    if (_tracking_level == NMT_unknown) {
+      // No fencing is needed here, since JVM is in single-threaded
+      // mode.
+      _tracking_level = init_tracking_level();
+      _cmdline_tracking_level = _tracking_level;
+    }
     return _tracking_level;
   }
 
-  // user readable reason for shutting down NMT
-  static const char* reason() {
-    switch(_reason) {
-      case NMT_shutdown_none:
-        return "Native memory tracking is not enabled";
-      case NMT_shutdown_user:
-        return "Native memory tracking has been shutdown by user";
-      case NMT_normal:
-        return "Native memory tracking has been shutdown due to process exiting";
-      case NMT_out_of_memory:
-        return "Native memory tracking has been shutdown due to out of native memory";
-      case NMT_initialization:
-        return "Native memory tracking failed to initialize";
-      case NMT_error_reporting:
-        return "Native memory tracking has been shutdown due to error reporting";
-      case NMT_out_of_generation:
-        return "Native memory tracking has been shutdown due to running out of generation buffer";
-      case NMT_sequence_overflow:
-        return "Native memory tracking has been shutdown due to overflow the sequence number";
-      case NMT_use_malloc_only:
-        return "Native memory tracking is not supported when UseMallocOnly is on";
-      default:
-        ShouldNotReachHere();
-        return NULL;
-    }
+  // A late initialization, for the stuff(s) can not be
+  // done in init_tracking_level(), which can NOT malloc
+  // any memory.
+  static void init();
+
+  // Shutdown native memory tracking
+  static void shutdown();
+
+  // Verify native memory tracking command line option.
+  // This check allows JVM to detect if compatible launcher
+  // is used.
+  // If an incompatible launcher is used, NMT may not be
+  // able to start, even it is enabled by command line option.
+  // A warning message should be given if it is encountered.
+  static bool check_launcher_nmt_support(const char* value);
+
+  // This method checks native memory tracking environment
+  // variable value passed by launcher.
+  // Launcher only obligates to pass native memory tracking
+  // option value, but not obligates to validate the value,
+  // and launcher has option to discard native memory tracking
+  // option from the command line once it sets up the environment
+  // variable, so NMT has to catch the bad value here.
+  static bool verify_nmt_option();
+
+  // Transition the tracking level to specified level
+  static bool transition_to(NMT_TrackingLevel level);
+
+  static inline void* record_malloc(void* mem_base, size_t size, MEMFLAGS flag,
+    const NativeCallStack& stack, NMT_TrackingLevel level) {
+    return MallocTracker::record_malloc(mem_base, size, flag, stack, level);
+  }
+
+  static inline size_t malloc_header_size(NMT_TrackingLevel level) {
+    return MallocTracker::malloc_header_size(level);
   }
 
-  // test if we can walk native stack
-  static bool can_walk_stack() {
-  // native stack is not walkable during bootstrapping on sparc
-#if defined(SPARC)
-    return (_state == NMT_started);
-#else
-    return (_state >= NMT_bootstrapping_single_thread && _state  <= NMT_started);
-#endif
+  static size_t malloc_header_size(void* memblock) {
+    if (tracking_level() != NMT_off) {
+      return MallocTracker::get_header_size(memblock);
+    }
+    return 0;
+  }
+
+  // To malloc base address, which is the starting address
+  // of malloc tracking header if tracking is enabled.
+  // Otherwise, it returns the same address.
+  static void* malloc_base(void* memblock);
+
+  // Record malloc free and return malloc base address
+  static inline void* record_free(void* memblock) {
+    return MallocTracker::record_free(memblock);
   }
 
-  // if native memory tracking tracks callsite
-  static inline bool track_callsite() { return _tracking_level == NMT_detail; }
+
+  // Record creation of an arena
+  static inline void record_new_arena(MEMFLAGS flag) {
+    if (tracking_level() < NMT_summary) return;
+    MallocTracker::record_new_arena(flag);
+  }
+
+  // Record destruction of an arena
+  static inline void record_arena_free(MEMFLAGS flag) {
+    if (tracking_level() < NMT_summary) return;
+    MallocTracker::record_arena_free(flag);
+  }
 
-  // NMT automatically shuts itself down under extreme situation by default.
-  // When the value is set to false,  NMT will try its best to stay alive,
-  // even it has to slow down VM.
-  static inline void set_autoShutdown(bool value) {
-    AutoShutdownNMT = value;
-    if (AutoShutdownNMT && _slowdown_calling_thread) {
-      _slowdown_calling_thread = false;
+  // Record arena size change. Arena size is the size of all arena
+  // chuncks that backing up the arena.
+  static inline void record_arena_size_change(int diff, MEMFLAGS flag) {
+    if (tracking_level() < NMT_summary) return;
+    MallocTracker::record_arena_size_change(diff, flag);
+  }
+
+  static inline void record_virtual_memory_reserve(void* addr, size_t size, const NativeCallStack& stack,
+    MEMFLAGS flag = mtNone) {
+    if (tracking_level() < NMT_summary) return;
+    if (addr != NULL) {
+      ThreadCritical tc;
+      // Recheck to avoid potential racing during NMT shutdown
+      if (tracking_level() < NMT_summary) return;
+      VirtualMemoryTracker::add_reserved_region((address)addr, size, stack, flag);
     }
   }
 
-  // shutdown native memory tracking capability. Native memory tracking
-  // can be shutdown by VM when it encounters low memory scenarios.
-  // Memory tracker should gracefully shutdown itself, and preserve the
-  // latest memory statistics for post morten diagnosis.
-  static void shutdown(ShutdownReason reason);
-
-  // if there is shutdown requested
-  static inline bool shutdown_in_progress() {
-    return (_state >= NMT_shutdown_pending);
-  }
-
-  // bootstrap native memory tracking, so it can start to collect raw data
-  // before worker thread can start
-
-  // the first phase of bootstrapping, when VM still in single-threaded mode
-  static void bootstrap_single_thread();
-  // the second phase of bootstrapping, VM is about or already in multi-threaded mode
-  static void bootstrap_multi_thread();
-
-
-  // start() has to be called when VM still in single thread mode, but after
-  // command line option parsing is done.
-  static void start();
-
-  // record a 'malloc' call
-  static inline void record_malloc(address addr, size_t size, MEMFLAGS flags,
-                            address pc = 0, Thread* thread = NULL) {
-    Tracker tkr(Tracker::Malloc, thread);
-    tkr.record(addr, size, flags, pc);
-  }
-  // record a 'free' call
-  static inline void record_free(address addr, MEMFLAGS flags, Thread* thread = NULL) {
-    Tracker tkr(Tracker::Free, thread);
-    tkr.record(addr, 0, flags, DEBUG_CALLER_PC);
-  }
-
-  static inline void record_arena_size(address addr, size_t size) {
-    Tracker tkr(Tracker::ArenaSize);
-    tkr.record(addr, size);
-  }
-
-  // record a virtual memory 'reserve' call
-  static inline void record_virtual_memory_reserve(address addr, size_t size,
-                     MEMFLAGS flags, address pc = 0, Thread* thread = NULL) {
-    assert(size > 0, "Sanity check");
-    Tracker tkr(Tracker::Reserve, thread);
-    tkr.record(addr, size, flags, pc);
-  }
-
-  static inline void record_thread_stack(address addr, size_t size, Thread* thr,
-                           address pc = 0) {
-    Tracker tkr(Tracker::StackAlloc, thr);
-    tkr.record(addr, size, mtThreadStack, pc);
-  }
-
-  static inline void release_thread_stack(address addr, size_t size, Thread* thr) {
-    Tracker tkr(Tracker::StackRelease, thr);
-    tkr.record(addr, size, mtThreadStack, DEBUG_CALLER_PC);
-  }
-
-  // record a virtual memory 'commit' call
-  static inline void record_virtual_memory_commit(address addr, size_t size,
-                            address pc, Thread* thread = NULL) {
-    Tracker tkr(Tracker::Commit, thread);
-    tkr.record(addr, size, mtNone, pc);
-  }
-
-  static inline void record_virtual_memory_reserve_and_commit(address addr, size_t size,
-    MEMFLAGS flags, address pc, Thread* thread = NULL) {
-    Tracker tkr(Tracker::ReserveAndCommit, thread);
-    tkr.record(addr, size, flags, pc);
-  }
-
-  static inline void record_virtual_memory_release(address addr, size_t size,
-      Thread* thread = NULL) {
-    if (is_on()) {
-      Tracker tkr(Tracker::Release, thread);
-      tkr.record(addr, size);
+  static inline void record_virtual_memory_reserve_and_commit(void* addr, size_t size,
+    const NativeCallStack& stack, MEMFLAGS flag = mtNone) {
+    if (tracking_level() < NMT_summary) return;
+    if (addr != NULL) {
+      ThreadCritical tc;
+      if (tracking_level() < NMT_summary) return;
+      VirtualMemoryTracker::add_reserved_region((address)addr, size,
+        stack, flag, true);
     }
   }
 
-  // record memory type on virtual memory base address
-  static inline void record_virtual_memory_type(address base, MEMFLAGS flags,
-                            Thread* thread = NULL) {
-    Tracker tkr(Tracker::Type);
-    tkr.record(base, 0, flags);
-  }
-
-  // Get memory trackers for memory operations that can result race conditions.
-  // The memory tracker has to be obtained before realloc, virtual memory uncommit
-  // and virtual memory release, and call tracker.record() method if operation
-  // succeeded, or tracker.discard() to abort the tracking.
-  static inline Tracker get_realloc_tracker() {
-    return Tracker(Tracker::Realloc);
+  static inline void record_virtual_memory_commit(void* addr, size_t size,
+    const NativeCallStack& stack) {
+    if (tracking_level() < NMT_summary) return;
+    if (addr != NULL) {
+      ThreadCritical tc;
+      if (tracking_level() < NMT_summary) return;
+      VirtualMemoryTracker::add_committed_region((address)addr, size, stack);
+    }
   }
 
   static inline Tracker get_virtual_memory_uncommit_tracker() {
-    return Tracker(Tracker::Uncommit);
+    assert(tracking_level() >= NMT_summary, "Check by caller");
+    return Tracker(Tracker::uncommit);
   }
 
   static inline Tracker get_virtual_memory_release_tracker() {
-    return Tracker(Tracker::Release);
-  }
-
-
-  // create memory baseline of current memory snapshot
-  static bool baseline();
-  // is there a memory baseline
-  static bool has_baseline() {
-    return _baseline.baselined();
+    assert(tracking_level() >= NMT_summary, "Check by caller");
+    return Tracker(Tracker::release);
   }
 
-  // print memory usage from current snapshot
-  static bool print_memory_usage(BaselineOutputer& out, size_t unit,
-           bool summary_only = true);
-  // compare memory usage between current snapshot and baseline
-  static bool compare_memory_usage(BaselineOutputer& out, size_t unit,
-           bool summary_only = true);
-
-  // the version for whitebox testing support, it ensures that all memory
-  // activities before this method call, are reflected in the snapshot
-  // database.
-  static bool wbtest_wait_for_data_merge();
-
-  // sync is called within global safepoint to synchronize nmt data
-  static void sync();
-
-  // called when a thread is about to exit
-  static void thread_exiting(JavaThread* thread);
-
-  // retrieve global snapshot
-  static MemSnapshot* get_snapshot() {
-    if (shutdown_in_progress()) {
-      return NULL;
+  static inline void record_virtual_memory_type(void* addr, MEMFLAGS flag) {
+    if (tracking_level() < NMT_summary) return;
+    if (addr != NULL) {
+      ThreadCritical tc;
+      if (tracking_level() < NMT_summary) return;
+      VirtualMemoryTracker::set_reserved_region_type((address)addr, flag);
     }
-    return _snapshot;
   }
 
-  // print tracker stats
-  NOT_PRODUCT(static void print_tracker_stats(outputStream* st);)
-  NOT_PRODUCT(static void walk_stack(int toSkip, char* buf, int len);)
-
- private:
-  // start native memory tracking worker thread
-  static bool start_worker(MemSnapshot* snapshot);
-
-  // called by worker thread to complete shutdown process
-  static void final_shutdown();
-
- protected:
-  // retrieve per-thread recorder of the specified thread.
-  // if the recorder is full, it will be enqueued to overflow
-  // queue, a new recorder is acquired from recorder pool or a
-  // new instance is created.
-  // when thread == NULL, it means global recorder
-  static MemRecorder* get_thread_recorder(JavaThread* thread);
-
-  // per-thread recorder pool
-  static void release_thread_recorder(MemRecorder* rec);
-  static void delete_all_pooled_recorders();
-
-  // pending recorder queue. Recorders are queued to pending queue
-  // when they are overflowed or collected at nmt sync point.
-  static void enqueue_pending_recorder(MemRecorder* rec);
-  static MemRecorder* get_pending_recorders();
-  static void delete_all_pending_recorders();
-
-  // write a memory tracking record in recorder
-  static void write_tracking_record(address addr, MEMFLAGS type,
-    size_t size, jint seq, address pc, JavaThread* thread);
-
-  static bool is_single_threaded_bootstrap() {
-    return _state == NMT_bootstrapping_single_thread;
+  static inline void record_thread_stack(void* addr, size_t size) {
+    if (tracking_level() < NMT_summary) return;
+    if (addr != NULL) {
+      // uses thread stack malloc slot for book keeping number of threads
+      MallocMemorySummary::record_malloc(0, mtThreadStack);
+      record_virtual_memory_reserve_and_commit(addr, size, CALLER_PC, mtThreadStack);
+    }
   }
 
-  static void check_NMT_load(Thread* thr) {
-    assert(thr != NULL, "Sanity check");
-    if (_slowdown_calling_thread && thr != _worker_thread) {
-#ifdef _WINDOWS
-      // On Windows, os::NakedYield() does not work as well
-      // as os::yield_all()
-      os::yield_all();
-#else
-     // On Solaris, os::yield_all() depends on os::sleep()
-     // which requires JavaTherad in _thread_in_vm state.
-     // Transits thread to _thread_in_vm state can be dangerous
-     // if caller holds lock, as it may deadlock with Threads_lock.
-     // So use NaKedYield instead.
-     //
-     // Linux and BSD, NakedYield() and yield_all() implementations
-     // are the same.
-      os::NakedYield();
-#endif
+  static inline void release_thread_stack(void* addr, size_t size) {
+    if (tracking_level() < NMT_summary) return;
+    if (addr != NULL) {
+      // uses thread stack malloc slot for book keeping number of threads
+      MallocMemorySummary::record_free(0, mtThreadStack);
+      ThreadCritical tc;
+      if (tracking_level() < NMT_summary) return;
+      VirtualMemoryTracker::remove_released_region((address)addr, size);
     }
   }
 
-  static void inc_pending_op_count() {
-    Atomic::inc(&_pending_op_count);
-  }
+  // Query lock is used to synchronize the access to tracking data.
+  // So far, it is only used by JCmd query, but it may be used by
+  // other tools.
+  static inline Mutex* query_lock() { return _query_lock; }
 
-  static void dec_pending_op_count() {
-    Atomic::dec(&_pending_op_count);
-    assert(_pending_op_count >= 0, "Sanity check");
+  // Make a final report and shutdown.
+  // This function generates summary report without creating snapshots,
+  // to avoid additional memory allocation. It uses native memory summary
+  // counters, and makes adjustment to them, once the adjustment is made,
+  // the counters are no longer accurate. As the result, this function
+  // should only be used for final reporting before shutting down.
+  static void final_report(outputStream*);
+
+  // Stored baseline
+  static inline MemBaseline& get_baseline() {
+    return _baseline;
   }
 
-
- private:
-  // retrieve a pooled memory record or create new one if there is not
-  // one available
-  static MemRecorder* get_new_or_pooled_instance();
-  static void create_memory_record(address addr, MEMFLAGS type,
-                   size_t size, address pc, Thread* thread);
-  static void create_record_in_recorder(address addr, MEMFLAGS type,
-                   size_t size, address pc, JavaThread* thread);
-
-  static void set_current_processing_generation(unsigned long generation) {
-    _worker_thread_idle = false;
-    _processing_generation = generation;
+  static NMT_TrackingLevel cmdline_tracking_level() {
+    return _cmdline_tracking_level;
   }
 
-  static void report_worker_idle() {
-    _worker_thread_idle = true;
-  }
+  static void tuning_statistics(outputStream* out);
 
  private:
-  // global memory snapshot
-  static MemSnapshot*     _snapshot;
-
-  // a memory baseline of snapshot
-  static MemBaseline      _baseline;
-
-  // query lock
-  static Mutex*           _query_lock;
-
-  // a thread can start to allocate memory before it is attached
-  // to VM 'Thread', those memory activities are recorded here.
-  // ThreadCritical is required to guard this global recorder.
-  static MemRecorder* volatile _global_recorder;
-
-  // main thread id
-  debug_only(static intx   _main_thread_tid;)
-
-  // pending recorders to be merged
-  static MemRecorder* volatile     _merge_pending_queue;
-
-  NOT_PRODUCT(static volatile jint   _pending_recorder_count;)
-
-  // pooled memory recorders
-  static MemRecorder* volatile     _pooled_recorders;
-
-  // memory recorder pool management, uses following
-  // counter to determine if a released memory recorder
-  // should be pooled
+  static NMT_TrackingLevel init_tracking_level();
 
-  // latest thread count
-  static int               _thread_count;
-  // pooled recorder count
-  static volatile jint     _pooled_recorder_count;
-
-
-  // worker thread to merge pending recorders into snapshot
-  static MemTrackWorker*  _worker_thread;
-
-  // how many safepoints we skipped without entering sync point
-  static int              _sync_point_skip_count;
-
-  // if the tracker is properly intialized
-  static bool             _is_tracker_ready;
-  // tracking level (off, summary and detail)
-  static enum NMTLevel    _tracking_level;
-
-  // current nmt state
-  static volatile enum NMTStates   _state;
-  // the reason for shutting down nmt
-  static enum ShutdownReason       _reason;
-  // the generation that NMT is processing
-  static volatile unsigned long    _processing_generation;
-  // although NMT is still procesing current generation, but
-  // there is not more recorder to process, set idle state
-  static volatile bool             _worker_thread_idle;
-
-  // if NMT should slow down calling thread to allow
-  // worker thread to catch up
-  static volatile bool             _slowdown_calling_thread;
-
-  // pending memory op count.
-  // Certain memory ops need to pre-reserve sequence number
-  // before memory operation can happen to avoid race condition.
-  // See MemTracker::Tracker for detail
-  static volatile jint             _pending_op_count;
+ private:
+  // Tracking level
+  static volatile NMT_TrackingLevel   _tracking_level;
+  // If NMT option value passed by launcher through environment
+  // variable is valid
+  static bool                         _is_nmt_env_valid;
+  // command line tracking level
+  static NMT_TrackingLevel            _cmdline_tracking_level;
+  // Stored baseline
+  static MemBaseline      _baseline;
+  // Query lock
+  static Mutex*           _query_lock;
 };
 
-#endif // !INCLUDE_NMT
+#endif // INCLUDE_NMT
 
 #endif // SHARE_VM_SERVICES_MEM_TRACKER_HPP
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/vm/services/nmtCommon.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2013, 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 "services/nmtCommon.hpp"
+
+const char* NMTUtil::_memory_type_names[] = {
+  "Java Heap",
+  "Class",
+  "Thread",
+  "Thread Stack",
+  "Code",
+  "GC",
+  "Compiler",
+  "Internal",
+  "Other",
+  "Symbol",
+  "Native Memory Tracking",
+  "Shared class space",
+  "Arena Chunk",
+  "Test",
+  "Tracing",
+  "Unknown"
+};
+
+
+const char* NMTUtil::scale_name(size_t scale) {
+  switch(scale) {
+    case K: return "KB";
+    case M: return "MB";
+    case G: return "GB";
+  }
+  ShouldNotReachHere();
+  return NULL;
+}
+
+size_t NMTUtil::scale_from_name(const char* scale) {
+  assert(scale != NULL, "Null pointer check");
+  if (strncmp(scale, "KB", 2) == 0 ||
+      strncmp(scale, "kb", 2) == 0) {
+    return K;
+  } else if (strncmp(scale, "MB", 2) == 0 ||
+             strncmp(scale, "mb", 2) == 0) {
+    return M;
+  } else if (strncmp(scale, "GB", 2) == 0 ||
+             strncmp(scale, "gb", 2) == 0) {
+    return G;
+  } else {
+    return 0; // Invalid value
+  }
+  return K;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/vm/services/nmtCommon.hpp	Fri Sep 05 06:26:44 2014 -0400
@@ -0,0 +1,84 @@
+/*
+ * 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.
+ *
+ */
+
+#ifndef SHARE_VM_SERVICES_NMT_COMMON_HPP
+#define SHARE_VM_SERVICES_NMT_COMMON_HPP
+
+#include "memory/allocation.hpp"
+#include "utilities/globalDefinitions.hpp"
+
+#define CALC_OBJ_SIZE_IN_TYPE(obj, type) (align_size_up_(sizeof(obj), sizeof(type))/sizeof(type))
+
+// Data type for memory counters
+#ifdef _LP64
+  typedef jlong    MemoryCounterType;
+#else
+  typedef jint     MemoryCounterType;
+#endif
+
+// Native memory tracking level
+enum NMT_TrackingLevel {
+  NMT_unknown = 0xFF,
+  NMT_off     = 0x00,
+  NMT_minimal = 0x01,
+  NMT_summary = 0x02,
+  NMT_detail  = 0x03
+};
+
+// Number of stack frames to capture. This is a
+// build time decision.
+const int NMT_TrackingStackDepth = 4;
+
+// A few common utilities for native memory tracking
+class NMTUtil : AllStatic {
+ public:
+  // Map memory type to index
+  static inline int flag_to_index(MEMFLAGS flag) {
+    return (flag & 0xff);
+  }
+
+  // Map memory type to human readable name
+  static const char* flag_to_name(MEMFLAGS flag) {
+    return _memory_type_names[flag_to_index(flag)];
+  }
+
+  // Map an index to memory type
+  static MEMFLAGS index_to_flag(int index) {
+    return (MEMFLAGS)index;
+  }
+
+  // Memory size scale
+  static const char* scale_name(size_t scale);
+  static size_t scale_from_name(const char* scale);
+
+  // Translate memory size in specified scale
+  static size_t amount_in_scale(size_t amount, size_t scale) {
+    return (amount + scale / 2) / scale;
+  }
+ private:
+  static const char* _memory_type_names[mt_number_of_types];
+};
+
+
+#endif
--- a/src/share/vm/services/nmtDCmd.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/services/nmtDCmd.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -22,6 +22,8 @@
  *
  */
 #include "precompiled.hpp"
+
+#include "runtime/mutexLocker.hpp"
 #include "services/nmtDCmd.hpp"
 #include "services/memReporter.hpp"
 #include "services/memTracker.hpp"
@@ -49,13 +51,8 @@
   _shutdown("shutdown", "request runtime to shutdown itself and free the " \
             "memory used by runtime.",
             "BOOLEAN", false, "false"),
-  _auto_shutdown("autoShutdown", "automatically shutdown itself under "    \
-            "stress situation",
-            "BOOLEAN", true, "true"),
-#ifndef PRODUCT
-  _debug("debug", "print tracker statistics. Debug only, not thread safe", \
+  _statistics("statistics", "print tracker statistics for tuning purpose.", \
             "BOOLEAN", false, "false"),
-#endif
   _scale("scale", "Memory usage in which scale, KB, MB or GB",
        "STRING", false, "KB") {
   _dcmdparser.add_dcmd_option(&_summary);
@@ -64,25 +61,30 @@
   _dcmdparser.add_dcmd_option(&_summary_diff);
   _dcmdparser.add_dcmd_option(&_detail_diff);
   _dcmdparser.add_dcmd_option(&_shutdown);
-  _dcmdparser.add_dcmd_option(&_auto_shutdown);
-#ifndef PRODUCT
-  _dcmdparser.add_dcmd_option(&_debug);
-#endif
+  _dcmdparser.add_dcmd_option(&_statistics);
   _dcmdparser.add_dcmd_option(&_scale);
 }
 
+
+size_t NMTDCmd::get_scale(const char* scale) const {
+  if (scale == NULL) return 0;
+  return NMTUtil::scale_from_name(scale);
+}
+
 void NMTDCmd::execute(DCmdSource source, TRAPS) {
+  // Check NMT state
+  //  native memory tracking has to be on
+  if (MemTracker::tracking_level() == NMT_off) {
+    output()->print_cr("Native memory tracking is not enabled");
+    return;
+  } else if (MemTracker::tracking_level() == NMT_minimal) {
+     output()->print_cr("Native memory tracking has been shutdown");
+     return;
+  }
+
   const char* scale_value = _scale.value();
-  size_t scale_unit;
-  if (strcmp(scale_value, "KB") == 0 || strcmp(scale_value, "kb") == 0) {
-    scale_unit = K;
-  } else if (strcmp(scale_value, "MB") == 0 ||
-             strcmp(scale_value, "mb") == 0) {
-    scale_unit = M;
-  } else if (strcmp(scale_value, "GB") == 0 ||
-             strcmp(scale_value, "gb") == 0) {
-    scale_unit = G;
-  } else {
+  size_t scale_unit = get_scale(scale_value);
+  if (scale_unit == 0) {
     output()->print_cr("Incorrect scale value: %s", scale_value);
     return;
   }
@@ -94,19 +96,11 @@
   if (_summary_diff.is_set() && _summary_diff.value()) { ++nopt; }
   if (_detail_diff.is_set() && _detail_diff.value()) { ++nopt; }
   if (_shutdown.is_set() && _shutdown.value()) { ++nopt; }
-  if (_auto_shutdown.is_set()) { ++nopt; }
-
-#ifndef PRODUCT
-  if (_debug.is_set() && _debug.value()) { ++nopt; }
-#endif
+  if (_statistics.is_set() && _statistics.value()) { ++nopt; }
 
   if (nopt > 1) {
       output()->print_cr("At most one of the following option can be specified: " \
-        "summary, detail, baseline, summary.diff, detail.diff, shutdown"
-#ifndef PRODUCT
-        ", debug"
-#endif
-      );
+        "summary, detail, baseline, summary.diff, detail.diff, shutdown");
       return;
   } else if (nopt == 0) {
     if (_summary.is_set()) {
@@ -117,53 +111,47 @@
     }
   }
 
-#ifndef PRODUCT
-  if (_debug.value()) {
-    output()->print_cr("debug command is NOT thread-safe, may cause crash");
-    MemTracker::print_tracker_stats(output());
-    return;
-  }
-#endif
-
-  // native memory tracking has to be on
-  if (!MemTracker::is_on() || MemTracker::shutdown_in_progress()) {
-    // if it is not on, what's the reason?
-    output()->print_cr("%s", MemTracker::reason());
-    return;
-  }
+  // Serialize NMT query
+  MutexLocker locker(MemTracker::query_lock());
 
   if (_summary.value()) {
-    BaselineTTYOutputer outputer(output());
-    MemTracker::print_memory_usage(outputer, scale_unit, true);
+    report(true, scale_unit);
   } else if (_detail.value()) {
-    BaselineTTYOutputer outputer(output());
-    MemTracker::print_memory_usage(outputer, scale_unit, false);
+    if (!check_detail_tracking_level(output())) {
+    return;
+  }
+    report(false, scale_unit);
   } else if (_baseline.value()) {
-    if (MemTracker::baseline()) {
-      output()->print_cr("Successfully baselined.");
+    MemBaseline& baseline = MemTracker::get_baseline();
+    if (!baseline.baseline(MemTracker::tracking_level() != NMT_detail)) {
+      output()->print_cr("Baseline failed");
     } else {
-      output()->print_cr("Baseline failed.");
+      output()->print_cr("Baseline succeeded");
     }
   } else if (_summary_diff.value()) {
-    if (MemTracker::has_baseline()) {
-      BaselineTTYOutputer outputer(output());
-      MemTracker::compare_memory_usage(outputer, scale_unit, true);
+    MemBaseline& baseline = MemTracker::get_baseline();
+    if (baseline.baseline_type() >= MemBaseline::Summary_baselined) {
+      report_diff(true, scale_unit);
     } else {
-      output()->print_cr("No baseline to compare, run 'baseline' command first");
+      output()->print_cr("No baseline for comparison");
     }
   } else if (_detail_diff.value()) {
-    if (MemTracker::has_baseline()) {
-      BaselineTTYOutputer outputer(output());
-      MemTracker::compare_memory_usage(outputer, scale_unit, false);
+    if (!check_detail_tracking_level(output())) {
+    return;
+  }
+    MemBaseline& baseline = MemTracker::get_baseline();
+    if (baseline.baseline_type() == MemBaseline::Detail_baselined) {
+      report_diff(false, scale_unit);
     } else {
-      output()->print_cr("No baseline to compare to, run 'baseline' command first");
+      output()->print_cr("No detail baseline for comparison");
     }
   } else if (_shutdown.value()) {
-    MemTracker::shutdown(MemTracker::NMT_shutdown_user);
-    output()->print_cr("Shutdown is in progress, it will take a few moments to " \
-      "completely shutdown");
-  } else if (_auto_shutdown.is_set()) {
-    MemTracker::set_autoShutdown(_auto_shutdown.value());
+    MemTracker::shutdown();
+    output()->print_cr("Native memory tracking has been turned off");
+  } else if (_statistics.value()) {
+    if (check_detail_tracking_level(output())) {
+      MemTracker::tuning_statistics(output());
+    }
   } else {
     ShouldNotReachHere();
     output()->print_cr("Unknown command");
@@ -181,3 +169,46 @@
   }
 }
 
+void NMTDCmd::report(bool summaryOnly, size_t scale_unit) {
+  MemBaseline baseline;
+  if (baseline.baseline(summaryOnly)) {
+    if (summaryOnly) {
+      MemSummaryReporter rpt(baseline, output(), scale_unit);
+      rpt.report();
+    } else {
+      MemDetailReporter rpt(baseline, output(), scale_unit);
+      rpt.report();
+    }
+  }
+}
+
+void NMTDCmd::report_diff(bool summaryOnly, size_t scale_unit) {
+  MemBaseline& early_baseline = MemTracker::get_baseline();
+  assert(early_baseline.baseline_type() != MemBaseline::Not_baselined,
+    "Not yet baselined");
+  assert(summaryOnly || early_baseline.baseline_type() == MemBaseline::Detail_baselined,
+    "Not a detail baseline");
+
+  MemBaseline baseline;
+  if (baseline.baseline(summaryOnly)) {
+    if (summaryOnly) {
+      MemSummaryDiffReporter rpt(early_baseline, baseline, output(), scale_unit);
+      rpt.report_diff();
+    } else {
+      MemDetailDiffReporter rpt(early_baseline, baseline, output(), scale_unit);
+      rpt.report_diff();
+    }
+  }
+}
+
+bool NMTDCmd::check_detail_tracking_level(outputStream* out) {
+  if (MemTracker::tracking_level() == NMT_detail) {
+    return true;
+  } else if (MemTracker::cmdline_tracking_level() == NMT_detail) {
+    out->print_cr("Tracking level has been downgraded due to lack of resources");
+    return false;
+  } else {
+    out->print_cr("Detail tracking is not enabled");
+    return false;
+  }
+}
--- a/src/share/vm/services/nmtDCmd.hpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/services/nmtDCmd.hpp	Fri Sep 05 06:26:44 2014 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 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
@@ -25,8 +25,12 @@
 #ifndef SHARE_VM_SERVICES_NMT_DCMD_HPP
 #define SHARE_VM_SERVICES_NMT_DCMD_HPP
 
+#if INCLUDE_NMT
+
 #include "services/diagnosticArgument.hpp"
 #include "services/diagnosticFramework.hpp"
+#include "services/memBaseline.hpp"
+#include "services/mallocTracker.hpp"
 
 /**
  * Native memory tracking DCmd implementation
@@ -39,10 +43,7 @@
   DCmdArgument<bool>  _summary_diff;
   DCmdArgument<bool>  _detail_diff;
   DCmdArgument<bool>  _shutdown;
-  DCmdArgument<bool>  _auto_shutdown;
-#ifndef PRODUCT
-  DCmdArgument<bool>  _debug;
-#endif
+  DCmdArgument<bool>  _statistics;
   DCmdArgument<char*> _scale;
 
  public:
@@ -61,6 +62,17 @@
   }
   static int num_arguments();
   virtual void execute(DCmdSource source, TRAPS);
+
+ private:
+  void report(bool summaryOnly, size_t scale);
+  void report_diff(bool summaryOnly, size_t scale);
+
+  size_t get_scale(const char* scale) const;
+
+  // check if NMT running at detail tracking level
+  bool check_detail_tracking_level(outputStream* out);
 };
 
+#endif // INCLUDE_NMT
+
 #endif // SHARE_VM_SERVICES_NMT_DCMD_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/vm/services/virtualMemoryTracker.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -0,0 +1,475 @@
+/*
+ * Copyright (c) 2013, 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 "runtime/threadCritical.hpp"
+#include "services/virtualMemoryTracker.hpp"
+
+size_t VirtualMemorySummary::_snapshot[CALC_OBJ_SIZE_IN_TYPE(VirtualMemorySnapshot, size_t)];
+
+void VirtualMemorySummary::initialize() {
+  assert(sizeof(_snapshot) >= sizeof(VirtualMemorySnapshot), "Sanity Check");
+  // Use placement operator new to initialize static data area.
+  ::new ((void*)_snapshot) VirtualMemorySnapshot();
+}
+
+SortedLinkedList<ReservedMemoryRegion, compare_reserved_region_base>* VirtualMemoryTracker::_reserved_regions;
+
+int compare_committed_region(const CommittedMemoryRegion& r1, const CommittedMemoryRegion& r2) {
+  return r1.compare(r2);
+}
+
+int compare_reserved_region_base(const ReservedMemoryRegion& r1, const ReservedMemoryRegion& r2) {
+  return r1.compare(r2);
+}
+
+bool ReservedMemoryRegion::add_committed_region(address addr, size_t size, const NativeCallStack& stack) {
+  assert(addr != NULL, "Invalid address");
+  assert(size > 0, "Invalid size");
+  assert(contain_region(addr, size), "Not contain this region");
+
+  if (all_committed()) return true;
+
+  CommittedMemoryRegion committed_rgn(addr, size, stack);
+  LinkedListNode<CommittedMemoryRegion>* node = _committed_regions.find_node(committed_rgn);
+  if (node != NULL) {
+    CommittedMemoryRegion* rgn = node->data();
+    if (rgn->same_region(addr, size)) {
+      return true;
+    }
+
+    if (rgn->adjacent_to(addr, size)) {
+      // check if the next region covers this committed region,
+      // the regions may not be merged due to different call stacks
+      LinkedListNode<CommittedMemoryRegion>* next =
+        node->next();
+      if (next != NULL && next->data()->contain_region(addr, size)) {
+        if (next->data()->same_region(addr, size)) {
+          next->data()->set_call_stack(stack);
+        }
+        return true;
+      }
+      if (rgn->call_stack()->equals(stack)) {
+        VirtualMemorySummary::record_uncommitted_memory(rgn->size(), flag());
+        // the two adjacent regions have the same call stack, merge them
+        rgn->expand_region(addr, size);
+        VirtualMemorySummary::record_committed_memory(rgn->size(), flag());
+        return true;
+      }
+      VirtualMemorySummary::record_committed_memory(size, flag());
+      if (rgn->base() > addr) {
+        return _committed_regions.insert_before(committed_rgn, node) != NULL;
+      } else {
+        return _committed_regions.insert_after(committed_rgn, node) != NULL;
+      }
+    }
+    assert(rgn->contain_region(addr, size), "Must cover this region");
+    return true;
+  } else {
+    // New committed region
+    VirtualMemorySummary::record_committed_memory(size, flag());
+    return add_committed_region(committed_rgn);
+  }
+}
+
+void ReservedMemoryRegion::set_all_committed(bool b) {
+  if (all_committed() != b) {
+    _all_committed = b;
+    if (b) {
+      VirtualMemorySummary::record_committed_memory(size(), flag());
+    }
+  }
+}
+
+bool ReservedMemoryRegion::remove_uncommitted_region(LinkedListNode<CommittedMemoryRegion>* node,
+  address addr, size_t size) {
+  assert(addr != NULL, "Invalid address");
+  assert(size > 0, "Invalid size");
+
+  CommittedMemoryRegion* rgn = node->data();
+  assert(rgn->contain_region(addr, size), "Has to be contained");
+  assert(!rgn->same_region(addr, size), "Can not be the same region");
+
+  if (rgn->base() == addr ||
+      rgn->end() == addr + size) {
+    rgn->exclude_region(addr, size);
+    return true;
+  } else {
+    // split this region
+    address top =rgn->end();
+    // use this region for lower part
+    size_t exclude_size = rgn->end() - addr;
+    rgn->exclude_region(addr, exclude_size);
+
+    // higher part
+    address high_base = addr + size;
+    size_t  high_size = top - high_base;
+
+    CommittedMemoryRegion high_rgn(high_base, high_size, *rgn->call_stack());
+    LinkedListNode<CommittedMemoryRegion>* high_node = _committed_regions.add(high_rgn);
+    assert(high_node == NULL || node->next() == high_node, "Should be right after");
+    return (high_node != NULL);
+  }
+
+  return false;
+}
+
+bool ReservedMemoryRegion::remove_uncommitted_region(address addr, size_t sz) {
+  // uncommit stack guard pages
+  if (flag() == mtThreadStack && !same_region(addr, sz)) {
+    return true;
+  }
+
+  assert(addr != NULL, "Invalid address");
+  assert(sz > 0, "Invalid size");
+
+  if (all_committed()) {
+    assert(_committed_regions.is_empty(), "Sanity check");
+    assert(contain_region(addr, sz), "Reserved region does not contain this region");
+    set_all_committed(false);
+    VirtualMemorySummary::record_uncommitted_memory(sz, flag());
+    if (same_region(addr, sz)) {
+      return true;
+    } else {
+      CommittedMemoryRegion rgn(base(), size(), *call_stack());
+      if (rgn.base() == addr || rgn.end() == (addr + sz)) {
+        rgn.exclude_region(addr, sz);
+        return add_committed_region(rgn);
+      } else {
+        // split this region
+        // top of the whole region
+        address top =rgn.end();
+        // use this region for lower part
+        size_t exclude_size = rgn.end() - addr;
+        rgn.exclude_region(addr, exclude_size);
+        if (add_committed_region(rgn)) {
+          // higher part
+          address high_base = addr + sz;
+          size_t  high_size = top - high_base;
+          CommittedMemoryRegion high_rgn(high_base, high_size, NativeCallStack::EMPTY_STACK);
+          return add_committed_region(high_rgn);
+        } else {
+          return false;
+        }
+      }
+    }
+  } else {
+    // we have to walk whole list to remove the committed regions in
+    // specified range
+    LinkedListNode<CommittedMemoryRegion>* head =
+      _committed_regions.head();
+    LinkedListNode<CommittedMemoryRegion>* prev = NULL;
+    VirtualMemoryRegion uncommitted_rgn(addr, sz);
+
+    while (head != NULL && !uncommitted_rgn.is_empty()) {
+      CommittedMemoryRegion* crgn = head->data();
+      // this committed region overlaps to region to uncommit
+      if (crgn->overlap_region(uncommitted_rgn.base(), uncommitted_rgn.size())) {
+        if (crgn->same_region(uncommitted_rgn.base(), uncommitted_rgn.size())) {
+          // find matched region, remove the node will do
+          VirtualMemorySummary::record_uncommitted_memory(uncommitted_rgn.size(), flag());
+          _committed_regions.remove_after(prev);
+          return true;
+        } else if (crgn->contain_region(uncommitted_rgn.base(), uncommitted_rgn.size())) {
+          // this committed region contains whole uncommitted region
+          VirtualMemorySummary::record_uncommitted_memory(uncommitted_rgn.size(), flag());
+          return remove_uncommitted_region(head, uncommitted_rgn.base(), uncommitted_rgn.size());
+        } else if (uncommitted_rgn.contain_region(crgn->base(), crgn->size())) {
+          // this committed region has been uncommitted
+          size_t exclude_size = crgn->end() - uncommitted_rgn.base();
+          uncommitted_rgn.exclude_region(uncommitted_rgn.base(), exclude_size);
+          VirtualMemorySummary::record_uncommitted_memory(crgn->size(), flag());
+          LinkedListNode<CommittedMemoryRegion>* tmp = head;
+          head = head->next();
+          _committed_regions.remove_after(prev);
+          continue;
+        } else if (crgn->contain_address(uncommitted_rgn.base())) {
+          size_t toUncommitted = crgn->end() - uncommitted_rgn.base();
+          crgn->exclude_region(uncommitted_rgn.base(), toUncommitted);
+          uncommitted_rgn.exclude_region(uncommitted_rgn.base(), toUncommitted);
+          VirtualMemorySummary::record_uncommitted_memory(toUncommitted, flag());
+        } else if (uncommitted_rgn.contain_address(crgn->base())) {
+          size_t toUncommitted = uncommitted_rgn.end() - crgn->base();
+          crgn->exclude_region(crgn->base(), toUncommitted);
+          uncommitted_rgn.exclude_region(uncommitted_rgn.end() - toUncommitted,
+            toUncommitted);
+          VirtualMemorySummary::record_uncommitted_memory(toUncommitted, flag());
+        }
+      }
+      prev = head;
+      head = head->next();
+    }
+  }
+
+  return true;
+}
+
+void ReservedMemoryRegion::move_committed_regions(address addr, ReservedMemoryRegion& rgn) {
+  assert(addr != NULL, "Invalid address");
+
+  // split committed regions
+  LinkedListNode<CommittedMemoryRegion>* head =
+    _committed_regions.head();
+  LinkedListNode<CommittedMemoryRegion>* prev = NULL;
+
+  while (head != NULL) {
+    if (head->data()->base() >= addr) {
+      break;
+    }
+    prev = head;
+    head = head->next();
+  }
+
+  if (head != NULL) {
+    if (prev != NULL) {
+      prev->set_next(head->next());
+    } else {
+      _committed_regions.set_head(NULL);
+    }
+  }
+
+  rgn._committed_regions.set_head(head);
+}
+
+size_t ReservedMemoryRegion::committed_size() const {
+  if (all_committed()) {
+    return size();
+  } else {
+    size_t committed = 0;
+    LinkedListNode<CommittedMemoryRegion>* head =
+      _committed_regions.head();
+    while (head != NULL) {
+      committed += head->data()->size();
+      head = head->next();
+    }
+    return committed;
+  }
+}
+
+void ReservedMemoryRegion::set_flag(MEMFLAGS f) {
+  assert((flag() == mtNone || flag() == f), "Overwrite memory type");
+  if (flag() != f) {
+    VirtualMemorySummary::move_reserved_memory(flag(), f, size());
+    VirtualMemorySummary::move_committed_memory(flag(), f, committed_size());
+    _flag = f;
+  }
+}
+
+bool VirtualMemoryTracker::initialize(NMT_TrackingLevel level) {
+  if (level >= NMT_summary) {
+    VirtualMemorySummary::initialize();
+  }
+  return true;
+}
+
+bool VirtualMemoryTracker::late_initialize(NMT_TrackingLevel level) {
+  if (level >= NMT_summary) {
+    _reserved_regions = new (std::nothrow, ResourceObj::C_HEAP, mtNMT)
+      SortedLinkedList<ReservedMemoryRegion, compare_reserved_region_base>();
+    return (_reserved_regions != NULL);
+  }
+  return true;
+}
+
+bool VirtualMemoryTracker::add_reserved_region(address base_addr, size_t size,
+   const NativeCallStack& stack, MEMFLAGS flag, bool all_committed) {
+  assert(base_addr != NULL, "Invalid address");
+  assert(size > 0, "Invalid size");
+  assert(_reserved_regions != NULL, "Sanity check");
+  ReservedMemoryRegion  rgn(base_addr, size, stack, flag);
+  ReservedMemoryRegion* reserved_rgn = _reserved_regions->find(rgn);
+  LinkedListNode<ReservedMemoryRegion>* node;
+  if (reserved_rgn == NULL) {
+    VirtualMemorySummary::record_reserved_memory(size, flag);
+    node = _reserved_regions->add(rgn);
+    if (node != NULL) {
+      node->data()->set_all_committed(all_committed);
+      return true;
+    } else {
+      return false;
+    }
+  } else {
+    if (reserved_rgn->same_region(base_addr, size)) {
+      reserved_rgn->set_call_stack(stack);
+      reserved_rgn->set_flag(flag);
+      return true;
+    } else if (reserved_rgn->adjacent_to(base_addr, size)) {
+      VirtualMemorySummary::record_reserved_memory(size, flag);
+      reserved_rgn->expand_region(base_addr, size);
+      reserved_rgn->set_call_stack(stack);
+      return true;
+    } else {
+      // Overlapped reservation.
+      // It can happen when the regions are thread stacks, as JNI
+      // thread does not detach from VM before exits, and leads to
+      // leak JavaThread object
+      if (reserved_rgn->flag() == mtThreadStack) {
+        guarantee(!CheckJNICalls, "Attached JNI thread exited without being detached");
+        // Overwrite with new region
+
+        // Release old region
+        VirtualMemorySummary::record_uncommitted_memory(reserved_rgn->committed_size(), reserved_rgn->flag());
+        VirtualMemorySummary::record_released_memory(reserved_rgn->size(), reserved_rgn->flag());
+
+        // Add new region
+        VirtualMemorySummary::record_reserved_memory(rgn.size(), flag);
+
+        *reserved_rgn = rgn;
+        return true;
+      }
+
+      // CDS mapping region.
+      // CDS reserves the whole region for mapping CDS archive, then maps each section into the region.
+      // NMT reports CDS as a whole.
+      if (reserved_rgn->flag() == mtClassShared) {
+        assert(reserved_rgn->contain_region(base_addr, size), "Reserved CDS region should contain this mapping region");
+        return true;
+      }
+
+      ShouldNotReachHere();
+      return false;
+    }
+  }
+}
+
+void VirtualMemoryTracker::set_reserved_region_type(address addr, MEMFLAGS flag) {
+  assert(addr != NULL, "Invalid address");
+  assert(_reserved_regions != NULL, "Sanity check");
+
+  ReservedMemoryRegion   rgn(addr, 1);
+  ReservedMemoryRegion*  reserved_rgn = _reserved_regions->find(rgn);
+  if (reserved_rgn != NULL) {
+    assert(reserved_rgn->contain_address(addr), "Containment");
+    if (reserved_rgn->flag() != flag) {
+      assert(reserved_rgn->flag() == mtNone, "Overwrite memory type");
+      reserved_rgn->set_flag(flag);
+    }
+  }
+}
+
+bool VirtualMemoryTracker::add_committed_region(address addr, size_t size,
+  const NativeCallStack& stack) {
+  assert(addr != NULL, "Invalid address");
+  assert(size > 0, "Invalid size");
+  assert(_reserved_regions != NULL, "Sanity check");
+
+  ReservedMemoryRegion  rgn(addr, size);
+  ReservedMemoryRegion* reserved_rgn = _reserved_regions->find(rgn);
+
+  assert(reserved_rgn != NULL, "No reserved region");
+  assert(reserved_rgn->contain_region(addr, size), "Not completely contained");
+  return reserved_rgn->add_committed_region(addr, size, stack);
+}
+
+bool VirtualMemoryTracker::remove_uncommitted_region(address addr, size_t size) {
+  assert(addr != NULL, "Invalid address");
+  assert(size > 0, "Invalid size");
+  assert(_reserved_regions != NULL, "Sanity check");
+
+  ReservedMemoryRegion  rgn(addr, size);
+  ReservedMemoryRegion* reserved_rgn = _reserved_regions->find(rgn);
+  assert(reserved_rgn != NULL, "No reserved region");
+  assert(reserved_rgn->contain_region(addr, size), "Not completely contained");
+  return reserved_rgn->remove_uncommitted_region(addr, size);
+}
+
+bool VirtualMemoryTracker::remove_released_region(address addr, size_t size) {
+  assert(addr != NULL, "Invalid address");
+  assert(size > 0, "Invalid size");
+  assert(_reserved_regions != NULL, "Sanity check");
+
+  ReservedMemoryRegion  rgn(addr, size);
+  ReservedMemoryRegion* reserved_rgn = _reserved_regions->find(rgn);
+
+  assert(reserved_rgn != NULL, "No reserved region");
+
+  // uncommit regions within the released region
+  if (!reserved_rgn->remove_uncommitted_region(addr, size)) {
+    return false;
+  }
+
+
+  VirtualMemorySummary::record_released_memory(size, reserved_rgn->flag());
+
+  if (reserved_rgn->same_region(addr, size)) {
+    return _reserved_regions->remove(rgn);
+  } else {
+    assert(reserved_rgn->contain_region(addr, size), "Not completely contained");
+    if (reserved_rgn->base() == addr ||
+        reserved_rgn->end() == addr + size) {
+        reserved_rgn->exclude_region(addr, size);
+      return true;
+    } else {
+      address top = reserved_rgn->end();
+      address high_base = addr + size;
+      ReservedMemoryRegion high_rgn(high_base, top - high_base,
+        *reserved_rgn->call_stack(), reserved_rgn->flag());
+
+      // use original region for lower region
+      reserved_rgn->exclude_region(addr, top - addr);
+      LinkedListNode<ReservedMemoryRegion>* new_rgn = _reserved_regions->add(high_rgn);
+      if (new_rgn == NULL) {
+        return false;
+      } else {
+        reserved_rgn->move_committed_regions(addr, *new_rgn->data());
+        return true;
+      }
+    }
+  }
+}
+
+
+bool VirtualMemoryTracker::walk_virtual_memory(VirtualMemoryWalker* walker) {
+  assert(_reserved_regions != NULL, "Sanity check");
+  ThreadCritical tc;
+  LinkedListNode<ReservedMemoryRegion>* head = _reserved_regions->head();
+  while (head != NULL) {
+    const ReservedMemoryRegion* rgn = head->peek();
+    if (!walker->do_allocation_site(rgn)) {
+      return false;
+    }
+    head = head->next();
+  }
+  return true;
+}
+
+// Transition virtual memory tracking level.
+bool VirtualMemoryTracker::transition(NMT_TrackingLevel from, NMT_TrackingLevel to) {
+  if (from == NMT_minimal) {
+    assert(to == NMT_summary || to == NMT_detail, "Just check");
+    VirtualMemorySummary::reset();
+  } else if (to == NMT_minimal) {
+    assert(from == NMT_summary || from == NMT_detail, "Just check");
+    // Clean up virtual memory tracking data structures.
+    ThreadCritical tc;
+    if (_reserved_regions != NULL) {
+      delete _reserved_regions;
+      _reserved_regions = NULL;
+    }
+  }
+
+  return true;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/vm/services/virtualMemoryTracker.hpp	Fri Sep 05 06:26:44 2014 -0400
@@ -0,0 +1,440 @@
+/*
+ * Copyright (c) 2013, 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_SERVICES_VIRTUAL_MEMORY_TRACKER_HPP
+#define SHARE_VM_SERVICES_VIRTUAL_MEMORY_TRACKER_HPP
+
+#if INCLUDE_NMT
+
+#include "memory/allocation.hpp"
+#include "services/allocationSite.hpp"
+#include "services/nmtCommon.hpp"
+#include "utilities/linkedlist.hpp"
+#include "utilities/nativeCallStack.hpp"
+#include "utilities/ostream.hpp"
+
+
+/*
+ * Virtual memory counter
+ */
+class VirtualMemory VALUE_OBJ_CLASS_SPEC {
+ private:
+  size_t     _reserved;
+  size_t     _committed;
+
+ public:
+  VirtualMemory() : _reserved(0), _committed(0) { }
+
+  inline void reserve_memory(size_t sz) { _reserved += sz; }
+  inline void commit_memory (size_t sz) {
+    _committed += sz;
+    assert(_committed <= _reserved, "Sanity check");
+  }
+
+  inline void release_memory (size_t sz) {
+    assert(_reserved >= sz, "Negative amount");
+    _reserved -= sz;
+  }
+
+  inline void uncommit_memory(size_t sz) {
+    assert(_committed >= sz, "Negative amount");
+    _committed -= sz;
+  }
+
+  void reset() {
+    _reserved  = 0;
+    _committed = 0;
+  }
+
+  inline size_t reserved()  const { return _reserved;  }
+  inline size_t committed() const { return _committed; }
+};
+
+// Virtual memory allocation site, keeps track where the virtual memory is reserved.
+class VirtualMemoryAllocationSite : public AllocationSite<VirtualMemory> {
+ public:
+  VirtualMemoryAllocationSite(const NativeCallStack& stack) :
+    AllocationSite<VirtualMemory>(stack) { }
+
+  inline void reserve_memory(size_t sz)  { data()->reserve_memory(sz);  }
+  inline void commit_memory (size_t sz)  { data()->commit_memory(sz);   }
+  inline void uncommit_memory(size_t sz) { data()->uncommit_memory(sz); }
+  inline void release_memory(size_t sz)  { data()->release_memory(sz);  }
+  inline size_t reserved() const  { return peek()->reserved(); }
+  inline size_t committed() const { return peek()->committed(); }
+};
+
+class VirtualMemorySummary;
+
+// This class represents a snapshot of virtual memory at a given time.
+// The latest snapshot is saved in a static area.
+class VirtualMemorySnapshot : public ResourceObj {
+  friend class VirtualMemorySummary;
+
+ private:
+  VirtualMemory  _virtual_memory[mt_number_of_types];
+
+ public:
+  inline VirtualMemory* by_type(MEMFLAGS flag) {
+    int index = NMTUtil::flag_to_index(flag);
+    return &_virtual_memory[index];
+  }
+
+  inline VirtualMemory* by_index(int index) {
+    assert(index >= 0, "Index out of bound");
+    assert(index < mt_number_of_types, "Index out of bound");
+    return &_virtual_memory[index];
+  }
+
+  inline size_t total_reserved() const {
+    size_t amount = 0;
+    for (int index = 0; index < mt_number_of_types; index ++) {
+      amount += _virtual_memory[index].reserved();
+    }
+    return amount;
+  }
+
+  inline size_t total_committed() const {
+    size_t amount = 0;
+    for (int index = 0; index < mt_number_of_types; index ++) {
+      amount += _virtual_memory[index].committed();
+    }
+    return amount;
+  }
+
+  inline void reset() {
+    for (int index = 0; index < mt_number_of_types; index ++) {
+      _virtual_memory[index].reset();
+    }
+  }
+
+  void copy_to(VirtualMemorySnapshot* s) {
+    for (int index = 0; index < mt_number_of_types; index ++) {
+      s->_virtual_memory[index] = _virtual_memory[index];
+    }
+  }
+};
+
+class VirtualMemorySummary : AllStatic {
+ public:
+  static void initialize();
+
+  static inline void record_reserved_memory(size_t size, MEMFLAGS flag) {
+    as_snapshot()->by_type(flag)->reserve_memory(size);
+  }
+
+  static inline void record_committed_memory(size_t size, MEMFLAGS flag) {
+    as_snapshot()->by_type(flag)->commit_memory(size);
+  }
+
+  static inline void record_uncommitted_memory(size_t size, MEMFLAGS flag) {
+    as_snapshot()->by_type(flag)->uncommit_memory(size);
+  }
+
+  static inline void record_released_memory(size_t size, MEMFLAGS flag) {
+    as_snapshot()->by_type(flag)->release_memory(size);
+  }
+
+  // Move virtual memory from one memory type to another.
+  // Virtual memory can be reserved before it is associated with a memory type, and tagged
+  // as 'unknown'. Once the memory is tagged, the virtual memory will be moved from 'unknown'
+  // type to specified memory type.
+  static inline void move_reserved_memory(MEMFLAGS from, MEMFLAGS to, size_t size) {
+    as_snapshot()->by_type(from)->release_memory(size);
+    as_snapshot()->by_type(to)->reserve_memory(size);
+  }
+
+  static inline void move_committed_memory(MEMFLAGS from, MEMFLAGS to, size_t size) {
+    as_snapshot()->by_type(from)->uncommit_memory(size);
+    as_snapshot()->by_type(to)->commit_memory(size);
+  }
+
+  static inline void snapshot(VirtualMemorySnapshot* s) {
+    as_snapshot()->copy_to(s);
+  }
+
+  static inline void reset() {
+    as_snapshot()->reset();
+  }
+
+  static VirtualMemorySnapshot* as_snapshot() {
+    return (VirtualMemorySnapshot*)_snapshot;
+  }
+
+ private:
+  static size_t _snapshot[CALC_OBJ_SIZE_IN_TYPE(VirtualMemorySnapshot, size_t)];
+};
+
+
+
+/*
+ * A virtual memory region
+ */
+class VirtualMemoryRegion VALUE_OBJ_CLASS_SPEC {
+ private:
+  address      _base_address;
+  size_t       _size;
+
+ public:
+  VirtualMemoryRegion(address addr, size_t size) :
+    _base_address(addr), _size(size) {
+     assert(addr != NULL, "Invalid address");
+     assert(size > 0, "Invalid size");
+   }
+
+  inline address base() const { return _base_address;   }
+  inline address end()  const { return base() + size(); }
+  inline size_t  size() const { return _size;           }
+
+  inline bool is_empty() const { return size() == 0; }
+
+  inline bool contain_address(address addr) const {
+    return (addr >= base() && addr < end());
+  }
+
+
+  inline bool contain_region(address addr, size_t size) const {
+    return contain_address(addr) && contain_address(addr + size - 1);
+  }
+
+  inline bool same_region(address addr, size_t sz) const {
+    return (addr == base() && sz == size());
+  }
+
+
+  inline bool overlap_region(address addr, size_t sz) const {
+    VirtualMemoryRegion rgn(addr, sz);
+    return contain_address(addr) ||
+           contain_address(addr + sz - 1) ||
+           rgn.contain_address(base()) ||
+           rgn.contain_address(end() - 1);
+  }
+
+  inline bool adjacent_to(address addr, size_t sz) const {
+    return (addr == end() || (addr + sz) == base());
+  }
+
+  void exclude_region(address addr, size_t sz) {
+    assert(contain_region(addr, sz), "Not containment");
+    assert(addr == base() || addr + sz == end(), "Can not exclude from middle");
+    size_t new_size = size() - sz;
+
+    if (addr == base()) {
+      set_base(addr + sz);
+    }
+    set_size(new_size);
+  }
+
+  void expand_region(address addr, size_t sz) {
+    assert(adjacent_to(addr, sz), "Not adjacent regions");
+    if (base() == addr + sz) {
+      set_base(addr);
+    }
+    set_size(size() + sz);
+  }
+
+ protected:
+  void set_base(address base) {
+    assert(base != NULL, "Sanity check");
+    _base_address = base;
+  }
+
+  void set_size(size_t  size) {
+    assert(size > 0, "Sanity check");
+    _size = size;
+  }
+};
+
+
+class CommittedMemoryRegion : public VirtualMemoryRegion {
+ private:
+  NativeCallStack  _stack;
+
+ public:
+  CommittedMemoryRegion(address addr, size_t size, const NativeCallStack& stack) :
+    VirtualMemoryRegion(addr, size), _stack(stack) { }
+
+  inline int compare(const CommittedMemoryRegion& rgn) const {
+    if (overlap_region(rgn.base(), rgn.size()) ||
+        adjacent_to   (rgn.base(), rgn.size())) {
+      return 0;
+    } else {
+      if (base() == rgn.base()) {
+        return 0;
+      } else if (base() > rgn.base()) {
+        return 1;
+      } else {
+        return -1;
+      }
+    }
+  }
+
+  inline bool equals(const CommittedMemoryRegion& rgn) const {
+    return compare(rgn) == 0;
+  }
+
+  inline void set_call_stack(const NativeCallStack& stack) { _stack = stack; }
+  inline const NativeCallStack* call_stack() const         { return &_stack; }
+};
+
+
+typedef LinkedListIterator<CommittedMemoryRegion> CommittedRegionIterator;
+
+int compare_committed_region(const CommittedMemoryRegion&, const CommittedMemoryRegion&);
+class ReservedMemoryRegion : public VirtualMemoryRegion {
+ private:
+  SortedLinkedList<CommittedMemoryRegion, compare_committed_region>
+    _committed_regions;
+
+  NativeCallStack  _stack;
+  MEMFLAGS         _flag;
+
+  bool             _all_committed;
+
+ public:
+  ReservedMemoryRegion(address base, size_t size, const NativeCallStack& stack,
+    MEMFLAGS flag = mtNone) :
+    VirtualMemoryRegion(base, size), _stack(stack), _flag(flag),
+    _all_committed(false) { }
+
+
+  ReservedMemoryRegion(address base, size_t size) :
+    VirtualMemoryRegion(base, size), _stack(NativeCallStack::EMPTY_STACK), _flag(mtNone),
+    _all_committed(false) { }
+
+  // Copy constructor
+  ReservedMemoryRegion(const ReservedMemoryRegion& rr) :
+    VirtualMemoryRegion(rr.base(), rr.size()) {
+    *this = rr;
+  }
+
+  inline void  set_call_stack(const NativeCallStack& stack) { _stack = stack; }
+  inline const NativeCallStack* call_stack() const          { return &_stack;  }
+
+  void  set_flag(MEMFLAGS flag);
+  inline MEMFLAGS flag() const            { return _flag;  }
+
+  inline int compare(const ReservedMemoryRegion& rgn) const {
+    if (overlap_region(rgn.base(), rgn.size())) {
+      return 0;
+    } else {
+      if (base() == rgn.base()) {
+        return 0;
+      } else if (base() > rgn.base()) {
+        return 1;
+      } else {
+        return -1;
+      }
+    }
+  }
+
+  inline bool equals(const ReservedMemoryRegion& rgn) const {
+    return compare(rgn) == 0;
+  }
+
+  bool    add_committed_region(address addr, size_t size, const NativeCallStack& stack);
+  bool    remove_uncommitted_region(address addr, size_t size);
+
+  size_t  committed_size() const;
+
+  // move committed regions that higher than specified address to
+  // the new region
+  void    move_committed_regions(address addr, ReservedMemoryRegion& rgn);
+
+  inline bool all_committed() const { return _all_committed; }
+  void        set_all_committed(bool b);
+
+  CommittedRegionIterator iterate_committed_regions() const {
+    return CommittedRegionIterator(_committed_regions.head());
+  }
+
+  ReservedMemoryRegion& operator= (const ReservedMemoryRegion& other) {
+    set_base(other.base());
+    set_size(other.size());
+
+    _stack =         *other.call_stack();
+    _flag  =         other.flag();
+    _all_committed = other.all_committed();
+    if (other.all_committed()) {
+      set_all_committed(true);
+    } else {
+      CommittedRegionIterator itr = other.iterate_committed_regions();
+      const CommittedMemoryRegion* rgn = itr.next();
+      while (rgn != NULL) {
+        _committed_regions.add(*rgn);
+        rgn = itr.next();
+      }
+    }
+    return *this;
+  }
+
+ private:
+  // The committed region contains the uncommitted region, subtract the uncommitted
+  // region from this committed region
+  bool remove_uncommitted_region(LinkedListNode<CommittedMemoryRegion>* node,
+    address addr, size_t sz);
+
+  bool add_committed_region(const CommittedMemoryRegion& rgn) {
+    assert(rgn.base() != NULL, "Invalid base address");
+    assert(size() > 0, "Invalid size");
+    return _committed_regions.add(rgn) != NULL;
+  }
+};
+
+int compare_reserved_region_base(const ReservedMemoryRegion& r1, const ReservedMemoryRegion& r2);
+
+class VirtualMemoryWalker : public StackObj {
+ public:
+   virtual bool do_allocation_site(const ReservedMemoryRegion* rgn) { return false; }
+};
+
+// Main class called from MemTracker to track virtual memory allocations, commits and releases.
+class VirtualMemoryTracker : AllStatic {
+ public:
+  static bool initialize(NMT_TrackingLevel level);
+
+  // Late phase initialization
+  static bool late_initialize(NMT_TrackingLevel level);
+
+  static bool add_reserved_region (address base_addr, size_t size, const NativeCallStack& stack,
+    MEMFLAGS flag = mtNone, bool all_committed = false);
+
+  static bool add_committed_region      (address base_addr, size_t size, const NativeCallStack& stack);
+  static bool remove_uncommitted_region (address base_addr, size_t size);
+  static bool remove_released_region    (address base_addr, size_t size);
+  static void set_reserved_region_type  (address addr, MEMFLAGS flag);
+
+  // Walk virtual memory data structure for creating baseline, etc.
+  static bool walk_virtual_memory(VirtualMemoryWalker* walker);
+
+  static bool transition(NMT_TrackingLevel from, NMT_TrackingLevel to);
+
+ private:
+  static SortedLinkedList<ReservedMemoryRegion, compare_reserved_region_base>* _reserved_regions;
+};
+
+
+#endif // INCLUDE_NMT
+
+#endif // SHARE_VM_SERVICES_VIRTUAL_MEMORY_TRACKER_HPP
--- a/src/share/vm/utilities/growableArray.hpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/utilities/growableArray.hpp	Fri Sep 05 06:26:44 2014 -0400
@@ -349,6 +349,7 @@
 
   // inserts the given element before the element at index i
   void insert_before(const int idx, const E& elem) {
+    assert(0 <= idx && idx <= _len, "illegal index");
     check_nesting();
     if (_len == _max) grow(_len);
     for (int j = _len - 1; j >= idx; j--) {
@@ -360,7 +361,7 @@
 
   void appendAll(const GrowableArray<E>* l) {
     for (int i = 0; i < l->_len; i++) {
-      raw_at_put_grow(_len, l->_data[i], 0);
+      raw_at_put_grow(_len, l->_data[i], E());
     }
   }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/vm/utilities/linkedlist.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -0,0 +1,114 @@
+/*
+ * 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.
+ *
+ */
+
+#include "precompiled.hpp"
+
+/////////////// Unit tests ///////////////
+
+#ifndef PRODUCT
+
+#include "runtime/os.hpp"
+#include "utilities/linkedlist.hpp"
+#include "memory/allocation.hpp"
+#include "memory/allocation.inline.hpp"
+
+class Integer : public StackObj {
+ private:
+  int  _value;
+ public:
+  Integer(int i) : _value(i) { }
+
+  int   value() const { return _value; }
+  bool  equals(const Integer& i) const {
+   return _value == i.value();
+  }
+};
+
+int compare_Integer(const Integer& i1, const Integer& i2) {
+  return i1.value() - i2.value();
+}
+
+void check_list_values(const int* expected, const LinkedList<Integer>* list) {
+  LinkedListNode<Integer>* head = list->head();
+  int index = 0;
+  while (head != NULL) {
+    assert(head->peek()->value() == expected[index], "Unexpected value");
+    head = head->next();
+    index ++;
+  }
+}
+
+void Test_linked_list() {
+  LinkedListImpl<Integer, ResourceObj::C_HEAP, mtTest>  ll;
+
+
+  // Test regular linked list
+  assert(ll.is_empty(), "Start with empty list");
+  Integer one(1), two(2), three(3), four(4), five(5), six(6);
+
+  ll.add(six);
+  assert(!ll.is_empty(), "Should not be empty");
+
+  Integer* i = ll.find(six);
+  assert(i != NULL, "Should find it");
+
+  i = ll.find(three);
+  assert(i == NULL, "Not in the list");
+
+  LinkedListNode<Integer>* node = ll.find_node(six);
+  assert(node != NULL, "6 is in the list");
+
+  ll.insert_after(three, node);
+  ll.insert_before(one, node);
+  int expected[3] = {1, 6, 3};
+  check_list_values(expected, &ll);
+
+  ll.add(two);
+  ll.add(four);
+  ll.add(five);
+
+  // Test sorted linked list
+  SortedLinkedList<Integer, compare_Integer, ResourceObj::C_HEAP, mtTest> sl;
+  assert(sl.is_empty(), "Start with empty list");
+
+  size_t ll_size = ll.size();
+  sl.move(&ll);
+  size_t sl_size = sl.size();
+
+  assert(ll_size == sl_size, "Should be the same size");
+  assert(ll.is_empty(), "No more entires");
+
+  // sorted result
+  int sorted_result[] = {1, 2, 3, 4, 5, 6};
+  check_list_values(sorted_result, &sl);
+
+  node = sl.find_node(four);
+  assert(node != NULL, "4 is in the list");
+  sl.remove_before(node);
+  sl.remove_after(node);
+  int remains[] = {1, 2, 4, 6};
+  check_list_values(remains, &sl);
+}
+#endif // PRODUCT
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/vm/utilities/linkedlist.hpp	Fri Sep 05 06:26:44 2014 -0400
@@ -0,0 +1,416 @@
+/*
+ * 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.
+ *
+ */
+
+#ifndef SHARE_VM_UTILITIES_LINKED_LIST_HPP
+#define SHARE_VM_UTILITIES_LINKED_LIST_HPP
+
+#include "memory/allocation.hpp"
+
+/*
+ * The implementation of a generic linked list, which uses various
+ * backing storages, such as C heap, arena and resource, etc.
+ */
+
+
+// An entry in a linked list. It should use the same backing storage
+// as the linked list that contains this entry.
+template <class E> class LinkedListNode : public ResourceObj {
+ private:
+  E                       _data;  // embedded content
+  LinkedListNode<E>*      _next;  // next entry
+
+ protected:
+  LinkedListNode() : _next(NULL) { }
+
+ public:
+  LinkedListNode(const E& e): _data(e), _next(NULL) { }
+
+  inline void set_next(LinkedListNode<E>* node) { _next = node; }
+  inline LinkedListNode<E> * next() const       { return _next; }
+
+  E*  data() { return &_data; }
+  const E* peek() const { return &_data; }
+};
+
+// A linked list interface. It does not specify
+// any storage type it uses, so all methods involving
+// memory allocation or deallocation are pure virtual
+template <class E> class LinkedList : public ResourceObj {
+ protected:
+  LinkedListNode<E>*    _head;
+
+ public:
+  LinkedList() : _head(NULL) { }
+
+  inline void set_head(LinkedListNode<E>* h) { _head = h; }
+  inline LinkedListNode<E>* head() const     { return _head; }
+  inline bool is_empty()           const     { return head() == NULL; }
+
+  inline size_t size() const {
+    LinkedListNode<E>* p;
+    size_t count = 0;
+    for (p = head(); p != NULL; count++, p = p->next());
+    return count;
+ }
+
+  // Move all entries from specified linked list to this one
+  virtual void move(LinkedList<E>* list) = 0;
+
+  // Add an entry to this linked list
+  virtual LinkedListNode<E>* add(const E& e) = 0;
+  // Add all entries from specified linked list to this one,
+  virtual void add(LinkedListNode<E>* node) = 0;
+
+  // Add a linked list to this linked list
+  virtual bool  add(const LinkedList<E>* list) = 0;
+
+  // Search entry in the linked list
+  virtual LinkedListNode<E>* find_node(const E& e) = 0;
+  virtual E* find(const E& e) = 0;
+
+  // Insert entry to the linked list
+  virtual LinkedListNode<E>* insert_before(const E& e, LinkedListNode<E>* ref) = 0;
+  virtual LinkedListNode<E>* insert_after (const E& e, LinkedListNode<E>* ref) = 0;
+
+  // Remove entry from the linked list
+  virtual bool               remove(const E& e) = 0;
+  virtual bool               remove(LinkedListNode<E>* node) = 0;
+  virtual bool               remove_before(LinkedListNode<E>* ref) = 0;
+  virtual bool               remove_after(LinkedListNode<E>*  ref) = 0;
+
+  LinkedListNode<E>* unlink_head() {
+    LinkedListNode<E>* h = this->head();
+    if (h != NULL) {
+      this->set_head(h->next());
+    }
+    return h;
+  }
+
+  DEBUG_ONLY(virtual ResourceObj::allocation_type storage_type() = 0;)
+};
+
+// A linked list implementation.
+// The linked list can be allocated in various type of memory: C heap, arena and resource area, etc.
+template <class E, ResourceObj::allocation_type T = ResourceObj::C_HEAP,
+  MEMFLAGS F = mtNMT, AllocFailType alloc_failmode = AllocFailStrategy::RETURN_NULL>
+  class LinkedListImpl : public LinkedList<E> {
+ protected:
+  Arena*                 _arena;
+ public:
+  LinkedListImpl() :  _arena(NULL) { }
+  LinkedListImpl(Arena* a) : _arena(a) { }
+
+  virtual ~LinkedListImpl() {
+    clear();
+  }
+
+  virtual void clear() {
+    LinkedListNode<E>* p = this->head();
+    this->set_head(NULL);
+    while (p != NULL) {
+      LinkedListNode<E>* to_delete = p;
+      p = p->next();
+      delete_node(to_delete);
+    }
+  }
+
+  // Add an entry to the linked list
+  virtual LinkedListNode<E>* add(const E& e)  {
+    LinkedListNode<E>* node = this->new_node(e);
+    if (node != NULL) {
+      this->add(node);
+    }
+
+    return node;
+  }
+
+  virtual void add(LinkedListNode<E>* node) {
+    assert(node != NULL, "NULL pointer");
+    node->set_next(this->head());
+    this->set_head(node);
+  }
+
+  // Move a linked list to this linked list, both have to be allocated on the same
+  // storage type.
+  virtual void move(LinkedList<E>* list) {
+    assert(list->storage_type() == this->storage_type(), "Different storage type");
+    LinkedListNode<E>* node = this->head();
+    while (node != NULL && node->next() != NULL) {
+      node = node->next();
+    }
+    if (node == NULL) {
+      this->set_head(list->head());
+    } else {
+      node->set_next(list->head());
+    }
+    // All entries are moved
+    list->set_head(NULL);
+  }
+
+  virtual bool add(const LinkedList<E>* list) {
+    LinkedListNode<E>* node = list->head();
+    while (node != NULL) {
+      if (this->add(*node->peek()) == NULL) {
+        return false;
+      }
+      node = node->next();
+    }
+    return true;
+  }
+
+
+  virtual LinkedListNode<E>* find_node(const E& e) {
+    LinkedListNode<E>* p = this->head();
+    while (p != NULL && !p->peek()->equals(e)) {
+      p = p->next();
+    }
+    return p;
+  }
+
+  E* find(const E& e) {
+    LinkedListNode<E>* node = find_node(e);
+    return (node == NULL) ? NULL : node->data();
+  }
+
+
+  // Add an entry in front of the reference entry
+  LinkedListNode<E>* insert_before(const E& e, LinkedListNode<E>* ref_node) {
+    LinkedListNode<E>* node = this->new_node(e);
+    if (node == NULL) return NULL;
+    if (ref_node == this->head()) {
+      node->set_next(ref_node);
+      this->set_head(node);
+    } else {
+      LinkedListNode<E>* p = this->head();
+      while (p != NULL && p->next() != ref_node) {
+        p = p->next();
+      }
+      assert(p != NULL, "ref_node not in the list");
+      node->set_next(ref_node);
+      p->set_next(node);
+    }
+    return node;
+  }
+
+   // Add an entry behind the reference entry
+   LinkedListNode<E>* insert_after(const E& e, LinkedListNode<E>* ref_node) {
+     LinkedListNode<E>* node = this->new_node(e);
+     if (node == NULL) return NULL;
+     node->set_next(ref_node->next());
+     ref_node->set_next(node);
+     return node;
+   }
+
+   // Remove an entry from the linked list.
+   // Return true if the entry is successfully removed
+   virtual bool remove(const E& e) {
+     LinkedListNode<E>* tmp = this->head();
+     LinkedListNode<E>* prev = NULL;
+
+     while (tmp != NULL) {
+       if (tmp->peek()->equals(e)) {
+         return remove_after(prev);
+       }
+       prev = tmp;
+       tmp = tmp->next();
+     }
+     return false;
+  }
+
+  // Remove the node after the reference entry
+  virtual bool remove_after(LinkedListNode<E>* prev) {
+    LinkedListNode<E>* to_delete;
+    if (prev == NULL) {
+      to_delete = this->unlink_head();
+    } else {
+      to_delete = prev->next();
+      if (to_delete != NULL) {
+        prev->set_next(to_delete->next());
+      }
+    }
+
+    if (to_delete != NULL) {
+      delete_node(to_delete);
+      return true;
+    }
+    return false;
+  }
+
+  virtual bool remove(LinkedListNode<E>* node) {
+    LinkedListNode<E>* p = this->head();
+    while (p != NULL && p->next() != node) {
+      p = p->next();
+    }
+    if (p != NULL) {
+      p->set_next(node->next());
+      delete_node(node);
+      return true;
+    } else {
+      return false;
+    }
+  }
+
+  virtual bool remove_before(LinkedListNode<E>* ref) {
+    assert(ref != NULL, "NULL pointer");
+    LinkedListNode<E>* p = this->head();
+    LinkedListNode<E>* to_delete = NULL; // to be deleted
+    LinkedListNode<E>* prev = NULL;      // node before the node to be deleted
+    while (p != NULL && p != ref) {
+      prev = to_delete;
+      to_delete = p;
+      p = p->next();
+    }
+    if (p == NULL || to_delete == NULL) return false;
+    assert(to_delete->next() == ref, "Wrong node to delete");
+    assert(prev == NULL || prev->next() == to_delete,
+      "Sanity check");
+    if (prev == NULL) {
+      assert(to_delete == this->head(), "Must be head");
+      this->set_head(to_delete->next());
+    } else {
+      prev->set_next(to_delete->next());
+    }
+    delete_node(to_delete);
+    return true;
+  }
+
+  DEBUG_ONLY(ResourceObj::allocation_type storage_type() { return T; })
+ protected:
+  // Create new linked list node object in specified storage
+  LinkedListNode<E>* new_node(const E& e) const {
+     switch(T) {
+       case ResourceObj::ARENA: {
+         assert(_arena != NULL, "Arena not set");
+         return new(_arena) LinkedListNode<E>(e);
+       }
+       case ResourceObj::RESOURCE_AREA:
+       case ResourceObj::C_HEAP: {
+         if (alloc_failmode == AllocFailStrategy::RETURN_NULL) {
+           return new(std::nothrow, T, F) LinkedListNode<E>(e);
+         } else {
+           return new(T, F) LinkedListNode<E>(e);
+         }
+       }
+       default:
+         ShouldNotReachHere();
+     }
+     return NULL;
+  }
+
+  // Delete linked list node object
+  void delete_node(LinkedListNode<E>* node) {
+    if (T == ResourceObj::C_HEAP) {
+      delete node;
+    }
+  }
+};
+
+// Sorted linked list. The linked list maintains sorting order specified by the comparison
+// function
+template <class E, int (*FUNC)(const E&, const E&),
+  ResourceObj::allocation_type T = ResourceObj::C_HEAP,
+  MEMFLAGS F = mtNMT, AllocFailType alloc_failmode = AllocFailStrategy::RETURN_NULL>
+  class SortedLinkedList : public LinkedListImpl<E, T, F, alloc_failmode> {
+ public:
+  SortedLinkedList() { }
+  SortedLinkedList(Arena* a) : LinkedListImpl<E, T, F, alloc_failmode>(a) { }
+
+  virtual LinkedListNode<E>* add(const E& e) {
+    return LinkedListImpl<E, T, F, alloc_failmode>::add(e);
+  }
+
+  virtual void move(LinkedList<E>* list) {
+    assert(list->storage_type() == this->storage_type(), "Different storage type");
+    LinkedListNode<E>* node;
+    while ((node = list->unlink_head()) != NULL) {
+      this->add(node);
+    }
+    assert(list->is_empty(), "All entries are moved");
+  }
+
+  virtual void add(LinkedListNode<E>* node) {
+    assert(node != NULL, "NULL pointer");
+    LinkedListNode<E>* tmp = this->head();
+    LinkedListNode<E>* prev = NULL;
+
+    int cmp_val;
+    while (tmp != NULL) {
+      cmp_val = FUNC(*tmp->peek(), *node->peek());
+      if (cmp_val >= 0) {
+        break;
+      }
+      prev = tmp;
+      tmp = tmp->next();
+    }
+
+    if (prev != NULL) {
+      node->set_next(prev->next());
+      prev->set_next(node);
+    } else {
+      node->set_next(this->head());
+      this->set_head(node);
+    }
+  }
+
+  virtual bool add(const LinkedList<E>* list) {
+    return LinkedListImpl<E, T, F, alloc_failmode>::add(list);
+  }
+
+  virtual LinkedListNode<E>* find_node(const E& e) {
+    LinkedListNode<E>* p = this->head();
+
+    while (p != NULL) {
+      int comp_val = FUNC(*p->peek(), e);
+      if (comp_val == 0) {
+        return p;
+      } else if (comp_val > 0) {
+        return NULL;
+      }
+      p = p->next();
+    }
+    return NULL;
+  }
+};
+
+// Iterates all entries in the list
+template <class E> class LinkedListIterator : public StackObj {
+ private:
+  LinkedListNode<E>* _p;
+  bool               _is_empty;
+ public:
+  LinkedListIterator(LinkedListNode<E>* head) : _p(head) {
+    _is_empty = (head == NULL);
+  }
+
+  bool is_empty() const { return _is_empty; }
+
+  const E* next() {
+    if (_p == NULL) return NULL;
+    const E* e = _p->peek();
+    _p = _p->next();
+    return e;
+  }
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/vm/utilities/nativeCallStack.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -0,0 +1,119 @@
+/*
+ * 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.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "runtime/os.hpp"
+#include "utilities/globalDefinitions.hpp"
+#include "utilities/nativeCallStack.hpp"
+
+const NativeCallStack NativeCallStack::EMPTY_STACK(0, false);
+
+NativeCallStack::NativeCallStack(int toSkip, bool fillStack) :
+  _hash_value(0) {
+
+#if !PLATFORM_NATIVE_STACK_WALKING_SUPPORTED
+  fillStack = false;
+#endif
+
+  if (fillStack) {
+    os::get_native_stack(_stack, NMT_TrackingStackDepth, toSkip);
+  } else {
+    for (int index = 0; index < NMT_TrackingStackDepth; index ++) {
+      _stack[index] = NULL;
+    }
+  }
+}
+
+NativeCallStack::NativeCallStack(address* pc, int frameCount) {
+  int frameToCopy = (frameCount < NMT_TrackingStackDepth) ?
+    frameCount : NMT_TrackingStackDepth;
+  int index;
+  for (index = 0; index < frameToCopy; index ++) {
+    _stack[index] = pc[index];
+  }
+  for (; index < NMT_TrackingStackDepth; index ++) {
+    _stack[index] = NULL;
+  }
+}
+
+// number of stack frames captured
+int NativeCallStack::frames() const {
+  int index;
+  for (index = 0; index < NMT_TrackingStackDepth; index ++) {
+    if (_stack[index] == NULL) {
+      break;
+    }
+  }
+  return index;
+}
+
+// Hash code. Any better algorithm?
+int NativeCallStack::hash() const {
+  long hash_val = _hash_value;
+  if (hash_val == 0) {
+    long pc;
+    int  index;
+    for (index = 0; index < NMT_TrackingStackDepth; index ++) {
+      pc = (long)_stack[index];
+      if (pc == 0) break;
+      hash_val += pc;
+    }
+
+    NativeCallStack* p = const_cast<NativeCallStack*>(this);
+    p->_hash_value = (int)(hash_val & 0xFFFFFFFF);
+  }
+  return _hash_value;
+}
+
+void NativeCallStack::print_on(outputStream* out) const {
+  print_on(out, 0);
+}
+
+// Decode and print this call path
+void NativeCallStack::print_on(outputStream* out, int indent) const {
+  address pc;
+  char    buf[1024];
+  int     offset;
+  if (is_empty()) {
+    for (int index = 0; index < indent; index ++) out->print(" ");
+#if PLATFORM_NATIVE_STACK_WALKING_SUPPORTED
+    out->print("[BOOTSTRAP]");
+#else
+    out->print("[No stack]");
+#endif
+  } else {
+    for (int frame = 0; frame < NMT_TrackingStackDepth; frame ++) {
+      pc = get_frame(frame);
+      if (pc == NULL) break;
+      // Print indent
+      for (int index = 0; index < indent; index ++) out->print(" ");
+      if (os::dll_address_to_function_name(pc, buf, sizeof(buf), &offset)) {
+        out->print_cr("[" PTR_FORMAT "] %s+0x%x", p2i(pc), buf, offset);
+      } else {
+        out->print_cr("[" PTR_FORMAT "]", p2i(pc));
+      }
+    }
+  }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/vm/utilities/nativeCallStack.hpp	Fri Sep 05 06:26:44 2014 -0400
@@ -0,0 +1,98 @@
+/*
+ * 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.
+ *
+ */
+
+#ifndef SHARE_VM_UTILITIES_NATIVE_CALL_STACK_HPP
+#define SHARE_VM_UTILITIES_NATIVE_CALL_STACK_HPP
+
+#include "memory/allocation.hpp"
+#include "services/nmtCommon.hpp"
+#include "utilities/ostream.hpp"
+
+/*
+ * This class represents a native call path (does not include Java frame)
+ *
+ * This class is developed in the context of native memory tracking, it can
+ * be an useful tool for debugging purpose.
+ *
+ * For example, following code should print out native call path:
+ *
+ *   ....
+ *   NativeCallStack here;
+ *   here.print_on(tty);
+ *   ....
+ *
+ * However, there are a couple of restrictions on this class. If the restrictions are
+ * not strictly followed, it may break native memory tracking badly.
+ *
+ * 1. Number of stack frames to capture, is defined by native memory tracking.
+ *    This number has impacts on how much memory to be used by native
+ *    memory tracking.
+ * 2. The class is strict stack object, no heap or virtual memory can be allocated
+ *    from it.
+ */
+class NativeCallStack : public StackObj {
+ public:
+  static const NativeCallStack EMPTY_STACK;
+
+ private:
+  address   _stack[NMT_TrackingStackDepth];
+  int       _hash_value;
+
+ public:
+  NativeCallStack(int toSkip = 0, bool fillStack = false);
+  NativeCallStack(address* pc, int frameCount);
+
+
+  // if it is an empty stack
+  inline bool is_empty() const {
+    return _stack[0] == NULL;
+  }
+
+  // number of stack frames captured
+  int frames() const;
+
+  inline int compare(const NativeCallStack& other) const {
+    return memcmp(_stack, other._stack, sizeof(_stack));
+  }
+
+  inline bool equals(const NativeCallStack& other) const {
+    // compare hash values
+    if (hash() != other.hash()) return false;
+    // compare each frame
+    return compare(other) == 0;
+  }
+
+  inline address get_frame(int index) const {
+    assert(index >= 0 && index < NMT_TrackingStackDepth, "Index out of bound");
+    return _stack[index];
+  }
+
+  // Hash code. Any better algorithm?
+  int hash() const;
+
+  void print_on(outputStream* out) const;
+  void print_on(outputStream* out, int indent) const;
+};
+
+#endif
--- a/src/share/vm/utilities/vmError.cpp	Thu Sep 04 13:06:04 2014 -0400
+++ b/src/share/vm/utilities/vmError.cpp	Fri Sep 05 06:26:44 2014 -0400
@@ -772,6 +772,11 @@
        st->cr();
      }
 
+  STEP(228, "(Native Memory Tracking)" )
+     if (_verbose) {
+       MemTracker::final_report(st);
+     }
+
   STEP(230, "" )
 
      if (_verbose) {
@@ -895,9 +900,6 @@
   static bool log_done = false;         // done saving error log
   static bool transmit_report_done = false; // done error reporting
 
-  // disble NMT to avoid further exception
-  MemTracker::shutdown(MemTracker::NMT_error_reporting);
-
   if (SuppressFatalErrorMessage) {
       os::abort();
   }
--- a/test/TEST.ROOT	Thu Sep 04 13:06:04 2014 -0400
+++ b/test/TEST.ROOT	Fri Sep 05 06:26:44 2014 -0400
@@ -1,5 +1,5 @@
 # 
-# Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2005, 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
@@ -27,6 +27,6 @@
 # It also contains test-suite configuration information.
 
 # The list of keywords supported in this test suite
-keys=cte_test jcmd nmt regression gc
+keys=cte_test jcmd nmt regression gc stress
 
 groups=TEST.groups [closed/TEST.groups]
--- a/test/TEST.groups	Thu Sep 04 13:06:04 2014 -0400
+++ b/test/TEST.groups	Fri Sep 05 06:26:44 2014 -0400
@@ -73,15 +73,23 @@
   runtime/jsig/Test8017498.sh \
   runtime/Metaspace/FragmentMetaspace.java \
   runtime/NMT/BaselineWithParameter.java \
+  runtime/NMT/JcmdBaselineDetail.java \
+  runtime/NMT/JcmdDetailDiff.java \
+  runtime/NMT/JcmdScaleDetail.java \
   runtime/NMT/JcmdScale.java \
   runtime/NMT/JcmdWithNMTDisabled.java \
+  runtime/NMT/MallocRoundingReportTest.java \
+  runtime/NMT/MallocSiteHashOverflow.java \
+  runtime/NMT/MallocStressTest.java \
   runtime/NMT/MallocTestType.java \
   runtime/NMT/ReleaseCommittedMemory.java \
+  runtime/NMT/ReleaseNoCommit.java \
   runtime/NMT/ShutdownTwice.java \
   runtime/NMT/SummaryAfterShutdown.java \
   runtime/NMT/SummarySanityCheck.java \
   runtime/NMT/ThreadedMallocTestType.java \
   runtime/NMT/ThreadedVirtualAllocTestType.java \
+  runtime/NMT/VirtualAllocCommitUncommitRecommit.java \
   runtime/NMT/VirtualAllocTestType.java \
   runtime/RedefineObject/TestRedefineObject.java \
   runtime/Thread/TestThreadDumpMonitorContention.java \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/compiler/classUnloading/anonymousClass/TestAnonymousClassUnloading.java	Fri Sep 05 06:26:44 2014 -0400
@@ -0,0 +1,130 @@
+/*
+ * 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.
+ */
+
+import sun.hotspot.WhiteBox;
+import sun.misc.Unsafe;
+import sun.misc.IOUtils;
+
+import java.lang.reflect.Method;
+import java.net.URL;
+import java.net.URLConnection;
+
+/*
+ * @test TestAnonymousClassUnloading
+ * @bug 8054402
+ * @summary "Tests unloading of anonymous classes."
+ * @library /testlibrary /testlibrary/whitebox
+ * @compile TestAnonymousClassUnloading.java
+ * @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 {
+    private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
+    private static final Unsafe UNSAFE = Unsafe.getUnsafe();
+    private static int COMP_LEVEL_SIMPLE = 1;
+    private static int COMP_LEVEL_FULL_OPTIMIZATION = 4;
+
+    /**
+     * We override hashCode here to be able to access this implementation
+     * via an Object reference (we cannot cast to TestAnonymousClassUnloading).
+     */
+    @Override
+    public int hashCode() {
+        return 42;
+    }
+
+    /**
+     * Does some work by using the anonymousClass.
+     * @param anonymousClass Class performing some work (will be unloaded)
+     */
+    static private void doWork(Class<?> anonymousClass) throws InstantiationException, IllegalAccessException {
+        // Create a new instance
+        Object anon = anonymousClass.newInstance();
+        // We would like to call a method of anonymousClass here but we cannot cast because the class
+        // was loaded by a different class loader. One solution would be to use reflection but since
+        // we want C2 to implement the call as an IC we call Object::hashCode() here which actually
+        // calls anonymousClass::hashCode(). C2 will then implement this call as an IC.
+        if (anon.hashCode() != 42) {
+            new RuntimeException("Work not done");
+        }
+    }
+
+    /**
+     * Makes sure that method is compiled by forcing compilation if not yet compiled.
+     * @param m Method to be checked
+     */
+    static private void makeSureIsCompiled(Method m) {
+        // Make sure background compilation is disabled
+        if (WHITE_BOX.getBooleanVMFlag("BackgroundCompilation")) {
+            throw new RuntimeException("Background compilation enabled");
+        }
+
+        // Check if already compiled
+        if (!WHITE_BOX.isMethodCompiled(m)) {
+            // If not, try to compile it with C2
+            if(!WHITE_BOX.enqueueMethodForCompilation(m, COMP_LEVEL_FULL_OPTIMIZATION)) {
+                // C2 compiler not available, try to compile with C1
+                WHITE_BOX.enqueueMethodForCompilation(m, COMP_LEVEL_SIMPLE);
+            }
+            // Because background compilation is disabled, method should now be compiled
+            if(!WHITE_BOX.isMethodCompiled(m)) {
+                throw new RuntimeException(m + " not compiled");
+            }
+        }
+    }
+
+    /**
+     * This test creates stale Klass* metadata referenced by a compiled IC.
+     *
+     * The following steps are performed:
+     * (1) An anonymous version of TestAnonymousClassUnloading is loaded by a custom class loader
+     * (2) The method doWork that calls a method of the anonymous class is compiled. The call
+     *     is implemented as an IC referencing Klass* metadata of the anonymous class.
+     * (3) Unloading of the anonymous class is enforced. The IC now references dead metadata.
+     */
+    static public void main(String[] args) throws Exception {
+        // (1) Load an anonymous version of this class using the corresponding Unsafe method
+        URL classUrl = TestAnonymousClassUnloading.class.getResource("TestAnonymousClassUnloading.class");
+        URLConnection connection = classUrl.openConnection();
+        byte[] classBytes = IOUtils.readFully(connection.getInputStream(), connection.getContentLength(), true);
+        Class<?> anonymousClass = UNSAFE.defineAnonymousClass(TestAnonymousClassUnloading.class, classBytes, null);
+
+        // (2) Make sure all paths of doWork are profiled and compiled
+        for (int i = 0; i < 100000; ++i) {
+            doWork(anonymousClass);
+        }
+
+        // Make sure doWork is compiled now
+        Method doWork = TestAnonymousClassUnloading.class.getDeclaredMethod("doWork", Class.class);
+        makeSureIsCompiled(doWork);
+
+        // (3) Throw away reference to anonymousClass to allow unloading
+        anonymousClass = null;
+
+        // Force garbage collection to trigger unloading of anonymousClass
+        // Dead metadata reference to anonymousClass triggers JDK-8054402
+        WHITE_BOX.fullGC();
+    }
+}
--- a/test/gc/class_unloading/TestCMSClassUnloadingEnabledHWM.java	Thu Sep 04 13:06:04 2014 -0400
+++ b/test/gc/class_unloading/TestCMSClassUnloadingEnabledHWM.java	Fri Sep 05 06:26:44 2014 -0400
@@ -45,6 +45,7 @@
   private static OutputAnalyzer run(boolean enableUnloading) throws Exception {
     ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
       "-Xbootclasspath/a:.",
+      "-XX:+UnlockDiagnosticVMOptions",
       "-XX:+WhiteBoxAPI",
       "-XX:MetaspaceSize=" + MetaspaceSize,
       "-Xmn" + YoungGenSize,
--- a/test/gc/class_unloading/TestG1ClassUnloadingHWM.java	Thu Sep 04 13:06:04 2014 -0400
+++ b/test/gc/class_unloading/TestG1ClassUnloadingHWM.java	Fri Sep 05 06:26:44 2014 -0400
@@ -45,6 +45,7 @@
   private static OutputAnalyzer run(boolean enableUnloading) throws Exception {
     ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
       "-Xbootclasspath/a:.",
+      "-XX:+UnlockDiagnosticVMOptions",
       "-XX:+WhiteBoxAPI",
       "-XX:MetaspaceSize=" + MetaspaceSize,
       "-Xmn" + YoungGenSize,
--- a/test/gc/g1/TestEagerReclaimHumongousRegions2.java	Thu Sep 04 13:06:04 2014 -0400
+++ b/test/gc/g1/TestEagerReclaimHumongousRegions2.java	Fri Sep 05 06:26:44 2014 -0400
@@ -46,6 +46,8 @@
 }
 
 class ReclaimRegionFast {
+    public static final long MAX_MILLIS_FOR_RUN = 50 * 1000; // The maximum runtime for the actual test.
+
     public static final int M = 1024*1024;
 
     public static LinkedList<Object> garbageList = new LinkedList<Object>();
@@ -83,7 +85,14 @@
 
         Object ref_from_stack = large1;
 
+        long start_millis = System.currentTimeMillis();
+
         for (int i = 0; i < 20; i++) {
+            long current_millis = System.currentTimeMillis();
+            if ((current_millis - start_millis) > MAX_MILLIS_FOR_RUN) {
+              System.out.println("Finishing test because maximum runtime exceeded");
+              break;
+            }
             // A set of large objects that will be reclaimed eagerly - and hopefully marked.
             large1 = new int[M - 20];
             large2 = new int[M - 20];
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/gc/whitebox/TestWBGC.java	Fri Sep 05 06:26:44 2014 -0400
@@ -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/test/runtime/NMT/BaselineWithParameter.java	Thu Sep 04 13:06:04 2014 -0400
+++ b/test/runtime/NMT/BaselineWithParameter.java	Fri Sep 05 06:26:44 2014 -0400
@@ -27,6 +27,7 @@
  * @key nmt jcmd regression
  * @summary Regression test for invoking a jcmd with baseline=false, result was that the target VM crashed
  * @library /testlibrary
+ * @ignore
  * @run main/othervm -XX:NativeMemoryTracking=detail BaselineWithParameter
  */
 
--- a/test/runtime/NMT/CommandLineDetail.java	Thu Sep 04 13:06:04 2014 -0400
+++ b/test/runtime/NMT/CommandLineDetail.java	Fri Sep 05 06:26:44 2014 -0400
@@ -26,6 +26,7 @@
  * @key nmt
  * @summary Running with NMT detail should not result in an error
  * @library /testlibrary
+ * @ignore
  */
 
 import com.oracle.java.testlibrary.*;
--- a/test/runtime/NMT/CommandLineEmptyArgument.java	Thu Sep 04 13:06:04 2014 -0400
+++ b/test/runtime/NMT/CommandLineEmptyArgument.java	Fri Sep 05 06:26:44 2014 -0400
@@ -26,6 +26,7 @@
  * @key nmt
  * @summary Empty argument to NMT should result in an informative error message
  * @library /testlibrary
+ * @ignore
  */
 
 import com.oracle.java.testlibrary.*;
--- a/test/runtime/NMT/CommandLineInvalidArgument.java	Thu Sep 04 13:06:04 2014 -0400
+++ b/test/runtime/NMT/CommandLineInvalidArgument.java	Fri Sep 05 06:26:44 2014 -0400
@@ -26,6 +26,7 @@
  * @key nmt
  * @summary Invalid argument to NMT should result in an informative error message
  * @library /testlibrary
+ * @ignore
  */
 
 import com.oracle.java.testlibrary.*;
--- a/test/runtime/NMT/CommandLineSummary.java	Thu Sep 04 13:06:04 2014 -0400
+++ b/test/runtime/NMT/CommandLineSummary.java	Fri Sep 05 06:26:44 2014 -0400
@@ -26,6 +26,7 @@
  * @key nmt
  * @summary Running with NMT summary should not result in an error
  * @library /testlibrary
+ * @ignore
  */
 
 import com.oracle.java.testlibrary.*;
--- a/test/runtime/NMT/CommandLineTurnOffNMT.java	Thu Sep 04 13:06:04 2014 -0400
+++ b/test/runtime/NMT/CommandLineTurnOffNMT.java	Fri Sep 05 06:26:44 2014 -0400
@@ -26,6 +26,7 @@
  * @key nmt
  * @summary Turning off NMT should not result in an error
  * @library /testlibrary
+ * @ignore
  */
 
 import com.oracle.java.testlibrary.*;
--- a/test/runtime/NMT/JcmdScale.java	Thu Sep 04 13:06:04 2014 -0400
+++ b/test/runtime/NMT/JcmdScale.java	Fri Sep 05 06:26:44 2014 -0400
@@ -26,6 +26,7 @@
  * @key nmt jcmd
  * @summary Test the NMT scale parameter
  * @library /testlibrary
+ * @ignore
  * @run main/othervm -XX:NativeMemoryTracking=summary JcmdScale
  */
 
@@ -41,15 +42,15 @@
 
     pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "scale=KB"});
     output = new OutputAnalyzer(pb.start());
-    output.shouldContain("KB,  committed=");
+    output.shouldContain("KB, committed=");
 
     pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "scale=MB"});
     output = new OutputAnalyzer(pb.start());
-    output.shouldContain("MB,  committed=");
+    output.shouldContain("MB, committed=");
 
     pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "scale=GB"});
     output = new OutputAnalyzer(pb.start());
-    output.shouldContain("GB,  committed=");
+    output.shouldContain("GB, committed=");
 
     pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "scale=apa"});
     output = new OutputAnalyzer(pb.start());
@@ -57,7 +58,7 @@
 
     pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "summary", "scale=GB"});
     output = new OutputAnalyzer(pb.start());
-    output.shouldContain("GB,  committed=");
+    output.shouldContain("GB, committed=");
 
     pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "summary", "scale=apa"});
     output = new OutputAnalyzer(pb.start());
--- a/test/runtime/NMT/JcmdWithNMTDisabled.java	Thu Sep 04 13:06:04 2014 -0400
+++ b/test/runtime/NMT/JcmdWithNMTDisabled.java	Fri Sep 05 06:26:44 2014 -0400
@@ -26,6 +26,7 @@
  * @key nmt jcmd
  * @summary Verify that jcmd correctly reports that NMT is not enabled
  * @library /testlibrary
+ * @ignore
  * First run without enabling NMT
  * @run main/othervm JcmdWithNMTDisabled
  * Then run with explicitly disabling NMT, should not be any difference
--- a/test/runtime/NMT/MallocTestType.java	Thu Sep 04 13:06:04 2014 -0400
+++ b/test/runtime/NMT/MallocTestType.java	Fri Sep 05 06:26:44 2014 -0400
@@ -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.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -27,6 +27,7 @@
  * @key nmt jcmd
  * @library /testlibrary /testlibrary/whitebox
  * @build MallocTestType
+ * @ignore
  * @run main ClassFileInstaller sun.hotspot.WhiteBox
  * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:NativeMemoryTracking=detail MallocTestType
  */
@@ -51,11 +52,6 @@
     long memAlloc1 = wb.NMTMalloc(512 * 1024);
     wb.NMTFree(memAlloc2);
 
-    // Use WB API to ensure that all data has been merged before we continue
-    if (!wb.NMTWaitForDataMerge()) {
-      throw new Exception("Call to WB API NMTWaitForDataMerge() failed");
-    }
-
     // Run 'jcmd <pid> VM.native_memory summary'
     pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "summary"});
     output = new OutputAnalyzer(pb.start());
@@ -64,10 +60,6 @@
     // Free the memory allocated by NMTAllocTest
     wb.NMTFree(memAlloc1);
 
-    // Use WB API to ensure that all data has been merged before we continue
-    if (!wb.NMTWaitForDataMerge()) {
-      throw new Exception("Call to WB API NMTWaitForDataMerge() failed");
-    }
     output = new OutputAnalyzer(pb.start());
     output.shouldNotContain("Test (reserved=");
   }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/runtime/NMT/NMTWithCDS.java	Fri Sep 05 06:26:44 2014 -0400
@@ -0,0 +1,56 @@
+/*
+ * 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
+ * @bug 8055061
+ * @key nmt
+ * @library /testlibrary
+ * @ignore
+ * @run main NMTWithCDS
+ */
+import com.oracle.java.testlibrary.*;
+
+public class NMTWithCDS {
+
+  public static void main(String[] args) throws Exception {
+    ProcessBuilder pb;
+    pb = ProcessTools.createJavaProcessBuilder("-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");
+      output = new OutputAnalyzer(pb.start());
+      output.shouldContain("sharing");
+      output.shouldHaveExitValue(0);
+
+    } catch (RuntimeException e) {
+      // Report 'passed' if CDS was turned off.
+      output.shouldContain("Unable to use shared archive");
+      output.shouldHaveExitValue(1);
+    }
+  }
+}
--- a/test/runtime/NMT/PrintNMTStatistics.java	Thu Sep 04 13:06:04 2014 -0400
+++ b/test/runtime/NMT/PrintNMTStatistics.java	Fri Sep 05 06:26:44 2014 -0400
@@ -28,6 +28,7 @@
  * @summary Make sure PrintNMTStatistics works on normal JVM exit
  * @library /testlibrary /testlibrary/whitebox
  * @build PrintNMTStatistics
+ * @ignore
  * @run main ClassFileInstaller sun.hotspot.WhiteBox
  * @run main PrintNMTStatistics
  */
@@ -45,10 +46,6 @@
     // We start a new java process running with an argument and use WB API to ensure
     // we have data for NMT on VM exit
     if (args.length > 0) {
-      // Use WB API to ensure that all data has been merged before we continue
-      if (!WhiteBox.getWhiteBox().NMTWaitForDataMerge()) {
-        throw new Exception("Call to WB API NMTWaitForDataMerge() failed");
-      }
       return;
     }
 
--- a/test/runtime/NMT/PrintNMTStatisticsWithNMTDisabled.java	Thu Sep 04 13:06:04 2014 -0400
+++ b/test/runtime/NMT/PrintNMTStatisticsWithNMTDisabled.java	Fri Sep 05 06:26:44 2014 -0400
@@ -26,6 +26,7 @@
  * @key nmt
  * @summary Trying to enable PrintNMTStatistics should result in a warning
  * @library /testlibrary
+ * @ignore
  */
 
 import com.oracle.java.testlibrary.*;
--- a/test/runtime/NMT/ReleaseCommittedMemory.java	Thu Sep 04 13:06:04 2014 -0400
+++ b/test/runtime/NMT/ReleaseCommittedMemory.java	Fri Sep 05 06:26:44 2014 -0400
@@ -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.
  * 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,6 +28,7 @@
  * @key nmt regression
  * @library /testlibrary /testlibrary/whitebox
  * @build ReleaseCommittedMemory
+ * @ignore
  * @run main ClassFileInstaller sun.hotspot.WhiteBox
  * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:NativeMemoryTracking=detail ReleaseCommittedMemory
  */
@@ -44,7 +45,6 @@
     addr = wb.NMTReserveMemory(reserveSize);
     wb.NMTCommitMemory(addr, 128*1024);
     wb.NMTReleaseMemory(addr, reserveSize);
-    wb.NMTWaitForDataMerge();
   }
 }
 
--- a/test/runtime/NMT/ShutdownTwice.java	Thu Sep 04 13:06:04 2014 -0400
+++ b/test/runtime/NMT/ShutdownTwice.java	Fri Sep 05 06:26:44 2014 -0400
@@ -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.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,6 +26,7 @@
  * @key nmt jcmd
  * @summary Run shutdown twice
  * @library /testlibrary
+ * @ignore
  * @run main/othervm -XX:NativeMemoryTracking=detail ShutdownTwice
  */
 
@@ -45,12 +46,12 @@
     output = new OutputAnalyzer(pb.start());
 
     // Verify that jcmd reports that NMT is shutting down
-    output.shouldContain("Shutdown is in progress, it will take a few moments to completely shutdown");
+    output.shouldContain("Native memory tracking has been turned off");
 
     // Run shutdown again
     output = new OutputAnalyzer(pb.start());
 
     // Verify that jcmd reports that NMT has been shutdown already
-    output.shouldContain("Native memory tracking has been shutdown by user");
+    output.shouldContain("Native memory tracking has been shutdown");
   }
 }
--- a/test/runtime/NMT/SummaryAfterShutdown.java	Thu Sep 04 13:06:04 2014 -0400
+++ b/test/runtime/NMT/SummaryAfterShutdown.java	Fri Sep 05 06:26:44 2014 -0400
@@ -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.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,6 +26,7 @@
  * @key nmt jcmd
  * @summary Verify that jcmd correctly reports that NMT is not enabled after a shutdown
  * @library /testlibrary
+ * @ignore
  * @run main/othervm -XX:NativeMemoryTracking=detail SummaryAfterShutdown
  */
 
@@ -44,13 +45,13 @@
     output = new OutputAnalyzer(pb.start());
 
     // Verify that jcmd reports that NMT is shutting down
-    output.shouldContain("Shutdown is in progress, it will take a few moments to completely shutdown");
+    output.shouldContain("Native memory tracking has been turned off");
 
     // Run 'jcmd <pid> VM.native_memory summary'
     pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "summary"});
     output = new OutputAnalyzer(pb.start());
 
     // Verify that jcmd reports that NMT has been shutdown
-    output.shouldContain("Native memory tracking has been shutdown by user");
+    output.shouldContain("Native memory tracking has been shutdown");
   }
 }
--- a/test/runtime/NMT/SummarySanityCheck.java	Thu Sep 04 13:06:04 2014 -0400
+++ b/test/runtime/NMT/SummarySanityCheck.java	Fri Sep 05 06:26:44 2014 -0400
@@ -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.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -27,6 +27,7 @@
  * @summary Sanity check the output of NMT
  * @library /testlibrary /testlibrary/whitebox
  * @build SummarySanityCheck
+ * @ignore
  * @run main ClassFileInstaller sun.hotspot.WhiteBox
  * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:NativeMemoryTracking=summary -XX:+WhiteBoxAPI SummarySanityCheck
  */
@@ -44,11 +45,6 @@
     // Grab my own PID
     String pid = Integer.toString(ProcessTools.getProcessId());
 
-    // Use WB API to ensure that all data has been merged before we continue
-    if (!WhiteBox.getWhiteBox().NMTWaitForDataMerge()) {
-      throw new Exception("Call to WB API NMTWaitForDataMerge() failed");
-    }
-
     ProcessBuilder pb = new ProcessBuilder();
 
     // Run  'jcmd <pid> VM.native_memory summary scale=KB'
@@ -69,13 +65,13 @@
     // Match '- <mtType> (reserved=<reserved>KB, committed=<committed>KB)
     Pattern mtTypePattern = Pattern.compile("-\\s+(?<typename>[\\w\\s]+)\\(reserved=(?<reserved>\\d+)KB,\\scommitted=(?<committed>\\d+)KB\\)");
     // Match 'Total: reserved=<reserved>KB, committed=<committed>KB'
-    Pattern totalMemoryPattern = Pattern.compile("Total\\:\\s\\sreserved=(?<reserved>\\d+)KB,\\s\\scommitted=(?<committed>\\d+)KB");
+    Pattern totalMemoryPattern = Pattern.compile("Total\\:\\sreserved=(?<reserved>\\d+)KB,\\scommitted=(?<committed>\\d+)KB");
 
     for (int i = 0; i < lines.length; i++) {
       if (lines[i].startsWith("Total")) {
         Matcher totalMemoryMatcher = totalMemoryPattern.matcher(lines[i]);
 
-        if (totalMemoryMatcher.matches() && totalMemoryMatcher.groupCount() == 2) {
+        if (totalMemoryMatcher.matches()) {
           totalCommitted = Integer.parseInt(totalMemoryMatcher.group("committed"));
           totalReserved = Integer.parseInt(totalMemoryMatcher.group("reserved"));
         } else {
--- a/test/runtime/NMT/ThreadedMallocTestType.java	Thu Sep 04 13:06:04 2014 -0400
+++ b/test/runtime/NMT/ThreadedMallocTestType.java	Fri Sep 05 06:26:44 2014 -0400
@@ -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.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,6 +26,7 @@
  * @key nmt jcmd
  * @library /testlibrary /testlibrary/whitebox
  * @build ThreadedMallocTestType
+ * @ignore
  * @run main ClassFileInstaller sun.hotspot.WhiteBox
  * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:NativeMemoryTracking=detail ThreadedMallocTestType
  */
@@ -58,11 +59,6 @@
     allocThread.start();
     allocThread.join();
 
-    // Use WB API to ensure that all data has been merged before we continue
-    if (!wb.NMTWaitForDataMerge()) {
-      throw new Exception("Call to WB API NMTWaitForDataMerge() failed");
-    }
-
     // Run 'jcmd <pid> VM.native_memory summary'
     pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "summary"});
     output = new OutputAnalyzer(pb.start());
@@ -80,11 +76,6 @@
     freeThread.start();
     freeThread.join();
 
-    // Use WB API to ensure that all data has been merged before we continue
-    if (!wb.NMTWaitForDataMerge()) {
-      throw new Exception("Call to WB API NMTWaitForDataMerge() failed");
-    }
-
     output = new OutputAnalyzer(pb.start());
     output.shouldNotContain("Test (reserved=");
   }
--- a/test/runtime/NMT/ThreadedVirtualAllocTestType.java	Thu Sep 04 13:06:04 2014 -0400
+++ b/test/runtime/NMT/ThreadedVirtualAllocTestType.java	Fri Sep 05 06:26:44 2014 -0400
@@ -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.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,6 +26,7 @@
  * @key nmt jcmd
  * @library /testlibrary /testlibrary/whitebox
  * @build ThreadedVirtualAllocTestType
+ * @ignore
  * @run main ClassFileInstaller sun.hotspot.WhiteBox
  * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:NativeMemoryTracking=detail ThreadedVirtualAllocTestType
  */
@@ -60,8 +61,6 @@
     reserveThread.start();
     reserveThread.join();
 
-    mergeData();
-
     pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "detail"});
     output = new OutputAnalyzer(pb.start());
     output.shouldContain("Test (reserved=512KB, committed=0KB)");
@@ -77,8 +76,6 @@
     commitThread.start();
     commitThread.join();
 
-    mergeData();
-
     output = new OutputAnalyzer(pb.start());
     output.shouldContain("Test (reserved=512KB, committed=128KB)");
     if (has_nmt_detail) {
@@ -93,8 +90,6 @@
     uncommitThread.start();
     uncommitThread.join();
 
-    mergeData();
-
     output = new OutputAnalyzer(pb.start());
     output.shouldContain("Test (reserved=512KB, committed=0KB)");
     output.shouldNotMatch("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*" + Long.toHexString(addr + commitSize) + "\\] committed");
@@ -107,17 +102,9 @@
     releaseThread.start();
     releaseThread.join();
 
-    mergeData();
-
     output = new OutputAnalyzer(pb.start());
     output.shouldNotContain("Test (reserved=");
     output.shouldNotContain("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*" + Long.toHexString(addr + reserveSize) + "\\] reserved");
   }
 
-  public static void mergeData() throws Exception {
-    // Use WB API to ensure that all data has been merged before we continue
-    if (!wb.NMTWaitForDataMerge()) {
-      throw new Exception("Call to WB API NMTWaitForDataMerge() failed");
     }
-  }
-}
--- a/test/runtime/NMT/VirtualAllocTestType.java	Thu Sep 04 13:06:04 2014 -0400
+++ b/test/runtime/NMT/VirtualAllocTestType.java	Fri Sep 05 06:26:44 2014 -0400
@@ -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.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,6 +26,7 @@
  * @summary Test Reserve/Commit/Uncommit/Release of virtual memory and that we track it correctly
  * @key nmt jcmd
  * @library /testlibrary /testlibrary/whitebox
+ * @ignore
  * @build VirtualAllocTestType
  * @run main ClassFileInstaller sun.hotspot.WhiteBox
  * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:NativeMemoryTracking=detail VirtualAllocTestType
@@ -54,7 +55,6 @@
     }
 
     addr = wb.NMTReserveMemory(reserveSize);
-    mergeData();
     pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "detail"});
 
     output = new OutputAnalyzer(pb.start());
@@ -65,7 +65,6 @@
 
     wb.NMTCommitMemory(addr, commitSize);
 
-    mergeData();
 
     output = new OutputAnalyzer(pb.start());
     output.shouldContain("Test (reserved=256KB, committed=128KB)");
@@ -75,24 +74,15 @@
 
     wb.NMTUncommitMemory(addr, commitSize);
 
-    mergeData();
 
     output = new OutputAnalyzer(pb.start());
     output.shouldContain("Test (reserved=256KB, committed=0KB)");
     output.shouldNotMatch("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*" + Long.toHexString(addr + commitSize) + "\\] committed");
 
     wb.NMTReleaseMemory(addr, reserveSize);
-    mergeData();
 
     output = new OutputAnalyzer(pb.start());
     output.shouldNotContain("Test (reserved=");
     output.shouldNotMatch("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*" + Long.toHexString(addr + reserveSize) + "\\] reserved");
   }
-
-  public static void mergeData() throws Exception {
-    // Use WB API to ensure that all data has been merged before we continue
-    if (!wb.NMTWaitForDataMerge()) {
-      throw new Exception("Call to WB API NMTWaitForDataMerge() failed");
     }
-  }
-}
--- a/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java	Thu Sep 04 13:06:04 2014 -0400
+++ b/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java	Fri Sep 05 06:26:44 2014 -0400
@@ -25,6 +25,10 @@
 package sun.hotspot;
 
 import java.lang.reflect.Executable;
+import java.util.Arrays;
+import java.util.List;
+import java.util.function.Function;
+import java.util.stream.Stream;
 import java.security.BasicPermission;
 import sun.hotspot.parser.DiagnosticCommand;
 
@@ -69,6 +73,8 @@
   // Memory
   public native long getObjectAddress(Object o);
   public native int  getHeapOopSize();
+  public native boolean isObjectInOldGen(Object o);
+  public native long getObjectSize(Object o);
 
   // Runtime
   // Make sure class name is in the correct format
@@ -91,7 +97,8 @@
   public native void NMTCommitMemory(long addr, long size);
   public native void NMTUncommitMemory(long addr, long size);
   public native void NMTReleaseMemory(long addr, long size);
-  public native boolean NMTWaitForDataMerge();
+  public native void NMTOverflowHashBucket(long num);
+  public native long NMTMallocWithPseudoStack(long size, int index);
   public native boolean NMTIsDetailSupported();
 
   // Compiler
@@ -145,6 +152,9 @@
   public native long allocateMetaspace(ClassLoader classLoader, long size);
   public native void freeMetaspace(ClassLoader classLoader, long addr, long size);
 
+  // force Young GC
+  public native void youngGC();
+
   // force Full GC
   public native void fullGC();
 
@@ -152,6 +162,8 @@
   public native int stressVirtualSpaceResize(long reservedSpaceSize, long magnitude, long iterations);
   public native void runMemoryUnitTests();
   public native void readFromNoaccessArea();
+  public native long getThreadStackSize();
+  public native long getThreadRemainingStackSize();
 
   // CPU features
   public native String getCPUFeatures();
@@ -169,4 +181,15 @@
   public native Long    getUint64VMFlag(String name);
   public native String  getStringVMFlag(String name);
   public native Double  getDoubleVMFlag(String name);
+  private final List<Function<String,Object>> flagsGetters = Arrays.asList(
+    this::getBooleanVMFlag, this::getIntxVMFlag, this::getUintxVMFlag,
+    this::getUint64VMFlag, this::getStringVMFlag, this::getDoubleVMFlag);
+
+  public Object getVMFlag(String name) {
+    return flagsGetters.stream()
+                       .map(f -> f.apply(name))
+                       .filter(x -> x != null)
+                       .findAny()
+                       .orElse(null);
+  }
 }