changeset 28490:39f2d17d9be3

Merge
author dlong
date Fri, 09 Jan 2015 13:28:02 -0500
parents f395f4b55ea1 43839f0cb0e8
children fa9243da0080
files hotspot/test/gc/g1/TestEagerReclaimHumongousRegions2.java hotspot/test/gc/g1/TestG1TraceReclaimDeadHumongousObjectsAtYoungGC.java jdk/src/java.base/share/classes/sun/nio/fs/AbstractPath.java jdk/test/javax/swing/JComboBox/ConsumedEscTest/ConsumedEscTest.java langtools/test/tools/sjavac/SJavac.java
diffstat 1075 files changed, 31840 insertions(+), 7096 deletions(-) [+]
line wrap: on
line diff
--- a/.hgtags	Fri Jan 09 05:45:13 2015 -0800
+++ b/.hgtags	Fri Jan 09 13:28:02 2015 -0500
@@ -285,3 +285,5 @@
 82f4cb44b2d7af2352f48568a64b7b6a5ae960cd jdk9-b40
 9fffb959eb4197ff806e4ac12244761815b4deee jdk9-b41
 3107be2ba9c6e208a0b86bc7100a141abbc5b5fb jdk9-b42
+6494b13f88a867026ee316b444d9a4fa589dd6bd jdk9-b43
+abbfccd659b91a7bb815d5e36fed635dcdd40f31 jdk9-b44
--- a/.hgtags-top-repo	Fri Jan 09 05:45:13 2015 -0800
+++ b/.hgtags-top-repo	Fri Jan 09 13:28:02 2015 -0500
@@ -285,3 +285,5 @@
 cf136458ee747e151a27aa9ea0c1492ea55ef3e7 jdk9-b40
 67395f7ca2db3b52e3a62a84888487de5cb9210a jdk9-b41
 f7c11da0b0481d49cc7a65a453336c108191e821 jdk9-b42
+02ee8c65622e8bd97496d584e22fc7dcf0edc4ae jdk9-b43
+8994f5d87b3bb5e8d317d4e8ccb326da1a73684a jdk9-b44
--- a/common/autoconf/generated-configure.sh	Fri Jan 09 05:45:13 2015 -0800
+++ b/common/autoconf/generated-configure.sh	Fri Jan 09 13:28:02 2015 -0500
@@ -4329,7 +4329,7 @@
 #CUSTOM_AUTOCONF_INCLUDE
 
 # Do not change or remove the following line, it is needed for consistency checks:
-DATE_WHEN_GENERATED=1418036274
+DATE_WHEN_GENERATED=1418395009
 
 ###############################################################################
 #
@@ -13965,7 +13965,8 @@
 
   # ZERO_ARCHDEF is used to enable architecture-specific code
   case "${OPENJDK_TARGET_CPU}" in
-    ppc*)    ZERO_ARCHDEF=PPC   ;;
+    ppc)     ZERO_ARCHDEF=PPC32 ;;
+    ppc64)   ZERO_ARCHDEF=PPC64 ;;
     s390*)   ZERO_ARCHDEF=S390  ;;
     sparc*)  ZERO_ARCHDEF=SPARC ;;
     x86_64*) ZERO_ARCHDEF=AMD64 ;;
--- a/common/autoconf/platform.m4	Fri Jan 09 05:45:13 2015 -0800
+++ b/common/autoconf/platform.m4	Fri Jan 09 13:28:02 2015 -0500
@@ -367,7 +367,8 @@
 
   # ZERO_ARCHDEF is used to enable architecture-specific code
   case "${OPENJDK_TARGET_CPU}" in
-    ppc*)    ZERO_ARCHDEF=PPC   ;;
+    ppc)     ZERO_ARCHDEF=PPC32 ;;
+    ppc64)   ZERO_ARCHDEF=PPC64 ;;
     s390*)   ZERO_ARCHDEF=S390  ;;
     sparc*)  ZERO_ARCHDEF=SPARC ;;
     x86_64*) ZERO_ARCHDEF=AMD64 ;;
--- a/common/bin/hgforest.sh	Fri Jan 09 05:45:13 2015 -0800
+++ b/common/bin/hgforest.sh	Fri Jan 09 13:28:02 2015 -0500
@@ -106,12 +106,15 @@
   echo "# Mercurial command: ${command}" > ${status_output}
 fi
 
-
-# capture command options and arguments (if any)
-command_args="${@:-}"
+# At this point all command options and args are in "$@".
+# Always use "$@" (within double quotes) to avoid breaking
+# args with spaces into separate args.
 
 if [ ${vflag} = "true" ] ; then
-  echo "# Mercurial command arguments: ${command_args}" > ${status_output}
+  echo "# Mercurial command argument count: $#" > ${status_output}
+  for cmdarg in "$@" ; do
+    echo "# Mercurial command argument: ${cmdarg}" > ${status_output}
+  done
 fi
 
 # Clean out the temporary directory that stores the pid files.
@@ -205,13 +208,14 @@
 
   pull_default_tail=`echo ${pull_default} | sed -e 's@^.*://[^/]*/\(.*\)@\1@'`
 
-  if [ -n "${command_args}" ] ; then
+  if [ $# -gt 0 ] ; then
     # if there is an "extra sources" path then reparent "extra" repos to that path
     if [ "x${pull_default}" = "x${pull_default_tail}" ] ; then
       echo "ERROR: Need initial clone from non-local source" > ${status_output}
       exit 1
     fi
-    pull_extra="${command_args}/${pull_default_tail}"
+    # assume that "extra sources" path is the first arg
+    pull_extra="${1}/${pull_default_tail}"
 
     # determine which extra subrepos need to be cloned.
     for i in ${subrepos_extra} ; do
@@ -356,8 +360,8 @@
           (PYTHONUNBUFFERED=true hg${global_opts} clone ${clone_newrepo} ${i}; echo "$?" > ${tmp}/${repopidfile}.pid.rc ) 2>&1 &
         else
           # run the command.
-          echo "cd ${i} && hg${global_opts} ${command} ${command_args}" > ${status_output}
-          cd ${i} && (PYTHONUNBUFFERED=true hg${global_opts} ${command} ${command_args}; echo "$?" > ${tmp}/${repopidfile}.pid.rc ) 2>&1 &
+          echo "cd ${i} && hg${global_opts} ${command} ${@}" > ${status_output}
+          cd ${i} && (PYTHONUNBUFFERED=true hg${global_opts} ${command} "${@}"; echo "$?" > ${tmp}/${repopidfile}.pid.rc ) 2>&1 &
         fi
 
         echo $! > ${tmp}/${repopidfile}.pid
--- a/corba/.hgtags	Fri Jan 09 05:45:13 2015 -0800
+++ b/corba/.hgtags	Fri Jan 09 13:28:02 2015 -0500
@@ -285,3 +285,5 @@
 e27c725d6c9d155667b35255f442d4ceb8c3c084 jdk9-b40
 1908b886ba1eda46fa725cf1160fe5d30fd1a7e5 jdk9-b41
 078bb11af876fe528d4b516f33ad4dd9bb60549e jdk9-b42
+9645e35616b60c5c07b4fdf11a132afc8081dfa8 jdk9-b43
+1f57bd728c9e6865ccb9d43ccd80a1c11230a32f jdk9-b44
--- a/hotspot/.hgtags	Fri Jan 09 05:45:13 2015 -0800
+++ b/hotspot/.hgtags	Fri Jan 09 13:28:02 2015 -0500
@@ -445,3 +445,5 @@
 6b09b3193d731e3288e2a240c504a20d0a06c766 jdk9-b40
 1d29b13e8a515a7ea3b882f140576d5d675bc11f jdk9-b41
 38cb4fbd47e3472bd1b5ebac83bda96fe4869c4f jdk9-b42
+65a9747147b8090037541040ba67156ec914db6a jdk9-b43
+43a44b56dca61a4d766a20f0528fdd8b5ceff873 jdk9-b44
--- a/hotspot/agent/make/Makefile	Fri Jan 09 05:45:13 2015 -0800
+++ b/hotspot/agent/make/Makefile	Fri Jan 09 13:28:02 2015 -0500
@@ -58,15 +58,19 @@
 sun.jvm.hotspot.debugger.dummy \
 sun.jvm.hotspot.debugger.linux \
 sun.jvm.hotspot.debugger.linux.amd64 \
+sun.jvm.hotspot.debugger.linux.ppc64 \
 sun.jvm.hotspot.debugger.linux.x86 \
 sun.jvm.hotspot.debugger.posix \
 sun.jvm.hotspot.debugger.posix.elf \
+sun.jvm.hotspot.debugger.ppc64 \
 sun.jvm.hotspot.debugger.proc \
 sun.jvm.hotspot.debugger.proc.amd64 \
+sun.jvm.hotspot.debugger.proc.ppc64 \
 sun.jvm.hotspot.debugger.proc.sparc \
 sun.jvm.hotspot.debugger.proc.x86 \
 sun.jvm.hotspot.debugger.remote \
 sun.jvm.hotspot.debugger.remote.amd64 \
+sun.jvm.hotspot.debugger.remote.ppc64 \
 sun.jvm.hotspot.debugger.remote.sparc \
 sun.jvm.hotspot.debugger.remote.x86 \
 sun.jvm.hotspot.debugger.sparc \
@@ -93,9 +97,11 @@
 sun.jvm.hotspot.runtime.bsd_x86 \
 sun.jvm.hotspot.runtime.linux \
 sun.jvm.hotspot.runtime.linux_amd64 \
+sun.jvm.hotspot.runtime.linux_ppc64 \
 sun.jvm.hotspot.runtime.linux_sparc \
 sun.jvm.hotspot.runtime.linux_x86 \
 sun.jvm.hotspot.runtime.posix \
+sun.jvm.hotspot.runtime.ppc64 \
 sun.jvm.hotspot.runtime.solaris_amd64 \
 sun.jvm.hotspot.runtime.solaris_sparc \
 sun.jvm.hotspot.runtime.solaris_x86 \
@@ -142,15 +148,19 @@
 sun/jvm/hotspot/debugger/cdbg/basic/x86/*.java \
 sun/jvm/hotspot/debugger/dummy/*.java \
 sun/jvm/hotspot/debugger/linux/*.java \
+sun/jvm/hotspot/debugger/linux/ppc64/*.java \
 sun/jvm/hotspot/debugger/linux/x86/*.java \
 sun/jvm/hotspot/debugger/posix/*.java \
 sun/jvm/hotspot/debugger/posix/elf/*.java \
+sun/jvm/hotspot/debugger/ppc64/*.java \
 sun/jvm/hotspot/debugger/proc/*.java \
 sun/jvm/hotspot/debugger/proc/amd64/*.java \
+sun/jvm/hotspot/debugger/proc/ppc64/*.java \
 sun/jvm/hotspot/debugger/proc/sparc/*.java \
 sun/jvm/hotspot/debugger/proc/x86/*.java \
 sun/jvm/hotspot/debugger/remote/*.java \
 sun/jvm/hotspot/debugger/remote/amd64/*.java \
+sun/jvm/hotspot/debugger/remote/ppc64/*.java \
 sun/jvm/hotspot/debugger/remote/sparc/*.java \
 sun/jvm/hotspot/debugger/remote/x86/*.java \
 sun/jvm/hotspot/debugger/sparc/*.java \
@@ -174,9 +184,11 @@
 sun/jvm/hotspot/runtime/bsd_x86/*.java \
 sun/jvm/hotspot/runtime/linux/*.java \
 sun/jvm/hotspot/runtime/linux_amd64/*.java \
+sun/jvm/hotspot/runtime/linux_ppc64/*.java \
 sun/jvm/hotspot/runtime/linux_sparc/*.java \
 sun/jvm/hotspot/runtime/linux_x86/*.java \
 sun/jvm/hotspot/runtime/posix/*.java \
+sun/jvm/hotspot/runtime/ppc64/*.java \
 sun/jvm/hotspot/runtime/solaris_amd64/*.java \
 sun/jvm/hotspot/runtime/solaris_sparc/*.java \
 sun/jvm/hotspot/runtime/solaris_x86/*.java \
--- a/hotspot/agent/src/os/linux/LinuxDebuggerLocal.c	Fri Jan 09 05:45:13 2015 -0800
+++ b/hotspot/agent/src/os/linux/LinuxDebuggerLocal.c	Fri Jan 09 13:28:02 2015 -0500
@@ -49,6 +49,10 @@
 #include "sun_jvm_hotspot_debugger_sparc_SPARCThreadContext.h"
 #endif
 
+#ifdef ppc64
+#include "sun_jvm_hotspot_debugger_ppc64_PPC64ThreadContext.h"
+#endif
+
 static jfieldID p_ps_prochandle_ID = 0;
 static jfieldID threadList_ID = 0;
 static jfieldID loadObjectList_ID = 0;
@@ -341,7 +345,7 @@
   return (err == PS_OK)? array : 0;
 }
 
-#if defined(i386) || defined(amd64) || defined(sparc) || defined(sparcv9)
+#if defined(i386) || defined(amd64) || defined(sparc) || defined(sparcv9) | defined(ppc64)
 JNIEXPORT jlongArray JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal_getThreadIntegerRegisterSet0
   (JNIEnv *env, jobject this_obj, jint lwp_id) {
 
@@ -366,6 +370,10 @@
 #if defined(sparc) || defined(sparcv9)
 #define NPRGREG sun_jvm_hotspot_debugger_sparc_SPARCThreadContext_NPRGREG
 #endif
+#ifdef ppc64
+#define NPRGREG sun_jvm_hotspot_debugger_ppc64_PPC64ThreadContext_NPRGREG
+#endif
+
 
   array = (*env)->NewLongArray(env, NPRGREG);
   CHECK_EXCEPTION_(0);
@@ -458,6 +466,45 @@
   regs[REG_INDEX(R_O7)]  = gregs.u_regs[14];
 #endif /* sparc */
 
+#ifdef ppc64
+#define REG_INDEX(reg) sun_jvm_hotspot_debugger_ppc64_PPC64ThreadContext_##reg
+
+  regs[REG_INDEX(LR)] = gregs.link;
+  regs[REG_INDEX(NIP)] = gregs.nip;
+  regs[REG_INDEX(R0)]  = gregs.gpr[0];
+  regs[REG_INDEX(R1)]  = gregs.gpr[1];
+  regs[REG_INDEX(R2)]  = gregs.gpr[2];
+  regs[REG_INDEX(R3)]  = gregs.gpr[3];
+  regs[REG_INDEX(R4)]  = gregs.gpr[4];
+  regs[REG_INDEX(R5)]  = gregs.gpr[5];
+  regs[REG_INDEX(R6)]  = gregs.gpr[6];
+  regs[REG_INDEX(R7)]  = gregs.gpr[7];
+  regs[REG_INDEX(R8)]  = gregs.gpr[8];
+  regs[REG_INDEX(R9)]  = gregs.gpr[9];
+  regs[REG_INDEX(R10)] = gregs.gpr[10];
+  regs[REG_INDEX(R11)] = gregs.gpr[11];
+  regs[REG_INDEX(R12)] = gregs.gpr[12];
+  regs[REG_INDEX(R13)] = gregs.gpr[13];
+  regs[REG_INDEX(R14)] = gregs.gpr[14];
+  regs[REG_INDEX(R15)] = gregs.gpr[15];
+  regs[REG_INDEX(R16)] = gregs.gpr[16];
+  regs[REG_INDEX(R17)] = gregs.gpr[17];
+  regs[REG_INDEX(R18)] = gregs.gpr[18];
+  regs[REG_INDEX(R19)] = gregs.gpr[19];
+  regs[REG_INDEX(R20)] = gregs.gpr[20];
+  regs[REG_INDEX(R21)] = gregs.gpr[21];
+  regs[REG_INDEX(R22)] = gregs.gpr[22];
+  regs[REG_INDEX(R23)] = gregs.gpr[23];
+  regs[REG_INDEX(R24)] = gregs.gpr[24];
+  regs[REG_INDEX(R25)] = gregs.gpr[25];
+  regs[REG_INDEX(R26)] = gregs.gpr[26];
+  regs[REG_INDEX(R27)] = gregs.gpr[27];
+  regs[REG_INDEX(R28)] = gregs.gpr[28];
+  regs[REG_INDEX(R29)] = gregs.gpr[29];
+  regs[REG_INDEX(R30)] = gregs.gpr[30];
+  regs[REG_INDEX(R31)] = gregs.gpr[31];
+
+#endif
 
   (*env)->ReleaseLongArrayElements(env, array, regs, JNI_COMMIT);
   return array;
--- a/hotspot/agent/src/os/linux/symtab.c	Fri Jan 09 05:45:13 2015 -0800
+++ b/hotspot/agent/src/os/linux/symtab.c	Fri Jan 09 13:28:02 2015 -0500
@@ -325,6 +325,12 @@
 
   // Reading of elf header
   struct elf_section *scn_cache = NULL;
+#if defined(ppc64) && !defined(ABI_ELFv2)
+  // Only big endian ppc64 (i.e. ABI_ELFv1) has 'official procedure descriptors' in ELF files
+  // see: http://refspecs.linuxfoundation.org/LSB_3.1.1/LSB-Core-PPC64/LSB-Core-PPC64/specialsections.html
+  struct elf_section *opd_sect = NULL;
+  ELF_SHDR *opd = NULL;
+#endif
   int cnt = 0;
   ELF_SHDR* shbuf = NULL;
   ELF_SHDR* cursct = NULL;
@@ -368,6 +374,14 @@
     cursct++;
   }
 
+#if defined(ppc64) && !defined(ABI_ELFv2)
+  opd_sect = find_section_by_name(".opd", fd, &ehdr, scn_cache);
+  if (opd_sect != NULL && opd_sect->c_data != NULL && opd_sect->c_shdr != NULL) {
+    // plausibility check
+    opd = opd_sect->c_shdr;
+  }
+#endif
+
   for (cnt = 1; cnt < ehdr.e_shnum; cnt++) {
     ELF_SHDR *shdr = scn_cache[cnt].c_shdr;
 
@@ -412,6 +426,7 @@
       // copy symbols info our symtab and enter them info the hash table
       for (j = 0; j < n; j++, syms++) {
         ENTRY item, *ret;
+        uintptr_t sym_value;
         char *sym_name = symtab->strs + syms->st_name;
 
         // skip non-object and non-function symbols
@@ -422,9 +437,19 @@
         if (*sym_name == '\0' || syms->st_shndx == SHN_UNDEF) continue;
 
         symtab->symbols[j].name   = sym_name;
-        symtab->symbols[j].offset = syms->st_value - baseaddr;
         symtab->symbols[j].size   = syms->st_size;
+        sym_value = syms->st_value;
 
+#if defined(ppc64) && !defined(ABI_ELFv2)
+        // see hotspot/src/share/vm/utilities/elfFuncDescTable.hpp for a detailed description
+        // of why we have to go this extra way via the '.opd' section on big endian ppc64
+        if (opd != NULL && *sym_name != '.' &&
+            (opd->sh_addr <= sym_value && sym_value <= opd->sh_addr + opd->sh_size)) {
+          sym_value = ((ELF_ADDR*)opd_sect->c_data)[(sym_value - opd->sh_addr) / sizeof(ELF_ADDR*)];
+        }
+#endif
+
+        symtab->symbols[j].offset = sym_value - baseaddr;
         item.key = sym_name;
         item.data = (void *)&(symtab->symbols[j]);
 
@@ -433,9 +458,17 @@
     }
   }
 
+#if defined(ppc64) && !defined(ABI_ELFv2)
+  // On Linux/PPC64 the debuginfo files contain an empty function descriptor
+  // section (i.e. '.opd' section) which makes the resolution of symbols
+  // with the above algorithm impossible (we would need the have both, the
+  // .opd section from the library and the symbol table from the debuginfo
+  // file which doesn't match with the current workflow.)
+  goto quit;
+#endif
+
   // Look for a separate debuginfo file.
   if (try_debuginfo) {
-
     // We prefer a debug symtab to an object's own symtab, so look in
     // the debuginfo file.  We stash a copy of the old symtab in case
     // there is no debuginfo.
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/MachineDescriptionPPC64.java	Fri Jan 09 05:45:13 2015 -0800
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/MachineDescriptionPPC64.java	Fri Jan 09 13:28:02 2015 -0500
@@ -34,6 +34,6 @@
   }
 
   public boolean isBigEndian() {
-    return true;
+    return "big".equals(System.getProperty("sun.cpu.endian"));
   }
 }
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/LinuxCDebugger.java	Fri Jan 09 05:45:13 2015 -0800
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/LinuxCDebugger.java	Fri Jan 09 13:28:02 2015 -0500
@@ -26,14 +26,17 @@
 
 import java.io.*;
 import java.util.*;
+
 import sun.jvm.hotspot.debugger.*;
 import sun.jvm.hotspot.debugger.cdbg.*;
 import sun.jvm.hotspot.debugger.x86.*;
 import sun.jvm.hotspot.debugger.amd64.*;
 import sun.jvm.hotspot.debugger.sparc.*;
+import sun.jvm.hotspot.debugger.ppc64.*;
 import sun.jvm.hotspot.debugger.linux.x86.*;
 import sun.jvm.hotspot.debugger.linux.amd64.*;
 import sun.jvm.hotspot.debugger.linux.sparc.*;
+import sun.jvm.hotspot.debugger.linux.ppc64.*;
 import sun.jvm.hotspot.utilities.*;
 
 class LinuxCDebugger implements CDebugger {
@@ -96,7 +99,14 @@
        Address pc  = context.getRegisterAsAddress(SPARCThreadContext.R_O7);
        if (pc == null) return null;
        return new LinuxSPARCCFrame(dbg, sp, pc, LinuxDebuggerLocal.getAddressSize());
-    } else {
+    }  else if (cpu.equals("ppc64")) {
+        PPC64ThreadContext context = (PPC64ThreadContext) thread.getContext();
+        Address sp = context.getRegisterAsAddress(PPC64ThreadContext.SP);
+        if (sp == null) return null;
+        Address pc  = context.getRegisterAsAddress(PPC64ThreadContext.PC);
+        if (pc == null) return null;
+        return new LinuxPPC64CFrame(dbg, sp, pc, LinuxDebuggerLocal.getAddressSize());
+     } else {
        // Runtime exception thrown by LinuxThreadContextFactory if unknown cpu
        ThreadContext context = (ThreadContext) thread.getContext();
        return context.getTopFrame(dbg);
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/LinuxThreadContextFactory.java	Fri Jan 09 05:45:13 2015 -0800
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/LinuxThreadContextFactory.java	Fri Jan 09 13:28:02 2015 -0500
@@ -29,6 +29,7 @@
 import sun.jvm.hotspot.debugger.linux.amd64.*;
 import sun.jvm.hotspot.debugger.linux.ia64.*;
 import sun.jvm.hotspot.debugger.linux.x86.*;
+import sun.jvm.hotspot.debugger.linux.ppc64.*;
 import sun.jvm.hotspot.debugger.linux.sparc.*;
 
 class LinuxThreadContextFactory {
@@ -42,6 +43,8 @@
          return new LinuxIA64ThreadContext(dbg);
       } else if (cpu.equals("sparc")) {
          return new LinuxSPARCThreadContext(dbg);
+      }  else if (cpu.equals("ppc64")) {
+          return new LinuxPPC64ThreadContext(dbg);
       } else  {
         try {
           Class tcc = Class.forName("sun.jvm.hotspot.debugger.linux." +
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/ppc64/LinuxPPC64CFrame.java	Fri Jan 09 13:28:02 2015 -0500
@@ -0,0 +1,79 @@
+/*
+ * 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.
+ *
+ */
+
+package sun.jvm.hotspot.debugger.linux.ppc64;
+
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.debugger.ppc64.*;
+import sun.jvm.hotspot.debugger.linux.*;
+import sun.jvm.hotspot.debugger.cdbg.*;
+import sun.jvm.hotspot.debugger.cdbg.basic.*;
+
+final public class LinuxPPC64CFrame extends BasicCFrame {
+  // package/class internals only
+
+  public LinuxPPC64CFrame(LinuxDebugger dbg, Address sp, Address pc, int address_size) {
+    super(dbg.getCDebugger());
+    this.sp = sp;
+    this.pc = pc;
+    this.dbg = dbg;
+    this.address_size = address_size;
+  }
+
+  // override base class impl to avoid ELF parsing
+  public ClosestSymbol closestSymbolToPC() {
+    // try native lookup in debugger.
+    return dbg.lookup(dbg.getAddressValue(pc()));
+  }
+
+  public Address pc() {
+    return pc;
+  }
+
+  public Address localVariableBase() {
+    return sp;
+  }
+
+  public CFrame sender(ThreadProxy thread) {
+    if (sp == null) {
+      return null;
+    }
+
+    Address nextSP = sp.getAddressAt(0);
+    if (nextSP == null) {
+      return null;
+    }
+    Address nextPC  = sp.getAddressAt(2 * address_size);
+    if (nextPC == null) {
+      return null;
+    }
+    return new LinuxPPC64CFrame(dbg, nextSP, nextPC, address_size);
+  }
+
+  public static int PPC64_STACK_BIAS = 0;
+  private static int address_size;
+  private Address pc;
+  private Address sp;
+  private LinuxDebugger dbg;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/ppc64/LinuxPPC64ThreadContext.java	Fri Jan 09 13:28:02 2015 -0500
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ *
+ */
+
+package sun.jvm.hotspot.debugger.linux.ppc64;
+
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.debugger.ppc64.*;
+import sun.jvm.hotspot.debugger.linux.*;
+
+public class LinuxPPC64ThreadContext extends PPC64ThreadContext {
+  private LinuxDebugger debugger;
+
+  public LinuxPPC64ThreadContext(LinuxDebugger debugger) {
+    super();
+    this.debugger = debugger;
+  }
+
+  public void setRegisterAsAddress(int index, Address value) {
+    setRegister(index, debugger.getAddressValue(value));
+  }
+
+  public Address getRegisterAsAddress(int index) {
+    return debugger.newAddress(getRegister(index));
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/ppc64/PPC64ThreadContext.java	Fri Jan 09 13:28:02 2015 -0500
@@ -0,0 +1,123 @@
+/*
+ * 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.
+ *
+ */
+
+package sun.jvm.hotspot.debugger.ppc64;
+
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.debugger.cdbg.*;
+
+/** Specifies the thread context on ppc64 platforms; only a sub-portion
+ * of the context is guaranteed to be present on all operating
+ * systems. */
+
+public abstract class PPC64ThreadContext implements ThreadContext {
+
+  // NOTE: The indices for the various registers must be maintained as
+  // listed across various operating systems. However, only a small
+  // subset of the registers' values are guaranteed to be present (and
+  // must be present for the SA's stack walking to work).
+
+  public static final int R31 = 0;
+  public static final int R30 = 1;
+  public static final int R29 = 2;
+  public static final int R28 = 3;
+  public static final int R27 = 4;
+  public static final int R26 = 5;
+  public static final int R25 = 6;
+  public static final int R24 = 7;
+  public static final int R23 = 8;
+  public static final int R22 = 9;
+  public static final int R21 = 10;
+  public static final int R20 = 11;
+  public static final int R19 = 12;
+  public static final int R18 = 13;
+  public static final int R17 = 14;
+  public static final int R16 = 15;
+  public static final int R15 = 16;
+  public static final int R14 = 17;
+  public static final int R13 = 18;
+  public static final int R12 = 19;
+  public static final int R11 = 20;
+  public static final int R10 = 21;
+  public static final int R9 = 22;
+  public static final int R8 = 23;
+  public static final int R7 = 24;
+  public static final int R6 = 25;
+  public static final int R5 = 26;
+  public static final int R4 = 27;
+  public static final int R3 = 28;
+  public static final int R2 = 29;
+  public static final int R1 = 30;
+  public static final int R0 = 31;
+  public static final int NIP = 32;
+  public static final int LR = 33;
+
+  public static final int NPRGREG = 34;
+
+  private static final String[] regNames = {
+    "r31", "r30", "r29", "r28", "r27", "r26", "r25", "r24",
+    "r23", "r22", "r21", "r20", "r19", "r18", "r17", "r16",
+    "r15", "r14", "r13", "r12", "r11", "r10", "r9",  "r8",
+    "r7",  "r6",  "r5",  "r4",  "r3",   "r2", "r1",  "r0",
+    "nip", "link"
+  };
+
+  public static final int PC = NIP;
+  public static final int SP = R1;
+
+  private long[] data;
+
+  public PPC64ThreadContext() {
+    data = new long[NPRGREG];
+  }
+
+  public int getNumRegisters() {
+    return NPRGREG;
+  }
+
+  public String getRegisterName(int index) {
+    return regNames[index];
+  }
+
+  public void setRegister(int index, long value) {
+    data[index] = value;
+  }
+
+  public long getRegister(int index) {
+    return data[index];
+  }
+
+  public CFrame getTopFrame(Debugger dbg) {
+    return null;
+  }
+
+  /** This can't be implemented in this class since we would have to
+   * tie the implementation to, for example, the debugging system */
+  public abstract void setRegisterAsAddress(int index, Address value);
+
+  /** This can't be implemented in this class since we would have to
+   * tie the implementation to, for example, the debugging system */
+  public abstract Address getRegisterAsAddress(int index);
+
+}
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/ProcDebuggerLocal.java	Fri Jan 09 05:45:13 2015 -0800
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/ProcDebuggerLocal.java	Fri Jan 09 13:28:02 2015 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -32,7 +32,9 @@
 import sun.jvm.hotspot.debugger.cdbg.*;
 import sun.jvm.hotspot.debugger.proc.amd64.*;
 import sun.jvm.hotspot.debugger.proc.sparc.*;
+import sun.jvm.hotspot.debugger.proc.ppc64.*;
 import sun.jvm.hotspot.debugger.proc.x86.*;
+import sun.jvm.hotspot.debugger.ppc64.*;
 import sun.jvm.hotspot.debugger.amd64.*;
 import sun.jvm.hotspot.debugger.sparc.*;
 import sun.jvm.hotspot.debugger.x86.*;
@@ -86,6 +88,10 @@
             threadFactory = new ProcAMD64ThreadFactory(this);
             pcRegIndex = AMD64ThreadContext.RIP;
             fpRegIndex = AMD64ThreadContext.RBP;
+        } else if (cpu.equals("ppc64")) {
+            threadFactory = new ProcPPC64ThreadFactory(this);
+            pcRegIndex = PPC64ThreadContext.PC;
+            fpRegIndex = PPC64ThreadContext.SP;
         } else {
           try {
             Class tfc = Class.forName("sun.jvm.hotspot.debugger.proc." +
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/ppc64/ProcPPC64Thread.java	Fri Jan 09 13:28:02 2015 -0500
@@ -0,0 +1,86 @@
+/*
+ * 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.
+ *
+ */
+
+package sun.jvm.hotspot.debugger.proc.ppc64;
+
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.debugger.ppc64.*;
+import sun.jvm.hotspot.debugger.proc.*;
+import sun.jvm.hotspot.utilities.*;
+
+public class ProcPPC64Thread implements ThreadProxy {
+  private ProcDebugger debugger;
+  private int id;
+
+  public ProcPPC64Thread(ProcDebugger debugger, Address addr) {
+    this.debugger = debugger;
+
+    // FIXME: the size here should be configurable. However, making it
+    // so would produce a dependency on the "types" package from the
+    // debugger package, which is not desired.
+    this.id = (int) addr.getCIntegerAt(0, 4, true);
+  }
+
+  public ProcPPC64Thread(ProcDebugger debugger, long id) {
+    this.debugger = debugger;
+    this.id = (int) id;
+  }
+
+  public ThreadContext getContext() throws IllegalThreadStateException {
+    ProcPPC64ThreadContext context = new ProcPPC64ThreadContext(debugger);
+    long[] regs = debugger.getThreadIntegerRegisterSet(id);
+    if (Assert.ASSERTS_ENABLED) {
+      Assert.that(regs.length <= PPC64ThreadContext.NPRGREG, "size of register set is greater than " + PPC64ThreadContext.NPRGREG);
+    }
+    for (int i = 0; i < regs.length; i++) {
+      context.setRegister(i, regs[i]);
+    }
+    return context;
+  }
+
+  public boolean canSetContext() throws DebuggerException {
+    return false;
+  }
+
+  public void setContext(ThreadContext context)
+    throws IllegalThreadStateException, DebuggerException {
+    throw new DebuggerException("Unimplemented");
+  }
+
+  public String toString() {
+    return "t@" + id;
+  }
+
+  public boolean equals(Object obj) {
+    if ((obj == null) || !(obj instanceof ProcPPC64Thread)) {
+      return false;
+    }
+
+    return (((ProcPPC64Thread) obj).id == id);
+  }
+
+  public int hashCode() {
+    return id;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/ppc64/ProcPPC64ThreadContext.java	Fri Jan 09 13:28:02 2015 -0500
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ *
+ */
+
+package sun.jvm.hotspot.debugger.proc.ppc64;
+
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.debugger.ppc64.*;
+import sun.jvm.hotspot.debugger.proc.*;
+
+public class ProcPPC64ThreadContext extends PPC64ThreadContext {
+  private ProcDebugger debugger;
+
+  public ProcPPC64ThreadContext(ProcDebugger debugger) {
+    super();
+    this.debugger = debugger;
+  }
+
+  public void setRegisterAsAddress(int index, Address value) {
+    setRegister(index, debugger.getAddressValue(value));
+  }
+
+  public Address getRegisterAsAddress(int index) {
+    return debugger.newAddress(getRegister(index));
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/ppc64/ProcPPC64ThreadFactory.java	Fri Jan 09 13:28:02 2015 -0500
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ *
+ */
+
+package sun.jvm.hotspot.debugger.proc.ppc64;
+
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.debugger.proc.*;
+
+public class ProcPPC64ThreadFactory implements ProcThreadFactory {
+  private ProcDebugger debugger;
+
+  public ProcPPC64ThreadFactory(ProcDebugger debugger) {
+    this.debugger = debugger;
+  }
+
+  public ThreadProxy createThreadWrapper(Address threadIdentifierAddr) {
+    return new ProcPPC64Thread(debugger, threadIdentifierAddr);
+  }
+
+  public ThreadProxy createThreadWrapper(long id) {
+    return new ProcPPC64Thread(debugger, id);
+  }
+}
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/RemoteDebuggerClient.java	Fri Jan 09 05:45:13 2015 -0800
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/RemoteDebuggerClient.java	Fri Jan 09 13:28:02 2015 -0500
@@ -33,6 +33,7 @@
 import sun.jvm.hotspot.debugger.remote.sparc.*;
 import sun.jvm.hotspot.debugger.remote.x86.*;
 import sun.jvm.hotspot.debugger.remote.amd64.*;
+import sun.jvm.hotspot.debugger.remote.ppc64.*;
 
 /** An implementation of Debugger which wraps a
     RemoteDebugger, providing remote debugging via RMI.
@@ -70,6 +71,11 @@
         cachePageSize = 4096;
         cacheNumPages = parseCacheNumPagesProperty(cacheSize / cachePageSize);
         unalignedAccessesOkay = true;
+      } else if (cpu.equals("ppc64")) {
+        threadFactory = new RemotePPC64ThreadFactory(this);
+        cachePageSize = 4096;
+        cacheNumPages = parseCacheNumPagesProperty(cacheSize / cachePageSize);
+        unalignedAccessesOkay = true;
       } else {
         try {
           Class tf = Class.forName("sun.jvm.hotspot.debugger.remote." +
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/ppc64/RemotePPC64Thread.java	Fri Jan 09 13:28:02 2015 -0500
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ *
+ */
+
+package sun.jvm.hotspot.debugger.remote.ppc64;
+
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.debugger.ppc64.*;
+import sun.jvm.hotspot.debugger.remote.*;
+import sun.jvm.hotspot.utilities.*;
+
+public class RemotePPC64Thread extends RemoteThread  {
+  public RemotePPC64Thread(RemoteDebuggerClient debugger, Address addr) {
+    super(debugger, addr);
+  }
+
+  public RemotePPC64Thread(RemoteDebuggerClient debugger, long id) {
+    super(debugger, id);
+  }
+
+  public ThreadContext getContext() throws IllegalThreadStateException {
+    RemotePPC64ThreadContext context = new RemotePPC64ThreadContext(debugger);
+    long[] regs = (addr != null)? debugger.getThreadIntegerRegisterSet(addr) :
+                                  debugger.getThreadIntegerRegisterSet(id);
+    if (Assert.ASSERTS_ENABLED) {
+      Assert.that(regs.length == PPC64ThreadContext.NPRGREG, "size of register set must match");
+    }
+    for (int i = 0; i < regs.length; i++) {
+      context.setRegister(i, regs[i]);
+    }
+    return context;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/ppc64/RemotePPC64ThreadContext.java	Fri Jan 09 13:28:02 2015 -0500
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ *
+ */
+
+package sun.jvm.hotspot.debugger.remote.ppc64;
+
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.debugger.ppc64.*;
+import sun.jvm.hotspot.debugger.remote.*;
+
+public class RemotePPC64ThreadContext extends PPC64ThreadContext {
+  private RemoteDebuggerClient debugger;
+
+  public RemotePPC64ThreadContext(RemoteDebuggerClient debugger) {
+    super();
+    this.debugger = debugger;
+  }
+
+  /** This can't be implemented in this class since we would have to
+      tie the implementation to, for example, the debugging system */
+  public void setRegisterAsAddress(int index, Address value) {
+    setRegister(index, debugger.getAddressValue(value));
+  }
+
+  /** This can't be implemented in this class since we would have to
+      tie the implementation to, for example, the debugging system */
+  public Address getRegisterAsAddress(int index) {
+    return debugger.newAddress(getRegister(index));
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/ppc64/RemotePPC64ThreadFactory.java	Fri Jan 09 13:28:02 2015 -0500
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ *
+ */
+
+package sun.jvm.hotspot.debugger.remote.ppc64;
+
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.debugger.remote.*;
+
+public class RemotePPC64ThreadFactory implements RemoteThreadFactory {
+  private RemoteDebuggerClient debugger;
+
+  public RemotePPC64ThreadFactory(RemoteDebuggerClient debugger) {
+    this.debugger = debugger;
+  }
+
+  public ThreadProxy createThreadWrapper(Address threadIdentifierAddr) {
+    return new RemotePPC64Thread(debugger, threadIdentifierAddr);
+  }
+
+  public ThreadProxy createThreadWrapper(long id) {
+    return new RemotePPC64Thread(debugger, id);
+  }
+}
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/Threads.java	Fri Jan 09 05:45:13 2015 -0800
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/Threads.java	Fri Jan 09 13:28:02 2015 -0500
@@ -25,6 +25,7 @@
 package sun.jvm.hotspot.runtime;
 
 import java.util.*;
+
 import sun.jvm.hotspot.debugger.*;
 import sun.jvm.hotspot.types.*;
 import sun.jvm.hotspot.runtime.solaris_sparc.SolarisSPARCJavaThreadPDAccess;
@@ -34,6 +35,7 @@
 import sun.jvm.hotspot.runtime.win32_x86.Win32X86JavaThreadPDAccess;
 import sun.jvm.hotspot.runtime.linux_x86.LinuxX86JavaThreadPDAccess;
 import sun.jvm.hotspot.runtime.linux_amd64.LinuxAMD64JavaThreadPDAccess;
+import sun.jvm.hotspot.runtime.linux_ppc64.LinuxPPC64JavaThreadPDAccess;
 import sun.jvm.hotspot.runtime.linux_sparc.LinuxSPARCJavaThreadPDAccess;
 import sun.jvm.hotspot.runtime.bsd_x86.BsdX86JavaThreadPDAccess;
 import sun.jvm.hotspot.runtime.bsd_amd64.BsdAMD64JavaThreadPDAccess;
@@ -87,6 +89,8 @@
                 access = new LinuxAMD64JavaThreadPDAccess();
             } else if (cpu.equals("sparc")) {
                 access = new LinuxSPARCJavaThreadPDAccess();
+            } else if (cpu.equals("ppc64")) {
+                access = new LinuxPPC64JavaThreadPDAccess();
             } else {
               try {
                 access = (JavaThreadPDAccess)
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/VFrame.java	Fri Jan 09 05:45:13 2015 -0800
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/VFrame.java	Fri Jan 09 13:28:02 2015 -0500
@@ -78,7 +78,7 @@
         }
 
         if (f.isRuntimeFrame()) {
-          // This is a conversion frame. Skip this frame and try again.
+          // This is a conversion frame or a Stub routine. Skip this frame and try again.
           RegisterMap tempMap = regMap.copy();
           Frame s = f.sender(tempMap);
           return newVFrame(s, tempMap, thread, unsafe, false);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/linux_ppc64/LinuxPPC64JavaThreadPDAccess.java	Fri Jan 09 13:28:02 2015 -0500
@@ -0,0 +1,132 @@
+/*
+ * 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.
+ *
+ */
+
+package sun.jvm.hotspot.runtime.linux_ppc64;
+
+import java.io.*;
+import java.util.*;
+
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.debugger.ppc64.*;
+import sun.jvm.hotspot.runtime.*;
+import sun.jvm.hotspot.runtime.ppc64.*;
+import sun.jvm.hotspot.types.*;
+import sun.jvm.hotspot.utilities.*;
+
+public class LinuxPPC64JavaThreadPDAccess implements JavaThreadPDAccess {
+  private static AddressField  osThreadField;
+
+  // Field from OSThread
+  private static CIntegerField osThreadThreadIDField;
+
+  // This is currently unneeded but is being kept in case we change
+  // the currentFrameGuess algorithm
+  private static final long GUESS_SCAN_RANGE = 128 * 1024;
+
+  static {
+    VM.registerVMInitializedObserver(new Observer() {
+        public void update(Observable o, Object data) {
+          initialize(VM.getVM().getTypeDataBase());
+        }
+      });
+  }
+
+  private static synchronized void initialize(TypeDataBase db) {
+    Type type = db.lookupType("JavaThread");
+    osThreadField = type.getAddressField("_osthread");
+
+    Type osThreadType = db.lookupType("OSThread");
+    osThreadThreadIDField = osThreadType.getCIntegerField("_thread_id");
+  }
+
+  public Address getLastJavaFP(Address addr) {
+    return null;
+  }
+
+  public Address getLastJavaPC(Address addr) {
+    return null;
+  }
+
+  public Address getBaseOfStackPointer(Address addr) {
+    return null;
+  }
+
+  public Frame getLastFramePD(JavaThread thread, Address addr) {
+    Address fp = thread.getLastJavaFP();
+    if (fp == null) {
+      return null; // no information
+    }
+    return new PPC64Frame(thread.getLastJavaSP(), fp);
+  }
+
+  public RegisterMap newRegisterMap(JavaThread thread, boolean updateMap) {
+    return new PPC64RegisterMap(thread, updateMap);
+  }
+
+  public Frame getCurrentFrameGuess(JavaThread thread, Address addr) {
+    ThreadProxy t = getThreadProxy(addr);
+    PPC64ThreadContext context = (PPC64ThreadContext) t.getContext();
+    PPC64CurrentFrameGuess guesser = new PPC64CurrentFrameGuess(context, thread);
+    if (!guesser.run(GUESS_SCAN_RANGE)) {
+      return null;
+    }
+    if (guesser.getPC() == null) {
+      return new PPC64Frame(guesser.getSP(), guesser.getFP());
+    } else {
+      return new PPC64Frame(guesser.getSP(), guesser.getFP(), guesser.getPC());
+    }
+  }
+
+  public void printThreadIDOn(Address addr, PrintStream tty) {
+    tty.print(getThreadProxy(addr));
+  }
+
+  public void printInfoOn(Address threadAddr, PrintStream tty) {
+    tty.print("Thread id: ");
+    printThreadIDOn(threadAddr, tty);
+    // tty.println("\nPostJavaState: " + getPostJavaState(threadAddr));
+  }
+
+  public Address getLastSP(Address addr) {
+    ThreadProxy t = getThreadProxy(addr);
+    PPC64ThreadContext context = (PPC64ThreadContext) t.getContext();
+    return context.getRegisterAsAddress(PPC64ThreadContext.SP);
+  }
+
+  public Address getLastFP(Address addr) {
+    return getLastSP(addr).getAddressAt(0);
+  }
+
+  public ThreadProxy getThreadProxy(Address addr) {
+    // Addr is the address of the JavaThread.
+    // Fetch the OSThread (for now and for simplicity, not making a
+    // separate "OSThread" class in this package)
+    Address osThreadAddr = osThreadField.getValue(addr);
+    // Get the address of the _thread_id from the OSThread
+    Address threadIdAddr = osThreadAddr.addOffsetTo(osThreadThreadIDField.getOffset());
+
+    JVMDebugger debugger = VM.getVM().getDebugger();
+    return debugger.getThreadForIdentifierAddress(threadIdAddr);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ppc64/PPC64CurrentFrameGuess.java	Fri Jan 09 13:28:02 2015 -0500
@@ -0,0 +1,179 @@
+/*
+ * 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.
+ *
+ */
+
+package sun.jvm.hotspot.runtime.ppc64;
+
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.debugger.ppc64.*;
+import sun.jvm.hotspot.code.*;
+import sun.jvm.hotspot.interpreter.*;
+import sun.jvm.hotspot.runtime.*;
+import sun.jvm.hotspot.runtime.ppc64.*;
+
+/** <P> Should be able to be used on all ppc64 platforms we support
+    (Linux/ppc64) to implement JavaThread's "currentFrameGuess()"
+    functionality. Input is a PPC64ThreadContext; output is SP, FP,
+    and PC for an PPC64Frame. Instantiation of the PPC64Frame is left
+    to the caller, since we may need to subclass PPC64Frame to support
+    signal handler frames on Unix platforms. </P>
+ */
+
+public class PPC64CurrentFrameGuess {
+  private PPC64ThreadContext context;
+  private JavaThread       thread;
+  private Address          spFound;
+  private Address          fpFound;
+  private Address          pcFound;
+
+  private static final boolean DEBUG;
+  static {
+    DEBUG = System.getProperty("sun.jvm.hotspot.runtime.ppc64.PPC64Frame.DEBUG") != null;
+  }
+
+  public PPC64CurrentFrameGuess(PPC64ThreadContext context,
+                              JavaThread thread) {
+    this.context = context;
+    this.thread  = thread;
+  }
+
+  /** Returns false if not able to find a frame within a reasonable range. */
+  public boolean run(long regionInBytesToSearch) {
+    Address sp = context.getRegisterAsAddress(PPC64ThreadContext.SP);
+    Address pc = context.getRegisterAsAddress(PPC64ThreadContext.PC);
+    if (sp == null) {
+      // Bail out if no last java frame either
+      if (thread.getLastJavaSP() != null) {
+        Address javaSP = thread.getLastJavaSP();
+        Address javaFP = javaSP.getAddressAt(0);
+        setValues(javaSP, javaFP, null);
+        return true;
+      }
+      return false;
+    }
+    /* There is no frame pointer per se for the ppc64 architecture.  To mirror
+     * the behavior of the VM frame manager, we set fp to be the caller's (i.e., "sender's")
+     * stack pointer, which is the back chain value contained in our sp.
+     */
+    Address fp = sp.getAddressAt(0);
+    setValues(null, null, null); // Assume we're not going to find anything
+
+    VM vm = VM.getVM();
+    if (vm.isJavaPCDbg(pc)) {
+      if (vm.isClientCompiler()) {
+        // Topmost frame is a Java frame.
+        if (DEBUG) {
+          System.out.println("CurrentFrameGuess: choosing compiler frame: sp = " +
+                             sp + ", fp = " + fp + ", pc = " + pc);
+        }
+        setValues(sp, fp, pc);
+        return true;
+      } else {
+        if (vm.getInterpreter().contains(pc)) {
+          if (DEBUG) {
+            System.out.println("CurrentFrameGuess: choosing interpreter frame: sp = " +
+                               sp + ", fp = " + fp + ", pc = " + pc);
+          }
+          setValues(sp, fp, pc);
+          return true;
+        }
+
+        // This algorithm takes the current PC as a given and tries to
+        // find the correct corresponding SP by walking up the stack
+        // and repeatedly performing stackwalks (very inefficient).
+        for (long offset = 0;
+             offset < regionInBytesToSearch;
+             offset += vm.getAddressSize()) {
+          try {
+            Address curSP = sp.addOffsetTo(offset);
+            fp = curSP.getAddressAt(0);
+            Frame frame = new PPC64Frame(curSP, fp, pc);
+            RegisterMap map = thread.newRegisterMap(false);
+            while (frame != null) {
+              if (frame.isEntryFrame() && frame.entryFrameIsFirst()) {
+                // We were able to traverse all the way to the
+                // bottommost Java frame.
+                // This sp looks good. Keep it.
+                if (DEBUG) {
+                  System.out.println("CurrentFrameGuess: Choosing sp = " + curSP + ", pc = " + pc);
+                }
+                setValues(curSP, fp, pc);
+                return true;
+              }
+              frame = frame.sender(map);
+            }
+          } catch (Exception e) {
+            if (DEBUG) {
+              System.out.println("CurrentFrameGuess: Exception " + e + " at offset " + offset);
+            }
+            // Bad SP. Try another.
+          }
+        }
+
+        // Were not able to find a plausible SP to go with this PC.
+        // Bail out.
+        return false;
+
+      }
+    } else {
+      // If the current program counter was not known to us as a Java
+      // PC, we currently assume that we are in the run-time system
+      // and attempt to look to thread-local storage for saved java SP.
+      // Note that if this is null (because we were, in fact,
+      // in Java code, i.e., vtable stubs or similar, and the SA
+      // didn't have enough insight into the target VM to understand
+      // that) then we are going to lose the entire stack trace for
+      // the thread, which is sub-optimal. FIXME.
+
+      if (thread.getLastJavaSP() == null) {
+        if (DEBUG) {
+          System.out.println("CurrentFrameGuess: last java sp is null");
+        }
+        return false; // No known Java frames on stack
+      }
+
+      Address javaSP = thread.getLastJavaSP();
+      Address javaFP = javaSP.getAddressAt(0);
+      Address javaPC = thread.getLastJavaPC();
+      if (DEBUG) {
+        System.out.println("CurrentFrameGuess: choosing last Java frame: sp = " +
+                           javaSP + ", fp = " + javaFP + ", pc = " + javaPC);
+      }
+      setValues(javaSP, javaFP, javaPC);
+      return true;
+    }
+  }
+
+  public Address getSP() { return spFound; }
+  public Address getFP() { return fpFound; }
+  /** May be null if getting values from thread-local storage; take
+      care to call the correct PPC64Frame constructor to recover this if
+      necessary */
+  public Address getPC() { return pcFound; }
+
+  private void setValues(Address sp, Address fp, Address pc) {
+    spFound = sp;
+    fpFound = fp;
+    pcFound = pc;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ppc64/PPC64Frame.java	Fri Jan 09 13:28:02 2015 -0500
@@ -0,0 +1,513 @@
+/*
+ * 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.
+ *
+ */
+
+package sun.jvm.hotspot.runtime.ppc64;
+
+import java.util.*;
+import sun.jvm.hotspot.code.*;
+import sun.jvm.hotspot.compiler.*;
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.oops.*;
+import sun.jvm.hotspot.runtime.*;
+import sun.jvm.hotspot.types.*;
+import sun.jvm.hotspot.utilities.*;
+
+/** Specialization of and implementation of abstract methods of the
+    Frame class for the ppc64 family of CPUs. */
+
+public class PPC64Frame extends Frame {
+  private static final boolean DEBUG;
+  static {
+    DEBUG = System.getProperty("sun.jvm.hotspot.runtime.ppc64.PPC64Frame.DEBUG") != null;
+  }
+
+  // All frames
+  private static final int SENDER_SP_OFFSET           =  0;
+
+  // Interpreter frames
+  private static final int INTERPRETER_FRAME_MIRROR_OFFSET = -3; // for native calls only
+  private static final int INTERPRETER_FRAME_SENDER_SP_OFFSET = -4;
+  private static final int INTERPRETER_FRAME_LAST_SP_OFFSET = INTERPRETER_FRAME_SENDER_SP_OFFSET - 1;
+  private static final int INTERPRETER_FRAME_MDX_OFFSET = INTERPRETER_FRAME_LAST_SP_OFFSET -1;
+  private static final int INTERPRETER_FRAME_ESP_OFFSET = INTERPRETER_FRAME_MDX_OFFSET - 1;
+  private static final int INTERPRETER_FRAME_BCX_OFFSET = INTERPRETER_FRAME_ESP_OFFSET - 1;
+  private static final int INTERPRETER_FRAME_CACHE_OFFSET =INTERPRETER_FRAME_BCX_OFFSET - 1;
+  private static final int INTERPRETER_FRAME_MONITORS_OFFSET = INTERPRETER_FRAME_CACHE_OFFSET - 1;
+  private static final int INTERPRETER_FRAME_LOCALS_OFFSET = INTERPRETER_FRAME_MONITORS_OFFSET - 1;
+  private static final int INTERPRETER_FRAME_METHOD_OFFSET = INTERPRETER_FRAME_LOCALS_OFFSET - 1;
+  private static final int INTERPRETER_FRAME_INITIAL_SP_OFFSET = INTERPRETER_FRAME_BCX_OFFSET - 1; // FIXME: probably wrong, but unused anyway
+  private static final int INTERPRETER_FRAME_MONITOR_BLOCK_TOP_OFFSET = INTERPRETER_FRAME_INITIAL_SP_OFFSET;
+  private static final int INTERPRETER_FRAME_MONITOR_BLOCK_BOTTOM_OFFSET = INTERPRETER_FRAME_INITIAL_SP_OFFSET;
+
+  // Entry frames
+  private static int ENTRY_FRAME_CALL_WRAPPER_OFFSET;
+
+  // Native frames
+  private static int NATIVE_FRAME_INITIAL_PARAM_OFFSET;
+
+
+  static {
+    VM.registerVMInitializedObserver(new Observer() {
+      public void update(Observable o, Object data) {
+        initialize(VM.getVM().getTypeDataBase());
+      }
+    });
+  }
+
+  private static synchronized void initialize(TypeDataBase db) {
+    int abi_minframe_size = db.lookupIntConstant("frame::abi_minframe_size").intValue();
+    int entry_frame_locals_size = db.lookupIntConstant("frame::entry_frame_locals_size").intValue();
+    int wordLength = (int) VM.getVM().getAddressSize();
+    NATIVE_FRAME_INITIAL_PARAM_OFFSET = -abi_minframe_size/wordLength;
+    ENTRY_FRAME_CALL_WRAPPER_OFFSET = -entry_frame_locals_size/wordLength;
+  }
+
+
+  // an additional field beyond sp and pc:
+  Address raw_fp; // frame pointer
+  private Address raw_unextendedSP;
+
+  private PPC64Frame() {
+  }
+
+  private void adjustForDeopt() {
+    if ( pc != null) {
+      // Look for a deopt pc and if it is deopted convert to original pc
+      CodeBlob cb = VM.getVM().getCodeCache().findBlob(pc);
+      if (cb != null && cb.isJavaMethod()) {
+        NMethod nm = (NMethod) cb;
+        if (pc.equals(nm.deoptHandlerBegin())) {
+          if (Assert.ASSERTS_ENABLED) {
+            Assert.that(this.getUnextendedSP() != null, "null SP in Java frame");
+          }
+          // adjust pc if frame is deoptimized.
+          pc = this.getUnextendedSP().getAddressAt(nm.origPCOffset());
+          deoptimized = true;
+        }
+      }
+    }
+  }
+
+  public PPC64Frame(Address raw_sp, Address raw_fp, Address pc) {
+    this.raw_sp = raw_sp;
+    this.raw_unextendedSP = raw_sp;
+    if (raw_fp == null) {
+      this.raw_fp = raw_sp.getAddressAt(0);
+    } else {
+      this.raw_fp = raw_fp;
+    }
+    if (pc == null) {
+      this.pc = raw_sp.getAddressAt(2 * VM.getVM().getAddressSize());
+    } else {
+      this.pc = pc;
+    }
+    adjustUnextendedSP();
+
+    // Frame must be fully constructed before this call
+    adjustForDeopt();
+
+    if (DEBUG) {
+      System.out.println("PPC64Frame(sp, fp, pc): " + this);
+      dumpStack();
+    }
+  }
+
+  public PPC64Frame(Address raw_sp, Address raw_fp) {
+    this.raw_sp = raw_sp;
+    this.raw_unextendedSP = raw_sp;
+    if (raw_fp == null) {
+      this.raw_fp = raw_sp.getAddressAt(0);
+    } else {
+      this.raw_fp = raw_fp;
+    }
+    this.pc = raw_sp.getAddressAt(2 * VM.getVM().getAddressSize());
+    adjustUnextendedSP();
+
+    // Frame must be fully constructed before this call
+    adjustForDeopt();
+
+    if (DEBUG) {
+      System.out.println("PPC64Frame(sp, fp): " + this);
+      dumpStack();
+    }
+  }
+
+  public PPC64Frame(Address raw_sp, Address raw_unextendedSp, Address raw_fp, Address pc) {
+    this.raw_sp = raw_sp;
+    this.raw_unextendedSP = raw_unextendedSp;
+    if (raw_fp == null) {
+      this.raw_fp = raw_sp.getAddressAt(0);
+    } else {
+      this.raw_fp = raw_fp;
+    }
+    if (pc == null) {
+      this.pc = raw_sp.getAddressAt(2 * VM.getVM().getAddressSize());
+    } else {
+      this.pc = pc;
+    }
+    adjustUnextendedSP();
+
+    // Frame must be fully constructed before this call
+    adjustForDeopt();
+
+    if (DEBUG) {
+      System.out.println("PPC64Frame(sp, unextendedSP, fp, pc): " + this);
+      dumpStack();
+    }
+
+  }
+
+  public Object clone() {
+    PPC64Frame frame = new PPC64Frame();
+    frame.raw_sp = raw_sp;
+    frame.raw_unextendedSP = raw_unextendedSP;
+    frame.raw_fp = raw_fp;
+    frame.pc = pc;
+    frame.deoptimized = deoptimized;
+    return frame;
+  }
+
+  public boolean equals(Object arg) {
+    if (arg == null) {
+      return false;
+    }
+
+    if (!(arg instanceof PPC64Frame)) {
+      return false;
+    }
+
+    PPC64Frame other = (PPC64Frame) arg;
+
+    return (AddressOps.equal(getSP(), other.getSP()) &&
+        AddressOps.equal(getUnextendedSP(), other.getUnextendedSP()) &&
+        AddressOps.equal(getFP(), other.getFP()) &&
+        AddressOps.equal(getPC(), other.getPC()));
+  }
+
+  public int hashCode() {
+    if (raw_sp == null) {
+      return 0;
+    }
+
+    return raw_sp.hashCode();
+  }
+
+  public String toString() {
+    return "sp: " + (getSP() == null ? "null" : getSP().toString()) +
+        ", unextendedSP: " + (getUnextendedSP() == null ? "null" : getUnextendedSP().toString()) +
+        ", fp: " + (getFP() == null ? "null" : getFP().toString()) +
+        ", pc: " + (pc == null ? "null" : pc.toString());
+  }
+
+  // accessors for the instance variables
+  public Address getFP() { return raw_fp; }
+  public Address getSP() { return raw_sp; }
+  public Address getID() { return raw_sp; }
+
+  // FIXME: not implemented yet (should be done for Solaris/PPC64)
+  public boolean isSignalHandlerFrameDbg() { return false; }
+  public int     getSignalNumberDbg()      { return 0;     }
+  public String  getSignalNameDbg()        { return null;  }
+
+  public boolean isInterpretedFrameValid() {
+    if (Assert.ASSERTS_ENABLED) {
+      Assert.that(isInterpretedFrame(), "Not an interpreted frame");
+    }
+
+    // These are reasonable sanity checks
+    if (getFP() == null || getFP().andWithMask(0x3) != null) {
+      return false;
+    }
+
+    if (getSP() == null || getSP().andWithMask(0x3) != null) {
+      return false;
+    }
+
+    // These are hacks to keep us out of trouble.
+    // The problem with these is that they mask other problems
+    if (getFP().lessThanOrEqual(getSP())) {
+      // this attempts to deal with unsigned comparison above
+      return false;
+    }
+
+    if (getFP().minus(getSP()) > 4096 * VM.getVM().getAddressSize()) {
+      // stack frames shouldn't be large.
+      return false;
+    }
+
+    return true;
+  }
+
+  // FIXME: not applicable in current system
+  //  void    patch_pc(Thread* thread, address pc);
+
+  public Frame sender(RegisterMap regMap, CodeBlob cb) {
+    PPC64RegisterMap map = (PPC64RegisterMap) regMap;
+
+    if (Assert.ASSERTS_ENABLED) {
+      Assert.that(map != null, "map must be set");
+    }
+
+    // Default is we done have to follow them. The sender_for_xxx will
+    // update it accordingly
+    map.setIncludeArgumentOops(false);
+
+    if (isEntryFrame()) return senderForEntryFrame(map);
+    if (isInterpretedFrame()) return senderForInterpreterFrame(map);
+
+    if(cb == null) {
+      cb = VM.getVM().getCodeCache().findBlob(getPC());
+    } else {
+      if (Assert.ASSERTS_ENABLED) {
+        Assert.that(cb.equals(VM.getVM().getCodeCache().findBlob(getPC())), "Must be the same");
+      }
+    }
+
+    if (cb != null) {
+      return senderForCompiledFrame(map, cb);
+    }
+
+    // Must be native-compiled frame, i.e. the marshaling code for native
+    // methods that exists in the core system.
+    return new PPC64Frame(getSenderSP(), getLink(), getSenderPC());
+  }
+
+  private Frame senderForEntryFrame(PPC64RegisterMap map) {
+    if (DEBUG) {
+      System.out.println("senderForEntryFrame");
+    }
+    if (Assert.ASSERTS_ENABLED) {
+      Assert.that(map != null, "map must be set");
+    }
+    // Java frame called from C; skip all C frames and return top C
+    // frame of that chunk as the sender
+    PPC64JavaCallWrapper jcw = (PPC64JavaCallWrapper) getEntryFrameCallWrapper();
+    if (Assert.ASSERTS_ENABLED) {
+      Assert.that(!entryFrameIsFirst(), "next Java fp must be non zero");
+      Assert.that(jcw.getLastJavaSP().greaterThan(getSP()), "must be above this frame on stack");
+    }
+    PPC64Frame fr;
+    if (jcw.getLastJavaPC() != null) {
+      fr = new PPC64Frame(jcw.getLastJavaSP(), jcw.getLastJavaFP(), jcw.getLastJavaPC());
+    } else {
+      fr = new PPC64Frame(jcw.getLastJavaSP(), jcw.getLastJavaFP());
+    }
+    map.clear();
+    if (Assert.ASSERTS_ENABLED) {
+      Assert.that(map.getIncludeArgumentOops(), "should be set by clear");
+    }
+    return fr;
+  }
+
+  //------------------------------------------------------------------------------
+  // frame::adjust_unextended_sp
+  private void adjustUnextendedSP() {
+    raw_unextendedSP = getFP();
+  }
+  private Frame senderForInterpreterFrame(PPC64RegisterMap map) {
+    if (DEBUG) {
+      System.out.println("senderForInterpreterFrame");
+    }
+    Address unextendedSP = addressOfStackSlot(INTERPRETER_FRAME_SENDER_SP_OFFSET).getAddressAt(0);
+    Address sp = getSenderSP();
+
+    return new PPC64Frame(sp, unextendedSP, getLink(), getSenderPC());
+  }
+
+
+  private Frame senderForCompiledFrame(PPC64RegisterMap map, CodeBlob cb) {
+    if (DEBUG) {
+      System.out.println("senderForCompiledFrame");
+    }
+
+    //
+    // NOTE: some of this code is (unfortunately) duplicated in PPC64CurrentFrameGuess
+    //
+
+    if (Assert.ASSERTS_ENABLED) {
+      Assert.that(map != null, "map must be set");
+    }
+
+    // frame owned by optimizing compiler
+    if (Assert.ASSERTS_ENABLED) {
+      Assert.that(cb.getFrameSize() >= 0, "must have non-zero frame size");
+    }
+    Address senderSP = getSenderSP();
+
+    Address senderPC = getSenderPC();
+
+    if (map.getUpdateMap()) {
+      // Tell GC to use argument oopmaps for some runtime stubs that need it.
+      // For C1, the runtime stub might not have oop maps, so set this flag
+      // outside of update_register_map.
+      map.setIncludeArgumentOops(cb.callerMustGCArguments());
+
+      if (cb.getOopMaps() != null) {
+        OopMapSet.updateRegisterMap(this, cb, map, true);
+      }
+    }
+
+    return new PPC64Frame(senderSP, getLink(), senderPC);
+  }
+
+  protected boolean hasSenderPD() {
+    // FIXME
+    return true;
+  }
+
+  public long frameSize() {
+    return (getSenderSP().minus(getSP()) / VM.getVM().getAddressSize());
+  }
+
+  public Address getLink() {
+    return getSenderSP().getAddressAt(0);
+  }
+
+  public Address getUnextendedSP() { return raw_unextendedSP; }
+
+  // Return address:
+  public Address getSenderPC()     { return getSenderSP().getAddressAt(2 * VM.getVM().getAddressSize()); }
+
+  // return address of param, zero origin index.
+  // MPJ note:   Appears to be unused.
+  public Address getNativeParamAddr(int idx) {
+    return null;
+    // return addressOfStackSlot(NATIVE_FRAME_INITIAL_PARAM_OFFSET + idx);
+  }
+
+  public Address getSenderSP()     { return getFP(); }
+  public Address addressOfInterpreterFrameLocals() {
+    return addressOfStackSlot(INTERPRETER_FRAME_LOCALS_OFFSET);
+  }
+
+  private Address addressOfInterpreterFrameBCX() {
+    return addressOfStackSlot(INTERPRETER_FRAME_BCX_OFFSET);
+  }
+
+  public int getInterpreterFrameBCI() {
+    // FIXME: this is not atomic with respect to GC and is unsuitable
+    // for use in a non-debugging, or reflective, system. Need to
+    // figure out how to express this.
+    Address bcp = addressOfInterpreterFrameBCX().getAddressAt(0);
+    Address methodHandle = addressOfInterpreterFrameMethod().getAddressAt(0);
+    Method method = (Method)Metadata.instantiateWrapperFor(methodHandle);
+    return bcpToBci(bcp, method);
+  }
+
+  public Address addressOfInterpreterFrameMDX() {
+    return addressOfStackSlot(INTERPRETER_FRAME_MDX_OFFSET);
+  }
+
+  // FIXME
+  //inline int frame::interpreter_frame_monitor_size() {
+  //  return BasicObjectLock::size();
+  //}
+
+  // expression stack
+  // (the max_stack arguments are used by the GC; see class FrameClosure)
+
+  public Address addressOfInterpreterFrameExpressionStack() {
+    Address monitorEnd = interpreterFrameMonitorEnd().address();
+    return monitorEnd.addOffsetTo(-1 * VM.getVM().getAddressSize());
+  }
+
+  public int getInterpreterFrameExpressionStackDirection() { return -1; }
+
+  // top of expression stack
+  public Address addressOfInterpreterFrameTOS() {
+    return getSP();
+  }
+
+  /** Expression stack from top down */
+  public Address addressOfInterpreterFrameTOSAt(int slot) {
+    return addressOfInterpreterFrameTOS().addOffsetTo(slot * VM.getVM().getAddressSize());
+  }
+
+  public Address getInterpreterFrameSenderSP() {
+    if (Assert.ASSERTS_ENABLED) {
+      Assert.that(isInterpretedFrame(), "interpreted frame expected");
+    }
+    return addressOfStackSlot(INTERPRETER_FRAME_SENDER_SP_OFFSET).getAddressAt(0);
+  }
+
+  // Monitors
+  public BasicObjectLock interpreterFrameMonitorBegin() {
+    return new BasicObjectLock(addressOfStackSlot(INTERPRETER_FRAME_MONITOR_BLOCK_BOTTOM_OFFSET));
+  }
+
+  public BasicObjectLock interpreterFrameMonitorEnd() {
+    Address result = addressOfStackSlot(INTERPRETER_FRAME_MONITOR_BLOCK_TOP_OFFSET).getAddressAt(0);
+    if (Assert.ASSERTS_ENABLED) {
+      // make sure the pointer points inside the frame
+      Assert.that(AddressOps.gt(getFP(), result), "result must <  than frame pointer");
+      Assert.that(AddressOps.lte(getSP(), result), "result must >= than stack pointer");
+    }
+    return new BasicObjectLock(result);
+  }
+
+  public int interpreterFrameMonitorSize() {
+    return BasicObjectLock.size();
+  }
+
+  // Method
+  public Address addressOfInterpreterFrameMethod() {
+    return addressOfStackSlot(INTERPRETER_FRAME_METHOD_OFFSET);
+  }
+
+  // Constant pool cache
+  public Address addressOfInterpreterFrameCPCache() {
+    return addressOfStackSlot(INTERPRETER_FRAME_CACHE_OFFSET);
+  }
+
+  // Entry frames
+  public JavaCallWrapper getEntryFrameCallWrapper() {
+    return new PPC64JavaCallWrapper(addressOfStackSlot(ENTRY_FRAME_CALL_WRAPPER_OFFSET).getAddressAt(0));
+  }
+
+  protected Address addressOfSavedOopResult() {
+    // offset is 2 for compiler2 and 3 for compiler1
+    return getSP().addOffsetTo((VM.getVM().isClientCompiler() ? 2 : 3) *
+        VM.getVM().getAddressSize());
+  }
+
+  protected Address addressOfSavedReceiver() {
+    return getSP().addOffsetTo(-4 * VM.getVM().getAddressSize());
+  }
+
+  private void dumpStack() {
+    if (getFP() != null) {
+      for (Address addr = getSP().addOffsetTo(-5 * VM.getVM().getAddressSize());
+          AddressOps.lte(addr, getFP().addOffsetTo(5 * VM.getVM().getAddressSize()));
+          addr = addr.addOffsetTo(VM.getVM().getAddressSize())) {
+        System.out.println(addr + ": " + addr.getAddressAt(0));
+      }
+    } else {
+      for (Address addr = getSP().addOffsetTo(-5 * VM.getVM().getAddressSize());
+          AddressOps.lte(addr, getSP().addOffsetTo(20 * VM.getVM().getAddressSize()));
+          addr = addr.addOffsetTo(VM.getVM().getAddressSize())) {
+        System.out.println(addr + ": " + addr.getAddressAt(0));
+      }
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ppc64/PPC64JavaCallWrapper.java	Fri Jan 09 13:28:02 2015 -0500
@@ -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.
+ *
+ */
+
+package sun.jvm.hotspot.runtime.ppc64;
+
+import java.util.*;
+
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.types.*;
+import sun.jvm.hotspot.runtime.*;
+
+public class PPC64JavaCallWrapper extends JavaCallWrapper {
+
+  public PPC64JavaCallWrapper(Address addr) {
+    super(addr);
+  }
+
+  public Address getLastJavaFP() {
+    return null;
+  }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ppc64/PPC64RegisterMap.java	Fri Jan 09 13:28:02 2015 -0500
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 20014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package sun.jvm.hotspot.runtime.ppc64;
+
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.runtime.*;
+
+public class PPC64RegisterMap extends RegisterMap {
+
+  /** This is the only public constructor */
+  public PPC64RegisterMap(JavaThread thread, boolean updateMap) {
+    super(thread, updateMap);
+  }
+
+  protected PPC64RegisterMap(RegisterMap map) {
+    super(map);
+  }
+
+  public Object clone() {
+    PPC64RegisterMap retval = new PPC64RegisterMap(this);
+    return retval;
+  }
+
+  // no PD state to clear or copy:
+  protected void clearPD() {}
+  protected void initializePD() {}
+  protected void initializeFromPD(RegisterMap map) {}
+  protected Address getLocationPD(VMReg reg) { return null; }
+}
--- a/hotspot/make/aix/makefiles/ppc64.make	Fri Jan 09 05:45:13 2015 -0800
+++ b/hotspot/make/aix/makefiles/ppc64.make	Fri Jan 09 13:28:02 2015 -0500
@@ -46,7 +46,9 @@
 #  - 1540-1090 (I) The destructor of "..." might not be called.
 #  - 1500-010: (W) WARNING in ...: Infinite loop.  Program may not stop.
 #    There are several infinite loops in the vm, suppress.
-CFLAGS += -qsuppress=1540-1090 -qsuppress=1500-010
+#  - 1540-1639 (I) The behavior of long type bit fields has changed ...
+#                  ... long type bit fields now default to long, not int.
+CFLAGS += -qsuppress=1540-1090 -qsuppress=1500-010 -qsuppress=1540-1639
 
 # Suppress 
 #  - 540-1088 (W) The exception specification is being ignored.
--- a/hotspot/make/aix/makefiles/xlc.make	Fri Jan 09 05:45:13 2015 -0800
+++ b/hotspot/make/aix/makefiles/xlc.make	Fri Jan 09 13:28:02 2015 -0500
@@ -124,7 +124,7 @@
 # MAPFLAG = -Xlinker --version-script=FILENAME
 
 # Build shared library
-SHARED_FLAG = -q64 -b64 -bexpall -G -bnoentry -qmkshrobj -brtl -bnolibpath
+SHARED_FLAG = -q64 -b64 -bexpall -G -bnoentry -qmkshrobj -brtl -bnolibpath -bernotok
 
 #------------------------------------------------------------------------
 # Debug flags
--- a/hotspot/make/linux/makefiles/sa.make	Fri Jan 09 05:45:13 2015 -0800
+++ b/hotspot/make/linux/makefiles/sa.make	Fri Jan 09 13:28:02 2015 -0500
@@ -109,6 +109,7 @@
 	$(QUIETLY) $(REMOTE) $(RUN.JAVAH) -classpath $(SA_CLASSDIR) -d $(GENERATED) -jni sun.jvm.hotspot.debugger.x86.X86ThreadContext
 	$(QUIETLY) $(REMOTE) $(RUN.JAVAH) -classpath $(SA_CLASSDIR) -d $(GENERATED) -jni sun.jvm.hotspot.debugger.amd64.AMD64ThreadContext
 	$(QUIETLY) $(REMOTE) $(RUN.JAVAH) -classpath $(SA_CLASSDIR) -d $(GENERATED) -jni sun.jvm.hotspot.debugger.sparc.SPARCThreadContext
+	$(QUIETLY) $(REMOTE) $(RUN.JAVAH) -classpath $(SA_CLASSDIR) -d $(GENERATED) -jni sun.jvm.hotspot.debugger.ppc64.PPC64ThreadContext
 	$(QUIETLY) $(REMOTE) $(RUN.JAVAH) -classpath $(SA_CLASSDIR) -d $(GENERATED) -jni sun.jvm.hotspot.asm.Disassembler
 
 clean:
--- a/hotspot/make/sa.files	Fri Jan 09 05:45:13 2015 -0800
+++ b/hotspot/make/sa.files	Fri Jan 09 13:28:02 2015 -0500
@@ -51,16 +51,20 @@
 $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/dummy/*.java \
 $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/linux/*.java \
 $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/linux/amd64/*.java \
+$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/linux/ppc64/*.java \
 $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/linux/x86/*.java \
 $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/linux/sparc/*.java \
 $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/posix/*.java \
 $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/posix/elf/*.java \
+$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/ppc64/*.java \
 $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/proc/*.java \
 $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/proc/amd64/*.java \
+$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/proc/ppc64/*.java \
 $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/proc/sparc/*.java \
 $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/proc/x86/*.java \
 $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/remote/*.java \
 $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/remote/amd64/*.java \
+$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/remote/ppc64/*.java \
 $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/remote/sparc/*.java \
 $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/remote/x86/*.java \
 $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/sparc/*.java \
@@ -90,12 +94,14 @@
 $(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/linux_amd64/*.java \
 $(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/linux_x86/*.java \
 $(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/linux_sparc/*.java \
+$(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/linux_ppc64/*.java \
 $(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/posix/*.java \
 $(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/solaris_amd64/*.java \
 $(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/solaris_sparc/*.java \
 $(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/solaris_x86/*.java \
 $(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/sparc/*.java \
 $(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/x86/*.java \
+$(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/ppc64/*.java \
 $(AGENT_SRC_DIR)/sun/jvm/hotspot/tools/*.java \
 $(AGENT_SRC_DIR)/sun/jvm/hotspot/tools/jcore/*.java \
 $(AGENT_SRC_DIR)/sun/jvm/hotspot/tools/soql/*.java \
--- a/hotspot/src/share/vm/classfile/classLoaderData.cpp	Fri Jan 09 05:45:13 2015 -0800
+++ b/hotspot/src/share/vm/classfile/classLoaderData.cpp	Fri Jan 09 13:28:02 2015 -0500
@@ -786,17 +786,12 @@
   MetadataOnStackMark md_on_stack(has_redefined_a_class);
 
   if (has_redefined_a_class) {
-    // purge_previous_versions also cleans weak method links. Because
-    // one method's MDO can reference another method from another
-    // class loader, we need to first clean weak method links for all
-    // class loaders here. Below, we can then free redefined methods
-    // for all class loaders.
     for (ClassLoaderData* data = _head; data != NULL; data = data->next()) {
       data->classes_do(InstanceKlass::purge_previous_versions);
     }
   }
 
-  // Need to purge the previous version before deallocating.
+  // Should purge the previous version before deallocating.
   free_deallocate_lists();
 }
 
@@ -834,8 +829,6 @@
 
 void ClassLoaderDataGraph::free_deallocate_lists() {
   for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) {
-    // We need to keep this data until InstanceKlass::purge_previous_version has been
-    // called on all alive classes. See the comment in ClassLoaderDataGraph::clean_metaspaces.
     cld->free_deallocate_list();
   }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/classfile/compactHashtable.cpp	Fri Jan 09 13:28:02 2015 -0500
@@ -0,0 +1,417 @@
+/*
+ * 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
+ * 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 "classfile/javaClasses.hpp"
+#include "memory/metaspaceShared.hpp"
+#include "utilities/numberSeq.hpp"
+#include <sys/stat.h>
+
+/////////////////////////////////////////////////////
+//
+// The compact hash table writer implementations
+//
+CompactHashtableWriter::CompactHashtableWriter(const char* table_name,
+                                               int num_entries,
+                                               CompactHashtableStats* stats) {
+  assert(DumpSharedSpaces, "dump-time only");
+  _table_name = table_name;
+  _num_entries = num_entries;
+  _num_buckets = number_of_buckets(_num_entries);
+  _buckets = NEW_C_HEAP_ARRAY(Entry*, _num_buckets, mtSymbol);
+  memset(_buckets, 0, sizeof(Entry*) * _num_buckets);
+
+  /* bucket sizes table */
+  _bucket_sizes = NEW_C_HEAP_ARRAY(juint, _num_buckets, mtSymbol);
+  memset(_bucket_sizes, 0, sizeof(juint) * _num_buckets);
+
+  stats->hashentry_count = _num_entries;
+  // Compact buckets' entries will have only the 4-byte offset, but
+  // we don't know how many there will be at this point. So use a
+  // conservative estimate here. The size is adjusted later when we
+  // write out the buckets.
+  stats->hashentry_bytes = _num_entries * 8;
+  stats->bucket_count    = _num_buckets;
+  stats->bucket_bytes    = (_num_buckets + 1) * (sizeof(juint));
+  _stats = stats;
+
+  // See compactHashtable.hpp for table layout
+  _required_bytes = sizeof(juint) * 2; // _base_address, written as 2 juints
+  _required_bytes+= sizeof(juint) +    // num_entries
+                    sizeof(juint) +    // num_buckets
+                    stats->hashentry_bytes +
+                    stats->bucket_bytes;
+}
+
+CompactHashtableWriter::~CompactHashtableWriter() {
+  for (int index = 0; index < _num_buckets; index++) {
+    Entry* next = NULL;
+    for (Entry* tent = _buckets[index]; tent; tent = next) {
+      next = tent->next();
+      delete tent;
+    }
+  }
+
+  FREE_C_HEAP_ARRAY(juint, _bucket_sizes);
+  FREE_C_HEAP_ARRAY(Entry*, _buckets);
+}
+
+// Calculate the number of buckets in the temporary hash table
+int CompactHashtableWriter::number_of_buckets(int num_entries) {
+  const int buksize = (int)SharedSymbolTableBucketSize;
+  int num_buckets = (num_entries + buksize - 1) / buksize;
+  num_buckets = (num_buckets + 1) & (~0x01);
+
+  return num_buckets;
+}
+
+// Add a symbol entry to the temporary hash table
+void CompactHashtableWriter::add(unsigned int hash, Entry* entry) {
+  int index = hash % _num_buckets;
+  entry->set_next(_buckets[index]);
+  _buckets[index] = entry;
+  _bucket_sizes[index] ++;
+}
+
+// Write the compact table's bucket infos
+juint* CompactHashtableWriter::dump_table(juint* p, juint** first_bucket,
+                                          NumberSeq* summary) {
+  int index;
+  juint* compact_table = p;
+  // Find the start of the buckets, skip the compact_bucket_infos table
+  // and the table end offset.
+  juint offset = _num_buckets + 1;
+  *first_bucket = compact_table + offset;
+
+  for (index = 0; index < _num_buckets; index++) {
+    int bucket_size = _bucket_sizes[index];
+    if (bucket_size == 1) {
+      // bucket with one entry is compacted and only has the symbol offset
+      compact_table[index] = BUCKET_INFO(offset, COMPACT_BUCKET_TYPE);
+      offset += bucket_size; // each entry contains symbol offset only
+    } else {
+      // regular bucket, each entry is a symbol (hash, offset) pair
+      compact_table[index] = BUCKET_INFO(offset, REGULAR_BUCKET_TYPE);
+      offset += bucket_size * 2; // each hash entry is 2 juints
+    }
+    if (offset & ~BUCKET_OFFSET_MASK) {
+      vm_exit_during_initialization("CompactHashtableWriter::dump_table: Overflow! "
+                                    "Too many symbols.");
+    }
+    summary->add(bucket_size);
+  }
+  // Mark the end of the table
+  compact_table[_num_buckets] = BUCKET_INFO(offset, TABLEEND_BUCKET_TYPE);
+
+  return compact_table;
+}
+
+// Write the compact table's entries
+juint* CompactHashtableWriter::dump_buckets(juint* compact_table, juint* p,
+                                            NumberSeq* summary) {
+  uintx base_address = uintx(MetaspaceShared::shared_rs()->base());
+  uintx max_delta    = uintx(MetaspaceShared::shared_rs()->size());
+  assert(max_delta <= 0x7fffffff, "range check");
+  int num_compact_buckets = 0;
+
+  assert(p != NULL, "sanity");
+  for (int index = 0; index < _num_buckets; index++) {
+    juint count = 0;
+    int bucket_size = _bucket_sizes[index];
+    int bucket_type = BUCKET_TYPE(compact_table[index]);
+
+    if (bucket_size == 1) {
+      assert(bucket_type == COMPACT_BUCKET_TYPE, "Bad bucket type");
+      num_compact_buckets ++;
+    }
+    for (Entry* tent = _buckets[index]; tent;
+         tent = tent->next()) {
+      if (bucket_type == REGULAR_BUCKET_TYPE) {
+        *p++ = juint(tent->hash()); // write symbol hash
+      }
+      uintx deltax = uintx(tent->value()) - base_address;
+      assert(deltax < max_delta, "range check");
+      juint delta = juint(deltax);
+      *p++ = delta; // write symbol offset
+      count ++;
+    }
+    assert(count == _bucket_sizes[index], "sanity");
+  }
+
+  // Adjust the hashentry_bytes in CompactHashtableStats. Each compact
+  // bucket saves 4-byte.
+  _stats->hashentry_bytes -= num_compact_buckets * 4;
+
+  return p;
+}
+
+// Write the compact table
+void CompactHashtableWriter::dump(char** top, char* end) {
+  NumberSeq summary;
+  char* old_top = *top;
+  juint* p = (juint*)(*top);
+
+  uintx base_address = uintx(MetaspaceShared::shared_rs()->base());
+
+  *p++ = high(base_address);
+  *p++ = low (base_address); // base address
+  *p++ = _num_entries;  // number of entries in the table
+  *p++ = _num_buckets;  // number of buckets in the table
+
+  juint* first_bucket = NULL;
+  juint* compact_table = dump_table(p, &first_bucket, &summary);
+  juint* bucket_end = dump_buckets(compact_table, first_bucket, &summary);
+
+  assert(bucket_end <= (juint*)end, "cannot write past end");
+  *top = (char*)bucket_end;
+
+  if (PrintSharedSpaces) {
+    double avg_cost = 0.0;
+    if (_num_entries > 0) {
+      avg_cost = double(_required_bytes)/double(_num_entries);
+    }
+    tty->print_cr("Shared %s table stats -------- base: " PTR_FORMAT, _table_name, (intptr_t)base_address);
+    tty->print_cr("Number of entries       : %9d", _num_entries);
+    tty->print_cr("Total bytes used        : %9d", (int)((*top) - old_top));
+    tty->print_cr("Average bytes per entry : %9.3f", avg_cost);
+    tty->print_cr("Average bucket size     : %9.3f", summary.avg());
+    tty->print_cr("Variance of bucket size : %9.3f", summary.variance());
+    tty->print_cr("Std. dev. of bucket size: %9.3f", summary.sd());
+    tty->print_cr("Maximum bucket size     : %9d", (int)summary.maximum());
+  }
+}
+
+/////////////////////////////////////////////////////////////
+//
+// The CompactHashtable implementation
+//
+template <class T, class N> const char* CompactHashtable<T, N>::init(const char* buffer) {
+  assert(!DumpSharedSpaces, "run-time only");
+  juint*p = (juint*)buffer;
+  juint upper = *p++;
+  juint lower = *p++;
+  _base_address = uintx(jlong_from(upper, lower));
+  _entry_count = *p++;
+  _bucket_count = *p++;
+  _buckets = p;
+  _table_end_offset = BUCKET_OFFSET(p[_bucket_count]); // located at the end of the bucket_info table
+
+  juint *end = _buckets + _table_end_offset;
+  return (const char*)end;
+}
+
+// Explicitly instantiate these types
+template class CompactHashtable<Symbol*, char>;
+
+#ifndef O_BINARY       // if defined (Win32) use binary files.
+#define O_BINARY 0     // otherwise do nothing.
+#endif
+
+////////////////////////////////////////////////////////
+//
+// HashtableTextDump
+//
+HashtableTextDump::HashtableTextDump(const char* filename) : _fd(-1) {
+  struct stat st;
+  if (os::stat(filename, &st) != 0) {
+    quit("Unable to get hashtable dump file size", filename);
+  }
+  _size = st.st_size;
+  _fd = open(filename, O_RDONLY | O_BINARY, 0);
+  if (_fd < 0) {
+    quit("Unable to open hashtable dump file", filename);
+  }
+  _base = os::map_memory(_fd, filename, 0, NULL, _size, true, false);
+  if (_base == NULL) {
+    quit("Unable to map hashtable dump file", filename);
+  }
+  _p = _base;
+  _end = _base + st.st_size;
+  _filename = filename;
+}
+
+HashtableTextDump::~HashtableTextDump() {
+  os::unmap_memory((char*)_base, _size);
+  if (_fd >= 0) {
+    close(_fd);
+  }
+}
+
+void HashtableTextDump::quit(const char* err, const char* msg) {
+  vm_exit_during_initialization(err, msg);
+}
+
+void HashtableTextDump::corrupted(const char *p) {
+  char info[60];
+  sprintf(info, "corrupted at pos %d", (int)(p - _base));
+  quit(info, _filename);
+}
+
+bool HashtableTextDump::skip_newline() {
+  if (_p[0] == '\r' && _p[1] == '\n') {
+    _p += 2;
+  } else if (_p[0] == '\n') {
+    _p += 1;
+  } else {
+    corrupted(_p);
+  }
+  return true;
+}
+
+int HashtableTextDump::skip(char must_be_char) {
+  corrupted_if(remain() < 1);
+  corrupted_if(*_p++ != must_be_char);
+  return 0;
+}
+
+void HashtableTextDump::skip_past(char c) {
+  for (;;) {
+    corrupted_if(remain() < 1);
+    if (*_p++ == c) {
+      return;
+    }
+  }
+}
+
+void HashtableTextDump::check_version(const char* ver) {
+  int len = (int)strlen(ver);
+  corrupted_if(remain() < len);
+  if (strncmp(_p, ver, len) != 0) {
+    quit("wrong version of hashtable dump file", _filename);
+  }
+  _p += len;
+  skip_newline();
+}
+
+
+int HashtableTextDump::scan_prefix() {
+  // Expect /[0-9]+: /
+  int utf8_length = get_num(':');
+  if (*_p != ' ') {
+    corrupted(_p);
+  }
+  _p++;
+  return utf8_length;
+}
+
+int HashtableTextDump::scan_prefix2() {
+  // Expect /[0-9]+ (-|)[0-9]+: /
+  int utf8_length = get_num(' ');
+  if (*_p == '-') {
+    _p++;
+  }
+  (void)get_num(':');
+  if (*_p != ' ') {
+    corrupted(_p);
+  }
+  _p++;
+  return utf8_length;
+}
+
+jchar HashtableTextDump::unescape(const char* from, const char* end, int count) {
+  jchar value = 0;
+
+  corrupted_if(from + count > end);
+
+  for (int i=0; i<count; i++) {
+    char c = *from++;
+    switch (c) {
+    case '0': case '1': case '2': case '3': case '4':
+    case '5': case '6': case '7': case '8': case '9':
+      value = (value << 4) + c - '0';
+      break;
+    case 'a': case 'b': case 'c':
+    case 'd': case 'e': case 'f':
+      value = (value << 4) + 10 + c - 'a';
+      break;
+    case 'A': case 'B': case 'C':
+    case 'D': case 'E': case 'F':
+      value = (value << 4) + 10 + c - 'A';
+      break;
+    default:
+      ShouldNotReachHere();
+    }
+  }
+  return value;
+}
+
+void HashtableTextDump::get_utf8(char* utf8_buffer, int utf8_length) {
+  // cache in local vars
+  const char* from = _p;
+  const char* end = _end;
+  char* to = utf8_buffer;
+  int n = utf8_length;
+
+  for (; n > 0 && from < end; n--) {
+    if (*from != '\\') {
+      *to++ = *from++;
+    } else {
+      corrupted_if(from + 2 > end);
+      char c = from[1];
+      from += 2;
+      switch (c) {
+      case 'x':
+        {
+          jchar value = unescape(from, end, 2);
+          from += 2;
+          assert(value <= 0xff, "sanity");
+          *to++ = (char)(value & 0xff);
+        }
+        break;
+      case 't':  *to++ = '\t'; break;
+      case 'n':  *to++ = '\n'; break;
+      case 'r':  *to++ = '\r'; break;
+      case '\\': *to++ = '\\'; break;
+      default:
+        ShouldNotReachHere();
+      }
+    }
+  }
+  corrupted_if(n > 0); // expected more chars but file has ended
+  _p = from;
+  skip_newline();
+}
+
+// NOTE: the content is NOT the same as
+// UTF8::as_quoted_ascii(const char* utf8_str, int utf8_length, char* buf, int buflen).
+// We want to escape \r\n\t so that output [1] is more readable; [2] can be more easily
+// parsed by scripts; [3] quickly processed by HashtableTextDump::get_utf8()
+void HashtableTextDump::put_utf8(outputStream* st, const char* utf8_string, int utf8_length) {
+  const char *c = utf8_string;
+  const char *end = c + utf8_length;
+  for (; c < end; c++) {
+    switch (*c) {
+    case '\t': st->print("\\t"); break;
+    case '\r': st->print("\\r"); break;
+    case '\n': st->print("\\n"); break;
+    case '\\': st->print("\\\\"); break;
+    default:
+      if (isprint(*c)) {
+        st->print("%c", *c);
+      } else {
+        st->print("\\x%02x", ((unsigned int)*c) & 0xff);
+      }
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/classfile/compactHashtable.hpp	Fri Jan 09 13:28:02 2015 -0500
@@ -0,0 +1,405 @@
+/*
+ * 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
+ * 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_CLASSFILE_COMPACTHASHTABLE_HPP
+#define SHARE_VM_CLASSFILE_COMPACTHASHTABLE_HPP
+
+#include "classfile/stringTable.hpp"
+#include "classfile/symbolTable.hpp"
+#include "memory/allocation.inline.hpp"
+#include "oops/symbol.hpp"
+#include "services/diagnosticCommand.hpp"
+#include "utilities/hashtable.hpp"
+
+class NumberSeq;
+
+// Stats for symbol tables in the CDS archive
+class CompactHashtableStats VALUE_OBJ_CLASS_SPEC {
+public:
+  int hashentry_count;
+  int hashentry_bytes;
+  int bucket_count;
+  int bucket_bytes;
+};
+
+/////////////////////////////////////////////////////////////////////////
+//
+// The compact hash table writer. Used at dump time for writing out
+// the compact table to the shared archive.
+//
+// At dump time, the CompactHashtableWriter obtains all entries from the
+// symbol table and adds them to a new temporary hash table. The hash
+// table size (number of buckets) is calculated using
+// '(num_entries + bucket_size - 1) / bucket_size'. The default bucket
+// size is 4 and can be changed by -XX:SharedSymbolTableBucketSize option.
+// 4 is chosen because it produces smaller sized bucket on average for
+// faster lookup. It also has relatively small number of empty buckets and
+// good distribution of the entries.
+//
+// We use a simple hash function (symbol_hash % num_bucket) for the table.
+// The new table is compacted when written out. Please see comments
+// above the CompactHashtable class for the table layout detail. The bucket
+// offsets are written to the archive as part of the compact table. The
+// bucket offset is encoded in the low 30-bit (0-29) and the bucket type
+// (regular or compact) are encoded in bit[31, 30]. For buckets with more
+// than one entry, both symbol hash and symbol offset are written to the
+// table. For buckets with only one entry, only the symbol offset is written
+// to the table and the buckets are tagged as compact in their type bits.
+// Buckets without entry are skipped from the table. Their offsets are
+// still written out for faster lookup.
+//
+class CompactHashtableWriter: public StackObj {
+public:
+  class Entry: public CHeapObj<mtSymbol> {
+    Entry* _next;
+    unsigned int _hash;
+    void* _literal;
+
+  public:
+    Entry(unsigned int hash, Symbol *symbol) : _next(NULL), _hash(hash), _literal(symbol) {}
+
+    void *value() {
+      return _literal;
+    }
+    Symbol *symbol() {
+      return (Symbol*)_literal;
+    }
+    unsigned int hash() {
+      return _hash;
+    }
+    Entry *next()           {return _next;}
+    void set_next(Entry *p) {_next = p;}
+  }; // class CompactHashtableWriter::Entry
+
+private:
+  static int number_of_buckets(int num_entries);
+
+  const char* _table_name;
+  int _num_entries;
+  int _num_buckets;
+  juint* _bucket_sizes;
+  Entry** _buckets;
+  int _required_bytes;
+  CompactHashtableStats* _stats;
+
+public:
+  // This is called at dump-time only
+  CompactHashtableWriter(const char* table_name, int num_entries, CompactHashtableStats* stats);
+  ~CompactHashtableWriter();
+
+  int get_required_bytes() {
+    return _required_bytes;
+  }
+
+  void add(unsigned int hash, Symbol* symbol) {
+    add(hash, new Entry(hash, symbol));
+  }
+
+private:
+  void add(unsigned int hash, Entry* entry);
+  juint* dump_table(juint* p, juint** first_bucket, NumberSeq* summary);
+  juint* dump_buckets(juint* table, juint* p, NumberSeq* summary);
+
+public:
+  void dump(char** top, char* end);
+};
+
+#define REGULAR_BUCKET_TYPE       0
+#define COMPACT_BUCKET_TYPE       1
+#define TABLEEND_BUCKET_TYPE      3
+#define BUCKET_OFFSET_MASK        0x3FFFFFFF
+#define BUCKET_OFFSET(info)       ((info) & BUCKET_OFFSET_MASK)
+#define BUCKET_TYPE_SHIFT         30
+#define BUCKET_TYPE(info)         (((info) & ~BUCKET_OFFSET_MASK) >> BUCKET_TYPE_SHIFT)
+#define BUCKET_INFO(offset, type) (((type) << BUCKET_TYPE_SHIFT) | ((offset) & BUCKET_OFFSET_MASK))
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// CompactHashtable is used to stored the CDS archive's symbol table. Used
+// at runtime only to access the compact table from the archive.
+//
+// Because these tables are read-only (no entries can be added/deleted) at run-time
+// and tend to have large number of entries, we try to minimize the footprint
+// cost per entry.
+//
+// Layout of compact symbol table in the shared archive:
+//
+//   uintx base_address;
+//   juint num_symbols;
+//   juint num_buckets;
+//   juint bucket_infos[num_buckets+1]; // bit[31,30]: type; bit[29-0]: offset
+//   juint table[]
+//
+// -----------------------------------
+// | base_address  | num_symbols     |
+// |---------------------------------|
+// | num_buckets   | bucket_info0    |
+// |---------------------------------|
+// | bucket_info1  | bucket_info2    |
+// | bucket_info3    ...             |
+// | ....          | table_end_info  |
+// |---------------------------------|
+// | entry0                          |
+// | entry1                          |
+// | entry2                          |
+// |                                 |
+// | ...                             |
+// -----------------------------------
+//
+// The size of the bucket_info table is 'num_buckets + 1'. Each entry of the
+// bucket_info table is a 32-bit encoding of the bucket type and bucket offset,
+// with the type in the left-most 2-bit and offset in the remaining 30-bit.
+// The last entry is a special type. It contains the offset of the last
+// bucket end. We use that information when traversing the compact table.
+//
+// There are two types of buckets, regular buckets and compact buckets. The
+// compact buckets have '01' in their highest 2-bit, and regular buckets have
+// '00' in their highest 2-bit.
+//
+// For normal buckets, each symbol's entry is 8 bytes in the table[]:
+//   juint hash;    /* symbol hash */
+//   juint offset;  /* Symbol* sym = (Symbol*)(base_address + offset) */
+//
+// For compact buckets, each entry has only the 4-byte 'offset' in the table[].
+//
+// See CompactHashtable::lookup() for how the table is searched at runtime.
+// See CompactHashtableWriter::dump() for how the table is written at CDS
+// dump time.
+//
+template <class T, class N> class CompactHashtable VALUE_OBJ_CLASS_SPEC {
+  uintx  _base_address;
+  juint  _entry_count;
+  juint  _bucket_count;
+  juint  _table_end_offset;
+  juint* _buckets;
+
+  inline bool equals(T entry, const char* name, int len) {
+    if (entry->equals(name, len)) {
+      assert(entry->refcount() == -1, "must be shared");
+      return true;
+    } else {
+      return false;
+    }
+  }
+
+public:
+  CompactHashtable() {
+    _entry_count = 0;
+    _bucket_count = 0;
+    _table_end_offset = 0;
+    _buckets = 0;
+  }
+  const char* init(const char *buffer);
+
+  // Lookup an entry from the compact table
+  inline T lookup(const N* name, unsigned int hash, int len) {
+    if (_entry_count > 0) {
+      assert(!DumpSharedSpaces, "run-time only");
+      int index = hash % _bucket_count;
+      juint bucket_info = _buckets[index];
+      juint bucket_offset = BUCKET_OFFSET(bucket_info);
+      int   bucket_type = BUCKET_TYPE(bucket_info);
+      juint* bucket = _buckets + bucket_offset;
+      juint* bucket_end = _buckets;
+
+      if (bucket_type == COMPACT_BUCKET_TYPE) {
+        // the compact bucket has one entry with symbol offset only
+        T entry = (T)((void*)(_base_address + bucket[0]));
+        if (equals(entry, name, len)) {
+          return entry;
+        }
+      } else {
+        // This is a regular bucket, which has more than one
+        // entries. Each entry is a pair of symbol (hash, offset).
+        // Seek until the end of the bucket.
+        bucket_end += BUCKET_OFFSET(_buckets[index + 1]);
+        while (bucket < bucket_end) {
+          unsigned int h = (unsigned int)(bucket[0]);
+          if (h == hash) {
+            juint offset = bucket[1];
+            T entry = (T)((void*)(_base_address + offset));
+            if (equals(entry, name, len)) {
+              return entry;
+            }
+          }
+          bucket += 2;
+        }
+      }
+    }
+    return NULL;
+  }
+};
+
+////////////////////////////////////////////////////////////////////////
+//
+// Read/Write the contents of a hashtable textual dump (created by
+// SymbolTable::dump).
+// Because the dump file may be big (hundred of MB in extreme cases),
+// we use mmap for fast access when reading it.
+//
+class HashtableTextDump VALUE_OBJ_CLASS_SPEC {
+  int _fd;
+  const char* _base;
+  const char* _p;
+  const char* _end;
+  const char* _filename;
+  size_t      _size;
+public:
+  HashtableTextDump(const char* filename);
+  ~HashtableTextDump();
+
+  void quit(const char* err, const char* msg);
+
+  inline int remain() {
+    return (int)(_end - _p);
+  }
+
+  void corrupted(const char *p);
+
+  inline void corrupted_if(bool cond) {
+    if (cond) {
+      corrupted(_p);
+    }
+  }
+
+  bool skip_newline();
+  int skip(char must_be_char);
+  void skip_past(char c);
+  void check_version(const char* ver);
+
+  inline int get_num(char delim) {
+    const char* p   = _p;
+    const char* end = _end;
+    int num = 0;
+
+    while (p < end) {
+      char c = *p ++;
+      if ('0' <= c && c <= '9') {
+        num = num * 10 + (c - '0');
+      } else if (c == delim) {
+        _p = p;
+        return num;
+      } else {
+        corrupted(p-1);
+      }
+    }
+    corrupted(_end);
+    ShouldNotReachHere();
+    return 0;
+  }
+
+  int scan_prefix();
+  int scan_prefix2();
+
+  jchar unescape(const char* from, const char* end, int count);
+  void get_utf8(char* utf8_buffer, int utf8_length);
+  static void put_utf8(outputStream* st, const char* utf8_string, int utf8_length);
+};
+
+///////////////////////////////////////////////////////////////////////
+//
+// jcmd command support for symbol table and string table dumping:
+//   VM.symboltable -verbose: for dumping the symbol table
+//   VM.stringtable -verbose: for dumping the string table
+//
+class VM_DumpHashtable : public VM_Operation {
+private:
+  outputStream* _out;
+  int _which;
+  bool _verbose;
+public:
+  enum {
+    DumpSymbols = 1 << 0,
+    DumpStrings = 1 << 1,
+    DumpSysDict = 1 << 2  // not implemented yet
+  };
+  VM_DumpHashtable(outputStream* out, int which, bool verbose) {
+    _out = out;
+    _which = which;
+    _verbose = verbose;
+  }
+
+  virtual VMOp_Type type() const { return VMOp_DumpHashtable; }
+
+  virtual void doit() {
+    switch (_which) {
+    case DumpSymbols:
+      SymbolTable::dump(_out, _verbose);
+      break;
+    case DumpStrings:
+      StringTable::dump(_out, _verbose);
+      break;
+    default:
+      ShouldNotReachHere();
+    }
+  }
+};
+
+class SymboltableDCmd : public DCmdWithParser {
+protected:
+  DCmdArgument<bool> _verbose;
+public:
+  SymboltableDCmd(outputStream* output, bool heap);
+  static const char* name() {
+    return "VM.symboltable";
+  }
+  static const char* description() {
+    return "Dump symbol table.";
+  }
+  static const char* impact() {
+    return "Medium: Depends on Java content.";
+  }
+  static const JavaPermission permission() {
+    JavaPermission p = {"java.lang.management.ManagementPermission",
+                        "monitor", NULL};
+    return p;
+  }
+  static int num_arguments();
+  virtual void execute(DCmdSource source, TRAPS);
+};
+
+class StringtableDCmd : public DCmdWithParser {
+protected:
+  DCmdArgument<bool> _verbose;
+public:
+  StringtableDCmd(outputStream* output, bool heap);
+  static const char* name() {
+    return "VM.stringtable";
+  }
+  static const char* description() {
+    return "Dump string table.";
+  }
+  static const char* impact() {
+    return "Medium: Depends on Java content.";
+  }
+  static const JavaPermission permission() {
+    JavaPermission p = {"java.lang.management.ManagementPermission",
+                        "monitor", NULL};
+    return p;
+  }
+  static int num_arguments();
+  virtual void execute(DCmdSource source, TRAPS);
+};
+
+#endif // SHARE_VM_CLASSFILE_COMPACTHASHTABLE_HPP
--- a/hotspot/src/share/vm/classfile/stringTable.cpp	Fri Jan 09 05:45:13 2015 -0800
+++ b/hotspot/src/share/vm/classfile/stringTable.cpp	Fri Jan 09 13:28:02 2015 -0500
@@ -24,6 +24,7 @@
 
 #include "precompiled.hpp"
 #include "classfile/altHashing.hpp"
+#include "classfile/compactHashtable.hpp"
 #include "classfile/javaClasses.hpp"
 #include "classfile/stringTable.hpp"
 #include "classfile/systemDictionary.hpp"
@@ -379,8 +380,36 @@
   }
 }
 
-void StringTable::dump(outputStream* st) {
-  the_table()->dump_table(st, "StringTable");
+void StringTable::dump(outputStream* st, bool verbose) {
+  if (!verbose) {
+    the_table()->dump_table(st, "StringTable");
+  } else {
+    Thread* THREAD = Thread::current();
+    st->print_cr("VERSION: 1.1");
+    for (int i = 0; i < the_table()->table_size(); ++i) {
+      HashtableEntry<oop, mtSymbol>* p = the_table()->bucket(i);
+      for ( ; p != NULL; p = p->next()) {
+        oop s = p->literal();
+        typeArrayOop value  = java_lang_String::value(s);
+        int          offset = java_lang_String::offset(s);
+        int          length = java_lang_String::length(s);
+
+        if (length <= 0) {
+          st->print("%d: ", length);
+        } else {
+          ResourceMark rm(THREAD);
+          jchar* chars = (jchar*)value->char_at_addr(offset);
+          int utf8_length = UNICODE::utf8_length(chars, length);
+          char* utf8_string = NEW_RESOURCE_ARRAY(char, utf8_length + 1);
+          UNICODE::convert_to_utf8(chars, length, utf8_string);
+
+          st->print("%d: ", utf8_length);
+          HashtableTextDump::put_utf8(st, utf8_string, utf8_length);
+        }
+        st->cr();
+      }
+    }
+  }
 }
 
 StringTable::VerifyRetTypes StringTable::compare_entries(
@@ -558,3 +587,28 @@
   _needs_rehashing = false;
   _the_table = new_table;
 }
+
+// Utility for dumping strings
+StringtableDCmd::StringtableDCmd(outputStream* output, bool heap) :
+                                 DCmdWithParser(output, heap),
+  _verbose("-verbose", "Dump the content of each string in the table",
+           "BOOLEAN", false, "false") {
+  _dcmdparser.add_dcmd_option(&_verbose);
+}
+
+void StringtableDCmd::execute(DCmdSource source, TRAPS) {
+  VM_DumpHashtable dumper(output(), VM_DumpHashtable::DumpStrings,
+                         _verbose.value());
+  VMThread::execute(&dumper);
+}
+
+int StringtableDCmd::num_arguments() {
+  ResourceMark rm;
+  StringtableDCmd* dcmd = new StringtableDCmd(NULL, false);
+  if (dcmd != NULL) {
+    DCmdMark mark(dcmd);
+    return dcmd->_dcmdparser.num_arguments();
+  } else {
+    return 0;
+  }
+}
--- a/hotspot/src/share/vm/classfile/stringTable.hpp	Fri Jan 09 05:45:13 2015 -0800
+++ b/hotspot/src/share/vm/classfile/stringTable.hpp	Fri Jan 09 13:28:02 2015 -0500
@@ -118,7 +118,7 @@
 
   // Debugging
   static void verify();
-  static void dump(outputStream* st);
+  static void dump(outputStream* st, bool verbose=false);
 
   enum VerifyMesgModes {
     _verify_quietly    = 0,
--- a/hotspot/src/share/vm/classfile/symbolTable.cpp	Fri Jan 09 05:45:13 2015 -0800
+++ b/hotspot/src/share/vm/classfile/symbolTable.cpp	Fri Jan 09 13:28:02 2015 -0500
@@ -24,6 +24,7 @@
 
 #include "precompiled.hpp"
 #include "classfile/altHashing.hpp"
+#include "classfile/compactHashtable.hpp"
 #include "classfile/javaClasses.hpp"
 #include "classfile/symbolTable.hpp"
 #include "classfile/systemDictionary.hpp"
@@ -47,6 +48,9 @@
 // Static arena for symbols that are not deallocated
 Arena* SymbolTable::_arena = NULL;
 bool SymbolTable::_needs_rehashing = false;
+bool SymbolTable::_lookup_shared_first = false;
+
+CompactHashtable<Symbol*, char> SymbolTable::_shared_table;
 
 Symbol* SymbolTable::allocate_symbol(const u1* name, int len, bool c_heap, TRAPS) {
   assert (len <= Symbol::max_length(), "should be checked by caller");
@@ -186,8 +190,8 @@
 
 // Lookup a symbol in a bucket.
 
-Symbol* SymbolTable::lookup(int index, const char* name,
-                              int len, unsigned int hash) {
+Symbol* SymbolTable::lookup_dynamic(int index, const char* name,
+                                    int len, unsigned int hash) {
   int count = 0;
   for (HashtableEntry<Symbol*, mtSymbol>* e = bucket(index); e != NULL; e = e->next()) {
     count++;  // count all entries in this bucket, not just ones with same hash
@@ -207,6 +211,34 @@
   return NULL;
 }
 
+Symbol* SymbolTable::lookup_shared(const char* name,
+                                   int len, unsigned int hash) {
+  return _shared_table.lookup(name, hash, len);
+}
+
+Symbol* SymbolTable::lookup(int index, const char* name,
+                            int len, unsigned int hash) {
+  Symbol* sym;
+  if (_lookup_shared_first) {
+    sym = lookup_shared(name, len, hash);
+    if (sym != NULL) {
+      return sym;
+    }
+    _lookup_shared_first = false;
+    return lookup_dynamic(index, name, len, hash);
+  } else {
+    sym = lookup_dynamic(index, name, len, hash);
+    if (sym != NULL) {
+      return sym;
+    }
+    sym = lookup_shared(name, len, hash);
+    if (sym != NULL) {
+      _lookup_shared_first = true;
+    }
+    return sym;
+  }
+}
+
 // Pick hashing algorithm.
 unsigned int SymbolTable::hash_symbol(const char* s, int len) {
   return use_alternate_hashcode() ?
@@ -483,10 +515,56 @@
   }
 }
 
-void SymbolTable::dump(outputStream* st) {
-  the_table()->dump_table(st, "SymbolTable");
+void SymbolTable::dump(outputStream* st, bool verbose) {
+  if (!verbose) {
+    the_table()->dump_table(st, "SymbolTable");
+  } else {
+    st->print_cr("VERSION: 1.0");
+    for (int i = 0; i < the_table()->table_size(); ++i) {
+      HashtableEntry<Symbol*, mtSymbol>* p = the_table()->bucket(i);
+      for ( ; p != NULL; p = p->next()) {
+        Symbol* s = (Symbol*)(p->literal());
+        const char* utf8_string = (const char*)s->bytes();
+        int utf8_length = s->utf8_length();
+        st->print("%d %d: ", utf8_length, s->refcount());
+        HashtableTextDump::put_utf8(st, utf8_string, utf8_length);
+        st->cr();
+      }
+    }
+  }
 }
 
+bool SymbolTable::copy_compact_table(char** top, char*end) {
+#if INCLUDE_CDS
+  CompactHashtableWriter ch_table("symbol", the_table()->number_of_entries(),
+                                  &MetaspaceShared::stats()->symbol);
+  if (*top + ch_table.get_required_bytes() > end) {
+    // not enough space left
+    return false;
+  }
+
+  for (int i = 0; i < the_table()->table_size(); ++i) {
+    HashtableEntry<Symbol*, mtSymbol>* p = the_table()->bucket(i);
+    for ( ; p != NULL; p = p->next()) {
+      Symbol* s = (Symbol*)(p->literal());
+      unsigned int fixed_hash = hash_symbol((char*)s->bytes(), s->utf8_length());
+      assert(fixed_hash == p->hash(), "must not rehash during dumping");
+      ch_table.add(fixed_hash, s);
+    }
+  }
+
+  char* old_top = *top;
+  ch_table.dump(top, end);
+
+  *top = (char*)align_pointer_up(*top, sizeof(void*));
+#endif
+  return true;
+}
+
+const char* SymbolTable::init_shared_table(const char* buffer) {
+  const char* end = _shared_table.init(buffer);
+  return (const char*)align_pointer_up(end, sizeof(void*));
+}
 
 //---------------------------------------------------------------------------
 // Non-product code
@@ -574,3 +652,29 @@
   }
 }
 #endif // PRODUCT
+
+
+// Utility for dumping symbols
+SymboltableDCmd::SymboltableDCmd(outputStream* output, bool heap) :
+                                 DCmdWithParser(output, heap),
+  _verbose("-verbose", "Dump the content of each symbol in the table",
+           "BOOLEAN", false, "false") {
+  _dcmdparser.add_dcmd_option(&_verbose);
+}
+
+void SymboltableDCmd::execute(DCmdSource source, TRAPS) {
+  VM_DumpHashtable dumper(output(), VM_DumpHashtable::DumpSymbols,
+                         _verbose.value());
+  VMThread::execute(&dumper);
+}
+
+int SymboltableDCmd::num_arguments() {
+  ResourceMark rm;
+  SymboltableDCmd* dcmd = new SymboltableDCmd(NULL, false);
+  if (dcmd != NULL) {
+    DCmdMark mark(dcmd);
+    return dcmd->_dcmdparser.num_arguments();
+  } else {
+    return 0;
+  }
+}
--- a/hotspot/src/share/vm/classfile/symbolTable.hpp	Fri Jan 09 05:45:13 2015 -0800
+++ b/hotspot/src/share/vm/classfile/symbolTable.hpp	Fri Jan 09 13:28:02 2015 -0500
@@ -73,6 +73,8 @@
   operator Symbol*()                             { return _temp; }
 };
 
+template <class T, class N> class CompactHashtable;
+
 class SymbolTable : public RehashableHashtable<Symbol*, mtSymbol> {
   friend class VMStructs;
   friend class ClassFileParser;
@@ -83,11 +85,15 @@
 
   // Set if one bucket is out of balance due to hash algorithm deficiency
   static bool _needs_rehashing;
+  static bool _lookup_shared_first;
 
   // For statistics
   static int _symbols_removed;
   static int _symbols_counted;
 
+  // shared symbol table.
+  static CompactHashtable<Symbol*, char> _shared_table;
+
   Symbol* allocate_symbol(const u1* name, int len, bool c_heap, TRAPS); // Assumes no characters larger than 0x7F
 
   // Adding elements
@@ -106,6 +112,8 @@
     add(loader_data, cp, names_count, name, lengths, cp_indices, hashValues, THREAD);
   }
 
+  static Symbol* lookup_shared(const char* name, int len, unsigned int hash);
+  Symbol* lookup_dynamic(int index, const char* name, int len, unsigned int hash);
   Symbol* lookup(int index, const char* name, int len, unsigned int hash);
 
   SymbolTable()
@@ -144,20 +152,6 @@
     initialize_symbols(symbol_alloc_arena_size);
   }
 
-  static void create_table(HashtableBucket<mtSymbol>* t, int length,
-                           int number_of_entries) {
-    assert(_the_table == NULL, "One symbol table allowed.");
-
-    // If CDS archive used a different symbol table size, use that size instead
-    // which is better than giving an error.
-    SymbolTableSize = length/bucket_size();
-
-    _the_table = new SymbolTable(t, number_of_entries);
-    // if CDS give symbol table a default arena size since most symbols
-    // are already allocated in the shared misc section.
-    initialize_symbols();
-  }
-
   static unsigned int hash_symbol(const char* s, int len);
 
   static Symbol* lookup(const char* name, int len, TRAPS);
@@ -230,18 +224,12 @@
 
   // Debugging
   static void verify();
-  static void dump(outputStream* st);
+  static void dump(outputStream* st, bool verbose=false);
+  static void read(const char* filename, TRAPS);
 
   // Sharing
-  static void copy_buckets(char** top, char*end) {
-    the_table()->Hashtable<Symbol*, mtSymbol>::copy_buckets(top, end);
-  }
-  static void copy_table(char** top, char*end) {
-    the_table()->Hashtable<Symbol*, mtSymbol>::copy_table(top, end);
-  }
-  static void reverse(void* boundary = NULL) {
-    the_table()->Hashtable<Symbol*, mtSymbol>::reverse(boundary);
-  }
+  static bool copy_compact_table(char** top, char* end);
+  static const char* init_shared_table(const char* buffer);
 
   // Rehash the symbol table if it gets out of balance
   static void rehash_table();
--- a/hotspot/src/share/vm/classfile/systemDictionary.cpp	Fri Jan 09 05:45:13 2015 -0800
+++ b/hotspot/src/share/vm/classfile/systemDictionary.cpp	Fri Jan 09 13:28:02 2015 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -32,6 +32,7 @@
 #include "classfile/stringTable.hpp"
 #include "classfile/systemDictionary.hpp"
 #include "classfile/vmSymbols.hpp"
+#include "code/codeCache.hpp"
 #include "compiler/compileBroker.hpp"
 #include "interpreter/bytecodeStream.hpp"
 #include "interpreter/interpreter.hpp"
@@ -1627,7 +1628,7 @@
   // Note: must be done *after* linking k into the hierarchy (was bug 12/9/97)
   // Also, first reinitialize vtable because it may have gotten out of synch
   // while the new class wasn't connected to the class hierarchy.
-  Universe::flush_dependents_on(k);
+  CodeCache::flush_dependents_on(k);
 }
 
 // ----------------------------------------------------------------------------
--- a/hotspot/src/share/vm/classfile/verifier.cpp	Fri Jan 09 05:45:13 2015 -0800
+++ b/hotspot/src/share/vm/classfile/verifier.cpp	Fri Jan 09 13:28:02 2015 -0500
@@ -2477,8 +2477,7 @@
     // of the current class.
     VerificationType objectref_type = new_class_type;
     if (name_in_supers(ref_class_type.name(), current_class())) {
-      Klass* ref_klass = load_class(
-        ref_class_type.name(), CHECK_VERIFY(this));
+      Klass* ref_klass = load_class(ref_class_type.name(), CHECK);
       Method* m = InstanceKlass::cast(ref_klass)->uncached_lookup_method(
         vmSymbols::object_initializer_name(),
         cp->signature_ref_at(bcs->get_index_u2()),
--- a/hotspot/src/share/vm/code/codeCache.cpp	Fri Jan 09 05:45:13 2015 -0800
+++ b/hotspot/src/share/vm/code/codeCache.cpp	Fri Jan 09 13:28:02 2015 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -1005,6 +1005,117 @@
   }
 }
 
+// Flushes compiled methods dependent on dependee.
+void CodeCache::flush_dependents_on(instanceKlassHandle dependee) {
+  assert_lock_strong(Compile_lock);
+
+  if (number_of_nmethods_with_dependencies() == 0) return;
+
+  // CodeCache can only be updated by a thread_in_VM and they will all be
+  // stopped during the safepoint so CodeCache will be safe to update without
+  // holding the CodeCache_lock.
+
+  KlassDepChange changes(dependee);
+
+  // Compute the dependent nmethods
+  if (mark_for_deoptimization(changes) > 0) {
+    // At least one nmethod has been marked for deoptimization
+    VM_Deoptimize op;
+    VMThread::execute(&op);
+  }
+}
+
+// Flushes compiled methods dependent on a particular CallSite
+// instance when its target is different than the given MethodHandle.
+void CodeCache::flush_dependents_on(Handle call_site, Handle method_handle) {
+  assert_lock_strong(Compile_lock);
+
+  if (number_of_nmethods_with_dependencies() == 0) return;
+
+  // CodeCache can only be updated by a thread_in_VM and they will all be
+  // stopped during the safepoint so CodeCache will be safe to update without
+  // holding the CodeCache_lock.
+
+  CallSiteDepChange changes(call_site(), method_handle());
+
+  // Compute the dependent nmethods that have a reference to a
+  // CallSite object.  We use InstanceKlass::mark_dependent_nmethod
+  // directly instead of CodeCache::mark_for_deoptimization because we
+  // want dependents on the call site class only not all classes in
+  // the ContextStream.
+  int marked = 0;
+  {
+    MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
+    InstanceKlass* call_site_klass = InstanceKlass::cast(call_site->klass());
+    marked = call_site_klass->mark_dependent_nmethods(changes);
+  }
+  if (marked > 0) {
+    // At least one nmethod has been marked for deoptimization
+    VM_Deoptimize op;
+    VMThread::execute(&op);
+  }
+}
+
+#ifdef HOTSWAP
+// Flushes compiled methods dependent on dependee in the evolutionary sense
+void CodeCache::flush_evol_dependents_on(instanceKlassHandle ev_k_h) {
+  // --- Compile_lock is not held. However we are at a safepoint.
+  assert_locked_or_safepoint(Compile_lock);
+  if (number_of_nmethods_with_dependencies() == 0) return;
+
+  // CodeCache can only be updated by a thread_in_VM and they will all be
+  // stopped during the safepoint so CodeCache will be safe to update without
+  // holding the CodeCache_lock.
+
+  // Compute the dependent nmethods
+  if (mark_for_evol_deoptimization(ev_k_h) > 0) {
+    // At least one nmethod has been marked for deoptimization
+
+    // All this already happens inside a VM_Operation, so we'll do all the work here.
+    // Stuff copied from VM_Deoptimize and modified slightly.
+
+    // We do not want any GCs to happen while we are in the middle of this VM operation
+    ResourceMark rm;
+    DeoptimizationMarker dm;
+
+    // Deoptimize all activations depending on marked nmethods
+    Deoptimization::deoptimize_dependents();
+
+    // Make the dependent methods not entrant (in VM_Deoptimize they are made zombies)
+    make_marked_nmethods_not_entrant();
+  }
+}
+#endif // HOTSWAP
+
+
+// Flushes compiled methods dependent on dependee
+void CodeCache::flush_dependents_on_method(methodHandle m_h) {
+  // --- Compile_lock is not held. However we are at a safepoint.
+  assert_locked_or_safepoint(Compile_lock);
+
+  // CodeCache can only be updated by a thread_in_VM and they will all be
+  // stopped dring the safepoint so CodeCache will be safe to update without
+  // holding the CodeCache_lock.
+
+  // Compute the dependent nmethods
+  if (mark_for_deoptimization(m_h()) > 0) {
+    // At least one nmethod has been marked for deoptimization
+
+    // All this already happens inside a VM_Operation, so we'll do all the work here.
+    // Stuff copied from VM_Deoptimize and modified slightly.
+
+    // We do not want any GCs to happen while we are in the middle of this VM operation
+    ResourceMark rm;
+    DeoptimizationMarker dm;
+
+    // Deoptimize all activations depending on marked nmethods
+    Deoptimization::deoptimize_dependents();
+
+    // Make the dependent methods not entrant (in VM_Deoptimize they are made zombies)
+    make_marked_nmethods_not_entrant();
+  }
+}
+
 void CodeCache::verify() {
   assert_locked_or_safepoint(CodeCache_lock);
   FOR_ALL_HEAPS(heap) {
--- a/hotspot/src/share/vm/code/codeCache.hpp	Fri Jan 09 05:45:13 2015 -0800
+++ b/hotspot/src/share/vm/code/codeCache.hpp	Fri Jan 09 13:28:02 2015 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -209,16 +209,28 @@
   static void verify_icholder_relocations();
 
   // Deoptimization
+ private:
   static int  mark_for_deoptimization(DepChange& changes);
 #ifdef HOTSWAP
   static int  mark_for_evol_deoptimization(instanceKlassHandle dependee);
 #endif // HOTSWAP
 
+ public:
   static void mark_all_nmethods_for_deoptimization();
   static int  mark_for_deoptimization(Method* dependee);
   static void make_marked_nmethods_zombies();
   static void make_marked_nmethods_not_entrant();
 
+  // Flushing and deoptimization
+  static void flush_dependents_on(instanceKlassHandle dependee);
+  static void flush_dependents_on(Handle call_site, Handle method_handle);
+#ifdef HOTSWAP
+  // Flushing and deoptimization in case of evolution
+  static void flush_evol_dependents_on(instanceKlassHandle dependee);
+#endif // HOTSWAP
+  // Support for fullspeed debugging
+  static void flush_dependents_on_method(methodHandle dependee);
+
   // tells how many nmethods have dependencies
   static int number_of_nmethods_with_dependencies();
 
--- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp	Fri Jan 09 05:45:13 2015 -0800
+++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp	Fri Jan 09 13:28:02 2015 -0500
@@ -2560,12 +2560,12 @@
      x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,   \
      x }
 
-// Initialize with default setting of CMSParPromoteBlocksToClaim, _not_
-// OldPLABSize, whose static default is different; if overridden at the
+// Initialize with default setting for CMS, _not_
+// generic OldPLABSize, whose static default is different; if overridden at the
 // command-line, this will get reinitialized via a call to
 // modify_initialization() below.
 AdaptiveWeightedAverage CFLS_LAB::_blocks_to_claim[]    =
-  VECTOR_257(AdaptiveWeightedAverage(OldPLABWeight, (float)CMSParPromoteBlocksToClaim));
+  VECTOR_257(AdaptiveWeightedAverage(OldPLABWeight, (float)CFLS_LAB::_default_dynamic_old_plab_size));
 size_t CFLS_LAB::_global_num_blocks[]  = VECTOR_257(0);
 uint   CFLS_LAB::_global_num_workers[] = VECTOR_257(0);
 
--- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp	Fri Jan 09 05:45:13 2015 -0800
+++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp	Fri Jan 09 13:28:02 2015 -0500
@@ -690,6 +690,9 @@
   void get_from_global_pool(size_t word_sz, AdaptiveFreeList<FreeChunk>* fl);
 
 public:
+  static const int _default_dynamic_old_plab_size = 16;
+  static const int _default_static_old_plab_size  = 50;
+
   CFLS_LAB(CompactibleFreeListSpace* cfls);
 
   // Allocate and return a block of the given size, or else return NULL.
--- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp	Fri Jan 09 05:45:13 2015 -0800
+++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp	Fri Jan 09 13:28:02 2015 -0500
@@ -1611,14 +1611,15 @@
 
   // If the collection is being acquired from the background
   // collector, there may be references on the discovered
-  // references lists that have NULL referents (being those
-  // that were concurrently cleared by a mutator) or
-  // that are no longer active (having been enqueued concurrently
-  // by the mutator).
-  // Scrub the list of those references because Mark-Sweep-Compact
-  // code assumes referents are not NULL and that all discovered
-  // Reference objects are active.
-  ref_processor()->clean_up_discovered_references();
+  // references lists.  Abandon those references, since some
+  // of them may have become unreachable after concurrent
+  // discovery; the STW compacting collector will redo discovery
+  // more precisely, without being subject to floating garbage.
+  // Leaving otherwise unreachable references in the discovered
+  // lists would require special handling.
+  ref_processor()->disable_discovery();
+  ref_processor()->abandon_partial_discovery();
+  ref_processor()->verify_no_references_recorded();
 
   if (first_state > Idling) {
     save_heap_summary();
@@ -1684,7 +1685,7 @@
   ReferenceProcessorMTDiscoveryMutator rp_mut_discovery(ref_processor(), false);
 
   ref_processor()->set_enqueuing_is_done(false);
-  ref_processor()->enable_discovery(false /*verify_disabled*/, false /*check_no_refs*/);
+  ref_processor()->enable_discovery();
   ref_processor()->setup_policy(clear_all_soft_refs);
   // If an asynchronous collection finishes, the _modUnionTable is
   // all clear.  If we are assuming the collection from an asynchronous
@@ -3001,7 +3002,7 @@
                     Mutex::_no_safepoint_check_flag);
     checkpointRootsInitialWork();
     // enable ("weak") refs discovery
-    rp->enable_discovery(true /*verify_disabled*/, true /*check_no_refs*/);
+    rp->enable_discovery();
     _collectorState = Marking;
   }
   SpecializationStats::print();
--- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp	Fri Jan 09 05:45:13 2015 -0800
+++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp	Fri Jan 09 13:28:02 2015 -0500
@@ -971,7 +971,7 @@
   // Start Concurrent Marking weak-reference discovery.
   ReferenceProcessor* rp = g1h->ref_processor_cm();
   // enable ("weak") refs discovery
-  rp->enable_discovery(true /*verify_disabled*/, true /*verify_no_refs*/);
+  rp->enable_discovery();
   rp->setup_policy(false); // snapshot the soft ref policy to be used in this cycle
 
   SATBMarkQueueSet& satb_mq_set = JavaThread::satb_mark_queue_set();
--- a/hotspot/src/share/vm/gc_implementation/g1/g1AllocRegion.cpp	Fri Jan 09 05:45:13 2015 -0800
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1AllocRegion.cpp	Fri Jan 09 13:28:02 2015 -0500
@@ -254,25 +254,23 @@
 HeapRegion* SurvivorGCAllocRegion::allocate_new_region(size_t word_size,
                                                        bool force) {
   assert(!force, "not supported for GC alloc regions");
-  return _g1h->new_gc_alloc_region(word_size, count(), GCAllocForSurvived);
+  return _g1h->new_gc_alloc_region(word_size, count(), InCSetState::Young);
 }
 
 void SurvivorGCAllocRegion::retire_region(HeapRegion* alloc_region,
                                           size_t allocated_bytes) {
-  _g1h->retire_gc_alloc_region(alloc_region, allocated_bytes,
-                               GCAllocForSurvived);
+  _g1h->retire_gc_alloc_region(alloc_region, allocated_bytes, InCSetState::Young);
 }
 
 HeapRegion* OldGCAllocRegion::allocate_new_region(size_t word_size,
                                                   bool force) {
   assert(!force, "not supported for GC alloc regions");
-  return _g1h->new_gc_alloc_region(word_size, count(), GCAllocForTenured);
+  return _g1h->new_gc_alloc_region(word_size, count(), InCSetState::Old);
 }
 
 void OldGCAllocRegion::retire_region(HeapRegion* alloc_region,
                                      size_t allocated_bytes) {
-  _g1h->retire_gc_alloc_region(alloc_region, allocated_bytes,
-                               GCAllocForTenured);
+  _g1h->retire_gc_alloc_region(alloc_region, allocated_bytes, InCSetState::Old);
 }
 
 HeapRegion* OldGCAllocRegion::release() {
--- a/hotspot/src/share/vm/gc_implementation/g1/g1Allocator.cpp	Fri Jan 09 05:45:13 2015 -0800
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1Allocator.cpp	Fri Jan 09 13:28:02 2015 -0500
@@ -99,8 +99,8 @@
   }
 
   if (ResizePLAB) {
-    _g1h->_survivor_plab_stats.adjust_desired_plab_sz(no_of_gc_workers);
-    _g1h->_old_plab_stats.adjust_desired_plab_sz(no_of_gc_workers);
+    _g1h->alloc_buffer_stats(InCSetState::Young)->adjust_desired_plab_sz(no_of_gc_workers);
+    _g1h->alloc_buffer_stats(InCSetState::Old)->adjust_desired_plab_sz(no_of_gc_workers);
   }
 }
 
@@ -113,15 +113,16 @@
 G1ParGCAllocBuffer::G1ParGCAllocBuffer(size_t gclab_word_size) :
   ParGCAllocBuffer(gclab_word_size), _retired(true) { }
 
-HeapWord* G1ParGCAllocator::allocate_slow(GCAllocPurpose purpose, size_t word_sz, AllocationContext_t context) {
-  HeapWord* obj = NULL;
-  size_t gclab_word_size = _g1h->desired_plab_sz(purpose);
+HeapWord* G1ParGCAllocator::allocate_direct_or_new_plab(InCSetState dest,
+                                                        size_t word_sz,
+                                                        AllocationContext_t context) {
+  size_t gclab_word_size = _g1h->desired_plab_sz(dest);
   if (word_sz * 100 < gclab_word_size * ParallelGCBufferWastePct) {
-    G1ParGCAllocBuffer* alloc_buf = alloc_buffer(purpose, context);
+    G1ParGCAllocBuffer* alloc_buf = alloc_buffer(dest, context);
     add_to_alloc_buffer_waste(alloc_buf->words_remaining());
     alloc_buf->retire(false /* end_of_gc */, false /* retain */);
 
-    HeapWord* buf = _g1h->par_allocate_during_gc(purpose, gclab_word_size, context);
+    HeapWord* buf = _g1h->par_allocate_during_gc(dest, gclab_word_size, context);
     if (buf == NULL) {
       return NULL; // Let caller handle allocation failure.
     }
@@ -129,30 +130,33 @@
     alloc_buf->set_word_size(gclab_word_size);
     alloc_buf->set_buf(buf);
 
-    obj = alloc_buf->allocate(word_sz);
+    HeapWord* const obj = alloc_buf->allocate(word_sz);
     assert(obj != NULL, "buffer was definitely big enough...");
+    return obj;
   } else {
-    obj = _g1h->par_allocate_during_gc(purpose, word_sz, context);
+    return _g1h->par_allocate_during_gc(dest, word_sz, context);
   }
-  return obj;
 }
 
 G1DefaultParGCAllocator::G1DefaultParGCAllocator(G1CollectedHeap* g1h) :
-            G1ParGCAllocator(g1h),
-            _surviving_alloc_buffer(g1h->desired_plab_sz(GCAllocForSurvived)),
-            _tenured_alloc_buffer(g1h->desired_plab_sz(GCAllocForTenured)) {
-
-  _alloc_buffers[GCAllocForSurvived] = &_surviving_alloc_buffer;
-  _alloc_buffers[GCAllocForTenured]  = &_tenured_alloc_buffer;
-
+  G1ParGCAllocator(g1h),
+  _surviving_alloc_buffer(g1h->desired_plab_sz(InCSetState::Young)),
+  _tenured_alloc_buffer(g1h->desired_plab_sz(InCSetState::Old)) {
+  for (uint state = 0; state < InCSetState::Num; state++) {
+    _alloc_buffers[state] = NULL;
+  }
+  _alloc_buffers[InCSetState::Young] = &_surviving_alloc_buffer;
+  _alloc_buffers[InCSetState::Old]  = &_tenured_alloc_buffer;
 }
 
 void G1DefaultParGCAllocator::retire_alloc_buffers() {
-  for (int ap = 0; ap < GCAllocPurposeCount; ++ap) {
-    size_t waste = _alloc_buffers[ap]->words_remaining();
-    add_to_alloc_buffer_waste(waste);
-    _alloc_buffers[ap]->flush_stats_and_retire(_g1h->stats_for_purpose((GCAllocPurpose)ap),
-                                               true /* end_of_gc */,
-                                               false /* retain */);
+  for (uint state = 0; state < InCSetState::Num; state++) {
+    G1ParGCAllocBuffer* const buf = _alloc_buffers[state];
+    if (buf != NULL) {
+      add_to_alloc_buffer_waste(buf->words_remaining());
+      buf->flush_stats_and_retire(_g1h->alloc_buffer_stats(state),
+                                  true /* end_of_gc */,
+                                  false /* retain */);
+    }
   }
 }
--- a/hotspot/src/share/vm/gc_implementation/g1/g1Allocator.hpp	Fri Jan 09 05:45:13 2015 -0800
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1Allocator.hpp	Fri Jan 09 13:28:02 2015 -0500
@@ -27,14 +27,9 @@
 
 #include "gc_implementation/g1/g1AllocationContext.hpp"
 #include "gc_implementation/g1/g1AllocRegion.hpp"
+#include "gc_implementation/g1/g1InCSetState.hpp"
 #include "gc_implementation/shared/parGCAllocBuffer.hpp"
 
-enum GCAllocPurpose {
-  GCAllocForTenured,
-  GCAllocForSurvived,
-  GCAllocPurposeCount
-};
-
 // Base class for G1 allocators.
 class G1Allocator : public CHeapObj<mtGC> {
   friend class VMStructs;
@@ -178,20 +173,40 @@
 protected:
   G1CollectedHeap* _g1h;
 
+  // The survivor alignment in effect in bytes.
+  // == 0 : don't align survivors
+  // != 0 : align survivors to that alignment
+  // These values were chosen to favor the non-alignment case since some
+  // architectures have a special compare against zero instructions.
+  const uint _survivor_alignment_bytes;
+
   size_t _alloc_buffer_waste;
   size_t _undo_waste;
 
   void add_to_alloc_buffer_waste(size_t waste) { _alloc_buffer_waste += waste; }
   void add_to_undo_waste(size_t waste)         { _undo_waste += waste; }
 
-  HeapWord* allocate_slow(GCAllocPurpose purpose, size_t word_sz, AllocationContext_t context);
+  virtual void retire_alloc_buffers() = 0;
+  virtual G1ParGCAllocBuffer* alloc_buffer(InCSetState dest, AllocationContext_t context) = 0;
 
-  virtual void retire_alloc_buffers() = 0;
-  virtual G1ParGCAllocBuffer* alloc_buffer(GCAllocPurpose purpose, AllocationContext_t context) = 0;
+  // Calculate the survivor space object alignment in bytes. Returns that or 0 if
+  // there are no restrictions on survivor alignment.
+  static uint calc_survivor_alignment_bytes() {
+    assert(SurvivorAlignmentInBytes >= ObjectAlignmentInBytes, "sanity");
+    if (SurvivorAlignmentInBytes == ObjectAlignmentInBytes) {
+      // No need to align objects in the survivors differently, return 0
+      // which means "survivor alignment is not used".
+      return 0;
+    } else {
+      assert(SurvivorAlignmentInBytes > 0, "sanity");
+      return SurvivorAlignmentInBytes;
+    }
+  }
 
 public:
   G1ParGCAllocator(G1CollectedHeap* g1h) :
-    _g1h(g1h), _alloc_buffer_waste(0), _undo_waste(0) {
+    _g1h(g1h), _survivor_alignment_bytes(calc_survivor_alignment_bytes()),
+    _alloc_buffer_waste(0), _undo_waste(0) {
   }
 
   static G1ParGCAllocator* create_allocator(G1CollectedHeap* g1h);
@@ -199,24 +214,40 @@
   size_t alloc_buffer_waste() { return _alloc_buffer_waste; }
   size_t undo_waste() {return _undo_waste; }
 
-  HeapWord* allocate(GCAllocPurpose purpose, size_t word_sz, AllocationContext_t context) {
-    HeapWord* obj = NULL;
-    if (purpose == GCAllocForSurvived) {
-      obj = alloc_buffer(purpose, context)->allocate_aligned(word_sz, SurvivorAlignmentInBytes);
+  // Allocate word_sz words in dest, either directly into the regions or by
+  // allocating a new PLAB. Returns the address of the allocated memory, NULL if
+  // not successful.
+  HeapWord* allocate_direct_or_new_plab(InCSetState dest,
+                                        size_t word_sz,
+                                        AllocationContext_t context);
+
+  // Allocate word_sz words in the PLAB of dest.  Returns the address of the
+  // allocated memory, NULL if not successful.
+  HeapWord* plab_allocate(InCSetState dest,
+                          size_t word_sz,
+                          AllocationContext_t context) {
+    G1ParGCAllocBuffer* buffer = alloc_buffer(dest, context);
+    if (_survivor_alignment_bytes == 0) {
+      return buffer->allocate(word_sz);
     } else {
-      obj = alloc_buffer(purpose, context)->allocate(word_sz);
+      return buffer->allocate_aligned(word_sz, _survivor_alignment_bytes);
     }
+  }
+
+  HeapWord* allocate(InCSetState dest, size_t word_sz,
+                     AllocationContext_t context) {
+    HeapWord* const obj = plab_allocate(dest, word_sz, context);
     if (obj != NULL) {
       return obj;
     }
-    return allocate_slow(purpose, word_sz, context);
+    return allocate_direct_or_new_plab(dest, word_sz, context);
   }
 
-  void undo_allocation(GCAllocPurpose purpose, HeapWord* obj, size_t word_sz, AllocationContext_t context) {
-    if (alloc_buffer(purpose, context)->contains(obj)) {
-      assert(alloc_buffer(purpose, context)->contains(obj + word_sz - 1),
+  void undo_allocation(InCSetState dest, HeapWord* obj, size_t word_sz, AllocationContext_t context) {
+    if (alloc_buffer(dest, context)->contains(obj)) {
+      assert(alloc_buffer(dest, context)->contains(obj + word_sz - 1),
              "should contain whole object");
-      alloc_buffer(purpose, context)->undo_allocation(obj, word_sz);
+      alloc_buffer(dest, context)->undo_allocation(obj, word_sz);
     } else {
       CollectedHeap::fill_with_object(obj, word_sz);
       add_to_undo_waste(word_sz);
@@ -227,13 +258,17 @@
 class G1DefaultParGCAllocator : public G1ParGCAllocator {
   G1ParGCAllocBuffer  _surviving_alloc_buffer;
   G1ParGCAllocBuffer  _tenured_alloc_buffer;
-  G1ParGCAllocBuffer* _alloc_buffers[GCAllocPurposeCount];
+  G1ParGCAllocBuffer* _alloc_buffers[InCSetState::Num];
 
 public:
   G1DefaultParGCAllocator(G1CollectedHeap* g1h);
 
-  virtual G1ParGCAllocBuffer* alloc_buffer(GCAllocPurpose purpose, AllocationContext_t context) {
-    return _alloc_buffers[purpose];
+  virtual G1ParGCAllocBuffer* alloc_buffer(InCSetState dest, AllocationContext_t context) {
+    assert(dest.is_valid(),
+           err_msg("Allocation buffer index out-of-bounds: " CSETSTATE_FORMAT, dest.value()));
+    assert(_alloc_buffers[dest.value()] != NULL,
+           err_msg("Allocation buffer is NULL: " CSETSTATE_FORMAT, dest.value()));
+    return _alloc_buffers[dest.value()];
   }
 
   virtual void retire_alloc_buffers() ;
--- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp	Fri Jan 09 05:45:13 2015 -0800
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp	Fri Jan 09 13:28:02 2015 -0500
@@ -1301,7 +1301,7 @@
       // Temporarily clear the STW ref processor's _is_alive_non_header field.
       ReferenceProcessorIsAliveMutator stw_rp_is_alive_null(ref_processor_stw(), NULL);
 
-      ref_processor_stw()->enable_discovery(true /*verify_disabled*/, true /*verify_no_refs*/);
+      ref_processor_stw()->enable_discovery();
       ref_processor_stw()->setup_policy(do_clear_all_soft_refs);
 
       // Do collection work
@@ -1886,13 +1886,12 @@
 
   initialize_reserved_region((HeapWord*)heap_rs.base(), (HeapWord*)(heap_rs.base() + heap_rs.size()));
 
-  // Create the gen rem set (and barrier set) for the entire reserved region.
-  _rem_set = collector_policy()->create_rem_set(reserved_region());
-  set_barrier_set(rem_set()->bs());
-  if (!barrier_set()->is_a(BarrierSet::G1SATBCTLogging)) {
-    vm_exit_during_initialization("G1 requires a G1SATBLoggingCardTableModRefBS");
-    return JNI_ENOMEM;
-  }
+  // Create the barrier set for the entire reserved region.
+  G1SATBCardTableLoggingModRefBS* bs
+    = new G1SATBCardTableLoggingModRefBS(reserved_region());
+  bs->initialize();
+  assert(bs->is_a(BarrierSet::G1SATBCTLogging), "sanity");
+  set_barrier_set(bs);
 
   // Also create a G1 rem set.
   _g1_rem_set = new G1RemSet(this, g1_barrier_set());
@@ -2069,7 +2068,7 @@
 }
 
 void G1CollectedHeap::clear_humongous_is_live_table() {
-  guarantee(G1ReclaimDeadHumongousObjectsAtYoungGC, "Should only be called if true");
+  guarantee(G1EagerReclaimHumongousObjects, "Should only be called if true");
   _humongous_is_live.clear();
 }
 
@@ -3153,8 +3152,6 @@
         failures = true;
       }
     }
-    if (!silent) gclog_or_tty->print("RemSet ");
-    rem_set()->verify();
 
     if (G1StringDedup::is_enabled()) {
       if (!silent) gclog_or_tty->print("StrDedup ");
@@ -3488,8 +3485,24 @@
  private:
   size_t _total_humongous;
   size_t _candidate_humongous;
+
+  DirtyCardQueue _dcq;
+
+  bool humongous_region_is_candidate(uint index) {
+    HeapRegion* region = G1CollectedHeap::heap()->region_at(index);
+    assert(region->is_starts_humongous(), "Must start a humongous object");
+    HeapRegionRemSet* const rset = region->rem_set();
+    bool const allow_stale_refs = G1EagerReclaimHumongousObjectsWithStaleRefs;
+    return !oop(region->bottom())->is_objArray() &&
+           ((allow_stale_refs && rset->occupancy_less_or_equal_than(G1RSetSparseRegionEntries)) ||
+            (!allow_stale_refs && rset->is_empty()));
+  }
+
  public:
-  RegisterHumongousWithInCSetFastTestClosure() : _total_humongous(0), _candidate_humongous(0) {
+  RegisterHumongousWithInCSetFastTestClosure()
+  : _total_humongous(0),
+    _candidate_humongous(0),
+    _dcq(&JavaThread::dirty_card_queue_set()) {
   }
 
   virtual bool doHeapRegion(HeapRegion* r) {
@@ -3499,11 +3512,29 @@
     G1CollectedHeap* g1h = G1CollectedHeap::heap();
 
     uint region_idx = r->hrm_index();
-    bool is_candidate = !g1h->humongous_region_is_always_live(region_idx);
-    // Is_candidate already filters out humongous regions with some remembered set.
-    // This will not lead to humongous object that we mistakenly keep alive because
-    // during young collection the remembered sets will only be added to.
+    bool is_candidate = humongous_region_is_candidate(region_idx);
+    // Is_candidate already filters out humongous object with large remembered sets.
+    // If we have a humongous object with a few remembered sets, we simply flush these
+    // remembered set entries into the DCQS. That will result in automatic
+    // re-evaluation of their remembered set entries during the following evacuation
+    // phase.
     if (is_candidate) {
+      if (!r->rem_set()->is_empty()) {
+        guarantee(r->rem_set()->occupancy_less_or_equal_than(G1RSetSparseRegionEntries),
+                  "Found a not-small remembered set here. This is inconsistent with previous assumptions.");
+        G1SATBCardTableLoggingModRefBS* bs = g1h->g1_barrier_set();
+        HeapRegionRemSetIterator hrrs(r->rem_set());
+        size_t card_index;
+        while (hrrs.has_next(card_index)) {
+          jbyte* card_ptr = (jbyte*)bs->byte_for_index(card_index);
+          if (*card_ptr != CardTableModRefBS::dirty_card_val()) {
+            *card_ptr = CardTableModRefBS::dirty_card_val();
+            _dcq.enqueue(card_ptr);
+          }
+        }
+        r->rem_set()->clear_locked();
+      }
+      assert(r->rem_set()->is_empty(), "At this point any humongous candidate remembered set must be empty.");
       g1h->register_humongous_region_with_in_cset_fast_test(region_idx);
       _candidate_humongous++;
     }
@@ -3514,23 +3545,32 @@
 
   size_t total_humongous() const { return _total_humongous; }
   size_t candidate_humongous() const { return _candidate_humongous; }
+
+  void flush_rem_set_entries() { _dcq.flush(); }
 };
 
 void G1CollectedHeap::register_humongous_regions_with_in_cset_fast_test() {
-  if (!G1ReclaimDeadHumongousObjectsAtYoungGC) {
-    g1_policy()->phase_times()->record_fast_reclaim_humongous_stats(0, 0);
+  if (!G1EagerReclaimHumongousObjects) {
+    g1_policy()->phase_times()->record_fast_reclaim_humongous_stats(0.0, 0, 0);
     return;
   }
+  double time = os::elapsed_counter();
 
   RegisterHumongousWithInCSetFastTestClosure cl;
   heap_region_iterate(&cl);
-  g1_policy()->phase_times()->record_fast_reclaim_humongous_stats(cl.total_humongous(),
+
+  time = ((double)(os::elapsed_counter() - time) / os::elapsed_frequency()) * 1000.0;
+  g1_policy()->phase_times()->record_fast_reclaim_humongous_stats(time,
+                                                                  cl.total_humongous(),
                                                                   cl.candidate_humongous());
   _has_humongous_reclaim_candidates = cl.candidate_humongous() > 0;
 
-  if (_has_humongous_reclaim_candidates || G1TraceReclaimDeadHumongousObjectsAtYoungGC) {
+  if (_has_humongous_reclaim_candidates || G1TraceEagerReclaimHumongousObjects) {
     clear_humongous_is_live_table();
   }
+
+  // Finally flush all remembered set entries to re-check into the global DCQS.
+  cl.flush_rem_set_entries();
 }
 
 void
@@ -3750,8 +3790,7 @@
       // reference processing currently works in G1.
 
       // Enable discovery in the STW reference processor
-      ref_processor_stw()->enable_discovery(true /*verify_disabled*/,
-                                            true /*verify_no_refs*/);
+      ref_processor_stw()->enable_discovery();
 
       {
         // We want to temporarily turn off discovery by the
@@ -3819,6 +3858,8 @@
 
         register_humongous_regions_with_in_cset_fast_test();
 
+        assert(check_cset_fast_test(), "Inconsistency in the InCSetState table.");
+
         _cm->note_start_of_gc();
         // We should not verify the per-thread SATB buffers given that
         // we have not filtered them yet (we'll do so during the
@@ -4048,29 +4089,6 @@
   return true;
 }
 
-size_t G1CollectedHeap::desired_plab_sz(GCAllocPurpose purpose)
-{
-  size_t gclab_word_size;
-  switch (purpose) {
-    case GCAllocForSurvived:
-      gclab_word_size = _survivor_plab_stats.desired_plab_sz();
-      break;
-    case GCAllocForTenured:
-      gclab_word_size = _old_plab_stats.desired_plab_sz();
-      break;
-    default:
-      assert(false, "unknown GCAllocPurpose");
-      gclab_word_size = _old_plab_stats.desired_plab_sz();
-      break;
-  }
-
-  // Prevent humongous PLAB sizes for two reasons:
-  // * PLABs are allocated using a similar paths as oops, but should
-  //   never be in a humongous region
-  // * Allowing humongous PLABs needlessly churns the region free lists
-  return MIN2(_humongous_object_threshold_in_words, gclab_word_size);
-}
-
 void G1CollectedHeap::init_for_evac_failure(OopsInHeapRegionClosure* cl) {
   _drain_in_progress = false;
   set_evac_failure_closure(cl);
@@ -4196,35 +4214,6 @@
   }
 }
 
-HeapWord* G1CollectedHeap::par_allocate_during_gc(GCAllocPurpose purpose,
-                                                  size_t word_size,
-                                                  AllocationContext_t context) {
-  if (purpose == GCAllocForSurvived) {
-    HeapWord* result = survivor_attempt_allocation(word_size, context);
-    if (result != NULL) {
-      return result;
-    } else {
-      // Let's try to allocate in the old gen in case we can fit the
-      // object there.
-      return old_attempt_allocation(word_size, context);
-    }
-  } else {
-    assert(purpose ==  GCAllocForTenured, "sanity");
-    HeapWord* result = old_attempt_allocation(word_size, context);
-    if (result != NULL) {
-      return result;
-    } else {
-      // Let's try to allocate in the survivors in case we can fit the
-      // object there.
-      return survivor_attempt_allocation(word_size, context);
-    }
-  }
-
-  ShouldNotReachHere();
-  // Trying to keep some compilers happy.
-  return NULL;
-}
-
 void G1ParCopyHelper::mark_object(oop obj) {
   assert(!_g1->heap_region_containing(obj)->in_collection_set(), "should not mark objects in the CSet");
 
@@ -4267,15 +4256,14 @@
 
   assert(_worker_id == _par_scan_state->queue_num(), "sanity");
 
-  G1CollectedHeap::in_cset_state_t state = _g1->in_cset_state(obj);
-
-  if (state == G1CollectedHeap::InCSet) {
+  const InCSetState state = _g1->in_cset_state(obj);
+  if (state.is_in_cset()) {
     oop forwardee;
     markOop m = obj->mark();
     if (m->is_marked()) {
       forwardee = (oop) m->decode_pointer();
     } else {
-      forwardee = _par_scan_state->copy_to_survivor_space(obj, m);
+      forwardee = _par_scan_state->copy_to_survivor_space(state, obj, m);
     }
     assert(forwardee != NULL, "forwardee should not be NULL");
     oopDesc::encode_store_heap_oop(p, forwardee);
@@ -4289,7 +4277,7 @@
       do_klass_barrier(p, forwardee);
     }
   } else {
-    if (state == G1CollectedHeap::IsHumongous) {
+    if (state.is_humongous()) {
       _g1->set_humongous_is_live(obj);
     }
     // The object is not in collection set. If we're a root scanning
@@ -4609,7 +4597,7 @@
 G1CollectedHeap::
 g1_process_roots(OopClosure* scan_non_heap_roots,
                  OopClosure* scan_non_heap_weak_roots,
-                 OopsInHeapRegionClosure* scan_rs,
+                 G1ParPushHeapRSClosure* scan_rs,
                  CLDClosure* scan_strong_clds,
                  CLDClosure* scan_weak_clds,
                  CodeBlobClosure* scan_strong_code,
@@ -5145,17 +5133,17 @@
     oop obj = *p;
     assert(obj != NULL, "the caller should have filtered out NULL values");
 
-    G1CollectedHeap::in_cset_state_t cset_state = _g1->in_cset_state(obj);
-    if (cset_state == G1CollectedHeap::InNeither) {
+    const InCSetState cset_state = _g1->in_cset_state(obj);
+    if (!cset_state.is_in_cset_or_humongous()) {
       return;
     }
-    if (cset_state == G1CollectedHeap::InCSet) {
+    if (cset_state.is_in_cset()) {
       assert( obj->is_forwarded(), "invariant" );
       *p = obj->forwardee();
     } else {
       assert(!obj->is_forwarded(), "invariant" );
-      assert(cset_state == G1CollectedHeap::IsHumongous,
-             err_msg("Only allowed InCSet state is IsHumongous, but is %d", cset_state));
+      assert(cset_state.is_humongous(),
+             err_msg("Only allowed InCSet state is IsHumongous, but is %d", cset_state.value()));
       _g1->set_humongous_is_live(obj);
     }
   }
@@ -5640,8 +5628,6 @@
 
   init_for_evac_failure(NULL);
 
-  rem_set()->prepare_for_younger_refs_iterate(true);
-
   assert(dirty_card_queue_set().completed_buffers_num() == 0, "Should be empty");
   double start_par_time_sec = os::elapsedTime();
   double end_par_time_sec;
@@ -5951,6 +5937,70 @@
   heap_region_iterate(&cl);
   guarantee(!cl.failures(), "bitmap verification");
 }
+
+class G1CheckCSetFastTableClosure : public HeapRegionClosure {
+ private:
+  bool _failures;
+ public:
+  G1CheckCSetFastTableClosure() : HeapRegionClosure(), _failures(false) { }
+
+  virtual bool doHeapRegion(HeapRegion* hr) {
+    uint i = hr->hrm_index();
+    InCSetState cset_state = (InCSetState) G1CollectedHeap::heap()->_in_cset_fast_test.get_by_index(i);
+    if (hr->is_humongous()) {
+      if (hr->in_collection_set()) {
+        gclog_or_tty->print_cr("\n## humongous region %u in CSet", i);
+        _failures = true;
+        return true;
+      }
+      if (cset_state.is_in_cset()) {
+        gclog_or_tty->print_cr("\n## inconsistent cset state %d for humongous region %u", cset_state.value(), i);
+        _failures = true;
+        return true;
+      }
+      if (hr->is_continues_humongous() && cset_state.is_humongous()) {
+        gclog_or_tty->print_cr("\n## inconsistent cset state %d for continues humongous region %u", cset_state.value(), i);
+        _failures = true;
+        return true;
+      }
+    } else {
+      if (cset_state.is_humongous()) {
+        gclog_or_tty->print_cr("\n## inconsistent cset state %d for non-humongous region %u", cset_state.value(), i);
+        _failures = true;
+        return true;
+      }
+      if (hr->in_collection_set() != cset_state.is_in_cset()) {
+        gclog_or_tty->print_cr("\n## in CSet %d / cset state %d inconsistency for region %u",
+                               hr->in_collection_set(), cset_state.value(), i);
+        _failures = true;
+        return true;
+      }
+      if (cset_state.is_in_cset()) {
+        if (hr->is_young() != (cset_state.is_young())) {
+          gclog_or_tty->print_cr("\n## is_young %d / cset state %d inconsistency for region %u",
+                                 hr->is_young(), cset_state.value(), i);
+          _failures = true;
+          return true;
+        }
+        if (hr->is_old() != (cset_state.is_old())) {
+          gclog_or_tty->print_cr("\n## is_old %d / cset state %d inconsistency for region %u",
+                                 hr->is_old(), cset_state.value(), i);
+          _failures = true;
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+
+  bool failures() const { return _failures; }
+};
+
+bool G1CollectedHeap::check_cset_fast_test() {
+  G1CheckCSetFastTableClosure cl;
+  _hrm.iterate(&cl);
+  return !cl.failures();
+}
 #endif // PRODUCT
 
 void G1CollectedHeap::cleanUpCardTable() {
@@ -6133,22 +6183,20 @@
     // are completely up-to-date wrt to references to the humongous object.
     //
     // Other implementation considerations:
-    // - never consider object arrays: while they are a valid target, they have not
-    // been observed to be used as temporary objects.
-    // - they would also pose considerable effort for cleaning up the the remembered
-    // sets.
-    // While this cleanup is not strictly necessary to be done (or done instantly),
-    // given that their occurrence is very low, this saves us this additional
-    // complexity.
+    // - never consider object arrays at this time because they would pose
+    // considerable effort for cleaning up the the remembered sets. This is
+    // required because stale remembered sets might reference locations that
+    // are currently allocated into.
     uint region_idx = r->hrm_index();
     if (g1h->humongous_is_live(region_idx) ||
         g1h->humongous_region_is_always_live(region_idx)) {
 
-      if (G1TraceReclaimDeadHumongousObjectsAtYoungGC) {
-        gclog_or_tty->print_cr("Live humongous %d region %d size "SIZE_FORMAT" with remset "SIZE_FORMAT" code roots "SIZE_FORMAT" is marked %d live-other %d obj array %d",
-                               r->is_humongous(),
+      if (G1TraceEagerReclaimHumongousObjects) {
+        gclog_or_tty->print_cr("Live humongous region %u size "SIZE_FORMAT" start "PTR_FORMAT" length "UINT32_FORMAT" with remset "SIZE_FORMAT" code roots "SIZE_FORMAT" is marked %d live-other %d obj array %d",
                                region_idx,
                                obj->size()*HeapWordSize,
+                               r->bottom(),
+                               r->region_num(),
                                r->rem_set()->occupied(),
                                r->rem_set()->strong_code_roots_list_length(),
                                next_bitmap->isMarked(r->bottom()),
@@ -6164,12 +6212,11 @@
               err_msg("Eagerly reclaiming object arrays is not supported, but the object "PTR_FORMAT" is.",
                       r->bottom()));
 
-    if (G1TraceReclaimDeadHumongousObjectsAtYoungGC) {
-      gclog_or_tty->print_cr("Reclaim humongous region %d size "SIZE_FORMAT" start "PTR_FORMAT" region %d length "UINT32_FORMAT" with remset "SIZE_FORMAT" code roots "SIZE_FORMAT" is marked %d live-other %d obj array %d",
-                             r->is_humongous(),
+    if (G1TraceEagerReclaimHumongousObjects) {
+      gclog_or_tty->print_cr("Dead humongous region %u size "SIZE_FORMAT" start "PTR_FORMAT" length "UINT32_FORMAT" with remset "SIZE_FORMAT" code roots "SIZE_FORMAT" is marked %d live-other %d obj array %d",
+                             region_idx,
                              obj->size()*HeapWordSize,
                              r->bottom(),
-                             region_idx,
                              r->region_num(),
                              r->rem_set()->occupied(),
                              r->rem_set()->strong_code_roots_list_length(),
@@ -6206,8 +6253,8 @@
 void G1CollectedHeap::eagerly_reclaim_humongous_regions() {
   assert_at_safepoint(true);
 
-  if (!G1ReclaimDeadHumongousObjectsAtYoungGC ||
-      (!_has_humongous_reclaim_candidates && !G1TraceReclaimDeadHumongousObjectsAtYoungGC)) {
+  if (!G1EagerReclaimHumongousObjects ||
+      (!_has_humongous_reclaim_candidates && !G1TraceEagerReclaimHumongousObjects)) {
     g1_policy()->phase_times()->record_fast_reclaim_humongous_time_ms(0.0, 0);
     return;
   }
@@ -6519,20 +6566,20 @@
 
 HeapRegion* G1CollectedHeap::new_gc_alloc_region(size_t word_size,
                                                  uint count,
-                                                 GCAllocPurpose ap) {
+                                                 InCSetState dest) {
   assert(FreeList_lock->owned_by_self(), "pre-condition");
 
-  if (count < g1_policy()->max_regions(ap)) {
-    bool survivor = (ap == GCAllocForSurvived);
+  if (count < g1_policy()->max_regions(dest)) {
+    const bool is_survivor = (dest.is_young());
     HeapRegion* new_alloc_region = new_region(word_size,
-                                              !survivor,
+                                              !is_survivor,
                                               true /* do_expand */);
     if (new_alloc_region != NULL) {
       // We really only need to do this for old regions given that we
       // should never scan survivors. But it doesn't hurt to do it
       // for survivors too.
       new_alloc_region->record_timestamp();
-      if (survivor) {
+      if (is_survivor) {
         new_alloc_region->set_survivor();
         _hr_printer.alloc(new_alloc_region, G1HRPrinter::Survivor);
         check_bitmaps("Survivor Region Allocation", new_alloc_region);
@@ -6544,8 +6591,6 @@
       bool during_im = g1_policy()->during_initial_mark_pause();
       new_alloc_region->note_start_of_copying(during_im);
       return new_alloc_region;
-    } else {
-      g1_policy()->note_alloc_region_limit_reached(ap);
     }
   }
   return NULL;
@@ -6553,11 +6598,11 @@
 
 void G1CollectedHeap::retire_gc_alloc_region(HeapRegion* alloc_region,
                                              size_t allocated_bytes,
-                                             GCAllocPurpose ap) {
+                                             InCSetState dest) {
   bool during_im = g1_policy()->during_initial_mark_pause();
   alloc_region->note_end_of_copying(during_im);
   g1_policy()->record_bytes_copied_during_gc(allocated_bytes);
-  if (ap == GCAllocForSurvived) {
+  if (dest.is_young()) {
     young_list()->add_survivor_region(alloc_region);
   } else {
     _old_set.add(alloc_region);
--- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp	Fri Jan 09 05:45:13 2015 -0800
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp	Fri Jan 09 13:28:02 2015 -0500
@@ -32,6 +32,7 @@
 #include "gc_implementation/g1/g1AllocRegion.hpp"
 #include "gc_implementation/g1/g1BiasedArray.hpp"
 #include "gc_implementation/g1/g1HRPrinter.hpp"
+#include "gc_implementation/g1/g1InCSetState.hpp"
 #include "gc_implementation/g1/g1MonitoringSupport.hpp"
 #include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp"
 #include "gc_implementation/g1/g1YCTypes.hpp"
@@ -185,34 +186,19 @@
   friend class SurvivorGCAllocRegion;
   friend class OldGCAllocRegion;
   friend class G1Allocator;
-  friend class G1DefaultAllocator;
-  friend class G1ResManAllocator;
 
   // Closures used in implementation.
-  template <G1Barrier barrier, G1Mark do_mark_object>
-  friend class G1ParCopyClosure;
-  friend class G1IsAliveClosure;
-  friend class G1EvacuateFollowersClosure;
   friend class G1ParScanThreadState;
-  friend class G1ParScanClosureSuper;
-  friend class G1ParEvacuateFollowersClosure;
   friend class G1ParTask;
   friend class G1ParGCAllocator;
-  friend class G1DefaultParGCAllocator;
-  friend class G1FreeGarbageRegionClosure;
-  friend class RefineCardTableEntryClosure;
   friend class G1PrepareCompactClosure;
-  friend class RegionSorter;
-  friend class RegionResetter;
-  friend class CountRCClosure;
-  friend class EvacPopObjClosure;
-  friend class G1ParCleanupCTTask;
 
-  friend class G1FreeHumongousRegionClosure;
   // Other related classes.
-  friend class G1MarkSweep;
   friend class HeapRegionClaimer;
 
+  // Testing classes.
+  friend class G1CheckCSetFastTableClosure;
+
 private:
   // The one and only G1CollectedHeap, so static functions can find it.
   static G1CollectedHeap* _g1h;
@@ -547,15 +533,9 @@
   // allocation region, either by picking one or expanding the
   // heap, and then allocate a block of the given size. The block
   // may not be a humongous - it must fit into a single heap region.
-  HeapWord* par_allocate_during_gc(GCAllocPurpose purpose,
-                                   size_t word_size,
-                                   AllocationContext_t context);
-
-  HeapWord* allocate_during_gc_slow(GCAllocPurpose purpose,
-                                    HeapRegion*    alloc_region,
-                                    bool           par,
-                                    size_t         word_size);
-
+  inline HeapWord* par_allocate_during_gc(InCSetState dest,
+                                          size_t word_size,
+                                          AllocationContext_t context);
   // Ensure that no further allocations can happen in "r", bearing in mind
   // that parallel threads might be attempting allocations.
   void par_allocate_remaining_space(HeapRegion* r);
@@ -577,9 +557,9 @@
 
   // For GC alloc regions.
   HeapRegion* new_gc_alloc_region(size_t word_size, uint count,
-                                  GCAllocPurpose ap);
+                                  InCSetState dest);
   void retire_gc_alloc_region(HeapRegion* alloc_region,
-                              size_t allocated_bytes, GCAllocPurpose ap);
+                              size_t allocated_bytes, InCSetState dest);
 
   // - if explicit_gc is true, the GC is for a System.gc() or a heap
   //   inspection request and should collect the entire heap
@@ -640,26 +620,11 @@
   // (Rounds up to a HeapRegion boundary.)
   bool expand(size_t expand_bytes);
 
-  // Returns the PLAB statistics given a purpose.
-  PLABStats* stats_for_purpose(GCAllocPurpose purpose) {
-    PLABStats* stats = NULL;
+  // Returns the PLAB statistics for a given destination.
+  inline PLABStats* alloc_buffer_stats(InCSetState dest);
 
-    switch (purpose) {
-    case GCAllocForSurvived:
-      stats = &_survivor_plab_stats;
-      break;
-    case GCAllocForTenured:
-      stats = &_old_plab_stats;
-      break;
-    default:
-      assert(false, "unrecognized GCAllocPurpose");
-    }
-
-    return stats;
-  }
-
-  // Determines PLAB size for a particular allocation purpose.
-  size_t desired_plab_sz(GCAllocPurpose purpose);
+  // Determines PLAB size for a given destination.
+  inline size_t desired_plab_sz(InCSetState dest);
 
   inline AllocationContextStats& allocation_context_stats();
 
@@ -676,6 +641,9 @@
   // Returns whether the given region (which must be a humongous (start) region)
   // is to be considered conservatively live regardless of any other conditions.
   bool humongous_region_is_always_live(uint index);
+  // Returns whether the given region (which must be a humongous (start) region)
+  // is considered a candidate for eager reclamation.
+  bool humongous_region_is_candidate(uint index);
   // Register the given region to be part of the collection set.
   inline void register_humongous_region_with_in_cset_fast_test(uint index);
   // Register regions with humongous objects (actually on the start region) in
@@ -683,8 +651,11 @@
   void register_humongous_regions_with_in_cset_fast_test();
   // We register a region with the fast "in collection set" test. We
   // simply set to true the array slot corresponding to this region.
-  void register_region_with_in_cset_fast_test(HeapRegion* r) {
-    _in_cset_fast_test.set_in_cset(r->hrm_index());
+  void register_young_region_with_in_cset_fast_test(HeapRegion* r) {
+    _in_cset_fast_test.set_in_young(r->hrm_index());
+  }
+  void register_old_region_with_in_cset_fast_test(HeapRegion* r) {
+    _in_cset_fast_test.set_in_old(r->hrm_index());
   }
 
   // This is a fast test on whether a reference points into the
@@ -821,7 +792,7 @@
   // In the sequential case this param will be ignored.
   void g1_process_roots(OopClosure* scan_non_heap_roots,
                         OopClosure* scan_non_heap_weak_roots,
-                        OopsInHeapRegionClosure* scan_rs,
+                        G1ParPushHeapRSClosure* scan_rs,
                         CLDClosure* scan_strong_clds,
                         CLDClosure* scan_weak_clds,
                         CodeBlobClosure* scan_strong_code,
@@ -1181,6 +1152,9 @@
   // appropriate error messages and crash.
   void check_bitmaps(const char* caller) PRODUCT_RETURN;
 
+  // Do sanity check on the contents of the in-cset fast test table.
+  bool check_cset_fast_test() PRODUCT_RETURN_( return true; );
+
   // verify_region_sets() performs verification over the region
   // lists. It will be compiled in the product code to be used when
   // necessary (i.e., during heap verification).
@@ -1276,53 +1250,15 @@
 
   inline bool is_in_cset_or_humongous(const oop obj);
 
-  enum in_cset_state_t {
-   InNeither,           // neither in collection set nor humongous
-   InCSet,              // region is in collection set only
-   IsHumongous          // region is a humongous start region
-  };
  private:
-  // Instances of this class are used for quick tests on whether a reference points
-  // into the collection set or is a humongous object (points into a humongous
-  // object).
-  // Each of the array's elements denotes whether the corresponding region is in
-  // the collection set or a humongous region.
-  // We use this to quickly reclaim humongous objects: by making a humongous region
-  // succeed this test, we sort-of add it to the collection set. During the reference
-  // iteration closures, when we see a humongous region, we simply mark it as
-  // referenced, i.e. live.
-  class G1FastCSetBiasedMappedArray : public G1BiasedMappedArray<char> {
-   protected:
-    char default_value() const { return G1CollectedHeap::InNeither; }
-   public:
-    void set_humongous(uintptr_t index) {
-      assert(get_by_index(index) != InCSet, "Should not overwrite InCSet values");
-      set_by_index(index, G1CollectedHeap::IsHumongous);
-    }
-
-    void clear_humongous(uintptr_t index) {
-      set_by_index(index, G1CollectedHeap::InNeither);
-    }
-
-    void set_in_cset(uintptr_t index) {
-      assert(get_by_index(index) != G1CollectedHeap::IsHumongous, "Should not overwrite IsHumongous value");
-      set_by_index(index, G1CollectedHeap::InCSet);
-    }
-
-    bool is_in_cset_or_humongous(HeapWord* addr) const { return get_by_address(addr) != G1CollectedHeap::InNeither; }
-    bool is_in_cset(HeapWord* addr) const { return get_by_address(addr) == G1CollectedHeap::InCSet; }
-    G1CollectedHeap::in_cset_state_t at(HeapWord* addr) const { return (G1CollectedHeap::in_cset_state_t)get_by_address(addr); }
-    void clear() { G1BiasedMappedArray<char>::clear(); }
-  };
-
   // This array is used for a quick test on whether a reference points into
   // the collection set or not. Each of the array's elements denotes whether the
   // corresponding region is in the collection set or not.
-  G1FastCSetBiasedMappedArray _in_cset_fast_test;
+  G1InCSetStateFastTestBiasedMappedArray _in_cset_fast_test;
 
  public:
 
-  inline in_cset_state_t in_cset_state(const oop obj);
+  inline InCSetState in_cset_state(const oop obj);
 
   // Return "TRUE" iff the given object address is in the reserved
   // region of g1.
--- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp	Fri Jan 09 05:45:13 2015 -0800
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp	Fri Jan 09 13:28:02 2015 -0500
@@ -35,6 +35,41 @@
 #include "runtime/orderAccess.inline.hpp"
 #include "utilities/taskqueue.hpp"
 
+PLABStats* G1CollectedHeap::alloc_buffer_stats(InCSetState dest) {
+  switch (dest.value()) {
+    case InCSetState::Young:
+      return &_survivor_plab_stats;
+    case InCSetState::Old:
+      return &_old_plab_stats;
+    default:
+      ShouldNotReachHere();
+      return NULL; // Keep some compilers happy
+  }
+}
+
+size_t G1CollectedHeap::desired_plab_sz(InCSetState dest) {
+  size_t gclab_word_size = alloc_buffer_stats(dest)->desired_plab_sz();
+  // Prevent humongous PLAB sizes for two reasons:
+  // * PLABs are allocated using a similar paths as oops, but should
+  //   never be in a humongous region
+  // * Allowing humongous PLABs needlessly churns the region free lists
+  return MIN2(_humongous_object_threshold_in_words, gclab_word_size);
+}
+
+HeapWord* G1CollectedHeap::par_allocate_during_gc(InCSetState dest,
+                                                  size_t word_size,
+                                                  AllocationContext_t context) {
+  switch (dest.value()) {
+    case InCSetState::Young:
+      return survivor_attempt_allocation(word_size, context);
+    case InCSetState::Old:
+      return old_attempt_allocation(word_size, context);
+    default:
+      ShouldNotReachHere();
+      return NULL; // Keep some compilers happy
+  }
+}
+
 // Inline functions for G1CollectedHeap
 
 inline AllocationContextStats& G1CollectedHeap::allocation_context_stats() {
@@ -203,7 +238,7 @@
   return _in_cset_fast_test.is_in_cset_or_humongous((HeapWord*)obj);
 }
 
-G1CollectedHeap::in_cset_state_t G1CollectedHeap::in_cset_state(const oop obj) {
+InCSetState G1CollectedHeap::in_cset_state(const oop obj) {
   return _in_cset_fast_test.at((HeapWord*)obj);
 }
 
--- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp	Fri Jan 09 05:45:13 2015 -0800
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp	Fri Jan 09 13:28:02 2015 -0500
@@ -1437,18 +1437,6 @@
   return young_list_length < young_list_max_length;
 }
 
-uint G1CollectorPolicy::max_regions(int purpose) {
-  switch (purpose) {
-    case GCAllocForSurvived:
-      return _max_survivor_regions;
-    case GCAllocForTenured:
-      return REGIONS_UNLIMITED;
-    default:
-      ShouldNotReachHere();
-      return REGIONS_UNLIMITED;
-  };
-}
-
 void G1CollectorPolicy::update_max_gc_locker_expansion() {
   uint expansion_region_num = 0;
   if (GCLockerEdenExpansionPercent > 0) {
@@ -1634,7 +1622,7 @@
   hr->set_next_in_collection_set(_collection_set);
   _collection_set = hr;
   _collection_set_bytes_used_before += hr->used();
-  _g1->register_region_with_in_cset_fast_test(hr);
+  _g1->register_old_region_with_in_cset_fast_test(hr);
   size_t rs_length = hr->rem_set()->occupied();
   _recorded_rs_lengths += rs_length;
   _old_cset_region_length += 1;
@@ -1767,7 +1755,7 @@
   hr->set_in_collection_set(true);
   assert( hr->next_in_collection_set() == NULL, "invariant");
 
-  _g1->register_region_with_in_cset_fast_test(hr);
+  _g1->register_young_region_with_in_cset_fast_test(hr);
 }
 
 // Add the region at the RHS of the incremental cset
--- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp	Fri Jan 09 05:45:13 2015 -0800
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp	Fri Jan 09 13:28:02 2015 -0500
@@ -881,28 +881,20 @@
 public:
   uint tenuring_threshold() const { return _tenuring_threshold; }
 
-  inline GCAllocPurpose
-    evacuation_destination(HeapRegion* src_region, uint age, size_t word_sz) {
-      if (age < _tenuring_threshold && src_region->is_young()) {
-        return GCAllocForSurvived;
-      } else {
-        return GCAllocForTenured;
-      }
-  }
-
-  inline bool track_object_age(GCAllocPurpose purpose) {
-    return purpose == GCAllocForSurvived;
-  }
-
   static const uint REGIONS_UNLIMITED = (uint) -1;
 
-  uint max_regions(int purpose);
-
-  // The limit on regions for a particular purpose is reached.
-  void note_alloc_region_limit_reached(int purpose) {
-    if (purpose == GCAllocForSurvived) {
-      _tenuring_threshold = 0;
+  uint max_regions(InCSetState dest) {
+    switch (dest.value()) {
+      case InCSetState::Young:
+        return _max_survivor_regions;
+      case InCSetState::Old:
+        return REGIONS_UNLIMITED;
+      default:
+        assert(false, err_msg("Unknown dest state: " CSETSTATE_FORMAT, dest.value()));
+        break;
     }
+    // keep some compilers happy
+    return 0;
   }
 
   void note_start_adding_survivor_regions() {
--- a/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp	Fri Jan 09 05:45:13 2015 -0800
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp	Fri Jan 09 13:28:02 2015 -0500
@@ -344,11 +344,14 @@
     _last_redirty_logged_cards_time_ms.print(3, "Parallel Redirty");
     _last_redirty_logged_cards_processed_cards.print(3, "Redirtied Cards");
   }
-  if (G1ReclaimDeadHumongousObjectsAtYoungGC) {
-    print_stats(2, "Humongous Reclaim", _cur_fast_reclaim_humongous_time_ms);
+  if (G1EagerReclaimHumongousObjects) {
+    print_stats(2, "Humongous Register", _cur_fast_reclaim_humongous_register_time_ms);
     if (G1Log::finest()) {
       print_stats(3, "Humongous Total", _cur_fast_reclaim_humongous_total);
       print_stats(3, "Humongous Candidate", _cur_fast_reclaim_humongous_candidates);
+    }
+    print_stats(2, "Humongous Reclaim", _cur_fast_reclaim_humongous_time_ms);
+    if (G1Log::finest()) {
       print_stats(3, "Humongous Reclaimed", _cur_fast_reclaim_humongous_reclaimed);
     }
   }
--- a/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp	Fri Jan 09 05:45:13 2015 -0800
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp	Fri Jan 09 13:28:02 2015 -0500
@@ -157,6 +157,7 @@
   double _recorded_non_young_free_cset_time_ms;
 
   double _cur_fast_reclaim_humongous_time_ms;
+  double _cur_fast_reclaim_humongous_register_time_ms;
   size_t _cur_fast_reclaim_humongous_total;
   size_t _cur_fast_reclaim_humongous_candidates;
   size_t _cur_fast_reclaim_humongous_reclaimed;
@@ -283,7 +284,8 @@
     _recorded_non_young_free_cset_time_ms = time_ms;
   }
 
-  void record_fast_reclaim_humongous_stats(size_t total, size_t candidates) {
+  void record_fast_reclaim_humongous_stats(double time_ms, size_t total, size_t candidates) {
+    _cur_fast_reclaim_humongous_register_time_ms = time_ms;
     _cur_fast_reclaim_humongous_total = total;
     _cur_fast_reclaim_humongous_candidates = candidates;
   }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1InCSetState.hpp	Fri Jan 09 13:28:02 2015 -0500
@@ -0,0 +1,132 @@
+/*
+ * 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_G1INCSETSTATE_HPP
+#define SHARE_VM_GC_IMPLEMENTATION_G1_G1INCSETSTATE_HPP
+
+#include "gc_implementation/g1/g1BiasedArray.hpp"
+#include "memory/allocation.hpp"
+
+// Per-region state during garbage collection.
+struct InCSetState {
+ public:
+  // We use different types to represent the state value. Particularly SPARC puts
+  // values in structs from "left to right", i.e. MSB to LSB. This results in many
+  // unnecessary shift operations when loading and storing values of this type.
+  // This degrades performance significantly (>10%) on that platform.
+  // Other tested ABIs do not seem to have this problem, and actually tend to
+  // favor smaller types, so we use the smallest usable type there.
+#ifdef SPARC
+  #define CSETSTATE_FORMAT INTPTR_FORMAT
+  typedef intptr_t in_cset_state_t;
+#else
+  #define CSETSTATE_FORMAT "%d"
+  typedef int8_t in_cset_state_t;
+#endif
+ private:
+  in_cset_state_t _value;
+ public:
+  enum {
+    // Selection of the values were driven to micro-optimize the encoding and
+    // frequency of the checks.
+    // The most common check is whether the region is in the collection set or not.
+    // This encoding allows us to use an != 0 check which in some architectures
+    // (x86*) can be encoded slightly more efficently than a normal comparison
+    // against zero.
+    // The same situation occurs when checking whether the region is humongous
+    // or not, which is encoded by values < 0.
+    // The other values are simply encoded in increasing generation order, which
+    // makes getting the next generation fast by a simple increment.
+    Humongous    = -1,    // The region is humongous - note that actually any value < 0 would be possible here.
+    NotInCSet    =  0,    // The region is not in the collection set.
+    Young        =  1,    // The region is in the collection set and a young region.
+    Old          =  2,    // The region is in the collection set and an old region.
+    Num
+  };
+
+  InCSetState(in_cset_state_t value = NotInCSet) : _value(value) {
+    assert(is_valid(), err_msg("Invalid state %d", _value));
+  }
+
+  in_cset_state_t value() const        { return _value; }
+
+  void set_old()                       { _value = Old; }
+
+  bool is_in_cset_or_humongous() const { return _value != NotInCSet; }
+  bool is_in_cset() const              { return _value > NotInCSet; }
+  bool is_humongous() const            { return _value < NotInCSet; }
+  bool is_young() const                { return _value == Young; }
+  bool is_old() const                  { return _value == Old; }
+
+#ifdef ASSERT
+  bool is_default() const              { return !is_in_cset_or_humongous(); }
+  bool is_valid() const                { return (_value >= Humongous) && (_value < Num); }
+  bool is_valid_gen() const            { return (_value >= Young && _value <= Old); }
+#endif
+};
+
+// Instances of this class are used for quick tests on whether a reference points
+// into the collection set and into which generation or is a humongous object
+//
+// Each of the array's elements indicates whether the corresponding region is in
+// the collection set and if so in which generation, or a humongous region.
+//
+// We use this to speed up reference processing during young collection and
+// quickly reclaim humongous objects. For the latter, by making a humongous region
+// succeed this test, we sort-of add it to the collection set. During the reference
+// iteration closures, when we see a humongous region, we then simply mark it as
+// referenced, i.e. live.
+class G1InCSetStateFastTestBiasedMappedArray : public G1BiasedMappedArray<InCSetState> {
+ protected:
+  InCSetState default_value() const { return InCSetState::NotInCSet; }
+ public:
+  void set_humongous(uintptr_t index) {
+    assert(get_by_index(index).is_default(),
+           err_msg("State at index " INTPTR_FORMAT" should be default but is " CSETSTATE_FORMAT, index, get_by_index(index).value()));
+    set_by_index(index, InCSetState::Humongous);
+  }
+
+  void clear_humongous(uintptr_t index) {
+    set_by_index(index, InCSetState::NotInCSet);
+  }
+
+  void set_in_young(uintptr_t index) {
+    assert(get_by_index(index).is_default(),
+           err_msg("State at index " INTPTR_FORMAT" should be default but is " CSETSTATE_FORMAT, index, get_by_index(index).value()));
+    set_by_index(index, InCSetState::Young);
+  }
+
+  void set_in_old(uintptr_t index) {
+    assert(get_by_index(index).is_default(),
+           err_msg("State at index " INTPTR_FORMAT" should be default but is " CSETSTATE_FORMAT, index, get_by_index(index).value()));
+    set_by_index(index, InCSetState::Old);
+  }
+
+  bool is_in_cset_or_humongous(HeapWord* addr) const { return at(addr).is_in_cset_or_humongous(); }
+  bool is_in_cset(HeapWord* addr) const { return at(addr).is_in_cset(); }
+  InCSetState at(HeapWord* addr) const { return get_by_address(addr); }
+  void clear() { G1BiasedMappedArray<InCSetState>::clear(); }
+};
+
+#endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1INCSETSTATE_HPP
--- a/hotspot/src/share/vm/gc_implementation/g1/g1OopClosures.hpp	Fri Jan 09 05:45:13 2015 -0800
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1OopClosures.hpp	Fri Jan 09 13:28:02 2015 -0500
@@ -26,6 +26,7 @@
 #define SHARE_VM_GC_IMPLEMENTATION_G1_G1OOPCLOSURES_HPP
 
 #include "memory/iterator.hpp"
+#include "oops/markOop.hpp"
 
 class HeapRegion;
 class G1CollectedHeap;
@@ -239,14 +240,14 @@
   G1CollectedHeap* _g1;
   G1RemSet* _g1_rem_set;
   HeapRegion* _from;
-  OopsInHeapRegionClosure* _push_ref_cl;
+  G1ParPushHeapRSClosure* _push_ref_cl;
   bool _record_refs_into_cset;
   uint _worker_i;
 
 public:
   G1UpdateRSOrPushRefOopClosure(G1CollectedHeap* g1h,
                                 G1RemSet* rs,
-                                OopsInHeapRegionClosure* push_ref_cl,
+                                G1ParPushHeapRSClosure* push_ref_cl,
                                 bool record_refs_into_cset,
                                 uint worker_i = 0);
 
@@ -256,7 +257,8 @@
   }
 
   bool self_forwarded(oop obj) {
-    bool result = (obj->is_forwarded() && (obj->forwardee()== obj));
+    markOop m = obj->mark();
+    bool result = (m->is_marked() && ((oop)m->decode_pointer() == obj));
     return result;
   }
 
--- a/hotspot/src/share/vm/gc_implementation/g1/g1OopClosures.inline.hpp	Fri Jan 09 05:45:13 2015 -0800
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1OopClosures.inline.hpp	Fri Jan 09 13:28:02 2015 -0500
@@ -67,8 +67,8 @@
 
   if (!oopDesc::is_null(heap_oop)) {
     oop obj = oopDesc::decode_heap_oop_not_null(heap_oop);
-    G1CollectedHeap::in_cset_state_t state = _g1->in_cset_state(obj);
-    if (state == G1CollectedHeap::InCSet) {
+    const InCSetState state = _g1->in_cset_state(obj);
+    if (state.is_in_cset()) {
       // We're not going to even bother checking whether the object is
       // already forwarded or not, as this usually causes an immediate
       // stall. We'll try to prefetch the object (for write, given that
@@ -87,7 +87,7 @@
 
       _par_scan_state->push_on_queue(p);
     } else {
-      if (state == G1CollectedHeap::IsHumongous) {
+      if (state.is_humongous()) {
         _g1->set_humongous_is_live(obj);
       }
       _par_scan_state->update_rs(_from, p, _worker_id);
--- a/hotspot/src/share/vm/gc_implementation/g1/g1PageBasedVirtualSpace.cpp	Fri Jan 09 05:45:13 2015 -0800
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1PageBasedVirtualSpace.cpp	Fri Jan 09 13:28:02 2015 -0500
@@ -131,6 +131,9 @@
   _committed.set_range(start, start + size_in_pages);
 
   MemRegion result((HeapWord*)page_start(start), byte_size_for_pages(size_in_pages) / HeapWordSize);
+  if (AlwaysPreTouch) {
+    os::pretouch_memory((char*)result.start(), (char*)result.end());
+  }
   return result;
 }
 
--- a/hotspot/src/share/vm/gc_implementation/g1/g1ParScanThreadState.cpp	Fri Jan 09 05:45:13 2015 -0800
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1ParScanThreadState.cpp	Fri Jan 09 13:28:02 2015 -0500
@@ -38,6 +38,7 @@
     _g1_rem(g1h->g1_rem_set()),
     _hash_seed(17), _queue_num(queue_num),
     _term_attempts(0),
+    _tenuring_threshold(g1h->g1_policy()->tenuring_threshold()),
     _age_table(false), _scanner(g1h, rp),
     _strong_roots_time(0), _term_time(0) {
   _scanner.set_par_scan_thread_state(this);
@@ -59,6 +60,12 @@
 
   _g1_par_allocator = G1ParGCAllocator::create_allocator(_g1h);
 
+  _dest[InCSetState::NotInCSet]    = InCSetState::NotInCSet;
+  // The dest for Young is used when the objects are aged enough to
+  // need to be moved to the next space.
+  _dest[InCSetState::Young]        = InCSetState::Old;
+  _dest[InCSetState::Old]          = InCSetState::Old;
+
   _start = os::elapsedTime();
 }
 
@@ -150,52 +157,94 @@
   } while (!_refs->is_empty());
 }
 
-oop G1ParScanThreadState::copy_to_survivor_space(oop const old,
+HeapWord* G1ParScanThreadState::allocate_in_next_plab(InCSetState const state,
+                                                      InCSetState* dest,
+                                                      size_t word_sz,
+                                                      AllocationContext_t const context) {
+  assert(state.is_in_cset_or_humongous(), err_msg("Unexpected state: " CSETSTATE_FORMAT, state.value()));
+  assert(dest->is_in_cset_or_humongous(), err_msg("Unexpected dest: " CSETSTATE_FORMAT, dest->value()));
+
+  // Right now we only have two types of regions (young / old) so
+  // let's keep the logic here simple. We can generalize it when necessary.
+  if (dest->is_young()) {
+    HeapWord* const obj_ptr = _g1_par_allocator->allocate(InCSetState::Old,
+                                                          word_sz, context);
+    if (obj_ptr == NULL) {
+      return NULL;
+    }
+    // Make sure that we won't attempt to copy any other objects out
+    // of a survivor region (given that apparently we cannot allocate
+    // any new ones) to avoid coming into this slow path.
+    _tenuring_threshold = 0;
+    dest->set_old();
+    return obj_ptr;
+  } else {
+    assert(dest->is_old(), err_msg("Unexpected dest: " CSETSTATE_FORMAT, dest->value()));
+    // no other space to try.
+    return NULL;
+  }
+}
+
+InCSetState G1ParScanThreadState::next_state(InCSetState const state, markOop const m, uint& age) {
+  if (state.is_young()) {
+    age = !m->has_displaced_mark_helper() ? m->age()
+                                          : m->displaced_mark_helper()->age();
+    if (age < _tenuring_threshold) {
+      return state;
+    }
+  }
+  return dest(state);
+}
+
+oop G1ParScanThreadState::copy_to_survivor_space(InCSetState const state,
+                                                 oop const old,
                                                  markOop const old_mark) {
-  size_t word_sz = old->size();
-  HeapRegion* from_region = _g1h->heap_region_containing_raw(old);
+  const size_t word_sz = old->size();
+  HeapRegion* const from_region = _g1h->heap_region_containing_raw(old);
   // +1 to make the -1 indexes valid...
-  int       young_index = from_region->young_index_in_cset()+1;
+  const int young_index = from_region->young_index_in_cset()+1;
   assert( (from_region->is_young() && young_index >  0) ||
          (!from_region->is_young() && young_index == 0), "invariant" );
-  G1CollectorPolicy* g1p = _g1h->g1_policy();
-  uint age = old_mark->has_displaced_mark_helper() ? old_mark->displaced_mark_helper()->age()
-                                                   : old_mark->age();
-  GCAllocPurpose alloc_purpose = g1p->evacuation_destination(from_region, age,
-                                                             word_sz);
-  AllocationContext_t context = from_region->allocation_context();
-  HeapWord* obj_ptr = _g1_par_allocator->allocate(alloc_purpose, word_sz, context);
+  const AllocationContext_t context = from_region->allocation_context();
+
+  uint age = 0;
+  InCSetState dest_state = next_state(state, old_mark, age);
+  HeapWord* obj_ptr = _g1_par_allocator->plab_allocate(dest_state, word_sz, context);
+
+  // PLAB allocations should succeed most of the time, so we'll
+  // normally check against NULL once and that's it.
+  if (obj_ptr == NULL) {
+    obj_ptr = _g1_par_allocator->allocate_direct_or_new_plab(dest_state, word_sz, context);
+    if (obj_ptr == NULL) {
+      obj_ptr = allocate_in_next_plab(state, &dest_state, word_sz, context);
+      if (obj_ptr == NULL) {
+        // This will either forward-to-self, or detect that someone else has
+        // installed a forwarding pointer.
+        return _g1h->handle_evacuation_failure_par(this, old);
+      }
+    }
+  }
+
+  assert(obj_ptr != NULL, "when we get here, allocation should have succeeded");
 #ifndef PRODUCT
   // Should this evacuation fail?
   if (_g1h->evacuation_should_fail()) {
-    if (obj_ptr != NULL) {
-      _g1_par_allocator->undo_allocation(alloc_purpose, obj_ptr, word_sz, context);
-      obj_ptr = NULL;
-    }
+    // Doing this after all the allocation attempts also tests the
+    // undo_allocation() method too.
+    _g1_par_allocator->undo_allocation(dest_state, obj_ptr, word_sz, context);
+    return _g1h->handle_evacuation_failure_par(this, old);
   }
 #endif // !PRODUCT
 
-  if (obj_ptr == NULL) {
-    // This will either forward-to-self, or detect that someone else has
-    // installed a forwarding pointer.
-    return _g1h->handle_evacuation_failure_par(this, old);
-  }
-
-  oop obj = oop(obj_ptr);
-
   // We're going to allocate linearly, so might as well prefetch ahead.
   Prefetch::write(obj_ptr, PrefetchCopyIntervalInBytes);
 
-  oop forward_ptr = old->forward_to_atomic(obj);
+  const oop obj = oop(obj_ptr);
+  const oop forward_ptr = old->forward_to_atomic(obj);
   if (forward_ptr == NULL) {
     Copy::aligned_disjoint_words((HeapWord*) old, obj_ptr, word_sz);
 
-    // alloc_purpose is just a hint to allocate() above, recheck the type of region
-    // we actually allocated from and update alloc_purpose accordingly
-    HeapRegion* to_region = _g1h->heap_region_containing_raw(obj_ptr);
-    alloc_purpose = to_region->is_young() ? GCAllocForSurvived : GCAllocForTenured;
-
-    if (g1p->track_object_age(alloc_purpose)) {
+    if (dest_state.is_young()) {
       if (age < markOopDesc::max_age) {
         age++;
       }
@@ -215,13 +264,19 @@
     }
 
     if (G1StringDedup::is_enabled()) {
-      G1StringDedup::enqueue_from_evacuation(from_region->is_young(),
-                                             to_region->is_young(),
+      const bool is_from_young = state.is_young();
+      const bool is_to_young = dest_state.is_young();
+      assert(is_from_young == _g1h->heap_region_containing_raw(old)->is_young(),
+             "sanity");
+      assert(is_to_young == _g1h->heap_region_containing_raw(obj)->is_young(),
+             "sanity");
+      G1StringDedup::enqueue_from_evacuation(is_from_young,
+                                             is_to_young,
                                              queue_num(),
                                              obj);
     }
 
-    size_t* surv_young_words = surviving_young_words();
+    size_t* const surv_young_words = surviving_young_words();
     surv_young_words[young_index] += word_sz;
 
     if (obj->is_objArray() && arrayOop(obj)->length() >= ParGCArrayScanChunk) {
@@ -232,14 +287,13 @@
       oop* old_p = set_partial_array_mask(old);
       push_on_queue(old_p);
     } else {
-      // No point in using the slower heap_region_containing() method,
-      // given that we know obj is in the heap.
-      _scanner.set_region(_g1h->heap_region_containing_raw(obj));
+      HeapRegion* const to_region = _g1h->heap_region_containing_raw(obj_ptr);
+      _scanner.set_region(to_region);
       obj->oop_iterate_backwards(&_scanner);
     }
+    return obj;
   } else {
-    _g1_par_allocator->undo_allocation(alloc_purpose, obj_ptr, word_sz, context);
-    obj = forward_ptr;
+    _g1_par_allocator->undo_allocation(dest_state, obj_ptr, word_sz, context);
+    return forward_ptr;
   }
-  return obj;
 }
--- a/hotspot/src/share/vm/gc_implementation/g1/g1ParScanThreadState.hpp	Fri Jan 09 05:45:13 2015 -0800
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1ParScanThreadState.hpp	Fri Jan 09 13:28:02 2015 -0500
@@ -46,14 +46,16 @@
   G1SATBCardTableModRefBS* _ct_bs;
   G1RemSet* _g1_rem;
 
-  G1ParGCAllocator*   _g1_par_allocator;
+  G1ParGCAllocator* _g1_par_allocator;
 
-  ageTable            _age_table;
+  ageTable          _age_table;
+  InCSetState       _dest[InCSetState::Num];
+  // Local tenuring threshold.
+  uint              _tenuring_threshold;
+  G1ParScanClosure  _scanner;
 
-  G1ParScanClosure    _scanner;
-
-  size_t           _alloc_buffer_waste;
-  size_t           _undo_waste;
+  size_t            _alloc_buffer_waste;
+  size_t            _undo_waste;
 
   OopsInHeapRegionClosure*      _evac_failure_cl;
 
@@ -82,6 +84,14 @@
   DirtyCardQueue& dirty_card_queue()             { return _dcq;  }
   G1SATBCardTableModRefBS* ctbs()                { return _ct_bs; }
 
+  InCSetState dest(InCSetState original) const {
+    assert(original.is_valid(),
+           err_msg("Original state invalid: " CSETSTATE_FORMAT, original.value()));
+    assert(_dest[original.value()].is_valid_gen(),
+           err_msg("Dest state is invalid: " CSETSTATE_FORMAT, _dest[original.value()].value()));
+    return _dest[original.value()];
+  }
+
  public:
   G1ParScanThreadState(G1CollectedHeap* g1h, uint queue_num, ReferenceProcessor* rp);
   ~G1ParScanThreadState();
@@ -112,7 +122,6 @@
       }
     }
   }
- public:
 
   void set_evac_failure_closure(OopsInHeapRegionClosure* evac_failure_cl) {
     _evac_failure_cl = evac_failure_cl;
@@ -193,9 +202,20 @@
   template <class T> inline void deal_with_reference(T* ref_to_scan);
 
   inline void dispatch_reference(StarTask ref);
+
+  // Tries to allocate word_sz in the PLAB of the next "generation" after trying to
+  // allocate into dest. State is the original (source) cset state for the object
+  // that is allocated for.
+  // Returns a non-NULL pointer if successful, and updates dest if required.
+  HeapWord* allocate_in_next_plab(InCSetState const state,
+                                  InCSetState* dest,
+                                  size_t word_sz,
+                                  AllocationContext_t const context);
+
+  inline InCSetState next_state(InCSetState const state, markOop const m, uint& age);
  public:
 
-  oop copy_to_survivor_space(oop const obj, markOop const old_mark);
+  oop copy_to_survivor_space(InCSetState const state, oop const obj, markOop const old_mark);
 
   void trim_queue();
 
--- a/hotspot/src/share/vm/gc_implementation/g1/g1ParScanThreadState.inline.hpp	Fri Jan 09 05:45:13 2015 -0800
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1ParScanThreadState.inline.hpp	Fri Jan 09 13:28:02 2015 -0500
@@ -38,21 +38,21 @@
   // set, due to (benign) races in the claim mechanism during RSet scanning more
   // than one thread might claim the same card. So the same card may be
   // processed multiple times. So redo this check.
-  G1CollectedHeap::in_cset_state_t in_cset_state = _g1h->in_cset_state(obj);
-  if (in_cset_state == G1CollectedHeap::InCSet) {
+  const InCSetState in_cset_state = _g1h->in_cset_state(obj);
+  if (in_cset_state.is_in_cset()) {
     oop forwardee;
     markOop m = obj->mark();
     if (m->is_marked()) {
       forwardee = (oop) m->decode_pointer();
     } else {
-      forwardee = copy_to_survivor_space(obj, m);
+      forwardee = copy_to_survivor_space(in_cset_state, obj, m);
     }
     oopDesc::encode_store_heap_oop(p, forwardee);
-  } else if (in_cset_state == G1CollectedHeap::IsHumongous) {
+  } else if (in_cset_state.is_humongous()) {
     _g1h->set_humongous_is_live(obj);
   } else {
-    assert(in_cset_state == G1CollectedHeap::InNeither,
-           err_msg("In_cset_state must be InNeither here, but is %d", in_cset_state));
+    assert(!in_cset_state.is_in_cset_or_humongous(),
+           err_msg("In_cset_state must be NotInCSet here, but is " CSETSTATE_FORMAT, in_cset_state.value()));
   }
 
   assert(obj != NULL, "Must be");
--- a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp	Fri Jan 09 05:45:13 2015 -0800
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp	Fri Jan 09 13:28:02 2015 -0500
@@ -80,7 +80,7 @@
     _prev_period_summary()
 {
   _seq_task = new SubTasksDone(NumSeqTasks);
-  _cset_rs_update_cl = NEW_C_HEAP_ARRAY(OopsInHeapRegionClosure*, n_workers(), mtGC);
+  _cset_rs_update_cl = NEW_C_HEAP_ARRAY(G1ParPushHeapRSClosure*, n_workers(), mtGC);
   for (uint i = 0; i < n_workers(); i++) {
     _cset_rs_update_cl[i] = NULL;
   }
@@ -94,14 +94,14 @@
   for (uint i = 0; i < n_workers(); i++) {
     assert(_cset_rs_update_cl[i] == NULL, "it should be");
   }
-  FREE_C_HEAP_ARRAY(OopsInHeapRegionClosure*, _cset_rs_update_cl);
+  FREE_C_HEAP_ARRAY(G1ParPushHeapRSClosure*, _cset_rs_update_cl);
 }
 
 class ScanRSClosure : public HeapRegionClosure {
   size_t _cards_done, _cards;
   G1CollectedHeap* _g1h;
 
-  OopsInHeapRegionClosure* _oc;
+  G1ParPushHeapRSClosure* _oc;
   CodeBlobClosure* _code_root_cl;
 
   G1BlockOffsetSharedArray* _bot_shared;
@@ -113,7 +113,7 @@
   bool   _try_claimed;
 
 public:
-  ScanRSClosure(OopsInHeapRegionClosure* oc,
+  ScanRSClosure(G1ParPushHeapRSClosure* oc,
                 CodeBlobClosure* code_root_cl,
                 uint worker_i) :
     _oc(oc),
@@ -135,8 +135,7 @@
   void scanCard(size_t index, HeapRegion *r) {
     // Stack allocate the DirtyCardToOopClosure instance
     HeapRegionDCTOC cl(_g1h, r, _oc,
-                       CardTableModRefBS::Precise,
-                       HeapRegionDCTOC::IntoCSFilterKind);
+                       CardTableModRefBS::Precise);
 
     // Set the "from" region in the closure.
     _oc->set_region(r);
@@ -231,7 +230,7 @@
   size_t cards_looked_up() { return _cards;}
 };
 
-void G1RemSet::scanRS(OopsInHeapRegionClosure* oc,
+void G1RemSet::scanRS(G1ParPushHeapRSClosure* oc,
                       CodeBlobClosure* code_root_cl,
                       uint worker_i) {
   double rs_time_start = os::elapsedTime();
@@ -301,7 +300,7 @@
   HeapRegionRemSet::cleanup();
 }
 
-void G1RemSet::oops_into_collection_set_do(OopsInHeapRegionClosure* oc,
+void G1RemSet::oops_into_collection_set_do(G1ParPushHeapRSClosure* oc,
                                            CodeBlobClosure* code_root_cl,
                                            uint worker_i) {
 #if CARD_REPEAT_HISTO
@@ -417,7 +416,7 @@
 G1UpdateRSOrPushRefOopClosure::
 G1UpdateRSOrPushRefOopClosure(G1CollectedHeap* g1h,
                               G1RemSet* rs,
-                              OopsInHeapRegionClosure* push_ref_cl,
+                              G1ParPushHeapRSClosure* push_ref_cl,
                               bool record_refs_into_cset,
                               uint worker_i) :
   _g1(g1h), _g1_rem_set(rs), _from(NULL),
@@ -518,7 +517,7 @@
   ct_freq_note_card(_ct_bs->index_for(start));
 #endif
 
-  OopsInHeapRegionClosure* oops_in_heap_closure = NULL;
+  G1ParPushHeapRSClosure* oops_in_heap_closure = NULL;
   if (check_for_refs_into_cset) {
     // ConcurrentG1RefineThreads have worker numbers larger than what
     // _cset_rs_update_cl[] is set up to handle. But those threads should
--- a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.hpp	Fri Jan 09 05:45:13 2015 -0800
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.hpp	Fri Jan 09 13:28:02 2015 -0500
@@ -33,6 +33,7 @@
 class G1CollectedHeap;
 class CardTableModRefBarrierSet;
 class ConcurrentG1Refine;
+class G1ParPushHeapRSClosure;
 
 // A G1RemSet in which each heap region has a rem set that records the
 // external heap references into it.  Uses a mod ref bs to track updates,
@@ -68,7 +69,7 @@
 
   // Used for caching the closure that is responsible for scanning
   // references into the collection set.
-  OopsInHeapRegionClosure** _cset_rs_update_cl;
+  G1ParPushHeapRSClosure** _cset_rs_update_cl;
 
   // Print the given summary info
   virtual void print_summary_info(G1RemSetSummary * summary, const char * header = NULL);
@@ -95,7 +96,7 @@
   // partitioning the work to be done. It should be the same as
   // the "i" passed to the calling thread's work(i) function.
   // In the sequential case this param will be ignored.
-  void oops_into_collection_set_do(OopsInHeapRegionClosure* blk,
+  void oops_into_collection_set_do(G1ParPushHeapRSClosure* blk,
                                    CodeBlobClosure* code_root_cl,
                                    uint worker_i);
 
@@ -107,7 +108,7 @@
   void prepare_for_oops_into_collection_set_do();
   void cleanup_after_oops_into_collection_set_do();
 
-  void scanRS(OopsInHeapRegionClosure* oc,
+  void scanRS(G1ParPushHeapRSClosure* oc,
               CodeBlobClosure* code_root_cl,
               uint worker_i);
 
--- a/hotspot/src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.cpp	Fri Jan 09 05:45:13 2015 -0800
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.cpp	Fri Jan 09 13:28:02 2015 -0500
@@ -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
@@ -33,7 +33,7 @@
 #include "runtime/thread.inline.hpp"
 
 G1SATBCardTableModRefBS::G1SATBCardTableModRefBS(MemRegion whole_heap) :
-    CardTableModRefBSForCTRS(whole_heap)
+    CardTableModRefBS(whole_heap)
 {
   _kind = G1SATBCT;
 }
--- a/hotspot/src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.hpp	Fri Jan 09 05:45:13 2015 -0800
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.hpp	Fri Jan 09 13:28:02 2015 -0500
@@ -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
@@ -37,7 +37,7 @@
 // This barrier is specialized to use a logging barrier to support
 // snapshot-at-the-beginning marking.
 
-class G1SATBCardTableModRefBS: public CardTableModRefBSForCTRS {
+class G1SATBCardTableModRefBS: public CardTableModRefBS {
 protected:
   enum G1CardValues {
     g1_young_gen = CT_MR_BS_last_reserved << 1
--- a/hotspot/src/share/vm/gc_implementation/g1/g1_globals.hpp	Fri Jan 09 05:45:13 2015 -0800
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1_globals.hpp	Fri Jan 09 13:28:02 2015 -0500
@@ -270,10 +270,14 @@
   product(uintx, G1MixedGCCountTarget, 8,                                   \
           "The target number of mixed GCs after a marking cycle.")          \
                                                                             \
-  experimental(bool, G1ReclaimDeadHumongousObjectsAtYoungGC, true,          \
+  experimental(bool, G1EagerReclaimHumongousObjects, true,                  \
           "Try to reclaim dead large objects at every young GC.")           \
                                                                             \
-  experimental(bool, G1TraceReclaimDeadHumongousObjectsAtYoungGC, false,    \
+  experimental(bool, G1EagerReclaimHumongousObjectsWithStaleRefs, true,     \
+          "Try to reclaim dead large objects that have a few stale "        \
+          "references at every young GC.")                                  \
+                                                                            \
+  experimental(bool, G1TraceEagerReclaimHumongousObjects, false,            \
           "Print some information about large object liveness "             \
           "at every young GC.")                                             \
                                                                             \
--- a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp	Fri Jan 09 05:45:13 2015 -0800
+++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp	Fri Jan 09 13:28:02 2015 -0500
@@ -48,93 +48,55 @@
 size_t HeapRegion::CardsPerRegion    = 0;
 
 HeapRegionDCTOC::HeapRegionDCTOC(G1CollectedHeap* g1,
-                                 HeapRegion* hr, ExtendedOopClosure* cl,
-                                 CardTableModRefBS::PrecisionStyle precision,
-                                 FilterKind fk) :
+                                 HeapRegion* hr,
+                                 G1ParPushHeapRSClosure* cl,
+                                 CardTableModRefBS::PrecisionStyle precision) :
   DirtyCardToOopClosure(hr, cl, precision, NULL),
-  _hr(hr), _fk(fk), _g1(g1) { }
+  _hr(hr), _rs_scan(cl), _g1(g1) { }
 
 FilterOutOfRegionClosure::FilterOutOfRegionClosure(HeapRegion* r,
                                                    OopClosure* oc) :
   _r_bottom(r->bottom()), _r_end(r->end()), _oc(oc) { }
 
-template<class ClosureType>
-HeapWord* walk_mem_region_loop(ClosureType* cl, G1CollectedHeap* g1h,
-                               HeapRegion* hr,
-                               HeapWord* cur, HeapWord* top) {
-  oop cur_oop = oop(cur);
-  size_t oop_size = hr->block_size(cur);
-  HeapWord* next_obj = cur + oop_size;
-  while (next_obj < top) {
-    // Keep filtering the remembered set.
-    if (!g1h->is_obj_dead(cur_oop, hr)) {
-      // Bottom lies entirely below top, so we can call the
-      // non-memRegion version of oop_iterate below.
-      cur_oop->oop_iterate(cl);
-    }
-    cur = next_obj;
-    cur_oop = oop(cur);
-    oop_size = hr->block_size(cur);
-    next_obj = cur + oop_size;
-  }
-  return cur;
-}
-
 void HeapRegionDCTOC::walk_mem_region(MemRegion mr,
                                       HeapWord* bottom,
                                       HeapWord* top) {
   G1CollectedHeap* g1h = _g1;
   size_t oop_size;
-  ExtendedOopClosure* cl2 = NULL;
-
-  FilterIntoCSClosure intoCSFilt(this, g1h, _cl);
-  FilterOutOfRegionClosure outOfRegionFilt(_hr, _cl);
-
-  switch (_fk) {
-  case NoFilterKind:          cl2 = _cl; break;
-  case IntoCSFilterKind:      cl2 = &intoCSFilt; break;
-  case OutOfRegionFilterKind: cl2 = &outOfRegionFilt; break;
-  default:                    ShouldNotReachHere();
-  }
+  HeapWord* cur = bottom;
 
   // Start filtering what we add to the remembered set. If the object is
   // not considered dead, either because it is marked (in the mark bitmap)
   // or it was allocated after marking finished, then we add it. Otherwise
   // we can safely ignore the object.
-  if (!g1h->is_obj_dead(oop(bottom), _hr)) {
-    oop_size = oop(bottom)->oop_iterate(cl2, mr);
+  if (!g1h->is_obj_dead(oop(cur), _hr)) {
+    oop_size = oop(cur)->oop_iterate(_rs_scan, mr);
   } else {
-    oop_size = _hr->block_size(bottom);
+    oop_size = _hr->block_size(cur);
   }
 
-  bottom += oop_size;
+  cur += oop_size;
 
-  if (bottom < top) {
-    // We replicate the loop below for several kinds of possible filters.
-    switch (_fk) {
-    case NoFilterKind:
-      bottom = walk_mem_region_loop(_cl, g1h, _hr, bottom, top);
-      break;
-
-    case IntoCSFilterKind: {
-      FilterIntoCSClosure filt(this, g1h, _cl);
-      bottom = walk_mem_region_loop(&filt, g1h, _hr, bottom, top);
-      break;
-    }
-
-    case OutOfRegionFilterKind: {
-      FilterOutOfRegionClosure filt(_hr, _cl);
-      bottom = walk_mem_region_loop(&filt, g1h, _hr, bottom, top);
-      break;
-    }
-
-    default:
-      ShouldNotReachHere();
+  if (cur < top) {
+    oop cur_oop = oop(cur);
+    oop_size = _hr->block_size(cur);
+    HeapWord* next_obj = cur + oop_size;
+    while (next_obj < top) {
+      // Keep filtering the remembered set.
+      if (!g1h->is_obj_dead(cur_oop, _hr)) {
+        // Bottom lies entirely below top, so we can call the
+        // non-memRegion version of oop_iterate below.
+        cur_oop->oop_iterate(_rs_scan);
+      }
+      cur = next_obj;
+      cur_oop = oop(cur);
+      oop_size = _hr->block_size(cur);
+      next_obj = cur + oop_size;
     }
 
     // Last object. Need to do dead-obj filtering here too.
-    if (!g1h->is_obj_dead(oop(bottom), _hr)) {
-      oop(bottom)->oop_iterate(cl2, mr);
+    if (!g1h->is_obj_dead(oop(cur), _hr)) {
+      oop(cur)->oop_iterate(_rs_scan, mr);
     }
   }
 }
--- a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp	Fri Jan 09 05:45:13 2015 -0800
+++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp	Fri Jan 09 13:28:02 2015 -0500
@@ -67,17 +67,9 @@
 // sets.
 
 class HeapRegionDCTOC : public DirtyCardToOopClosure {
-public:
-  // Specification of possible DirtyCardToOopClosure filtering.
-  enum FilterKind {
-    NoFilterKind,
-    IntoCSFilterKind,
-    OutOfRegionFilterKind
-  };
-
-protected:
+private:
   HeapRegion* _hr;
-  FilterKind _fk;
+  G1ParPushHeapRSClosure* _rs_scan;
   G1CollectedHeap* _g1;
 
   // Walk the given memory region from bottom to (actual) top
@@ -90,9 +82,9 @@
 
 public:
   HeapRegionDCTOC(G1CollectedHeap* g1,
-                  HeapRegion* hr, ExtendedOopClosure* cl,
-                  CardTableModRefBS::PrecisionStyle precision,
-                  FilterKind fk);
+                  HeapRegion* hr,
+                  G1ParPushHeapRSClosure* cl,
+                  CardTableModRefBS::PrecisionStyle precision);
 };
 
 // The complicating factor is that BlockOffsetTable diverged
--- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp	Fri Jan 09 05:45:13 2015 -0800
+++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp	Fri Jan 09 13:28:02 2015 -0500
@@ -681,6 +681,18 @@
   clear_fcc();
 }
 
+bool OtherRegionsTable::occupancy_less_or_equal_than(size_t limit) const {
+  if (limit <= (size_t)G1RSetSparseRegionEntries) {
+    return occ_coarse() == 0 && _first_all_fine_prts == NULL && occ_sparse() <= limit;
+  } else {
+    // Current uses of this method may only use values less than G1RSetSparseRegionEntries
+    // for the limit. The solution, comparing against occupied() would be too slow
+    // at this time.
+    Unimplemented();
+    return false;
+  }
+}
+
 bool OtherRegionsTable::is_empty() const {
   return occ_sparse() == 0 && occ_coarse() == 0 && _first_all_fine_prts == NULL;
 }
--- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp	Fri Jan 09 05:45:13 2015 -0800
+++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp	Fri Jan 09 13:28:02 2015 -0500
@@ -183,6 +183,10 @@
   // Returns whether the remembered set contains the given reference.
   bool contains_reference(OopOrNarrowOopStar from) const;
 
+  // Returns whether this remembered set (and all sub-sets) have an occupancy
+  // that is less or equal than the given occupancy.
+  bool occupancy_less_or_equal_than(size_t limit) const;
+
   // Removes any entries shown by the given bitmaps to contain only dead
   // objects. Not thread safe.
   // Set bits in the bitmaps indicate that the given region or card is live.
@@ -261,6 +265,10 @@
     return (strong_code_roots_list_length() == 0) && _other_regions.is_empty();
   }
 
+  bool occupancy_less_or_equal_than(size_t occ) const {
+    return (strong_code_roots_list_length() == 0) && _other_regions.occupancy_less_or_equal_than(occ);
+  }
+
   size_t occupied() {
     MutexLockerEx x(&_m, Mutex::_no_safepoint_check_flag);
     return occupied_locked();
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp	Fri Jan 09 05:45:13 2015 -0800
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp	Fri Jan 09 13:28:02 2015 -0500
@@ -195,7 +195,7 @@
 
     COMPILER2_PRESENT(DerivedPointerTable::clear());
 
-    ref_processor()->enable_discovery(true /*verify_disabled*/, true /*verify_no_refs*/);
+    ref_processor()->enable_discovery();
     ref_processor()->setup_policy(clear_all_softrefs);
 
     mark_sweep_phase1(clear_all_softrefs);
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp	Fri Jan 09 05:45:13 2015 -0800
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp	Fri Jan 09 13:28:02 2015 -0500
@@ -2069,7 +2069,7 @@
 
     COMPILER2_PRESENT(DerivedPointerTable::clear());
 
-    ref_processor()->enable_discovery(true /*verify_disabled*/, true /*verify_no_refs*/);
+    ref_processor()->enable_discovery();
     ref_processor()->setup_policy(maximum_heap_compaction);
 
     bool marked_for_unloading = false;
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp	Fri Jan 09 05:45:13 2015 -0800
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp	Fri Jan 09 13:28:02 2015 -0500
@@ -362,7 +362,7 @@
 
     COMPILER2_PRESENT(DerivedPointerTable::clear());
 
-    reference_processor()->enable_discovery(true /*verify_disabled*/, true /*verify_no_refs*/);
+    reference_processor()->enable_discovery();
     reference_processor()->setup_policy(false);
 
     // We track how much was promoted to the next generation for
--- a/hotspot/src/share/vm/gc_implementation/shared/mutableSpace.cpp	Fri Jan 09 05:45:13 2015 -0800
+++ b/hotspot/src/share/vm/gc_implementation/shared/mutableSpace.cpp	Fri Jan 09 13:28:02 2015 -0500
@@ -63,9 +63,7 @@
 }
 
 void MutableSpace::pretouch_pages(MemRegion mr) {
-  for (volatile char *p = (char*)mr.start(); p < (char*)mr.end(); p += os::vm_page_size()) {
-    char t = *p; *p = t;
-  }
+  os::pretouch_memory((char*)mr.start(), (char*)mr.end());
 }
 
 void MutableSpace::initialize(MemRegion mr,
--- a/hotspot/src/share/vm/memory/cardTableRS.cpp	Fri Jan 09 05:45:13 2015 -0800
+++ b/hotspot/src/share/vm/memory/cardTableRS.cpp	Fri Jan 09 13:28:02 2015 -0500
@@ -33,24 +33,13 @@
 #include "runtime/java.hpp"
 #include "runtime/os.hpp"
 #include "utilities/macros.hpp"
-#if INCLUDE_ALL_GCS
-#include "gc_implementation/g1/concurrentMark.hpp"
-#include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp"
-#endif // INCLUDE_ALL_GCS
 
 CardTableRS::CardTableRS(MemRegion whole_heap) :
   GenRemSet(),
   _cur_youngergen_card_val(youngergenP1_card)
 {
-#if INCLUDE_ALL_GCS
-  if (UseG1GC) {
-      _ct_bs = new G1SATBCardTableLoggingModRefBS(whole_heap);
-  } else {
-    _ct_bs = new CardTableModRefBSForCTRS(whole_heap);
-  }
-#else
+  guarantee(Universe::heap()->kind() == CollectedHeap::GenCollectedHeap, "sanity");
   _ct_bs = new CardTableModRefBSForCTRS(whole_heap);
-#endif
   _ct_bs->initialize();
   set_bs(_ct_bs);
   _last_cur_val_in_gen = NEW_C_HEAP_ARRAY3(jbyte, GenCollectedHeap::max_gens + 1,
--- a/hotspot/src/share/vm/memory/genCollectedHeap.cpp	Fri Jan 09 05:45:13 2015 -0800
+++ b/hotspot/src/share/vm/memory/genCollectedHeap.cpp	Fri Jan 09 13:28:02 2015 -0500
@@ -70,6 +70,7 @@
 
 GenCollectedHeap::GenCollectedHeap(GenCollectorPolicy *policy) :
   SharedHeap(policy),
+  _rem_set(NULL),
   _gen_policy(policy),
   _gen_process_roots_tasks(new SubTasksDone(GCH_PS_NumElements)),
   _full_collections_completed(0)
@@ -465,7 +466,7 @@
           // atomic wrt other collectors in this configuration, we
           // are guaranteed to have empty discovered ref lists.
           if (rp->discovery_is_atomic()) {
-            rp->enable_discovery(true /*verify_disabled*/, true /*verify_no_refs*/);
+            rp->enable_discovery();
             rp->setup_policy(do_clear_all_soft_refs);
           } else {
             // collect() below will enable discovery as appropriate
--- a/hotspot/src/share/vm/memory/genCollectedHeap.hpp	Fri Jan 09 05:45:13 2015 -0800
+++ b/hotspot/src/share/vm/memory/genCollectedHeap.hpp	Fri Jan 09 13:28:02 2015 -0500
@@ -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
@@ -66,6 +66,9 @@
   Generation* _gens[max_gens];
   GenerationSpec** _gen_specs;
 
+  // The singleton Gen Remembered Set.
+  GenRemSet* _rem_set;
+
   // The generational collector policy.
   GenCollectorPolicy* _gen_policy;
 
@@ -383,6 +386,10 @@
     return _n_gens;
   }
 
+  // This function returns the "GenRemSet" object that allows us to scan
+  // generations in a fully generational heap.
+  GenRemSet* rem_set() { return _rem_set; }
+
   // Convenience function to be used in situations where the heap type can be
   // asserted to be this type.
   static GenCollectedHeap* heap();
--- a/hotspot/src/share/vm/memory/genOopClosures.inline.hpp	Fri Jan 09 05:45:13 2015 -0800
+++ b/hotspot/src/share/vm/memory/genOopClosures.inline.hpp	Fri Jan 09 13:28:02 2015 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, 2012, 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
@@ -44,7 +44,7 @@
   _gen_boundary = _gen->reserved().start();
   // Barrier set for the heap, must be set after heap is initialized
   if (_rs == NULL) {
-    GenRemSet* rs = SharedHeap::heap()->rem_set();
+    GenRemSet* rs = GenCollectedHeap::heap()->rem_set();
     _rs = (CardTableRS*)rs;
   }
 }
--- a/hotspot/src/share/vm/memory/generation.cpp	Fri Jan 09 05:45:13 2015 -0800
+++ b/hotspot/src/share/vm/memory/generation.cpp	Fri Jan 09 13:28:02 2015 -0500
@@ -297,7 +297,7 @@
 
 void Generation::younger_refs_in_space_iterate(Space* sp,
                                                OopsInGenClosure* cl) {
-  GenRemSet* rs = SharedHeap::heap()->rem_set();
+  GenRemSet* rs = GenCollectedHeap::heap()->rem_set();
   rs->younger_refs_in_space_iterate(sp, cl);
 }
 
--- a/hotspot/src/share/vm/memory/metaspace.cpp	Fri Jan 09 05:45:13 2015 -0800
+++ b/hotspot/src/share/vm/memory/metaspace.cpp	Fri Jan 09 13:28:02 2015 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -422,7 +422,7 @@
     bool large_pages = false; // No large pages when dumping the CDS archive.
     char* shared_base = (char*)align_ptr_up((char*)SharedBaseAddress, Metaspace::reserve_alignment());
 
-    _rs = ReservedSpace(bytes, Metaspace::reserve_alignment(), large_pages, shared_base, 0);
+    _rs = ReservedSpace(bytes, Metaspace::reserve_alignment(), large_pages, shared_base);
     if (_rs.is_reserved()) {
       assert(shared_base == 0 || _rs.base() == shared_base, "should match");
     } else {
@@ -3025,7 +3025,7 @@
   ReservedSpace metaspace_rs = ReservedSpace(compressed_class_space_size(),
                                              _reserve_alignment,
                                              large_pages,
-                                             requested_addr, 0);
+                                             requested_addr);
   if (!metaspace_rs.is_reserved()) {
 #if INCLUDE_CDS
     if (UseSharedSpaces) {
@@ -3039,7 +3039,7 @@
              can_use_cds_with_metaspace_addr(addr + increment, cds_base)) {
         addr = addr + increment;
         metaspace_rs = ReservedSpace(compressed_class_space_size(),
-                                     _reserve_alignment, large_pages, addr, 0);
+                                     _reserve_alignment, large_pages, addr);
       }
     }
 #endif
--- a/hotspot/src/share/vm/memory/metaspaceShared.cpp	Fri Jan 09 05:45:13 2015 -0800
+++ b/hotspot/src/share/vm/memory/metaspaceShared.cpp	Fri Jan 09 13:28:02 2015 -0500
@@ -48,6 +48,8 @@
 
 ReservedSpace* MetaspaceShared::_shared_rs = NULL;
 
+MetaspaceSharedStats MetaspaceShared::_stats;
+
 bool MetaspaceShared::_link_classes_made_progress;
 bool MetaspaceShared::_check_classes_made_progress;
 bool MetaspaceShared::_has_error_classes;
@@ -259,7 +261,7 @@
 #define SHAREDSPACE_OBJ_TYPES_DO(f) \
   METASPACE_OBJ_TYPES_DO(f) \
   f(SymbolHashentry) \
-  f(SymbolBuckets) \
+  f(SymbolBucket) \
   f(Other)
 
 #define SHAREDSPACE_OBJ_TYPE_DECLARE(name) name ## Type,
@@ -315,18 +317,16 @@
   int other_bytes = md_all + mc_all;
 
   // Calculate size of data that was not allocated by Metaspace::allocate()
-  int symbol_count = _counts[RO][MetaspaceObj::SymbolType];
-  int symhash_bytes = symbol_count * sizeof (HashtableEntry<Symbol*, mtSymbol>);
-  int symbuck_count = SymbolTable::the_table()->table_size();
-  int symbuck_bytes = symbuck_count * sizeof(HashtableBucket<mtSymbol>);
+  MetaspaceSharedStats *stats = MetaspaceShared::stats();
 
-  _counts[RW][SymbolHashentryType] = symbol_count;
-  _bytes [RW][SymbolHashentryType] = symhash_bytes;
-  other_bytes -= symhash_bytes;
+  // symbols
+  _counts[RW][SymbolHashentryType] = stats->symbol.hashentry_count;
+  _bytes [RW][SymbolHashentryType] = stats->symbol.hashentry_bytes;
+  other_bytes -= stats->symbol.hashentry_bytes;
 
-  _counts[RW][SymbolBucketsType] = symbuck_count;
-  _bytes [RW][SymbolBucketsType] = symbuck_bytes;
-  other_bytes -= symbuck_bytes;
+  _counts[RW][SymbolBucketType] = stats->symbol.bucket_count;
+  _bytes [RW][SymbolBucketType] = stats->symbol.bucket_bytes;
+  other_bytes -= stats->symbol.bucket_bytes;
 
   // TODO: count things like dictionary, vtable, etc
   _bytes[RW][OtherType] =  other_bytes;
@@ -424,6 +424,13 @@
 
   VMOp_Type type() const { return VMOp_PopulateDumpSharedSpace; }
   void doit();   // outline because gdb sucks
+
+private:
+  void handle_misc_data_space_failure(bool success) {
+    if (!success) {
+      report_out_of_shared_space(SharedMiscData);
+    }
+  }
 }; // class VM_PopulateDumpSharedSpace
 
 
@@ -517,9 +524,8 @@
   // buckets first [read-write], then copy the linked lists of entries
   // [read-only].
 
-  SymbolTable::reverse(md_top);
   NOT_PRODUCT(SymbolTable::verify());
-  SymbolTable::copy_buckets(&md_top, md_end);
+  handle_misc_data_space_failure(SymbolTable::copy_compact_table(&md_top, md_end));
 
   SystemDictionary::reverse();
   SystemDictionary::copy_buckets(&md_top, md_end);
@@ -528,7 +534,6 @@
   ClassLoader::copy_package_info_buckets(&md_top, md_end);
   ClassLoader::verify();
 
-  SymbolTable::copy_table(&md_top, md_end);
   SystemDictionary::copy_table(&md_top, md_end);
   ClassLoader::verify();
   ClassLoader::copy_package_info_table(&md_top, md_end);
@@ -1000,17 +1005,12 @@
   buffer += sizeof(intptr_t);
   buffer += vtable_size;
 
-  // Create the symbol table using the bucket array at this spot in the
-  // misc data space.  Since the symbol table is often modified, this
-  // region (of mapped pages) will be copy-on-write.
+  // Create the shared symbol table using the bucket array at this spot in the
+  // misc data space. (Todo: move this to read-only space. Currently
+  // this is mapped copy-on-write but will never be written into).
 
-  int symbolTableLen = *(intptr_t*)buffer;
-  buffer += sizeof(intptr_t);
-  int number_of_entries = *(intptr_t*)buffer;
-  buffer += sizeof(intptr_t);
-  SymbolTable::create_table((HashtableBucket<mtSymbol>*)buffer, symbolTableLen,
-                            number_of_entries);
-  buffer += symbolTableLen;
+  buffer = (char*)SymbolTable::init_shared_table(buffer);
+  SymbolTable::create_table();
 
   // Create the shared dictionary using the bucket array at this spot in
   // the misc data space.  Since the shared dictionary table is never
@@ -1019,7 +1019,7 @@
 
   int sharedDictionaryLen = *(intptr_t*)buffer;
   buffer += sizeof(intptr_t);
-  number_of_entries = *(intptr_t*)buffer;
+  int number_of_entries = *(intptr_t*)buffer;
   buffer += sizeof(intptr_t);
   SystemDictionary::set_shared_dictionary((HashtableBucket<mtClass>*)buffer,
                                           sharedDictionaryLen,
@@ -1041,18 +1041,10 @@
   ClassLoader::verify();
 
   // The following data in the shared misc data region are the linked
-  // list elements (HashtableEntry objects) for the symbol table, string
-  // table, and shared dictionary.  The heap objects referred to by the
-  // symbol table, string table, and shared dictionary are permanent and
-  // unmovable.  Since new entries added to the string and symbol tables
-  // are always added at the beginning of the linked lists, THESE LINKED
-  // LIST ELEMENTS ARE READ-ONLY.
+  // list elements (HashtableEntry objects) for the shared dictionary
+  // and package info table.
 
-  int len = *(intptr_t*)buffer; // skip over symbol table entries
-  buffer += sizeof(intptr_t);
-  buffer += len;
-
-  len = *(intptr_t*)buffer;     // skip over shared dictionary entries
+  int len = *(intptr_t*)buffer;     // skip over shared dictionary entries
   buffer += sizeof(intptr_t);
   buffer += len;
 
--- a/hotspot/src/share/vm/memory/metaspaceShared.hpp	Fri Jan 09 05:45:13 2015 -0800
+++ b/hotspot/src/share/vm/memory/metaspaceShared.hpp	Fri Jan 09 13:28:02 2015 -0500
@@ -24,6 +24,7 @@
 #ifndef SHARE_VM_MEMORY_METASPACE_SHARED_HPP
 #define SHARE_VM_MEMORY_METASPACE_SHARED_HPP
 
+#include "classfile/compactHashtable.hpp"
 #include "memory/allocation.hpp"
 #include "memory/memRegion.hpp"
 #include "runtime/virtualspace.hpp"
@@ -45,12 +46,21 @@
 
 class FileMapInfo;
 
+class MetaspaceSharedStats VALUE_OBJ_CLASS_SPEC {
+public:
+  MetaspaceSharedStats() {
+    memset(this, 0, sizeof(*this));
+  }
+  CompactHashtableStats symbol;
+};
+
 // Class Data Sharing Support
 class MetaspaceShared : AllStatic {
 
   // CDS support
   static ReservedSpace* _shared_rs;
   static int _max_alignment;
+  static MetaspaceSharedStats _stats;
   static bool _link_classes_made_progress;
   static bool _check_classes_made_progress;
   static bool _has_error_classes;
@@ -123,6 +133,10 @@
                                       char** mc_top, char* mc_end);
   static void serialize(SerializeClosure* sc);
 
+  static MetaspaceSharedStats* stats() {
+    return &_stats;
+  }
+
   // JVM/TI RedefineClasses() support:
   // Remap the shared readonly space to shared readwrite, private if
   // sharing is enabled. Simply returns true if sharing is not enabled
--- a/hotspot/src/share/vm/memory/referenceProcessor.cpp	Fri Jan 09 05:45:13 2015 -0800
+++ b/hotspot/src/share/vm/memory/referenceProcessor.cpp	Fri Jan 09 13:28:02 2015 -0500
@@ -68,10 +68,10 @@
   _pending_list_uses_discovered_field = JDK_Version::current().pending_list_uses_discovered_field();
 }
 
-void ReferenceProcessor::enable_discovery(bool verify_disabled, bool check_no_refs) {
+void ReferenceProcessor::enable_discovery(bool check_no_refs) {
 #ifdef ASSERT
   // Verify that we're not currently discovering refs
-  assert(!verify_disabled || !_discovering_refs, "nested call?");
+  assert(!_discovering_refs, "nested call?");
 
   if (check_no_refs) {
     // Verify that the discovered lists are empty
@@ -963,52 +963,6 @@
   return total_list_count;
 }
 
-void ReferenceProcessor::clean_up_discovered_references() {
-  // loop over the lists
-  for (uint i = 0; i < _max_num_q * number_of_subclasses_of_ref(); i++) {
-    if (TraceReferenceGC && PrintGCDetails && ((i % _max_num_q) == 0)) {
-      gclog_or_tty->print_cr(
-        "\nScrubbing %s discovered list of Null referents",
-        list_name(i));
-    }
-    clean_up_discovered_reflist(_discovered_refs[i]);
-  }
-}
-
-void ReferenceProcessor::clean_up_discovered_reflist(DiscoveredList& refs_list) {
-  assert(!discovery_is_atomic(), "Else why call this method?");
-  DiscoveredListIterator iter(refs_list, NULL, NULL);
-  while (iter.has_next()) {
-    iter.load_ptrs(DEBUG_ONLY(true /* allow_null_referent */));
-    oop next = java_lang_ref_Reference::next(iter.obj());
-    assert(next->is_oop_or_null(), err_msg("Expected an oop or NULL for next field at " PTR_FORMAT, p2i(next)));
-    // If referent has been cleared or Reference is not active,
-    // drop it.
-    if (iter.referent() == NULL || next != NULL) {
-      debug_only(
-        if (PrintGCDetails && TraceReferenceGC) {
-          gclog_or_tty->print_cr("clean_up_discovered_list: Dropping Reference: "
-            INTPTR_FORMAT " with next field: " INTPTR_FORMAT
-            " and referent: " INTPTR_FORMAT,
-            (void *)iter.obj(), (void *)next, (void *)iter.referent());
-        }
-      )
-      // Remove Reference object from list
-      iter.remove();
-      iter.move_to_next();
-    } else {
-      iter.next();
-    }
-  }
-  NOT_PRODUCT(
-    if (PrintGCDetails && TraceReferenceGC) {
-      gclog_or_tty->print(
-        " Removed %d Refs with NULL referents out of %d discovered Refs",
-        iter.removed(), iter.processed());
-    }
-  )
-}
-
 inline DiscoveredList* ReferenceProcessor::get_discovered_list(ReferenceType rt) {
   uint id = 0;
   // Determine the queue index to use for this object.
--- a/hotspot/src/share/vm/memory/referenceProcessor.hpp	Fri Jan 09 05:45:13 2015 -0800
+++ b/hotspot/src/share/vm/memory/referenceProcessor.hpp	Fri Jan 09 13:28:02 2015 -0500
@@ -353,19 +353,6 @@
                                       GCTimer*           gc_timer,
                                       GCId               gc_id);
 
-  // Delete entries in the discovered lists that have
-  // either a null referent or are not active. Such
-  // Reference objects can result from the clearing
-  // or enqueueing of Reference objects concurrent
-  // with their discovery by a (concurrent) collector.
-  // For a definition of "active" see java.lang.ref.Reference;
-  // Refs are born active, become inactive when enqueued,
-  // and never become active again. The state of being
-  // active is encoded as follows: A Ref is active
-  // if and only if its "next" field is NULL.
-  void clean_up_discovered_references();
-  void clean_up_discovered_reflist(DiscoveredList& refs_list);
-
   // Returns the name of the discovered reference list
   // occupying the i / _num_q slot.
   const char* list_name(uint i);
@@ -439,7 +426,7 @@
   void      set_span(MemRegion span) { _span = span; }
 
   // start and stop weak ref discovery
-  void enable_discovery(bool verify_disabled, bool check_no_refs);
+  void enable_discovery(bool check_no_refs = true);
   void disable_discovery()  { _discovering_refs = false; }
   bool discovery_enabled()  { return _discovering_refs;  }
 
@@ -517,7 +504,7 @@
 
   ~NoRefDiscovery() {
     if (_was_discovering_refs) {
-      _rp->enable_discovery(true /*verify_disabled*/, false /*check_no_refs*/);
+      _rp->enable_discovery(false /*check_no_refs*/);
     }
   }
 };
--- a/hotspot/src/share/vm/memory/sharedHeap.cpp	Fri Jan 09 05:45:13 2015 -0800
+++ b/hotspot/src/share/vm/memory/sharedHeap.cpp	Fri Jan 09 13:28:02 2015 -0500
@@ -58,7 +58,6 @@
 SharedHeap::SharedHeap(CollectorPolicy* policy_) :
   CollectedHeap(),
   _collector_policy(policy_),
-  _rem_set(NULL),
   _strong_roots_scope(NULL),
   _strong_roots_parity(0),
   _process_strong_tasks(new SubTasksDone(SH_PS_NumElements)),
--- a/hotspot/src/share/vm/memory/sharedHeap.hpp	Fri Jan 09 05:45:13 2015 -0800
+++ b/hotspot/src/share/vm/memory/sharedHeap.hpp	Fri Jan 09 13:28:02 2015 -0500
@@ -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
@@ -114,10 +114,6 @@
   // set the static pointer "_sh" to that instance.
   static SharedHeap* _sh;
 
-  // and the Gen Remembered Set, at least one good enough to scan the perm
-  // gen.
-  GenRemSet* _rem_set;
-
   // A gc policy, controls global gc resource issues
   CollectorPolicy *_collector_policy;
 
@@ -152,10 +148,6 @@
   // Initialization of ("weak") reference processing support
   virtual void ref_processing_init();
 
-  // This function returns the "GenRemSet" object that allows us to scan
-  // generations in a fully generational heap.
-  GenRemSet* rem_set() { return _rem_set; }
-
   // Iteration functions.
   void oop_iterate(ExtendedOopClosure* cl) = 0;
 
--- a/hotspot/src/share/vm/memory/universe.cpp	Fri Jan 09 05:45:13 2015 -0800
+++ b/hotspot/src/share/vm/memory/universe.cpp	Fri Jan 09 13:28:02 2015 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -694,103 +694,6 @@
 //     NarrowOopHeapBaseMin + heap_size < 32Gb
 // HeapBased - Use compressed oops with heap base + encoding.
 
-// 4Gb
-static const uint64_t UnscaledOopHeapMax = (uint64_t(max_juint) + 1);
-// 32Gb
-// OopEncodingHeapMax == UnscaledOopHeapMax << LogMinObjAlignmentInBytes;
-
-char* Universe::preferred_heap_base(size_t heap_size, size_t alignment, NARROW_OOP_MODE mode) {
-  assert(is_size_aligned((size_t)OopEncodingHeapMax, alignment), "Must be");
-  assert(is_size_aligned((size_t)UnscaledOopHeapMax, alignment), "Must be");
-  assert(is_size_aligned(heap_size, alignment), "Must be");
-
-  uintx heap_base_min_address_aligned = align_size_up(HeapBaseMinAddress, alignment);
-
-  size_t base = 0;
-#ifdef _LP64
-  if (UseCompressedOops) {
-    assert(mode == UnscaledNarrowOop  ||
-           mode == ZeroBasedNarrowOop ||
-           mode == HeapBasedNarrowOop, "mode is invalid");
-    const size_t total_size = heap_size + heap_base_min_address_aligned;
-    // Return specified base for the first request.
-    if (!FLAG_IS_DEFAULT(HeapBaseMinAddress) && (mode == UnscaledNarrowOop)) {
-      base = heap_base_min_address_aligned;
-
-    // If the total size is small enough to allow UnscaledNarrowOop then
-    // just use UnscaledNarrowOop.
-    } else if ((total_size <= OopEncodingHeapMax) && (mode != HeapBasedNarrowOop)) {
-      if ((total_size <= UnscaledOopHeapMax) && (mode == UnscaledNarrowOop) &&
-          (Universe::narrow_oop_shift() == 0)) {
-        // Use 32-bits oops without encoding and
-        // place heap's top on the 4Gb boundary
-        base = (UnscaledOopHeapMax - heap_size);
-      } else {
-        // Can't reserve with NarrowOopShift == 0
-        Universe::set_narrow_oop_shift(LogMinObjAlignmentInBytes);
-
-        if (mode == UnscaledNarrowOop ||
-            mode == ZeroBasedNarrowOop && total_size <= UnscaledOopHeapMax) {
-
-          // Use zero based compressed oops with encoding and
-          // place heap's top on the 32Gb boundary in case
-          // total_size > 4Gb or failed to reserve below 4Gb.
-          uint64_t heap_top = OopEncodingHeapMax;
-
-          // For small heaps, save some space for compressed class pointer
-          // space so it can be decoded with no base.
-          if (UseCompressedClassPointers && !UseSharedSpaces &&
-              OopEncodingHeapMax <= 32*G) {
-
-            uint64_t class_space = align_size_up(CompressedClassSpaceSize, alignment);
-            assert(is_size_aligned((size_t)OopEncodingHeapMax-class_space,
-                   alignment), "difference must be aligned too");
-            uint64_t new_top = OopEncodingHeapMax-class_space;
-
-            if (total_size <= new_top) {
-              heap_top = new_top;
-            }
-          }
-
-          // Align base to the adjusted top of the heap
-          base = heap_top - heap_size;
-        }
-      }
-    } else {
-      // UnscaledNarrowOop encoding didn't work, and no base was found for ZeroBasedOops or
-      // HeapBasedNarrowOop encoding was requested.  So, can't reserve below 32Gb.
-      Universe::set_narrow_oop_shift(LogMinObjAlignmentInBytes);
-    }
-
-    // Set narrow_oop_base and narrow_oop_use_implicit_null_checks
-    // used in ReservedHeapSpace() constructors.
-    // The final values will be set in initialize_heap() below.
-    if ((base != 0) && ((base + heap_size) <= OopEncodingHeapMax)) {
-      // Use zero based compressed oops
-      Universe::set_narrow_oop_base(NULL);
-      // Don't need guard page for implicit checks in indexed
-      // addressing mode with zero based Compressed Oops.
-      Universe::set_narrow_oop_use_implicit_null_checks(true);
-    } else {
-      // Set to a non-NULL value so the ReservedSpace ctor computes
-      // the correct no-access prefix.
-      // The final value will be set in initialize_heap() below.
-      Universe::set_narrow_oop_base((address)UnscaledOopHeapMax);
-#if defined(_WIN64) || defined(AIX)
-      if (UseLargePages) {
-        // Cannot allocate guard pages for implicit checks in indexed
-        // addressing mode when large pages are specified on windows.
-        Universe::set_narrow_oop_use_implicit_null_checks(false);
-      }
-#endif //  _WIN64
-    }
-  }
-#endif
-
-  assert(is_ptr_aligned((char*)base, alignment), "Must be");
-  return (char*)base; // also return NULL (don't care) for 32-bit VM
-}
-
 jint Universe::initialize_heap() {
 
   if (UseParallelGC) {
@@ -844,30 +747,13 @@
     // See needs_explicit_null_check.
     // Only set the heap base for compressed oops because it indicates
     // compressed oops for pstack code.
-    if (((uint64_t)Universe::heap()->reserved_region().end() > OopEncodingHeapMax)) {
-      // Can't reserve heap below 32Gb.
-      // keep the Universe::narrow_oop_base() set