changeset 10245:923ac8d1df95

Merge
author jwilhelm
date Thu, 09 May 2013 12:23:43 +0200
parents 7243490a6847 (diff) 06ab37f08701 (current diff)
children 194f52aa2f23
files
diffstat 41 files changed, 1136 insertions(+), 226 deletions(-) [+]
line wrap: on
line diff
--- a/agent/src/os/bsd/ps_core.c	Wed May 08 17:12:52 2013 -0700
+++ b/agent/src/os/bsd/ps_core.c	Thu May 09 12:23:43 2013 +0200
@@ -199,10 +199,10 @@
 //---------------------------------------------------------------
 // Part of the class sharing workaround:
 //
-// With class sharing, pages are mapped from classes[_g].jsa file.
+// With class sharing, pages are mapped from classes.jsa file.
 // The read-only class sharing pages are mapped as MAP_SHARED,
 // PROT_READ pages. These pages are not dumped into core dump.
-// With this workaround, these pages are read from classes[_g].jsa.
+// With this workaround, these pages are read from classes.jsa.
 
 // FIXME: !HACK ALERT!
 // The format of sharing achive file header is needed to read shared heap
@@ -298,14 +298,12 @@
   lib_info* lib = ph->libs;
   while (lib != NULL) {
     // we are iterating over shared objects from the core dump. look for
-    // libjvm[_g].so.
+    // libjvm.so.
     const char *jvm_name = 0;
 #ifdef __APPLE__
-    if ((jvm_name = strstr(lib->name, "/libjvm.dylib")) != 0 ||
-        (jvm_name = strstr(lib->name, "/libjvm_g.dylib")) != 0)
+    if ((jvm_name = strstr(lib->name, "/libjvm.dylib")) != 0)
 #else
-    if ((jvm_name = strstr(lib->name, "/libjvm.so")) != 0 ||
-        (jvm_name = strstr(lib->name, "/libjvm_g.so")) != 0)
+    if ((jvm_name = strstr(lib->name, "/libjvm.so")) != 0)
 #endif // __APPLE__
     {
       char classes_jsa[PATH_MAX];
@@ -389,7 +387,7 @@
       }
 
       ph->core->classes_jsa_fd = fd;
-      // add read-only maps from classes[_g].jsa to the list of maps
+      // add read-only maps from classes.jsa to the list of maps
       for (m = 0; m < NUM_SHARED_MAPS; m++) {
         if (header._space[m]._read_only) {
           base = (uintptr_t) header._space[m]._base;
--- a/agent/src/os/linux/ps_core.c	Wed May 08 17:12:52 2013 -0700
+++ b/agent/src/os/linux/ps_core.c	Thu May 09 12:23:43 2013 +0200
@@ -195,10 +195,10 @@
 //---------------------------------------------------------------
 // Part of the class sharing workaround:
 //
-// With class sharing, pages are mapped from classes[_g].jsa file.
+// With class sharing, pages are mapped from classes.jsa file.
 // The read-only class sharing pages are mapped as MAP_SHARED,
 // PROT_READ pages. These pages are not dumped into core dump.
-// With this workaround, these pages are read from classes[_g].jsa.
+// With this workaround, these pages are read from classes.jsa.
 
 // FIXME: !HACK ALERT!
 // The format of sharing achive file header is needed to read shared heap
@@ -284,10 +284,9 @@
    lib_info* lib = ph->libs;
    while (lib != NULL) {
       // we are iterating over shared objects from the core dump. look for
-      // libjvm[_g].so.
+      // libjvm.so.
       const char *jvm_name = 0;
-      if ((jvm_name = strstr(lib->name, "/libjvm.so")) != 0 ||
-          (jvm_name = strstr(lib->name, "/libjvm_g.so")) != 0) {
+      if ((jvm_name = strstr(lib->name, "/libjvm.so")) != 0) {
          char classes_jsa[PATH_MAX];
          struct FileMapHeader header;
          size_t n = 0;
@@ -371,7 +370,7 @@
          }
 
          ph->core->classes_jsa_fd = fd;
-         // add read-only maps from classes[_g].jsa to the list of maps
+         // add read-only maps from classes.jsa to the list of maps
          for (m = 0; m < NUM_SHARED_MAPS; m++) {
             if (header._space[m]._read_only) {
                base = (uintptr_t) header._space[m]._base;
--- a/agent/src/os/solaris/proc/saproc.cpp	Wed May 08 17:12:52 2013 -0700
+++ b/agent/src/os/solaris/proc/saproc.cpp	Thu May 09 12:23:43 2013 +0200
@@ -589,8 +589,7 @@
   JNIEnv*   env = dbg->env;
   jobject this_obj = dbg->this_obj;
   const char* jvm_name = 0;
-  if ((jvm_name = strstr(obj_name, "libjvm.so")) != NULL ||
-      (jvm_name = strstr(obj_name, "libjvm_g.so")) != NULL) {
+  if ((jvm_name = strstr(obj_name, "libjvm.so")) != NULL) {
     jvm_name = obj_name;
   } else {
     return 0;
@@ -598,7 +597,7 @@
 
   struct ps_prochandle* ph = (struct ps_prochandle*) env->GetLongField(this_obj, p_ps_prochandle_ID);
 
-  // initialize classes[_g].jsa file descriptor field.
+  // initialize classes.jsa file descriptor field.
   dbg->env->SetIntField(this_obj, classes_jsa_fd_ID, -1);
 
   // check whether class sharing is on by reading variable "UseSharedSpaces"
@@ -641,7 +640,7 @@
 
   print_debug("looking for %s\n", classes_jsa);
 
-  // open the classes[_g].jsa
+  // open the classes.jsa
   int fd = libsaproc_open(classes_jsa, O_RDONLY);
   if (fd < 0) {
     char errMsg[ERR_MSG_SIZE];
@@ -651,7 +650,7 @@
     print_debug("opened shared archive file %s\n", classes_jsa);
   }
 
-  // parse classes[_g].jsa
+  // parse classes.jsa
   struct FileMapHeader* pheader = (struct FileMapHeader*) malloc(sizeof(struct FileMapHeader));
   if (pheader == NULL) {
     close(fd);
@@ -798,8 +797,8 @@
   if (! isProcess) {
     /*
      * With class sharing, shared perm. gen heap is allocated in with MAP_SHARED|PROT_READ.
-     * These pages are mapped from the file "classes[_g].jsa". MAP_SHARED pages are not dumped
-     * in Solaris core.To read shared heap pages, we have to read classes[_g].jsa file.
+     * These pages are mapped from the file "classes.jsa". MAP_SHARED pages are not dumped
+     * in Solaris core.To read shared heap pages, we have to read classes.jsa file.
      */
     Pobject_iter(ph, init_classsharing_workaround, &dbg);
     exception = env->ExceptionOccurred();
--- a/agent/src/share/classes/sun/jvm/hotspot/HotSpotAgent.java	Wed May 08 17:12:52 2013 -0700
+++ b/agent/src/share/classes/sun/jvm/hotspot/HotSpotAgent.java	Thu May 09 12:23:43 2013 +0200
@@ -24,20 +24,29 @@
 
 package sun.jvm.hotspot;
 
-import java.io.PrintStream;
-import java.net.*;
-import java.rmi.*;
-import sun.jvm.hotspot.debugger.*;
-import sun.jvm.hotspot.debugger.bsd.*;
-import sun.jvm.hotspot.debugger.proc.*;
-import sun.jvm.hotspot.debugger.remote.*;
-import sun.jvm.hotspot.debugger.windbg.*;
-import sun.jvm.hotspot.debugger.linux.*;
-import sun.jvm.hotspot.memory.*;
-import sun.jvm.hotspot.oops.*;
-import sun.jvm.hotspot.runtime.*;
-import sun.jvm.hotspot.types.*;
-import sun.jvm.hotspot.utilities.*;
+import java.rmi.RemoteException;
+
+import sun.jvm.hotspot.debugger.Debugger;
+import sun.jvm.hotspot.debugger.DebuggerException;
+import sun.jvm.hotspot.debugger.JVMDebugger;
+import sun.jvm.hotspot.debugger.MachineDescription;
+import sun.jvm.hotspot.debugger.MachineDescriptionAMD64;
+import sun.jvm.hotspot.debugger.MachineDescriptionIA64;
+import sun.jvm.hotspot.debugger.MachineDescriptionIntelX86;
+import sun.jvm.hotspot.debugger.MachineDescriptionSPARC32Bit;
+import sun.jvm.hotspot.debugger.MachineDescriptionSPARC64Bit;
+import sun.jvm.hotspot.debugger.NoSuchSymbolException;
+import sun.jvm.hotspot.debugger.bsd.BsdDebuggerLocal;
+import sun.jvm.hotspot.debugger.linux.LinuxDebuggerLocal;
+import sun.jvm.hotspot.debugger.proc.ProcDebuggerLocal;
+import sun.jvm.hotspot.debugger.remote.RemoteDebugger;
+import sun.jvm.hotspot.debugger.remote.RemoteDebuggerClient;
+import sun.jvm.hotspot.debugger.remote.RemoteDebuggerServer;
+import sun.jvm.hotspot.debugger.windbg.WindbgDebuggerLocal;
+import sun.jvm.hotspot.runtime.VM;
+import sun.jvm.hotspot.types.TypeDataBase;
+import sun.jvm.hotspot.utilities.PlatformInfo;
+import sun.jvm.hotspot.utilities.UnsupportedPlatformException;
 
 /** <P> This class wraps much of the basic functionality and is the
  * highest-level factory for VM data structures. It makes it simple
@@ -475,7 +484,7 @@
     }
 
     private void setupJVMLibNamesSolaris() {
-        jvmLibNames = new String[] { "libjvm.so", "libjvm_g.so", "gamma_g" };
+        jvmLibNames = new String[] { "libjvm.so" };
     }
 
     //
@@ -507,7 +516,7 @@
     }
 
     private void setupJVMLibNamesWin32() {
-        jvmLibNames = new String[] { "jvm.dll", "jvm_g.dll" };
+        jvmLibNames = new String[] { "jvm.dll" };
     }
 
     //
@@ -547,7 +556,7 @@
     }
 
     private void setupJVMLibNamesLinux() {
-        jvmLibNames = new String[] { "libjvm.so", "libjvm_g.so" };
+        jvmLibNames = new String[] { "libjvm.so" };
     }
 
     //
@@ -572,7 +581,7 @@
     }
 
     private void setupJVMLibNamesBsd() {
-        jvmLibNames = new String[] { "libjvm.so", "libjvm_g.so" };
+        jvmLibNames = new String[] { "libjvm.so" };
     }
 
     //
@@ -595,7 +604,7 @@
     }
 
     private void setupJVMLibNamesDarwin() {
-        jvmLibNames = new String[] { "libjvm.dylib", "libjvm_g.dylib" };
+        jvmLibNames = new String[] { "libjvm.dylib" };
     }
 
     /** Convenience routine which should be called by per-platform
--- a/agent/src/share/classes/sun/jvm/hotspot/LinuxVtblAccess.java	Wed May 08 17:12:52 2013 -0700
+++ b/agent/src/share/classes/sun/jvm/hotspot/LinuxVtblAccess.java	Thu May 09 12:23:43 2013 +0200
@@ -24,9 +24,9 @@
 
 package sun.jvm.hotspot;
 
-import sun.jvm.hotspot.debugger.*;
-import sun.jvm.hotspot.types.*;
-import sun.jvm.hotspot.types.basic.*;
+import sun.jvm.hotspot.debugger.SymbolLookup;
+import sun.jvm.hotspot.types.Type;
+import sun.jvm.hotspot.types.basic.BasicVtblAccess;
 
 public class LinuxVtblAccess extends BasicVtblAccess {
   private String vt;
@@ -35,8 +35,7 @@
                          String[] dllNames) {
     super(symbolLookup, dllNames);
 
-    if (symbolLookup.lookup("libjvm.so", "__vt_10JavaThread") != null ||
-        symbolLookup.lookup("libjvm_g.so", "__vt_10JavaThread") != null) {
+    if (symbolLookup.lookup("libjvm.so", "__vt_10JavaThread") != null) {
        // old C++ ABI
        vt = "__vt_";
     } else {
--- a/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebuggerLocal.java	Wed May 08 17:12:52 2013 -0700
+++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebuggerLocal.java	Thu May 09 12:23:43 2013 +0200
@@ -24,17 +24,28 @@
 
 package sun.jvm.hotspot.debugger.bsd;
 
-import java.io.*;
-import java.net.*;
-import java.util.*;
-import sun.jvm.hotspot.debugger.*;
-import sun.jvm.hotspot.debugger.x86.*;
-import sun.jvm.hotspot.debugger.cdbg.*;
-import sun.jvm.hotspot.utilities.*;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+import sun.jvm.hotspot.debugger.Address;
+import sun.jvm.hotspot.debugger.DebuggerBase;
+import sun.jvm.hotspot.debugger.DebuggerException;
+import sun.jvm.hotspot.debugger.DebuggerUtilities;
+import sun.jvm.hotspot.debugger.MachineDescription;
+import sun.jvm.hotspot.debugger.NotInHeapException;
+import sun.jvm.hotspot.debugger.OopHandle;
+import sun.jvm.hotspot.debugger.ReadResult;
+import sun.jvm.hotspot.debugger.ThreadProxy;
+import sun.jvm.hotspot.debugger.UnalignedAddressException;
+import sun.jvm.hotspot.debugger.UnmappedAddressException;
+import sun.jvm.hotspot.debugger.cdbg.CDebugger;
+import sun.jvm.hotspot.debugger.cdbg.ClosestSymbol;
+import sun.jvm.hotspot.debugger.cdbg.LoadObject;
+import sun.jvm.hotspot.runtime.JavaThread;
+import sun.jvm.hotspot.runtime.Threads;
 import sun.jvm.hotspot.runtime.VM;
-import sun.jvm.hotspot.runtime.Threads;
-import sun.jvm.hotspot.runtime.JavaThread;
-import java.lang.reflect.*;
+import sun.jvm.hotspot.utilities.PlatformInfo;
 
 /** <P> An implementation of the JVMDebugger interface. The basic debug
     facilities are implemented through ptrace interface in the JNI code
@@ -246,10 +257,8 @@
     /* called from attach methods */
     private void findABIVersion() throws DebuggerException {
         String libjvmName = isDarwin ? "libjvm.dylib" : "libjvm.so";
-        String libjvm_gName = isDarwin? "libjvm_g.dylib" : "libjvm_g.so";
         String javaThreadVt = isDarwin ? "_vt_10JavaThread" : "__vt_10JavaThread";
-        if (lookupByName0(libjvmName, javaThreadVt) != 0 ||
-            lookupByName0(libjvm_gName, javaThreadVt) != 0) {
+        if (lookupByName0(libjvmName, javaThreadVt) != 0) {
             // old C++ ABI
             useGCC32ABI = false;
         } else {
--- a/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/LinuxDebuggerLocal.java	Wed May 08 17:12:52 2013 -0700
+++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/LinuxDebuggerLocal.java	Thu May 09 12:23:43 2013 +0200
@@ -24,14 +24,25 @@
 
 package sun.jvm.hotspot.debugger.linux;
 
-import java.io.*;
-import java.net.*;
-import java.util.*;
-import sun.jvm.hotspot.debugger.*;
-import sun.jvm.hotspot.debugger.x86.*;
-import sun.jvm.hotspot.debugger.cdbg.*;
-import sun.jvm.hotspot.utilities.*;
-import java.lang.reflect.*;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+import sun.jvm.hotspot.debugger.Address;
+import sun.jvm.hotspot.debugger.DebuggerBase;
+import sun.jvm.hotspot.debugger.DebuggerException;
+import sun.jvm.hotspot.debugger.DebuggerUtilities;
+import sun.jvm.hotspot.debugger.MachineDescription;
+import sun.jvm.hotspot.debugger.NotInHeapException;
+import sun.jvm.hotspot.debugger.OopHandle;
+import sun.jvm.hotspot.debugger.ReadResult;
+import sun.jvm.hotspot.debugger.ThreadProxy;
+import sun.jvm.hotspot.debugger.UnalignedAddressException;
+import sun.jvm.hotspot.debugger.UnmappedAddressException;
+import sun.jvm.hotspot.debugger.cdbg.CDebugger;
+import sun.jvm.hotspot.debugger.cdbg.ClosestSymbol;
+import sun.jvm.hotspot.debugger.cdbg.LoadObject;
+import sun.jvm.hotspot.utilities.PlatformInfo;
 
 /** <P> An implementation of the JVMDebugger interface. The basic debug
     facilities are implemented through ptrace interface in the JNI code
@@ -238,8 +249,7 @@
 
     /* called from attach methods */
     private void findABIVersion() throws DebuggerException {
-        if (lookupByName0("libjvm.so", "__vt_10JavaThread") != 0 ||
-            lookupByName0("libjvm_g.so", "__vt_10JavaThread") != 0) {
+        if (lookupByName0("libjvm.so", "__vt_10JavaThread") != 0) {
             // old C++ ABI
             useGCC32ABI = false;
         } else {
--- a/make/windows/makefiles/compile.make	Wed May 08 17:12:52 2013 -0700
+++ b/make/windows/makefiles/compile.make	Thu May 09 12:23:43 2013 +0200
@@ -52,7 +52,7 @@
 # improving the quality of crash log stack traces involving jvm.dll.
 
 # These are always used in all compiles
-CXX_FLAGS=/nologo /W3 /WX
+CXX_FLAGS=$(EXTRA_CFLAGS) /nologo /W3 /WX
 
 # Let's add debug information when Full Debug Symbols is enabled
 !if "$(ENABLE_FULL_DEBUG_SYMBOLS)" == "1"
--- a/make/windows/makefiles/defs.make	Wed May 08 17:12:52 2013 -0700
+++ b/make/windows/makefiles/defs.make	Thu May 09 12:23:43 2013 +0200
@@ -193,7 +193,7 @@
   MAKE_ARGS += JDK_BUILD_NUMBER=$(COOKED_BUILD_NUMBER)
 endif
 
-NMAKE= MAKEFLAGS= MFLAGS= nmake -NOLOGO
+NMAKE= MAKEFLAGS= MFLAGS= EXTRA_CFLAGS="$(EXTRA_CFLAGS)" nmake -NOLOGO
 ifndef SYSTEM_UNAME
   SYSTEM_UNAME := $(shell uname)
   export SYSTEM_UNAME
--- a/src/cpu/sparc/vm/jni_sparc.h	Wed May 08 17:12:52 2013 -0700
+++ b/src/cpu/sparc/vm/jni_sparc.h	Thu May 09 12:23:43 2013 +0200
@@ -23,7 +23,12 @@
  * questions.
  */
 
-#if defined(__GNUC__) && (__GNUC__ >= 4)
+// Note: please do not change these without also changing jni_md.h in the JDK
+// repository
+#ifndef __has_attribute
+  #define __has_attribute(x) 0
+#endif
+#if (defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4) && (__GNUC_MINOR__ > 2))) || __has_attribute(visibility)
   #define JNIEXPORT     __attribute__((visibility("default")))
   #define JNIIMPORT     __attribute__((visibility("default")))
 #else
--- a/src/cpu/x86/vm/jni_x86.h	Wed May 08 17:12:52 2013 -0700
+++ b/src/cpu/x86/vm/jni_x86.h	Thu May 09 12:23:43 2013 +0200
@@ -28,7 +28,13 @@
 
 #if defined(SOLARIS) || defined(LINUX) || defined(_ALLBSD_SOURCE)
 
-#if defined(__GNUC__) && (__GNUC__ > 4) || (__GNUC__ == 4) && (__GNUC_MINOR__ > 2)
+
+// Note: please do not change these without also changing jni_md.h in the JDK
+// repository
+#ifndef __has_attribute
+  #define __has_attribute(x) 0
+#endif
+#if (defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4) && (__GNUC_MINOR__ > 2))) || __has_attribute(visibility)
   #define JNIEXPORT     __attribute__((visibility("default")))
   #define JNIIMPORT     __attribute__((visibility("default")))
 #else
--- a/src/cpu/zero/vm/jni_zero.h	Wed May 08 17:12:52 2013 -0700
+++ b/src/cpu/zero/vm/jni_zero.h	Thu May 09 12:23:43 2013 +0200
@@ -25,7 +25,13 @@
  */
 
 
-#if defined(__GNUC__) && (__GNUC__ >= 4)
+
+// Note: please do not change these without also changing jni_md.h in the JDK
+// repository
+#ifndef __has_attribute
+  #define __has_attribute(x) 0
+#endif
+#if (defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4) && (__GNUC_MINOR__ > 2))) || __has_attribute(visibility)
   #define JNIEXPORT     __attribute__((visibility("default")))
   #define JNIIMPORT     __attribute__((visibility("default")))
 #else
--- a/src/share/vm/classfile/bytecodeAssembler.cpp	Wed May 08 17:12:52 2013 -0700
+++ b/src/share/vm/classfile/bytecodeAssembler.cpp	Thu May 09 12:23:43 2013 +0200
@@ -75,8 +75,8 @@
     int idx = i + _orig->length();
     switch (entry._tag) {
       case BytecodeCPEntry::UTF8:
+        entry._u.utf8->increment_refcount();
         cp->symbol_at_put(idx, entry._u.utf8);
-        entry._u.utf8->increment_refcount();
         break;
       case BytecodeCPEntry::KLASS:
         cp->unresolved_klass_at_put(
--- a/src/share/vm/classfile/systemDictionary.cpp	Wed May 08 17:12:52 2013 -0700
+++ b/src/share/vm/classfile/systemDictionary.cpp	Thu May 09 12:23:43 2013 +0200
@@ -830,7 +830,7 @@
             Klass *kk;
             {
               MutexLocker mu(SystemDictionary_lock, THREAD);
-              kk = find_class(name, ik->class_loader_data());
+              kk = find_class(d_index, d_hash, name, ik->class_loader_data());
             }
             if (kk != NULL) {
               // No clean up is needed if the shared class has been entered
--- a/src/share/vm/classfile/vmSymbols.hpp	Wed May 08 17:12:52 2013 -0700
+++ b/src/share/vm/classfile/vmSymbols.hpp	Thu May 09 12:23:43 2013 +0200
@@ -517,13 +517,18 @@
   template(sun_management_ManagementFactory,           "sun/management/ManagementFactory")                        \
   template(sun_management_Sensor,                      "sun/management/Sensor")                                   \
   template(sun_management_Agent,                       "sun/management/Agent")                                    \
+  template(sun_management_DiagnosticCommandImpl,       "sun/management/DiagnosticCommandImpl")                    \
   template(sun_management_GarbageCollectorImpl,        "sun/management/GarbageCollectorImpl")                     \
+  template(sun_management_ManagementFactoryHelper,     "sun/management/ManagementFactoryHelper")                  \
+  template(getDiagnosticCommandMBean_name,             "getDiagnosticCommandMBean")                               \
+  template(getDiagnosticCommandMBean_signature,        "()Lcom/sun/management/DiagnosticCommandMBean;")           \
   template(getGcInfoBuilder_name,                      "getGcInfoBuilder")                                        \
   template(getGcInfoBuilder_signature,                 "()Lsun/management/GcInfoBuilder;")                        \
   template(com_sun_management_GcInfo,                  "com/sun/management/GcInfo")                               \
   template(com_sun_management_GcInfo_constructor_signature, "(Lsun/management/GcInfoBuilder;JJJ[Ljava/lang/management/MemoryUsage;[Ljava/lang/management/MemoryUsage;[Ljava/lang/Object;)V") \
   template(createGCNotification_name,                  "createGCNotification")                                    \
   template(createGCNotification_signature,             "(JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/sun/management/GcInfo;)V") \
+  template(createDiagnosticFrameworkNotification_name, "createDiagnosticFrameworkNotification")                   \
   template(createMemoryPoolMBean_name,                 "createMemoryPoolMBean")                                   \
   template(createMemoryManagerMBean_name,              "createMemoryManagerMBean")                                \
   template(createGarbageCollectorMBean_name,           "createGarbageCollectorMBean")                             \
--- a/src/share/vm/memory/allocation.inline.hpp	Wed May 08 17:12:52 2013 -0700
+++ b/src/share/vm/memory/allocation.inline.hpp	Thu May 09 12:23:43 2013 +0200
@@ -132,7 +132,7 @@
   int alignment = os::vm_allocation_granularity();
   _size = align_size_up(_size, alignment);
 
-  _addr = os::reserve_memory(_size, NULL, alignment);
+  _addr = os::reserve_memory(_size, NULL, alignment, F);
   if (_addr == NULL) {
     vm_exit_out_of_memory(_size, OOM_MMAP_ERROR, "Allocator (reserve)");
   }
--- a/src/share/vm/prims/jvmtiClassFileReconstituter.cpp	Wed May 08 17:12:52 2013 -0700
+++ b/src/share/vm/prims/jvmtiClassFileReconstituter.cpp	Thu May 09 12:23:43 2013 +0200
@@ -341,6 +341,44 @@
   memcpy(writeable_address(length), annos->adr_at(0), length);
 }
 
+//  BootstrapMethods_attribute {
+//    u2 attribute_name_index;
+//    u4 attribute_length;
+//    u2 num_bootstrap_methods;
+//    {   u2 bootstrap_method_ref;
+//        u2 num_bootstrap_arguments;
+//        u2 bootstrap_arguments[num_bootstrap_arguments];
+//    } bootstrap_methods[num_bootstrap_methods];
+//  }
+void JvmtiClassFileReconstituter::write_bootstrapmethod_attribute() {
+  Array<u2>* operands = cpool()->operands();
+  write_attribute_name_index("BootstrapMethods");
+  int num_bootstrap_methods = ConstantPool::operand_array_length(operands);
+
+  // calculate length of attribute
+  int length = sizeof(u2); // num_bootstrap_methods
+  for (int n = 0; n < num_bootstrap_methods; n++) {
+    u2 num_bootstrap_arguments = cpool()->operand_argument_count_at(n);
+    length += sizeof(u2); // bootstrap_method_ref
+    length += sizeof(u2); // num_bootstrap_arguments
+    length += sizeof(u2) * num_bootstrap_arguments; // bootstrap_arguments[num_bootstrap_arguments]
+  }
+  write_u4(length);
+
+  // write attribute
+  write_u2(num_bootstrap_methods);
+  for (int n = 0; n < num_bootstrap_methods; n++) {
+    u2 bootstrap_method_ref = cpool()->operand_bootstrap_method_ref_index_at(n);
+    u2 num_bootstrap_arguments = cpool()->operand_argument_count_at(n);
+    write_u2(bootstrap_method_ref);
+    write_u2(num_bootstrap_arguments);
+    for (int arg = 0; arg < num_bootstrap_arguments; arg++) {
+      u2 bootstrap_argument = cpool()->operand_argument_index_at(n, arg);
+      write_u2(bootstrap_argument);
+    }
+  }
+}
+
 
 // Write InnerClasses attribute
 // JVMSpec|   InnerClasses_attribute {
@@ -513,6 +551,11 @@
   AnnotationArray* param_anno = method->parameter_annotations();
   AnnotationArray* default_anno = method->annotation_default();
 
+  // skip generated default interface methods
+  if (method->is_overpass()) {
+    return;
+  }
+
   write_u2(access_flags.get_flags() & JVM_RECOGNIZED_METHOD_MODIFIERS);
   write_u2(const_method->name_index());
   write_u2(const_method->signature_index());
@@ -592,6 +635,9 @@
   if (anno != NULL) {
     ++attr_count;     // has RuntimeVisibleAnnotations attribute
   }
+  if (cpool()->operands() != NULL) {
+    ++attr_count;
+  }
 
   write_u2(attr_count);
 
@@ -610,6 +656,9 @@
   if (anno != NULL) {
     write_annotations_attribute("RuntimeVisibleAnnotations", anno);
   }
+  if (cpool()->operands() != NULL) {
+    write_bootstrapmethod_attribute();
+  }
 }
 
 // Write the method information portion of ClassFile structure
@@ -619,8 +668,19 @@
   HandleMark hm(thread());
   Array<Method*>* methods = ikh()->methods();
   int num_methods = methods->length();
+  int num_overpass = 0;
 
-  write_u2(num_methods);
+  // count the generated default interface methods
+  // these will not be re-created by write_method_info
+  // and should not be included in the total count
+  for (int index = 0; index < num_methods; index++) {
+    Method* method = methods->at(index);
+    if (method->is_overpass()) {
+      num_overpass++;
+    }
+  }
+
+  write_u2(num_methods - num_overpass);
   if (JvmtiExport::can_maintain_original_method_order()) {
     int index;
     int original_index;
--- a/src/share/vm/prims/jvmtiClassFileReconstituter.hpp	Wed May 08 17:12:52 2013 -0700
+++ b/src/share/vm/prims/jvmtiClassFileReconstituter.hpp	Thu May 09 12:23:43 2013 +0200
@@ -127,6 +127,7 @@
   void write_signature_attribute(u2 generic_signaure_index);
   void write_attribute_name_index(const char* name);
   void write_annotations_attribute(const char* attr_name, AnnotationArray* annos);
+  void write_bootstrapmethod_attribute();
 
   address writeable_address(size_t size);
   void write_u1(u1 x);
--- a/src/share/vm/prims/perf.cpp	Wed May 08 17:12:52 2013 -0700
+++ b/src/share/vm/prims/perf.cpp	Thu May 09 12:23:43 2013 +0200
@@ -142,20 +142,20 @@
   }
 
   switch(variability) {
-  case 1:  /* V_Constant */
+  case PerfData::V_Constant:
     pl = PerfDataManager::create_long_constant(NULL_NS, (char *)name_utf,
                                                (PerfData::Units)units, value,
                                                CHECK_NULL);
     break;
 
-  case 2:  /* V_Variable */
-    pl = PerfDataManager::create_long_variable(NULL_NS, (char *)name_utf,
+  case PerfData::V_Monotonic:
+    pl = PerfDataManager::create_long_counter(NULL_NS, (char *)name_utf,
                                                (PerfData::Units)units, value,
                                                CHECK_NULL);
     break;
 
-  case 3:  /* V_Monotonic Counter */
-    pl = PerfDataManager::create_long_counter(NULL_NS, (char *)name_utf,
+  case PerfData::V_Variable:
+    pl = PerfDataManager::create_long_variable(NULL_NS, (char *)name_utf,
                                               (PerfData::Units)units, value,
                                               CHECK_NULL);
     break;
--- a/src/share/vm/runtime/os.cpp	Wed May 08 17:12:52 2013 -0700
+++ b/src/share/vm/runtime/os.cpp	Thu May 09 12:23:43 2013 +0200
@@ -1457,6 +1457,18 @@
 
   return result;
 }
+
+char* os::reserve_memory(size_t bytes, char* addr, size_t alignment_hint,
+   MEMFLAGS flags) {
+  char* result = pd_reserve_memory(bytes, addr, alignment_hint);
+  if (result != NULL) {
+    MemTracker::record_virtual_memory_reserve((address)result, bytes, CALLER_PC);
+    MemTracker::record_virtual_memory_type((address)result, flags);
+  }
+
+  return result;
+}
+
 char* os::attempt_reserve_memory_at(size_t bytes, char* addr) {
   char* result = pd_attempt_reserve_memory_at(bytes, addr);
   if (result != NULL) {
--- a/src/share/vm/runtime/os.hpp	Wed May 08 17:12:52 2013 -0700
+++ b/src/share/vm/runtime/os.hpp	Thu May 09 12:23:43 2013 +0200
@@ -255,6 +255,8 @@
   static int    vm_allocation_granularity();
   static char*  reserve_memory(size_t bytes, char* addr = 0,
                                size_t alignment_hint = 0);
+  static char*  reserve_memory(size_t bytes, char* addr,
+                               size_t alignment_hint, MEMFLAGS flags);
   static char*  reserve_memory_aligned(size_t size, size_t alignment);
   static char*  attempt_reserve_memory_at(size_t bytes, char* addr);
   static void   split_reserved_memory(char *base, size_t size,
--- a/src/share/vm/runtime/serviceThread.cpp	Wed May 08 17:12:52 2013 -0700
+++ b/src/share/vm/runtime/serviceThread.cpp	Thu May 09 12:23:43 2013 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -29,6 +29,8 @@
 #include "runtime/mutexLocker.hpp"
 #include "prims/jvmtiImpl.hpp"
 #include "services/gcNotifier.hpp"
+#include "services/diagnosticArgument.hpp"
+#include "services/diagnosticFramework.hpp"
 
 ServiceThread* ServiceThread::_instance = NULL;
 
@@ -83,6 +85,7 @@
     bool sensors_changed = false;
     bool has_jvmti_events = false;
     bool has_gc_notification_event = false;
+    bool has_dcmd_notification_event = false;
     JvmtiDeferredEvent jvmti_event;
     {
       // Need state transition ThreadBlockInVM so that this thread
@@ -98,7 +101,8 @@
       MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag);
       while (!(sensors_changed = LowMemoryDetector::has_pending_requests()) &&
              !(has_jvmti_events = JvmtiDeferredEventQueue::has_events()) &&
-              !(has_gc_notification_event = GCNotifier::has_event())) {
+              !(has_gc_notification_event = GCNotifier::has_event()) &&
+              !(has_dcmd_notification_event = DCmdFactory::has_pending_jmx_notification())) {
         // wait until one of the sensors has pending requests, or there is a
         // pending JVMTI event or JMX GC notification to post
         Service_lock->wait(Mutex::_no_safepoint_check_flag);
@@ -120,6 +124,10 @@
     if(has_gc_notification_event) {
         GCNotifier::sendNotification(CHECK);
     }
+
+    if(has_dcmd_notification_event) {
+      DCmdFactory::send_notification(CHECK);
+    }
   }
 }
 
--- a/src/share/vm/services/attachListener.cpp	Wed May 08 17:12:52 2013 -0700
+++ b/src/share/vm/services/attachListener.cpp	Thu May 09 12:23:43 2013 +0200
@@ -157,7 +157,7 @@
   Thread* THREAD = Thread::current();
   // All the supplied jcmd arguments are stored as a single
   // string (op->arg(0)). This is parsed by the Dcmd framework.
-  DCmd::parse_and_execute(out, op->arg(0), ' ', THREAD);
+  DCmd::parse_and_execute(DCmd_Source_AttachAPI, out, op->arg(0), ' ', THREAD);
   if (HAS_PENDING_EXCEPTION) {
     java_lang_Throwable::print(PENDING_EXCEPTION, out);
     out->cr();
--- a/src/share/vm/services/diagnosticCommand.cpp	Wed May 08 17:12:52 2013 -0700
+++ b/src/share/vm/services/diagnosticCommand.cpp	Thu May 09 12:23:43 2013 +0200
@@ -34,26 +34,33 @@
 
 void DCmdRegistrant::register_dcmds(){
   // Registration of the diagnostic commands
-  // First boolean argument specifies if the command is enabled
-  // Second boolean argument specifies if the command is hidden
-  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<HelpDCmd>(true, false));
-  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<VersionDCmd>(true, false));
-  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<CommandLineDCmd>(true, false));
-  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<PrintSystemPropertiesDCmd>(true, false));
-  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<PrintVMFlagsDCmd>(true, false));
-  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<VMUptimeDCmd>(true, false));
-  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<SystemGCDCmd>(true, false));
-  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<RunFinalizationDCmd>(true, false));
+  // First argument specifies which interfaces will export the command
+  // Second argument specifies if the command is enabled
+  // Third  argument specifies if the command is hidden
+  uint32_t full_export = DCmd_Source_Internal | DCmd_Source_AttachAPI
+                         | DCmd_Source_MBean;
+  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<HelpDCmd>(full_export, true, false));
+  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<VersionDCmd>(full_export, true, false));
+  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<CommandLineDCmd>(full_export, true, false));
+  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<PrintSystemPropertiesDCmd>(full_export, true, false));
+  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<PrintVMFlagsDCmd>(full_export, true, false));
+  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<VMUptimeDCmd>(full_export, true, false));
+  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<SystemGCDCmd>(full_export, true, false));
+  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<RunFinalizationDCmd>(full_export, true, false));
 #if INCLUDE_SERVICES // Heap dumping/inspection supported
-  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<HeapDumpDCmd>(true, false));
-  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ClassHistogramDCmd>(true, false));
-  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ClassStatsDCmd>(true, false));
+  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<HeapDumpDCmd>(full_export, true, false));
+  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ClassHistogramDCmd>(full_export, true, false));
+  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ClassStatsDCmd>(full_export, true, false));
 #endif // INCLUDE_SERVICES
-  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ThreadDumpDCmd>(true, false));
-  //Enhanced JMX Agent Support
-  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JMXStartRemoteDCmd>(true,false));
-  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JMXStartLocalDCmd>(true,false));
-  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JMXStopRemoteDCmd>(true,false));
+  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ThreadDumpDCmd>(full_export, true, false));
+
+  // Enhanced JMX Agent Support
+  // These commands won't be exported via the DiagnosticCommandMBean until an
+  // appropriate permission is created for them
+  uint32_t jmx_agent_export_flags = DCmd_Source_Internal | DCmd_Source_AttachAPI;
+  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JMXStartRemoteDCmd>(jmx_agent_export_flags, true,false));
+  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JMXStartLocalDCmd>(jmx_agent_export_flags, true,false));
+  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JMXStopRemoteDCmd>(jmx_agent_export_flags, true,false));
 
 }
 
@@ -72,29 +79,37 @@
   _dcmdparser.add_dcmd_argument(&_cmd);
 };
 
-void HelpDCmd::execute(TRAPS) {
+void HelpDCmd::execute(DCmdSource source, TRAPS) {
   if (_all.value()) {
-    GrowableArray<const char*>* cmd_list = DCmdFactory::DCmd_list();
+    GrowableArray<const char*>* cmd_list = DCmdFactory::DCmd_list(source);
     for (int i = 0; i < cmd_list->length(); i++) {
-      DCmdFactory* factory = DCmdFactory::factory(cmd_list->at(i),
+      DCmdFactory* factory = DCmdFactory::factory(source, cmd_list->at(i),
                                                   strlen(cmd_list->at(i)));
-      if (!factory->is_hidden()) {
-        output()->print_cr("%s%s", factory->name(),
-                           factory->is_enabled() ? "" : " [disabled]");
-        output()->print_cr("\t%s", factory->description());
-        output()->cr();
-      }
+      output()->print_cr("%s%s", factory->name(),
+                         factory->is_enabled() ? "" : " [disabled]");
+      output()->print_cr("\t%s", factory->description());
+      output()->cr();
       factory = factory->next();
     }
   } else if (_cmd.has_value()) {
     DCmd* cmd = NULL;
-    DCmdFactory* factory = DCmdFactory::factory(_cmd.value(),
+    DCmdFactory* factory = DCmdFactory::factory(source, _cmd.value(),
                                                 strlen(_cmd.value()));
     if (factory != NULL) {
       output()->print_cr("%s%s", factory->name(),
                          factory->is_enabled() ? "" : " [disabled]");
       output()->print_cr(factory->description());
       output()->print_cr("\nImpact: %s", factory->impact());
+      JavaPermission p = factory->permission();
+      if(p._class != NULL) {
+        if(p._action != NULL) {
+          output()->print_cr("\nPermission: %s(%s, %s)",
+                  p._class, p._name == NULL ? "null" : p._name, p._action);
+        } else {
+          output()->print_cr("\nPermission: %s(%s)",
+                  p._class, p._name == NULL ? "null" : p._name);
+        }
+      }
       output()->cr();
       cmd = factory->create_resource_instance(output());
       if (cmd != NULL) {
@@ -106,14 +121,12 @@
     }
   } else {
     output()->print_cr("The following commands are available:");
-    GrowableArray<const char *>* cmd_list = DCmdFactory::DCmd_list();
+    GrowableArray<const char *>* cmd_list = DCmdFactory::DCmd_list(source);
     for (int i = 0; i < cmd_list->length(); i++) {
-      DCmdFactory* factory = DCmdFactory::factory(cmd_list->at(i),
+      DCmdFactory* factory = DCmdFactory::factory(source, cmd_list->at(i),
                                                   strlen(cmd_list->at(i)));
-      if (!factory->is_hidden()) {
-        output()->print_cr("%s%s", factory->name(),
-                           factory->is_enabled() ? "" : " [disabled]");
-      }
+      output()->print_cr("%s%s", factory->name(),
+                         factory->is_enabled() ? "" : " [disabled]");
       factory = factory->_next;
     }
     output()->print_cr("\nFor more information about a specific command use 'help <command>'.");
@@ -131,7 +144,7 @@
   }
 }
 
-void VersionDCmd::execute(TRAPS) {
+void VersionDCmd::execute(DCmdSource source, TRAPS) {
   output()->print_cr("%s version %s", Abstract_VM_Version::vm_name(),
           Abstract_VM_Version::vm_release());
   JDK_Version jdk_version = JDK_Version::current();
@@ -150,7 +163,7 @@
   _dcmdparser.add_dcmd_option(&_all);
 }
 
-void PrintVMFlagsDCmd::execute(TRAPS) {
+void PrintVMFlagsDCmd::execute(DCmdSource source, TRAPS) {
   if (_all.value()) {
     CommandLineFlags::printFlags(output(), true);
   } else {
@@ -169,7 +182,7 @@
     }
 }
 
-void PrintSystemPropertiesDCmd::execute(TRAPS) {
+void PrintSystemPropertiesDCmd::execute(DCmdSource source, TRAPS) {
   // load sun.misc.VMSupport
   Symbol* klass = vmSymbols::sun_misc_VMSupport();
   Klass* k = SystemDictionary::resolve_or_fail(klass, true, CHECK);
@@ -219,7 +232,7 @@
   _dcmdparser.add_dcmd_option(&_date);
 }
 
-void VMUptimeDCmd::execute(TRAPS) {
+void VMUptimeDCmd::execute(DCmdSource source, TRAPS) {
   if (_date.value()) {
     output()->date_stamp(true, "", ": ");
   }
@@ -239,11 +252,15 @@
   }
 }
 
-void SystemGCDCmd::execute(TRAPS) {
-  Universe::heap()->collect(GCCause::_java_lang_system_gc);
+void SystemGCDCmd::execute(DCmdSource source, TRAPS) {
+  if (!DisableExplicitGC) {
+    Universe::heap()->collect(GCCause::_java_lang_system_gc);
+  } else {
+    output()->print_cr("Explicit GC is disabled, no GC has been performed.");
+  }
 }
 
-void RunFinalizationDCmd::execute(TRAPS) {
+void RunFinalizationDCmd::execute(DCmdSource source, TRAPS) {
   Klass* k = SystemDictionary::resolve_or_fail(vmSymbols::java_lang_System(),
                                                  true, CHECK);
   instanceKlassHandle klass(THREAD, k);
@@ -263,7 +280,7 @@
   _dcmdparser.add_dcmd_argument(&_filename);
 }
 
-void HeapDumpDCmd::execute(TRAPS) {
+void HeapDumpDCmd::execute(DCmdSource source, TRAPS) {
   // Request a full GC before heap dump if _all is false
   // This helps reduces the amount of unreachable objects in the dump
   // and makes it easier to browse.
@@ -301,7 +318,7 @@
   _dcmdparser.add_dcmd_option(&_all);
 }
 
-void ClassHistogramDCmd::execute(TRAPS) {
+void ClassHistogramDCmd::execute(DCmdSource source, TRAPS) {
   VM_GC_HeapInspection heapop(output(),
                               !_all.value() /* request full gc if false */,
                               true /* need_prologue */);
@@ -337,7 +354,7 @@
   _dcmdparser.add_dcmd_argument(&_columns);
 }
 
-void ClassStatsDCmd::execute(TRAPS) {
+void ClassStatsDCmd::execute(DCmdSource source, TRAPS) {
   if (!UnlockDiagnosticVMOptions) {
     output()->print_cr("GC.class_stats command requires -XX:+UnlockDiagnosticVMOptions");
     return;
@@ -384,7 +401,7 @@
   _dcmdparser.add_dcmd_option(&_locks);
 }
 
-void ThreadDumpDCmd::execute(TRAPS) {
+void ThreadDumpDCmd::execute(DCmdSource source, TRAPS) {
   // thread stacks
   VM_PrintThreads op1(output(), _locks.value());
   VMThread::execute(&op1);
@@ -526,7 +543,8 @@
   }
 }
 
-void JMXStartRemoteDCmd::execute(TRAPS) {
+
+void JMXStartRemoteDCmd::execute(DCmdSource source, TRAPS) {
     ResourceMark rm(THREAD);
     HandleMark hm(THREAD);
 
@@ -593,7 +611,7 @@
   // do nothing
 }
 
-void JMXStartLocalDCmd::execute(TRAPS) {
+void JMXStartLocalDCmd::execute(DCmdSource source, TRAPS) {
     ResourceMark rm(THREAD);
     HandleMark hm(THREAD);
 
@@ -611,7 +629,7 @@
 }
 
 
-void JMXStopRemoteDCmd::execute(TRAPS) {
+void JMXStopRemoteDCmd::execute(DCmdSource source, TRAPS) {
     ResourceMark rm(THREAD);
     HandleMark hm(THREAD);
 
--- a/src/share/vm/services/diagnosticCommand.hpp	Wed May 08 17:12:52 2013 -0700
+++ b/src/share/vm/services/diagnosticCommand.hpp	Thu May 09 12:23:43 2013 +0200
@@ -51,7 +51,7 @@
   }
   static const char* impact() { return "Low"; }
   static int num_arguments();
-  virtual void execute(TRAPS);
+  virtual void execute(DCmdSource source, TRAPS);
 };
 
 class VersionDCmd : public DCmd {
@@ -62,8 +62,13 @@
     return "Print JVM version information.";
   }
   static const char* impact() { return "Low"; }
+  static const JavaPermission permission() {
+    JavaPermission p = {"java.util.PropertyPermission",
+                        "java.vm.version", "read"};
+    return p;
+  }
   static int num_arguments() { return 0; }
-  virtual void execute(TRAPS);
+  virtual void execute(DCmdSource source, TRAPS);
 };
 
 class CommandLineDCmd : public DCmd {
@@ -74,8 +79,13 @@
     return "Print the command line used to start this VM instance.";
   }
   static const char* impact() { return "Low"; }
+  static const JavaPermission permission() {
+    JavaPermission p = {"java.lang.management.ManagementPermission",
+                        "monitor", NULL};
+    return p;
+  }
   static int num_arguments() { return 0; }
-  virtual void execute(TRAPS) {
+  virtual void execute(DCmdSource source, TRAPS) {
     Arguments::print_on(_output);
   }
 };
@@ -91,8 +101,13 @@
     static const char* impact() {
       return "Low";
     }
+    static const JavaPermission permission() {
+      JavaPermission p = {"java.util.PropertyPermission",
+                          "*", "read"};
+      return p;
+    }
     static int num_arguments() { return 0; }
-    virtual void execute(TRAPS);
+    virtual void execute(DCmdSource source, TRAPS);
 };
 
 // See also: print_flag in attachListener.cpp
@@ -108,8 +123,13 @@
   static const char* impact() {
     return "Low";
   }
+  static const JavaPermission permission() {
+    JavaPermission p = {"java.lang.management.ManagementPermission",
+                        "monitor", NULL};
+    return p;
+  }
   static int num_arguments();
-  virtual void execute(TRAPS);
+  virtual void execute(DCmdSource source, TRAPS);
 };
 
 class VMUptimeDCmd : public DCmdWithParser {
@@ -125,7 +145,7 @@
     return "Low";
   }
   static int num_arguments();
-  virtual void execute(TRAPS);
+  virtual void execute(DCmdSource source, TRAPS);
 };
 
 class SystemGCDCmd : public DCmd {
@@ -139,7 +159,7 @@
       return "Medium: Depends on Java heap size and content.";
     }
     static int num_arguments() { return 0; }
-    virtual void execute(TRAPS);
+    virtual void execute(DCmdSource source, TRAPS);
 };
 
 class RunFinalizationDCmd : public DCmd {
@@ -153,7 +173,7 @@
       return "Medium: Depends on Java content.";
     }
     static int num_arguments() { return 0; }
-    virtual void execute(TRAPS);
+    virtual void execute(DCmdSource source, TRAPS);
 };
 
 #if INCLUDE_SERVICES   // Heap dumping supported
@@ -174,8 +194,13 @@
     return "High: Depends on Java heap size and content. "
            "Request a full GC unless the '-all' option is specified.";
   }
+  static const JavaPermission permission() {
+    JavaPermission p = {"java.lang.management.ManagementPermission",
+                        "monitor", NULL};
+    return p;
+  }
   static int num_arguments();
-  virtual void execute(TRAPS);
+  virtual void execute(DCmdSource source, TRAPS);
 };
 #endif // INCLUDE_SERVICES
 
@@ -194,8 +219,13 @@
   static const char* impact() {
     return "High: Depends on Java heap size and content.";
   }
+  static const JavaPermission permission() {
+    JavaPermission p = {"java.lang.management.ManagementPermission",
+                        "monitor", NULL};
+    return p;
+  }
   static int num_arguments();
-  virtual void execute(TRAPS);
+  virtual void execute(DCmdSource source, TRAPS);
 };
 
 class ClassStatsDCmd : public DCmdWithParser {
@@ -216,7 +246,7 @@
     return "High: Depends on Java heap size and content.";
   }
   static int num_arguments();
-  virtual void execute(TRAPS);
+  virtual void execute(DCmdSource source, TRAPS);
 };
 
 // See also: thread_dump in attachListener.cpp
@@ -232,8 +262,13 @@
   static const char* impact() {
     return "Medium: Depends on the number of threads.";
   }
+  static const JavaPermission permission() {
+    JavaPermission p = {"java.lang.management.ManagementPermission",
+                        "monitor", NULL};
+    return p;
+  }
   static int num_arguments();
-  virtual void execute(TRAPS);
+  virtual void execute(DCmdSource source, TRAPS);
 };
 
 // Enhanced JMX Agent support
@@ -281,7 +316,7 @@
 
   static int num_arguments();
 
-  virtual void execute(TRAPS);
+  virtual void execute(DCmdSource source, TRAPS);
 
 };
 
@@ -302,7 +337,7 @@
     return "Start local management agent.";
   }
 
-  virtual void execute(TRAPS);
+  virtual void execute(DCmdSource source, TRAPS);
 
 };
 
@@ -321,7 +356,7 @@
     return "Stop remote management agent.";
   }
 
-  virtual void execute(TRAPS);
+  virtual void execute(DCmdSource source, TRAPS);
 };
 
 #endif // SHARE_VM_SERVICES_DIAGNOSTICCOMMAND_HPP
--- a/src/share/vm/services/diagnosticFramework.cpp	Wed May 08 17:12:52 2013 -0700
+++ b/src/share/vm/services/diagnosticFramework.cpp	Thu May 09 12:23:43 2013 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -359,7 +359,7 @@
   while (arg != NULL) {
     array->append(new DCmdArgumentInfo(arg->name(), arg->description(),
                   arg->type(), arg->default_string(), arg->is_mandatory(),
-                  false, idx));
+                  false, arg->allow_multiple(), idx));
     idx++;
     arg = arg->next();
   }
@@ -367,32 +367,42 @@
   while (arg != NULL) {
     array->append(new DCmdArgumentInfo(arg->name(), arg->description(),
                   arg->type(), arg->default_string(), arg->is_mandatory(),
-                  true));
+                  true, arg->allow_multiple()));
     arg = arg->next();
   }
   return array;
 }
 
 DCmdFactory* DCmdFactory::_DCmdFactoryList = NULL;
+bool DCmdFactory::_has_pending_jmx_notification = false;
 
-void DCmd::parse_and_execute(outputStream* out, const char* cmdline,
-                             char delim, TRAPS) {
+void DCmd::parse_and_execute(DCmdSource source, outputStream* out,
+                             const char* cmdline, char delim, TRAPS) {
 
   if (cmdline == NULL) return; // Nothing to do!
   DCmdIter iter(cmdline, '\n');
 
+  int count = 0;
   while (iter.has_next()) {
+    if(source == DCmd_Source_MBean && count > 0) {
+      // When diagnostic commands are invoked via JMX, each command line
+      // must contains one and only one command because of the Permission
+      // checks performed by the DiagnosticCommandMBean
+      THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
+              "Invalid syntax");
+    }
     CmdLine line = iter.next();
     if (line.is_stop()) {
       break;
     }
     if (line.is_executable()) {
-      DCmd* command = DCmdFactory::create_local_DCmd(line, out, CHECK);
+      DCmd* command = DCmdFactory::create_local_DCmd(source, line, out, CHECK);
       assert(command != NULL, "command error must be handled before this line");
       DCmdMark mark(command);
       command->parse(&line, delim, CHECK);
-      command->execute(CHECK);
+      command->execute(source, CHECK);
     }
+    count++;
   }
 }
 
@@ -420,15 +430,78 @@
   return _dcmdparser.argument_info_array();
 }
 
-Mutex* DCmdFactory::_dcmdFactory_lock = new Mutex(Mutex::leaf, "DCmdFactory", true);
+void DCmdFactory::push_jmx_notification_request() {
+  MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag);
+  _has_pending_jmx_notification = true;
+  Service_lock->notify_all();
+}
+
+void DCmdFactory::send_notification(TRAPS) {
+  DCmdFactory::send_notification_internal(THREAD);
+  // Clearing pending exception to avoid premature termination of
+  // the service thread
+  if (HAS_PENDING_EXCEPTION) {
+    CLEAR_PENDING_EXCEPTION;
+  }
+}
+void DCmdFactory::send_notification_internal(TRAPS) {
+  ResourceMark rm(THREAD);
+  HandleMark hm(THREAD);
+  bool notif = false;
+  {
+    MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag);
+    notif = _has_pending_jmx_notification;
+    _has_pending_jmx_notification = false;
+  }
+  if (notif) {
+
+    Klass* k = Management::sun_management_ManagementFactoryHelper_klass(CHECK);
+    instanceKlassHandle mgmt_factory_helper_klass(THREAD, k);
 
-DCmdFactory* DCmdFactory::factory(const char* name, size_t len) {
+    JavaValue result(T_OBJECT);
+    JavaCalls::call_static(&result,
+            mgmt_factory_helper_klass,
+            vmSymbols::getDiagnosticCommandMBean_name(),
+            vmSymbols::getDiagnosticCommandMBean_signature(),
+            CHECK);
+
+    instanceOop m = (instanceOop) result.get_jobject();
+    instanceHandle dcmd_mbean_h(THREAD, m);
+
+    Klass* k2 = Management::sun_management_DiagnosticCommandImpl_klass(CHECK);
+    instanceKlassHandle dcmd_mbean_klass(THREAD, k2);
+
+    if (!dcmd_mbean_h->is_a(k2)) {
+      THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
+              "ManagementFactory.getDiagnosticCommandMBean didn't return a DiagnosticCommandMBean instance");
+    }
+
+    JavaValue result2(T_VOID);
+    JavaCallArguments args2(dcmd_mbean_h);
+
+    JavaCalls::call_virtual(&result2,
+            dcmd_mbean_klass,
+            vmSymbols::createDiagnosticFrameworkNotification_name(),
+            vmSymbols::void_method_signature(),
+            &args2,
+            CHECK);
+  }
+}
+
+Mutex* DCmdFactory::_dcmdFactory_lock = new Mutex(Mutex::leaf, "DCmdFactory", true);
+bool DCmdFactory::_send_jmx_notification = false;
+
+DCmdFactory* DCmdFactory::factory(DCmdSource source, const char* name, size_t len) {
   MutexLockerEx ml(_dcmdFactory_lock, Mutex::_no_safepoint_check_flag);
   DCmdFactory* factory = _DCmdFactoryList;
   while (factory != NULL) {
     if (strlen(factory->name()) == len &&
         strncmp(name, factory->name(), len) == 0) {
-      return factory;
+      if(factory->export_flags() & source) {
+        return factory;
+      } else {
+        return NULL;
+      }
     }
     factory = factory->_next;
   }
@@ -439,11 +512,16 @@
   MutexLockerEx ml(_dcmdFactory_lock, Mutex::_no_safepoint_check_flag);
   factory->_next = _DCmdFactoryList;
   _DCmdFactoryList = factory;
+  if (_send_jmx_notification && !factory->_hidden
+      && (factory->_export_flags & DCmd_Source_MBean)) {
+    DCmdFactory::push_jmx_notification_request();
+  }
   return 0; // Actually, there's no checks for duplicates
 }
 
-DCmd* DCmdFactory::create_global_DCmd(CmdLine &line, outputStream* out, TRAPS) {
-  DCmdFactory* f = factory(line.cmd_addr(), line.cmd_len());
+DCmd* DCmdFactory::create_global_DCmd(DCmdSource source, CmdLine &line,
+                                      outputStream* out, TRAPS) {
+  DCmdFactory* f = factory(source, line.cmd_addr(), line.cmd_len());
   if (f != NULL) {
     if (f->is_enabled()) {
       THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(),
@@ -455,8 +533,9 @@
              "Unknown diagnostic command");
 }
 
-DCmd* DCmdFactory::create_local_DCmd(CmdLine &line, outputStream* out, TRAPS) {
-  DCmdFactory* f = factory(line.cmd_addr(), line.cmd_len());
+DCmd* DCmdFactory::create_local_DCmd(DCmdSource source, CmdLine &line,
+                                     outputStream* out, TRAPS) {
+  DCmdFactory* f = factory(source, line.cmd_addr(), line.cmd_len());
   if (f != NULL) {
     if (!f->is_enabled()) {
       THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(),
@@ -468,12 +547,12 @@
              "Unknown diagnostic command");
 }
 
-GrowableArray<const char*>* DCmdFactory::DCmd_list() {
+GrowableArray<const char*>* DCmdFactory::DCmd_list(DCmdSource source) {
   MutexLockerEx ml(_dcmdFactory_lock, Mutex::_no_safepoint_check_flag);
   GrowableArray<const char*>* array = new GrowableArray<const char*>();
   DCmdFactory* factory = _DCmdFactoryList;
   while (factory != NULL) {
-    if (!factory->is_hidden()) {
+    if (!factory->is_hidden() && (factory->export_flags() & source)) {
       array->append(factory->name());
     }
     factory = factory->next();
@@ -481,15 +560,16 @@
   return array;
 }
 
-GrowableArray<DCmdInfo*>* DCmdFactory::DCmdInfo_list() {
+GrowableArray<DCmdInfo*>* DCmdFactory::DCmdInfo_list(DCmdSource source ) {
   MutexLockerEx ml(_dcmdFactory_lock, Mutex::_no_safepoint_check_flag);
   GrowableArray<DCmdInfo*>* array = new GrowableArray<DCmdInfo*>();
   DCmdFactory* factory = _DCmdFactoryList;
   while (factory != NULL) {
-    if (!factory->is_hidden()) {
+    if (!factory->is_hidden() && (factory->export_flags() & source)) {
       array->append(new DCmdInfo(factory->name(),
                     factory->description(), factory->impact(),
-                    factory->num_arguments(), factory->is_enabled()));
+                    factory->permission(), factory->num_arguments(),
+                    factory->is_enabled()));
     }
     factory = factory->next();
   }
--- a/src/share/vm/services/diagnosticFramework.hpp	Wed May 08 17:12:52 2013 -0700
+++ b/src/share/vm/services/diagnosticFramework.hpp	Thu May 09 12:23:43 2013 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -34,6 +34,22 @@
 #include "utilities/ostream.hpp"
 
 
+enum DCmdSource {
+  DCmd_Source_Internal  = 0x01U,  // invocation from the JVM
+  DCmd_Source_AttachAPI = 0x02U,  // invocation via the attachAPI
+  DCmd_Source_MBean     = 0x04U   // invocation via a MBean
+};
+
+// Warning: strings referenced by the JavaPermission struct are passed to
+// the native part of the JDK. Avoid use of dynamically allocated strings
+// that could be de-allocated before the JDK native code had time to
+// convert them into Java Strings.
+struct JavaPermission {
+  const char* _class;
+  const char* _name;
+  const char* _action;
+};
+
 // CmdLine is the class used to handle a command line containing a single
 // diagnostic command and its arguments. It provides methods to access the
 // command name and the beginning of the arguments. The class is also
@@ -113,26 +129,30 @@
 // used to export the description to the JMX interface of the framework.
 class DCmdInfo : public ResourceObj {
 protected:
-  const char* _name;
-  const char* _description;
-  const char* _impact;
-  int         _num_arguments;
-  bool        _is_enabled;
+  const char* _name;           /* Name of the diagnostic command */
+  const char* _description;    /* Short description */
+  const char* _impact;         /* Impact on the JVM */
+  JavaPermission _permission;  /* Java Permission required to execute this command if any */
+  int         _num_arguments;  /* Number of supported options or arguments */
+  bool        _is_enabled;     /* True if the diagnostic command can be invoked, false otherwise */
 public:
   DCmdInfo(const char* name,
           const char* description,
           const char* impact,
+          JavaPermission permission,
           int num_arguments,
           bool enabled) {
     this->_name = name;
     this->_description = description;
     this->_impact = impact;
+    this->_permission = permission;
     this->_num_arguments = num_arguments;
     this->_is_enabled = enabled;
   }
   const char* name() const { return _name; }
   const char* description() const { return _description; }
   const char* impact() const { return _impact; }
+  JavaPermission permission() const { return _permission; }
   int num_arguments() const { return _num_arguments; }
   bool is_enabled() const { return _is_enabled; }
 
@@ -144,16 +164,20 @@
 // framework.
 class DCmdArgumentInfo : public ResourceObj {
 protected:
-  const char* _name;
-  const char* _description;
-  const char* _type;
-  const char* _default_string;
-  bool        _mandatory;
-  bool        _option;
-  int         _position;
+  const char* _name;            /* Option/Argument name*/
+  const char* _description;     /* Short description */
+  const char* _type;            /* Type: STRING, BOOLEAN, etc. */
+  const char* _default_string;  /* Default value in a parsable string */
+  bool        _mandatory;       /* True if the option/argument is mandatory */
+  bool        _option;          /* True if it is an option, false if it is an argument */
+                                /* (see diagnosticFramework.hpp for option/argument definitions) */
+  bool        _multiple;        /* True is the option can be specified several time */
+  int         _position;        /* Expected position for this argument (this field is */
+                                /* meaningless for options) */
 public:
   DCmdArgumentInfo(const char* name, const char* description, const char* type,
-                   const char* default_string, bool mandatory, bool option) {
+                   const char* default_string, bool mandatory, bool option,
+                   bool multiple) {
     this->_name = name;
     this->_description = description;
     this->_type = type;
@@ -161,11 +185,12 @@
     this->_option = option;
     this->_mandatory = mandatory;
     this->_option = option;
+    this->_multiple = multiple;
     this->_position = -1;
   }
   DCmdArgumentInfo(const char* name, const char* description, const char* type,
                    const char* default_string, bool mandatory, bool option,
-                   int position) {
+                   bool multiple, int position) {
     this->_name = name;
     this->_description = description;
     this->_type = type;
@@ -173,6 +198,7 @@
     this->_option = option;
     this->_mandatory = mandatory;
     this->_option = option;
+    this->_multiple = multiple;
     this->_position = position;
   }
   const char* name() const { return _name; }
@@ -181,11 +207,29 @@
   const char* default_string() const { return _default_string; }
   bool is_mandatory() const { return _mandatory; }
   bool is_option() const { return _option; }
+  bool is_multiple() const { return _multiple; }
   int position() const { return _position; }
 };
 
 // The DCmdParser class can be used to create an argument parser for a
 // diagnostic command. It is not mandatory to use it to parse arguments.
+// The DCmdParser parses a CmdLine instance according to the parameters that
+// have been declared by its associated diagnostic command. A parameter can
+// either be an option or an argument. Options are identified by the option name
+// while arguments are identified by their position in the command line. The
+// position of an argument is defined relative to all arguments passed on the
+// command line, options are not considered when defining an argument position.
+// The generic syntax of a diagnostic command is:
+//
+//    <command name> [<option>=<value>] [<argument_value>]
+//
+// Example:
+//
+//    command_name option1=value1 option2=value argumentA argumentB argumentC
+//
+// In this command line, the diagnostic command receives five parameters, two
+// options named option1 and option2, and three arguments. argumentA's position
+// is 0, argumentB's position is 1 and argumentC's position is 2.
 class DCmdParser {
 private:
   GenDCmdArgument* _options;
@@ -249,6 +293,19 @@
   // longer description can provide more specific details like the fact that Thread Dump
   // impact depends on the heap size.
   static const char* impact() { return "Low: No impact"; }
+  // The permission() method returns the description of Java Permission. This
+  // permission is required when the diagnostic command is invoked via the
+  // DiagnosticCommandMBean. The rationale for this permission check is that
+  // the DiagnosticCommandMBean can be used to perform remote invocations of
+  // diagnostic commands through the PlatformMBeanServer. The (optional) Java
+  // Permission associated with each diagnostic command should ease the work
+  // of system administrators to write policy files granting permissions to
+  // execute diagnostic commands to remote users. Any diagnostic command with
+  // a potential impact on security should overwrite this method.
+  static const JavaPermission permission() {
+    JavaPermission p = {NULL, NULL, NULL};
+    return p;
+  }
   static int num_arguments() { return 0; }
   outputStream* output() { return _output; }
   bool is_heap_allocated()  { return _is_heap_allocated; }
@@ -263,7 +320,7 @@
                 "The argument list of this diagnostic command should be empty.");
     }
   }
-  virtual void execute(TRAPS) { }
+  virtual void execute(DCmdSource source, TRAPS) { }
   virtual void reset(TRAPS) { }
   virtual void cleanup() { }
 
@@ -278,7 +335,7 @@
   }
 
   // main method to invoke the framework
-  static void parse_and_execute(outputStream* out, const char* cmdline,
+  static void parse_and_execute(DCmdSource source, outputStream* out, const char* cmdline,
                                 char delim, TRAPS);
 };
 
@@ -291,9 +348,10 @@
   static const char* description() { return "No Help";}
   static const char* disabled_message() { return "Diagnostic command currently disabled"; }
   static const char* impact() { return "Low: No impact"; }
+  static const JavaPermission permission() {JavaPermission p = {NULL, NULL, NULL}; return p; }
   static int num_arguments() { return 0; }
   virtual void parse(CmdLine *line, char delim, TRAPS);
-  virtual void execute(TRAPS) { }
+  virtual void execute(DCmdSource source, TRAPS) { }
   virtual void reset(TRAPS);
   virtual void cleanup();
   virtual void print_help(const char* name);
@@ -323,6 +381,8 @@
 class DCmdFactory: public CHeapObj<mtInternal> {
 private:
   static Mutex*       _dcmdFactory_lock;
+  static bool         _send_jmx_notification;
+  static bool         _has_pending_jmx_notification;
   // Pointer to the next factory in the singly-linked list of registered
   // diagnostic commands
   DCmdFactory*        _next;
@@ -333,19 +393,23 @@
   // When hidden, a diagnostic command doesn't appear in the list of commands
   // provided by the 'help' command.
   bool                _hidden;
+  uint32_t            _export_flags;
   int                 _num_arguments;
   static DCmdFactory* _DCmdFactoryList;
 public:
-  DCmdFactory(int num_arguments, bool enabled, bool hidden) {
+  DCmdFactory(int num_arguments, uint32_t flags, bool enabled, bool hidden) {
     _next = NULL;
     _enabled = enabled;
     _hidden = hidden;
+    _export_flags = flags;
     _num_arguments = num_arguments;
   }
   bool is_enabled() const { return _enabled; }
   void set_enabled(bool b) { _enabled = b; }
   bool is_hidden() const { return _hidden; }
   void set_hidden(bool b) { _hidden = b; }
+  uint32_t export_flags() { return _export_flags; }
+  void set_export_flags(uint32_t f) { _export_flags = f; }
   int num_arguments() { return _num_arguments; }
   DCmdFactory* next() { return _next; }
   virtual DCmd* create_Cheap_instance(outputStream* output) = 0;
@@ -353,19 +417,29 @@
   virtual const char* name() const = 0;
   virtual const char* description() const = 0;
   virtual const char* impact() const = 0;
+  virtual const JavaPermission permission() const = 0;
   virtual const char* disabled_message() const = 0;
   // Register a DCmdFactory to make a diagnostic command available.
   // Once registered, a diagnostic command must not be unregistered.
   // To prevent a diagnostic command from being executed, just set the
   // enabled flag to false.
   static int register_DCmdFactory(DCmdFactory* factory);
-  static DCmdFactory* factory(const char* cmd, size_t len);
+  static DCmdFactory* factory(DCmdSource source, const char* cmd, size_t len);
   // Returns a C-heap allocated diagnostic command for the given command line
-  static DCmd* create_global_DCmd(CmdLine &line, outputStream* out, TRAPS);
+  static DCmd* create_global_DCmd(DCmdSource source, CmdLine &line, outputStream* out, TRAPS);
   // Returns a resourceArea allocated diagnostic command for the given command line
-  static DCmd* create_local_DCmd(CmdLine &line, outputStream* out, TRAPS);
-  static GrowableArray<const char*>* DCmd_list();
-  static GrowableArray<DCmdInfo*>* DCmdInfo_list();
+  static DCmd* create_local_DCmd(DCmdSource source, CmdLine &line, outputStream* out, TRAPS);
+  static GrowableArray<const char*>* DCmd_list(DCmdSource source);
+  static GrowableArray<DCmdInfo*>* DCmdInfo_list(DCmdSource source);
+
+  static void set_jmx_notification_enabled(bool enabled) {
+    _send_jmx_notification = enabled;
+  }
+  static void push_jmx_notification_request();
+  static bool has_pending_jmx_notification() { return _has_pending_jmx_notification; }
+  static void send_notification(TRAPS);
+private:
+  static void send_notification_internal(TRAPS);
 
   friend class HelpDCmd;
 };
@@ -374,8 +448,8 @@
 // where this template is used to create and register factories.
 template <class DCmdClass> class DCmdFactoryImpl : public DCmdFactory {
 public:
-  DCmdFactoryImpl(bool enabled, bool hidden) :
-    DCmdFactory(DCmdClass::num_arguments(), enabled, hidden) { }
+  DCmdFactoryImpl(uint32_t flags, bool enabled, bool hidden) :
+    DCmdFactory(DCmdClass::num_arguments(), flags, enabled, hidden) { }
   // Returns a C-heap allocated instance
   virtual DCmd* create_Cheap_instance(outputStream* output) {
     return new (ResourceObj::C_HEAP, mtInternal) DCmdClass(output, true);
@@ -393,6 +467,9 @@
   virtual const char* impact() const {
     return DCmdClass::impact();
   }
+  virtual const JavaPermission permission() const {
+    return DCmdClass::permission();
+  }
   virtual const char* disabled_message() const {
      return DCmdClass::disabled_message();
   }
--- a/src/share/vm/services/jmm.h	Wed May 08 17:12:52 2013 -0700
+++ b/src/share/vm/services/jmm.h	Thu May 09 12:23:43 2013 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -49,7 +49,8 @@
   JMM_VERSION_1_1 = 0x20010100, // JDK 6
   JMM_VERSION_1_2 = 0x20010200, // JDK 7
   JMM_VERSION_1_2_1 = 0x20010201, // JDK 7 GA
-  JMM_VERSION     = 0x20010202
+  JMM_VERSION_1_2_2 = 0x20010202,
+  JMM_VERSION     = 0x20010203
 };
 
 typedef struct {
@@ -62,7 +63,8 @@
   unsigned int isObjectMonitorUsageSupported : 1;
   unsigned int isSynchronizerUsageSupported : 1;
   unsigned int isThreadAllocatedMemorySupported : 1;
-  unsigned int : 23;
+  unsigned int isRemoteDiagnosticCommandsSupported : 1;
+  unsigned int : 22;
 } jmmOptionalSupport;
 
 typedef enum {
@@ -190,21 +192,27 @@
 } jmmGCStat;
 
 typedef struct {
-  const char* name;
-  const char* description;
-  const char* impact;
-  int         num_arguments;
-  jboolean    enabled;
+  const char* name;                /* Name of the diagnostic command */
+  const char* description;         /* Short description */
+  const char* impact;              /* Impact on the JVM */
+  const char* permission_class;    /* Class name of the required permission if any */
+  const char* permission_name;     /* Permission name of the required permission if any */
+  const char* permission_action;   /* Action name of the required permission if any*/
+  int         num_arguments;       /* Number of supported options or arguments */
+  jboolean    enabled;             /* True if the diagnostic command can be invoked, false otherwise */
 } dcmdInfo;
 
 typedef struct {
-  const char* name;
-  const char* description;
-  const char* type;
-  const char* default_string;
-  jboolean    mandatory;
-  jboolean    option;
-  int         position;
+  const char* name;                /* Option/Argument name*/
+  const char* description;         /* Short description */
+  const char* type;                /* Type: STRING, BOOLEAN, etc. */
+  const char* default_string;      /* Default value in a parsable string */
+  jboolean    mandatory;           /* True if the option/argument is mandatory */
+  jboolean    option;              /* True if it is an option, false if it is an argument */
+                                   /* (see diagnosticFramework.hpp for option/argument definitions) */
+  jboolean    multiple;            /* True if the option can be specified several time */
+  int         position;            /* Expected position for this argument (this field is */
+                                   /* meaningless for options) */
 } dcmdArgInfo;
 
 typedef struct jmmInterface_1_ {
@@ -327,6 +335,9 @@
   jstring      (JNICALL *ExecuteDiagnosticCommand)
                                                  (JNIEnv *env,
                                                   jstring command);
+  void         (JNICALL *SetDiagnosticFrameworkNotificationEnabled)
+                                                 (JNIEnv *env,
+                                                  jboolean enabled);
 } JmmInterface;
 
 #ifdef __cplusplus
--- a/src/share/vm/services/management.cpp	Wed May 08 17:12:52 2013 -0700
+++ b/src/share/vm/services/management.cpp	Thu May 09 12:23:43 2013 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -68,6 +68,9 @@
 Klass* Management::_managementFactory_klass = NULL;
 Klass* Management::_garbageCollectorImpl_klass = NULL;
 Klass* Management::_gcInfo_klass = NULL;
+Klass* Management::_diagnosticCommandImpl_klass = NULL;
+Klass* Management::_managementFactoryHelper_klass = NULL;
+
 
 jmmOptionalSupport Management::_optional_support = {0};
 TimeStamp Management::_stamp;
@@ -128,11 +131,14 @@
   _optional_support.isSynchronizerUsageSupported = 1;
 #endif // INCLUDE_SERVICES
   _optional_support.isThreadAllocatedMemorySupported = 1;
+  _optional_support.isRemoteDiagnosticCommandsSupported = 1;
 
   // Registration of the diagnostic commands
   DCmdRegistrant::register_dcmds();
   DCmdRegistrant::register_dcmds_ext();
-  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<NMTDCmd>(true, false));
+  uint32_t full_export = DCmd_Source_Internal | DCmd_Source_AttachAPI
+                         | DCmd_Source_MBean;
+  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<NMTDCmd>(full_export, true, false));
 }
 
 void Management::initialize(TRAPS) {
@@ -262,6 +268,20 @@
   return _gcInfo_klass;
 }
 
+Klass* Management::sun_management_DiagnosticCommandImpl_klass(TRAPS) {
+  if (_diagnosticCommandImpl_klass == NULL) {
+    _diagnosticCommandImpl_klass = load_and_initialize_klass(vmSymbols::sun_management_DiagnosticCommandImpl(), CHECK_NULL);
+  }
+  return _diagnosticCommandImpl_klass;
+}
+
+Klass* Management::sun_management_ManagementFactoryHelper_klass(TRAPS) {
+  if (_managementFactoryHelper_klass == NULL) {
+    _managementFactoryHelper_klass = load_and_initialize_klass(vmSymbols::sun_management_ManagementFactoryHelper(), CHECK_NULL);
+  }
+  return _managementFactoryHelper_klass;
+}
+
 static void initialize_ThreadInfo_constructor_arguments(JavaCallArguments* args, ThreadSnapshot* snapshot, TRAPS) {
   Handle snapshot_thread(THREAD, snapshot->threadObj());
 
@@ -2144,7 +2164,7 @@
 
 JVM_ENTRY(jobjectArray, jmm_GetDiagnosticCommands(JNIEnv *env))
   ResourceMark rm(THREAD);
-  GrowableArray<const char *>* dcmd_list = DCmdFactory::DCmd_list();
+  GrowableArray<const char *>* dcmd_list = DCmdFactory::DCmd_list(DCmd_Source_MBean);
   objArrayOop cmd_array_oop = oopFactory::new_objArray(SystemDictionary::String_klass(),
           dcmd_list->length(), CHECK_NULL);
   objArrayHandle cmd_array(THREAD, cmd_array_oop);
@@ -2173,7 +2193,7 @@
                "Array element type is not String class");
   }
 
-  GrowableArray<DCmdInfo *>* info_list = DCmdFactory::DCmdInfo_list();
+  GrowableArray<DCmdInfo *>* info_list = DCmdFactory::DCmdInfo_list(DCmd_Source_MBean);
 
   int num_cmds = cmds_ah->length();
   for (int i = 0; i < num_cmds; i++) {
@@ -2196,6 +2216,10 @@
     infoArray[i].name = info->name();
     infoArray[i].description = info->description();
     infoArray[i].impact = info->impact();
+    JavaPermission p = info->permission();
+    infoArray[i].permission_class = p._class;
+    infoArray[i].permission_name = p._name;
+    infoArray[i].permission_action = p._action;
     infoArray[i].num_arguments = info->num_arguments();
     infoArray[i].enabled = info->is_enabled();
   }
@@ -2215,7 +2239,8 @@
               "Command line content cannot be null.");
   }
   DCmd* dcmd = NULL;
-  DCmdFactory*factory = DCmdFactory::factory(cmd_name, strlen(cmd_name));
+  DCmdFactory*factory = DCmdFactory::factory(DCmd_Source_MBean, cmd_name,
+                                             strlen(cmd_name));
   if (factory != NULL) {
     dcmd = factory->create_resource_instance(NULL);
   }
@@ -2235,6 +2260,7 @@
     infoArray[i].default_string = array->at(i)->default_string();
     infoArray[i].mandatory = array->at(i)->is_mandatory();
     infoArray[i].option = array->at(i)->is_option();
+    infoArray[i].multiple = array->at(i)->is_multiple();
     infoArray[i].position = array->at(i)->position();
   }
   return;
@@ -2253,11 +2279,15 @@
                    "Command line content cannot be null.");
   }
   bufferedStream output;
-  DCmd::parse_and_execute(&output, cmdline, ' ', CHECK_NULL);
+  DCmd::parse_and_execute(DCmd_Source_MBean, &output, cmdline, ' ', CHECK_NULL);
   oop result = java_lang_String::create_oop_from_str(output.as_string(), CHECK_NULL);
   return (jstring) JNIHandles::make_local(env, result);
 JVM_END
 
+JVM_ENTRY(void, jmm_SetDiagnosticFrameworkNotificationEnabled(JNIEnv *env, jboolean enabled))
+  DCmdFactory::set_jmx_notification_enabled(enabled?true:false);
+JVM_END
+
 jlong Management::ticks_to_ms(jlong ticks) {
   assert(os::elapsed_frequency() > 0, "Must be non-zero");
   return (jlong)(((double)ticks / (double)os::elapsed_frequency())
@@ -2304,7 +2334,8 @@
   jmm_GetDiagnosticCommands,
   jmm_GetDiagnosticCommandInfo,
   jmm_GetDiagnosticCommandArgumentsInfo,
-  jmm_ExecuteDiagnosticCommand
+  jmm_ExecuteDiagnosticCommand,
+  jmm_SetDiagnosticFrameworkNotificationEnabled
 };
 #endif // INCLUDE_MANAGEMENT
 
--- a/src/share/vm/services/management.hpp	Wed May 08 17:12:52 2013 -0700
+++ b/src/share/vm/services/management.hpp	Thu May 09 12:23:43 2013 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -50,6 +50,8 @@
   static Klass*             _garbageCollectorMXBean_klass;
   static Klass*             _managementFactory_klass;
   static Klass*             _garbageCollectorImpl_klass;
+  static Klass*             _diagnosticCommandImpl_klass;
+  static Klass*             _managementFactoryHelper_klass;
   static Klass*             _gcInfo_klass;
 
   static Klass* load_and_initialize_klass(Symbol* sh, TRAPS);
@@ -99,6 +101,10 @@
       NOT_MANAGEMENT_RETURN_(NULL);
   static Klass* com_sun_management_GcInfo_klass(TRAPS)
       NOT_MANAGEMENT_RETURN_(NULL);
+  static Klass* sun_management_DiagnosticCommandImpl_klass(TRAPS)
+      NOT_MANAGEMENT_RETURN_(NULL);
+  static Klass* sun_management_ManagementFactoryHelper_klass(TRAPS)
+      NOT_MANAGEMENT_RETURN_(NULL);
 
   static instanceOop create_thread_info_instance(ThreadSnapshot* snapshot, TRAPS);
   static instanceOop create_thread_info_instance(ThreadSnapshot* snapshot, objArrayHandle monitors_array, typeArrayHandle depths_array, objArrayHandle synchronizers_array, TRAPS);
--- a/src/share/vm/services/memSnapshot.cpp	Wed May 08 17:12:52 2013 -0700
+++ b/src/share/vm/services/memSnapshot.cpp	Thu May 09 12:23:43 2013 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -262,13 +262,28 @@
   assert(cur->is_reserved_region() && cur->contains_region(rec),
     "Sanity check");
   if (rec->is_same_region(cur)) {
-    // release whole reserved region
+
+    // In snapshot, the virtual memory records are sorted in following orders:
+    // 1. virtual memory's base address
+    // 2. virtual memory reservation record, followed by commit records within this reservation.
+    //    The commit records are also in base address order.
+    // When a reserved region is released, we want to remove the reservation record and all
+    // commit records following it.
 #ifdef ASSERT
-    VMMemRegion* next_region = (VMMemRegion*)peek_next();
-    // should not have any committed memory in this reserved region
-    assert(next_region == NULL || !next_region->is_committed_region(), "Sanity check");
+    address low_addr = cur->addr();
+    address high_addr = low_addr + cur->size();
 #endif
+    // remove virtual memory reservation record
     remove();
+    // remove committed regions within above reservation
+    VMMemRegion* next_region = (VMMemRegion*)current();
+    while (next_region != NULL && next_region->is_committed_region()) {
+      assert(next_region->addr() >= low_addr &&
+             next_region->addr() + next_region->size() <= high_addr,
+            "Range check");
+      remove();
+      next_region = (VMMemRegion*)current();
+    }
   } else if (rec->addr() == cur->addr() ||
     rec->addr() + rec->size() == cur->addr() + cur->size()) {
     // released region is at either end of this region
--- a/src/share/vm/services/nmtDCmd.cpp	Wed May 08 17:12:52 2013 -0700
+++ b/src/share/vm/services/nmtDCmd.cpp	Thu May 09 12:23:43 2013 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -71,7 +71,7 @@
   _dcmdparser.add_dcmd_option(&_scale);
 }
 
-void NMTDCmd::execute(TRAPS) {
+void NMTDCmd::execute(DCmdSource source, TRAPS) {
   const char* scale_value = _scale.value();
   size_t scale_unit;
   if (strcmp(scale_value, "KB") == 0 || strcmp(scale_value, "kb") == 0) {
--- a/src/share/vm/services/nmtDCmd.hpp	Wed May 08 17:12:52 2013 -0700
+++ b/src/share/vm/services/nmtDCmd.hpp	Thu May 09 12:23:43 2013 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -52,10 +52,15 @@
     return "Print native memory usage";
   }
   static const char* impact() {
-    return "Medium:";
+    return "Medium";
+  }
+  static const JavaPermission permission() {
+    JavaPermission p = {"java.lang.management.ManagementPermission",
+                        "monitor", NULL};
+    return p;
   }
   static int num_arguments();
-  virtual void execute(TRAPS);
+  virtual void execute(DCmdSource source, TRAPS);
 };
 
 #endif // SHARE_VM_SERVICES_NMT_DCMD_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/runtime/ClassUnload/KeepAliveClass.java	Thu May 09 12:23:43 2013 +0200
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test KeepAliveClass
+ * @summary This test case uses a java.lang.Class instance to keep a class alive.
+ * @library /testlibrary /testlibrary/whitebox /runtime/testlibrary
+ * @library classes
+ * @build KeepAliveClass test.Empty
+ * @build ClassUnloadCommon
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ * @run main/othervm -Xbootclasspath/a:. -Xmn8m -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI KeepAliveClass
+ */
+
+import java.lang.ref.SoftReference;
+import sun.hotspot.WhiteBox;
+
+/**
+ * Test that verifies that classes are not unloaded when specific types of references are kept to them.
+ */
+public class KeepAliveClass {
+  private static final String className = "test.Empty";
+  private static final WhiteBox wb = WhiteBox.getWhiteBox();
+  public static Object escape = null;
+
+  public static void main(String... args) throws Exception {
+    ClassLoader cl = ClassUnloadCommon.newClassLoader();
+    Class<?> c = cl.loadClass(className);
+    Object o = c.newInstance();
+    o = null; cl = null;
+    escape = c;
+
+    {
+        boolean isAlive = wb.isClassAlive(className);
+        System.out.println("testClass (1) alive: " + isAlive);
+
+        ClassUnloadCommon.failIf(!isAlive, "should be alive");
+    }
+
+    ClassUnloadCommon.triggerUnloading();
+
+    {
+        boolean isAlive = wb.isClassAlive(className);
+        System.out.println("testClass (2) alive: " + isAlive);
+
+        ClassUnloadCommon.failIf(!isAlive, "should be alive");
+    }
+    c = null;
+    escape = null;
+    ClassUnloadCommon.triggerUnloading();
+
+    {
+        boolean isAlive = wb.isClassAlive(className);
+        System.out.println("testClass (3) alive: " + isAlive);
+        ClassUnloadCommon.failIf(isAlive, "should be unloaded");
+    }
+
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/runtime/ClassUnload/KeepAliveClassLoader.java	Thu May 09 12:23:43 2013 +0200
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test KeepAliveClassLoader
+ * @summary This test case uses a java.lang.ClassLoader instance to keep a class alive.
+ * @library /testlibrary /testlibrary/whitebox /runtime/testlibrary
+ * @library classes
+ * @build KeepAliveClassLoader test.Empty
+ * @build ClassUnloadCommon
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ * @run main/othervm -Xbootclasspath/a:. -Xmn8m -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI KeepAliveClassLoader
+ */
+
+import sun.hotspot.WhiteBox;
+
+/**
+ * Test that verifies that classes are not unloaded when specific types of references are kept to them.
+ */
+public class KeepAliveClassLoader {
+  private static final String className = "test.Empty";
+  private static final WhiteBox wb = WhiteBox.getWhiteBox();
+  public static Object escape = null;
+
+
+  public static void main(String... args) throws Exception {
+    ClassLoader cl = ClassUnloadCommon.newClassLoader();
+    Class<?> c = cl.loadClass(className);
+    Object o = c.newInstance();
+    o = null; c = null;
+    escape = cl;
+
+    {
+        boolean isAlive = wb.isClassAlive(className);
+        System.out.println("testClassLoader (1) alive: " + isAlive);
+
+        ClassUnloadCommon.failIf(!isAlive, "should be alive");
+    }
+    ClassUnloadCommon.triggerUnloading();
+
+    {
+        boolean isAlive = wb.isClassAlive(className);
+        System.out.println("testClassLoader (2) alive: " + isAlive);
+
+        ClassUnloadCommon.failIf(!isAlive, "should be alive");
+    }
+    cl = null;
+    escape = null;
+    ClassUnloadCommon.triggerUnloading();
+
+    {
+        boolean isAlive = wb.isClassAlive(className);
+        System.out.println("testClassLoader (3) alive: " + isAlive);
+        ClassUnloadCommon.failIf(isAlive, "should be unloaded");
+    }
+
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/runtime/ClassUnload/KeepAliveObject.java	Thu May 09 12:23:43 2013 +0200
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test KeepAliveObject
+ * @summary This test case uses a class instance to keep the class alive.
+ * @library /testlibrary /testlibrary/whitebox /runtime/testlibrary
+ * @library classes
+ * @build KeepAliveObject test.Empty
+ * @build ClassUnloadCommon
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ * @run main/othervm -Xbootclasspath/a:. -Xmn8m -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI KeepAliveObject
+ */
+
+import sun.hotspot.WhiteBox;
+
+/**
+ * Test that verifies that classes are not unloaded when specific types of references are kept to them.
+ */
+public class KeepAliveObject {
+  private static final String className = "test.Empty";
+  private static final WhiteBox wb = WhiteBox.getWhiteBox();
+  public static Object escape = null;
+
+  public static void main(String... args) throws Exception {
+    ClassLoader cl = ClassUnloadCommon.newClassLoader();
+    Class<?> c = cl.loadClass(className);
+    Object o = c.newInstance();
+    cl = null; c = null;
+    escape = o;
+
+    {
+        boolean isAlive = wb.isClassAlive(className);
+        System.out.println("testObject (1) alive: " + isAlive);
+
+        ClassUnloadCommon.failIf(!isAlive, "should be alive");
+    }
+
+    ClassUnloadCommon.triggerUnloading();
+
+    {
+        boolean isAlive = wb.isClassAlive(className);
+        System.out.println("testObject (2) alive: " + isAlive);
+
+        ClassUnloadCommon.failIf(!isAlive, "should be alive");
+    }
+    o = null;
+    escape = null;
+    ClassUnloadCommon.triggerUnloading();
+
+    {
+        boolean isAlive = wb.isClassAlive(className);
+        System.out.println("testObject (3) alive: " + isAlive);
+        ClassUnloadCommon.failIf(isAlive, "should be unloaded");
+    }
+
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/runtime/ClassUnload/KeepAliveSoftReference.java	Thu May 09 12:23:43 2013 +0200
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test KeepAliveSoftReference
+ * @summary This test case uses a java.lang.ref.SoftReference referencing a class instance to keep a class alive.
+ * @library /testlibrary /testlibrary/whitebox /runtime/testlibrary
+ * @library classes
+ * @build KeepAliveSoftReference test.Empty
+ * @build ClassUnloadCommon
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ * @run main/othervm -Xbootclasspath/a:. -Xmn8m -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI KeepAliveSoftReference
+ */
+
+import java.lang.ref.SoftReference;
+import sun.hotspot.WhiteBox;
+
+/**
+ * Test that verifies that classes are not unloaded when specific types of references are kept to them.
+ */
+public class KeepAliveSoftReference {
+  private static final String className = "test.Empty";
+  private static final WhiteBox wb = WhiteBox.getWhiteBox();
+
+  public static void main(String... args) throws Exception {
+    ClassLoader cl = ClassUnloadCommon.newClassLoader();
+    Class<?> c = cl.loadClass(className);
+    Object o = c.newInstance();
+    SoftReference<Object> sr = new SoftReference(o);
+    o = null; c = null; cl = null;
+
+    {
+        boolean isAlive = wb.isClassAlive(className);
+        System.out.println("testSoftReference (1) alive: " + isAlive);
+        boolean cleared = (sr.get() == null);
+        boolean shouldBeAlive = !cleared;
+        ClassUnloadCommon.failIf(isAlive != shouldBeAlive, "" + isAlive + " != " + shouldBeAlive);
+    }
+
+    ClassUnloadCommon.triggerUnloading();
+
+    {
+        boolean isAlive = wb.isClassAlive(className);
+        System.out.println("testSoftReference (2) alive: " + isAlive);
+        boolean cleared = (sr.get() == null);
+        boolean shouldBeAlive = !cleared;
+        ClassUnloadCommon.failIf(isAlive != shouldBeAlive, "" + isAlive + " != " + shouldBeAlive);
+    }
+    sr.clear();
+    ClassUnloadCommon.triggerUnloading();
+
+    {
+        boolean isAlive = wb.isClassAlive(className);
+        System.out.println("testSoftReference (3) alive: " + isAlive);
+        boolean cleared = (sr.get() == null);
+        boolean shouldBeAlive = !cleared;
+        ClassUnloadCommon.failIf(isAlive != shouldBeAlive, "" + isAlive + " != " + shouldBeAlive);
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/runtime/ClassUnload/UnloadTest.java	Thu May 09 12:23:43 2013 +0200
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test UnloadTest
+ * @library /runtime/testlibrary /testlibrary /testlibrary/whitebox
+ * @library classes
+ * @build ClassUnloadCommon test.Empty
+ * @build UnloadTest
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ * @run main/othervm -Xbootclasspath/a:. -Xmn8m -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI UnloadTest
+ */
+import sun.hotspot.WhiteBox;
+
+/**
+ * Test that verifies that classes are unloaded when they are no longer reachable.
+ *
+ * The test creates a class loader, uses the loader to load a class and creates an instance
+ * of that class. The it nulls out all the references to the instance, class and class loader
+ * and tries to trigger class unloading. Then it verifies that the class is no longer
+ * loaded by the VM.
+ */
+public class UnloadTest {
+    private static String className = "test.Empty";
+
+    public static void main(String... args) throws Exception {
+       run();
+    }
+
+    private static void run() throws Exception {
+        final WhiteBox wb = WhiteBox.getWhiteBox();
+
+        ClassUnloadCommon.failIf(wb.isClassAlive(className), "is not expected to be alive yet");
+
+        ClassLoader cl = ClassUnloadCommon.newClassLoader();
+        Class<?> c = cl.loadClass(className);
+        Object o = c.newInstance();
+
+        ClassUnloadCommon.failIf(!wb.isClassAlive(className), "should be live here");
+
+        cl = null; c = null; o = null;
+        ClassUnloadCommon.triggerUnloading();
+        ClassUnloadCommon.failIf(wb.isClassAlive(className), "should have been unloaded");
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/runtime/ClassUnload/classes/test/Empty.java	Thu May 09 12:23:43 2013 +0200
@@ -0,0 +1,5 @@
+package test;
+
+public class Empty {
+public String toString() { return "nothing"; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/runtime/NMT/ReleaseCommittedMemory.java	Thu May 09 12:23:43 2013 +0200
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8013120
+ * @summary Release committed memory and make sure NMT handles it correctly
+ * @key nmt regression
+ * @library /testlibrary /testlibrary/whitebox
+ * @build ReleaseCommittedMemory
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:NativeMemoryTracking=detail ReleaseCommittedMemory
+ */
+
+import sun.hotspot.WhiteBox;
+
+public class ReleaseCommittedMemory {
+
+  public static void main(String args[]) throws Exception {
+    WhiteBox wb = WhiteBox.getWhiteBox();
+    long reserveSize = 256 * 1024;
+    long addr;
+
+    addr = wb.NMTReserveMemory(reserveSize);
+    wb.NMTCommitMemory(addr, 128*1024);
+    wb.NMTReleaseMemory(addr, reserveSize);
+    wb.NMTWaitForDataMerge();
+  }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/runtime/testlibrary/ClassUnloadCommon.java	Thu May 09 12:23:43 2013 +0200
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.File;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+
+public class ClassUnloadCommon {
+    public static class TestFailure extends RuntimeException {
+        TestFailure(String msg) {
+            super(msg);
+        }
+    }
+
+    public static void failIf(boolean value, String msg) {
+        if (value) throw new TestFailure("Test failed: " + msg);
+    }
+
+    private static volatile Object dummy = null;
+    private static void allocateMemory(int kilobytes) {
+        ArrayList<byte[]> l = new ArrayList<>();
+        dummy = l;
+        for (int i = kilobytes; i > 0; i -= 1) {
+            l.add(new byte[1024]);
+        }
+        l = null;
+        dummy = null;
+    }
+
+    public static void triggerUnloading() {
+        allocateMemory(16 * 1024); // yg size is 8m with cms, force young collection
+        System.gc();
+    }
+
+    public static ClassLoader newClassLoader() {
+        try {
+            return new URLClassLoader(new URL[] {
+                Paths.get(System.getProperty("test.classes",".") + File.separatorChar + "classes").toUri().toURL(),
+            }, null);
+        } catch (MalformedURLException e){
+            throw new RuntimeException("Unexpected URL conversion failure", e);
+        }
+    }
+
+}