Merge
authorduke
Wed, 05 Jul 2017 16:40:29 +0200
changeset 1050 8444a48d787d
parent 1049 1f47a876c043 (current diff)
parent 1035 28cdcb96b5fb (diff)
child 1051 90cf935adb35
Merge
hotspot/agent/src/share/lib/jlfgr-1_0.jar
hotspot/agent/src/share/lib/maf-1_0.jar
--- a/.hgtags-top-repo	Thu Aug 14 22:17:02 2008 -0700
+++ b/.hgtags-top-repo	Wed Jul 05 16:40:29 2017 +0200
@@ -7,3 +7,4 @@
 2dab2f712e1832c92acfa63ec0337048b9422c20 jdk7-b30
 3300a35a0bd56d695b92fe0b34f03ebbfc939064 jdk7-b31
 64da805be725721bf2004e7409a0d7a16fc8ddbc jdk7-b32
+bb1ef4ee3d2c8cbf43a37d372325a7952be590b9 jdk7-b33
--- a/Makefile	Thu Aug 14 22:17:02 2008 -0700
+++ b/Makefile	Wed Jul 05 16:40:29 2017 +0200
@@ -74,7 +74,7 @@
 all::
 	@$(START_ECHO)
 
-all:: openjdk_check sanity all_product_build 
+all:: openjdk_check sanity
 
 ifeq ($(SKIP_FASTDEBUG_BUILD), false)
   all:: fastdebug_build
@@ -88,6 +88,8 @@
   all:: openjdk_build
 endif
 
+all:: all_product_build 
+
 all:: 
 	@$(FINISH_ECHO)
 
--- a/corba/.hgtags	Thu Aug 14 22:17:02 2008 -0700
+++ b/corba/.hgtags	Wed Jul 05 16:40:29 2017 +0200
@@ -7,3 +7,4 @@
 c0252adbb2abbfdd6c35595429ac6fbdd98e20ac jdk7-b30
 ef6af34d75a7b44e77083f1d4ee47631fa09d3b4 jdk7-b31
 80a0f46a6203e727012bd579fe38a609b83decce jdk7-b32
+6a5b9d2f8b20de54e3bfe33cd12bd0793caedc4e jdk7-b33
--- a/hotspot/.hgtags	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/.hgtags	Wed Jul 05 16:40:29 2017 +0200
@@ -7,3 +7,4 @@
 d1605aabd0a15ecf93787c47de63073c33fba52d jdk7-b30
 9c2ecc2ffb125f14fab3857fe7689598956348a0 jdk7-b31
 b727c32788a906c04839516ae7443a085185a300 jdk7-b32
+585535ec8a14adafa6bfea65d6975e29094c8cec jdk7-b33
--- a/hotspot/agent/make/Makefile	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/agent/make/Makefile	Wed Jul 05 16:40:29 2017 +0200
@@ -32,6 +32,12 @@
 include $(GAMMADIR)/make/defs.make
 endif
 
+ifeq "x$(HOTSPOT_BUILD_VERSION)" "x"
+SA_BUILD_VERSION=$(HOTSPOT_RELEASE_VERSION)
+else
+SA_BUILD_VERSION=$(HOTSPOT_RELEASE_VERSION)-$(HOTSPOT_BUILD_VERSION)
+endif
+
 PKGLIST = \
 sun.jvm.hotspot \
 sun.jvm.hotspot.asm \
@@ -117,7 +123,9 @@
 sun.jvm.hotspot.ui.treetable \
 sun.jvm.hotspot.utilities \
 sun.jvm.hotspot.utilities.memo \
-sun.jvm.hotspot.utilities.soql
+sun.jvm.hotspot.utilities.soql \
+com.sun.java.swing.action \
+com.sun.java.swing.ui
 #END PKGLIST
 
 # Generated using the build-filelist script
@@ -198,7 +206,9 @@
 sun/jvm/hotspot/ui/treetable/*.java \
 sun/jvm/hotspot/utilities/*.java \
 sun/jvm/hotspot/utilities/memo/*.java \
-sun/jvm/hotspot/utilities/soql/*.java 
+sun/jvm/hotspot/utilities/soql/*.java \
+com/sun/java/swing/action/*.java \
+com/sun/java/swing/ui/*.java 
 #END FILELIST
 
 ifneq "x$(ALT_BOOTDIR)" "x"
@@ -220,8 +230,6 @@
 endif
 
 SRC_DIR    = ../src/share/classes
-LIB_DIR    = ../src/share/lib
-CLOSED_LIB_DIR    = ../closed/src/share/lib
 BUILD_DIR  = ../build
 OUTPUT_DIR = $(BUILD_DIR)/classes
 DOC_DIR    = $(BUILD_DIR)/doc
@@ -231,9 +239,9 @@
 ALLFILES := $(patsubst %,$(SRC_DIR)/%,$(FILELIST))
 ALLFILES := $(shell /bin/ls $(ALLFILES))
 
+# tools.jar is used by the sa-jdi binding
+CLASSPATH = $(JDK_HOME)/lib/tools.jar
 
-# tools.jar is needed by the JDI - SA binding
-CLASSPATH = $(LIB_DIR)/maf-1_0.jar$(CPS)$(JDK_HOME)/lib/tools.jar
 CLASSPATH := $(subst \,/,$(CLASSPATH))
 
 # FIXME: autogenerate call to rmic
@@ -241,24 +249,36 @@
 SA_BUILD_VERSION_PROP = "sun.jvm.hotspot.runtime.VM.saBuildVersion=$(SA_BUILD_VERSION)"
 
 SA_PROPERTIES = $(OUTPUT_DIR)/sa.properties
+JAVAC = $(JDK_HOME)/bin/javac
+JAVADOC = $(JDK_HOME)/bin/javadoc
+RMIC = $(JDK_HOME)/bin/rmic
 
 # Tagging it on because there's no reason not to run it
 all: filelist
 	@mkdir -p $(OUTPUT_DIR)
 	@echo "$(SA_BUILD_VERSION_PROP)" > $(SA_PROPERTIES)
-	@${JDK_HOME}/bin/javac -source 1.4 -classpath $(CLASSPATH) -deprecation -sourcepath $(SRC_DIR) -g -d $(OUTPUT_DIR) @filelist
-	@${JDK_HOME}/bin/rmic -classpath $(OUTPUT_DIR) -d $(OUTPUT_DIR) sun.jvm.hotspot.debugger.remote.RemoteDebuggerServer
+	$(JAVAC) -source 1.4 -classpath $(CLASSPATH) -deprecation -sourcepath $(SRC_DIR) -g -d $(OUTPUT_DIR) @filelist
+	$(RMIC) -classpath $(OUTPUT_DIR) -d $(OUTPUT_DIR) sun.jvm.hotspot.debugger.remote.RemoteDebuggerServer
 	rm -f $(OUTPUT_DIR)/sun/jvm/hotspot/utilities/soql/sa.js
 	cp $(SRC_DIR)/sun/jvm/hotspot/utilities/soql/sa.js $(OUTPUT_DIR)/sun/jvm/hotspot/utilities/soql
+	mkdir -p $(OUTPUT_DIR)/sun/jvm/hotspot/ui/resources
+	rm -f $(OUTPUT_DIR)/sun/jvm/hotspot/ui/resources/*
+	cp $(SRC_DIR)/sun/jvm/hotspot/ui/resources/*.png $(OUTPUT_DIR)/sun/jvm/hotspot/ui/resources/
+	cp -r $(SRC_DIR)/images/*  $(OUTPUT_DIR)/
 
 allprof: filelist
 	@mkdir -p $(OUTPUT_DIR)
 	@echo "$(SA_BUILD_VERSION_PROP)" > $(SA_PROPERTIES)
-	@${JDK_HOME}/bin/javac -source 1.4 -J-Xprof -classpath $(CLASSPATH) -deprecation -sourcepath $(SRC_DIR) -g -d $(OUTPUT_DIR) @filelist
-	@${JDK_HOME}/bin/rmic -classpath $(OUTPUT_DIR) -d $(OUTPUT_DIR) sun.jvm.hotspot.debugger.remote.RemoteDebuggerServer
+	$(JAVAC) -source 1.4 -J-Xprof -classpath $(CLASSPATH) -deprecation -sourcepath $(SRC_DIR) -g -d $(OUTPUT_DIR) @filelist
+	$(RMIC) -classpath $(OUTPUT_DIR) -d $(OUTPUT_DIR) sun.jvm.hotspot.debugger.remote.RemoteDebuggerServer
 	rm -f $(OUTPUT_DIR)/sun/jvm/hotspot/utilities/soql/sa.js
 	cp $(SRC_DIR)/sun/jvm/hotspot/utilities/soql/sa.js $(OUTPUT_DIR)/sun/jvm/hotspot/utilities/soql
+	mkdir -p $(OUTPUT_DIR)/sun/jvm/hotspot/ui/resources
+	rm -f $(OUTPUT_DIR)/sun/jvm/hotspot/ui/resources/*
+	cp $(SRC_DIR)/sun/jvm/hotspot/ui/resources/*.png $(OUTPUT_DIR)/sun/jvm/hotspot/ui/resources/
+	cp -r $(SRC_DIR)/images/*  $(OUTPUT_DIR)/
 
+.PHONY: filelist
 filelist: $(ALLFILES)
 	@if [ ! -f $(JDK_HOME)/lib/tools.jar ] ; then \
           echo "Missing $(JDK_HOME)/lib/tools.jar file. Use 1.6.0 or later version jdk to build SA."; \
@@ -274,36 +294,23 @@
 
 .PHONY: sa-jdi.jar
 sa-jdi.jar:
-	if [ ! -f $(JDK_HOME)/lib/tools.jar ] ; then \
-          echo "Missing $(JDK_HOME)/lib/tools.jar file. Use 1.6.0 or later version jdk to build SA.";\
-          exit 1; \
-        fi
-	rm -f $(BUILD_DIR)/sa-jdi.jar
-	rm -f $(OUTPUT_DIR)/jdi_class_files
-	javac -source 1.4 ClosureFinder.java -d $(OUTPUT_DIR)
-	cd $(OUTPUT_DIR) ; find sun/jvm/hotspot/jdi -name "*.class" > jdi_class_files
-	cd $(OUTPUT_DIR) ; jar cvf ../sa-jdi.jar `java ClosureFinder jdi_class_files .`
-	cd $(BUILD_DIR) ; jar uvf sa-jdi.jar -C $(SRC_DIR) META-INF/services/com.sun.jdi.connect.Connector
-	cd $(BUILD_DIR) ; jar uvf sa-jdi.jar -C $(OUTPUT_DIR) sa.properties
-	rm -f $(OUTPUT_DIR)/ClosureFinder.class
-	rm -f $(OUTPUT_DIR)/jdi_class_files
+	echo "sa-jdi.jar is built by a hotspot build."
 
 docs:
-	@javadoc -private -classpath $(CLASSPATH) -sourcepath $(SRC_DIR) -d $(DOC_DIR) $(PKGLIST)
+	@$(JAVADOC) -private -classpath $(CLASSPATH) -sourcepath $(SRC_DIR) -d $(DOC_DIR) $(PKGLIST)
 
 sizes: $(ALLFILES)
 	wc -l $(ALLFILES)
 
 cscope: $(ALLFILES)
+	rm -f java.files
 	echo $(ALLFILES) > java.files
 	cscope -b -i java.files -f java.out 
+	rm -f java.files
 
 .PHONY: sa.jar
 sa.jar:
 	rm -f $(BUILD_DIR)/sa.jar
-	mkdir -p $(OUTPUT_DIR)/sun/jvm/hotspot/ui/resources
-	rm -f $(OUTPUT_DIR)/sun/jvm/hotspot/ui/resources/*
-	cp $(SRC_DIR)/sun/jvm/hotspot/ui/resources/*.png $(OUTPUT_DIR)/sun/jvm/hotspot/ui/resources/
 	cd $(OUTPUT_DIR) ; jar cvf ../sa.jar *
 
 clean::
--- a/hotspot/agent/make/bugspot.bat	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/agent/make/bugspot.bat	Wed Jul 05 16:40:29 2017 +0200
@@ -22,4 +22,4 @@
 REM  
 REM
 
-java -showversion -cp ..\build\classes;..\src\share\lib\maf-1_0.jar;..\src\share\lib\jlfgr-1_0.jar;..\src\share\lib\js.jar;sa.jar;lib\maf-1_0.jar;lib\jlfgr-1_0.jar;lib\js.jar sun.jvm.hotspot.bugspot.Main
+java -showversion -cp ..\build\classes;..\src\share\lib\js.jar;.\sa.jar;lib\js.jar sun.jvm.hotspot.bugspot.Main
--- a/hotspot/agent/make/build.xml	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/agent/make/build.xml	Wed Jul 05 16:40:29 2017 +0200
@@ -42,7 +42,6 @@
 
   <property name="app.name" value="sa"/>
   <property name="dist.jar" value="${app.name}.jar"/>
-  <property name="libs"     value="../src/share/lib"/>
   <property name="classes"  value="../build/classes"/>
 
 <!-- The "prepare" target is used to construct the deployment home
@@ -83,11 +82,6 @@
      home directory structure will be created if needed the first time.
 -->
 
-  <path id="javac.classpath">
-    <pathelement path="${libs}/maf-1_0.jar" />
-    <pathelement path="${libs}/jlfgr-1_0.jar" />
-  </path>
-
   <target name="compile" depends="prepare" description="Compiles the sources">
     <javac srcdir="../src/share/classes" 
            destdir="${classes}"
@@ -110,6 +104,18 @@
     <copy todir="${classes}/sun/jvm/hotspot/ui/resources">
       <fileset dir="../src/share/classes/sun/jvm/hotspot/ui/resources" includes="*.png" />
     </copy>
+    <copy todir="${classes}/toolbarButtonGraphics/development/">
+      <fileset dir="../src/share/classes/images/toolbarButtonGraphics/development/" includes="*.gif" />
+    </copy>
+    <copy todir="${classes}/toolbarButtonGraphics/general/">
+      <fileset dir="../src/share/classes/images/toolbarButtonGraphics/general/" includes="*.gif" />
+    </copy>
+    <copy todir="${classes}/toolbarButtonGraphics/navigation/">
+      <fileset dir="../src/share/classes/images/toolbarButtonGraphics/navigation/" includes="*.gif" />
+    </copy>
+    <copy todir="${classes}/toolbarButtonGraphics/text/">
+      <fileset dir="../src/share/classes/images/toolbarButtonGraphics/text/" includes="*.gif" />
+    </copy>
 
     <jar jarfile="${classes}/${dist.jar}"
          basedir="${classes}"/>
--- a/hotspot/agent/make/hsdb.bat	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/agent/make/hsdb.bat	Wed Jul 05 16:40:29 2017 +0200
@@ -22,4 +22,4 @@
 REM  
 REM
 
-java -showversion -cp ..\build\classes;..\src\share\lib\maf-1_0.jar;..\src\share\lib\jlfgr-1_0.jar;..\src\share\lib\js.jar;sa.jar;lib\maf-1_0.jar;lib\jlfgr-1_0.jar;lib\js.jar sun.jvm.hotspot.HSDB %1 %2
+java -showversion -cp ..\build\classes;..\src\share\lib\js.jar;.\sa.jar;lib\js.jar sun.jvm.hotspot.HSDB %1 %2
--- a/hotspot/agent/make/hsdb.sh	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/agent/make/hsdb.sh	Wed Jul 05 16:40:29 2017 +0200
@@ -29,4 +29,4 @@
    SA_JAVA=java
 fi
 
-$SA_JAVA -showversion -cp $STARTDIR/../build/classes:$STARTDIR/../src/share/lib/maf-1_0.jar:$STARTDIR/../src/share/lib/jlfgr-1_0.jar:$STARTDIR/../src/share/lib/js.jar:$STARTDIR/sa.jar:$STARTDIR/lib/maf-1_0.jar:$STARTDIR/lib/jlfgr-1_0.jar:$STARTDIR/lib/js.jar sun.jvm.hotspot.HSDB $*
+$SA_JAVA -showversion -cp $STARTDIR/../build/classes:$STARTDIR/../src/share/lib/js.jar:$STARTDIR/sa.jar:$STARTDIR/lib/js.jar sun.jvm.hotspot.HSDB $*
--- a/hotspot/agent/make/saenv.bat	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/agent/make/saenv.bat	Wed Jul 05 16:40:29 2017 +0200
@@ -39,7 +39,7 @@
 
 :sa_java_set
 
-set SA_CLASSPATH=..\build\classes;..\src\share\lib\maf-1_0.jar;..\src\share\lib\jlfgr-1_0.jar;..\src\share\lib\js.jar;sa.jar;lib\maf-1_0.jar;lib\jlfgr-1_0.jar;lib\js.jar
+set SA_CLASSPATH=..\build\classes;..\src\share\lib\js.jar;sa.jar;lib\js.jar
 
 set SA_LIBPATH=..\src\os\win32\windbg\i386;.\win32\i386
 
--- a/hotspot/agent/make/saenv.sh	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/agent/make/saenv.sh	Wed Jul 05 16:40:29 2017 +0200
@@ -58,7 +58,7 @@
 fi
 
 
-SA_CLASSPATH=$STARTDIR/../build/classes:$STARTDIR/../src/share/lib/maf-1_0.jar:$STARTDIR/../src/share/lib/jlfgr-1_0.jar:$STARTDIR/../src/share/lib/js.jar:$STARTDIR/sa.jar:$STARTDIR/lib/maf-1_0.jar:$STARTDIR/lib/jlfgr-1_0.jar:$STARTDIR/lib/js.jar
+SA_CLASSPATH=$STARTDIR/../build/classes:$STARTDIR/../src/share/lib/js.jar:$STARTDIR/sa.jar:$STARTDIR/lib/js.jar
 
 OPTIONS="-Djava.system.class.loader=sun.jvm.hotspot.SALauncherLoader ${OPTIONS}"
 
--- a/hotspot/agent/make/saenv64.bat	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/agent/make/saenv64.bat	Wed Jul 05 16:40:29 2017 +0200
@@ -43,7 +43,7 @@
 
 :sa_java_set
 
-set SA_CLASSPATH=..\build\classes;..\src\share\lib\maf-1_0.jar;..\src\share\lib\jlfgr-1_0.jar;..\src\share\lib\js.jar;sa.jar;lib\maf-1_0.jar;lib\jlfgr-1_0.jar;lib\js.jar
+set SA_CLASSPATH=..\build\classes;..\src\share\lib\js.jar;sa.jar;lib\js.jar
 
 REM For now, only AMD-64, IA-64 stack walking is not working anyway
 set SA_LIBPATH=.\src\os\win32\windbg\amd64;.\win32\amd64
--- a/hotspot/agent/make/saenv64.sh	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/agent/make/saenv64.sh	Wed Jul 05 16:40:29 2017 +0200
@@ -55,7 +55,7 @@
    OPTIONS="-Dsun.jvm.hotspot.runtime.VM.disableVersionCheck ${OPTIONS}"
 fi
 
-SA_CLASSPATH=$STARTDIR/../build/classes:$STARTDIR/../src/share/lib/maf-1_0.jar:$STARTDIR/../src/share/lib/jlfgr-1_0.jar:$STARTDIR/../src/share/lib/js.jar:$STARTDIR/sa.jar:$STARTDIR/lib/maf-1_0.jar:$STARTDIR/lib/jlfgr-1_0.jar:$STARTDIR/lib/js.jar
+SA_CLASSPATH=$STARTDIR/../build/classes:$STARTDIR/../src/share/lib/js.jar:$STARTDIR/sa.jar::$STARTDIR/lib/js.jar
 
 OPTIONS="-Djava.system.class.loader=sun.jvm.hotspot.SALauncherLoader ${OPTIONS}"
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/com/sun/java/swing/action/AboutAction.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2000-2008 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+
+package com.sun.java.swing.action;
+
+
+// Referenced classes of package com.sun.java.swing.action:
+//            DelegateAction, ActionManager
+
+public class AboutAction extends DelegateAction
+{
+
+    public AboutAction()
+    {
+        this("general/About16.gif");
+    }
+
+    public AboutAction(String iconPath)
+    {
+        super("About...", ActionManager.getIcon(iconPath));
+        putValue("ActionCommandKey", "about-command");
+        putValue("ShortDescription", "About...");
+        putValue("LongDescription", "System information and version of the application.");
+        putValue("MnemonicKey", VALUE_MNEMONIC);
+    }
+
+    public static final String VALUE_COMMAND = "about-command";
+    public static final String VALUE_NAME = "About...";
+    public static final String VALUE_SMALL_ICON = "general/About16.gif";
+    public static final String VALUE_LARGE_ICON = "general/About24.gif";
+    public static final Integer VALUE_MNEMONIC = new Integer(65);
+    public static final String VALUE_SHORT_DESCRIPTION = "About...";
+    public static final String VALUE_LONG_DESCRIPTION = "System information and version of the application.";
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/com/sun/java/swing/action/ActionManager.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2000-2008 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+
+package com.sun.java.swing.action;
+
+import java.util.HashMap;
+import javax.swing.Action;
+import javax.swing.ImageIcon;
+
+// Referenced classes of package com.sun.java.swing.action:
+//            DelegateAction, StateChangeAction, ActionUtilities
+
+public abstract class ActionManager
+{
+
+    protected ActionManager()
+    {
+        actions = new HashMap();
+        addActions();
+    }
+
+    public static ActionManager getInstance()
+    {
+        return manager;
+    }
+
+    protected abstract void addActions();
+
+    protected void addAction(String cmdname, Action action)
+    {
+        actions.put(cmdname, action);
+    }
+
+    public Action getAction(String key)
+    {
+        return (Action)actions.get(key);
+    }
+
+    public DelegateAction getDelegateAction(String name)
+    {
+        Action a = getAction(name);
+        if(a instanceof DelegateAction)
+            return (DelegateAction)a;
+        else
+            return null;
+    }
+
+    public StateChangeAction getStateChangeAction(String name)
+    {
+        Action a = getAction(name);
+        if(a instanceof StateChangeAction)
+            return (StateChangeAction)a;
+        else
+            return null;
+    }
+
+    public static ImageIcon getIcon(String name)
+    {
+        return utilities.getIcon(name);
+    }
+
+    public void setActionEnabled(String name, boolean enabled)
+    {
+        Action action = getAction(name);
+        if(action != null)
+            action.setEnabled(enabled);
+    }
+
+    private HashMap actions;
+    private static ActionUtilities utilities = new ActionUtilities();
+    protected static ActionManager manager;
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/com/sun/java/swing/action/ActionUtilities.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2000-2008 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+
+package com.sun.java.swing.action;
+
+import javax.swing.ImageIcon;
+
+class ActionUtilities
+{
+
+    ActionUtilities()
+    {
+    }
+
+    public ImageIcon getIcon(String name)
+    {
+        String imagePath = "/toolbarButtonGraphics/" + name;
+        java.net.URL url = getClass().getResource(imagePath);
+        if(url != null)
+            return new ImageIcon(url);
+        else
+            return null;
+    }
+
+    public static final String IMAGE_DIR = "/toolbarButtonGraphics/";
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/com/sun/java/swing/action/AlignCenterAction.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2000-2008 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+
+package com.sun.java.swing.action;
+
+import javax.swing.KeyStroke;
+
+// Referenced classes of package com.sun.java.swing.action:
+//            StateChangeAction, ActionManager
+
+public class AlignCenterAction extends StateChangeAction
+{
+
+    public AlignCenterAction()
+    {
+        this("text/AlignCenter16.gif");
+    }
+
+    public AlignCenterAction(String iconPath)
+    {
+        super("Center", ActionManager.getIcon(iconPath));
+        putValue("ActionCommandKey", "align-center-command");
+        putValue("ShortDescription", "Center");
+        putValue("LongDescription", "Adjust the placement of text to the center of the line");
+        putValue("MnemonicKey", VALUE_MNEMONIC);
+        putValue("AcceleratorKey", VALUE_ACCELERATOR);
+    }
+
+    public static final String VALUE_COMMAND = "align-center-command";
+    public static final String VALUE_NAME = "Center";
+    public static final String VALUE_SMALL_ICON = "text/AlignCenter16.gif";
+    public static final String VALUE_LARGE_ICON = "text/AlignCenter24.gif";
+    public static final Integer VALUE_MNEMONIC = new Integer(78);
+    public static final KeyStroke VALUE_ACCELERATOR = KeyStroke.getKeyStroke(69, 2);
+    public static final String VALUE_SHORT_DESCRIPTION = "Center";
+    public static final String VALUE_LONG_DESCRIPTION = "Adjust the placement of text to the center of the line";
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/com/sun/java/swing/action/AlignLeftAction.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2000-2008 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+
+package com.sun.java.swing.action;
+
+import javax.swing.KeyStroke;
+
+// Referenced classes of package com.sun.java.swing.action:
+//            StateChangeAction, ActionManager
+
+public class AlignLeftAction extends StateChangeAction
+{
+
+    public AlignLeftAction()
+    {
+        this("text/AlignLeft16.gif");
+    }
+
+    public AlignLeftAction(String iconPath)
+    {
+        super("Left Align", ActionManager.getIcon(iconPath));
+        putValue("ActionCommandKey", "align-left-command");
+        putValue("ShortDescription", "Left Align");
+        putValue("LongDescription", "Adjust the placement of text along the left edge");
+        putValue("MnemonicKey", VALUE_MNEMONIC);
+        putValue("AcceleratorKey", VALUE_ACCELERATOR);
+    }
+
+    public static final String VALUE_COMMAND = "align-left-command";
+    public static final String VALUE_NAME = "Left Align";
+    public static final String VALUE_SMALL_ICON = "text/AlignLeft16.gif";
+    public static final String VALUE_LARGE_ICON = "text/AlignLeft24.gif";
+    public static final Integer VALUE_MNEMONIC = new Integer(76);
+    public static final KeyStroke VALUE_ACCELERATOR = KeyStroke.getKeyStroke(76, 2);
+    public static final String VALUE_SHORT_DESCRIPTION = "Left Align";
+    public static final String VALUE_LONG_DESCRIPTION = "Adjust the placement of text along the left edge";
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/com/sun/java/swing/action/AlignRightAction.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2000-2008 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+
+package com.sun.java.swing.action;
+
+import javax.swing.KeyStroke;
+
+// Referenced classes of package com.sun.java.swing.action:
+//            StateChangeAction, ActionManager
+
+public class AlignRightAction extends StateChangeAction
+{
+
+    public AlignRightAction()
+    {
+        this("text/AlignRight16.gif");
+    }
+
+    public AlignRightAction(String iconPath)
+    {
+        super("Right Align", ActionManager.getIcon(iconPath));
+        putValue("ActionCommandKey", "align-right-command");
+        putValue("ShortDescription", "Right Align");
+        putValue("LongDescription", "Adjust the placement of text along the right edge");
+        putValue("MnemonicKey", VALUE_MNEMONIC);
+        putValue("AcceleratorKey", VALUE_ACCELERATOR);
+    }
+
+    public static final String VALUE_COMMAND = "align-right-command";
+    public static final String VALUE_NAME = "Right Align";
+    public static final String VALUE_SMALL_ICON = "text/AlignRight16.gif";
+    public static final String VALUE_LARGE_ICON = "text/AlignRight24.gif";
+    public static final Integer VALUE_MNEMONIC = new Integer(82);
+    public static final KeyStroke VALUE_ACCELERATOR = KeyStroke.getKeyStroke(82, 2);
+    public static final String VALUE_SHORT_DESCRIPTION = "Right Align";
+    public static final String VALUE_LONG_DESCRIPTION = "Adjust the placement of text along the right edge";
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/com/sun/java/swing/action/ApplyAction.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2000-2008 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+
+package com.sun.java.swing.action;
+
+import javax.swing.KeyStroke;
+
+// Referenced classes of package com.sun.java.swing.action:
+//            DelegateAction, ActionManager
+
+public class ApplyAction extends DelegateAction
+{
+
+    public ApplyAction()
+    {
+        this(VALUE_SMALL_ICON);
+    }
+
+    public ApplyAction(String iconPath)
+    {
+        super("Apply", ActionManager.getIcon(iconPath));
+        putValue("ActionCommandKey", "apply-command");
+        putValue("ShortDescription", "Apply the activity");
+        putValue("LongDescription", "Apply the activity");
+        putValue("MnemonicKey", VALUE_MNEMONIC);
+        putValue("AcceleratorKey", VALUE_ACCELERATOR);
+    }
+
+    public static final String VALUE_COMMAND = "apply-command";
+    public static final String VALUE_NAME = "Apply";
+    public static final String VALUE_SMALL_ICON = null;
+    public static final String VALUE_LARGE_ICON = null;
+    public static final Integer VALUE_MNEMONIC = new Integer(65);
+    public static final KeyStroke VALUE_ACCELERATOR = null;
+    public static final String VALUE_SHORT_DESCRIPTION = "Apply the activity";
+    public static final String VALUE_LONG_DESCRIPTION = "Apply the activity";
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/com/sun/java/swing/action/BackAction.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2000-2008 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+
+package com.sun.java.swing.action;
+
+import javax.swing.KeyStroke;
+
+// Referenced classes of package com.sun.java.swing.action:
+//            DelegateAction, ActionManager
+
+public class BackAction extends DelegateAction
+{
+
+    public BackAction()
+    {
+        this(VALUE_SMALL_ICON);
+    }
+
+    public BackAction(String iconPath)
+    {
+        super("< Back", ActionManager.getIcon(iconPath));
+        putValue("ActionCommandKey", "back-command");
+        putValue("ShortDescription", "Select previous item");
+        putValue("LongDescription", "Select previous item");
+        putValue("MnemonicKey", VALUE_MNEMONIC);
+        putValue("AcceleratorKey", VALUE_ACCELERATOR);
+    }
+
+    public static final String VALUE_COMMAND = "back-command";
+    public static final String VALUE_NAME = "< Back";
+    public static final String VALUE_SMALL_ICON = null;
+    public static final String VALUE_LARGE_ICON = null;
+    public static final Integer VALUE_MNEMONIC = new Integer(66);
+    public static final KeyStroke VALUE_ACCELERATOR = null;
+    public static final String VALUE_SHORT_DESCRIPTION = "Select previous item";
+    public static final String VALUE_LONG_DESCRIPTION = "Select previous item";
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/com/sun/java/swing/action/CancelAction.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2000-2008 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+
+package com.sun.java.swing.action;
+
+import javax.swing.KeyStroke;
+
+// Referenced classes of package com.sun.java.swing.action:
+//            DelegateAction, ActionManager
+
+public class CancelAction extends DelegateAction
+{
+
+    public CancelAction()
+    {
+        this(VALUE_SMALL_ICON);
+    }
+
+    public CancelAction(String iconPath)
+    {
+        super("Cancel", ActionManager.getIcon(iconPath));
+        putValue("ActionCommandKey", "cancel-command");
+        putValue("ShortDescription", "Cancels the action");
+        putValue("LongDescription", "Cancels the action");
+        putValue("MnemonicKey", VALUE_MNEMONIC);
+        putValue("AcceleratorKey", VALUE_ACCELERATOR);
+    }
+
+    public static final String VALUE_COMMAND = "cancel-command";
+    public static final String VALUE_NAME = "Cancel";
+    public static final String VALUE_SMALL_ICON = null;
+    public static final String VALUE_LARGE_ICON = null;
+    public static final Integer VALUE_MNEMONIC = new Integer(67);
+    public static final KeyStroke VALUE_ACCELERATOR = null;
+    public static final String VALUE_SHORT_DESCRIPTION = "Cancels the action";
+    public static final String VALUE_LONG_DESCRIPTION = "Cancels the action";
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/com/sun/java/swing/action/DelegateAction.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2000-2008 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+
+package com.sun.java.swing.action;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import javax.swing.AbstractAction;
+import javax.swing.Icon;
+
+public abstract class DelegateAction extends AbstractAction
+{
+
+    public DelegateAction(String name, Icon icon)
+    {
+        super(name, icon);
+    }
+
+    public void addActionListener(ActionListener listener)
+    {
+        this.listener = listener;
+    }
+
+    public void removeActionListener(ActionListener listener)
+    {
+        this.listener = null;
+    }
+
+    public ActionListener[] getActionListeners()
+    {
+        return (new ActionListener[] {
+            listener
+        });
+    }
+
+    public void actionPerformed(ActionEvent evt)
+    {
+        if(listener != null)
+            listener.actionPerformed(evt);
+    }
+
+    private ActionListener listener;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/com/sun/java/swing/action/ExitAction.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2000-2008 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+
+package com.sun.java.swing.action;
+
+import javax.swing.KeyStroke;
+
+// Referenced classes of package com.sun.java.swing.action:
+//            DelegateAction, ActionManager
+
+public class ExitAction extends DelegateAction
+{
+
+    public ExitAction()
+    {
+        super("Exit", ActionManager.getIcon(VALUE_SMALL_ICON));
+        putValue("ActionCommandKey", "exit-command");
+        putValue("ShortDescription", "Exits the application");
+        putValue("LongDescription", "Exits the application");
+        putValue("MnemonicKey", VALUE_MNEMONIC);
+        putValue("AcceleratorKey", VALUE_ACCELERATOR);
+    }
+
+    public static final String VALUE_COMMAND = "exit-command";
+    public static final String VALUE_NAME = "Exit";
+    public static final String VALUE_SMALL_ICON = null;
+    public static final String VALUE_LARGE_ICON = null;
+    public static final Integer VALUE_MNEMONIC = new Integer(88);
+    public static final KeyStroke VALUE_ACCELERATOR = null;
+    public static final String VALUE_SHORT_DESCRIPTION = "Exits the application";
+    public static final String VALUE_LONG_DESCRIPTION = "Exits the application";
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/com/sun/java/swing/action/FileMenu.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2000-2008 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+
+package com.sun.java.swing.action;
+
+import java.awt.event.ActionEvent;
+import javax.swing.AbstractAction;
+
+public class FileMenu extends AbstractAction
+{
+
+    public FileMenu()
+    {
+        super("File");
+        putValue("ActionCommandKey", "file-menu-command");
+        putValue("ShortDescription", "File operations");
+        putValue("LongDescription", "File operations");
+        putValue("MnemonicKey", VALUE_MNEMONIC);
+    }
+
+    public void actionPerformed(ActionEvent actionevent)
+    {
+    }
+
+    public static final String VALUE_COMMAND = "file-menu-command";
+    public static final String VALUE_NAME = "File";
+    public static final Integer VALUE_MNEMONIC = new Integer(70);
+    public static final String VALUE_SHORT_DESCRIPTION = "File operations";
+    public static final String VALUE_LONG_DESCRIPTION = "File operations";
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/com/sun/java/swing/action/FinishAction.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2000-2008 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+
+package com.sun.java.swing.action;
+
+import javax.swing.KeyStroke;
+
+// Referenced classes of package com.sun.java.swing.action:
+//            DelegateAction, ActionManager
+
+public class FinishAction extends DelegateAction
+{
+
+    public FinishAction()
+    {
+        this(VALUE_SMALL_ICON);
+    }
+
+    public FinishAction(String iconPath)
+    {
+        super("Finish", ActionManager.getIcon(iconPath));
+        putValue("ActionCommandKey", "finish-command");
+        putValue("ShortDescription", "Finish the activity");
+        putValue("LongDescription", "Finish the activity");
+        putValue("MnemonicKey", VALUE_MNEMONIC);
+        putValue("AcceleratorKey", VALUE_ACCELERATOR);
+    }
+
+    public static final String VALUE_COMMAND = "finish-command";
+    public static final String VALUE_NAME = "Finish";
+    public static final String VALUE_SMALL_ICON = null;
+    public static final String VALUE_LARGE_ICON = null;
+    public static final Integer VALUE_MNEMONIC = new Integer(70);
+    public static final KeyStroke VALUE_ACCELERATOR = null;
+    public static final String VALUE_SHORT_DESCRIPTION = "Finish the activity";
+    public static final String VALUE_LONG_DESCRIPTION = "Finish the activity";
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/com/sun/java/swing/action/HelpAction.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2000-2008 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+
+package com.sun.java.swing.action;
+
+import javax.swing.KeyStroke;
+
+// Referenced classes of package com.sun.java.swing.action:
+//            DelegateAction, ActionManager
+
+public class HelpAction extends DelegateAction
+{
+
+    public HelpAction()
+    {
+        this("general/Help16.gif");
+    }
+
+    public HelpAction(String iconPath)
+    {
+        super("Help", ActionManager.getIcon(iconPath));
+        putValue("ActionCommandKey", "help-command");
+        putValue("ShortDescription", "Help...");
+        putValue("LongDescription", "Provide information which may aid the user.");
+        putValue("MnemonicKey", VALUE_MNEMONIC);
+        putValue("AcceleratorKey", VALUE_ACCELERATOR);
+    }
+
+    public static final String VALUE_COMMAND = "help-command";
+    public static final String VALUE_NAME = "Help";
+    public static final String VALUE_SMALL_ICON = "general/Help16.gif";
+    public static final String VALUE_LARGE_ICON = "general/Help24.gif";
+    public static final Integer VALUE_MNEMONIC = new Integer(72);
+    public static final KeyStroke VALUE_ACCELERATOR = KeyStroke.getKeyStroke(112, 0);
+    public static final String VALUE_SHORT_DESCRIPTION = "Help...";
+    public static final String VALUE_LONG_DESCRIPTION = "Provide information which may aid the user.";
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/com/sun/java/swing/action/HelpMenu.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2000-2008 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+
+package com.sun.java.swing.action;
+
+import java.awt.event.ActionEvent;
+import javax.swing.AbstractAction;
+
+public class HelpMenu extends AbstractAction
+{
+
+    public HelpMenu()
+    {
+        super("Help");
+        putValue("ActionCommandKey", "help-menu-command");
+        putValue("ShortDescription", "Help operations");
+        putValue("LongDescription", "Help operations");
+        putValue("MnemonicKey", VALUE_MNEMONIC);
+    }
+
+    public void actionPerformed(ActionEvent actionevent)
+    {
+    }
+
+    public static final String VALUE_COMMAND = "help-menu-command";
+    public static final String VALUE_NAME = "Help";
+    public static final Integer VALUE_MNEMONIC = new Integer(72);
+    public static final String VALUE_SHORT_DESCRIPTION = "Help operations";
+    public static final String VALUE_LONG_DESCRIPTION = "Help operations";
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/com/sun/java/swing/action/NewAction.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2000-2008 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+
+package com.sun.java.swing.action;
+
+import javax.swing.KeyStroke;
+
+// Referenced classes of package com.sun.java.swing.action:
+//            DelegateAction, ActionManager
+
+public class NewAction extends DelegateAction
+{
+
+    public NewAction()
+    {
+        this("general/New16.gif");
+    }
+
+    public NewAction(String iconPath)
+    {
+        super("New", ActionManager.getIcon(iconPath));
+        putValue("ActionCommandKey", "new-command");
+        putValue("ShortDescription", "Create a new object.");
+        putValue("LongDescription", "Create a new object.");
+        putValue("MnemonicKey", VALUE_MNEMONIC);
+        putValue("AcceleratorKey", VALUE_ACCELERATOR);
+    }
+
+    public static final String VALUE_COMMAND = "new-command";
+    public static final String VALUE_NAME = "New";
+    public static final String VALUE_SMALL_ICON = "general/New16.gif";
+    public static final String VALUE_LARGE_ICON = "general/New24.gif";
+    public static final Integer VALUE_MNEMONIC = new Integer(78);
+    public static final KeyStroke VALUE_ACCELERATOR = KeyStroke.getKeyStroke(78, 2);
+    public static final String VALUE_SHORT_DESCRIPTION = "Create a new object.";
+    public static final String VALUE_LONG_DESCRIPTION = "Create a new object.";
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/com/sun/java/swing/action/NextAction.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2000-2008 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+
+package com.sun.java.swing.action;
+
+import javax.swing.KeyStroke;
+
+// Referenced classes of package com.sun.java.swing.action:
+//            DelegateAction, ActionManager
+
+public class NextAction extends DelegateAction
+{
+
+    public NextAction()
+    {
+        this(VALUE_SMALL_ICON);
+    }
+
+    public NextAction(String iconPath)
+    {
+        super("Next >", ActionManager.getIcon(iconPath));
+        putValue("ActionCommandKey", "next-command");
+        putValue("ShortDescription", "Select next item");
+        putValue("LongDescription", "Select next item");
+        putValue("MnemonicKey", VALUE_MNEMONIC);
+        putValue("AcceleratorKey", VALUE_ACCELERATOR);
+    }
+
+    public static final String VALUE_COMMAND = "next-command";
+    public static final String VALUE_NAME = "Next >";
+    public static final String VALUE_SMALL_ICON = null;
+    public static final String VALUE_LARGE_ICON = null;
+    public static final Integer VALUE_MNEMONIC = new Integer(78);
+    public static final KeyStroke VALUE_ACCELERATOR = null;
+    public static final String VALUE_SHORT_DESCRIPTION = "Select next item";
+    public static final String VALUE_LONG_DESCRIPTION = "Select next item";
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/com/sun/java/swing/action/OkAction.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2000-2008 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+
+package com.sun.java.swing.action;
+
+import javax.swing.KeyStroke;
+
+// Referenced classes of package com.sun.java.swing.action:
+//            DelegateAction, ActionManager
+
+public class OkAction extends DelegateAction
+{
+
+    public OkAction()
+    {
+        this(VALUE_SMALL_ICON);
+    }
+
+    public OkAction(String iconPath)
+    {
+        super("OK", ActionManager.getIcon(iconPath));
+        putValue("ActionCommandKey", "ok-command");
+        putValue("ShortDescription", "Acknowleges the action");
+        putValue("LongDescription", "Acknowleges the action");
+        putValue("MnemonicKey", VALUE_MNEMONIC);
+        putValue("AcceleratorKey", VALUE_ACCELERATOR);
+    }
+
+    public static final String VALUE_COMMAND = "ok-command";
+    public static final String VALUE_NAME = "OK";
+    public static final String VALUE_SMALL_ICON = null;
+    public static final String VALUE_LARGE_ICON = null;
+    public static final Integer VALUE_MNEMONIC = new Integer(79);
+    public static final KeyStroke VALUE_ACCELERATOR = null;
+    public static final String VALUE_SHORT_DESCRIPTION = "Acknowleges the action";
+    public static final String VALUE_LONG_DESCRIPTION = "Acknowleges the action";
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/com/sun/java/swing/action/OpenAction.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2000-2008 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+
+package com.sun.java.swing.action;
+
+import javax.swing.KeyStroke;
+
+// Referenced classes of package com.sun.java.swing.action:
+//            DelegateAction, ActionManager
+
+public class OpenAction extends DelegateAction
+{
+
+    public OpenAction()
+    {
+        this("general/Open16.gif");
+    }
+
+    public OpenAction(String iconPath)
+    {
+        super("Open...", ActionManager.getIcon(iconPath));
+        putValue("ActionCommandKey", "open-command");
+        putValue("ShortDescription", "Open the specified object.");
+        putValue("LongDescription", "Open the specified object.");
+        putValue("MnemonicKey", VALUE_MNEMONIC);
+        putValue("AcceleratorKey", VALUE_ACCELERATOR);
+    }
+
+    public static final String VALUE_COMMAND = "open-command";
+    public static final String VALUE_NAME = "Open...";
+    public static final String VALUE_SMALL_ICON = "general/Open16.gif";
+    public static final String VALUE_LARGE_ICON = "general/Open24.gif";
+    public static final Integer VALUE_MNEMONIC = new Integer(79);
+    public static final KeyStroke VALUE_ACCELERATOR = KeyStroke.getKeyStroke(79, 2);
+    public static final String VALUE_SHORT_DESCRIPTION = "Open the specified object.";
+    public static final String VALUE_LONG_DESCRIPTION = "Open the specified object.";
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/com/sun/java/swing/action/SaveAction.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2000-2008 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+
+package com.sun.java.swing.action;
+
+import javax.swing.KeyStroke;
+
+// Referenced classes of package com.sun.java.swing.action:
+//            DelegateAction, ActionManager
+
+public class SaveAction extends DelegateAction
+{
+
+    public SaveAction()
+    {
+        this("general/Save16.gif");
+    }
+
+    public SaveAction(String iconPath)
+    {
+        super("Save", ActionManager.getIcon(iconPath));
+        putValue("ActionCommandKey", "save-command");
+        putValue("ShortDescription", "Commit changes to a permanent storage area");
+        putValue("LongDescription", "Commit changes to a permanent storage area");
+        putValue("MnemonicKey", VALUE_MNEMONIC);
+        putValue("AcceleratorKey", VALUE_ACCELERATOR);
+    }
+
+    public static final String VALUE_COMMAND = "save-command";
+    public static final String VALUE_NAME = "Save";
+    public static final String VALUE_SMALL_ICON = "general/Save16.gif";
+    public static final String VALUE_LARGE_ICON = "general/Save24.gif";
+    public static final Integer VALUE_MNEMONIC = new Integer(83);
+    public static final KeyStroke VALUE_ACCELERATOR = KeyStroke.getKeyStroke(83, 2);
+    public static final String VALUE_SHORT_DESCRIPTION = "Commit changes to a permanent storage area";
+    public static final String VALUE_LONG_DESCRIPTION = "Commit changes to a permanent storage area";
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/com/sun/java/swing/action/SaveAsAction.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2000-2008 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+
+package com.sun.java.swing.action;
+
+
+// Referenced classes of package com.sun.java.swing.action:
+//            DelegateAction, ActionManager
+
+public class SaveAsAction extends DelegateAction
+{
+
+    public SaveAsAction()
+    {
+        this("general/SaveAs16.gif");
+    }
+
+    public SaveAsAction(String iconPath)
+    {
+        super("Save As", ActionManager.getIcon(iconPath));
+        putValue("ActionCommandKey", "save-as-command");
+        putValue("ShortDescription", "Save as a new file");
+        putValue("LongDescription", "Saves the current object as another object");
+        putValue("MnemonicKey", VALUE_MNEMONIC);
+    }
+
+    public static final String VALUE_COMMAND = "save-as-command";
+    public static final String VALUE_NAME = "Save As";
+    public static final String VALUE_SMALL_ICON = "general/SaveAs16.gif";
+    public static final String VALUE_LARGE_ICON = "general/SaveAs24.gif";
+    public static final Integer VALUE_MNEMONIC = new Integer(65);
+    public static final String VALUE_SHORT_DESCRIPTION = "Save as a new file";
+    public static final String VALUE_LONG_DESCRIPTION = "Saves the current object as another object";
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/com/sun/java/swing/action/StateChangeAction.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2000-2008 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+
+package com.sun.java.swing.action;
+
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+import javax.swing.Icon;
+
+// Referenced classes of package com.sun.java.swing.action:
+//            DelegateAction
+
+public abstract class StateChangeAction extends DelegateAction
+    implements ItemListener
+{
+
+    public StateChangeAction(String name)
+    {
+        super(name, null);
+        selected = false;
+    }
+
+    public StateChangeAction(String name, Icon icon)
+    {
+        super(name, icon);
+        selected = false;
+    }
+
+    public boolean isSelected()
+    {
+        return selected;
+    }
+
+    public synchronized void setSelected(boolean newValue)
+    {
+        boolean oldValue = selected;
+        if(oldValue != newValue)
+        {
+            selected = newValue;
+            firePropertyChange("selected", Boolean.valueOf(oldValue), Boolean.valueOf(newValue));
+        }
+    }
+
+    public void setItemListener(ItemListener listener)
+    {
+        this.listener = listener;
+    }
+
+    public ItemListener getItemListener()
+    {
+        return listener;
+    }
+
+    public void itemStateChanged(ItemEvent evt)
+    {
+        if(evt.getStateChange() == 1)
+            setSelected(true);
+        else
+            setSelected(false);
+        if(listener != null)
+            listener.itemStateChanged(evt);
+    }
+
+    protected boolean selected;
+    private ItemListener listener;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/com/sun/java/swing/action/ViewMenu.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2000-2008 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+
+package com.sun.java.swing.action;
+
+import java.awt.event.ActionEvent;
+import javax.swing.AbstractAction;
+
+public class ViewMenu extends AbstractAction
+{
+
+    public ViewMenu()
+    {
+        super("View");
+        putValue("ActionCommandKey", "view-menu-command");
+        putValue("ShortDescription", "View operations");
+        putValue("LongDescription", "View operations");
+        putValue("MnemonicKey", VALUE_MNEMONIC);
+    }
+
+    public void actionPerformed(ActionEvent actionevent)
+    {
+    }
+
+    public static final String VALUE_COMMAND = "view-menu-command";
+    public static final String VALUE_NAME = "View";
+    public static final Integer VALUE_MNEMONIC = new Integer(86);
+    public static final String VALUE_SHORT_DESCRIPTION = "View operations";
+    public static final String VALUE_LONG_DESCRIPTION = "View operations";
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/com/sun/java/swing/ui/CommonMenuBar.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2000-2008 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+
+package com.sun.java.swing.ui;
+
+import com.sun.java.swing.action.ActionManager;
+import com.sun.java.swing.action.StateChangeAction;
+import javax.swing.*;
+
+// Referenced classes of package com.sun.java.swing.ui:
+//            ToggleActionPropertyChangeListener, StatusBar
+
+public abstract class CommonMenuBar extends JMenuBar
+{
+
+    protected CommonMenuBar(ActionManager manager)
+    {
+        this(manager, StatusBar.getInstance());
+    }
+
+    protected CommonMenuBar(ActionManager manager, StatusBar status)
+    {
+        this.manager = manager;
+        statusBar = status;
+        configureMenu();
+    }
+
+    protected abstract void configureMenu();
+
+    protected void configureToggleMenuItem(JMenuItem menuItem, Action action)
+    {
+        configureMenuItem(menuItem, action);
+        action.addPropertyChangeListener(new ToggleActionPropertyChangeListener(menuItem));
+    }
+
+    protected void configureMenuItem(JMenuItem menuItem, Action action)
+    {
+        menuItem.addMouseListener(statusBar);
+    }
+
+    protected JMenu createMenu(String name, char mnemonic)
+    {
+        JMenu menu = new JMenu(name);
+        menu.setMnemonic(mnemonic);
+        return menu;
+    }
+
+    protected void addMenuItem(JMenu menu, Action action)
+    {
+        JMenuItem menuItem = menu.add(action);
+        configureMenuItem(menuItem, action);
+    }
+
+    protected void addCheckBoxMenuItem(JMenu menu, StateChangeAction a)
+    {
+        addCheckBoxMenuItem(menu, a, false);
+    }
+
+    protected void addCheckBoxMenuItem(JMenu menu, StateChangeAction a, boolean selected)
+    {
+        JCheckBoxMenuItem mi = new JCheckBoxMenuItem(a);
+        mi.addItemListener(a);
+        mi.setSelected(selected);
+        menu.add(mi);
+        configureToggleMenuItem(mi, a);
+    }
+
+    protected void addRadioButtonMenuItem(JMenu menu, ButtonGroup group, StateChangeAction a)
+    {
+        addRadioButtonMenuItem(menu, group, a, false);
+    }
+
+    protected void addRadioButtonMenuItem(JMenu menu, ButtonGroup group, StateChangeAction a, boolean selected)
+    {
+        JRadioButtonMenuItem mi = new JRadioButtonMenuItem(a);
+        mi.addItemListener(a);
+        mi.setSelected(selected);
+        menu.add(mi);
+        if(group != null)
+            group.add(mi);
+        configureToggleMenuItem(mi, a);
+    }
+
+    protected ActionManager manager;
+    private StatusBar statusBar;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/com/sun/java/swing/ui/CommonToolBar.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2000-2008 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+
+package com.sun.java.swing.ui;
+
+import com.sun.java.swing.action.ActionManager;
+import com.sun.java.swing.action.StateChangeAction;
+import java.awt.Dimension;
+import java.awt.Insets;
+import javax.swing.*;
+
+// Referenced classes of package com.sun.java.swing.ui:
+//            ToggleActionPropertyChangeListener, StatusBar, CommonUI
+
+public abstract class CommonToolBar extends JToolBar
+{
+
+    protected CommonToolBar(ActionManager manager)
+    {
+        this(manager, StatusBar.getInstance());
+    }
+
+    protected CommonToolBar(ActionManager manager, StatusBar status)
+    {
+        this.manager = manager;
+        statusBar = status;
+        buttonSize = new Dimension(CommonUI.buttconPrefSize);
+        buttonInsets = new Insets(0, 0, 0, 0);
+        addComponents();
+    }
+
+    protected abstract void addComponents();
+
+    protected void addButton(Action action)
+    {
+        javax.swing.JButton button = add(action);
+        configureButton(button, action);
+    }
+
+    protected void addToggleButton(StateChangeAction a)
+    {
+        addToggleButton(a, null);
+    }
+
+    protected void addToggleButton(StateChangeAction a, ButtonGroup group)
+    {
+        JToggleButton button = new JToggleButton(a);
+        button.addItemListener(a);
+        button.setSelected(a.isSelected());
+        if(group != null)
+            group.add(button);
+        add(button);
+        configureToggleButton(button, a);
+    }
+
+    protected void configureToggleButton(JToggleButton button, Action action)
+    {
+        configureButton(button, action);
+        action.addPropertyChangeListener(new ToggleActionPropertyChangeListener(button));
+    }
+
+    protected void configureButton(AbstractButton button, Action action)
+    {
+        button.setToolTipText((String)action.getValue("Name"));
+        button.setText("");
+        button.addMouseListener(statusBar);
+    }
+
+    protected ActionManager manager;
+    private Dimension buttonSize;
+    private Insets buttonInsets;
+    private StatusBar statusBar;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/com/sun/java/swing/ui/CommonUI.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,392 @@
+/*
+ * Copyright 2000-2008 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+
+package com.sun.java.swing.ui;
+
+import java.awt.*;
+import java.awt.event.ActionListener;
+import java.awt.event.KeyListener;
+import java.util.StringTokenizer;
+import java.util.Vector;
+import javax.swing.*;
+import javax.swing.border.Border;
+import javax.swing.text.*;
+
+public class CommonUI
+{
+    private static class NumberDocument extends PlainDocument
+    {
+
+        public void insertString(int offs, String str, AttributeSet atts)
+            throws BadLocationException
+        {
+            if(!Character.isDigit(str.charAt(0)))
+            {
+                return;
+            } else
+            {
+                super.insertString(offs, str, atts);
+                return;
+            }
+        }
+
+        private NumberDocument()
+        {
+        }
+
+    }
+
+
+    public CommonUI()
+    {
+    }
+
+    public static JLabel createLabel(String text, int mnemonic, Component comp)
+    {
+        JLabel label = new JLabel("  " + text);
+        label.setMinimumSize(labelPrefSize);
+        if(mnemonic != -1)
+            label.setDisplayedMnemonic(mnemonic);
+        if(comp != null)
+            label.setLabelFor(comp);
+        if(text.length() == 0)
+            label.setPreferredSize(labelPrefSize);
+        return label;
+    }
+
+    public static JLabel createLabel(String text)
+    {
+        return createLabel(text, -1, null);
+    }
+
+    public static JTextField createTextField(String text, KeyListener listener, boolean numbers)
+    {
+        JTextField field = new JTextField(text);
+        field.setMinimumSize(textPrefSize);
+        if(text.length() == 0)
+            field.setPreferredSize(textPrefSize);
+        if(listener != null)
+            field.addKeyListener(listener);
+        if(numbers)
+            field.setDocument(new NumberDocument());
+        return field;
+    }
+
+    public static JTextField createTextField(String text, boolean numbers)
+    {
+        return createTextField(text, null, numbers);
+    }
+
+    public static JTextField createTextField(String text, KeyListener listener)
+    {
+        return createTextField(text, listener, false);
+    }
+
+    public static JTextField createTextField(String text)
+    {
+        return createTextField(text, null, false);
+    }
+
+    public static JRadioButton createRadioButton(String text, int mnemonic, ActionListener listener, boolean selected)
+    {
+        JRadioButton button = new JRadioButton(text);
+        button.setMnemonic(mnemonic);
+        button.setSelected(selected);
+        button.setMinimumSize(labelPrefSize);
+        if(listener != null)
+            button.addActionListener(listener);
+        if(text.length() == 0)
+            button.setPreferredSize(labelPrefSize);
+        return button;
+    }
+
+    public static JRadioButton createRadioButton(String text, int mnemonic, boolean selected)
+    {
+        return createRadioButton(text, mnemonic, null, selected);
+    }
+
+    public static JRadioButton createRadioButton(String text, int mnemonic, ActionListener listener)
+    {
+        return createRadioButton(text, mnemonic, listener, false);
+    }
+
+    public static JRadioButton createRadioButton(String text, int mnemonic)
+    {
+        return createRadioButton(text, mnemonic, null, false);
+    }
+
+    public static JRadioButton createRadioButton(String text)
+    {
+        return createRadioButton(text, -1, null, false);
+    }
+
+    public static JCheckBox createCheckBox(String text, int mnemonic, ActionListener listener, boolean selected)
+    {
+        JCheckBox checkbox = new JCheckBox(text);
+        checkbox.setMinimumSize(labelPrefSize);
+        if(mnemonic != -1)
+            checkbox.setMnemonic(mnemonic);
+        checkbox.setSelected(selected);
+        if(text.length() == 0)
+            checkbox.setPreferredSize(labelPrefSize);
+        if(listener != null)
+            checkbox.addActionListener(listener);
+        return checkbox;
+    }
+
+    public static JCheckBox createCheckBox(String text, int mnemonic, ActionListener listener)
+    {
+        return createCheckBox(text, mnemonic, listener, false);
+    }
+
+    public static JCheckBox createCheckBox(String text, int mnemonic, boolean selected)
+    {
+        return createCheckBox(text, mnemonic, null, selected);
+    }
+
+    public static JCheckBox createCheckBox(String text, int mnemonic)
+    {
+        return createCheckBox(text, mnemonic, null, false);
+    }
+
+    public static JCheckBox createCheckBox(String text)
+    {
+        return createCheckBox(text, -1, null, false);
+    }
+
+    public static JComboBox createComboBox(Object items[], ActionListener listener, boolean editable)
+    {
+        JComboBox comboBox = new JComboBox(items);
+        if(listener != null)
+            comboBox.addActionListener(listener);
+        comboBox.setEditable(editable);
+        return comboBox;
+    }
+
+    public static JComboBox createComboBox(Object items[], boolean editable)
+    {
+        return createComboBox(items, null, editable);
+    }
+
+    public static JComboBox createComboBox(Vector items, ActionListener listener, boolean editable)
+    {
+        JComboBox comboBox = new JComboBox(items);
+        if(listener != null)
+            comboBox.addActionListener(listener);
+        comboBox.setEditable(editable);
+        return comboBox;
+    }
+
+    public static JComboBox createComboBox(Vector items, boolean editable)
+    {
+        return createComboBox(items, null, editable);
+    }
+
+    public static JButton createButton(Action action)
+    {
+        JButton button = new JButton(action);
+        setButtonSize(button, buttonPrefSize);
+        return button;
+    }
+
+    public static JButton createButton(String text, ActionListener listener, int mnemonic)
+    {
+        JButton button = new JButton(text);
+        if(listener != null)
+            button.addActionListener(listener);
+        if(mnemonic != -1)
+            button.setMnemonic(mnemonic);
+        setButtonSize(button, buttonPrefSize);
+        return button;
+    }
+
+    private static void setButtonSize(JButton button, Dimension size)
+    {
+        String text = button.getText();
+        button.setMinimumSize(size);
+        if(text.length() == 0)
+        {
+            button.setPreferredSize(size);
+        } else
+        {
+            Dimension psize = button.getPreferredSize();
+            if(psize.width < size.width)
+                button.setPreferredSize(size);
+        }
+    }
+
+    public static JButton createButton(String text, ActionListener listener)
+    {
+        return createButton(text, listener, -1);
+    }
+
+    public static JButton createSmallButton(String text, ActionListener listener, int mnemonic)
+    {
+        JButton button = createButton(text, listener, mnemonic);
+        setButtonSize(button, smbuttonPrefSize);
+        return button;
+    }
+
+    public static JButton createSmallButton(String text, ActionListener listener)
+    {
+        return createSmallButton(text, listener, -1);
+    }
+
+    public static Border createBorder(String text)
+    {
+        Border border = BorderFactory.createEtchedBorder();
+        return BorderFactory.createTitledBorder(border, text, 0, 2);
+    }
+
+    public static Border createBorder()
+    {
+        return BorderFactory.createEmptyBorder(4, 4, 4, 4);
+    }
+
+    public static JScrollPane createListPane(JList list, String text)
+    {
+        JScrollPane pane = new JScrollPane(list);
+        pane.setBorder(BorderFactory.createCompoundBorder(createBorder(text), BorderFactory.createLoweredBevelBorder()));
+        return pane;
+    }
+
+    public static void centerComponent(Component source, Component parent)
+    {
+        Dimension dim = source.getSize();
+        Rectangle rect;
+        if(parent != null)
+        {
+            rect = parent.getBounds();
+        } else
+        {
+            Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
+            rect = new Rectangle(0, 0, d.width, d.height);
+        }
+        int x = rect.x + (rect.width - dim.width) / 2;
+        int y = rect.y + (rect.height - dim.height) / 2;
+        source.setLocation(x, y);
+    }
+
+    public static void centerComponent(Component source)
+    {
+        centerComponent(source, null);
+    }
+
+    public static JFrame getParentFrame(Component source)
+    {
+        Container parent;
+        for(parent = source.getParent(); parent != null; parent = parent.getParent())
+            if(parent instanceof JFrame)
+                break;
+
+        if(parent == null)
+            return null;
+        else
+            return (JFrame)parent;
+    }
+
+    public static Integer msToSec(Integer ms)
+    {
+        int value = ms.intValue();
+        value /= 1000;
+        return new Integer(value);
+    }
+
+    public static Integer secToMs(Integer sec)
+    {
+        int value = sec.intValue();
+        value *= 1000;
+        return new Integer(value);
+    }
+
+    public static String stringFromStringArray(String strings[], String delim)
+    {
+        String string = "";
+        String separator;
+        if(delim == null || delim.equals(""))
+            separator = " ";
+        else
+            separator = delim;
+        for(int i = 0; i < strings.length; i++)
+        {
+            string = string + strings[i];
+            string = string + separator;
+        }
+
+        return string;
+    }
+
+    public static String stringFromStringArray(String strings[])
+    {
+        return stringFromStringArray(strings, "");
+    }
+
+    public static String[] stringArrayFromString(String string, String delim)
+    {
+        StringTokenizer st;
+        if(delim == null || delim.equals(""))
+            st = new StringTokenizer(string);
+        else
+            st = new StringTokenizer(string, delim);
+        int numTokens = st.countTokens();
+        String strings[] = new String[numTokens];
+        int index = 0;
+        while(st.hasMoreTokens())
+            strings[index++] = st.nextToken();
+        return strings;
+    }
+
+    public static String[] stringArrayFromString(String string)
+    {
+        return stringArrayFromString(string, "");
+    }
+
+    public static void setWaitCursor(Component comp)
+    {
+        comp.setCursor(Cursor.getPredefinedCursor(3));
+    }
+
+    public static void setDefaultCursor(Component comp)
+    {
+        comp.setCursor(Cursor.getPredefinedCursor(0));
+    }
+
+    public static final int BUTTON_WIDTH = 100;
+    public static final int BUTTON_HEIGHT = 26;
+    public static final int BUTTCON_WIDTH = 28;
+    public static final int BUTTCON_HEIGHT = 28;
+    public static final int SM_BUTTON_WIDTH = 72;
+    public static final int SM_BUTTON_HEIGHT = 26;
+    public static final int LABEL_WIDTH = 100;
+    public static final int LABEL_HEIGHT = 20;
+    public static final int TEXT_WIDTH = 150;
+    public static final int TEXT_HEIGHT = 20;
+    public static Dimension buttonPrefSize = new Dimension(100, 26);
+    public static Dimension buttconPrefSize = new Dimension(28, 28);
+    public static Dimension smbuttonPrefSize = new Dimension(72, 26);
+    public static Dimension labelPrefSize = new Dimension(100, 20);
+    public static Dimension textPrefSize = new Dimension(150, 20);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/com/sun/java/swing/ui/OkCancelButtonPanel.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2000-2008 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+
+package com.sun.java.swing.ui;
+
+import com.sun.java.swing.action.*;
+import java.awt.event.ActionListener;
+import javax.swing.JPanel;
+
+// Referenced classes of package com.sun.java.swing.ui:
+//            CommonUI
+
+public class OkCancelButtonPanel extends JPanel
+{
+
+    public OkCancelButtonPanel(ActionListener listener)
+    {
+        DelegateAction okAction = new OkAction();
+        okAction.addActionListener(listener);
+        DelegateAction cancelAction = new CancelAction();
+        cancelAction.addActionListener(listener);
+        add(CommonUI.createButton(okAction));
+        add(CommonUI.createButton(cancelAction));
+    }
+
+    public static final String OK_COMMAND = "ok-command";
+    public static final String CANCEL_COMMAND = "cancel-command";
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/com/sun/java/swing/ui/OkCancelDialog.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2000-2008 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+
+package com.sun.java.swing.ui;
+
+import java.awt.BorderLayout;
+import java.awt.Container;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import javax.swing.JDialog;
+import javax.swing.JPanel;
+
+// Referenced classes of package com.sun.java.swing.ui:
+//            OkCancelButtonPanel, CommonUI
+
+public class OkCancelDialog extends JDialog
+    implements ActionListener
+{
+
+    public OkCancelDialog(String title, JPanel panel)
+    {
+        this(title, panel, true);
+    }
+
+    public OkCancelDialog(String title, JPanel panel, boolean modal)
+    {
+        setTitle(title);
+        setModal(modal);
+        Container pane = getContentPane();
+        pane.setLayout(new BorderLayout());
+        pane.add(panel, "Center");
+        pane.add(new OkCancelButtonPanel(this), "South");
+        pack();
+        CommonUI.centerComponent(this);
+    }
+
+    public boolean isOk()
+    {
+        return okPressed;
+    }
+
+    public void actionPerformed(ActionEvent evt)
+    {
+        String command = evt.getActionCommand();
+        if(command.equals("ok-command"))
+        {
+            okPressed = true;
+            setVisible(false);
+            dispose();
+        } else
+        if(command.equals("cancel-command"))
+        {
+            okPressed = false;
+            setVisible(false);
+            dispose();
+        }
+    }
+
+    private boolean okPressed;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/com/sun/java/swing/ui/SplashScreen.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2000-2008 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+
+package com.sun.java.swing.ui;
+
+import java.awt.*;
+import javax.swing.ImageIcon;
+
+public class SplashScreen extends Window
+{
+
+    public SplashScreen(Frame f)
+    {
+        super(f);
+        setBackground(Color.white);
+        java.net.URL url = getClass().getResource("/images/SplashScreen.jpg");
+        if(url != null)
+        {
+            screen = new ImageIcon(url);
+            MediaTracker mt = new MediaTracker(this);
+            mt.addImage(screen.getImage(), 0);
+            try
+            {
+                mt.waitForAll();
+            }
+            catch(Exception ex) { }
+        }
+    }
+
+    public void setVisible(boolean val)
+    {
+        if(screen == null)
+            return;
+        if(val)
+        {
+            setSize(screen.getIconWidth(), screen.getIconHeight());
+            setLocation(-500, -500);
+            super.setVisible(true);
+            Dimension d = getToolkit().getScreenSize();
+            Insets i = getInsets();
+            int w = screen.getIconWidth() + i.left + i.right;
+            int h = screen.getIconHeight() + i.top + i.bottom;
+            setSize(w, h);
+            setLocation(d.width / 2 - w / 2, d.height / 2 - h / 2);
+        } else
+        {
+            super.setVisible(false);
+        }
+    }
+
+    public void paint(Graphics g)
+    {
+        if(screen != null)
+        {
+            Dimension d = getSize();
+            g.setColor(Color.black);
+            g.drawRect(0, 0, d.width - 1, d.height - 1);
+            g.drawImage(screen.getImage(), 1, 1, this);
+        }
+    }
+
+    private ImageIcon screen;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/com/sun/java/swing/ui/StatusBar.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,178 @@
+/*
+ * Copyright 2000-2008 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+
+package com.sun.java.swing.ui;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+
+public class StatusBar extends JPanel
+    implements ActionListener, MouseListener
+{
+
+    public StatusBar()
+    {
+        setLayout(new FlowLayout(0));
+        setBorder(BorderFactory.createEtchedBorder());
+        progressBar = new JProgressBar(0, 0, 100);
+        progressBar.setPreferredSize(new Dimension(60, progressBar.getPreferredSize().height + 2));
+        progressBar.setVisible(false);
+        label = new JLabel("                                                                                        ");
+        preferredSize = new Dimension(getWidth(label.getText()), 2 * getFontHeight());
+        add(progressBar);
+        add(label);
+    }
+
+    public static StatusBar getInstance()
+    {
+        if(statusBar == null)
+            statusBar = new StatusBar();
+        return statusBar;
+    }
+
+    public static void setInstance(StatusBar sb)
+    {
+        statusBar = sb;
+    }
+
+    protected int getWidth(String s)
+    {
+        FontMetrics fm = getFontMetrics(getFont());
+        if(fm == null)
+            return 0;
+        else
+            return fm.stringWidth(s);
+    }
+
+    protected int getFontHeight()
+    {
+        FontMetrics fm = getFontMetrics(getFont());
+        if(fm == null)
+            return 0;
+        else
+            return fm.getHeight();
+    }
+
+    public Dimension getPreferredSize()
+    {
+        return preferredSize;
+    }
+
+    public void setMessage(String message)
+    {
+        label.setText(message);
+        label.repaint();
+    }
+
+    public void startBusyBar()
+    {
+        forward = true;
+        if(timer == null)
+        {
+            setMessage("");
+            progressBar.setVisible(true);
+            timer = new Timer(15, this);
+            timer.start();
+        }
+    }
+
+    public void stopBusyBar()
+    {
+        if(timer != null)
+        {
+            timer.stop();
+            timer = null;
+        }
+        setMessage("");
+        progressBar.setVisible(false);
+        progressBar.setValue(0);
+    }
+
+    public void actionPerformed(ActionEvent evt)
+    {
+        int value = progressBar.getValue();
+        if(forward)
+        {
+            if(value < 100)
+            {
+                progressBar.setValue(value + 1);
+            } else
+            {
+                forward = false;
+                progressBar.setValue(value - 1);
+            }
+        } else
+        if(value > 0)
+        {
+            progressBar.setValue(value - 1);
+        } else
+        {
+            forward = true;
+            progressBar.setValue(value + 1);
+        }
+    }
+
+    public void mouseClicked(MouseEvent mouseevent)
+    {
+    }
+
+    public void mousePressed(MouseEvent mouseevent)
+    {
+    }
+
+    public void mouseReleased(MouseEvent mouseevent)
+    {
+    }
+
+    public void mouseExited(MouseEvent evt)
+    {
+        setMessage("");
+    }
+
+    public void mouseEntered(MouseEvent evt)
+    {
+        if(evt.getSource() instanceof AbstractButton)
+        {
+            AbstractButton button = (AbstractButton)evt.getSource();
+            Action action = button.getAction();
+            if(action != null)
+            {
+                String message = (String)action.getValue("LongDescription");
+                setMessage(message);
+            }
+        }
+    }
+
+    private static final int PROGRESS_MAX = 100;
+    private static final int PROGRESS_MIN = 0;
+    private JLabel label;
+    private Dimension preferredSize;
+    private JProgressBar progressBar;
+    private Timer timer;
+    private boolean forward;
+    private static StatusBar statusBar;
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/com/sun/java/swing/ui/TabsDlg.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,221 @@
+/*
+ * Copyright 2000-2008 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+
+package com.sun.java.swing.ui;
+
+import com.sun.java.swing.action.*;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.Vector;
+import javax.swing.*;
+
+// Referenced classes of package com.sun.java.swing.ui:
+//            CommonUI
+
+public class TabsDlg extends JDialog
+{
+    private class ApplyListener
+        implements ActionListener
+    {
+
+        public void actionPerformed(ActionEvent evt)
+        {
+            if(applyListener != null)
+            {
+                applyListener.actionPerformed(evt);
+                enableApplyButton(false);
+            }
+        }
+
+        private ApplyListener()
+        {
+        }
+
+    }
+
+    private class CancelListener
+        implements ActionListener
+    {
+
+        public void actionPerformed(ActionEvent evt)
+        {
+            if(cancelListener != null)
+                cancelListener.actionPerformed(evt);
+            setVisible(false);
+        }
+
+        private CancelListener()
+        {
+        }
+
+    }
+
+    private class OkListener
+        implements ActionListener
+    {
+
+        public void actionPerformed(ActionEvent evt)
+        {
+            if(okListener != null)
+                okListener.actionPerformed(evt);
+            setVisible(false);
+        }
+
+        private OkListener()
+        {
+        }
+
+    }
+
+
+    public TabsDlg(String title, Vector panels)
+    {
+        super(new JFrame(), title, true);
+        okListener = null;
+        cancelListener = null;
+        applyListener = null;
+        Container pane = getContentPane();
+        pane.setLayout(new BorderLayout());
+        tabsPanel = new JTabbedPane();
+        int numPanels = panels.size();
+        for(int i = 0; i < numPanels; i++)
+        {
+            JPanel panel = (JPanel)panels.elementAt(i);
+            tabsPanel.addTab(panel.getName(), panel);
+        }
+
+        pane.add(tabsPanel, "Center");
+        pane.add(createButtonPanel(), "South");
+        pack();
+        CommonUI.centerComponent(this);
+    }
+
+    public static void main(String args[])
+    {
+        JPanel p1 = new JPanel();
+        p1.add(new JButton("One"));
+        p1.setName("One");
+        JPanel p2 = new JPanel();
+        p2.add(new JButton("Two"));
+        p2.setName("Two");
+        JPanel p3 = new JPanel();
+        p3.add(new JButton("Three"));
+        p3.setName("Three");
+        JPanel p4 = new JPanel();
+        p4.add(new JButton("Four"));
+        p4.setName("Four");
+        Vector panels = new Vector();
+        panels.addElement(p1);
+        panels.addElement(p2);
+        panels.addElement(p3);
+        panels.addElement(p4);
+        tabsDlg = new TabsDlg("Test Dialog", panels);
+        tabsDlg.addOkListener(new ActionListener() {
+
+            public void actionPerformed(ActionEvent evt)
+            {
+                System.exit(0);
+            }
+
+        }
+);
+        tabsDlg.addCancelListener(new ActionListener() {
+
+            public void actionPerformed(ActionEvent evt)
+            {
+                System.exit(0);
+            }
+
+        }
+);
+        tabsDlg.setVisible(true);
+    }
+
+    private JPanel createButtonPanel()
+    {
+        JPanel panel = new JPanel();
+        okAction = new OkAction();
+        cancelAction = new CancelAction();
+        applyAction = new ApplyAction();
+        okAction.addActionListener(new OkListener());
+        cancelAction.addActionListener(new CancelListener());
+        applyAction.addActionListener(new ApplyListener());
+        panel.add(CommonUI.createButton(okAction));
+        panel.add(CommonUI.createButton(cancelAction));
+        panel.add(CommonUI.createButton(applyAction));
+        JPanel p2 = new JPanel(new BorderLayout());
+        p2.add(panel, "Center");
+        p2.add(new JSeparator(), "North");
+        return p2;
+    }
+
+    public void enableApplyButton(boolean enabled)
+    {
+        applyAction.setEnabled(enabled);
+    }
+
+    public synchronized void addOkListener(ActionListener l)
+    {
+        okListener = AWTEventMulticaster.add(okListener, l);
+    }
+
+    public synchronized void removeOkListener(ActionListener l)
+    {
+        okListener = AWTEventMulticaster.remove(okListener, l);
+    }
+
+    public synchronized void addCancelListener(ActionListener l)
+    {
+        cancelListener = AWTEventMulticaster.add(cancelListener, l);
+    }
+
+    public synchronized void removeCancelListener(ActionListener l)
+    {
+        cancelListener = AWTEventMulticaster.remove(cancelListener, l);
+    }
+
+    public synchronized void addApplyListener(ActionListener l)
+    {
+        applyListener = AWTEventMulticaster.add(applyListener, l);
+    }
+
+    public synchronized void removeApplyListener(ActionListener l)
+    {
+        applyListener = AWTEventMulticaster.remove(applyListener, l);
+    }
+
+    private JTabbedPane tabsPanel;
+    private DelegateAction okAction;
+    private DelegateAction cancelAction;
+    private DelegateAction applyAction;
+    private ActionListener okListener;
+    private ActionListener cancelListener;
+    private ActionListener applyListener;
+    private static TabsDlg tabsDlg;
+
+
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/com/sun/java/swing/ui/ToggleActionPropertyChangeListener.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2000-2008 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+
+package com.sun.java.swing.ui;
+
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import javax.swing.AbstractButton;
+
+public class ToggleActionPropertyChangeListener
+    implements PropertyChangeListener
+{
+
+    public ToggleActionPropertyChangeListener(AbstractButton button)
+    {
+        this.button = button;
+    }
+
+    public void propertyChange(PropertyChangeEvent evt)
+    {
+        String propertyName = evt.getPropertyName();
+        if(propertyName.equals("selected"))
+        {
+            Boolean selected = (Boolean)evt.getNewValue();
+            button.setSelected(selected.booleanValue());
+        }
+    }
+
+    private AbstractButton button;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/com/sun/java/swing/ui/WizardDlg.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,336 @@
+/*
+ * Copyright 2000-2008 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+
+package com.sun.java.swing.ui;
+
+import com.sun.java.swing.action.*;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.Vector;
+import javax.swing.*;
+
+// Referenced classes of package com.sun.java.swing.ui:
+//            CommonUI
+
+public class WizardDlg extends JDialog
+{
+    private class CancelListener
+        implements ActionListener
+    {
+
+        public void actionPerformed(ActionEvent evt)
+        {
+            if(cancelListener != null)
+                cancelListener.actionPerformed(evt);
+            setVisible(false);
+        }
+
+        private CancelListener()
+        {
+        }
+
+    }
+
+    private class FinishListener
+        implements ActionListener
+    {
+
+        public void actionPerformed(ActionEvent evt)
+        {
+            if(finishListener != null)
+                finishListener.actionPerformed(evt);
+            setVisible(false);
+        }
+
+        private FinishListener()
+        {
+        }
+
+    }
+
+    private class NextListener
+        implements ActionListener
+    {
+
+        public void actionPerformed(ActionEvent evt)
+        {
+            cardShowing++;
+            if(cardShowing > numCards)
+                cardShowing = numCards;
+            else
+                panesLayout.next(panesPanel);
+            if(nextListener != null)
+                nextListener.actionPerformed(evt);
+            enableBackNextButtons();
+        }
+
+        private NextListener()
+        {
+        }
+
+    }
+
+    private class BackListener
+        implements ActionListener
+    {
+
+        public void actionPerformed(ActionEvent evt)
+        {
+            cardShowing--;
+            if(cardShowing < 1)
+                cardShowing = 1;
+            else
+                panesLayout.previous(panesPanel);
+            if(backListener != null)
+                backListener.actionPerformed(evt);
+            enableBackNextButtons();
+        }
+
+        private BackListener()
+        {
+        }
+
+    }
+
+
+    public WizardDlg(JFrame frame, String title, Vector panels, Vector images)
+    {
+        super(frame, title, true);
+        this.title = title;
+        this.images = images;
+        Container pane = getContentPane();
+        pane.setLayout(new BorderLayout());
+        panesLayout = new CardLayout();
+        panesPanel = new JPanel(panesLayout);
+        pane.add(panesPanel, "Center");
+        pane.add(createButtonPanel(), "South");
+        setPanels(panels);
+        pack();
+        CommonUI.centerComponent(this);
+    }
+
+    public WizardDlg(JFrame frame, String title, Vector panels)
+    {
+        this(frame, title, panels, null);
+    }
+
+    public WizardDlg(String title, Vector panels)
+    {
+        this(new JFrame(), title, panels, null);
+    }
+
+    public void setPanels(Vector panels)
+    {
+        numCards = panels.size();
+        cardShowing = 1;
+        this.panels = panels;
+        panesPanel.removeAll();
+        for(int i = 0; i < numCards; i++)
+            panesPanel.add((JPanel)panels.elementAt(i), (new Integer(i)).toString());
+
+        validate();
+        enableBackNextButtons();
+    }
+
+    public void reset()
+    {
+        cardShowing = 1;
+        panesLayout.first(panesPanel);
+        enableBackNextButtons();
+    }
+
+    public void setWestPanel(JPanel panel)
+    {
+        Container pane = getContentPane();
+        pane.add(panel, "West");
+    }
+
+    public static void main(String args[])
+    {
+        JPanel p1 = new JPanel();
+        p1.add(new JButton("One"));
+        JPanel p2 = new JPanel();
+        p2.add(new JButton("Two"));
+        JPanel p3 = new JPanel();
+        p3.add(new JButton("Three"));
+        JPanel p4 = new JPanel();
+        p4.add(new JButton("Four"));
+        Vector panels = new Vector();
+        panels.addElement(p1);
+        panels.addElement(p2);
+        panels.addElement(p3);
+        panels.addElement(p4);
+        wizardDlg = new WizardDlg("Test Dialog", panels);
+        wizardDlg.addFinishListener(new ActionListener() {
+
+            public void actionPerformed(ActionEvent evt)
+            {
+                System.exit(0);
+            }
+
+        }
+);
+        wizardDlg.addCancelListener(new ActionListener() {
+
+            public void actionPerformed(ActionEvent evt)
+            {
+                System.exit(0);
+            }
+
+        }
+);
+        wizardDlg.setVisible(true);
+    }
+
+    private JPanel createButtonPanel()
+    {
+        JPanel panel = new JPanel();
+        backAction = new BackAction();
+        nextAction = new NextAction();
+        finishAction = new FinishAction();
+        cancelAction = new CancelAction();
+        backAction.setEnabled(false);
+        finishAction.setEnabled(false);
+        backAction.addActionListener(new BackListener());
+        nextAction.addActionListener(new NextListener());
+        finishAction.addActionListener(new FinishListener());
+        cancelAction.addActionListener(new CancelListener());
+        panel.add(CommonUI.createButton(backAction));
+        panel.add(CommonUI.createButton(nextAction));
+        panel.add(CommonUI.createButton(finishAction));
+        panel.add(CommonUI.createButton(cancelAction));
+        JPanel p2 = new JPanel(new BorderLayout());
+        p2.add(panel, "Center");
+        p2.add(new JSeparator(), "North");
+        return p2;
+    }
+
+    private void enableBackNextButtons()
+    {
+        if(cardShowing == 1)
+        {
+            backAction.setEnabled(false);
+            finishAction.setEnabled(false);
+            if(numCards > 1)
+            {
+                nextAction.setEnabled(true);
+            } else
+            {
+                finishAction.setEnabled(true);
+                nextAction.setEnabled(false);
+            }
+        } else
+        if(cardShowing == numCards)
+        {
+            nextAction.setEnabled(false);
+            finishAction.setEnabled(true);
+            if(numCards > 1)
+                backAction.setEnabled(true);
+            else
+                backAction.setEnabled(false);
+        } else
+        {
+            backAction.setEnabled(true);
+            nextAction.setEnabled(true);
+            finishAction.setEnabled(false);
+        }
+        setTitle();
+    }
+
+    private void setTitle()
+    {
+        JPanel panel = (JPanel)panels.elementAt(cardShowing - 1);
+        String newTitle = title;
+        String panelTitle = panel.getName();
+        if(panelTitle != null && panelTitle.equals(""))
+        {
+            newTitle = newTitle + " - ";
+            newTitle = newTitle + panelTitle;
+        }
+        super.setTitle(newTitle);
+    }
+
+    public synchronized void addFinishListener(ActionListener l)
+    {
+        finishListener = AWTEventMulticaster.add(finishListener, l);
+    }
+
+    public synchronized void removeFinishListener(ActionListener l)
+    {
+        finishListener = AWTEventMulticaster.remove(finishListener, l);
+    }
+
+    public synchronized void addCancelListener(ActionListener l)
+    {
+        cancelListener = AWTEventMulticaster.add(cancelListener, l);
+    }
+
+    public synchronized void removeCancelListener(ActionListener l)
+    {
+        cancelListener = AWTEventMulticaster.remove(cancelListener, l);
+    }
+
+    public synchronized void addNextListener(ActionListener l)
+    {
+        nextListener = AWTEventMulticaster.add(nextListener, l);
+    }
+
+    public synchronized void removeNextListener(ActionListener l)
+    {
+        nextListener = AWTEventMulticaster.remove(nextListener, l);
+    }
+
+    public synchronized void addBackListener(ActionListener l)
+    {
+        backListener = AWTEventMulticaster.add(backListener, l);
+    }
+
+    public synchronized void removeBackListener(ActionListener l)
+    {
+        backListener = AWTEventMulticaster.remove(backListener, l);
+    }
+
+    private CardLayout panesLayout;
+    private JPanel panesPanel;
+    private DelegateAction backAction;
+    private DelegateAction nextAction;
+    private DelegateAction finishAction;
+    private DelegateAction cancelAction;
+    private ActionListener finishListener;
+    private ActionListener cancelListener;
+    private ActionListener nextListener;
+    private ActionListener backListener;
+    private int numCards;
+    private int cardShowing;
+    private String title;
+    private Vector panels;
+    private Vector images;
+    private static WizardDlg wizardDlg;
+
+
+
+
+}
Binary file hotspot/agent/src/share/classes/images/toolbarButtonGraphics/development/Server16.gif has changed
Binary file hotspot/agent/src/share/classes/images/toolbarButtonGraphics/development/Server24.gif has changed
Binary file hotspot/agent/src/share/classes/images/toolbarButtonGraphics/general/About16.gif has changed
Binary file hotspot/agent/src/share/classes/images/toolbarButtonGraphics/general/About24.gif has changed
Binary file hotspot/agent/src/share/classes/images/toolbarButtonGraphics/general/Delete16.gif has changed
Binary file hotspot/agent/src/share/classes/images/toolbarButtonGraphics/general/Delete24.gif has changed
Binary file hotspot/agent/src/share/classes/images/toolbarButtonGraphics/general/Find16.gif has changed
Binary file hotspot/agent/src/share/classes/images/toolbarButtonGraphics/general/Help16.gif has changed
Binary file hotspot/agent/src/share/classes/images/toolbarButtonGraphics/general/Help24.gif has changed
Binary file hotspot/agent/src/share/classes/images/toolbarButtonGraphics/general/History16.gif has changed
Binary file hotspot/agent/src/share/classes/images/toolbarButtonGraphics/general/History24.gif has changed
Binary file hotspot/agent/src/share/classes/images/toolbarButtonGraphics/general/Information16.gif has changed
Binary file hotspot/agent/src/share/classes/images/toolbarButtonGraphics/general/Information24.gif has changed
Binary file hotspot/agent/src/share/classes/images/toolbarButtonGraphics/general/New16.gif has changed
Binary file hotspot/agent/src/share/classes/images/toolbarButtonGraphics/general/New24.gif has changed
Binary file hotspot/agent/src/share/classes/images/toolbarButtonGraphics/general/Open16.gif has changed
Binary file hotspot/agent/src/share/classes/images/toolbarButtonGraphics/general/Open24.gif has changed
Binary file hotspot/agent/src/share/classes/images/toolbarButtonGraphics/general/Save16.gif has changed
Binary file hotspot/agent/src/share/classes/images/toolbarButtonGraphics/general/Save24.gif has changed
Binary file hotspot/agent/src/share/classes/images/toolbarButtonGraphics/general/SaveAs16.gif has changed
Binary file hotspot/agent/src/share/classes/images/toolbarButtonGraphics/general/SaveAs24.gif has changed
Binary file hotspot/agent/src/share/classes/images/toolbarButtonGraphics/general/Zoom16.gif has changed
Binary file hotspot/agent/src/share/classes/images/toolbarButtonGraphics/general/ZoomIn16.gif has changed
Binary file hotspot/agent/src/share/classes/images/toolbarButtonGraphics/general/ZoomIn24.gif has changed
Binary file hotspot/agent/src/share/classes/images/toolbarButtonGraphics/navigation/Down16.gif has changed
Binary file hotspot/agent/src/share/classes/images/toolbarButtonGraphics/navigation/Up16.gif has changed
Binary file hotspot/agent/src/share/classes/images/toolbarButtonGraphics/text/AlignCenter16.gif has changed
Binary file hotspot/agent/src/share/classes/images/toolbarButtonGraphics/text/AlignCenter24.gif has changed
Binary file hotspot/agent/src/share/classes/images/toolbarButtonGraphics/text/AlignLeft16.gif has changed
Binary file hotspot/agent/src/share/classes/images/toolbarButtonGraphics/text/AlignLeft24.gif has changed
Binary file hotspot/agent/src/share/classes/images/toolbarButtonGraphics/text/AlignRight16.gif has changed
Binary file hotspot/agent/src/share/classes/images/toolbarButtonGraphics/text/AlignRight24.gif has changed
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/HeapSummary.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/HeapSummary.java	Wed Jul 05 16:40:29 2017 +0200
@@ -193,8 +193,12 @@
 
    private static final double FACTOR = 1024*1024;
    private void printValMB(String title, long value) {
-      double mb = value / FACTOR;
-      System.out.println(alignment + title + value + " (" + mb + "MB)");
+      if (value < 0) {
+        System.out.println(alignment + title +   (value >>> 20)  + " MB");
+      } else {
+        double mb = value/FACTOR;
+        System.out.println(alignment + title + value + " (" + mb + "MB)");
+      }
    }
 
    private void printValue(String title, long value) {
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/PermStat.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/PermStat.java	Wed Jul 05 16:40:29 2017 +0200
@@ -266,45 +266,51 @@
       out.println();
    }
 
+   private static long objectSize(Oop oop) {
+      return oop == null ? 0L : oop.getObjectSize();
+   }
+
+   // Don't count the shared empty arrays
+   private static long arraySize(Array arr) {
+     return arr.getLength() != 0L ? arr.getObjectSize() : 0L;
+   }
+
    private long computeSize(InstanceKlass k) {
       long size = 0L;
-      // InstanceKlass object size
+      // the InstanceKlass object itself
       size += k.getObjectSize();
 
-      // add ConstantPool size
-      size += k.getConstants().getObjectSize();
+      // Constant pool
+      ConstantPool cp = k.getConstants();
+      size += cp.getObjectSize();
+      size += objectSize(cp.getCache());
+      size += objectSize(cp.getTags());
+
+      // Interfaces
+      size += arraySize(k.getLocalInterfaces());
+      size += arraySize(k.getTransitiveInterfaces());
+
+      // Inner classes
+      size += objectSize(k.getInnerClasses());
 
-      // add ConstantPoolCache, if any
-      ConstantPoolCache cpCache = k.getConstants().getCache();
-      if (cpCache != null) {
-         size += cpCache.getObjectSize();
+      // Fields
+      size += objectSize(k.getFields());
+
+      // Methods
+      ObjArray methods = k.getMethods();
+      int nmethods = (int) methods.getLength();
+      if (nmethods != 0L) {
+         size += methods.getObjectSize();
+         for (int i = 0; i < nmethods; ++i) {
+            Method m = (Method) methods.getObjAt(i);
+            size += m.getObjectSize();
+            size += objectSize(m.getConstMethod());
+         }
       }
 
-      // add interfaces size
-      ObjArray interfaces = k.getLocalInterfaces();
-      size +=  (interfaces.getLength() != 0L)? interfaces.getObjectSize() : 0L;
-      ObjArray transitiveInterfaces = k.getTransitiveInterfaces();
-      size += (transitiveInterfaces.getLength() != 0L)? transitiveInterfaces.getObjectSize() : 0L;
-
-      // add inner classes size
-      TypeArray innerClasses = k.getInnerClasses();
-      size += innerClasses.getObjectSize();
-
-      // add fields size
-      size += k.getFields().getObjectSize();
-
-      // add methods size
-      ObjArray methods = k.getMethods();
-      size += (methods.getLength() != 0L)? methods.getObjectSize() : 0L;
-      TypeArray methodOrdering = k.getMethodOrdering();
-      size += (methodOrdering.getLength() != 0L)? methodOrdering.getObjectSize() : 0;
-
-      // add each method's size
-      int numMethods = (int) methods.getLength();
-      for (int i = 0; i < numMethods; i++) {
-         Method m = (Method) methods.getObjAt(i);
-         size += m.getObjectSize();
-      }
+      // MethodOrdering - an int array that records the original
+      // ordering of methods in the class file
+      size += arraySize(k.getMethodOrdering());
 
       return size;
    }
Binary file hotspot/agent/src/share/lib/jlfgr-1_0.jar has changed
Binary file hotspot/agent/src/share/lib/maf-1_0.jar has changed
--- a/hotspot/make/hotspot_distro	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/make/hotspot_distro	Wed Jul 05 16:40:29 2017 +0200
@@ -1,6 +1,24 @@
-# 
-# Copyright 2006-2008 Sun Microsystems, Inc.  All rights reserved.
-# SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
+#
+# Copyright 2006-2008 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+# CA 95054 USA or visit www.sun.com if you need additional information or
+# have any questions.
 #
 
 #
--- a/hotspot/make/hotspot_version	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/make/hotspot_version	Wed Jul 05 16:40:29 2017 +0200
@@ -35,7 +35,7 @@
 
 HS_MAJOR_VER=14
 HS_MINOR_VER=0
-HS_BUILD_NUMBER=01
+HS_BUILD_NUMBER=03
 
 JDK_MAJOR_VER=1
 JDK_MINOR_VER=7
--- a/hotspot/make/jprt.config	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/make/jprt.config	Wed Jul 05 16:40:29 2017 +0200
@@ -77,9 +77,7 @@
             # All jdk6 builds use SS11
             compiler_name=SS11
         else
-            # FIXUP: Change to SS12 once it has been validated.
-	    #compiler_name=SS12
-            compiler_name=SS11
+	    compiler_name=SS12
         fi
     fi
     
--- a/hotspot/make/linux/makefiles/vm.make	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/make/linux/makefiles/vm.make	Wed Jul 05 16:40:29 2017 +0200
@@ -195,7 +195,7 @@
               if [ $$? = 0 ] ; then					\
 		/usr/bin/chcon -t textrel_shlib_t $@;                   \
 		if [ $$? != 0 ]; then                                   \
-		  echo "ERROR: Cannot chcon $@"; exit 1;                \
+		  echo "ERROR: Cannot chcon $@";			\
 		fi							\
 	      fi							\
 	    fi                                                          \
--- a/hotspot/make/solaris/makefiles/fastdebug.make	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/make/solaris/makefiles/fastdebug.make	Wed Jul 05 16:40:29 2017 +0200
@@ -38,6 +38,8 @@
 
 # Problem with SS12 compiler, dtrace doesn't like the .o files  (bug 6693876)
 ifeq ($(COMPILER_REV), 5.9)
+  # To avoid jvm98 crash
+  OPT_CFLAGS/instanceKlass.o = $(OPT_CFLAGS/SLOWER)
   # Not clear this workaround could be skipped in some cases.
   OPT_CFLAGS/vmGCOperations.o = $(OPT_CFLAGS/SLOWER)
   OPT_CFLAGS/java.o = $(OPT_CFLAGS/SLOWER)
--- a/hotspot/make/solaris/makefiles/sparcWorks.make	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/make/solaris/makefiles/sparcWorks.make	Wed Jul 05 16:40:29 2017 +0200
@@ -51,12 +51,9 @@
   VALIDATED_COMPILER_REV   := 5.8
   VALIDATED_C_COMPILER_REV := 5.8
 else
-  # FIXUP: Change to SS12 (5.9) once it has been validated.
   # Validated compiler for JDK7 is SS12 (5.9)
-  #VALIDATED_COMPILER_REV   := 5.9
-  #VALIDATED_C_COMPILER_REV := 5.9
-  VALIDATED_COMPILER_REV   := 5.8
-  VALIDATED_C_COMPILER_REV := 5.8
+  VALIDATED_COMPILER_REV   := 5.9
+  VALIDATED_C_COMPILER_REV := 5.9
 endif
 
 # Warning messages about not using the above validated version
--- a/hotspot/make/windows/makefiles/defs.make	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/make/windows/makefiles/defs.make	Wed Jul 05 16:40:29 2017 +0200
@@ -107,7 +107,7 @@
   ABS_OUTPUTDIR   := $(subst /,\\,$(shell /bin/cygpath -m -a "$(OUTPUTDIR)"))
   ABS_BOOTDIR     := $(subst /,\\,$(shell /bin/cygpath -m -a "$(BOOTDIR)"))
   ABS_GAMMADIR    := $(subst /,\\,$(shell /bin/cygpath -m -a "$(GAMMADIR)"))
-  ABS_OS_MAKEFILE := $(shell /bin/cygpath -m -a "$(HS_BUILD_DIR)/$(OSNAME)")/build.make
+  ABS_OS_MAKEFILE := $(shell /bin/cygpath -m -a "$(HS_MAKE_DIR)/$(OSNAME)")/build.make
 else
   ABS_OUTPUTDIR   := $(subst /,\\,$(shell $(CD) $(OUTPUTDIR);$(PWD)))
   ABS_BOOTDIR     := $(subst /,\\,$(shell $(CD) $(BOOTDIR);$(PWD)))
--- a/hotspot/src/cpu/x86/vm/stubGenerator_x86_32.cpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/cpu/x86/vm/stubGenerator_x86_32.cpp	Wed Jul 05 16:40:29 2017 +0200
@@ -779,9 +779,9 @@
           __ shrl(end,   CardTableModRefBS::card_shift);
           __ subl(end, start); // end --> count
         __ BIND(L_loop);
-          ExternalAddress base((address)ct->byte_map_base);
-          Address index(start, count, Address::times_1, 0);
-          __ movbyte(ArrayAddress(base, index), 0);
+          intptr_t disp = (intptr_t) ct->byte_map_base;
+          Address cardtable(start, count, Address::times_1, disp);
+          __ movb(cardtable, 0);
           __ decrement(count);
           __ jcc(Assembler::greaterEqual, L_loop);
         }
--- a/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp	Wed Jul 05 16:40:29 2017 +0200
@@ -1222,8 +1222,16 @@
            __ shrq(end, CardTableModRefBS::card_shift);
            __ subq(end, start); // number of bytes to copy
 
+          intptr_t disp = (intptr_t) ct->byte_map_base;
+          if (__ is_simm32(disp)) {
+            Address cardtable(noreg, noreg, Address::no_scale, disp);
+            __ lea(scratch, cardtable);
+          } else {
+            ExternalAddress cardtable((address)disp);
+            __ lea(scratch, cardtable);
+          }
+
           const Register count = end; // 'end' register contains bytes count now
-          __ lea(scratch, ExternalAddress((address)ct->byte_map_base));
           __ addq(start, scratch);
         __ BIND(L_loop);
           __ movb(Address(start, count, Address::times_1), 0);
--- a/hotspot/src/os/linux/vm/os_linux.cpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/os/linux/vm/os_linux.cpp	Wed Jul 05 16:40:29 2017 +0200
@@ -94,6 +94,9 @@
 static int SR_signum = SIGUSR2;
 sigset_t SR_sigset;
 
+/* Used to protect dlsym() calls */
+static pthread_mutex_t dl_mutex;
+
 ////////////////////////////////////////////////////////////////////////////////
 // utility functions
 
@@ -1493,6 +1496,24 @@
 
 const char* os::get_temp_directory() { return "/tmp/"; }
 
+void os::dll_build_name(
+    char* buffer, size_t buflen, const char* pname, const char* fname) {
+  // copied from libhpi
+  const size_t pnamelen = pname ? strlen(pname) : 0;
+
+  /* Quietly truncate on buffer overflow.  Should be an error. */
+  if (pnamelen + strlen(fname) + 10 > (size_t) buflen) {
+      *buffer = '\0';
+      return;
+  }
+
+  if (pnamelen == 0) {
+      sprintf(buffer, "lib%s.so", fname);
+  } else {
+      sprintf(buffer, "%s/lib%s.so", pname, fname);
+  }
+}
+
 const char* os::get_current_directory(char *buf, int buflen) {
   return getcwd(buf, buflen);
 }
@@ -1742,7 +1763,17 @@
   return NULL;
 }
 
-
+/*
+ * glibc-2.0 libdl is not MT safe.  If you are building with any glibc,
+ * chances are you might want to run the generated bits against glibc-2.0
+ * libdl.so, so always use locking for any version of glibc.
+ */
+void* os::dll_lookup(void* handle, const char* name) {
+  pthread_mutex_lock(&dl_mutex);
+  void* res = dlsym(handle, name);
+  pthread_mutex_unlock(&dl_mutex);
+  return res;
+}
 
 
 bool _print_ascii_file(const char* filename, outputStream* st) {
@@ -2278,7 +2309,7 @@
                                   dlsym(RTLD_DEFAULT, "sched_getcpu")));
 
   if (sched_getcpu() != -1) { // Does it work?
-    void *handle = dlopen("libnuma.so", RTLD_LAZY);
+    void *handle = dlopen("libnuma.so.1", RTLD_LAZY);
     if (handle != NULL) {
       set_numa_node_to_cpus(CAST_TO_FN_PTR(numa_node_to_cpus_func_t,
                                            dlsym(handle, "numa_node_to_cpus")));
@@ -3581,6 +3612,7 @@
 
   Linux::clock_init();
   initial_time_count = os::elapsed_counter();
+  pthread_mutex_init(&dl_mutex, NULL);
 }
 
 // To install functions for atexit system call
--- a/hotspot/src/os/solaris/vm/osThread_solaris.cpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/os/solaris/vm/osThread_solaris.cpp	Wed Jul 05 16:40:29 2017 +0200
@@ -69,15 +69,15 @@
 static intptr_t compare_and_exchange_current_callback (
        intptr_t callback, intptr_t *addr, intptr_t compare_value, Mutex *sync) {
   if (VM_Version::supports_compare_and_exchange()) {
-     return Atomic::cmpxchg_ptr(callback, addr, compare_value);
+    return Atomic::cmpxchg_ptr(callback, addr, compare_value);
   } else {
-     MutexLockerEx(sync, Mutex::_no_safepoint_check_flag);
-     if (*addr == compare_value) {
-       *addr = callback;
-       return compare_value;
-     } else {
-       return callback;
-     }
+    MutexLockerEx ml(sync, Mutex::_no_safepoint_check_flag);
+    if (*addr == compare_value) {
+      *addr = callback;
+      return compare_value;
+    } else {
+      return callback;
+    }
   }
 }
 
@@ -86,7 +86,7 @@
   if (VM_Version::supports_compare_and_exchange()) {
     return Atomic::xchg_ptr(callback, addr);
   } else {
-    MutexLockerEx(sync, Mutex::_no_safepoint_check_flag);
+    MutexLockerEx ml(sync, Mutex::_no_safepoint_check_flag);
     intptr_t cb = *addr;
     *addr = callback;
     return cb;
--- a/hotspot/src/os/solaris/vm/os_solaris.cpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/os/solaris/vm/os_solaris.cpp	Wed Jul 05 16:40:29 2017 +0200
@@ -1783,6 +1783,24 @@
 
 const char* os::get_temp_directory() { return "/tmp/"; }
 
+void os::dll_build_name(
+    char* buffer, size_t buflen, const char* pname, const char* fname) {
+  // copied from libhpi
+  const size_t pnamelen = pname ? strlen(pname) : 0;
+
+  /* Quietly truncate on buffer overflow.  Should be an error. */
+  if (pnamelen + strlen(fname) + 10 > (size_t) buflen) {
+      *buffer = '\0';
+      return;
+  }
+
+  if (pnamelen == 0) {
+      sprintf(buffer, "lib%s.so", fname);
+  } else {
+      sprintf(buffer, "%s/lib%s.so", pname, fname);
+  }
+}
+
 const char* os::get_current_directory(char *buf, int buflen) {
   return getcwd(buf, buflen);
 }
@@ -2034,6 +2052,9 @@
   return NULL;
 }
 
+void* os::dll_lookup(void* handle, const char* name) {
+  return dlsym(handle, name);
+}
 
 
 bool _print_ascii_file(const char* filename, outputStream* st) {
@@ -2658,6 +2679,12 @@
      top += r;
      cur++;
    }
+   if (bottom == 0) {
+     // Handle a situation, when the OS reports no memory available.
+     // Assume UMA architecture.
+     ids[0] = 0;
+     return 1;
+   }
    return bottom;
 }
 
@@ -4581,7 +4608,7 @@
 }
 
 void os::Solaris::liblgrp_init() {
-  void *handle = dlopen("liblgrp.so", RTLD_LAZY);
+  void *handle = dlopen("liblgrp.so.1", RTLD_LAZY);
   if (handle != NULL) {
     os::Solaris::set_lgrp_home(CAST_TO_FN_PTR(lgrp_home_func_t, dlsym(handle, "lgrp_home")));
     os::Solaris::set_lgrp_init(CAST_TO_FN_PTR(lgrp_init_func_t, dlsym(handle, "lgrp_init")));
--- a/hotspot/src/os/windows/vm/os_windows.cpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/os/windows/vm/os_windows.cpp	Wed Jul 05 16:40:29 2017 +0200
@@ -985,6 +985,28 @@
     }
 }
 
+void os::dll_build_name(char *holder, size_t holderlen,
+                        const char* pname, const char* fname)
+{
+    // copied from libhpi
+    const size_t pnamelen = pname ? strlen(pname) : 0;
+    const char c = (pnamelen > 0) ? pname[pnamelen-1] : 0;
+
+    /* Quietly truncates on buffer overflow. Should be an error. */
+    if (pnamelen + strlen(fname) + 10 > holderlen) {
+        *holder = '\0';
+        return;
+    }
+
+    if (pnamelen == 0) {
+        sprintf(holder, "%s.dll", fname);
+    } else if (c == ':' || c == '\\') {
+        sprintf(holder, "%s%s.dll", pname, fname);
+    } else {
+        sprintf(holder, "%s\\%s.dll", pname, fname);
+    }
+}
+
 // Needs to be in os specific directory because windows requires another
 // header file <direct.h>
 const char* os::get_current_directory(char *buf, int buflen) {
@@ -1248,6 +1270,10 @@
   return false;
 }
 
+void* os::dll_lookup(void* handle, const char* name) {
+  return GetProcAddress((HMODULE)handle, name);
+}
+
 // save the start and end address of jvm.dll into param[0] and param[1]
 static int _locate_jvm_dll(int pid, char* mod_fname, address base_addr,
                     unsigned size, void * param) {
@@ -1421,44 +1447,78 @@
    enumerate_modules(pid, _print_module, (void *)st);
 }
 
+// function pointer to Windows API "GetNativeSystemInfo".
+typedef void (WINAPI *GetNativeSystemInfo_func_type)(LPSYSTEM_INFO);
+static GetNativeSystemInfo_func_type _GetNativeSystemInfo;
+
 void os::print_os_info(outputStream* st) {
-   st->print("OS:");
-
-   OSVERSIONINFOEX osvi;
-   ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
-   osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
-
-   if (!GetVersionEx((OSVERSIONINFO *)&osvi)) {
-      st->print_cr("N/A");
-      return;
-   }
-
-   int os_vers = osvi.dwMajorVersion * 1000 + osvi.dwMinorVersion;
-
-   if (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
-     switch (os_vers) {
-       case 3051: st->print(" Windows NT 3.51"); break;
-       case 4000: st->print(" Windows NT 4.0"); break;
-       case 5000: st->print(" Windows 2000"); break;
-       case 5001: st->print(" Windows XP"); break;
-       case 5002: st->print(" Windows Server 2003 family"); break;
-       case 6000: st->print(" Windows Vista"); break;
-       default: // future windows, print out its major and minor versions
-                st->print(" Windows NT %d.%d", osvi.dwMajorVersion, osvi.dwMinorVersion);
-     }
-   } else {
-     switch (os_vers) {
-       case 4000: st->print(" Windows 95"); break;
-       case 4010: st->print(" Windows 98"); break;
-       case 4090: st->print(" Windows Me"); break;
-       default: // future windows, print out its major and minor versions
-                st->print(" Windows %d.%d", osvi.dwMajorVersion, osvi.dwMinorVersion);
-     }
-   }
-
-   st->print(" Build %d", osvi.dwBuildNumber);
-   st->print(" %s", osvi.szCSDVersion);           // service pack
-   st->cr();
+  st->print("OS:");
+
+  OSVERSIONINFOEX osvi;
+  ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
+  osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
+
+  if (!GetVersionEx((OSVERSIONINFO *)&osvi)) {
+    st->print_cr("N/A");
+    return;
+  }
+
+  int os_vers = osvi.dwMajorVersion * 1000 + osvi.dwMinorVersion;
+  if (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
+    switch (os_vers) {
+    case 3051: st->print(" Windows NT 3.51"); break;
+    case 4000: st->print(" Windows NT 4.0"); break;
+    case 5000: st->print(" Windows 2000"); break;
+    case 5001: st->print(" Windows XP"); break;
+    case 5002:
+    case 6000: {
+      // Retrieve SYSTEM_INFO from GetNativeSystemInfo call so that we could
+      // find out whether we are running on 64 bit processor or not.
+      SYSTEM_INFO si;
+      ZeroMemory(&si, sizeof(SYSTEM_INFO));
+      // Check to see if _GetNativeSystemInfo has been initialized.
+      if (_GetNativeSystemInfo == NULL) {
+        HMODULE hKernel32 = GetModuleHandle(TEXT("kernel32.dll"));
+        _GetNativeSystemInfo =
+            CAST_TO_FN_PTR(GetNativeSystemInfo_func_type,
+                           GetProcAddress(hKernel32,
+                                          "GetNativeSystemInfo"));
+        if (_GetNativeSystemInfo == NULL)
+          GetSystemInfo(&si);
+      } else {
+        _GetNativeSystemInfo(&si);
+      }
+      if (os_vers == 5002) {
+        if (osvi.wProductType == VER_NT_WORKSTATION &&
+            si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64)
+          st->print(" Windows XP x64 Edition");
+        else
+            st->print(" Windows Server 2003 family");
+      } else { // os_vers == 6000
+        if (osvi.wProductType == VER_NT_WORKSTATION)
+            st->print(" Windows Vista");
+        else
+            st->print(" Windows Server 2008");
+        if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64)
+            st->print(" , 64 bit");
+      }
+      break;
+    }
+    default: // future windows, print out its major and minor versions
+      st->print(" Windows NT %d.%d", osvi.dwMajorVersion, osvi.dwMinorVersion);
+    }
+  } else {
+    switch (os_vers) {
+    case 4000: st->print(" Windows 95"); break;
+    case 4010: st->print(" Windows 98"); break;
+    case 4090: st->print(" Windows Me"); break;
+    default: // future windows, print out its major and minor versions
+      st->print(" Windows %d.%d", osvi.dwMajorVersion, osvi.dwMinorVersion);
+    }
+  }
+  st->print(" Build %d", osvi.dwBuildNumber);
+  st->print(" %s", osvi.szCSDVersion);           // service pack
+  st->cr();
 }
 
 void os::print_memory_info(outputStream* st) {
--- a/hotspot/src/share/vm/adlc/formssel.cpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/adlc/formssel.cpp	Wed Jul 05 16:40:29 2017 +0200
@@ -3825,6 +3825,8 @@
         strcmp(opType,"ConvL2D")==0 ||
         strcmp(opType,"ConvL2F")==0 ||
         strcmp(opType,"ConvL2I")==0 ||
+        strcmp(opType,"DecodeN")==0 ||
+        strcmp(opType,"EncodeP")==0 ||
         strcmp(opType,"RoundDouble")==0 ||
         strcmp(opType,"RoundFloat")==0 ||
         strcmp(opType,"ReverseBytesI")==0 ||
--- a/hotspot/src/share/vm/ci/ciMethodBlocks.cpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/ci/ciMethodBlocks.cpp	Wed Jul 05 16:40:29 2017 +0200
@@ -351,7 +351,7 @@
 }
 
 #ifndef PRODUCT
-static char *flagnames[] = {
+static const char *flagnames[] = {
   "Processed",
   "Handler",
   "MayThrow",
--- a/hotspot/src/share/vm/classfile/javaClasses.cpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/classfile/javaClasses.cpp	Wed Jul 05 16:40:29 2017 +0200
@@ -649,8 +649,8 @@
 }
 
 oop java_lang_Thread::park_blocker(oop java_thread) {
-  assert(JDK_Version::supports_thread_park_blocker() && _park_blocker_offset != 0,
-         "Must support parkBlocker field");
+  assert(JDK_Version::current().supports_thread_park_blocker() &&
+         _park_blocker_offset != 0, "Must support parkBlocker field");
 
   if (_park_blocker_offset > 0) {
     return java_thread->obj_field(_park_blocker_offset);
--- a/hotspot/src/share/vm/compiler/oopMap.cpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/compiler/oopMap.cpp	Wed Jul 05 16:40:29 2017 +0200
@@ -188,10 +188,6 @@
   }
 }
 
-void OopMap::set_stack_obj(VMReg reg) {
-  set_xxx(reg, OopMapValue::stack_obj, VMRegImpl::Bad());
-}
-
 // OopMapSet
 
 OopMapSet::OopMapSet() {
@@ -399,8 +395,7 @@
       if ( loc != NULL ) {
         if ( omv.type() == OopMapValue::oop_value ) {
 #ifdef ASSERT
-          if (COMPILER2_PRESENT(!DoEscapeAnalysis &&)
-             (((uintptr_t)loc & (sizeof(*loc)-1)) != 0) ||
+          if ((((uintptr_t)loc & (sizeof(*loc)-1)) != 0) ||
              !Universe::heap()->is_in_or_null(*loc)) {
             tty->print_cr("# Found non oop pointer.  Dumping state at failure");
             // try to dump out some helpful debugging information
@@ -431,17 +426,6 @@
       }
     }
   }
-
-#ifdef COMPILER2
-  if (DoEscapeAnalysis) {
-    for (OopMapStream oms(map, OopMapValue::stack_obj); !oms.is_done(); oms.next()) {
-      omv = oms.current();
-      assert(omv.is_stack_loc(), "should refer to stack location");
-      oop loc = (oop) fr->oopmapreg_to_location(omv.reg(),reg_map);
-      oop_fn->do_oop(&loc);
-    }
-  }
-#endif // COMPILER2
 }
 
 
@@ -540,9 +524,6 @@
     st->print("Derived_oop_" );
     optional->print_on(st);
     break;
-  case OopMapValue::stack_obj:
-    st->print("Stack");
-    break;
   default:
     ShouldNotReachHere();
   }
--- a/hotspot/src/share/vm/compiler/oopMap.hpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/compiler/oopMap.hpp	Wed Jul 05 16:40:29 2017 +0200
@@ -46,7 +46,7 @@
 
 public:
   // Constants
-  enum { type_bits                = 6,
+  enum { type_bits                = 5,
          register_bits            = BitsPerShort - type_bits };
 
   enum { type_shift               = 0,
@@ -63,8 +63,7 @@
          value_value = 2,
          narrowoop_value = 4,
          callee_saved_value = 8,
-         derived_oop_value= 16,
-         stack_obj = 32 };
+         derived_oop_value= 16 };
 
   // Constructors
   OopMapValue () { set_value(0); set_content_reg(VMRegImpl::Bad()); }
@@ -93,14 +92,12 @@
   bool is_narrowoop()           { return mask_bits(value(), type_mask_in_place) == narrowoop_value; }
   bool is_callee_saved()      { return mask_bits(value(), type_mask_in_place) == callee_saved_value; }
   bool is_derived_oop()       { return mask_bits(value(), type_mask_in_place) == derived_oop_value; }
-  bool is_stack_obj()         { return mask_bits(value(), type_mask_in_place) == stack_obj; }
 
   void set_oop()              { set_value((value() & register_mask_in_place) | oop_value); }
   void set_value()            { set_value((value() & register_mask_in_place) | value_value); }
   void set_narrowoop()          { set_value((value() & register_mask_in_place) | narrowoop_value); }
   void set_callee_saved()     { set_value((value() & register_mask_in_place) | callee_saved_value); }
   void set_derived_oop()      { set_value((value() & register_mask_in_place) | derived_oop_value); }
-  void set_stack_obj()        { set_value((value() & register_mask_in_place) | stack_obj); }
 
   VMReg reg() const { return VMRegImpl::as_VMReg(mask_bits(value(), register_mask_in_place) >> register_shift); }
   oop_types type() const      { return (oop_types)mask_bits(value(), type_mask_in_place); }
@@ -180,7 +177,6 @@
   void set_dead ( VMReg local);
   void set_callee_saved( VMReg local, VMReg caller_machine_register );
   void set_derived_oop ( VMReg local, VMReg derived_from_local_register );
-  void set_stack_obj( VMReg local);
   void set_xxx(VMReg reg, OopMapValue::oop_types x, VMReg optional);
 
   int heap_size() const;
--- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/binaryTreeDictionary.cpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/binaryTreeDictionary.cpp	Wed Jul 05 16:40:29 2017 +0200
@@ -71,8 +71,15 @@
 TreeList* TreeList::as_TreeList(HeapWord* addr, size_t size) {
   TreeChunk* tc = (TreeChunk*) addr;
   assert(size >= sizeof(TreeChunk), "Chunk is too small for a TreeChunk");
-  assert(tc->size() == 0 && tc->prev() == NULL && tc->next() == NULL,
-    "Space should be clear");
+  // The space in the heap will have been mangled initially but
+  // is not remangled when a free chunk is returned to the free list
+  // (since it is used to maintain the chunk on the free list).
+  assert((ZapUnusedHeapArea &&
+          SpaceMangler::is_mangled((HeapWord*) tc->size_addr()) &&
+          SpaceMangler::is_mangled((HeapWord*) tc->prev_addr()) &&
+          SpaceMangler::is_mangled((HeapWord*) tc->next_addr())) ||
+          (tc->size() == 0 && tc->prev() == NULL && tc->next() == NULL),
+    "Space should be clear or mangled");
   tc->setSize(size);
   tc->linkPrev(NULL);
   tc->linkNext(NULL);
--- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp	Wed Jul 05 16:40:29 2017 +0200
@@ -54,7 +54,7 @@
   _collector(NULL)
 {
   _bt.set_space(this);
-  initialize(mr, true);
+  initialize(mr, SpaceDecorator::Clear, SpaceDecorator::Mangle);
   // We have all of "mr", all of which we place in the dictionary
   // as one big chunk. We'll need to decide here which of several
   // possible alternative dictionary implementations to use. For
--- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp	Wed Jul 05 16:40:29 2017 +0200
@@ -3195,31 +3195,16 @@
 // YSR: All of this generation expansion/shrinking stuff is an exact copy of
 // OneContigSpaceCardGeneration, which makes me wonder if we should move this
 // to CardGeneration and share it...
+bool ConcurrentMarkSweepGeneration::expand(size_t bytes, size_t expand_bytes) {
+  return CardGeneration::expand(bytes, expand_bytes);
+}
+
 void ConcurrentMarkSweepGeneration::expand(size_t bytes, size_t expand_bytes,
   CMSExpansionCause::Cause cause)
 {
-  assert_locked_or_safepoint(Heap_lock);
-
-  size_t aligned_bytes  = ReservedSpace::page_align_size_up(bytes);
-  size_t aligned_expand_bytes = ReservedSpace::page_align_size_up(expand_bytes);
-  bool success = false;
-  if (aligned_expand_bytes > aligned_bytes) {
-    success = grow_by(aligned_expand_bytes);
-  }
-  if (!success) {
-    success = grow_by(aligned_bytes);
-  }
-  if (!success) {
-    size_t remaining_bytes = _virtual_space.uncommitted_size();
-    if (remaining_bytes > 0) {
-      success = grow_by(remaining_bytes);
-    }
-  }
-  if (GC_locker::is_active()) {
-    if (PrintGC && Verbose) {
-      gclog_or_tty->print_cr("Garbage collection disabled, expanded heap instead");
-    }
-  }
+
+  bool success = expand(bytes, expand_bytes);
+
   // remember why we expanded; this information is used
   // by shouldConcurrentCollect() when making decisions on whether to start
   // a new CMS cycle.
@@ -6882,11 +6867,9 @@
         // during the preclean or remark phase. (CMSCleanOnEnter)
         if (CMSCleanOnEnter) {
           size_t sz = _collector->block_size_using_printezis_bits(addr);
-          HeapWord* start_card_addr = (HeapWord*)round_down(
-                                         (intptr_t)addr, CardTableModRefBS::card_size);
           HeapWord* end_card_addr   = (HeapWord*)round_to(
                                          (intptr_t)(addr+sz), CardTableModRefBS::card_size);
-          MemRegion redirty_range = MemRegion(start_card_addr, end_card_addr);
+          MemRegion redirty_range = MemRegion(addr, end_card_addr);
           assert(!redirty_range.is_empty(), "Arithmetical tautology");
           // Bump _threshold to end_card_addr; note that
           // _threshold cannot possibly exceed end_card_addr, anyhow.
@@ -7475,12 +7458,25 @@
     )
     if (simulate_overflow || !_mark_stack->push(obj)) {
       if (_concurrent_precleaning) {
-         // During precleaning we can just dirty the appropriate card
+         // During precleaning we can just dirty the appropriate card(s)
          // in the mod union table, thus ensuring that the object remains
-         // in the grey set  and continue. Note that no one can be intefering
-         // with us in this action of dirtying the mod union table, so
-         // no locking is required.
-         _mod_union_table->mark(addr);
+         // in the grey set  and continue. In the case of object arrays
+         // we need to dirty all of the cards that the object spans,
+         // since the rescan of object arrays will be limited to the
+         // dirty cards.
+         // Note that no one can be intefering with us in this action
+         // of dirtying the mod union table, so no locking or atomics
+         // are required.
+         if (obj->is_objArray()) {
+           size_t sz = obj->size();
+           HeapWord* end_card_addr = (HeapWord*)round_to(
+                                        (intptr_t)(addr+sz), CardTableModRefBS::card_size);
+           MemRegion redirty_range = MemRegion(addr, end_card_addr);
+           assert(!redirty_range.is_empty(), "Arithmetical tautology");
+           _mod_union_table->mark_range(redirty_range);
+         } else {
+           _mod_union_table->mark(addr);
+         }
          _collector->_ser_pmc_preclean_ovflw++;
       } else {
          // During the remark phase, we need to remember this oop
--- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp	Wed Jul 05 16:40:29 2017 +0200
@@ -1048,10 +1048,6 @@
   double _initiating_occupancy;
 
  protected:
-  // Grow generation by specified size (returns false if unable to grow)
-  bool grow_by(size_t bytes);
-  // Grow generation to reserved size.
-  bool grow_to_reserved();
   // Shrink generation by specified size (returns false if unable to shrink)
   virtual void shrink_by(size_t bytes);
 
@@ -1103,6 +1099,11 @@
   // Override
   virtual void ref_processor_init();
 
+  // Grow generation by specified size (returns false if unable to grow)
+  bool grow_by(size_t bytes);
+  // Grow generation to reserved size.
+  bool grow_to_reserved();
+
   void clear_expansion_cause() { _expansion_cause = CMSExpansionCause::_no_expansion; }
 
   // Space enquiries
@@ -1193,6 +1194,7 @@
   // Allocation failure
   void expand(size_t bytes, size_t expand_bytes,
     CMSExpansionCause::Cause cause);
+  virtual bool expand(size_t bytes, size_t expand_bytes);
   void shrink(size_t bytes);
   HeapWord* expand_and_par_lab_allocate(CMSParGCThreadState* ps, size_t word_sz);
   bool expand_and_ensure_spooling_space(PromotionInfo* promo);
--- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/freeBlockDictionary.hpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/freeBlockDictionary.hpp	Wed Jul 05 16:40:29 2017 +0200
@@ -22,7 +22,6 @@
  *
  */
 
-
 // A FreeBlockDictionary is an abstract superclass that will allow
 // a number of alternative implementations in the future.
 class FreeBlockDictionary: public CHeapObj {
--- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/freeChunk.hpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/freeChunk.hpp	Wed Jul 05 16:40:29 2017 +0200
@@ -85,6 +85,8 @@
   }
 
   debug_only(void* prev_addr() const { return (void*)&_prev; })
+  debug_only(void* next_addr() const { return (void*)&_next; })
+  debug_only(void* size_addr() const { return (void*)&_size; })
 
   size_t size() const volatile {
     LP64_ONLY(if (UseCompressedOops) return mark()->get_size(); else )
--- a/hotspot/src/share/vm/gc_implementation/includeDB_gc_concurrentMarkSweep	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/gc_implementation/includeDB_gc_concurrentMarkSweep	Wed Jul 05 16:40:29 2017 +0200
@@ -28,6 +28,7 @@
 binaryTreeDictionary.cpp                binaryTreeDictionary.hpp
 binaryTreeDictionary.cpp                globals.hpp
 binaryTreeDictionary.cpp                ostream.hpp
+binaryTreeDictionary.cpp                spaceDecorator.hpp
 
 binaryTreeDictionary.hpp                freeBlockDictionary.hpp
 binaryTreeDictionary.hpp                freeList.hpp
@@ -114,6 +115,7 @@
 compactibleFreeListSpace.cpp            liveRange.hpp
 compactibleFreeListSpace.cpp            oop.inline.hpp
 compactibleFreeListSpace.cpp            resourceArea.hpp
+compactibleFreeListSpace.cpp            spaceDecorator.hpp
 compactibleFreeListSpace.cpp            universe.inline.hpp
 compactibleFreeListSpace.cpp            vmThread.hpp
 
--- a/hotspot/src/share/vm/gc_implementation/includeDB_gc_parNew	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/gc_implementation/includeDB_gc_parNew	Wed Jul 05 16:40:29 2017 +0200
@@ -22,16 +22,17 @@
 //
 //
 
-asParNewGeneration.hpp			adaptiveSizePolicy.hpp
-asParNewGeneration.hpp			parNewGeneration.hpp
+asParNewGeneration.hpp                  adaptiveSizePolicy.hpp
+asParNewGeneration.hpp                  parNewGeneration.hpp
 
-asParNewGeneration.cpp			asParNewGeneration.hpp
-asParNewGeneration.cpp			cmsAdaptiveSizePolicy.hpp
+asParNewGeneration.cpp                  asParNewGeneration.hpp
+asParNewGeneration.cpp                  cmsAdaptiveSizePolicy.hpp
 asParNewGeneration.cpp                  cmsGCAdaptivePolicyCounters.hpp
-asParNewGeneration.cpp			defNewGeneration.inline.hpp
-asParNewGeneration.cpp			oop.pcgc.inline.hpp
-asParNewGeneration.cpp			parNewGeneration.hpp
+asParNewGeneration.cpp                  defNewGeneration.inline.hpp
+asParNewGeneration.cpp                  oop.pcgc.inline.hpp
+asParNewGeneration.cpp                  parNewGeneration.hpp
 asParNewGeneration.cpp                  referencePolicy.hpp
+asParNewGeneration.cpp                  spaceDecorator.hpp
 
 parCardTableModRefBS.cpp                allocation.inline.hpp
 parCardTableModRefBS.cpp                cardTableModRefBS.hpp
@@ -75,6 +76,7 @@
 parNewGeneration.cpp                    resourceArea.hpp
 parNewGeneration.cpp                    sharedHeap.hpp
 parNewGeneration.cpp                    space.hpp
+parNewGeneration.cpp                    spaceDecorator.hpp
 parNewGeneration.cpp                    workgroup.hpp
 
 parNewGeneration.hpp                    defNewGeneration.hpp
--- a/hotspot/src/share/vm/gc_implementation/includeDB_gc_parallelScavenge	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/gc_implementation/includeDB_gc_parallelScavenge	Wed Jul 05 16:40:29 2017 +0200
@@ -53,14 +53,15 @@
 asPSOldGen.cpp                          oop.inline.hpp
 asPSOldGen.cpp                          parallelScavengeHeap.hpp
 asPSOldGen.cpp                          psMarkSweepDecorator.hpp
-asPSOldGen.cpp				asPSOldGen.hpp
+asPSOldGen.cpp                          asPSOldGen.hpp
 
 asPSYoungGen.hpp                        generationCounters.hpp
 asPSYoungGen.hpp                        mutableSpace.hpp
 asPSYoungGen.hpp                        objectStartArray.hpp
 asPSYoungGen.hpp                        spaceCounters.hpp
 asPSYoungGen.hpp                        psVirtualspace.hpp
-asPSYoungGen.hpp			psYoungGen.hpp
+asPSYoungGen.hpp                        psYoungGen.hpp
+asPSYoungGen.hpp                        spaceDecorator.hpp
 
 asPSYoungGen.cpp                        gcUtil.hpp
 asPSYoungGen.cpp                        java.hpp
@@ -68,8 +69,9 @@
 asPSYoungGen.cpp                        parallelScavengeHeap.hpp
 asPSYoungGen.cpp                        psMarkSweepDecorator.hpp
 asPSYoungGen.cpp                        psScavenge.hpp
-asPSYoungGen.cpp			asPSYoungGen.hpp
-asPSYoungGen.cpp			psYoungGen.hpp
+asPSYoungGen.cpp                        asPSYoungGen.hpp
+asPSYoungGen.cpp                        psYoungGen.hpp
+asPSYoungGen.cpp                        spaceDecorator.hpp
 
 cardTableExtension.cpp                  cardTableExtension.hpp
 cardTableExtension.cpp                  gcTaskManager.hpp
@@ -225,6 +227,7 @@
 psMarkSweep.cpp                         referencePolicy.hpp
 psMarkSweep.cpp                         referenceProcessor.hpp
 psMarkSweep.cpp                         safepoint.hpp
+psMarkSweep.cpp                         spaceDecorator.hpp
 psMarkSweep.cpp                         symbolTable.hpp
 psMarkSweep.cpp                         systemDictionary.hpp
 psMarkSweep.cpp                         vmThread.hpp
@@ -239,6 +242,7 @@
 psMarkSweepDecorator.cpp                parallelScavengeHeap.hpp
 psMarkSweepDecorator.cpp                psMarkSweep.hpp
 psMarkSweepDecorator.cpp                psMarkSweepDecorator.hpp
+psMarkSweepDecorator.cpp                spaceDecorator.hpp
 psMarkSweepDecorator.cpp                systemDictionary.hpp
 
 psMarkSweepDecorator.hpp                mutableSpace.hpp
@@ -290,6 +294,7 @@
 psOldGen.cpp                            parallelScavengeHeap.hpp
 psOldGen.cpp                            psMarkSweepDecorator.hpp
 psOldGen.cpp                            psOldGen.hpp
+psOldGen.cpp                            spaceDecorator.hpp
 
 psOldGen.hpp                            psGenerationCounters.hpp
 psOldGen.hpp                            mutableSpace.hpp
@@ -351,6 +356,7 @@
 psScavenge.cpp                          referencePolicy.hpp
 psScavenge.cpp                          referenceProcessor.hpp
 psScavenge.cpp                          resourceArea.hpp
+psScavenge.cpp                          spaceDecorator.hpp
 psScavenge.cpp                          threadCritical.hpp
 psScavenge.cpp                          vmThread.hpp
 psScavenge.cpp                          vm_operations.hpp
@@ -409,8 +415,8 @@
 
 psVirtualspace.cpp			os.hpp
 psVirtualspace.cpp                      os_<os_family>.inline.hpp
-psVirtualspace.cpp			psVirtualspace.hpp
-psVirtualspace.cpp			virtualspace.hpp
+psVirtualspace.cpp                      psVirtualspace.hpp
+psVirtualspace.cpp                      virtualspace.hpp
 
 psYoungGen.cpp                          gcUtil.hpp
 psYoungGen.cpp                          java.hpp
@@ -419,7 +425,8 @@
 psYoungGen.cpp                          psMarkSweepDecorator.hpp
 psYoungGen.cpp                          psScavenge.hpp
 psYoungGen.cpp                          psYoungGen.hpp
-psYoungGen.cpp				mutableNUMASpace.hpp
+psYoungGen.cpp                          mutableNUMASpace.hpp
+psYoungGen.cpp                          spaceDecorator.hpp
 
 psYoungGen.hpp                          psGenerationCounters.hpp
 psYoungGen.hpp                          mutableSpace.hpp
--- a/hotspot/src/share/vm/gc_implementation/includeDB_gc_shared	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/gc_implementation/includeDB_gc_shared	Wed Jul 05 16:40:29 2017 +0200
@@ -56,6 +56,7 @@
 mutableNUMASpace.cpp                    mutableNUMASpace.hpp
 mutableNUMASpace.cpp                    oop.inline.hpp
 mutableNUMASpace.cpp                    sharedHeap.hpp
+mutableNUMASpace.cpp                    spaceDecorator.hpp
 mutableNUMASpace.cpp                    thread_<os_family>.inline.hpp
 
 mutableNUMASpace.hpp                    mutableSpace.hpp
@@ -64,6 +65,7 @@
 mutableSpace.cpp                        mutableSpace.hpp
 mutableSpace.cpp                        oop.inline.hpp
 mutableSpace.cpp                        safepoint.hpp
+mutableSpace.cpp                        spaceDecorator.hpp
 mutableSpace.cpp                        thread.hpp
 
 spaceCounters.cpp                       resourceArea.hpp
--- a/hotspot/src/share/vm/gc_implementation/parNew/asParNewGeneration.cpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/gc_implementation/parNew/asParNewGeneration.cpp	Wed Jul 05 16:40:29 2017 +0200
@@ -162,10 +162,9 @@
     // Grow the generation
     size_t change = desired_size - orig_size;
     assert(change % alignment == 0, "just checking");
-    if (!virtual_space()->expand_by(change)) {
+    if (expand(change)) {
       return false; // Error if we fail to resize!
     }
-
     size_changed = true;
   } else if (desired_size < orig_size) {
     size_t desired_change = orig_size - desired_size;
@@ -222,7 +221,9 @@
     // Was there a shrink of the survivor space?
     if (new_end < to()->end()) {
       MemRegion mr(to()->bottom(), new_end);
-      to()->initialize(mr, false /* clear */);
+      to()->initialize(mr,
+                       SpaceDecorator::DontClear,
+                       SpaceDecorator::DontMangle);
     }
   }
 }
@@ -322,9 +323,7 @@
                        pointer_delta(from_start, eden_start, sizeof(char)));
     }
 
-// tty->print_cr("eden_size before: " SIZE_FORMAT, eden_size);
     eden_size = align_size_down(eden_size, alignment);
-// tty->print_cr("eden_size after: " SIZE_FORMAT, eden_size);
     eden_end = eden_start + eden_size;
     assert(eden_end >= eden_start, "addition overflowed")
 
@@ -501,11 +500,31 @@
   size_t old_from = from()->capacity();
   size_t old_to   = to()->capacity();
 
+  // If not clearing the spaces, do some checking to verify that
+  // the spaces are already mangled.
+
+  // Must check mangling before the spaces are reshaped.  Otherwise,
+  // the bottom or end of one space may have moved into another
+  // a failure of the check may not correctly indicate which space
+  // is not properly mangled.
+  if (ZapUnusedHeapArea) {
+    HeapWord* limit = (HeapWord*) virtual_space()->high();
+    eden()->check_mangled_unused_area(limit);
+    from()->check_mangled_unused_area(limit);
+      to()->check_mangled_unused_area(limit);
+  }
+
   // The call to initialize NULL's the next compaction space
-  eden()->initialize(edenMR, true);
+  eden()->initialize(edenMR,
+                     SpaceDecorator::Clear,
+                     SpaceDecorator::DontMangle);
   eden()->set_next_compaction_space(from());
-    to()->initialize(toMR  , true);
-  from()->initialize(fromMR, false);     // Note, not cleared!
+    to()->initialize(toMR  ,
+                     SpaceDecorator::Clear,
+                     SpaceDecorator::DontMangle);
+  from()->initialize(fromMR,
+                     SpaceDecorator::DontClear,
+                     SpaceDecorator::DontMangle);
 
   assert(from()->top() == old_from_top, "from top changed!");
 
--- a/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp	Wed Jul 05 16:40:29 2017 +0200
@@ -727,7 +727,7 @@
   SpecializationStats::clear();
 
   age_table()->clear();
-  to()->clear();
+  to()->clear(SpaceDecorator::Mangle);
 
   gch->save_marks();
   assert(workers != NULL, "Need parallel worker threads.");
@@ -793,8 +793,18 @@
   }
   if (!promotion_failed()) {
     // Swap the survivor spaces.
-    eden()->clear();
-    from()->clear();
+    eden()->clear(SpaceDecorator::Mangle);
+    from()->clear(SpaceDecorator::Mangle);
+    if (ZapUnusedHeapArea) {
+      // This is now done here because of the piece-meal mangling which
+      // can check for valid mangling at intermediate points in the
+      // collection(s).  When a minor collection fails to collect
+      // sufficient space resizing of the young generation can occur
+      // an redistribute the spaces in the young generation.  Mangle
+      // here so that unzapped regions don't get distributed to
+      // other spaces.
+      to()->mangle_unused_area();
+    }
     swap_spaces();
 
     assert(to()->is_empty(), "to space should be empty now");
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/asPSYoungGen.cpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/asPSYoungGen.cpp	Wed Jul 05 16:40:29 2017 +0200
@@ -170,9 +170,20 @@
   if (desired_size > orig_size) {
     // Grow the generation
     size_t change = desired_size - orig_size;
+    HeapWord* prev_low = (HeapWord*) virtual_space()->low();
     if (!virtual_space()->expand_by(change)) {
       return false;
     }
+    if (ZapUnusedHeapArea) {
+      // Mangle newly committed space immediately because it
+      // can be done here more simply that after the new
+      // spaces have been computed.
+      HeapWord* new_low = (HeapWord*) virtual_space()->low();
+      assert(new_low < prev_low, "Did not grow");
+
+      MemRegion mangle_region(new_low, prev_low);
+      SpaceMangler::mangle_region(mangle_region);
+    }
     size_changed = true;
   } else if (desired_size < orig_size) {
     size_t desired_change = orig_size - desired_size;
@@ -215,8 +226,10 @@
 //  current implementation does not allow holes between the spaces
 //  _young_generation_boundary has to be reset because it changes.
 //  so additional verification
+
 void ASPSYoungGen::resize_spaces(size_t requested_eden_size,
                                  size_t requested_survivor_size) {
+  assert(UseAdaptiveSizePolicy, "sanity check");
   assert(requested_eden_size > 0 && requested_survivor_size > 0,
          "just checking");
 
@@ -276,22 +289,42 @@
 
   ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap();
   const size_t alignment = heap->intra_heap_alignment();
+  const bool maintain_minimum =
+    (requested_eden_size + 2 * requested_survivor_size) <= min_gen_size();
 
+  bool eden_from_to_order = from_start < to_start;
   // Check whether from space is below to space
-  if (from_start < to_start) {
+  if (eden_from_to_order) {
     // Eden, from, to
+
     if (PrintAdaptiveSizePolicy && Verbose) {
       gclog_or_tty->print_cr("  Eden, from, to:");
     }
 
     // Set eden
-    // Compute how big eden can be, then adjust end.
-    // See comment in PSYoungGen::resize_spaces() on
-    // calculating eden_end.
-    const size_t eden_size = MIN2(requested_eden_size,
-                                  pointer_delta(from_start,
-                                                eden_start,
-                                                sizeof(char)));
+    // "requested_eden_size" is a goal for the size of eden
+    // and may not be attainable.  "eden_size" below is
+    // calculated based on the location of from-space and
+    // the goal for the size of eden.  from-space is
+    // fixed in place because it contains live data.
+    // The calculation is done this way to avoid 32bit
+    // overflow (i.e., eden_start + requested_eden_size
+    // may too large for representation in 32bits).
+    size_t eden_size;
+    if (maintain_minimum) {
+      // Only make eden larger than the requested size if
+      // the minimum size of the generation has to be maintained.
+      // This could be done in general but policy at a higher
+      // level is determining a requested size for eden and that
+      // should be honored unless there is a fundamental reason.
+      eden_size = pointer_delta(from_start,
+                                eden_start,
+                                sizeof(char));
+    } else {
+      eden_size = MIN2(requested_eden_size,
+                       pointer_delta(from_start, eden_start, sizeof(char)));
+    }
+
     eden_end = eden_start + eden_size;
     assert(eden_end >= eden_start, "addition overflowed")
 
@@ -371,12 +404,14 @@
     to_start = MAX2(to_start, eden_start + alignment);
 
     // Compute how big eden can be, then adjust end.
-    // See comment in PSYoungGen::resize_spaces() on
-    // calculating eden_end.
-    const size_t eden_size = MIN2(requested_eden_size,
-                                  pointer_delta(to_start,
-                                                eden_start,
-                                                sizeof(char)));
+    // See  comments above on calculating eden_end.
+    size_t eden_size;
+    if (maintain_minimum) {
+      eden_size = pointer_delta(to_start, eden_start, sizeof(char));
+    } else {
+      eden_size = MIN2(requested_eden_size,
+                       pointer_delta(to_start, eden_start, sizeof(char)));
+    }
     eden_end = eden_start + eden_size;
     assert(eden_end >= eden_start, "addition overflowed")
 
@@ -423,9 +458,47 @@
   size_t old_from = from_space()->capacity_in_bytes();
   size_t old_to   = to_space()->capacity_in_bytes();
 
-  eden_space()->initialize(edenMR, true);
-    to_space()->initialize(toMR  , true);
-  from_space()->initialize(fromMR, false);     // Note, not cleared!
+  if (ZapUnusedHeapArea) {
+    // NUMA is a special case because a numa space is not mangled
+    // in order to not prematurely bind its address to memory to
+    // the wrong memory (i.e., don't want the GC thread to first
+    // touch the memory).  The survivor spaces are not numa
+    // spaces and are mangled.
+    if (UseNUMA) {
+      if (eden_from_to_order) {
+        mangle_survivors(from_space(), fromMR, to_space(), toMR);
+      } else {
+        mangle_survivors(to_space(), toMR, from_space(), fromMR);
+      }
+    }
+
+    // If not mangling the spaces, do some checking to verify that
+    // the spaces are already mangled.
+    // The spaces should be correctly mangled at this point so
+    // do some checking here. Note that they are not being mangled
+    // in the calls to initialize().
+    // Must check mangling before the spaces are reshaped.  Otherwise,
+    // the bottom or end of one space may have moved into an area
+    // covered by another space and a failure of the check may
+    // not correctly indicate which space is not properly mangled.
+
+    HeapWord* limit = (HeapWord*) virtual_space()->high();
+    eden_space()->check_mangled_unused_area(limit);
+    from_space()->check_mangled_unused_area(limit);
+      to_space()->check_mangled_unused_area(limit);
+  }
+  // When an existing space is being initialized, it is not
+  // mangled because the space has been previously mangled.
+  eden_space()->initialize(edenMR,
+                           SpaceDecorator::Clear,
+                           SpaceDecorator::DontMangle);
+    to_space()->initialize(toMR,
+                           SpaceDecorator::Clear,
+                           SpaceDecorator::DontMangle);
+  from_space()->initialize(fromMR,
+                           SpaceDecorator::DontClear,
+                           SpaceDecorator::DontMangle);
+
   PSScavenge::set_young_generation_boundary(eden_space()->bottom());
 
   assert(from_space()->top() == old_from_top, "from top changed!");
@@ -446,7 +519,6 @@
   }
   space_invariants();
 }
-
 void ASPSYoungGen::reset_after_change() {
   assert_locked_or_safepoint(Heap_lock);
 
@@ -458,7 +530,9 @@
   HeapWord* eden_bottom = eden_space()->bottom();
   if (new_eden_bottom != eden_bottom) {
     MemRegion eden_mr(new_eden_bottom, eden_space()->end());
-    eden_space()->initialize(eden_mr, true);
+    eden_space()->initialize(eden_mr,
+                             SpaceDecorator::Clear,
+                             SpaceDecorator::Mangle);
     PSScavenge::set_young_generation_boundary(eden_space()->bottom());
   }
   MemRegion cmr((HeapWord*)virtual_space()->low(),
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/cardTableExtension.cpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/cardTableExtension.cpp	Wed Jul 05 16:40:29 2017 +0200
@@ -666,9 +666,9 @@
 
     HeapWord* new_end_for_commit =
       MIN2(cur_committed.end(), _guard_region.start());
-    MemRegion new_committed =
-      MemRegion(new_start_aligned, new_end_for_commit);
-    if(!new_committed.is_empty()) {
+    if(new_start_aligned < new_end_for_commit) {
+      MemRegion new_committed =
+        MemRegion(new_start_aligned, new_end_for_commit);
       if (!os::commit_memory((char*)new_committed.start(),
                              new_committed.byte_size())) {
         vm_exit_out_of_memory(new_committed.byte_size(),
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp	Wed Jul 05 16:40:29 2017 +0200
@@ -938,3 +938,23 @@
   // Delegate the resize to the generation.
   _old_gen->resize(desired_free_space);
 }
+
+#ifndef PRODUCT
+void ParallelScavengeHeap::record_gen_tops_before_GC() {
+  if (ZapUnusedHeapArea) {
+    young_gen()->record_spaces_top();
+    old_gen()->record_spaces_top();
+    perm_gen()->record_spaces_top();
+  }
+}
+
+void ParallelScavengeHeap::gen_mangle_unused_area() {
+  if (ZapUnusedHeapArea) {
+    young_gen()->eden_space()->mangle_unused_area();
+    young_gen()->to_space()->mangle_unused_area();
+    young_gen()->from_space()->mangle_unused_area();
+    old_gen()->object_space()->mangle_unused_area();
+    perm_gen()->object_space()->mangle_unused_area();
+  }
+}
+#endif
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.hpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.hpp	Wed Jul 05 16:40:29 2017 +0200
@@ -213,6 +213,12 @@
   // Resize the old generation.  The reserved space for the
   // generation may be expanded in preparation for the resize.
   void resize_old_gen(size_t desired_free_space);
+
+  // Save the tops of the spaces in all generations
+  void record_gen_tops_before_GC() PRODUCT_RETURN;
+
+  // Mangle the unused parts of all spaces in the heap
+  void gen_mangle_unused_area() PRODUCT_RETURN;
 };
 
 inline size_t ParallelScavengeHeap::set_alignment(size_t& var, size_t val)
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp	Wed Jul 05 16:40:29 2017 +0200
@@ -98,6 +98,9 @@
   // Increment the invocation count
   heap->increment_total_collections(true /* full */);
 
+  // Save information needed to minimize mangling
+  heap->record_gen_tops_before_GC();
+
   // We need to track unique mark sweep invocations as well.
   _total_invocations++;
 
@@ -188,6 +191,12 @@
 
     deallocate_stacks();
 
+    if (ZapUnusedHeapArea) {
+      // Do a complete mangle (top to end) because the usage for
+      // scratch does not maintain a top pointer.
+      young_gen->to_space()->mangle_unused_area_complete();
+    }
+
     eden_empty = young_gen->eden_space()->is_empty();
     if (!eden_empty) {
       eden_empty = absorb_live_data_from_eden(size_policy, young_gen, old_gen);
@@ -198,7 +207,7 @@
     Universe::update_heap_info_at_gc();
 
     survivors_empty = young_gen->from_space()->is_empty() &&
-      young_gen->to_space()->is_empty();
+                      young_gen->to_space()->is_empty();
     young_gen_empty = eden_empty && survivors_empty;
 
     BarrierSet* bs = heap->barrier_set();
@@ -344,6 +353,11 @@
     perm_gen->verify_object_start_array();
   }
 
+  if (ZapUnusedHeapArea) {
+    old_gen->object_space()->check_mangled_unused_area_complete();
+    perm_gen->object_space()->check_mangled_unused_area_complete();
+  }
+
   NOT_PRODUCT(ref_processor()->verify_no_references_recorded());
 
   if (PrintHeapAtGC) {
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweepDecorator.cpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweepDecorator.cpp	Wed Jul 05 16:40:29 2017 +0200
@@ -438,5 +438,7 @@
          "should point inside space");
   space()->set_top(compaction_top());
 
-  if (mangle_free_space) space()->mangle_unused_area();
+  if (mangle_free_space) {
+    space()->mangle_unused_area();
+  }
 }
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psOldGen.cpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psOldGen.cpp	Wed Jul 05 16:40:29 2017 +0200
@@ -87,6 +87,15 @@
 
   MemRegion cmr((HeapWord*)virtual_space()->low(),
                 (HeapWord*)virtual_space()->high());
+  if (ZapUnusedHeapArea) {
+    // Mangle newly committed space immediately rather than
+    // waiting for the initialization of the space even though
+    // mangling is related to spaces.  Doing it here eliminates
+    // the need to carry along information that a complete mangling
+    // (bottom to end) needs to be done.
+    SpaceMangler::mangle_region(cmr);
+  }
+
   Universe::heap()->barrier_set()->resize_covered_region(cmr);
 
   CardTableModRefBS* _ct = (CardTableModRefBS*)Universe::heap()->barrier_set();
@@ -112,7 +121,9 @@
   if (_object_space == NULL)
     vm_exit_during_initialization("Could not allocate an old gen space");
 
-  object_space()->initialize(cmr, true);
+  object_space()->initialize(cmr,
+                             SpaceDecorator::Clear,
+                             SpaceDecorator::Mangle);
 
   _object_mark_sweep = new PSMarkSweepDecorator(_object_space, start_array(), MarkSweepDeadRatio);
 
@@ -204,10 +215,22 @@
 }
 
 void PSOldGen::expand(size_t bytes) {
+  if (bytes == 0) {
+    return;
+  }
   MutexLocker x(ExpandHeap_lock);
   const size_t alignment = virtual_space()->alignment();
   size_t aligned_bytes  = align_size_up(bytes, alignment);
   size_t aligned_expand_bytes = align_size_up(MinHeapDeltaBytes, alignment);
+  if (aligned_bytes == 0){
+    // The alignment caused the number of bytes to wrap.  An expand_by(0) will
+    // return true with the implication that and expansion was done when it
+    // was not.  A call to expand implies a best effort to expand by "bytes"
+    // but not a guarantee.  Align down to give a best effort.  This is likely
+    // the most that the generation can expand since it has some capacity to
+    // start with.
+    aligned_bytes = align_size_down(bytes, alignment);
+  }
 
   bool success = false;
   if (aligned_expand_bytes > aligned_bytes) {
@@ -220,8 +243,8 @@
     success = expand_to_reserved();
   }
 
-  if (GC_locker::is_active()) {
-    if (PrintGC && Verbose) {
+  if (PrintGC && Verbose) {
+    if (success && GC_locker::is_active()) {
       gclog_or_tty->print_cr("Garbage collection disabled, expanded heap instead");
     }
   }
@@ -230,8 +253,24 @@
 bool PSOldGen::expand_by(size_t bytes) {
   assert_lock_strong(ExpandHeap_lock);
   assert_locked_or_safepoint(Heap_lock);
+  if (bytes == 0) {
+    return true;  // That's what virtual_space()->expand_by(0) would return
+  }
   bool result = virtual_space()->expand_by(bytes);
   if (result) {
+    if (ZapUnusedHeapArea) {
+      // We need to mangle the newly expanded area. The memregion spans
+      // end -> new_end, we assume that top -> end is already mangled.
+      // Do the mangling before post_resize() is called because
+      // the space is available for allocation after post_resize();
+      HeapWord* const virtual_space_high = (HeapWord*) virtual_space()->high();
+      assert(object_space()->end() < virtual_space_high,
+        "Should be true before post_resize()");
+      MemRegion mangle_region(object_space()->end(), virtual_space_high);
+      // Note that the object space has not yet been updated to
+      // coincede with the new underlying virtual space.
+      SpaceMangler::mangle_region(mangle_region);
+    }
     post_resize();
     if (UsePerfData) {
       _space_counters->update_capacity();
@@ -348,16 +387,7 @@
   start_array()->set_covered_region(new_memregion);
   Universe::heap()->barrier_set()->resize_covered_region(new_memregion);
 
-  // Did we expand?
   HeapWord* const virtual_space_high = (HeapWord*) virtual_space()->high();
-  if (object_space()->end() < virtual_space_high) {
-    // We need to mangle the newly expanded area. The memregion spans
-    // end -> new_end, we assume that top -> end is already mangled.
-    // This cannot be safely tested for, as allocation may be taking
-    // place.
-    MemRegion mangle_region(object_space()->end(), virtual_space_high);
-    object_space()->mangle_region(mangle_region);
-  }
 
   // ALWAYS do this last!!
   object_space()->set_end(virtual_space_high);
@@ -462,3 +492,10 @@
   VerifyObjectStartArrayClosure check( this, &_start_array );
   object_iterate(&check);
 }
+
+#ifndef PRODUCT
+void PSOldGen::record_spaces_top() {
+  assert(ZapUnusedHeapArea, "Not mangling unused space");
+  object_space()->set_top_for_allocations();
+}
+#endif
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psOldGen.hpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psOldGen.hpp	Wed Jul 05 16:40:29 2017 +0200
@@ -185,4 +185,8 @@
 
   // Printing support
   virtual const char* name() const { return _name; }
+
+  // Debugging support
+  // Save the tops of all spaces for later use during mangling.
+  void record_spaces_top() PRODUCT_RETURN;
 };
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp	Wed Jul 05 16:40:29 2017 +0200
@@ -200,8 +200,8 @@
   for (unsigned int id = 0; id < last_space_id; ++id) {
     const MutableSpace* space = _space_info[id].space();
     tty->print_cr("%u %s "
-                  SIZE_FORMAT_W("10") " " SIZE_FORMAT_W("10") " "
-                  SIZE_FORMAT_W("10") " " SIZE_FORMAT_W("10") " ",
+                  SIZE_FORMAT_W(10) " " SIZE_FORMAT_W(10) " "
+                  SIZE_FORMAT_W(10) " " SIZE_FORMAT_W(10) " ",
                   id, space_names[id],
                   summary_data().addr_to_chunk_idx(space->bottom()),
                   summary_data().addr_to_chunk_idx(space->top()),
@@ -213,8 +213,8 @@
 void
 print_generic_summary_chunk(size_t i, const ParallelCompactData::ChunkData* c)
 {
-#define CHUNK_IDX_FORMAT        SIZE_FORMAT_W("7")
-#define CHUNK_DATA_FORMAT       SIZE_FORMAT_W("5")
+#define CHUNK_IDX_FORMAT        SIZE_FORMAT_W(7)
+#define CHUNK_DATA_FORMAT       SIZE_FORMAT_W(5)
 
   ParallelCompactData& sd = PSParallelCompact::summary_data();
   size_t dci = c->destination() ? sd.addr_to_chunk_idx(c->destination()) : 0;
@@ -269,9 +269,9 @@
                             const ParallelCompactData::ChunkData* c,
                             bool newline = true)
 {
-  tty->print(SIZE_FORMAT_W("5") " " PTR_FORMAT " "
-             SIZE_FORMAT_W("5") " " SIZE_FORMAT_W("5") " "
-             SIZE_FORMAT_W("5") " " SIZE_FORMAT_W("5") " %d",
+  tty->print(SIZE_FORMAT_W(5) " " PTR_FORMAT " "
+             SIZE_FORMAT_W(5) " " SIZE_FORMAT_W(5) " "
+             SIZE_FORMAT_W(5) " " SIZE_FORMAT_W(5) " %d",
              i, c->destination(),
              c->partial_obj_size(), c->live_obj_size(),
              c->data_size(), c->source_chunk(), c->destination_count());
@@ -326,7 +326,7 @@
     }
 
     print_initial_summary_chunk(i, c, false);
-    tty->print_cr(" %12.10f " SIZE_FORMAT_W("10") " " SIZE_FORMAT_W("10"),
+    tty->print_cr(" %12.10f " SIZE_FORMAT_W(10) " " SIZE_FORMAT_W(10),
                   reclaimed_ratio, dead_to_right, live_to_right);
 
     live_to_right -= c->data_size();
@@ -338,8 +338,8 @@
     print_initial_summary_chunk(i, summary_data.chunk(i));
   }
 
-  tty->print_cr("max:  " SIZE_FORMAT_W("4") " d2r=" SIZE_FORMAT_W("10") " "
-                "l2r=" SIZE_FORMAT_W("10") " max_ratio=%14.12f",
+  tty->print_cr("max:  " SIZE_FORMAT_W(4) " d2r=" SIZE_FORMAT_W(10) " "
+                "l2r=" SIZE_FORMAT_W(10) " max_ratio=%14.12f",
                 max_reclaimed_ratio_chunk, max_dead_to_right,
                 max_live_to_right, max_reclaimed_ratio);
 }
@@ -1060,6 +1060,10 @@
 
   ref_processor()->enqueue_discovered_references(NULL);
 
+  if (ZapUnusedHeapArea) {
+    heap->gen_mangle_unused_area();
+  }
+
   // Update time of last GC
   reset_millis_since_last_gc();
 }
@@ -1119,8 +1123,8 @@
     HeapWord* chunk_destination = cp->destination();
     const size_t cur_deadwood = pointer_delta(dense_prefix, chunk_destination);
     if (TraceParallelOldGCDensePrefix && Verbose) {
-      tty->print_cr("c#=" SIZE_FORMAT_W("04") " dst=" PTR_FORMAT " "
-                    "dp=" SIZE_FORMAT_W("08") " " "cdw=" SIZE_FORMAT_W("08"),
+      tty->print_cr("c#=" SIZE_FORMAT_W(4) " dst=" PTR_FORMAT " "
+                    "dp=" SIZE_FORMAT_W(8) " " "cdw=" SIZE_FORMAT_W(8),
                     sd.chunk(cp), chunk_destination,
                     dense_prefix, cur_deadwood);
     }
@@ -1145,7 +1149,7 @@
           return dense_prefix;
         }
         if (TraceParallelOldGCDensePrefix && Verbose) {
-          tty->print_cr("backing up from c=" SIZE_FORMAT_W("4") " d2r=%10.8f "
+          tty->print_cr("backing up from c=" SIZE_FORMAT_W(4) " d2r=%10.8f "
                         "pc_d2r=%10.8f", sd.chunk(cp), density_to_right,
                         prev_chunk_density_to_right);
         }
@@ -1182,7 +1186,7 @@
   const size_t live_to_right = new_top - cp->destination();
   const size_t dead_to_right = space->top() - addr - live_to_right;
 
-  tty->print_cr("%s=" PTR_FORMAT " dpc=" SIZE_FORMAT_W("05") " "
+  tty->print_cr("%s=" PTR_FORMAT " dpc=" SIZE_FORMAT_W(5) " "
                 "spl=" SIZE_FORMAT " "
                 "d2l=" SIZE_FORMAT " d2l%%=%6.4f "
                 "d2r=" SIZE_FORMAT " l2r=" SIZE_FORMAT
@@ -1522,48 +1526,53 @@
 PSParallelCompact::summarize_space(SpaceId id, bool maximum_compaction)
 {
   assert(id < last_space_id, "id out of range");
+  assert(_space_info[id].dense_prefix() == _space_info[id].space()->bottom(),
+         "should have been set in summarize_spaces_quick()");
 
   const MutableSpace* space = _space_info[id].space();
-  HeapWord** new_top_addr = _space_info[id].new_top_addr();
-
-  HeapWord* dense_prefix_end = compute_dense_prefix(id, maximum_compaction);
-  _space_info[id].set_dense_prefix(dense_prefix_end);
+  if (_space_info[id].new_top() != space->bottom()) {
+    HeapWord* dense_prefix_end = compute_dense_prefix(id, maximum_compaction);
+    _space_info[id].set_dense_prefix(dense_prefix_end);
 
 #ifndef PRODUCT
-  if (TraceParallelOldGCDensePrefix) {
-    print_dense_prefix_stats("ratio", id, maximum_compaction, dense_prefix_end);
-    HeapWord* addr = compute_dense_prefix_via_density(id, maximum_compaction);
-    print_dense_prefix_stats("density", id, maximum_compaction, addr);
-  }
+    if (TraceParallelOldGCDensePrefix) {
+      print_dense_prefix_stats("ratio", id, maximum_compaction,
+                               dense_prefix_end);
+      HeapWord* addr = compute_dense_prefix_via_density(id, maximum_compaction);
+      print_dense_prefix_stats("density", id, maximum_compaction, addr);
+    }
 #endif  // #ifndef PRODUCT
 
-  // If dead space crosses the dense prefix boundary, it is (at least partially)
-  // filled with a dummy object, marked live and added to the summary data.
-  // This simplifies the copy/update phase and must be done before the final
-  // locations of objects are determined, to prevent leaving a fragment of dead
-  // space that is too small to fill with an object.
-  if (!maximum_compaction && dense_prefix_end != space->bottom()) {
-    fill_dense_prefix_end(id);
+    // If dead space crosses the dense prefix boundary, it is (at least
+    // partially) filled with a dummy object, marked live and added to the
+    // summary data.  This simplifies the copy/update phase and must be done
+    // before the final locations of objects are determined, to prevent leaving
+    // a fragment of dead space that is too small to fill with an object.
+    if (!maximum_compaction && dense_prefix_end != space->bottom()) {
+      fill_dense_prefix_end(id);
+    }
+
+    // Compute the destination of each Chunk, and thus each object.
+    _summary_data.summarize_dense_prefix(space->bottom(), dense_prefix_end);
+    _summary_data.summarize(dense_prefix_end, space->end(),
+                            dense_prefix_end, space->top(),
+                            _space_info[id].new_top_addr());
   }
 
-  // Compute the destination of each Chunk, and thus each object.
-  _summary_data.summarize_dense_prefix(space->bottom(), dense_prefix_end);
-  _summary_data.summarize(dense_prefix_end, space->end(),
-                          dense_prefix_end, space->top(),
-                          new_top_addr);
-
   if (TraceParallelOldGCSummaryPhase) {
     const size_t chunk_size = ParallelCompactData::ChunkSize;
+    HeapWord* const dense_prefix_end = _space_info[id].dense_prefix();
     const size_t dp_chunk = _summary_data.addr_to_chunk_idx(dense_prefix_end);
     const size_t dp_words = pointer_delta(dense_prefix_end, space->bottom());
-    const HeapWord* nt_aligned_up = _summary_data.chunk_align_up(*new_top_addr);
+    HeapWord* const new_top = _space_info[id].new_top();
+    const HeapWord* nt_aligned_up = _summary_data.chunk_align_up(new_top);
     const size_t cr_words = pointer_delta(nt_aligned_up, dense_prefix_end);
     tty->print_cr("id=%d cap=" SIZE_FORMAT " dp=" PTR_FORMAT " "
                   "dp_chunk=" SIZE_FORMAT " " "dp_count=" SIZE_FORMAT " "
                   "cr_count=" SIZE_FORMAT " " "nt=" PTR_FORMAT,
                   id, space->capacity_in_words(), dense_prefix_end,
                   dp_chunk, dp_words / chunk_size,
-                  cr_words / chunk_size, *new_top_addr);
+                  cr_words / chunk_size, new_top);
   }
 }
 
@@ -1632,7 +1641,7 @@
     const size_t live = pointer_delta(_space_info[id].new_top(),
                                       space->bottom());
     const size_t available = pointer_delta(target_space_end, *new_top_addr);
-    if (live <= available) {
+    if (live > 0 && live <= available) {
       // All the live data will fit.
       if (TraceParallelOldGCSummaryPhase) {
         tty->print_cr("summarizing %d into old_space @ " PTR_FORMAT,
@@ -1642,16 +1651,18 @@
                               space->bottom(), space->top(),
                               new_top_addr);
 
-      // Reset the new_top value for the space.
-      _space_info[id].set_new_top(space->bottom());
-
       // Clear the source_chunk field for each chunk in the space.
+      HeapWord* const new_top = _space_info[id].new_top();
+      HeapWord* const clear_end = _summary_data.chunk_align_up(new_top);
       ChunkData* beg_chunk = _summary_data.addr_to_chunk_ptr(space->bottom());
-      ChunkData* end_chunk = _summary_data.addr_to_chunk_ptr(space->top() - 1);
-      while (beg_chunk <= end_chunk) {
+      ChunkData* end_chunk = _summary_data.addr_to_chunk_ptr(clear_end);
+      while (beg_chunk < end_chunk) {
         beg_chunk->set_source_chunk(0);
         ++beg_chunk;
       }
+
+      // Reset the new_top value for the space.
+      _space_info[id].set_new_top(space->bottom());
     }
   }
 
@@ -1961,6 +1972,11 @@
   PSPermGen* perm_gen = heap->perm_gen();
   PSAdaptiveSizePolicy* size_policy = heap->size_policy();
 
+  if (ZapUnusedHeapArea) {
+    // Save information needed to minimize mangling
+    heap->record_gen_tops_before_GC();
+  }
+
   _print_phases = PrintGCDetails && PrintParallelOldGCPhaseTimes;
 
   // Make sure data structures are sane, make the heap parsable, and do other
@@ -2129,17 +2145,19 @@
         size_t max_eden_size = young_gen->max_size() -
           young_gen->from_space()->capacity_in_bytes() -
           young_gen->to_space()->capacity_in_bytes();
-        size_policy->compute_generation_free_space(young_gen->used_in_bytes(),
-                                 young_gen->eden_space()->used_in_bytes(),
-                                 old_gen->used_in_bytes(),
-                                 perm_gen->used_in_bytes(),
-                                 young_gen->eden_space()->capacity_in_bytes(),
-                                 old_gen->max_gen_size(),
-                                 max_eden_size,
-                                 true /* full gc*/,
-                                 gc_cause);
-
-        heap->resize_old_gen(size_policy->calculated_old_free_size_in_bytes());
+        size_policy->compute_generation_free_space(
+                              young_gen->used_in_bytes(),
+                              young_gen->eden_space()->used_in_bytes(),
+                              old_gen->used_in_bytes(),
+                              perm_gen->used_in_bytes(),
+                              young_gen->eden_space()->capacity_in_bytes(),
+                              old_gen->max_gen_size(),
+                              max_eden_size,
+                              true /* full gc*/,
+                              gc_cause);
+
+        heap->resize_old_gen(
+          size_policy->calculated_old_free_size_in_bytes());
 
         // Don't resize the young generation at an major collection.  A
         // desired young generation size may have been calculated but
@@ -2212,6 +2230,11 @@
     perm_gen->verify_object_start_array();
   }
 
+  if (ZapUnusedHeapArea) {
+    old_gen->object_space()->check_mangled_unused_area_complete();
+    perm_gen->object_space()->check_mangled_unused_area_complete();
+  }
+
   NOT_PRODUCT(ref_processor()->verify_no_references_recorded());
 
   collection_exit.update();
@@ -2499,7 +2522,7 @@
         if (TraceParallelOldGCCompactionPhase && Verbose) {
           const size_t count_mod_8 = fillable_chunks & 7;
           if (count_mod_8 == 0) gclog_or_tty->print("fillable: ");
-          gclog_or_tty->print(" " SIZE_FORMAT_W("7"), cur);
+          gclog_or_tty->print(" " SIZE_FORMAT_W(7), cur);
           if (count_mod_8 == 7) gclog_or_tty->cr();
         }
 
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.hpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.hpp	Wed Jul 05 16:40:29 2017 +0200
@@ -716,6 +716,99 @@
   virtual IterationStatus do_addr(HeapWord* addr, size_t words);
 };
 
+// The UseParallelOldGC collector is a stop-the-world garbage
+// collector that does parts of the collection using parallel threads.
+// The collection includes the tenured generation and the young
+// generation.  The permanent generation is collected at the same
+// time as the other two generations but the permanent generation
+// is collect by a single GC thread.  The permanent generation is
+// collected serially because of the requirement that during the
+// processing of a klass AAA, any objects reference by AAA must
+// already have been processed.  This requirement is enforced by
+// a left (lower address) to right (higher address) sliding compaction.
+//
+// There are four phases of the collection.
+//
+//      - marking phase
+//      - summary phase
+//      - compacting phase
+//      - clean up phase
+//
+// Roughly speaking these phases correspond, respectively, to
+//      - mark all the live objects
+//      - calculate the destination of each object at the end of the collection
+//      - move the objects to their destination
+//      - update some references and reinitialize some variables
+//
+// These three phases are invoked in PSParallelCompact::invoke_no_policy().
+// The marking phase is implemented in PSParallelCompact::marking_phase()
+// and does a complete marking of the heap.
+// The summary phase is implemented in PSParallelCompact::summary_phase().
+// The move and update phase is implemented in PSParallelCompact::compact().
+//
+// A space that is being collected is divided into chunks and with
+// each chunk is associated an object of type ParallelCompactData.
+// Each chunk is of a fixed size and typically will contain more than
+// 1 object and may have parts of objects at the front and back of the
+// chunk.
+//
+// chunk            -----+---------------------+----------
+// objects covered   [ AAA  )[ BBB )[ CCC   )[ DDD     )
+//
+// The marking phase does a complete marking of all live objects in the
+// heap.  The marking also compiles the size of the data for
+// all live objects covered by the chunk.  This size includes the
+// part of any live object spanning onto the chunk (part of AAA
+// if it is live) from the front, all live objects contained in the chunk
+// (BBB and/or CCC if they are live), and the part of any live objects
+// covered by the chunk that extends off the chunk (part of DDD if it is
+// live).  The marking phase uses multiple GC threads and marking is
+// done in a bit array of type ParMarkBitMap.  The marking of the
+// bit map is done atomically as is the accumulation of the size of the
+// live objects covered by a chunk.
+//
+// The summary phase calculates the total live data to the left of
+// each chunk XXX.  Based on that total and the bottom of the space,
+// it can calculate the starting location of the live data in XXX.
+// The summary phase calculates for each chunk XXX quantites such as
+//
+//      - the amount of live data at the beginning of a chunk from an object
+//      entering the chunk.
+//      - the location of the first live data on the chunk
+//      - a count of the number of chunks receiving live data from XXX.
+//
+// See ParallelCompactData for precise details.  The summary phase also
+// calculates the dense prefix for the compaction.  The dense prefix
+// is a portion at the beginning of the space that is not moved.  The
+// objects in the dense prefix do need to have their object references
+// updated.  See method summarize_dense_prefix().
+//
+// The summary phase is done using 1 GC thread.
+//
+// The compaction phase moves objects to their new location and updates
+// all references in the object.
+//
+// A current exception is that objects that cross a chunk boundary
+// are moved but do not have their references updated.  References are
+// not updated because it cannot easily be determined if the klass
+// pointer KKK for the object AAA has been updated.  KKK likely resides
+// in a chunk to the left of the chunk containing AAA.  These AAA's
+// have there references updated at the end in a clean up phase.
+// See the method PSParallelCompact::update_deferred_objects().  An
+// alternate strategy is being investigated for this deferral of updating.
+//
+// Compaction is done on a chunk basis.  A chunk that is ready to be
+// filled is put on a ready list and GC threads take chunk off the list
+// and fill them.  A chunk is ready to be filled if it
+// empty of live objects.  Such a chunk may have been initially
+// empty (only contained
+// dead objects) or may have had all its live objects copied out already.
+// A chunk that compacts into itself is also ready for filling.  The
+// ready list is initially filled with empty chunks and chunks compacting
+// into themselves.  There is always at least 1 chunk that can be put on
+// the ready list.  The chunks are atomically added and removed from
+// the ready list.
+//
 class PSParallelCompact : AllStatic {
  public:
   // Convenient access to type names.
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp	Wed Jul 05 16:40:29 2017 +0200
@@ -265,6 +265,11 @@
     young_gen->eden_space()->accumulate_statistics();
   }
 
+  if (ZapUnusedHeapArea) {
+    // Save information needed to minimize mangling
+    heap->record_gen_tops_before_GC();
+  }
+
   if (PrintHeapAtGC) {
     Universe::print_heap_before_gc();
   }
@@ -315,7 +320,7 @@
     if (!ScavengeWithObjectsInToSpace) {
       assert(young_gen->to_space()->is_empty(),
              "Attempt to scavenge with live objects in to_space");
-      young_gen->to_space()->clear();
+      young_gen->to_space()->clear(SpaceDecorator::Mangle);
     } else if (ZapUnusedHeapArea) {
       young_gen->to_space()->mangle_unused_area();
     }
@@ -437,8 +442,10 @@
 
     if (!promotion_failure_occurred) {
       // Swap the survivor spaces.
-      young_gen->eden_space()->clear();
-      young_gen->from_space()->clear();
+
+
+      young_gen->eden_space()->clear(SpaceDecorator::Mangle);
+      young_gen->from_space()->clear(SpaceDecorator::Mangle);
       young_gen->swap_spaces();
 
       size_t survived = young_gen->from_space()->used_in_bytes();
@@ -600,6 +607,12 @@
     Universe::print_heap_after_gc();
   }
 
+  if (ZapUnusedHeapArea) {
+    young_gen->eden_space()->check_mangled_unused_area_complete();
+    young_gen->from_space()->check_mangled_unused_area_complete();
+    young_gen->to_space()->check_mangled_unused_area_complete();
+  }
+
   scavenge_exit.update();
 
   if (PrintGCTaskTimeStamps) {
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psYoungGen.cpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psYoungGen.cpp	Wed Jul 05 16:40:29 2017 +0200
@@ -36,7 +36,7 @@
 void PSYoungGen::initialize_virtual_space(ReservedSpace rs, size_t alignment) {
   assert(_init_gen_size != 0, "Should have a finite size");
   _virtual_space = new PSVirtualSpace(rs, alignment);
-  if (!_virtual_space->expand_by(_init_gen_size)) {
+  if (!virtual_space()->expand_by(_init_gen_size)) {
     vm_exit_during_initialization("Could not reserve enough space for "
                                   "object heap");
   }
@@ -49,12 +49,19 @@
 
 void PSYoungGen::initialize_work() {
 
-  _reserved = MemRegion((HeapWord*)_virtual_space->low_boundary(),
-                        (HeapWord*)_virtual_space->high_boundary());
+  _reserved = MemRegion((HeapWord*)virtual_space()->low_boundary(),
+                        (HeapWord*)virtual_space()->high_boundary());
+
+  MemRegion cmr((HeapWord*)virtual_space()->low(),
+                (HeapWord*)virtual_space()->high());
+  Universe::heap()->barrier_set()->resize_covered_region(cmr);
 
-  MemRegion cmr((HeapWord*)_virtual_space->low(),
-                (HeapWord*)_virtual_space->high());
-  Universe::heap()->barrier_set()->resize_covered_region(cmr);
+  if (ZapUnusedHeapArea) {
+    // Mangle newly committed space immediately because it
+    // can be done here more simply that after the new
+    // spaces have been computed.
+    SpaceMangler::mangle_region(cmr);
+  }
 
   if (UseNUMA) {
     _eden_space = new MutableNUMASpace();
@@ -89,7 +96,7 @@
   // Compute maximum space sizes for performance counters
   ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap();
   size_t alignment = heap->intra_heap_alignment();
-  size_t size = _virtual_space->reserved_size();
+  size_t size = virtual_space()->reserved_size();
 
   size_t max_survivor_size;
   size_t max_eden_size;
@@ -142,7 +149,7 @@
 
   // Compute sizes
   size_t alignment = heap->intra_heap_alignment();
-  size_t size = _virtual_space->committed_size();
+  size_t size = virtual_space()->committed_size();
 
   size_t survivor_size = size / InitialSurvivorRatio;
   survivor_size = align_size_down(survivor_size, alignment);
@@ -164,18 +171,18 @@
 }
 
 void PSYoungGen::set_space_boundaries(size_t eden_size, size_t survivor_size) {
-  assert(eden_size < _virtual_space->committed_size(), "just checking");
+  assert(eden_size < virtual_space()->committed_size(), "just checking");
   assert(eden_size > 0  && survivor_size > 0, "just checking");
 
   // Initial layout is Eden, to, from. After swapping survivor spaces,
   // that leaves us with Eden, from, to, which is step one in our two
   // step resize-with-live-data procedure.
-  char *eden_start = _virtual_space->low();
+  char *eden_start = virtual_space()->low();
   char *to_start   = eden_start + eden_size;
   char *from_start = to_start   + survivor_size;
   char *from_end   = from_start + survivor_size;
 
-  assert(from_end == _virtual_space->high(), "just checking");
+  assert(from_end == virtual_space()->high(), "just checking");
   assert(is_object_aligned((intptr_t)eden_start), "checking alignment");
   assert(is_object_aligned((intptr_t)to_start),   "checking alignment");
   assert(is_object_aligned((intptr_t)from_start), "checking alignment");
@@ -184,9 +191,9 @@
   MemRegion to_mr  ((HeapWord*)to_start, (HeapWord*)from_start);
   MemRegion from_mr((HeapWord*)from_start, (HeapWord*)from_end);
 
-  eden_space()->initialize(eden_mr, true);
-    to_space()->initialize(to_mr  , true);
-  from_space()->initialize(from_mr, true);
+  eden_space()->initialize(eden_mr, true, ZapUnusedHeapArea);
+    to_space()->initialize(to_mr  , true, ZapUnusedHeapArea);
+  from_space()->initialize(from_mr, true, ZapUnusedHeapArea);
 }
 
 #ifndef PRODUCT
@@ -207,7 +214,7 @@
   char* to_start   = (char*)to_space()->bottom();
   char* to_end     = (char*)to_space()->end();
 
-  guarantee(eden_start >= _virtual_space->low(), "eden bottom");
+  guarantee(eden_start >= virtual_space()->low(), "eden bottom");
   guarantee(eden_start < eden_end, "eden space consistency");
   guarantee(from_start < from_end, "from space consistency");
   guarantee(to_start < to_end, "to space consistency");
@@ -217,29 +224,29 @@
     // Eden, from, to
     guarantee(eden_end <= from_start, "eden/from boundary");
     guarantee(from_end <= to_start,   "from/to boundary");
-    guarantee(to_end <= _virtual_space->high(), "to end");
+    guarantee(to_end <= virtual_space()->high(), "to end");
   } else {
     // Eden, to, from
     guarantee(eden_end <= to_start, "eden/to boundary");
     guarantee(to_end <= from_start, "to/from boundary");
-    guarantee(from_end <= _virtual_space->high(), "from end");
+    guarantee(from_end <= virtual_space()->high(), "from end");
   }
 
   // More checks that the virtual space is consistent with the spaces
-  assert(_virtual_space->committed_size() >=
+  assert(virtual_space()->committed_size() >=
     (eden_space()->capacity_in_bytes() +
      to_space()->capacity_in_bytes() +
      from_space()->capacity_in_bytes()), "Committed size is inconsistent");
-  assert(_virtual_space->committed_size() <= _virtual_space->reserved_size(),
+  assert(virtual_space()->committed_size() <= virtual_space()->reserved_size(),
     "Space invariant");
   char* eden_top = (char*)eden_space()->top();
   char* from_top = (char*)from_space()->top();
   char* to_top = (char*)to_space()->top();
-  assert(eden_top <= _virtual_space->high(), "eden top");
-  assert(from_top <= _virtual_space->high(), "from top");
-  assert(to_top <= _virtual_space->high(), "to top");
+  assert(eden_top <= virtual_space()->high(), "eden top");
+  assert(from_top <= virtual_space()->high(), "from top");
+  assert(to_top <= virtual_space()->high(), "to top");
 
-  _virtual_space->verify();
+  virtual_space()->verify();
 }
 #endif
 
@@ -265,8 +272,8 @@
 
 
 bool PSYoungGen::resize_generation(size_t eden_size, size_t survivor_size) {
-  const size_t alignment = _virtual_space->alignment();
-  size_t orig_size = _virtual_space->committed_size();
+  const size_t alignment = virtual_space()->alignment();
+  size_t orig_size = virtual_space()->committed_size();
   bool size_changed = false;
 
   // There used to be this guarantee there.
@@ -288,10 +295,18 @@
     // Grow the generation
     size_t change = desired_size - orig_size;
     assert(change % alignment == 0, "just checking");
-    if (!_virtual_space->expand_by(change)) {
+    HeapWord* prev_high = (HeapWord*) virtual_space()->high();
+    if (!virtual_space()->expand_by(change)) {
       return false; // Error if we fail to resize!
     }
-
+    if (ZapUnusedHeapArea) {
+      // Mangle newly committed space immediately because it
+      // can be done here more simply that after the new
+      // spaces have been computed.
+      HeapWord* new_high = (HeapWord*) virtual_space()->high();
+      MemRegion mangle_region(prev_high, new_high);
+      SpaceMangler::mangle_region(mangle_region);
+    }
     size_changed = true;
   } else if (desired_size < orig_size) {
     size_t desired_change = orig_size - desired_size;
@@ -321,19 +336,95 @@
     post_resize();
 
     if (Verbose && PrintGC) {
-      size_t current_size  = _virtual_space->committed_size();
+      size_t current_size  = virtual_space()->committed_size();
       gclog_or_tty->print_cr("PSYoung generation size changed: "
                              SIZE_FORMAT "K->" SIZE_FORMAT "K",
                              orig_size/K, current_size/K);
     }
   }
 
-  guarantee(eden_plus_survivors <= _virtual_space->committed_size() ||
-            _virtual_space->committed_size() == max_size(), "Sanity");
+  guarantee(eden_plus_survivors <= virtual_space()->committed_size() ||
+            virtual_space()->committed_size() == max_size(), "Sanity");
 
   return true;
 }
 
+#ifndef PRODUCT
+// In the numa case eden is not mangled so a survivor space
+// moving into a region previously occupied by a survivor
+// may find an unmangled region.  Also in the PS case eden
+// to-space and from-space may not touch (i.e., there may be
+// gaps between them due to movement while resizing the
+// spaces).  Those gaps must be mangled.
+void PSYoungGen::mangle_survivors(MutableSpace* s1,
+                                  MemRegion s1MR,
+                                  MutableSpace* s2,
+                                  MemRegion s2MR) {
+  // Check eden and gap between eden and from-space, in deciding
+  // what to mangle in from-space.  Check the gap between from-space
+  // and to-space when deciding what to mangle.
+  //
+  //      +--------+   +----+    +---+
+  //      | eden   |   |s1  |    |s2 |
+  //      +--------+   +----+    +---+
+  //                 +-------+ +-----+
+  //                 |s1MR   | |s2MR |
+  //                 +-------+ +-----+
+  // All of survivor-space is properly mangled so find the
+  // upper bound on the mangling for any portion above current s1.
+  HeapWord* delta_end = MIN2(s1->bottom(), s1MR.end());
+  MemRegion delta1_left;
+  if (s1MR.start() < delta_end) {
+    delta1_left = MemRegion(s1MR.start(), delta_end);
+    s1->mangle_region(delta1_left);
+  }
+  // Find any portion to the right of the current s1.
+  HeapWord* delta_start = MAX2(s1->end(), s1MR.start());
+  MemRegion delta1_right;
+  if (delta_start < s1MR.end()) {
+    delta1_right = MemRegion(delta_start, s1MR.end());
+    s1->mangle_region(delta1_right);
+  }
+
+  // Similarly for the second survivor space except that
+  // any of the new region that overlaps with the current
+  // region of the first survivor space has already been
+  // mangled.
+  delta_end = MIN2(s2->bottom(), s2MR.end());
+  delta_start = MAX2(s2MR.start(), s1->end());
+  MemRegion delta2_left;
+  if (s2MR.start() < delta_end) {
+    delta2_left = MemRegion(s2MR.start(), delta_end);
+    s2->mangle_region(delta2_left);
+  }
+  delta_start = MAX2(s2->end(), s2MR.start());
+  MemRegion delta2_right;
+  if (delta_start < s2MR.end()) {
+    s2->mangle_region(delta2_right);
+  }
+
+  if (TraceZapUnusedHeapArea) {
+    // s1
+    gclog_or_tty->print_cr("Current region: [" PTR_FORMAT ", " PTR_FORMAT ") "
+      "New region: [" PTR_FORMAT ", " PTR_FORMAT ")",
+      s1->bottom(), s1->end(), s1MR.start(), s1MR.end());
+    gclog_or_tty->print_cr("    Mangle before: [" PTR_FORMAT ", "
+      PTR_FORMAT ")  Mangle after: [" PTR_FORMAT ", " PTR_FORMAT ")",
+      delta1_left.start(), delta1_left.end(), delta1_right.start(),
+      delta1_right.end());
+
+    // s2
+    gclog_or_tty->print_cr("Current region: [" PTR_FORMAT ", " PTR_FORMAT ") "
+      "New region: [" PTR_FORMAT ", " PTR_FORMAT ")",
+      s2->bottom(), s2->end(), s2MR.start(), s2MR.end());
+    gclog_or_tty->print_cr("    Mangle before: [" PTR_FORMAT ", "
+      PTR_FORMAT ")  Mangle after: [" PTR_FORMAT ", " PTR_FORMAT ")",
+      delta2_left.start(), delta2_left.end(), delta2_right.start(),
+      delta2_right.end());
+  }
+
+}
+#endif // NOT PRODUCT
 
 void PSYoungGen::resize_spaces(size_t requested_eden_size,
                                size_t requested_survivor_size) {
@@ -396,9 +487,11 @@
   const bool maintain_minimum =
     (requested_eden_size + 2 * requested_survivor_size) <= min_gen_size();
 
+  bool eden_from_to_order = from_start < to_start;
   // Check whether from space is below to space
-  if (from_start < to_start) {
+  if (eden_from_to_order) {
     // Eden, from, to
+    eden_from_to_order = true;
     if (PrintAdaptiveSizePolicy && Verbose) {
       gclog_or_tty->print_cr("  Eden, from, to:");
     }
@@ -435,7 +528,7 @@
     // extra calculations.
 
     // First calculate an optimal to-space
-    to_end   = (char*)_virtual_space->high();
+    to_end   = (char*)virtual_space()->high();
     to_start = (char*)pointer_delta(to_end, (char*)requested_survivor_size,
                                     sizeof(char));
 
@@ -491,7 +584,7 @@
     // to space as if we were able to resize from space, even though from
     // space is not modified.
     // Giving eden priority was tried and gave poorer performance.
-    to_end   = (char*)pointer_delta(_virtual_space->high(),
+    to_end   = (char*)pointer_delta(virtual_space()->high(),
                                     (char*)requested_survivor_size,
                                     sizeof(char));
     to_end   = MIN2(to_end, from_start);
@@ -560,9 +653,45 @@
   size_t old_from = from_space()->capacity_in_bytes();
   size_t old_to   = to_space()->capacity_in_bytes();
 
-  eden_space()->initialize(edenMR, true);
-    to_space()->initialize(toMR  , true);
-  from_space()->initialize(fromMR, false);     // Note, not cleared!
+  if (ZapUnusedHeapArea) {
+    // NUMA is a special case because a numa space is not mangled
+    // in order to not prematurely bind its address to memory to
+    // the wrong memory (i.e., don't want the GC thread to first
+    // touch the memory).  The survivor spaces are not numa
+    // spaces and are mangled.
+    if (UseNUMA) {
+      if (eden_from_to_order) {
+        mangle_survivors(from_space(), fromMR, to_space(), toMR);
+      } else {
+        mangle_survivors(to_space(), toMR, from_space(), fromMR);
+      }
+    }
+
+    // If not mangling the spaces, do some checking to verify that
+    // the spaces are already mangled.
+    // The spaces should be correctly mangled at this point so
+    // do some checking here. Note that they are not being mangled
+    // in the calls to initialize().
+    // Must check mangling before the spaces are reshaped.  Otherwise,
+    // the bottom or end of one space may have moved into an area
+    // covered by another space and a failure of the check may
+    // not correctly indicate which space is not properly mangled.
+    HeapWord* limit = (HeapWord*) virtual_space()->high();
+    eden_space()->check_mangled_unused_area(limit);
+    from_space()->check_mangled_unused_area(limit);
+      to_space()->check_mangled_unused_area(limit);
+  }
+  // When an existing space is being initialized, it is not
+  // mangled because the space has been previously mangled.
+  eden_space()->initialize(edenMR,
+                           SpaceDecorator::Clear,
+                           SpaceDecorator::DontMangle);
+    to_space()->initialize(toMR,
+                           SpaceDecorator::Clear,
+                           SpaceDecorator::DontMangle);
+  from_space()->initialize(fromMR,
+                           SpaceDecorator::DontClear,
+                           SpaceDecorator::DontMangle);
 
   assert(from_space()->top() == old_from_top, "from top changed!");
 
@@ -671,7 +800,7 @@
     st->print(" total " SIZE_FORMAT "K, used " SIZE_FORMAT "K",
                capacity_in_bytes()/K, used_in_bytes()/K);
   }
-  _virtual_space->print_space_boundaries_on(st);
+  virtual_space()->print_space_boundaries_on(st);
   st->print("  eden"); eden_space()->print_on(st);
   st->print("  from"); from_space()->print_on(st);
   st->print("  to  "); to_space()->print_on(st);
@@ -774,7 +903,9 @@
   // Was there a shrink of the survivor space?
   if (new_end < space_shrinking->end()) {
     MemRegion mr(space_shrinking->bottom(), new_end);
-    space_shrinking->initialize(mr, false /* clear */);
+    space_shrinking->initialize(mr,
+                                SpaceDecorator::DontClear,
+                                SpaceDecorator::Mangle);
   }
 }
 
@@ -809,3 +940,12 @@
   from_space()->verify(allow_dirty);
   to_space()->verify(allow_dirty);
 }
+
+#ifndef PRODUCT
+void PSYoungGen::record_spaces_top() {
+  assert(ZapUnusedHeapArea, "Not mangling unused space");
+  eden_space()->set_top_for_allocations();
+  from_space()->set_top_for_allocations();
+  to_space()->set_top_for_allocations();
+}
+#endif
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psYoungGen.hpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psYoungGen.hpp	Wed Jul 05 16:40:29 2017 +0200
@@ -179,4 +179,12 @@
 
   // Space boundary invariant checker
   void space_invariants() PRODUCT_RETURN;
+
+  // Helper for mangling survivor spaces.
+  void mangle_survivors(MutableSpace* s1,
+                        MemRegion s1MR,
+                        MutableSpace* s2,
+                        MemRegion s2MR) PRODUCT_RETURN;
+
+  void record_spaces_top() PRODUCT_RETURN;
 };
--- a/hotspot/src/share/vm/gc_implementation/shared/gcUtil.hpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/gc_implementation/shared/gcUtil.hpp	Wed Jul 05 16:40:29 2017 +0200
@@ -58,6 +58,12 @@
     _average(0.0), _sample_count(0), _weight(weight), _last_sample(0.0) {
   }
 
+  void clear() {
+    _average = 0;
+    _sample_count = 0;
+    _last_sample = 0;
+  }
+
   // Accessors
   float    average() const       { return _average;       }
   unsigned weight()  const       { return _weight;        }
@@ -115,6 +121,12 @@
   float deviation()      const         { return _deviation;  }
   unsigned padding()     const         { return _padding;    }
 
+  void clear() {
+    AdaptiveWeightedAverage::clear();
+    _padded_avg = 0;
+    _deviation = 0;
+  }
+
   // Override
   void  sample(float new_sample);
 };
--- a/hotspot/src/share/vm/gc_implementation/shared/mutableNUMASpace.cpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/gc_implementation/shared/mutableNUMASpace.cpp	Wed Jul 05 16:40:29 2017 +0200
@@ -42,19 +42,31 @@
   delete lgrp_spaces();
 }
 
+#ifndef PRODUCT
 void MutableNUMASpace::mangle_unused_area() {
-  for (int i = 0; i < lgrp_spaces()->length(); i++) {
-    LGRPSpace *ls = lgrp_spaces()->at(i);
-    MutableSpace *s = ls->space();
-    if (!os::numa_has_static_binding()) {
-      HeapWord *top = MAX2((HeapWord*)round_down((intptr_t)s->top(), page_size()), s->bottom());
-      if (top < s->end()) {
-        ls->add_invalid_region(MemRegion(top, s->end()));
-      }
-    }
-    s->mangle_unused_area();
-  }
+  // This method should do nothing.
+  // It can be called on a numa space during a full compaction.
+}
+void MutableNUMASpace::mangle_unused_area_complete() {
+  // This method should do nothing.
+  // It can be called on a numa space during a full compaction.
+}
+void MutableNUMASpace::mangle_region(MemRegion mr) {
+  // This method should do nothing because numa spaces are not mangled.
 }
+void MutableNUMASpace::set_top_for_allocations(HeapWord* v) {
+  assert(false, "Do not mangle MutableNUMASpace's");
+}
+void MutableNUMASpace::set_top_for_allocations() {
+  // This method should do nothing.
+}
+void MutableNUMASpace::check_mangled_unused_area(HeapWord* limit) {
+  // This method should do nothing.
+}
+void MutableNUMASpace::check_mangled_unused_area_complete() {
+  // This method should do nothing.
+}
+#endif  // NOT_PRODUCT
 
 // There may be unallocated holes in the middle chunks
 // that should be filled with dead objects to ensure parseability.
@@ -129,7 +141,20 @@
 size_t MutableNUMASpace::tlab_capacity(Thread *thr) const {
   guarantee(thr != NULL, "No thread");
   int lgrp_id = thr->lgrp_id();
-  assert(lgrp_id != -1, "No lgrp_id set");
+  if (lgrp_id == -1) {
+    // This case can occur after the topology of the system has
+    // changed. Thread can change their location, the new home
+    // group will be determined during the first allocation
+    // attempt. For now we can safely assume that all spaces
+    // have equal size because the whole space will be reinitialized.
+    if (lgrp_spaces()->length() > 0) {
+      return capacity_in_bytes() / lgrp_spaces()->length();
+    } else {
+      assert(false, "There should be at least one locality group");
+      return 0;
+    }
+  }
+  // That's the normal case, where we know the locality group of the thread.
   int i = lgrp_spaces()->find(&lgrp_id, LGRPSpace::equals);
   if (i == -1) {
     return 0;
@@ -138,9 +163,17 @@
 }
 
 size_t MutableNUMASpace::unsafe_max_tlab_alloc(Thread *thr) const {
+  // Please see the comments for tlab_capacity().
   guarantee(thr != NULL, "No thread");
   int lgrp_id = thr->lgrp_id();
-  assert(lgrp_id != -1, "No lgrp_id set");
+  if (lgrp_id == -1) {
+    if (lgrp_spaces()->length() > 0) {
+      return free_in_bytes() / lgrp_spaces()->length();
+    } else {
+      assert(false, "There should be at least one locality group");
+      return 0;
+    }
+  }
   int i = lgrp_spaces()->find(&lgrp_id, LGRPSpace::equals);
   if (i == -1) {
     return 0;
@@ -238,12 +271,20 @@
 void MutableNUMASpace::update() {
   if (update_layout(false)) {
     // If the topology has changed, make all chunks zero-sized.
+    // And clear the alloc-rate statistics.
+    // In future we may want to handle this more gracefully in order
+    // to avoid the reallocation of the pages as much as possible.
     for (int i = 0; i < lgrp_spaces()->length(); i++) {
-      MutableSpace *s = lgrp_spaces()->at(i)->space();
+      LGRPSpace *ls = lgrp_spaces()->at(i);
+      MutableSpace *s = ls->space();
       s->set_end(s->bottom());
       s->set_top(s->bottom());
+      ls->clear_alloc_rate();
     }
-    initialize(region(), true);
+    // A NUMA space is never mangled
+    initialize(region(),
+               SpaceDecorator::Clear,
+               SpaceDecorator::DontMangle);
   } else {
     bool should_initialize = false;
     if (!os::numa_has_static_binding()) {
@@ -257,7 +298,10 @@
 
     if (should_initialize ||
         (UseAdaptiveNUMAChunkSizing && adaptation_cycles() < samples_count())) {
-      initialize(region(), true);
+      // A NUMA space is never mangled
+      initialize(region(),
+                 SpaceDecorator::Clear,
+                 SpaceDecorator::DontMangle);
     }
   }
 
@@ -448,14 +492,17 @@
         }
 }
 
-void MutableNUMASpace::initialize(MemRegion mr, bool clear_space) {
+void MutableNUMASpace::initialize(MemRegion mr,
+                                  bool clear_space,
+                                  bool mangle_space) {
   assert(clear_space, "Reallocation will destory data!");
   assert(lgrp_spaces()->length() > 0, "There should be at least one space");
 
   MemRegion old_region = region(), new_region;
   set_bottom(mr.start());
   set_end(mr.end());
-  MutableSpace::set_top(bottom());
+  // Must always clear the space
+  clear(SpaceDecorator::DontMangle);
 
   // Compute chunk sizes
   size_t prev_page_size = page_size();
@@ -586,10 +633,8 @@
       bias_region(top_region, ls->lgrp_id());
     }
 
-    // If we clear the region, we would mangle it in debug. That would cause page
-    // allocation in a different place. Hence setting the top directly.
-    s->initialize(new_region, false);
-    s->set_top(s->bottom());
+    // Clear space (set top = bottom) but never mangle.
+    s->initialize(new_region, SpaceDecorator::Clear, SpaceDecorator::DontMangle);
 
     set_adaptation_cycles(samples_count());
   }
@@ -641,10 +686,12 @@
   MutableSpace::set_top(value);
 }
 
-void MutableNUMASpace::clear() {
+void MutableNUMASpace::clear(bool mangle_space) {
   MutableSpace::set_top(bottom());
   for (int i = 0; i < lgrp_spaces()->length(); i++) {
-    lgrp_spaces()->at(i)->space()->clear();
+    // Never mangle NUMA spaces because the mangling will
+    // bind the memory to a possibly unwanted lgroup.
+    lgrp_spaces()->at(i)->space()->clear(SpaceDecorator::DontMangle);
   }
 }
 
--- a/hotspot/src/share/vm/gc_implementation/shared/mutableNUMASpace.hpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/gc_implementation/shared/mutableNUMASpace.hpp	Wed Jul 05 16:40:29 2017 +0200
@@ -112,6 +112,7 @@
     int lgrp_id() const                             { return _lgrp_id;             }
     MutableSpace* space() const                     { return _space;               }
     AdaptiveWeightedAverage* alloc_rate() const     { return _alloc_rate;          }
+    void clear_alloc_rate()                         { _alloc_rate->clear();        }
     SpaceStats* space_stats()                       { return &_space_stats;        }
     void clear_space_stats()                        { _space_stats = SpaceStats(); }
 
@@ -171,14 +172,21 @@
   MutableNUMASpace();
   virtual ~MutableNUMASpace();
   // Space initialization.
-  virtual void initialize(MemRegion mr, bool clear_space);
+  virtual void initialize(MemRegion mr, bool clear_space, bool mangle_space);
   // Update space layout if necessary. Do all adaptive resizing job.
   virtual void update();
   // Update allocation rate averages.
   virtual void accumulate_statistics();
 
-  virtual void clear();
-  virtual void mangle_unused_area();
+  virtual void clear(bool mangle_space);
+  virtual void mangle_unused_area() PRODUCT_RETURN;
+  virtual void mangle_unused_area_complete() PRODUCT_RETURN;
+  virtual void mangle_region(MemRegion mr) PRODUCT_RETURN;
+  virtual void check_mangled_unused_area(HeapWord* limit) PRODUCT_RETURN;
+  virtual void check_mangled_unused_area_complete() PRODUCT_RETURN;
+  virtual void set_top_for_allocations(HeapWord* v) PRODUCT_RETURN;
+  virtual void set_top_for_allocations() PRODUCT_RETURN;
+
   virtual void ensure_parsability();
   virtual size_t used_in_words() const;
   virtual size_t free_in_words() const;
--- a/hotspot/src/share/vm/gc_implementation/shared/mutableSpace.cpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/gc_implementation/shared/mutableSpace.cpp	Wed Jul 05 16:40:29 2017 +0200
@@ -25,7 +25,17 @@
 # include "incls/_precompiled.incl"
 # include "incls/_mutableSpace.cpp.incl"
 
-void MutableSpace::initialize(MemRegion mr, bool clear_space) {
+MutableSpace::MutableSpace(): ImmutableSpace(), _top(NULL) {
+  _mangler = new MutableSpaceMangler(this);
+}
+
+MutableSpace::~MutableSpace() {
+  delete _mangler;
+}
+
+void MutableSpace::initialize(MemRegion mr,
+                              bool clear_space,
+                              bool mangle_space) {
   HeapWord* bottom = mr.start();
   HeapWord* end    = mr.end();
 
@@ -34,14 +44,51 @@
   set_bottom(bottom);
   set_end(end);
 
-  if (clear_space) clear();
+  if (clear_space) {
+    clear(mangle_space);
+  }
+}
+
+void MutableSpace::clear(bool mangle_space) {
+  set_top(bottom());
+  if (ZapUnusedHeapArea && mangle_space) {
+    mangle_unused_area();
+  }
+}
+
+#ifndef PRODUCT
+void MutableSpace::check_mangled_unused_area(HeapWord* limit) {
+  mangler()->check_mangled_unused_area(limit);
+}
+
+void MutableSpace::check_mangled_unused_area_complete() {
+  mangler()->check_mangled_unused_area_complete();
 }
 
-void MutableSpace::clear() {
-  set_top(bottom());
-  if (ZapUnusedHeapArea) mangle_unused_area();
+// Mangle only the unused space that has not previously
+// been mangled and that has not been allocated since being
+// mangled.
+void MutableSpace::mangle_unused_area() {
+  mangler()->mangle_unused_area();
+}
+
+void MutableSpace::mangle_unused_area_complete() {
+  mangler()->mangle_unused_area_complete();
 }
 
+void MutableSpace::mangle_region(MemRegion mr) {
+  SpaceMangler::mangle_region(mr);
+}
+
+void MutableSpace::set_top_for_allocations(HeapWord* v) {
+  mangler()->set_top_for_allocations(v);
+}
+
+void MutableSpace::set_top_for_allocations() {
+  mangler()->set_top_for_allocations(top());
+}
+#endif
+
 // This version requires locking. */
 HeapWord* MutableSpace::allocate(size_t size) {
   assert(Heap_lock->owned_by_self() ||
--- a/hotspot/src/share/vm/gc_implementation/shared/mutableSpace.hpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/gc_implementation/shared/mutableSpace.hpp	Wed Jul 05 16:40:29 2017 +0200
@@ -30,14 +30,23 @@
 // Invariant: (ImmutableSpace +) bottom() <= top() <= end()
 // top() is inclusive and end() is exclusive.
 
+class MutableSpaceMangler;
+
 class MutableSpace: public ImmutableSpace {
   friend class VMStructs;
+
+  // Helper for mangling unused space in debug builds
+  MutableSpaceMangler* _mangler;
+
  protected:
   HeapWord* _top;
 
+  MutableSpaceMangler* mangler() { return _mangler; }
+
  public:
-  virtual ~MutableSpace()                  {}
-  MutableSpace()                           { _top = NULL;    }
+  virtual ~MutableSpace();
+  MutableSpace();
+
   // Accessors
   HeapWord* top() const                    { return _top;    }
   virtual void set_top(HeapWord* value)    { _top = value;   }
@@ -52,21 +61,30 @@
   MemRegion used_region() { return MemRegion(bottom(), top()); }
 
   // Initialization
-  virtual void initialize(MemRegion mr, bool clear_space);
-  virtual void clear();
+  virtual void initialize(MemRegion mr,
+                          bool clear_space,
+                          bool mangle_space);
+  virtual void clear(bool mangle_space);
+  // Does the usual initialization but optionally resets top to bottom.
+#if 0  // MANGLE_SPACE
+  void initialize(MemRegion mr, bool clear_space, bool reset_top);
+#endif
   virtual void update() { }
   virtual void accumulate_statistics() { }
 
-  // Overwrites the unused portion of this space. Note that some collectors
-  // may use this "scratch" space during collections.
-  virtual void mangle_unused_area() {
-    mangle_region(MemRegion(_top, _end));
-  }
+  // Methods used in mangling.  See descriptions under SpaceMangler.
+  virtual void mangle_unused_area() PRODUCT_RETURN;
+  virtual void mangle_unused_area_complete() PRODUCT_RETURN;
+  virtual void check_mangled_unused_area(HeapWord* limit) PRODUCT_RETURN;
+  virtual void check_mangled_unused_area_complete() PRODUCT_RETURN;
+  virtual void set_top_for_allocations(HeapWord* v) PRODUCT_RETURN;
+
+  // Used to save the space's current top for later use during mangling.
+  virtual void set_top_for_allocations() PRODUCT_RETURN;
+
   virtual void ensure_parsability() { }
 
-  void mangle_region(MemRegion mr) {
-    debug_only(Copy::fill_to_words(mr.start(), mr.word_size(), badHeapWord));
-  }
+  virtual void mangle_region(MemRegion mr) PRODUCT_RETURN;
 
   // Boolean querries.
   bool is_empty() const              { return used_in_words() == 0; }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/gc_implementation/shared/spaceDecorator.cpp	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2002-2005 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+# include "incls/_precompiled.incl"
+# include "incls/_spaceDecorator.cpp.incl"
+
+// Catch-all file for utility classes
+
+#ifndef PRODUCT
+
+// Returns true is the location q matches the mangling
+// pattern.
+bool SpaceMangler::is_mangled(HeapWord* q) {
+  // This test loses precision but is good enough
+  return badHeapWord == (max_juint & (uintptr_t) q->value());
+}
+
+
+void SpaceMangler::set_top_for_allocations(HeapWord* v)  {
+  if (v < end()) {
+    assert(!CheckZapUnusedHeapArea || is_mangled(v),
+      "The high water mark is not mangled");
+  }
+  _top_for_allocations = v;
+}
+
+// Mangle only the unused space that has not previously
+// been mangled and that has not been allocated since being
+// mangled.
+void SpaceMangler::mangle_unused_area() {
+  assert(ZapUnusedHeapArea, "Mangling should not be in use");
+  // Mangle between top and the high water mark.  Safeguard
+  // against the space changing since top_for_allocations was
+  // set.
+  HeapWord* mangled_end = MIN2(top_for_allocations(), end());
+  if (top() < mangled_end) {
+    MemRegion mangle_mr(top(), mangled_end);
+    SpaceMangler::mangle_region(mangle_mr);
+    // Light weight check of mangling.
+    check_mangled_unused_area(end());
+  }
+  // Complete check of unused area which is functional when
+  // DEBUG_MANGLING is defined.
+  check_mangled_unused_area_complete();
+}
+
+// A complete mangle is expected in the
+// exceptional case where top_for_allocations is not
+// properly tracking the high water mark for mangling.
+// This can be the case when to-space is being used for
+// scratch space during a mark-sweep-compact.  See
+// contribute_scratch() and PSMarkSweep::allocate_stacks().
+void SpaceMangler::mangle_unused_area_complete() {
+  assert(ZapUnusedHeapArea, "Mangling should not be in use");
+  MemRegion mangle_mr(top(), end());
+  SpaceMangler::mangle_region(mangle_mr);
+}
+
+// Simply mangle the MemRegion mr.
+void SpaceMangler::mangle_region(MemRegion mr) {
+  assert(ZapUnusedHeapArea, "Mangling should not be in use");
+#ifdef ASSERT
+  if(TraceZapUnusedHeapArea) {
+    gclog_or_tty->print("Mangling [0x%x to 0x%x)", mr.start(), mr.end());
+  }
+  Copy::fill_to_words(mr.start(), mr.word_size(), badHeapWord);
+  if(TraceZapUnusedHeapArea) {
+    gclog_or_tty->print_cr(" done");
+  }
+#endif
+}
+
+// Check that top, top_for_allocations and the last
+// word of the space are mangled.  In a tight memory
+// situation even this light weight mangling could
+// cause paging by touching the end of the space.
+void  SpaceMangler::check_mangled_unused_area(HeapWord* limit) {
+  if (CheckZapUnusedHeapArea) {
+    // This method can be called while the spaces are
+    // being reshaped so skip the test if the end of the
+    // space is beyond the specified limit;
+    if (end() > limit) return;
+
+    assert(top() == end() ||
+           (is_mangled(top())), "Top not mangled");
+    assert((top_for_allocations() < top()) ||
+           (top_for_allocations() >= end()) ||
+           (is_mangled(top_for_allocations())),
+           "Older unused not mangled");
+    assert(top() == end() ||
+           (is_mangled(end() - 1)), "End not properly mangled");
+    // Only does checking when DEBUG_MANGLING is defined.
+    check_mangled_unused_area_complete();
+  }
+}
+
+#undef DEBUG_MANGLING
+// This should only be used while debugging the mangling
+// because of the high cost of checking the completeness.
+void  SpaceMangler::check_mangled_unused_area_complete() {
+  if (CheckZapUnusedHeapArea) {
+    assert(ZapUnusedHeapArea, "Not mangling unused area");
+#ifdef DEBUG_MANGLING
+    HeapWord* q = top();
+    HeapWord* limit = end();
+
+    bool passed = true;
+    while (q < limit) {
+      if (!is_mangled(q)) {
+        passed = false;
+        break;
+      }
+      q++;
+    }
+    assert(passed, "Mangling is not complete");
+#endif
+  }
+}
+#undef DEBUG_MANGLING
+#endif // not PRODUCT
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/gc_implementation/shared/spaceDecorator.hpp	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2002-2005 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+class SpaceDecorator: public AllStatic {
+ public:
+  // Initialization flags.
+  static const bool Clear               = true;
+  static const bool DontClear           = false;
+  static const bool Mangle              = true;
+  static const bool DontMangle          = false;
+};
+
+// Functionality for use with class Space and class MutableSpace.
+//   The approach taken with the mangling is to mangle all
+// the space initially and then to mangle areas that have
+// been allocated since the last collection.  Mangling is
+// done in the context of a generation and in the context
+// of a space.
+//   The space in a generation is mangled when it is first
+// initialized and when the generation grows.  The spaces
+// are not necessarily up-to-date when this mangling occurs
+// and the method mangle_region() is used.
+//   After allocations have been done in a space, the space generally
+// need to be remangled.  Remangling is only done on the
+// recently allocated regions in the space.  Typically, that is
+// the region between the new top and the top just before a
+// garbage collection.
+//   An exception to the usual mangling in a space is done when the
+// space is used for an extraordinary purpose.  Specifically, when
+// to-space is used as scratch space for a mark-sweep-compact
+// collection.
+//   Spaces are mangled after a collection.  If the generation
+// grows after a collection, the added space is mangled as part of
+// the growth of the generation.  No additional mangling is needed when the
+// spaces are resized after an expansion.
+//   The class SpaceMangler keeps a pointer to the top of the allocated
+// area and provides the methods for doing the piece meal mangling.
+// Methods for doing sparces and full checking of the mangling are
+// included.  The full checking is done if DEBUG_MANGLING is defined.
+//   GenSpaceMangler is used with the GenCollectedHeap collectors and
+// MutableSpaceMangler is used with the ParallelScavengeHeap collectors.
+// These subclasses abstract the differences in the types of spaces used
+// by each heap.
+
+class SpaceMangler: public CHeapObj {
+  friend class VMStructs;
+
+  // High water mark for allocations.  Typically, the space above
+  // this point have been mangle previously and don't need to be
+  // touched again.  Space belows this point has been allocated
+  // and remangling is needed between the current top and this
+  // high water mark.
+  HeapWord* _top_for_allocations;
+  HeapWord* top_for_allocations() { return _top_for_allocations; }
+
+ public:
+
+  // Setting _top_for_allocations to NULL at initialization
+  // makes it always below top so that mangling done as part
+  // of the initialize() call of a space does nothing (as it
+  // should since the mangling is done as part of the constructor
+  // for the space.
+  SpaceMangler() : _top_for_allocations(NULL) {}
+
+  // Methods for top and end that delegate to the specific
+  // space type.
+  virtual HeapWord* top() const = 0;
+  virtual HeapWord* end() const = 0;
+
+  // Return true if q matches the mangled pattern.
+  static bool is_mangled(HeapWord* q) PRODUCT_RETURN0;
+
+  // Used to save the an address in a space for later use during mangling.
+  void set_top_for_allocations(HeapWord* v);
+
+  // Overwrites the unused portion of this space.
+  // Mangle only the region not previously mangled [top, top_previously_mangled)
+  void mangle_unused_area();
+  // Mangle all the unused region [top, end)
+  void mangle_unused_area_complete();
+  // Do some sparse checking on the area that should have been mangled.
+  void check_mangled_unused_area(HeapWord* limit) PRODUCT_RETURN;
+  // Do a complete check of the area that should be mangled.
+  void check_mangled_unused_area_complete() PRODUCT_RETURN;
+
+  // Mangle the MemRegion.  This is a non-space specific mangler.  It
+  // is used during the initial mangling of a space before the space
+  // is fully constructed.  Also is used when a generation is expanded
+  // and possibly before the spaces have been reshaped to to the new
+  // size of the generation.
+  static void mangle_region(MemRegion mr);
+};
+
+class ContiguousSpace;
+
+// For use with GenCollectedHeap's
+class GenSpaceMangler: public SpaceMangler {
+  ContiguousSpace* _sp;
+
+  ContiguousSpace* sp() { return _sp; }
+
+  HeapWord* top() const { return _sp->top(); }
+  HeapWord* end() const { return _sp->end(); }
+
+ public:
+  GenSpaceMangler(ContiguousSpace* sp) : SpaceMangler(), _sp(sp) {}
+};
+
+// For use with ParallelScavengeHeap's.
+class MutableSpaceMangler: public SpaceMangler {
+  MutableSpace* _sp;
+
+  MutableSpace* sp() { return _sp; }
+
+  HeapWord* top() const { return _sp->top(); }
+  HeapWord* end() const { return _sp->end(); }
+
+ public:
+  MutableSpaceMangler(MutableSpace* sp) : SpaceMangler(), _sp(sp) {}
+};
--- a/hotspot/src/share/vm/includeDB_core	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/includeDB_core	Wed Jul 05 16:40:29 2017 +0200
@@ -178,6 +178,7 @@
 arguments.cpp                           universe.inline.hpp
 arguments.cpp                           vm_version_<arch_model>.hpp
 
+arguments.hpp                           java.hpp
 arguments.hpp                           perfData.hpp
 arguments.hpp                           top.hpp
 
@@ -1405,6 +1406,7 @@
 defNewGeneration.cpp                    oop.inline.hpp
 defNewGeneration.cpp                    referencePolicy.hpp
 defNewGeneration.cpp                    space.inline.hpp
+defNewGeneration.cpp                    spaceDecorator.hpp
 defNewGeneration.cpp                    thread_<os_family>.inline.hpp
 
 defNewGeneration.hpp                    ageTable.hpp
@@ -1789,6 +1791,7 @@
 generation.cpp                          java.hpp
 generation.cpp                          oop.hpp
 generation.cpp                          oop.inline.hpp
+generation.cpp                          spaceDecorator.hpp
 generation.cpp                          space.inline.hpp
 
 generation.hpp                          allocation.hpp
@@ -3722,6 +3725,7 @@
 space.cpp                               safepoint.hpp
 space.cpp                               space.hpp
 space.cpp                               space.inline.hpp
+space.cpp                               spaceDecorator.hpp
 space.cpp                               systemDictionary.hpp
 space.cpp                               universe.inline.hpp
 space.cpp                               vmSymbols.hpp
@@ -3744,6 +3748,13 @@
 space.inline.hpp                        space.hpp
 space.inline.hpp                        universe.hpp
 
+spaceDecorator.hpp                      globalDefinitions.hpp
+spaceDecorator.hpp                      mutableSpace.hpp
+spaceDecorator.hpp                      space.hpp
+
+spaceDecorator.cpp                      copy.hpp
+spaceDecorator.cpp                      spaceDecorator.hpp
+
 specialized_oop_closures.cpp            ostream.hpp
 specialized_oop_closures.cpp            specialized_oop_closures.hpp
 
--- a/hotspot/src/share/vm/includeDB_features	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/includeDB_features	Wed Jul 05 16:40:29 2017 +0200
@@ -51,6 +51,7 @@
 dump.cpp                                oopFactory.hpp
 dump.cpp                                resourceArea.hpp
 dump.cpp                                signature.hpp
+dump.cpp                                spaceDecorator.hpp
 dump.cpp                                symbolTable.hpp
 dump.cpp                                systemDictionary.hpp
 dump.cpp                                vmThread.hpp
--- a/hotspot/src/share/vm/memory/compactingPermGenGen.cpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/memory/compactingPermGenGen.cpp	Wed Jul 05 16:40:29 2017 +0200
@@ -421,28 +421,6 @@
 }
 
 
-
-bool CompactingPermGenGen::grow_by(size_t bytes) {
-  // Don't allow _virtual_size to expand into shared spaces.
-  size_t max_bytes = _virtual_space.uncommitted_size() - _shared_space_size;
-  if (bytes > _shared_space_size) {
-    bytes = _shared_space_size;
-  }
-  return OneContigSpaceCardGeneration::grow_by(bytes);
-}
-
-
-void CompactingPermGenGen::grow_to_reserved() {
-  // Don't allow _virtual_size to expand into shared spaces.
-  if (_virtual_space.uncommitted_size() > _shared_space_size) {
-    size_t remaining_bytes =
-      _virtual_space.uncommitted_size() - _shared_space_size;
-    bool success = OneContigSpaceCardGeneration::grow_by(remaining_bytes);
-    DEBUG_ONLY(if (!success) warning("grow to reserved failed");)
-  }
-}
-
-
 // No young generation references, clear this generation's main space's
 // card table entries.  Do NOT clear the card table entries for the
 // read-only space (always clear) or the read-write space (valuable
--- a/hotspot/src/share/vm/memory/compactingPermGenGen.hpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/memory/compactingPermGenGen.hpp	Wed Jul 05 16:40:29 2017 +0200
@@ -183,8 +183,6 @@
   void compact();
   void post_compact();
   size_t contiguous_available() const;
-  bool grow_by(size_t bytes);
-  void grow_to_reserved();
 
   void clear_remembered_set();
   void invalidate_remembered_set();
--- a/hotspot/src/share/vm/memory/defNewGeneration.cpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/memory/defNewGeneration.cpp	Wed Jul 05 16:40:29 2017 +0200
@@ -172,15 +172,25 @@
   _to_counters = new CSpaceCounters("s1", 2, _max_survivor_size, _to_space,
                                     _gen_counters);
 
-  compute_space_boundaries(0);
+  compute_space_boundaries(0, SpaceDecorator::Clear, SpaceDecorator::Mangle);
   update_counters();
   _next_gen = NULL;
   _tenuring_threshold = MaxTenuringThreshold;
   _pretenure_size_threshold_words = PretenureSizeThreshold >> LogHeapWordSize;
 }
 
-void DefNewGeneration::compute_space_boundaries(uintx minimum_eden_size) {
-  uintx alignment = GenCollectedHeap::heap()->collector_policy()->min_alignment();
+void DefNewGeneration::compute_space_boundaries(uintx minimum_eden_size,
+                                                bool clear_space,
+                                                bool mangle_space) {
+  uintx alignment =
+    GenCollectedHeap::heap()->collector_policy()->min_alignment();
+
+  // If the spaces are being cleared (only done at heap initialization
+  // currently), the survivor spaces need not be empty.
+  // Otherwise, no care is taken for used areas in the survivor spaces
+  // so check.
+  assert(clear_space || (to()->is_empty() && from()->is_empty()),
+    "Initialization of the survivor spaces assumes these are empty");
 
   // Compute sizes
   uintx size = _virtual_space.committed_size();
@@ -214,16 +224,41 @@
   MemRegion fromMR((HeapWord*)from_start, (HeapWord*)to_start);
   MemRegion toMR  ((HeapWord*)to_start, (HeapWord*)to_end);
 
-  eden()->initialize(edenMR, (minimum_eden_size == 0));
-  // If minumum_eden_size != 0, we will not have cleared any
+  // A minimum eden size implies that there is a part of eden that
+  // is being used and that affects the initialization of any
+  // newly formed eden.
+  bool live_in_eden = minimum_eden_size > 0;
+
+  // If not clearing the spaces, do some checking to verify that
+  // the space are already mangled.
+  if (!clear_space) {
+    // Must check mangling before the spaces are reshaped.  Otherwise,
+    // the bottom or end of one space may have moved into another
+    // a failure of the check may not correctly indicate which space
+    // is not properly mangled.
+    if (ZapUnusedHeapArea) {
+      HeapWord* limit = (HeapWord*) _virtual_space.high();
+      eden()->check_mangled_unused_area(limit);
+      from()->check_mangled_unused_area(limit);
+        to()->check_mangled_unused_area(limit);
+    }
+  }
+
+  // Reset the spaces for their new regions.
+  eden()->initialize(edenMR,
+                     clear_space && !live_in_eden,
+                     SpaceDecorator::Mangle);
+  // If clear_space and live_in_eden, we will not have cleared any
   // portion of eden above its top. This can cause newly
   // expanded space not to be mangled if using ZapUnusedHeapArea.
   // We explicitly do such mangling here.
-  if (ZapUnusedHeapArea && (minimum_eden_size != 0)) {
+  if (ZapUnusedHeapArea && clear_space && live_in_eden && mangle_space) {
     eden()->mangle_unused_area();
   }
-  from()->initialize(fromMR, true);
-    to()->initialize(toMR  , true);
+  from()->initialize(fromMR, clear_space, mangle_space);
+  to()->initialize(toMR, clear_space, mangle_space);
+
+  // Set next compaction spaces.
   eden()->set_next_compaction_space(from());
   // The to-space is normally empty before a compaction so need
   // not be considered.  The exception is during promotion
@@ -250,7 +285,16 @@
 
 bool DefNewGeneration::expand(size_t bytes) {
   MutexLocker x(ExpandHeap_lock);
+  HeapWord* prev_high = (HeapWord*) _virtual_space.high();
   bool success = _virtual_space.expand_by(bytes);
+  if (success && ZapUnusedHeapArea) {
+    // Mangle newly committed space immediately because it
+    // can be done here more simply that after the new
+    // spaces have been computed.
+    HeapWord* new_high = (HeapWord*) _virtual_space.high();
+    MemRegion mangle_region(prev_high, new_high);
+    SpaceMangler::mangle_region(mangle_region);
+  }
 
   // Do not attempt an expand-to-the reserve size.  The
   // request should properly observe the maximum size of
@@ -262,7 +306,8 @@
   // value.
   if (GC_locker::is_active()) {
     if (PrintGC && Verbose) {
-      gclog_or_tty->print_cr("Garbage collection disabled, expanded heap instead");
+      gclog_or_tty->print_cr("Garbage collection disabled, "
+        "expanded heap instead");
     }
   }
 
@@ -326,16 +371,24 @@
     changed = true;
   }
   if (changed) {
-    compute_space_boundaries(eden()->used());
-    MemRegion cmr((HeapWord*)_virtual_space.low(), (HeapWord*)_virtual_space.high());
+    // The spaces have already been mangled at this point but
+    // may not have been cleared (set top = bottom) and should be.
+    // Mangling was done when the heap was being expanded.
+    compute_space_boundaries(eden()->used(),
+                             SpaceDecorator::Clear,
+                             SpaceDecorator::DontMangle);
+    MemRegion cmr((HeapWord*)_virtual_space.low(),
+                  (HeapWord*)_virtual_space.high());
     Universe::heap()->barrier_set()->resize_covered_region(cmr);
     if (Verbose && PrintGC) {
       size_t new_size_after  = _virtual_space.committed_size();
       size_t eden_size_after = eden()->capacity();
       size_t survivor_size_after = from()->capacity();
-      gclog_or_tty->print("New generation size " SIZE_FORMAT "K->" SIZE_FORMAT "K [eden="
+      gclog_or_tty->print("New generation size " SIZE_FORMAT "K->"
+        SIZE_FORMAT "K [eden="
         SIZE_FORMAT "K,survivor=" SIZE_FORMAT "K]",
-        new_size_before/K, new_size_after/K, eden_size_after/K, survivor_size_after/K);
+        new_size_before/K, new_size_after/K,
+        eden_size_after/K, survivor_size_after/K);
       if (WizardMode) {
         gclog_or_tty->print("[allowed " SIZE_FORMAT "K extra for %d threads]",
           thread_increase_size/K, threads_count);
@@ -480,7 +533,7 @@
   ScanWeakRefClosure scan_weak_ref(this);
 
   age_table()->clear();
-  to()->clear();
+  to()->clear(SpaceDecorator::Mangle);
 
   gch->rem_set()->prepare_for_younger_refs_iterate(false);
 
@@ -525,8 +578,18 @@
     soft_ref_policy, &is_alive, &keep_alive, &evacuate_followers, NULL);
   if (!promotion_failed()) {
     // Swap the survivor spaces.
-    eden()->clear();
-    from()->clear();
+    eden()->clear(SpaceDecorator::Mangle);
+    from()->clear(SpaceDecorator::Mangle);
+    if (ZapUnusedHeapArea) {
+      // This is now done here because of the piece-meal mangling which
+      // can check for valid mangling at intermediate points in the
+      // collection(s).  When a minor collection fails to collect
+      // sufficient space resizing of the young generation can occur
+      // an redistribute the spaces in the young generation.  Mangle
+      // here so that unzapped regions don't get distributed to
+      // other spaces.
+      to()->mangle_unused_area();
+    }
     swap_spaces();
 
     assert(to()->is_empty(), "to space should be empty now");
@@ -753,6 +816,15 @@
   }
 }
 
+void DefNewGeneration::reset_scratch() {
+  // If contributing scratch in to_space, mangle all of
+  // to_space if ZapUnusedHeapArea.  This is needed because
+  // top is not maintained while using to-space as scratch.
+  if (ZapUnusedHeapArea) {
+    to()->mangle_unused_area_complete();
+  }
+}
+
 bool DefNewGeneration::collection_attempt_is_safe() {
   if (!to()->is_empty()) {
     return false;
@@ -806,11 +878,25 @@
     }
   }
 
+  if (ZapUnusedHeapArea) {
+    eden()->check_mangled_unused_area_complete();
+    from()->check_mangled_unused_area_complete();
+    to()->check_mangled_unused_area_complete();
+  }
+
   // update the generation and space performance counters
   update_counters();
   gch->collector_policy()->counters()->update_counters();
 }
 
+void DefNewGeneration::record_spaces_top() {
+  assert(ZapUnusedHeapArea, "Not mangling unused space");
+  eden()->set_top_for_allocations();
+  to()->set_top_for_allocations();
+  from()->set_top_for_allocations();
+}
+
+
 void DefNewGeneration::update_counters() {
   if (UsePerfData) {
     _eden_counters->update_all();
--- a/hotspot/src/share/vm/memory/defNewGeneration.hpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/memory/defNewGeneration.hpp	Wed Jul 05 16:40:29 2017 +0200
@@ -279,6 +279,9 @@
   virtual void gc_prologue(bool full);
   virtual void gc_epilogue(bool full);
 
+  // Save the tops for eden, from, and to
+  virtual void record_spaces_top();
+
   // Doesn't require additional work during GC prologue and epilogue
   virtual bool performs_in_place_marking() const { return false; }
 
@@ -299,9 +302,12 @@
 
   // For non-youngest collection, the DefNewGeneration can contribute
   // "to-space".
-  void contribute_scratch(ScratchBlock*& list, Generation* requestor,
+  virtual void contribute_scratch(ScratchBlock*& list, Generation* requestor,
                           size_t max_alloc_words);
 
+  // Reset for contribution of "to-space".
+  virtual void reset_scratch();
+
   // GC support
   virtual void compute_new_size();
   virtual void collect(bool   full,
@@ -331,7 +337,12 @@
   void verify(bool allow_dirty);
 
  protected:
-  void compute_space_boundaries(uintx minimum_eden_size);
+  // If clear_space is true, clear the survivor spaces.  Eden is
+  // cleared if the minimum size of eden is 0.  If mangle_space
+  // is true, also mangle the space in debug mode.
+  void compute_space_boundaries(uintx minimum_eden_size,
+                                bool clear_space,
+                                bool mangle_space);
   // Scavenge support
   void swap_spaces();
 };
--- a/hotspot/src/share/vm/memory/dump.cpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/memory/dump.cpp	Wed Jul 05 16:40:29 2017 +0200
@@ -645,7 +645,7 @@
 class ClearSpaceClosure : public SpaceClosure {
 public:
   void do_space(Space* s) {
-    s->clear();
+    s->clear(SpaceDecorator::Mangle);
   }
 };
 
@@ -1200,10 +1200,12 @@
     mapinfo->write_space(CompactingPermGenGen::rw, _rw_space, false);
     _rw_space->set_saved_mark();
     mapinfo->write_region(CompactingPermGenGen::md, _md_vs->low(),
-                          md_top - _md_vs->low(), SharedMiscDataSize,
+                          pointer_delta(md_top, _md_vs->low(), sizeof(char)),
+                          SharedMiscDataSize,
                           false, false);
     mapinfo->write_region(CompactingPermGenGen::mc, _mc_vs->low(),
-                          mc_top - _mc_vs->low(), SharedMiscCodeSize,
+                          pointer_delta(mc_top, _mc_vs->low(), sizeof(char)),
+                          SharedMiscCodeSize,
                           true, true);
 
     // Pass 2 - write data.
@@ -1212,10 +1214,12 @@
     mapinfo->write_space(CompactingPermGenGen::ro, _ro_space, true);
     mapinfo->write_space(CompactingPermGenGen::rw, _rw_space, false);
     mapinfo->write_region(CompactingPermGenGen::md, _md_vs->low(),
-                          md_top - _md_vs->low(), SharedMiscDataSize,
+                          pointer_delta(md_top, _md_vs->low(), sizeof(char)),
+                          SharedMiscDataSize,
                           false, false);
     mapinfo->write_region(CompactingPermGenGen::mc, _mc_vs->low(),
-                          mc_top - _mc_vs->low(), SharedMiscCodeSize,
+                          pointer_delta(mc_top, _mc_vs->low(), sizeof(char)),
+                          SharedMiscCodeSize,
                           true, true);
     mapinfo->close();
 
--- a/hotspot/src/share/vm/memory/genCollectedHeap.cpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/memory/genCollectedHeap.cpp	Wed Jul 05 16:40:29 2017 +0200
@@ -465,6 +465,11 @@
         _gens[i]->stat_record()->invocations++;
         _gens[i]->stat_record()->accumulated_time.start();
 
+        // Must be done anew before each collection because
+        // a previous collection will do mangling and will
+        // change top of some spaces.
+        record_gen_tops_before_GC();
+
         if (PrintGC && Verbose) {
           gclog_or_tty->print("level=%d invoke=%d size=" SIZE_FORMAT,
                      i,
@@ -1058,6 +1063,12 @@
   return res;
 }
 
+void GenCollectedHeap::release_scratch() {
+  for (int i = 0; i < _n_gens; i++) {
+    _gens[i]->reset_scratch();
+  }
+}
+
 size_t GenCollectedHeap::large_typearray_limit() {
   return gen_policy()->large_typearray_limit();
 }
@@ -1285,6 +1296,24 @@
   always_do_update_barrier = UseConcMarkSweepGC;
 };
 
+#ifndef PRODUCT
+class GenGCSaveTopsBeforeGCClosure: public GenCollectedHeap::GenClosure {
+ private:
+ public:
+  void do_generation(Generation* gen) {
+    gen->record_spaces_top();
+  }
+};
+
+void GenCollectedHeap::record_gen_tops_before_GC() {
+  if (ZapUnusedHeapArea) {
+    GenGCSaveTopsBeforeGCClosure blk;
+    generation_iterate(&blk, false);  // not old-to-young.
+    perm_gen()->record_spaces_top();
+  }
+}
+#endif  // not PRODUCT
+
 class GenEnsureParsabilityClosure: public GenCollectedHeap::GenClosure {
  public:
   void do_generation(Generation* gen) {
--- a/hotspot/src/share/vm/memory/genCollectedHeap.hpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/memory/genCollectedHeap.hpp	Wed Jul 05 16:40:29 2017 +0200
@@ -259,6 +259,9 @@
   // be provided are returned as a list of ScratchBlocks, sorted by
   // decreasing size.
   ScratchBlock* gather_scratch(Generation* requestor, size_t max_alloc_words);
+  // Allow each generation to reset any scratch space that it has
+  // contributed as it needs.
+  void release_scratch();
 
   size_t large_typearray_limit();
 
@@ -482,6 +485,9 @@
   bool should_do_concurrent_full_gc(GCCause::Cause cause);
   void collect_mostly_concurrent(GCCause::Cause cause);
 
+  // Save the tops of the spaces in all generations
+  void record_gen_tops_before_GC() PRODUCT_RETURN;
+
 protected:
   virtual void gc_prologue(bool full);
   virtual void gc_epilogue(bool full);
--- a/hotspot/src/share/vm/memory/genMarkSweep.cpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/memory/genMarkSweep.cpp	Wed Jul 05 16:40:29 2017 +0200
@@ -190,6 +190,10 @@
 
 
 void GenMarkSweep::deallocate_stacks() {
+
+  GenCollectedHeap* gch = GenCollectedHeap::heap();
+  gch->release_scratch();
+
   if (_preserved_oop_stack) {
     delete _preserved_mark_stack;
     _preserved_mark_stack = NULL;
--- a/hotspot/src/share/vm/memory/generation.cpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/memory/generation.cpp	Wed Jul 05 16:40:29 2017 +0200
@@ -32,6 +32,12 @@
     vm_exit_during_initialization("Could not reserve enough space for "
                     "object heap");
   }
+  // Mangle all of the the initial generation.
+  if (ZapUnusedHeapArea) {
+    MemRegion mangle_region((HeapWord*)_virtual_space.low(),
+      (HeapWord*)_virtual_space.high());
+    SpaceMangler::mangle_region(mangle_region);
+  }
   _reserved = MemRegion((HeapWord*)_virtual_space.low_boundary(),
           (HeapWord*)_virtual_space.high_boundary());
 }
@@ -373,6 +379,41 @@
   }
 }
 
+bool CardGeneration::expand(size_t bytes, size_t expand_bytes) {
+  assert_locked_or_safepoint(Heap_lock);
+  if (bytes == 0) {
+    return true;  // That's what grow_by(0) would return
+  }
+  size_t aligned_bytes  = ReservedSpace::page_align_size_up(bytes);
+  if (aligned_bytes == 0){
+    // The alignment caused the number of bytes to wrap.  An expand_by(0) will
+    // return true with the implication that an expansion was done when it
+    // was not.  A call to expand implies a best effort to expand by "bytes"
+    // but not a guarantee.  Align down to give a best effort.  This is likely
+    // the most that the generation can expand since it has some capacity to
+    // start with.
+    aligned_bytes = ReservedSpace::page_align_size_down(bytes);
+  }
+  size_t aligned_expand_bytes = ReservedSpace::page_align_size_up(expand_bytes);
+  bool success = false;
+  if (aligned_expand_bytes > aligned_bytes) {
+    success = grow_by(aligned_expand_bytes);
+  }
+  if (!success) {
+    success = grow_by(aligned_bytes);
+  }
+  if (!success) {
+    success = grow_to_reserved();
+  }
+  if (PrintGC && Verbose) {
+    if (success && GC_locker::is_active()) {
+      gclog_or_tty->print_cr("Garbage collection disabled, expanded heap instead");
+    }
+  }
+
+  return success;
+}
+
 
 // No young generation references, clear this generation's cards.
 void CardGeneration::clear_remembered_set() {
@@ -435,25 +476,9 @@
   }
 }
 
-void OneContigSpaceCardGeneration::expand(size_t bytes, size_t expand_bytes) {
+bool OneContigSpaceCardGeneration::expand(size_t bytes, size_t expand_bytes) {
   GCMutexLocker x(ExpandHeap_lock);
-  size_t aligned_bytes  = ReservedSpace::page_align_size_up(bytes);
-  size_t aligned_expand_bytes = ReservedSpace::page_align_size_up(expand_bytes);
-  bool success = false;
-  if (aligned_expand_bytes > aligned_bytes) {
-    success = grow_by(aligned_expand_bytes);
-  }
-  if (!success) {
-    success = grow_by(aligned_bytes);
-  }
-  if (!success) {
-    grow_to_reserved();
-  }
-  if (GC_locker::is_active()) {
-    if (PrintGC && Verbose) {
-      gclog_or_tty->print_cr("Garbage collection disabled, expanded heap instead");
-    }
-  }
+  return CardGeneration::expand(bytes, expand_bytes);
 }
 
 
@@ -505,8 +530,11 @@
     _bts->resize(new_word_size);
 
     // Fix for bug #4668531
-    MemRegion mangle_region(_the_space->end(), (HeapWord*)_virtual_space.high());
-    _the_space->mangle_region(mangle_region);
+    if (ZapUnusedHeapArea) {
+      MemRegion mangle_region(_the_space->end(),
+      (HeapWord*)_virtual_space.high());
+      SpaceMangler::mangle_region(mangle_region);
+    }
 
     // Expand space -- also expands space's BOT
     // (which uses (part of) shared array above)
@@ -622,6 +650,14 @@
 
   // update the generation and space performance counters
   update_counters();
+  if (ZapUnusedHeapArea) {
+    the_space()->check_mangled_unused_area_complete();
+  }
+}
+
+void OneContigSpaceCardGeneration::record_spaces_top() {
+  assert(ZapUnusedHeapArea, "Not mangling unused space");
+  the_space()->set_top_for_allocations();
 }
 
 void OneContigSpaceCardGeneration::verify(bool allow_dirty) {
--- a/hotspot/src/share/vm/memory/generation.hpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/memory/generation.hpp	Wed Jul 05 16:40:29 2017 +0200
@@ -376,6 +376,9 @@
   // The default is to do nothing.
   virtual void gc_epilogue(bool full) {};
 
+  // Save the high water marks for the used space in a generation.
+  virtual void record_spaces_top() {};
+
   // Some generations may need to be "fixed-up" after some allocation
   // activity to make them parsable again. The default is to do nothing.
   virtual void ensure_parsability() {};
@@ -476,6 +479,10 @@
   virtual void contribute_scratch(ScratchBlock*& list, Generation* requestor,
                                   size_t max_alloc_words) {}
 
+  // Give each generation an opportunity to do clean up for any
+  // contributed scratch.
+  virtual void reset_scratch() {};
+
   // When an older generation has been collected, and perhaps resized,
   // this method will be invoked on all younger generations (from older to
   // younger), allowing them to resize themselves as appropriate.
@@ -599,11 +606,21 @@
 
  public:
 
+  // Attempt to expand the generation by "bytes".  Expand by at a
+  // minimum "expand_bytes".  Return true if some amount (not
+  // necessarily the full "bytes") was done.
+  virtual bool expand(size_t bytes, size_t expand_bytes);
+
   virtual void clear_remembered_set();
 
   virtual void invalidate_remembered_set();
 
   virtual void prepare_for_verify();
+
+  // Grow generation with specified size (returns false if unable to grow)
+  virtual bool grow_by(size_t bytes) = 0;
+  // Grow generation to reserved size.
+  virtual bool grow_to_reserved() = 0;
 };
 
 // OneContigSpaceCardGeneration models a heap of old objects contained in a single
@@ -624,14 +641,14 @@
                                       // and after last GC.
 
   // Grow generation with specified size (returns false if unable to grow)
-  bool grow_by(size_t bytes);
+  virtual bool grow_by(size_t bytes);
   // Grow generation to reserved size.
-  bool grow_to_reserved();
+  virtual bool grow_to_reserved();
   // Shrink generation with specified size (returns false if unable to shrink)
   void shrink_by(size_t bytes);
 
   // Allocation failure
-  void expand(size_t bytes, size_t expand_bytes);
+  virtual bool expand(size_t bytes, size_t expand_bytes);
   void shrink(size_t bytes);
 
   // Accessing spaces
@@ -699,6 +716,8 @@
 
   virtual void gc_epilogue(bool full);
 
+  virtual void record_spaces_top();
+
   virtual void verify(bool allow_dirty);
   virtual void print_on(outputStream* st) const;
 };
--- a/hotspot/src/share/vm/memory/space.cpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/memory/space.cpp	Wed Jul 05 16:40:29 2017 +0200
@@ -232,30 +232,44 @@
   return new ContiguousSpaceDCTOC(this, cl, precision, boundary);
 }
 
-void Space::initialize(MemRegion mr, bool clear_space) {
+void Space::initialize(MemRegion mr,
+                       bool clear_space,
+                       bool mangle_space) {
   HeapWord* bottom = mr.start();
   HeapWord* end    = mr.end();
   assert(Universe::on_page_boundary(bottom) && Universe::on_page_boundary(end),
          "invalid space boundaries");
   set_bottom(bottom);
   set_end(end);
-  if (clear_space) clear();
+  if (clear_space) clear(mangle_space);
+}
+
+void Space::clear(bool mangle_space) {
+  if (ZapUnusedHeapArea && mangle_space) {
+    mangle_unused_area();
+  }
 }
 
-void Space::clear() {
-  if (ZapUnusedHeapArea) mangle_unused_area();
+ContiguousSpace::ContiguousSpace(): CompactibleSpace(), _top(NULL) {
+  _mangler = new GenSpaceMangler(this);
 }
 
-void ContiguousSpace::initialize(MemRegion mr, bool clear_space)
+ContiguousSpace::~ContiguousSpace() {
+  delete _mangler;
+}
+
+void ContiguousSpace::initialize(MemRegion mr,
+                                 bool clear_space,
+                                 bool mangle_space)
 {
-  CompactibleSpace::initialize(mr, clear_space);
+  CompactibleSpace::initialize(mr, clear_space, mangle_space);
   _concurrent_iteration_safe_limit = top();
 }
 
-void ContiguousSpace::clear() {
+void ContiguousSpace::clear(bool mangle_space) {
   set_top(bottom());
   set_saved_mark();
-  Space::clear();
+  Space::clear(mangle_space);
 }
 
 bool Space::is_in(const void* p) const {
@@ -271,8 +285,8 @@
   return p >= _top;
 }
 
-void OffsetTableContigSpace::clear() {
-  ContiguousSpace::clear();
+void OffsetTableContigSpace::clear(bool mangle_space) {
+  ContiguousSpace::clear(mangle_space);
   _offsets.initialize_threshold();
 }
 
@@ -288,17 +302,46 @@
   Space::set_end(new_end);
 }
 
-void ContiguousSpace::mangle_unused_area() {
-  // to-space is used for storing marks during mark-sweep
-  mangle_region(MemRegion(top(), end()));
+#ifndef PRODUCT
+
+void ContiguousSpace::set_top_for_allocations(HeapWord* v) {
+  mangler()->set_top_for_allocations(v);
+}
+void ContiguousSpace::set_top_for_allocations() {
+  mangler()->set_top_for_allocations(top());
+}
+void ContiguousSpace::check_mangled_unused_area(HeapWord* limit) {
+  mangler()->check_mangled_unused_area(limit);
+}
+
+void ContiguousSpace::check_mangled_unused_area_complete() {
+  mangler()->check_mangled_unused_area_complete();
 }
 
-void ContiguousSpace::mangle_region(MemRegion mr) {
-  debug_only(Copy::fill_to_words(mr.start(), mr.word_size(), badHeapWord));
+// Mangled only the unused space that has not previously
+// been mangled and that has not been allocated since being
+// mangled.
+void ContiguousSpace::mangle_unused_area() {
+  mangler()->mangle_unused_area();
+}
+void ContiguousSpace::mangle_unused_area_complete() {
+  mangler()->mangle_unused_area_complete();
 }
+void ContiguousSpace::mangle_region(MemRegion mr) {
+  // Although this method uses SpaceMangler::mangle_region() which
+  // is not specific to a space, the when the ContiguousSpace version
+  // is called, it is always with regard to a space and this
+  // bounds checking is appropriate.
+  MemRegion space_mr(bottom(), end());
+  assert(space_mr.contains(mr), "Mangling outside space");
+  SpaceMangler::mangle_region(mr);
+}
+#endif  // NOT_PRODUCT
 
-void CompactibleSpace::initialize(MemRegion mr, bool clear_space) {
-  Space::initialize(mr, clear_space);
+void CompactibleSpace::initialize(MemRegion mr,
+                                  bool clear_space,
+                                  bool mangle_space) {
+  Space::initialize(mr, clear_space, mangle_space);
   _compaction_top = bottom();
   _next_compaction_space = NULL;
 }
@@ -820,8 +863,8 @@
   }
 }
 
-void EdenSpace::clear() {
-  ContiguousSpace::clear();
+void EdenSpace::clear(bool mangle_space) {
+  ContiguousSpace::clear(mangle_space);
   set_soft_end(end());
 }
 
@@ -878,7 +921,7 @@
   _par_alloc_lock(Mutex::leaf, "OffsetTableContigSpace par alloc lock", true)
 {
   _offsets.set_contig_space(this);
-  initialize(mr, true);
+  initialize(mr, SpaceDecorator::Clear, SpaceDecorator::Mangle);
 }
 
 
--- a/hotspot/src/share/vm/memory/space.hpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/memory/space.hpp	Wed Jul 05 16:40:29 2017 +0200
@@ -131,15 +131,17 @@
     return MemRegion(bottom(), saved_mark_word());
   }
 
-  // Initialization
-  virtual void initialize(MemRegion mr, bool clear_space);
-  virtual void clear();
+  // Initialization.  These may be run to reset an existing
+  // Space.
+  virtual void initialize(MemRegion mr, bool clear_space, bool mangle_space);
+  virtual void clear(bool mangle_space);
 
   // For detecting GC bugs.  Should only be called at GC boundaries, since
   // some unused space may be used as scratch space during GC's.
   // Default implementation does nothing. We also call this when expanding
   // a space to satisfy an allocation request. See bug #4668531
   virtual void mangle_unused_area() {}
+  virtual void mangle_unused_area_complete() {}
   virtual void mangle_region(MemRegion mr) {}
 
   // Testers
@@ -354,7 +356,7 @@
   CompactibleSpace* _next_compaction_space;
 
 public:
-  virtual void initialize(MemRegion mr, bool clear_space);
+  virtual void initialize(MemRegion mr, bool clear_space, bool mangle_space);
 
   // Used temporarily during a compaction phase to hold the value
   // top should have when compaction is complete.
@@ -724,12 +726,14 @@
   /* continuously, but those that weren't need to have their thresholds */      \
   /* re-initialized.  Also mangles unused area for debugging.           */      \
   if (is_empty()) {                                                             \
-    clear();                                                                    \
+    clear(SpaceDecorator::Mangle);                                              \
   } else {                                                                      \
     if (ZapUnusedHeapArea) mangle_unused_area();                                \
   }                                                                             \
 }
 
+class GenSpaceMangler;
+
 // A space in which the free area is contiguous.  It therefore supports
 // faster allocation, and compaction.
 class ContiguousSpace: public CompactibleSpace {
@@ -738,13 +742,21 @@
  protected:
   HeapWord* _top;
   HeapWord* _concurrent_iteration_safe_limit;
+  // A helper for mangling the unused area of the space in debug builds.
+  GenSpaceMangler* _mangler;
+
+  GenSpaceMangler* mangler() { return _mangler; }
 
   // Allocation helpers (return NULL if full).
   inline HeapWord* allocate_impl(size_t word_size, HeapWord* end_value);
   inline HeapWord* par_allocate_impl(size_t word_size, HeapWord* end_value);
 
  public:
-  virtual void initialize(MemRegion mr, bool clear_space);
+
+  ContiguousSpace();
+  ~ContiguousSpace();
+
+  virtual void initialize(MemRegion mr, bool clear_space, bool mangle_space);
 
   // Accessors
   HeapWord* top() const            { return _top;    }
@@ -753,15 +765,34 @@
   void set_saved_mark()       { _saved_mark_word = top();    }
   void reset_saved_mark()     { _saved_mark_word = bottom(); }
 
-  virtual void clear();
+  virtual void clear(bool mangle_space);
 
   WaterMark bottom_mark()     { return WaterMark(this, bottom()); }
   WaterMark top_mark()        { return WaterMark(this, top()); }
   WaterMark saved_mark()      { return WaterMark(this, saved_mark_word()); }
   bool saved_mark_at_top() const { return saved_mark_word() == top(); }
 
-  void mangle_unused_area();
-  void mangle_region(MemRegion mr);
+  // In debug mode mangle (write it with a particular bit
+  // pattern) the unused part of a space.
+
+  // Used to save the an address in a space for later use during mangling.
+  void set_top_for_allocations(HeapWord* v) PRODUCT_RETURN;
+  // Used to save the space's current top for later use during mangling.
+  void set_top_for_allocations() PRODUCT_RETURN;
+
+  // Mangle regions in the space from the current top up to the
+  // previously mangled part of the space.
+  void mangle_unused_area() PRODUCT_RETURN;
+  // Mangle [top, end)
+  void mangle_unused_area_complete() PRODUCT_RETURN;
+  // Mangle the given MemRegion.
+  void mangle_region(MemRegion mr) PRODUCT_RETURN;
+
+  // Do some sparse checking on the area that should have been mangled.
+  void check_mangled_unused_area(HeapWord* limit) PRODUCT_RETURN;
+  // Check the complete area that should have been mangled.
+  // This code may be NULL depending on the macro DEBUG_MANGLING.
+  void check_mangled_unused_area_complete() PRODUCT_RETURN;
 
   // Size computations: sizes in bytes.
   size_t capacity() const        { return byte_size(bottom(), end()); }
@@ -956,7 +987,7 @@
   void set_soft_end(HeapWord* value) { _soft_end = value; }
 
   // Override.
-  void clear();
+  void clear(bool mangle_space);
 
   // Set both the 'hard' and 'soft' limits (_end and _soft_end).
   void set_end(HeapWord* value) {
@@ -1000,7 +1031,7 @@
   void set_bottom(HeapWord* value);
   void set_end(HeapWord* value);
 
-  void clear();
+  void clear(bool mangle_space);
 
   inline HeapWord* block_start(const void* p) const;
 
--- a/hotspot/src/share/vm/memory/universe.cpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/memory/universe.cpp	Wed Jul 05 16:40:29 2017 +0200
@@ -367,26 +367,31 @@
   // Only 1.3 or later has the java.lang.Shutdown class.
   // Only 1.4 or later has the java.lang.CharSequence interface.
   // Only 1.5 or later has the java.lang.management.MemoryUsage class.
-  if (JDK_Version::is_pre_jdk16_version()) {
-    klassOop k = SystemDictionary::resolve_or_null(vmSymbolHandles::java_lang_management_MemoryUsage(), THREAD);
+  if (JDK_Version::is_partially_initialized()) {
+    uint8_t jdk_version;
+    klassOop k = SystemDictionary::resolve_or_null(
+        vmSymbolHandles::java_lang_management_MemoryUsage(), THREAD);
     CLEAR_PENDING_EXCEPTION; // ignore exceptions
     if (k == NULL) {
-      k = SystemDictionary::resolve_or_null(vmSymbolHandles::java_lang_CharSequence(), THREAD);
+      k = SystemDictionary::resolve_or_null(
+          vmSymbolHandles::java_lang_CharSequence(), THREAD);
       CLEAR_PENDING_EXCEPTION; // ignore exceptions
       if (k == NULL) {
-        k = SystemDictionary::resolve_or_null(vmSymbolHandles::java_lang_Shutdown(), THREAD);
+        k = SystemDictionary::resolve_or_null(
+            vmSymbolHandles::java_lang_Shutdown(), THREAD);
         CLEAR_PENDING_EXCEPTION; // ignore exceptions
         if (k == NULL) {
-          JDK_Version::set_jdk12x_version();
+          jdk_version = 2;
         } else {
-          JDK_Version::set_jdk13x_version();
+          jdk_version = 3;
         }
       } else {
-          JDK_Version::set_jdk14x_version();
+        jdk_version = 4;
       }
     } else {
-          JDK_Version::set_jdk15x_version();
+      jdk_version = 5;
     }
+    JDK_Version::fully_initialize(jdk_version);
   }
 
   #ifdef ASSERT
--- a/hotspot/src/share/vm/opto/bytecodeInfo.cpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/opto/bytecodeInfo.cpp	Wed Jul 05 16:40:29 2017 +0200
@@ -83,7 +83,7 @@
                             ciMethod* caller_method, Compile* C) {
   // True when EA is ON and a java constructor is called or
   // a super constructor is called from an inlined java constructor.
-  return DoEscapeAnalysis && EliminateAllocations &&
+  return C->do_escape_analysis() && EliminateAllocations &&
          ( callee_method->is_initializer() ||
            (caller_method->is_initializer() &&
             caller_method != C->method() &&
--- a/hotspot/src/share/vm/opto/c2_globals.hpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/opto/c2_globals.hpp	Wed Jul 05 16:40:29 2017 +0200
@@ -388,6 +388,9 @@
   product(intx, EliminateAllocationArraySizeLimit, 64,                      \
           "Array size (number of elements) limit for scalar replacement")   \
                                                                             \
+  product(intx, ValueSearchLimit, 1000,                                     \
+          "Recursion limit in PhaseMacroExpand::value_from_mem_phi")        \
+                                                                            \
   product(intx, MaxLabelRootDepth, 1100,                                    \
           "Maximum times call Label_Root to prevent stack overflow")        \
                                                                             \
--- a/hotspot/src/share/vm/opto/callnode.cpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/opto/callnode.cpp	Wed Jul 05 16:40:29 2017 +0200
@@ -631,61 +631,13 @@
 bool CallNode::may_modify(const TypePtr *addr_t, PhaseTransform *phase) {
   const TypeOopPtr *adrInst_t  = addr_t->isa_oopptr();
 
-  // if not an InstPtr or not an instance type, assume the worst
-  if (adrInst_t == NULL || !adrInst_t->is_known_instance_field()) {
+  // If not an OopPtr or not an instance type, assume the worst.
+  // Note: currently this method is called only for instance types.
+  if (adrInst_t == NULL || !adrInst_t->is_known_instance()) {
     return true;
   }
-  Compile *C = phase->C;
-  int offset = adrInst_t->offset();
-  assert(adrInst_t->klass_is_exact() && offset >= 0, "should be valid offset");
-  ciKlass* adr_k = adrInst_t->klass();
-  assert(adr_k->is_loaded() &&
-         adr_k->is_java_klass() &&
-         !adr_k->is_interface(),
-         "only non-abstract classes are expected");
-
-  int base_idx = C->get_alias_index(adrInst_t);
-  int size = BytesPerLong; // If we don't know the size, assume largest.
-  if (adrInst_t->isa_instptr()) {
-    ciField* field = C->alias_type(base_idx)->field();
-    if (field != NULL) {
-      size = field->size_in_bytes();
-    }
-  } else {
-    assert(adrInst_t->isa_aryptr(), "only arrays are expected");
-    size = type2aelembytes(adr_k->as_array_klass()->element_type()->basic_type());
-  }
-
-  ciMethod * meth = is_CallStaticJava() ?  as_CallStaticJava()->method() : NULL;
-  BCEscapeAnalyzer *bcea = (meth != NULL) ? meth->get_bcea() : NULL;
-
-  const TypeTuple * d = tf()->domain();
-  for (uint i = TypeFunc::Parms; i < d->cnt(); i++) {
-    const Type* t = d->field_at(i);
-    Node *arg = in(i);
-    const Type *at = phase->type(arg);
-    if (at == TypePtr::NULL_PTR || at == Type::TOP)
-      continue;  // null can't affect anything
-
-    const TypeOopPtr *at_ptr = at->isa_oopptr();
-    if (!arg->is_top() && (t->isa_oopptr() != NULL ||
-                           t->isa_ptr() && at_ptr != NULL)) {
-      assert(at_ptr != NULL, "expecting an OopPtr");
-      ciKlass* at_k = at_ptr->klass();
-      if ((adrInst_t->base() == at_ptr->base()) &&
-          at_k->is_loaded() &&
-          at_k->is_java_klass()) {
-        // If we have found an argument matching addr_t, check if the field
-        // at the specified offset is modified.
-        if ((at_k->is_interface() || adr_k == at_k ||
-             adr_k->is_subclass_of(at_k) && !at_ptr->klass_is_exact()) &&
-            (bcea == NULL ||
-             bcea->is_arg_modified(i - TypeFunc::Parms, offset, size))) {
-          return true;
-        }
-      }
-    }
-  }
+  // The instance_id is set only for scalar-replaceable allocations which
+  // are not passed as arguments according to Escape Analysis.
   return false;
 }
 
--- a/hotspot/src/share/vm/opto/cfgnode.cpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/opto/cfgnode.cpp	Wed Jul 05 16:40:29 2017 +0200
@@ -713,7 +713,9 @@
   assert(type() == Type::MEMORY &&
          (t == TypePtr::BOTTOM || t == TypeRawPtr::BOTTOM ||
           t->isa_oopptr() && !t->is_oopptr()->is_known_instance() &&
-          t->is_oopptr()->cast_to_instance_id(t_oop->instance_id()) == t_oop),
+          t->is_oopptr()->cast_to_exactness(true)
+           ->is_oopptr()->cast_to_ptr_type(t_oop->ptr())
+           ->is_oopptr()->cast_to_instance_id(t_oop->instance_id()) == t_oop),
          "bottom or raw memory required");
 
   // Check if an appropriate node already exists.
@@ -1089,6 +1091,8 @@
     if (rc == NULL || phase->type(rc) == Type::TOP)
       continue;                 // ignore unreachable control path
     Node* n = in(i);
+    if (n == NULL)
+      continue;
     Node* un = n->uncast();
     if (un == NULL || un == this || phase->type(un) == Type::TOP) {
       continue; // ignore if top, or in(i) and "this" are in a data cycle
--- a/hotspot/src/share/vm/opto/compile.cpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/opto/compile.cpp	Wed Jul 05 16:40:29 2017 +0200
@@ -583,18 +583,32 @@
   NOT_PRODUCT( verify_graph_edges(); )
 
   // Perform escape analysis
-  if (_do_escape_analysis)
-    _congraph = new ConnectionGraph(this);
-  if (_congraph != NULL) {
-    NOT_PRODUCT( TracePhase t2("escapeAnalysis", &_t_escapeAnalysis, TimeCompiler); )
-    _congraph->compute_escape();
-    if (failing())  return;
+  if (_do_escape_analysis && ConnectionGraph::has_candidates(this)) {
+    TracePhase t2("escapeAnalysis", &_t_escapeAnalysis, true);
+    // Add ConP#NULL and ConN#NULL nodes before ConnectionGraph construction.
+    PhaseGVN* igvn = initial_gvn();
+    Node* oop_null = igvn->zerocon(T_OBJECT);
+    Node* noop_null = igvn->zerocon(T_NARROWOOP);
+
+    _congraph = new(comp_arena()) ConnectionGraph(this);
+    bool has_non_escaping_obj = _congraph->compute_escape();
 
 #ifndef PRODUCT
     if (PrintEscapeAnalysis) {
       _congraph->dump();
     }
 #endif
+    // Cleanup.
+    if (oop_null->outcnt() == 0)
+      igvn->hash_delete(oop_null);
+    if (noop_null->outcnt() == 0)
+      igvn->hash_delete(noop_null);
+
+    if (!has_non_escaping_obj) {
+      _congraph = NULL;
+    }
+
+    if (failing())  return;
   }
   // Now optimize
   Optimize();
@@ -995,9 +1009,14 @@
   int offset = tj->offset();
   TypePtr::PTR ptr = tj->ptr();
 
+  // Known instance (scalarizable allocation) alias only with itself.
+  bool is_known_inst = tj->isa_oopptr() != NULL &&
+                       tj->is_oopptr()->is_known_instance();
+
   // Process weird unsafe references.
   if (offset == Type::OffsetBot && (tj->isa_instptr() /*|| tj->isa_klassptr()*/)) {
     assert(InlineUnsafeOps, "indeterminate pointers come only from unsafe ops");
+    assert(!is_known_inst, "scalarizable allocation should not have unsafe references");
     tj = TypeOopPtr::BOTTOM;
     ptr = tj->ptr();
     offset = tj->offset();
@@ -1005,14 +1024,20 @@
 
   // Array pointers need some flattening
   const TypeAryPtr *ta = tj->isa_aryptr();
-  if( ta && _AliasLevel >= 2 ) {
+  if( ta && is_known_inst ) {
+    if ( offset != Type::OffsetBot &&
+         offset > arrayOopDesc::length_offset_in_bytes() ) {
+      offset = Type::OffsetBot; // Flatten constant access into array body only
+      tj = ta = TypeAryPtr::make(ptr, ta->ary(), ta->klass(), true, offset, ta->instance_id());
+    }
+  } else if( ta && _AliasLevel >= 2 ) {
     // For arrays indexed by constant indices, we flatten the alias
     // space to include all of the array body.  Only the header, klass
     // and array length can be accessed un-aliased.
     if( offset != Type::OffsetBot ) {
       if( ta->const_oop() ) { // methodDataOop or methodOop
         offset = Type::OffsetBot;   // Flatten constant access into array body
-        tj = ta = TypeAryPtr::make(ptr,ta->const_oop(),ta->ary(),ta->klass(),false,Type::OffsetBot, ta->instance_id());
+        tj = ta = TypeAryPtr::make(ptr,ta->const_oop(),ta->ary(),ta->klass(),false,offset);
       } else if( offset == arrayOopDesc::length_offset_in_bytes() ) {
         // range is OK as-is.
         tj = ta = TypeAryPtr::RANGE;
@@ -1026,29 +1051,29 @@
         ptr = TypePtr::BotPTR;
       } else {                  // Random constant offset into array body
         offset = Type::OffsetBot;   // Flatten constant access into array body
-        tj = ta = TypeAryPtr::make(ptr,ta->ary(),ta->klass(),false,Type::OffsetBot, ta->instance_id());
+        tj = ta = TypeAryPtr::make(ptr,ta->ary(),ta->klass(),false,offset);
       }
     }
     // Arrays of fixed size alias with arrays of unknown size.
     if (ta->size() != TypeInt::POS) {
       const TypeAry *tary = TypeAry::make(ta->elem(), TypeInt::POS);
-      tj = ta = TypeAryPtr::make(ptr,ta->const_oop(),tary,ta->klass(),false,offset, ta->instance_id());
+      tj = ta = TypeAryPtr::make(ptr,ta->const_oop(),tary,ta->klass(),false,offset);
     }
     // Arrays of known objects become arrays of unknown objects.
     if (ta->elem()->isa_narrowoop() && ta->elem() != TypeNarrowOop::BOTTOM) {
       const TypeAry *tary = TypeAry::make(TypeNarrowOop::BOTTOM, ta->size());
-      tj = ta = TypeAryPtr::make(ptr,ta->const_oop(),tary,NULL,false,offset, ta->instance_id());
+      tj = ta = TypeAryPtr::make(ptr,ta->const_oop(),tary,NULL,false,offset);
     }
     if (ta->elem()->isa_oopptr() && ta->elem() != TypeInstPtr::BOTTOM) {
       const TypeAry *tary = TypeAry::make(TypeInstPtr::BOTTOM, ta->size());
-      tj = ta = TypeAryPtr::make(ptr,ta->const_oop(),tary,NULL,false,offset, ta->instance_id());
+      tj = ta = TypeAryPtr::make(ptr,ta->const_oop(),tary,NULL,false,offset);
     }
     // Arrays of bytes and of booleans both use 'bastore' and 'baload' so
     // cannot be distinguished by bytecode alone.
     if (ta->elem() == TypeInt::BOOL) {
       const TypeAry *tary = TypeAry::make(TypeInt::BYTE, ta->size());
       ciKlass* aklass = ciTypeArrayKlass::make(T_BYTE);
-      tj = ta = TypeAryPtr::make(ptr,ta->const_oop(),tary,aklass,false,offset, ta->instance_id());
+      tj = ta = TypeAryPtr::make(ptr,ta->const_oop(),tary,aklass,false,offset);
     }
     // During the 2nd round of IterGVN, NotNull castings are removed.
     // Make sure the Bottom and NotNull variants alias the same.
@@ -1068,21 +1093,24 @@
     if( ptr == TypePtr::Constant ) {
       // No constant oop pointers (such as Strings); they alias with
       // unknown strings.
+      assert(!is_known_inst, "not scalarizable allocation");
       tj = to = TypeInstPtr::make(TypePtr::BotPTR,to->klass(),false,0,offset);
-    } else if( to->is_known_instance_field() ) {
+    } else if( is_known_inst ) {
       tj = to; // Keep NotNull and klass_is_exact for instance type
     } else if( ptr == TypePtr::NotNull || to->klass_is_exact() ) {
       // During the 2nd round of IterGVN, NotNull castings are removed.
       // Make sure the Bottom and NotNull variants alias the same.
       // Also, make sure exact and non-exact variants alias the same.
-      tj = to = TypeInstPtr::make(TypePtr::BotPTR,to->klass(),false,0,offset, to->instance_id());
+      tj = to = TypeInstPtr::make(TypePtr::BotPTR,to->klass(),false,0,offset);
     }
     // Canonicalize the holder of this field
     ciInstanceKlass *k = to->klass()->as_instance_klass();
     if (offset >= 0 && offset < instanceOopDesc::base_offset_in_bytes()) {
       // First handle header references such as a LoadKlassNode, even if the
       // object's klass is unloaded at compile time (4965979).
-      tj = to = TypeInstPtr::make(TypePtr::BotPTR, env()->Object_klass(), false, NULL, offset, to->instance_id());
+      if (!is_known_inst) { // Do it only for non-instance types
+        tj = to = TypeInstPtr::make(TypePtr::BotPTR, env()->Object_klass(), false, NULL, offset);
+      }
     } else if (offset < 0 || offset >= k->size_helper() * wordSize) {
       to = NULL;
       tj = TypeOopPtr::BOTTOM;
@@ -1090,7 +1118,11 @@
     } else {
       ciInstanceKlass *canonical_holder = k->get_canonical_holder(offset);
       if (!k->equals(canonical_holder) || tj->offset() != offset) {
-        tj = to = TypeInstPtr::make(to->ptr(), canonical_holder, false, NULL, offset, to->instance_id());
+        if( is_known_inst ) {
+          tj = to = TypeInstPtr::make(to->ptr(), canonical_holder, true, NULL, offset, to->instance_id());
+        } else {
+          tj = to = TypeInstPtr::make(to->ptr(), canonical_holder, false, NULL, offset);
+        }
       }
     }
   }
@@ -1276,7 +1308,9 @@
   assert(flat != TypePtr::BOTTOM,     "cannot alias-analyze an untyped ptr");
   if (flat->isa_oopptr() && !flat->isa_klassptr()) {
     const TypeOopPtr* foop = flat->is_oopptr();
-    const TypePtr* xoop = foop->cast_to_exactness(!foop->klass_is_exact())->is_ptr();
+    // Scalarizable allocations have exact klass always.
+    bool exact = !foop->klass_is_exact() || foop->is_known_instance();
+    const TypePtr* xoop = foop->cast_to_exactness(exact)->is_ptr();
     assert(foop == flatten_alias_type(xoop), "exactness must not affect alias type");
   }
   assert(flat == flatten_alias_type(flat), "exact bit doesn't matter");
--- a/hotspot/src/share/vm/opto/escape.cpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/opto/escape.cpp	Wed Jul 05 16:40:29 2017 +0200
@@ -25,16 +25,6 @@
 #include "incls/_precompiled.incl"
 #include "incls/_escape.cpp.incl"
 
-uint PointsToNode::edge_target(uint e) const {
-  assert(_edges != NULL && e < (uint)_edges->length(), "valid edge index");
-  return (_edges->at(e) >> EdgeShift);
-}
-
-PointsToNode::EdgeType PointsToNode::edge_type(uint e) const {
-  assert(_edges != NULL && e < (uint)_edges->length(), "valid edge index");
-  return (EdgeType) (_edges->at(e) & EdgeMask);
-}
-
 void PointsToNode::add_edge(uint targIdx, PointsToNode::EdgeType et) {
   uint v = (targIdx << EdgeShift) + ((uint) et);
   if (_edges == NULL) {
@@ -72,10 +62,14 @@
  "F"  // FieldEdge
 };
 
-void PointsToNode::dump() const {
+void PointsToNode::dump(bool print_state) const {
   NodeType nt = node_type();
-  EscapeState es = escape_state();
-  tty->print("%s %s %s [[", node_type_names[(int) nt], esc_names[(int) es], _scalar_replaceable ? "" : "NSR");
+  tty->print("%s ", node_type_names[(int) nt]);
+  if (print_state) {
+    EscapeState es = escape_state();
+    tty->print("%s %s ", esc_names[(int) es], _scalar_replaceable ? "":"NSR");
+  }
+  tty->print("[[");
   for (uint i = 0; i < edge_count(); i++) {
     tty->print(" %d%s", edge_target(i), edge_type_suffix[(int) edge_type(i)]);
   }
@@ -87,17 +81,29 @@
 }
 #endif
 
-ConnectionGraph::ConnectionGraph(Compile * C) : _processed(C->comp_arena()), _node_map(C->comp_arena()) {
-  _collecting = true;
-  this->_compile = C;
-  const PointsToNode &dummy = PointsToNode();
-  int sz = C->unique();
-  _nodes = new(C->comp_arena()) GrowableArray<PointsToNode>(C->comp_arena(), sz, sz, dummy);
-  _phantom_object = C->top()->_idx;
-  PointsToNode *phn = ptnode_adr(_phantom_object);
-  phn->_node = C->top();
-  phn->set_node_type(PointsToNode::JavaObject);
-  phn->set_escape_state(PointsToNode::GlobalEscape);
+ConnectionGraph::ConnectionGraph(Compile * C) :
+  _nodes(C->comp_arena(), C->unique(), C->unique(), PointsToNode()),
+  _processed(C->comp_arena()),
+  _collecting(true),
+  _compile(C),
+  _node_map(C->comp_arena()) {
+
+  _phantom_object = C->top()->_idx,
+  add_node(C->top(), PointsToNode::JavaObject, PointsToNode::GlobalEscape,true);
+
+  // Add ConP(#NULL) and ConN(#NULL) nodes.
+  PhaseGVN* igvn = C->initial_gvn();
+  Node* oop_null = igvn->zerocon(T_OBJECT);
+  _oop_null = oop_null->_idx;
+  assert(_oop_null < C->unique(), "should be created already");
+  add_node(oop_null, PointsToNode::JavaObject, PointsToNode::NoEscape, true);
+
+  if (UseCompressedOops) {
+    Node* noop_null = igvn->zerocon(T_NARROWOOP);
+    _noop_null = noop_null->_idx;
+    assert(_noop_null < C->unique(), "should be created already");
+    add_node(noop_null, PointsToNode::JavaObject, PointsToNode::NoEscape, true);
+  }
 }
 
 void ConnectionGraph::add_pointsto_edge(uint from_i, uint to_i) {
@@ -182,32 +188,36 @@
 
   // If we are still collecting or there were no non-escaping allocations
   // we don't know the answer yet
-  if (_collecting || !_has_allocations)
+  if (_collecting)
     return PointsToNode::UnknownEscape;
 
   // if the node was created after the escape computation, return
   // UnknownEscape
-  if (idx >= (uint)_nodes->length())
+  if (idx >= nodes_size())
     return PointsToNode::UnknownEscape;
 
-  es = _nodes->at_grow(idx).escape_state();
+  es = ptnode_adr(idx)->escape_state();
 
   // if we have already computed a value, return it
   if (es != PointsToNode::UnknownEscape)
     return es;
 
+  // PointsTo() calls n->uncast() which can return a new ideal node.
+  if (n->uncast()->_idx >= nodes_size())
+    return PointsToNode::UnknownEscape;
+
   // compute max escape state of anything this node could point to
   VectorSet ptset(Thread::current()->resource_area());
   PointsTo(ptset, n, phase);
   for(VectorSetI i(&ptset); i.test() && es != PointsToNode::GlobalEscape; ++i) {
     uint pt = i.elem;
-    PointsToNode::EscapeState pes = _nodes->adr_at(pt)->escape_state();
+    PointsToNode::EscapeState pes = ptnode_adr(pt)->escape_state();
     if (pes > es)
       es = pes;
   }
   // cache the computed escape state
   assert(es != PointsToNode::UnknownEscape, "should have computed an escape state");
-  _nodes->adr_at(idx)->set_escape_state(es);
+  ptnode_adr(idx)->set_escape_state(es);
   return es;
 }
 
@@ -220,48 +230,50 @@
 #endif
 
   n = n->uncast();
-  PointsToNode  npt = _nodes->at_grow(n->_idx);
+  PointsToNode* npt = ptnode_adr(n->_idx);
 
   // If we have a JavaObject, return just that object
-  if (npt.node_type() == PointsToNode::JavaObject) {
+  if (npt->node_type() == PointsToNode::JavaObject) {
     ptset.set(n->_idx);
     return;
   }
 #ifdef ASSERT
-  if (npt._node == NULL) {
+  if (npt->_node == NULL) {
     if (orig_n != n)
       orig_n->dump();
     n->dump();
-    assert(npt._node != NULL, "unregistered node");
+    assert(npt->_node != NULL, "unregistered node");
   }
 #endif
   worklist.push(n->_idx);
   while(worklist.length() > 0) {
     int ni = worklist.pop();
-    PointsToNode pn = _nodes->at_grow(ni);
-    if (!visited.test_set(ni)) {
-      // ensure that all inputs of a Phi have been processed
-      assert(!_collecting || !pn._node->is_Phi() || _processed.test(ni),"");
+    if (visited.test_set(ni))
+      continue;
+
+    PointsToNode* pn = ptnode_adr(ni);
+    // ensure that all inputs of a Phi have been processed
+    assert(!_collecting || !pn->_node->is_Phi() || _processed.test(ni),"");
 
-      int edges_processed = 0;
-      for (uint e = 0; e < pn.edge_count(); e++) {
-        uint etgt = pn.edge_target(e);
-        PointsToNode::EdgeType et = pn.edge_type(e);
-        if (et == PointsToNode::PointsToEdge) {
-          ptset.set(etgt);
-          edges_processed++;
-        } else if (et == PointsToNode::DeferredEdge) {
-          worklist.push(etgt);
-          edges_processed++;
-        } else {
-          assert(false,"neither PointsToEdge or DeferredEdge");
-        }
+    int edges_processed = 0;
+    uint e_cnt = pn->edge_count();
+    for (uint e = 0; e < e_cnt; e++) {
+      uint etgt = pn->edge_target(e);
+      PointsToNode::EdgeType et = pn->edge_type(e);
+      if (et == PointsToNode::PointsToEdge) {
+        ptset.set(etgt);
+        edges_processed++;
+      } else if (et == PointsToNode::DeferredEdge) {
+        worklist.push(etgt);
+        edges_processed++;
+      } else {
+        assert(false,"neither PointsToEdge or DeferredEdge");
       }
-      if (edges_processed == 0) {
-        // no deferred or pointsto edges found.  Assume the value was set
-        // outside this method.  Add the phantom object to the pointsto set.
-        ptset.set(_phantom_object);
-      }
+    }
+    if (edges_processed == 0) {
+      // no deferred or pointsto edges found.  Assume the value was set
+      // outside this method.  Add the phantom object to the pointsto set.
+      ptset.set(_phantom_object);
     }
   }
 }
@@ -272,11 +284,11 @@
   deferred_edges->clear();
   visited->Clear();
 
-  uint i = 0;
+  visited->set(ni);
   PointsToNode *ptn = ptnode_adr(ni);
 
   // Mark current edges as visited and move deferred edges to separate array.
-  while (i < ptn->edge_count()) {
+  for (uint i = 0; i < ptn->edge_count(); ) {
     uint t = ptn->edge_target(i);
 #ifdef ASSERT
     assert(!visited->test_set(t), "expecting no duplications");
@@ -293,24 +305,23 @@
   for (int next = 0; next < deferred_edges->length(); ++next) {
     uint t = deferred_edges->at(next);
     PointsToNode *ptt = ptnode_adr(t);
-    for (uint j = 0; j < ptt->edge_count(); j++) {
-      uint n1 = ptt->edge_target(j);
-      if (visited->test_set(n1))
+    uint e_cnt = ptt->edge_count();
+    for (uint e = 0; e < e_cnt; e++) {
+      uint etgt = ptt->edge_target(e);
+      if (visited->test_set(etgt))
         continue;
-      switch(ptt->edge_type(j)) {
-        case PointsToNode::PointsToEdge:
-          add_pointsto_edge(ni, n1);
-          if(n1 == _phantom_object) {
-            // Special case - field set outside (globally escaping).
-            ptn->set_escape_state(PointsToNode::GlobalEscape);
-          }
-          break;
-        case PointsToNode::DeferredEdge:
-          deferred_edges->append(n1);
-          break;
-        case PointsToNode::FieldEdge:
-          assert(false, "invalid connection graph");
-          break;
+
+      PointsToNode::EdgeType et = ptt->edge_type(e);
+      if (et == PointsToNode::PointsToEdge) {
+        add_pointsto_edge(ni, etgt);
+        if(etgt == _phantom_object) {
+          // Special case - field set outside (globally escaping).
+          ptn->set_escape_state(PointsToNode::GlobalEscape);
+        }
+      } else if (et == PointsToNode::DeferredEdge) {
+        deferred_edges->append(etgt);
+      } else {
+        assert(false,"invalid connection graph");
       }
     }
   }
@@ -322,15 +333,15 @@
 //  a pointsto edge is added if it is a JavaObject
 
 void ConnectionGraph::add_edge_from_fields(uint adr_i, uint to_i, int offs) {
-  PointsToNode an = _nodes->at_grow(adr_i);
-  PointsToNode to = _nodes->at_grow(to_i);
-  bool deferred = (to.node_type() == PointsToNode::LocalVar);
+  PointsToNode* an = ptnode_adr(adr_i);
+  PointsToNode* to = ptnode_adr(to_i);
+  bool deferred = (to->node_type() == PointsToNode::LocalVar);
 
-  for (uint fe = 0; fe < an.edge_count(); fe++) {
-    assert(an.edge_type(fe) == PointsToNode::FieldEdge, "expecting a field edge");
-    int fi = an.edge_target(fe);
-    PointsToNode pf = _nodes->at_grow(fi);
-    int po = pf.offset();
+  for (uint fe = 0; fe < an->edge_count(); fe++) {
+    assert(an->edge_type(fe) == PointsToNode::FieldEdge, "expecting a field edge");
+    int fi = an->edge_target(fe);
+    PointsToNode* pf = ptnode_adr(fi);
+    int po = pf->offset();
     if (po == offs || po == Type::OffsetBot || offs == Type::OffsetBot) {
       if (deferred)
         add_deferred_edge(fi, to_i);
@@ -343,13 +354,13 @@
 // Add a deferred  edge from node given by "from_i" to any field of adr_i
 // whose offset matches "offset".
 void ConnectionGraph::add_deferred_edge_to_fields(uint from_i, uint adr_i, int offs) {
-  PointsToNode an = _nodes->at_grow(adr_i);
-  for (uint fe = 0; fe < an.edge_count(); fe++) {
-    assert(an.edge_type(fe) == PointsToNode::FieldEdge, "expecting a field edge");
-    int fi = an.edge_target(fe);
-    PointsToNode pf = _nodes->at_grow(fi);
-    int po = pf.offset();
-    if (pf.edge_count() == 0) {
+  PointsToNode* an = ptnode_adr(adr_i);
+  for (uint fe = 0; fe < an->edge_count(); fe++) {
+    assert(an->edge_type(fe) == PointsToNode::FieldEdge, "expecting a field edge");
+    int fi = an->edge_target(fe);
+    PointsToNode* pf = ptnode_adr(fi);
+    int po = pf->offset();
+    if (pf->edge_count() == 0) {
       // we have not seen any stores to this field, assume it was set outside this method
       add_pointsto_edge(fi, _phantom_object);
     }
@@ -504,29 +515,30 @@
   igvn->set_type(addp, tinst);
   // record the allocation in the node map
   set_map(addp->_idx, get_map(base->_idx));
-  // if the Address input is not the appropriate instance type
-  // (due to intervening casts,) insert a cast
-  Node *adr = addp->in(AddPNode::Address);
-  const TypeOopPtr  *atype = igvn->type(adr)->isa_oopptr();
-  if (atype != NULL && atype->instance_id() != inst_id) {
-    assert(!atype->is_known_instance(), "no conflicting instances");
-    const TypeOopPtr *new_atype = base_t->add_offset(atype->offset())->isa_oopptr();
-    Node *acast = new (_compile, 2) CastPPNode(adr, new_atype);
-    acast->set_req(0, adr->in(0));
-    igvn->set_type(acast, new_atype);
-    record_for_optimizer(acast);
-    Node *bcast = acast;
-    Node *abase = addp->in(AddPNode::Base);
-    if (abase != adr) {
-      bcast = new (_compile, 2) CastPPNode(abase, base_t);
-      bcast->set_req(0, abase->in(0));
-      igvn->set_type(bcast, base_t);
-      record_for_optimizer(bcast);
+
+  // Set addp's Base and Address to 'base'.
+  Node *abase = addp->in(AddPNode::Base);
+  Node *adr   = addp->in(AddPNode::Address);
+  if (adr->is_Proj() && adr->in(0)->is_Allocate() &&
+      adr->in(0)->_idx == (uint)inst_id) {
+    // Skip AddP cases #3 and #5.
+  } else {
+    assert(!abase->is_top(), "sanity"); // AddP case #3
+    if (abase != base) {
+      igvn->hash_delete(addp);
+      addp->set_req(AddPNode::Base, base);
+      if (abase == adr) {
+        addp->set_req(AddPNode::Address, base);
+      } else {
+        // AddP case #4 (adr is array's element offset AddP node)
+#ifdef ASSERT
+        const TypeOopPtr *atype = igvn->type(adr)->isa_oopptr();
+        assert(adr->is_AddP() && atype != NULL &&
+               atype->instance_id() == inst_id, "array's element offset should be processed first");
+#endif
+      }
+      igvn->hash_insert(addp);
     }
-    igvn->hash_delete(addp);
-    addp->set_req(AddPNode::Base, bcast);
-    addp->set_req(AddPNode::Address, acast);
-    igvn->hash_insert(addp);
   }
   // Put on IGVN worklist since at least addp's type was changed above.
   record_for_optimizer(addp);
@@ -664,27 +676,31 @@
   Compile* C = phase->C;
   const TypeOopPtr *tinst = C->get_adr_type(alias_idx)->isa_oopptr();
   bool is_instance = (tinst != NULL) && tinst->is_known_instance();
+  Node *start_mem = C->start()->proj_out(TypeFunc::Memory);
   Node *prev = NULL;
   Node *result = orig_mem;
   while (prev != result) {
     prev = result;
+    if (result == start_mem)
+      break;  // hit one of our sentinals
     if (result->is_Mem()) {
-      MemNode *mem = result->as_Mem();
-      const Type *at = phase->type(mem->in(MemNode::Address));
+      const Type *at = phase->type(result->in(MemNode::Address));
       if (at != Type::TOP) {
         assert (at->isa_ptr() != NULL, "pointer type required.");
         int idx = C->get_alias_index(at->is_ptr());
         if (idx == alias_idx)
           break;
       }
-      result = mem->in(MemNode::Memory);
+      result = result->in(MemNode::Memory);
     }
     if (!is_instance)
       continue;  // don't search further for non-instance types
     // skip over a call which does not affect this memory slice
     if (result->is_Proj() && result->as_Proj()->_con == TypeFunc::Memory) {
       Node *proj_in = result->in(0);
-      if (proj_in->is_Call()) {
+      if (proj_in->is_Allocate() && proj_in->_idx == (uint)tinst->instance_id()) {
+        break;  // hit one of our sentinals
+      } else if (proj_in->is_Call()) {
         CallNode *call = proj_in->as_Call();
         if (!call->may_modify(tinst, phase)) {
           result = call->in(TypeFunc::Memory);
@@ -721,12 +737,17 @@
       }
     }
   }
-  if (is_instance && result->is_Phi()) {
+  if (result->is_Phi()) {
     PhiNode *mphi = result->as_Phi();
     assert(mphi->bottom_type() == Type::MEMORY, "memory phi required");
     const TypePtr *t = mphi->adr_type();
     if (C->get_alias_index(t) != alias_idx) {
+      // Create a new Phi with the specified alias index type.
       result = split_memory_phi(mphi, alias_idx, orig_phis, phase);
+    } else if (!is_instance) {
+      // Push all non-instance Phis on the orig_phis worklist to update inputs
+      // during Phase 4 if needed.
+      orig_phis.append_if_missing(mphi);
     }
   }
   // the result is either MemNode, PhiNode, InitializeNode.
@@ -835,6 +856,11 @@
 
   //  Phase 1:  Process possible allocations from alloc_worklist.
   //  Create instance types for the CheckCastPP for allocations where possible.
+  //
+  // (Note: don't forget to change the order of the second AddP node on
+  //  the alloc_worklist if the order of the worklist processing is changed,
+  //  see the comment in find_second_addp().)
+  //
   while (alloc_worklist.length() != 0) {
     Node *n = alloc_worklist.pop();
     uint ni = n->_idx;
@@ -842,7 +868,7 @@
     if (n->is_Call()) {
       CallNode *alloc = n->as_Call();
       // copy escape information to call node
-      PointsToNode* ptn = _nodes->adr_at(alloc->_idx);
+      PointsToNode* ptn = ptnode_adr(alloc->_idx);
       PointsToNode::EscapeState es = escape_state(alloc, igvn);
       // We have an allocation or call which returns a Java object,
       // see if it is unescaped.
@@ -858,10 +884,14 @@
           !n->is_CheckCastPP()) // not unique CheckCastPP.
         continue;
       // The inline code for Object.clone() casts the allocation result to
-      // java.lang.Object and then to the the actual type of the allocated
+      // java.lang.Object and then to the actual type of the allocated
       // object. Detect this case and use the second cast.
+      // Also detect j.l.reflect.Array.newInstance(jobject, jint) case when
+      // the allocation result is cast to java.lang.Object and then
+      // to the actual Array type.
       if (alloc->is_Allocate() && n->as_Type()->type() == TypeInstPtr::NOTNULL
-          && igvn->type(alloc->in(AllocateNode::KlassNode)) != TypeKlassPtr::OBJECT) {
+          && (alloc->is_AllocateArray() ||
+              igvn->type(alloc->in(AllocateNode::KlassNode)) != TypeKlassPtr::OBJECT)) {
         Node *cast2 = NULL;
         for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) {
           Node *use = n->fast_out(i);
@@ -877,7 +907,7 @@
         }
       }
       set_escape_state(n->_idx, es);
-      // in order for an object to be stackallocatable, it must be:
+      // in order for an object to be scalar-replaceable, it must be:
       //   - a direct allocation (not a call returning an object)
       //   - non-escaping
       //   - eligible to be a unique type
@@ -887,7 +917,7 @@
       const TypeOopPtr *t = igvn->type(n)->isa_oopptr();
       if (t == NULL)
         continue;  // not a TypeInstPtr
-      tinst = t->cast_to_instance_id(ni);
+      tinst = t->cast_to_exactness(true)->is_oopptr()->cast_to_instance_id(ni);
       igvn->hash_delete(n);
       igvn->set_type(n,  tinst);
       n->raise_bottom_type(tinst);
@@ -899,7 +929,7 @@
         // First, put on the worklist all Field edges from Connection Graph
         // which is more accurate then putting immediate users from Ideal Graph.
         for (uint e = 0; e < ptn->edge_count(); e++) {
-          Node *use = _nodes->adr_at(ptn->edge_target(e))->_node;
+          Node *use = ptnode_adr(ptn->edge_target(e))->_node;
           assert(ptn->edge_type(e) == PointsToNode::FieldEdge && use->is_AddP(),
                  "only AddP nodes are Field edges in CG");
           if (use->outcnt() > 0) { // Don't process dead nodes
@@ -996,12 +1026,12 @@
         memnode_worklist.append_if_missing(use);
       } else if (use->is_MergeMem()) {
         mergemem_worklist.append_if_missing(use);
-      } else if (use->is_Call() && tinst != NULL) {
+      } else if (use->is_SafePoint() && tinst != NULL) {
         // Look for MergeMem nodes for calls which reference unique allocation
         // (through CheckCastPP nodes) even for debug info.
         Node* m = use->in(TypeFunc::Memory);
         uint iid = tinst->instance_id();
-        while (m->is_Proj() && m->in(0)->is_Call() &&
+        while (m->is_Proj() && m->in(0)->is_SafePoint() &&
                m->in(0) != use && !m->in(0)->_idx != iid) {
           m = m->in(0)->in(TypeFunc::Memory);
         }
@@ -1062,7 +1092,7 @@
       }
       if (mem != n->in(MemNode::Memory)) {
         set_map(n->_idx, mem);
-        _nodes->adr_at(n->_idx)->_node = n;
+        ptnode_adr(n->_idx)->_node = n;
       }
       if (n->is_Load()) {
         continue;  // don't push users
@@ -1203,8 +1233,8 @@
   // to recursively process Phi's encounted on the input memory
   // chains as is done in split_memory_phi() since they  will
   // also be processed here.
-  while (orig_phis.length() != 0) {
-    PhiNode *phi = orig_phis.pop();
+  for (int j = 0; j < orig_phis.length(); j++) {
+    PhiNode *phi = orig_phis.at(j);
     int alias_idx = _compile->get_alias_index(phi->adr_type());
     igvn->hash_delete(phi);
     for (uint i = 1; i < phi->req(); i++) {
@@ -1223,10 +1253,10 @@
 
   // Update the memory inputs of MemNodes with the value we computed
   // in Phase 2.
-  for (int i = 0; i < _nodes->length(); i++) {
+  for (uint i = 0; i < nodes_size(); i++) {
     Node *nmem = get_map(i);
     if (nmem != NULL) {
-      Node *n = _nodes->adr_at(i)->_node;
+      Node *n = ptnode_adr(i)->_node;
       if (n != NULL && n->is_Mem()) {
         igvn->hash_delete(n);
         n->set_req(MemNode::Memory, nmem);
@@ -1237,28 +1267,48 @@
   }
 }
 
-void ConnectionGraph::compute_escape() {
+bool ConnectionGraph::has_candidates(Compile *C) {
+  // EA brings benefits only when the code has allocations and/or locks which
+  // are represented by ideal Macro nodes.
+  int cnt = C->macro_count();
+  for( int i=0; i < cnt; i++ ) {
+    Node *n = C->macro_node(i);
+    if ( n->is_Allocate() )
+      return true;
+    if( n->is_Lock() ) {
+      Node* obj = n->as_Lock()->obj_node()->uncast();
+      if( !(obj->is_Parm() || obj->is_Con()) )
+        return true;
+    }
+  }
+  return false;
+}
+
+bool ConnectionGraph::compute_escape() {
+  Compile* C = _compile;
 
   // 1. Populate Connection Graph (CG) with Ideal nodes.
 
   Unique_Node_List worklist_init;
-  worklist_init.map(_compile->unique(), NULL);  // preallocate space
+  worklist_init.map(C->unique(), NULL);  // preallocate space
 
   // Initialize worklist
-  if (_compile->root() != NULL) {
-    worklist_init.push(_compile->root());
+  if (C->root() != NULL) {
+    worklist_init.push(C->root());
   }
 
   GrowableArray<int> cg_worklist;
-  PhaseGVN* igvn = _compile->initial_gvn();
+  PhaseGVN* igvn = C->initial_gvn();
   bool has_allocations = false;
 
   // Push all useful nodes onto CG list and set their type.
   for( uint next = 0; next < worklist_init.size(); ++next ) {
     Node* n = worklist_init.at(next);
     record_for_escape_analysis(n, igvn);
-    if (n->is_Call() &&
-        _nodes->adr_at(n->_idx)->node_type() == PointsToNode::JavaObject) {
+    // Only allocations and java static calls results are checked
+    // for an escape status. See process_call_result() below.
+    if (n->is_Allocate() || n->is_CallStaticJava() &&
+        ptnode_adr(n->_idx)->node_type() == PointsToNode::JavaObject) {
       has_allocations = true;
     }
     if(n->is_AddP())
@@ -1269,24 +1319,23 @@
     }
   }
 
-  if (has_allocations) {
-    _has_allocations = true;
-  } else {
-    _has_allocations = false;
+  if (!has_allocations) {
     _collecting = false;
-    return; // Nothing to do.
+    return false; // Nothing to do.
   }
 
   // 2. First pass to create simple CG edges (doesn't require to walk CG).
-  for( uint next = 0; next < _delayed_worklist.size(); ++next ) {
+  uint delayed_size = _delayed_worklist.size();
+  for( uint next = 0; next < delayed_size; ++next ) {
     Node* n = _delayed_worklist.at(next);
     build_connection_graph(n, igvn);
   }
 
   // 3. Pass to create fields edges (Allocate -F-> AddP).
-  for( int next = 0; next < cg_worklist.length(); ++next ) {
+  uint cg_length = cg_worklist.length();
+  for( uint next = 0; next < cg_length; ++next ) {
     int ni = cg_worklist.at(next);
-    build_connection_graph(_nodes->adr_at(ni)->_node, igvn);
+    build_connection_graph(ptnode_adr(ni)->_node, igvn);
   }
 
   cg_worklist.clear();
@@ -1294,8 +1343,8 @@
 
   // 4. Build Connection Graph which need
   //    to walk the connection graph.
-  for (uint ni = 0; ni < (uint)_nodes->length(); ni++) {
-    PointsToNode* ptn = _nodes->adr_at(ni);
+  for (uint ni = 0; ni < nodes_size(); ni++) {
+    PointsToNode* ptn = ptnode_adr(ni);
     Node *n = ptn->_node;
     if (n != NULL) { // Call, AddP, LoadP, StoreP
       build_connection_graph(n, igvn);
@@ -1305,140 +1354,226 @@
   }
 
   VectorSet ptset(Thread::current()->resource_area());
-  GrowableArray<Node*> alloc_worklist;
-  GrowableArray<int>   worklist;
   GrowableArray<uint>  deferred_edges;
   VectorSet visited(Thread::current()->resource_area());
 
-  // remove deferred edges from the graph and collect
-  // information we will need for type splitting
-  for( int next = 0; next < cg_worklist.length(); ++next ) {
+  // 5. Remove deferred edges from the graph and collect
+  //    information needed for type splitting.
+  cg_length = cg_worklist.length();
+  for( uint next = 0; next < cg_length; ++next ) {
     int ni = cg_worklist.at(next);
-    PointsToNode* ptn = _nodes->adr_at(ni);
+    PointsToNode* ptn = ptnode_adr(ni);
     PointsToNode::NodeType nt = ptn->node_type();
-    Node *n = ptn->_node;
     if (nt == PointsToNode::LocalVar || nt == PointsToNode::Field) {
       remove_deferred(ni, &deferred_edges, &visited);
+      Node *n = ptn->_node;
       if (n->is_AddP()) {
-        // If this AddP computes an address which may point to more that one
-        // object or more then one field (array's element), nothing the address
-        // points to can be scalar replaceable.
+        // Search for objects which are not scalar replaceable.
+        // Mark their escape state as ArgEscape to propagate the state
+        // to referenced objects.
+        // Note: currently there are no difference in compiler optimizations
+        // for ArgEscape objects and NoEscape objects which are not
+        // scalar replaceable.
+
+        int offset = ptn->offset();
         Node *base = get_addp_base(n);
         ptset.Clear();
         PointsTo(ptset, base, igvn);
-        if (ptset.Size() > 1 ||
-            (ptset.Size() != 0 && ptn->offset() == Type::OffsetBot)) {
+        int ptset_size = ptset.Size();
+
+        // Check if a field's initializing value is recorded and add
+        // a corresponding NULL field's value if it is not recorded.
+        // Connection Graph does not record a default initialization by NULL
+        // captured by Initialize node.
+        //
+        // Note: it will disable scalar replacement in some cases:
+        //
+        //    Point p[] = new Point[1];
+        //    p[0] = new Point(); // Will be not scalar replaced
+        //
+        // but it will save us from incorrect optimizations in next cases:
+        //
+        //    Point p[] = new Point[1];
+        //    if ( x ) p[0] = new Point(); // Will be not scalar replaced
+        //
+        // Without a control flow analysis we can't distinguish above cases.
+        //
+        if (offset != Type::OffsetBot && ptset_size == 1) {
+          uint elem = ptset.getelem(); // Allocation node's index
+          // It does not matter if it is not Allocation node since
+          // only non-escaping allocations are scalar replaced.
+          if (ptnode_adr(elem)->_node->is_Allocate() &&
+              ptnode_adr(elem)->escape_state() == PointsToNode::NoEscape) {
+            AllocateNode* alloc = ptnode_adr(elem)->_node->as_Allocate();
+            InitializeNode* ini = alloc->initialization();
+            Node* value = NULL;
+            if (ini != NULL) {
+              BasicType ft = UseCompressedOops ? T_NARROWOOP : T_OBJECT;
+              Node* store = ini->find_captured_store(offset, type2aelembytes(ft), igvn);
+              if (store != NULL && store->is_Store())
+                value = store->in(MemNode::ValueIn);
+            }
+            if (value == NULL || value != ptnode_adr(value->_idx)->_node) {
+              // A field's initializing value was not recorded. Add NULL.
+              uint null_idx = UseCompressedOops ? _noop_null : _oop_null;
+              add_pointsto_edge(ni, null_idx);
+            }
+          }
+        }
+
+        // An object is not scalar replaceable if the field which may point
+        // to it has unknown offset (unknown element of an array of objects).
+        //
+        if (offset == Type::OffsetBot) {
+          uint e_cnt = ptn->edge_count();
+          for (uint ei = 0; ei < e_cnt; ei++) {
+            uint npi = ptn->edge_target(ei);
+            set_escape_state(npi, PointsToNode::ArgEscape);
+            ptnode_adr(npi)->_scalar_replaceable = false;
+          }
+        }
+
+        // Currently an object is not scalar replaceable if a LoadStore node
+        // access its field since the field value is unknown after it.
+        //
+        bool has_LoadStore = false;
+        for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) {
+          Node *use = n->fast_out(i);
+          if (use->is_LoadStore()) {
+            has_LoadStore = true;
+            break;
+          }
+        }
+        // An object is not scalar replaceable if the address points
+        // to unknown field (unknown element for arrays, offset is OffsetBot).
+        //
+        // Or the address may point to more then one object. This may produce
+        // the false positive result (set scalar_replaceable to false)
+        // since the flow-insensitive escape analysis can't separate
+        // the case when stores overwrite the field's value from the case
+        // when stores happened on different control branches.
+        //
+        if (ptset_size > 1 || ptset_size != 0 &&
+            (has_LoadStore || offset == Type::OffsetBot)) {
           for( VectorSetI j(&ptset); j.test(); ++j ) {
-            uint pt = j.elem;
-            ptnode_adr(pt)->_scalar_replaceable = false;
+            set_escape_state(j.elem, PointsToNode::ArgEscape);
+            ptnode_adr(j.elem)->_scalar_replaceable = false;
           }
         }
       }
-    } else if (nt == PointsToNode::JavaObject && n->is_Call()) {
-      // Push call on alloc_worlist (alocations are calls)
-      // for processing by split_unique_types().
-      alloc_worklist.append(n);
     }
   }
 
+  // 6. Propagate escape states.
+  GrowableArray<int>  worklist;
+  bool has_non_escaping_obj = false;
+
   // push all GlobalEscape nodes on the worklist
-  for( int next = 0; next < cg_worklist.length(); ++next ) {
+  for( uint next = 0; next < cg_length; ++next ) {
     int nk = cg_worklist.at(next);
-    if (_nodes->adr_at(nk)->escape_state() == PointsToNode::GlobalEscape)
-      worklist.append(nk);
+    if (ptnode_adr(nk)->escape_state() == PointsToNode::GlobalEscape)
+      worklist.push(nk);
   }
-  // mark all node reachable from GlobalEscape nodes
+  // mark all nodes reachable from GlobalEscape nodes
   while(worklist.length() > 0) {
-    PointsToNode n = _nodes->at(worklist.pop());
-    for (uint ei = 0; ei < n.edge_count(); ei++) {
-      uint npi = n.edge_target(ei);
+    PointsToNode* ptn = ptnode_adr(worklist.pop());
+    uint e_cnt = ptn->edge_count();
+    for (uint ei = 0; ei < e_cnt; ei++) {
+      uint npi = ptn->edge_target(ei);
       PointsToNode *np = ptnode_adr(npi);
       if (np->escape_state() < PointsToNode::GlobalEscape) {
         np->set_escape_state(PointsToNode::GlobalEscape);
-        worklist.append_if_missing(npi);
+        worklist.push(npi);
       }
     }
   }
 
   // push all ArgEscape nodes on the worklist
-  for( int next = 0; next < cg_worklist.length(); ++next ) {
+  for( uint next = 0; next < cg_length; ++next ) {
     int nk = cg_worklist.at(next);
-    if (_nodes->adr_at(nk)->escape_state() == PointsToNode::ArgEscape)
+    if (ptnode_adr(nk)->escape_state() == PointsToNode::ArgEscape)
       worklist.push(nk);
   }
-  // mark all node reachable from ArgEscape nodes
+  // mark all nodes reachable from ArgEscape nodes
   while(worklist.length() > 0) {
-    PointsToNode n = _nodes->at(worklist.pop());
-    for (uint ei = 0; ei < n.edge_count(); ei++) {
-      uint npi = n.edge_target(ei);
+    PointsToNode* ptn = ptnode_adr(worklist.pop());
+    if (ptn->node_type() == PointsToNode::JavaObject)
+      has_non_escaping_obj = true; // Non GlobalEscape
+    uint e_cnt = ptn->edge_count();
+    for (uint ei = 0; ei < e_cnt; ei++) {
+      uint npi = ptn->edge_target(ei);
       PointsToNode *np = ptnode_adr(npi);
       if (np->escape_state() < PointsToNode::ArgEscape) {
         np->set_escape_state(PointsToNode::ArgEscape);
-        worklist.append_if_missing(npi);
+        worklist.push(npi);
       }
     }
   }
 
+  GrowableArray<Node*> alloc_worklist;
+
   // push all NoEscape nodes on the worklist
-  for( int next = 0; next < cg_worklist.length(); ++next ) {
+  for( uint next = 0; next < cg_length; ++next ) {
     int nk = cg_worklist.at(next);
-    if (_nodes->adr_at(nk)->escape_state() == PointsToNode::NoEscape)
+    if (ptnode_adr(nk)->escape_state() == PointsToNode::NoEscape)
       worklist.push(nk);
   }
-  // mark all node reachable from NoEscape nodes
+  // mark all nodes reachable from NoEscape nodes
   while(worklist.length() > 0) {
-    PointsToNode n = _nodes->at(worklist.pop());
-    for (uint ei = 0; ei < n.edge_count(); ei++) {
-      uint npi = n.edge_target(ei);
+    PointsToNode* ptn = ptnode_adr(worklist.pop());
+    if (ptn->node_type() == PointsToNode::JavaObject)
+      has_non_escaping_obj = true; // Non GlobalEscape
+    Node* n = ptn->_node;
+    if (n->is_Allocate() && ptn->_scalar_replaceable ) {
+      // Push scalar replaceable alocations on alloc_worklist
+      // for processing in split_unique_types().
+      alloc_worklist.append(n);
+    }
+    uint e_cnt = ptn->edge_count();
+    for (uint ei = 0; ei < e_cnt; ei++) {
+      uint npi = ptn->edge_target(ei);
       PointsToNode *np = ptnode_adr(npi);
       if (np->escape_state() < PointsToNode::NoEscape) {
         np->set_escape_state(PointsToNode::NoEscape);
-        worklist.append_if_missing(npi);
+        worklist.push(npi);
       }
     }
   }
 
   _collecting = false;
+  assert(C->unique() == nodes_size(), "there should be no new ideal nodes during ConnectionGraph build");
 
-  has_allocations = false; // Are there scalar replaceable allocations?
+  bool has_scalar_replaceable_candidates = alloc_worklist.length() > 0;
+  if ( has_scalar_replaceable_candidates &&
+       C->AliasLevel() >= 3 && EliminateAllocations ) {
 
-  for( int next = 0; next < alloc_worklist.length(); ++next ) {
-    Node* n = alloc_worklist.at(next);
-    uint ni = n->_idx;
-    PointsToNode* ptn = _nodes->adr_at(ni);
-    PointsToNode::EscapeState es = ptn->escape_state();
-    if (ptn->escape_state() == PointsToNode::NoEscape &&
-        ptn->_scalar_replaceable) {
-      has_allocations = true;
-      break;
-    }
-  }
-  if (!has_allocations) {
-    return; // Nothing to do.
-  }
+    // Now use the escape information to create unique types for
+    // scalar replaceable objects.
+    split_unique_types(alloc_worklist);
 
-  if(_compile->AliasLevel() >= 3 && EliminateAllocations) {
-    // Now use the escape information to create unique types for
-    // unescaped objects
-    split_unique_types(alloc_worklist);
-    if (_compile->failing())  return;
+    if (C->failing())  return false;
 
     // Clean up after split unique types.
     ResourceMark rm;
-    PhaseRemoveUseless pru(_compile->initial_gvn(), _compile->for_igvn());
+    PhaseRemoveUseless pru(C->initial_gvn(), C->for_igvn());
+
+    C->print_method("After Escape Analysis", 2);
 
 #ifdef ASSERT
-  } else if (PrintEscapeAnalysis || PrintEliminateAllocations) {
+  } else if (Verbose && (PrintEscapeAnalysis || PrintEliminateAllocations)) {
     tty->print("=== No allocations eliminated for ");
-    C()->method()->print_short_name();
+    C->method()->print_short_name();
     if(!EliminateAllocations) {
       tty->print(" since EliminateAllocations is off ===");
-    } else if(_compile->AliasLevel() < 3) {
+    } else if(!has_scalar_replaceable_candidates) {
+      tty->print(" since there are no scalar replaceable candidates ===");
+    } else if(C->AliasLevel() < 3) {
       tty->print(" since AliasLevel < 3 ===");
     }
     tty->cr();
 #endif
   }
+  return has_non_escaping_obj;
 }
 
 void ConnectionGraph::process_call_arguments(CallNode *call, PhaseTransform *phase) {
@@ -1538,7 +1673,7 @@
           }
         }
         if (copy_dependencies)
-          call_analyzer->copy_dependencies(C()->dependencies());
+          call_analyzer->copy_dependencies(_compile->dependencies());
         break;
       }
     }
@@ -1561,7 +1696,6 @@
           for( VectorSetI j(&ptset); j.test(); ++j ) {
             uint pt = j.elem;
             set_escape_state(pt, PointsToNode::GlobalEscape);
-            PointsToNode *ptadr = ptnode_adr(pt);
           }
         }
       }
@@ -1569,9 +1703,10 @@
   }
 }
 void ConnectionGraph::process_call_result(ProjNode *resproj, PhaseTransform *phase) {
-  PointsToNode *ptadr = ptnode_adr(resproj->_idx);
+  CallNode   *call = resproj->in(0)->as_Call();
+  uint    call_idx = call->_idx;
+  uint resproj_idx = resproj->_idx;
 
-  CallNode *call = resproj->in(0)->as_Call();
   switch (call->Opcode()) {
     case Op_Allocate:
     {
@@ -1587,7 +1722,6 @@
       ciKlass* cik = kt->klass();
       ciInstanceKlass* ciik = cik->as_instance_klass();
 
-      PointsToNode *ptadr = ptnode_adr(call->_idx);
       PointsToNode::EscapeState es;
       uint edge_to;
       if (cik->is_subclass_of(_compile->env()->Thread_klass()) || ciik->has_finalizer()) {
@@ -1595,25 +1729,24 @@
         edge_to = _phantom_object; // Could not be worse
       } else {
         es = PointsToNode::NoEscape;
-        edge_to = call->_idx;
+        edge_to = call_idx;
       }
-      set_escape_state(call->_idx, es);
-      add_pointsto_edge(resproj->_idx, edge_to);
-      _processed.set(resproj->_idx);
+      set_escape_state(call_idx, es);
+      add_pointsto_edge(resproj_idx, edge_to);
+      _processed.set(resproj_idx);
       break;
     }
 
     case Op_AllocateArray:
     {
-      PointsToNode *ptadr = ptnode_adr(call->_idx);
       int length = call->in(AllocateNode::ALength)->find_int_con(-1);
       if (length < 0 || length > EliminateAllocationArraySizeLimit) {
         // Not scalar replaceable if the length is not constant or too big.
-        ptadr->_scalar_replaceable = false;
+        ptnode_adr(call_idx)->_scalar_replaceable = false;
       }
-      set_escape_state(call->_idx, PointsToNode::NoEscape);
-      add_pointsto_edge(resproj->_idx, call->_idx);
-      _processed.set(resproj->_idx);
+      set_escape_state(call_idx, PointsToNode::NoEscape);
+      add_pointsto_edge(resproj_idx, call_idx);
+      _processed.set(resproj_idx);
       break;
     }
 
@@ -1631,19 +1764,17 @@
       // Note:  we use isa_ptr() instead of isa_oopptr()  here because the
       //        _multianewarray functions return a TypeRawPtr.
       if (ret_type == NULL || ret_type->isa_ptr() == NULL) {
-        _processed.set(resproj->_idx);
+        _processed.set(resproj_idx);
         break;  // doesn't return a pointer type
       }
       ciMethod *meth = call->as_CallJava()->method();
       const TypeTuple * d = call->tf()->domain();
       if (meth == NULL) {
         // not a Java method, assume global escape
-        set_escape_state(call->_idx, PointsToNode::GlobalEscape);
-        if (resproj != NULL)
-          add_pointsto_edge(resproj->_idx, _phantom_object);
+        set_escape_state(call_idx, PointsToNode::GlobalEscape);
+        add_pointsto_edge(resproj_idx, _phantom_object);
       } else {
         BCEscapeAnalyzer *call_analyzer = meth->get_bcea();
-        VectorSet ptset(Thread::current()->resource_area());
         bool copy_dependencies = false;
 
         if (call_analyzer->is_return_allocated()) {
@@ -1651,13 +1782,12 @@
           // update dependency information.
           // Mark it as NoEscape so that objects referenced by
           // it's fields will be marked as NoEscape at least.
-          set_escape_state(call->_idx, PointsToNode::NoEscape);
-          if (resproj != NULL)
-            add_pointsto_edge(resproj->_idx, call->_idx);
+          set_escape_state(call_idx, PointsToNode::NoEscape);
+          add_pointsto_edge(resproj_idx, call_idx);
           copy_dependencies = true;
-        } else if (call_analyzer->is_return_local() && resproj != NULL) {
+        } else if (call_analyzer->is_return_local()) {
           // determine whether any arguments are returned
-          set_escape_state(call->_idx, PointsToNode::NoEscape);
+          set_escape_state(call_idx, PointsToNode::NoEscape);
           for (uint i = TypeFunc::Parms; i < d->cnt(); i++) {
             const Type* at = d->field_at(i);
 
@@ -1665,36 +1795,35 @@
               Node *arg = call->in(i)->uncast();
 
               if (call_analyzer->is_arg_returned(i - TypeFunc::Parms)) {
-                PointsToNode *arg_esp = _nodes->adr_at(arg->_idx);
+                PointsToNode *arg_esp = ptnode_adr(arg->_idx);
                 if (arg_esp->node_type() == PointsToNode::UnknownType)
                   done = false;
                 else if (arg_esp->node_type() == PointsToNode::JavaObject)
-                  add_pointsto_edge(resproj->_idx, arg->_idx);
+                  add_pointsto_edge(resproj_idx, arg->_idx);
                 else
-                  add_deferred_edge(resproj->_idx, arg->_idx);
+                  add_deferred_edge(resproj_idx, arg->_idx);
                 arg_esp->_hidden_alias = true;
               }
             }
           }
           copy_dependencies = true;
         } else {
-          set_escape_state(call->_idx, PointsToNode::GlobalEscape);
-          if (resproj != NULL)
-            add_pointsto_edge(resproj->_idx, _phantom_object);
+          set_escape_state(call_idx, PointsToNode::GlobalEscape);
+          add_pointsto_edge(resproj_idx, _phantom_object);
           for (uint i = TypeFunc::Parms; i < d->cnt(); i++) {
             const Type* at = d->field_at(i);
             if (at->isa_oopptr() != NULL) {
               Node *arg = call->in(i)->uncast();
-              PointsToNode *arg_esp = _nodes->adr_at(arg->_idx);
+              PointsToNode *arg_esp = ptnode_adr(arg->_idx);
               arg_esp->_hidden_alias = true;
             }
           }
         }
         if (copy_dependencies)
-          call_analyzer->copy_dependencies(C()->dependencies());
+          call_analyzer->copy_dependencies(_compile->dependencies());
       }
       if (done)
-        _processed.set(resproj->_idx);
+        _processed.set(resproj_idx);
       break;
     }
 
@@ -1709,13 +1838,11 @@
         // Note:  we use isa_ptr() instead of isa_oopptr()  here because the
         //        _multianewarray functions return a TypeRawPtr.
         if (ret_type->isa_ptr() != NULL) {
-          PointsToNode *ptadr = ptnode_adr(call->_idx);
-          set_escape_state(call->_idx, PointsToNode::GlobalEscape);
-          if (resproj != NULL)
-            add_pointsto_edge(resproj->_idx, _phantom_object);
+          set_escape_state(call_idx, PointsToNode::GlobalEscape);
+          add_pointsto_edge(resproj_idx, _phantom_object);
         }
       }
-      _processed.set(resproj->_idx);
+      _processed.set(resproj_idx);
     }
   }
 }
@@ -1743,7 +1870,7 @@
 
       // Check if a call returns an object.
       const TypeTuple *r = n->as_Call()->tf()->range();
-      if (r->cnt() > TypeFunc::Parms &&
+      if (n->is_CallStaticJava() && r->cnt() > TypeFunc::Parms &&
           n->as_Call()->proj_out(TypeFunc::Parms) != NULL) {
         // Note:  use isa_ptr() instead of isa_oopptr() here because
         //        the _multianewarray functions return a TypeRawPtr.
@@ -1776,7 +1903,7 @@
     {
       add_node(n, PointsToNode::LocalVar, PointsToNode::UnknownEscape, false);
       int ti = n->in(1)->_idx;
-      PointsToNode::NodeType nt = _nodes->adr_at(ti)->node_type();
+      PointsToNode::NodeType nt = ptnode_adr(ti)->node_type();
       if (nt == PointsToNode::UnknownType) {
         _delayed_worklist.push(n); // Process it later.
         break;
@@ -1828,7 +1955,7 @@
     case Op_LoadN:
     {
       const Type *t = phase->type(n);
-      if (!t->isa_narrowoop() && t->isa_ptr() == NULL) {
+      if (t->make_ptr() == NULL) {
         _processed.set(n->_idx);
         return;
       }
@@ -1851,8 +1978,9 @@
     }
     case Op_Phi:
     {
-      if (n->as_Phi()->type()->isa_ptr() == NULL) {
-        // nothing to do if not an oop
+      const Type *t = n->as_Phi()->type();
+      if (t->make_ptr() == NULL) {
+        // nothing to do if not an oop or narrow oop
         _processed.set(n->_idx);
         return;
       }
@@ -1866,7 +1994,7 @@
         if (in->is_top() || in == n)
           continue;  // ignore top or inputs which go back this node
         int ti = in->_idx;
-        PointsToNode::NodeType nt = _nodes->adr_at(ti)->node_type();
+        PointsToNode::NodeType nt = ptnode_adr(ti)->node_type();
         if (nt == PointsToNode::UnknownType) {
           break;
         } else if (nt == PointsToNode::JavaObject) {
@@ -1904,7 +2032,7 @@
         // Treat Return value as LocalVar with GlobalEscape escape state.
         add_node(n, PointsToNode::LocalVar, PointsToNode::GlobalEscape, false);
         int ti = n->in(TypeFunc::Parms)->_idx;
-        PointsToNode::NodeType nt = _nodes->adr_at(ti)->node_type();
+        PointsToNode::NodeType nt = ptnode_adr(ti)->node_type();
         if (nt == PointsToNode::UnknownType) {
           _delayed_worklist.push(n); // Process it later.
           break;
@@ -1968,17 +2096,17 @@
 }
 
 void ConnectionGraph::build_connection_graph(Node *n, PhaseTransform *phase) {
+  uint n_idx = n->_idx;
+
   // Don't set processed bit for AddP, LoadP, StoreP since
   // they may need more then one pass to process.
-  if (_processed.test(n->_idx))
+  if (_processed.test(n_idx))
     return; // No need to redefine node's state.
 
-  PointsToNode *ptadr = ptnode_adr(n->_idx);
-
   if (n->is_Call()) {
     CallNode *call = n->as_Call();
     process_call_arguments(call, phase);
-    _processed.set(n->_idx);
+    _processed.set(n_idx);
     return;
   }
 
@@ -1991,7 +2119,7 @@
       PointsTo(ptset, base, phase);
       for( VectorSetI i(&ptset); i.test(); ++i ) {
         uint pt = i.elem;
-        add_field_edge(pt, n->_idx, address_offset(n, phase));
+        add_field_edge(pt, n_idx, address_offset(n, phase));
       }
       break;
     }
@@ -2006,12 +2134,12 @@
     case Op_DecodeN:
     {
       int ti = n->in(1)->_idx;
-      if (_nodes->adr_at(ti)->node_type() == PointsToNode::JavaObject) {
-        add_pointsto_edge(n->_idx, ti);
+      if (ptnode_adr(ti)->node_type() == PointsToNode::JavaObject) {
+        add_pointsto_edge(n_idx, ti);
       } else {
-        add_deferred_edge(n->_idx, ti);
+        add_deferred_edge(n_idx, ti);
       }
-      _processed.set(n->_idx);
+      _processed.set(n_idx);
       break;
     }
     case Op_ConP:
@@ -2040,7 +2168,7 @@
     {
       const Type *t = phase->type(n);
 #ifdef ASSERT
-      if (!t->isa_narrowoop() && t->isa_ptr() == NULL)
+      if (t->make_ptr() == NULL)
         assert(false, "Op_LoadP");
 #endif
 
@@ -2060,7 +2188,7 @@
       int offset = address_offset(adr, phase);
       for( VectorSetI i(&ptset); i.test(); ++i ) {
         uint pt = i.elem;
-        add_deferred_edge_to_fields(n->_idx, pt, offset);
+        add_deferred_edge_to_fields(n_idx, pt, offset);
       }
       break;
     }
@@ -2072,7 +2200,8 @@
     case Op_Phi:
     {
 #ifdef ASSERT
-      if (n->as_Phi()->type()->isa_ptr() == NULL)
+      const Type *t = n->as_Phi()->type();
+      if (t->make_ptr() == NULL)
         assert(false, "Op_Phi");
 #endif
       for (uint i = 1; i < n->req() ; i++) {
@@ -2083,13 +2212,13 @@
         if (in->is_top() || in == n)
           continue;  // ignore top or inputs which go back this node
         int ti = in->_idx;
-        if (_nodes->adr_at(in->_idx)->node_type() == PointsToNode::JavaObject) {
-          add_pointsto_edge(n->_idx, ti);
+        if (ptnode_adr(in->_idx)->node_type() == PointsToNode::JavaObject) {
+          add_pointsto_edge(n_idx, ti);
         } else {
-          add_deferred_edge(n->_idx, ti);
+          add_deferred_edge(n_idx, ti);
         }
       }
-      _processed.set(n->_idx);
+      _processed.set(n_idx);
       break;
     }
     case Op_Proj:
@@ -2097,7 +2226,7 @@
       // we are only interested in the result projection from a call
       if (n->as_Proj()->_con == TypeFunc::Parms && n->in(0)->is_Call() ) {
         process_call_result(n->as_Proj(), phase);
-        assert(_processed.test(n->_idx), "all call results should be processed");
+        assert(_processed.test(n_idx), "all call results should be processed");
       } else {
         assert(false, "Op_Proj");
       }
@@ -2112,12 +2241,12 @@
       }
 #endif
       int ti = n->in(TypeFunc::Parms)->_idx;
-      if (_nodes->adr_at(ti)->node_type() == PointsToNode::JavaObject) {
-        add_pointsto_edge(n->_idx, ti);
+      if (ptnode_adr(ti)->node_type() == PointsToNode::JavaObject) {
+        add_pointsto_edge(n_idx, ti);
       } else {
-        add_deferred_edge(n->_idx, ti);
+        add_deferred_edge(n_idx, ti);
       }
-      _processed.set(n->_idx);
+      _processed.set(n_idx);
       break;
     }
     case Op_StoreP:
@@ -2162,9 +2291,9 @@
   PhaseGVN  *igvn = _compile->initial_gvn();
   bool first = true;
 
-  uint size = (uint)_nodes->length();
+  uint size = nodes_size();
   for (uint ni = 0; ni < size; ni++) {
-    PointsToNode *ptn = _nodes->adr_at(ni);
+    PointsToNode *ptn = ptnode_adr(ni);
     PointsToNode::NodeType ptn_type = ptn->node_type();
 
     if (ptn_type != PointsToNode::JavaObject || ptn->_node == NULL)
@@ -2174,7 +2303,7 @@
       if (first) {
         tty->cr();
         tty->print("======== Connection graph for ");
-        C()->method()->print_short_name();
+        _compile->method()->print_short_name();
         tty->cr();
         first = false;
       }
@@ -2182,20 +2311,18 @@
       ptn->dump();
       // Print all locals which reference this allocation
       for (uint li = ni; li < size; li++) {
-        PointsToNode *ptn_loc = _nodes->adr_at(li);
+        PointsToNode *ptn_loc = ptnode_adr(li);
         PointsToNode::NodeType ptn_loc_type = ptn_loc->node_type();
         if ( ptn_loc_type == PointsToNode::LocalVar && ptn_loc->_node != NULL &&
              ptn_loc->edge_count() == 1 && ptn_loc->edge_target(0) == ni ) {
-          tty->print("%6d  LocalVar [[%d]]", li, ni);
-          _nodes->adr_at(li)->_node->dump();
+          ptnode_adr(li)->dump(false);
         }
       }
       if (Verbose) {
         // Print all fields which reference this allocation
         for (uint i = 0; i < ptn->edge_count(); i++) {
           uint ei = ptn->edge_target(i);
-          tty->print("%6d  Field [[%d]]", ei, ni);
-          _nodes->adr_at(ei)->_node->dump();
+          ptnode_adr(ei)->dump(false);
         }
       }
       tty->cr();
--- a/hotspot/src/share/vm/opto/escape.hpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/opto/escape.hpp	Wed Jul 05 16:40:29 2017 +0200
@@ -178,23 +178,33 @@
 
   // count of outgoing edges
   uint edge_count() const { return (_edges == NULL) ? 0 : _edges->length(); }
+
   // node index of target of outgoing edge "e"
-  uint edge_target(uint e)  const;
+  uint edge_target(uint e) const {
+    assert(_edges != NULL, "valid edge index");
+    return (_edges->at(e) >> EdgeShift);
+  }
   // type of outgoing edge "e"
-  EdgeType edge_type(uint e)  const;
+  EdgeType edge_type(uint e) const {
+    assert(_edges != NULL, "valid edge index");
+    return (EdgeType) (_edges->at(e) & EdgeMask);
+  }
+
   // add a edge of the specified type pointing to the specified target
   void add_edge(uint targIdx, EdgeType et);
+
   // remove an edge of the specified type pointing to the specified target
   void remove_edge(uint targIdx, EdgeType et);
+
 #ifndef PRODUCT
-  void dump() const;
+  void dump(bool print_state=true) const;
 #endif
 
 };
 
 class ConnectionGraph: public ResourceObj {
 private:
-  GrowableArray<PointsToNode>* _nodes; // Connection graph nodes indexed
+  GrowableArray<PointsToNode>  _nodes; // Connection graph nodes indexed
                                        // by ideal node index.
 
   Unique_Node_List  _delayed_worklist; // Nodes to be processed before
@@ -207,24 +217,22 @@
                                        // is still being collected. If false,
                                        // no new nodes will be processed.
 
-  bool               _has_allocations; // Indicates whether method has any
-                                       // non-escaping allocations.
-
   uint                _phantom_object; // Index of globally escaping object
                                        // that pointer values loaded from
                                        // a field which has not been set
                                        // are assumed to point to.
+  uint                      _oop_null; // ConP(#NULL)
+  uint                     _noop_null; // ConN(#NULL)
 
   Compile *                  _compile; // Compile object for current compilation
 
-  // address of an element in _nodes.  Used when the element is to be modified
-  PointsToNode *ptnode_adr(uint idx) {
-    if ((uint)_nodes->length() <= idx) {
-      // expand _nodes array
-      PointsToNode dummy = _nodes->at_grow(idx);
-    }
-    return _nodes->adr_at(idx);
+  // Address of an element in _nodes.  Used when the element is to be modified
+  PointsToNode *ptnode_adr(uint idx) const {
+    // There should be no new ideal nodes during ConnectionGraph build,
+    // growableArray::adr_at() will throw assert otherwise.
+    return _nodes.adr_at(idx);
   }
+  uint nodes_size() const { return _nodes.length(); }
 
   // Add node to ConnectionGraph.
   void add_node(Node *n, PointsToNode::NodeType nt, PointsToNode::EscapeState es, bool done);
@@ -307,30 +315,30 @@
   // Set the escape state of a node
   void set_escape_state(uint ni, PointsToNode::EscapeState es);
 
-  // Get Compile object for current compilation.
-  Compile *C() const        { return _compile; }
-
 public:
   ConnectionGraph(Compile *C);
 
+  // Check for non-escaping candidates
+  static bool has_candidates(Compile *C);
+
   // Compute the escape information
-  void compute_escape();
+  bool compute_escape();
 
   // escape state of a node
   PointsToNode::EscapeState escape_state(Node *n, PhaseTransform *phase);
   // other information we have collected
   bool is_scalar_replaceable(Node *n) {
-    if (_collecting)
+    if (_collecting || (n->_idx >= nodes_size()))
       return false;
-    PointsToNode  ptn = _nodes->at_grow(n->_idx);
-    return ptn.escape_state() == PointsToNode::NoEscape && ptn._scalar_replaceable;
+    PointsToNode* ptn = ptnode_adr(n->_idx);
+    return ptn->escape_state() == PointsToNode::NoEscape && ptn->_scalar_replaceable;
   }
 
   bool hidden_alias(Node *n) {
-    if (_collecting)
+    if (_collecting || (n->_idx >= nodes_size()))
       return true;
-    PointsToNode  ptn = _nodes->at_grow(n->_idx);
-    return (ptn.escape_state() != PointsToNode::NoEscape) || ptn._hidden_alias;
+    PointsToNode* ptn = ptnode_adr(n->_idx);
+    return (ptn->escape_state() != PointsToNode::NoEscape) || ptn->_hidden_alias;
   }
 
 #ifndef PRODUCT
--- a/hotspot/src/share/vm/opto/idealGraphPrinter.cpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/opto/idealGraphPrinter.cpp	Wed Jul 05 16:40:29 2017 +0200
@@ -473,10 +473,12 @@
         print_prop("is_dontcare", "false");
       }
 
+#ifdef ASSERT
       Node* old = C->matcher()->find_old_node(node);
       if (old != NULL) {
         print_prop("old_node_idx", old->_idx);
       }
+#endif
     }
 
     if (node->is_Proj()) {
--- a/hotspot/src/share/vm/opto/ifnode.cpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/opto/ifnode.cpp	Wed Jul 05 16:40:29 2017 +0200
@@ -725,6 +725,11 @@
   int true_path = phi->is_diamond_phi();
   if( true_path == 0 ) return NULL;
 
+  // Make sure that iff and the control of the phi are different. This
+  // should really only happen for dead control flow since it requires
+  // an illegal cycle.
+  if (phi->in(0)->in(1)->in(0) == iff) return NULL;
+
   // phi->region->if_proj->ifnode->bool->cmp
   BoolNode *bol2 = phi->in(0)->in(1)->in(0)->in(1)->as_Bool();
 
@@ -751,6 +756,7 @@
   }
 
   Node* new_bol = (flip ? phase->transform( bol2->negate(phase) ) : bol2);
+  assert(new_bol != iff->in(1), "must make progress");
   iff->set_req(1, new_bol);
   // Intervening diamond probably goes dead
   phase->C->set_major_progress();
--- a/hotspot/src/share/vm/opto/lcm.cpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/opto/lcm.cpp	Wed Jul 05 16:40:29 2017 +0200
@@ -322,7 +322,7 @@
   uint choice  = 0; // Bigger is most important
   uint latency = 0; // Bigger is scheduled first
   uint score   = 0; // Bigger is better
-  uint idx;         // Index in worklist
+  int idx = -1;     // Index in worklist
 
   for( uint i=0; i<cnt; i++ ) { // Inspect entire worklist
     // Order in worklist is used to break ties.
@@ -412,9 +412,10 @@
     }
   } // End of for all ready nodes in worklist
 
-  Node *n = worklist[idx];      // Get the winner
+  assert(idx >= 0, "index should be set");
+  Node *n = worklist[(uint)idx];      // Get the winner
 
-  worklist.map(idx,worklist.pop());     // Compress worklist
+  worklist.map((uint)idx, worklist.pop());     // Compress worklist
   return n;
 }
 
@@ -599,7 +600,14 @@
           assert(cfg->_bbs[oop_store->_idx]->_dom_depth <= this->_dom_depth, "oop_store must dominate card-mark");
         }
       }
-      if( n->is_Mach() && n->as_Mach()->ideal_Opcode() == Op_MemBarAcquire ) {
+      if( n->is_Mach() && n->as_Mach()->ideal_Opcode() == Op_MemBarAcquire &&
+          n->req() > TypeFunc::Parms ) {
+        // MemBarAcquire could be created without Precedent edge.
+        // del_req() replaces the specified edge with the last input edge
+        // and then removes the last edge. If the specified edge > number of
+        // edges the last edge will be moved outside of the input edges array
+        // and the edge will be lost. This is why this code should be
+        // executed only when Precedent (== TypeFunc::Parms) edge is present.
         Node *x = n->in(TypeFunc::Parms);
         n->del_req(TypeFunc::Parms);
         n->add_prec(x);
--- a/hotspot/src/share/vm/opto/loopopts.cpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/opto/loopopts.cpp	Wed Jul 05 16:40:29 2017 +0200
@@ -578,7 +578,8 @@
     Node *cmov = conditional_move( n );
     if( cmov ) return cmov;
   }
-  if( n->is_CFG() || n_op == Op_StorePConditional || n_op == Op_StoreLConditional || n_op == Op_CompareAndSwapI || n_op == Op_CompareAndSwapL ||n_op == Op_CompareAndSwapP)  return n;
+  if( n->is_CFG() || n->is_LoadStore() )
+    return n;
   if( n_op == Op_Opaque1 ||     // Opaque nodes cannot be mod'd
       n_op == Op_Opaque2 ) {
     if( !C->major_progress() )   // If chance of no more loop opts...
@@ -1891,18 +1892,19 @@
     _igvn.hash_delete(use);
     use->set_req(j, n_clone);
     _igvn._worklist.push(use);
+    Node* use_c;
     if (!use->is_Phi()) {
-      Node* use_c = has_ctrl(use) ? get_ctrl(use) : use->in(0);
-      set_ctrl(n_clone, use_c);
-      assert(!loop->is_member(get_loop(use_c)), "should be outside loop");
-      get_loop(use_c)->_body.push(n_clone);
+      use_c = has_ctrl(use) ? get_ctrl(use) : use->in(0);
     } else {
       // Use in a phi is considered a use in the associated predecessor block
-      Node *prevbb = use->in(0)->in(j);
-      set_ctrl(n_clone, prevbb);
-      assert(!loop->is_member(get_loop(prevbb)), "should be outside loop");
-      get_loop(prevbb)->_body.push(n_clone);
+      use_c = use->in(0)->in(j);
     }
+    if (use_c->is_CountedLoop()) {
+      use_c = use_c->in(LoopNode::EntryControl);
+    }
+    set_ctrl(n_clone, use_c);
+    assert(!loop->is_member(get_loop(use_c)), "should be outside loop");
+    get_loop(use_c)->_body.push(n_clone);
     _igvn.register_new_node_with_optimizer(n_clone);
 #if !defined(PRODUCT)
     if (TracePartialPeeling) {
--- a/hotspot/src/share/vm/opto/macro.cpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/opto/macro.cpp	Wed Jul 05 16:40:29 2017 +0200
@@ -194,9 +194,10 @@
 }
 
 // Search for a memory operation for the specified memory slice.
-static Node *scan_mem_chain(Node *mem, int alias_idx, int offset, Node *start_mem, Node *alloc) {
+static Node *scan_mem_chain(Node *mem, int alias_idx, int offset, Node *start_mem, Node *alloc, PhaseGVN *phase) {
   Node *orig_mem = mem;
   Node *alloc_mem = alloc->in(TypeFunc::Memory);
+  const TypeOopPtr *tinst = phase->C->get_adr_type(alias_idx)->isa_oopptr();
   while (true) {
     if (mem == alloc_mem || mem == start_mem ) {
       return mem;  // hit one of our sentinals
@@ -208,7 +209,13 @@
       // already know that the object is safe to eliminate.
       if (in->is_Initialize() && in->as_Initialize()->allocation() == alloc) {
         return in;
-      } else if (in->is_Call() || in->is_MemBar()) {
+      } else if (in->is_Call()) {
+        CallNode *call = in->as_Call();
+        if (!call->may_modify(tinst, phase)) {
+          mem = call->in(TypeFunc::Memory);
+        }
+        mem = in->in(TypeFunc::Memory);
+      } else if (in->is_MemBar()) {
         mem = in->in(TypeFunc::Memory);
       } else {
         assert(false, "unexpected projection");
@@ -231,8 +238,7 @@
     } else {
       return mem;
     }
-    if (mem == orig_mem)
-      return mem;
+    assert(mem != orig_mem, "dead memory loop");
   }
 }
 
@@ -241,27 +247,50 @@
 // on the input paths.
 // Note: this function is recursive, its depth is limied by the "level" argument
 // Returns the computed Phi, or NULL if it cannot compute it.
-Node *PhaseMacroExpand::value_from_mem_phi(Node *mem, BasicType ft, const Type *phi_type, const TypeOopPtr *adr_t, Node *alloc, int level) {
-
-  if (level <= 0) {
-    return NULL;
-  }
+Node *PhaseMacroExpand::value_from_mem_phi(Node *mem, BasicType ft, const Type *phi_type, const TypeOopPtr *adr_t, Node *alloc, Node_Stack *value_phis, int level) {
+  assert(mem->is_Phi(), "sanity");
   int alias_idx = C->get_alias_index(adr_t);
   int offset = adr_t->offset();
   int instance_id = adr_t->instance_id();
 
+  // Check if an appropriate value phi already exists.
+  Node* region = mem->in(0);
+  for (DUIterator_Fast kmax, k = region->fast_outs(kmax); k < kmax; k++) {
+    Node* phi = region->fast_out(k);
+    if (phi->is_Phi() && phi != mem &&
+        phi->as_Phi()->is_same_inst_field(phi_type, instance_id, alias_idx, offset)) {
+      return phi;
+    }
+  }
+  // Check if an appropriate new value phi already exists.
+  Node* new_phi = NULL;
+  uint size = value_phis->size();
+  for (uint i=0; i < size; i++) {
+    if ( mem->_idx == value_phis->index_at(i) ) {
+      return value_phis->node_at(i);
+    }
+  }
+
+  if (level <= 0) {
+    return NULL; // Give up: phi tree too deep
+  }
   Node *start_mem = C->start()->proj_out(TypeFunc::Memory);
   Node *alloc_mem = alloc->in(TypeFunc::Memory);
 
   uint length = mem->req();
   GrowableArray <Node *> values(length, length, NULL);
 
+  // create a new Phi for the value
+  PhiNode *phi = new (C, length) PhiNode(mem->in(0), phi_type, NULL, instance_id, alias_idx, offset);
+  transform_later(phi);
+  value_phis->push(phi, mem->_idx);
+
   for (uint j = 1; j < length; j++) {
     Node *in = mem->in(j);
     if (in == NULL || in->is_top()) {
       values.at_put(j, in);
     } else  {
-      Node *val = scan_mem_chain(in, alias_idx, offset, start_mem, alloc);
+      Node *val = scan_mem_chain(in, alias_idx, offset, start_mem, alloc, &_igvn);
       if (val == start_mem || val == alloc_mem) {
         // hit a sentinel, return appropriate 0 value
         values.at_put(j, _igvn.zerocon(ft));
@@ -280,33 +309,18 @@
       } else if(val->is_Proj() && val->in(0) == alloc) {
         values.at_put(j, _igvn.zerocon(ft));
       } else if (val->is_Phi()) {
-        // Check if an appropriate node already exists.
-        Node* region = val->in(0);
-        Node* old_phi = NULL;
-        for (DUIterator_Fast kmax, k = region->fast_outs(kmax); k < kmax; k++) {
-          Node* phi = region->fast_out(k);
-          if (phi->is_Phi() && phi != val &&
-              phi->as_Phi()->is_same_inst_field(phi_type, instance_id, alias_idx, offset)) {
-            old_phi = phi;
-            break;
-          }
+        val = value_from_mem_phi(val, ft, phi_type, adr_t, alloc, value_phis, level-1);
+        if (val == NULL) {
+          return NULL;
         }
-        if (old_phi == NULL) {
-          val = value_from_mem_phi(val, ft, phi_type, adr_t, alloc, level-1);
-          if (val == NULL) {
-            return NULL;
-          }
-          values.at_put(j, val);
-        } else {
-          values.at_put(j, old_phi);
-        }
+        values.at_put(j, val);
       } else {
-        return NULL;  // unknown node  on this path
+        assert(false, "unknown node on this path");
+        return NULL;  // unknown node on this path
       }
     }
   }
-  // create a new Phi for the value
-  PhiNode *phi = new (C, length) PhiNode(mem->in(0), phi_type, NULL, instance_id, alias_idx, offset);
+  // Set Phi's inputs
   for (uint j = 1; j < length; j++) {
     if (values.at(j) == mem) {
       phi->init_req(j, phi);
@@ -314,7 +328,6 @@
       phi->init_req(j, values.at(j));
     }
   }
-  transform_later(phi);
   return phi;
 }
 
@@ -329,7 +342,8 @@
   Node *start_mem = C->start()->proj_out(TypeFunc::Memory);
   Node *alloc_ctrl = alloc->in(TypeFunc::Control);
   Node *alloc_mem = alloc->in(TypeFunc::Memory);
-  VectorSet visited(Thread::current()->resource_area());
+  Arena *a = Thread::current()->resource_area();
+  VectorSet visited(a);
 
 
   bool done = sfpt_mem == alloc_mem;
@@ -338,7 +352,7 @@
     if (visited.test_set(mem->_idx)) {
       return NULL;  // found a loop, give up
     }
-    mem = scan_mem_chain(mem, alias_idx, offset, start_mem, alloc);
+    mem = scan_mem_chain(mem, alias_idx, offset, start_mem, alloc, &_igvn);
     if (mem == start_mem || mem == alloc_mem) {
       done = true;  // hit a sentinel, return appropriate 0 value
     } else if (mem->is_Initialize()) {
@@ -362,7 +376,7 @@
       Node *unique_input = NULL;
       Node *top = C->top();
       for (uint i = 1; i < mem->req(); i++) {
-        Node *n = scan_mem_chain(mem->in(i), alias_idx, offset, start_mem, alloc);
+        Node *n = scan_mem_chain(mem->in(i), alias_idx, offset, start_mem, alloc, &_igvn);
         if (n == NULL || n == top || n == mem) {
           continue;
         } else if (unique_input == NULL) {
@@ -389,9 +403,18 @@
       return mem->in(MemNode::ValueIn);
     } else if (mem->is_Phi()) {
       // attempt to produce a Phi reflecting the values on the input paths of the Phi
-      Node * phi = value_from_mem_phi(mem, ft, ftype, adr_t, alloc, 8);
+      Node_Stack value_phis(a, 8);
+      Node * phi = value_from_mem_phi(mem, ft, ftype, adr_t, alloc, &value_phis, ValueSearchLimit);
       if (phi != NULL) {
         return phi;
+      } else {
+        // Kill all new Phis
+        while(value_phis.is_nonempty()) {
+          Node* n = value_phis.node();
+          _igvn.hash_delete(n);
+          _igvn.subsume_node(n, C->top());
+          value_phis.pop();
+        }
       }
     }
   }
@@ -448,7 +471,7 @@
           Node* n = use->fast_out(k);
           if (!n->is_Store() && n->Opcode() != Op_CastP2X) {
             DEBUG_ONLY(disq_node = n;)
-            if (n->is_Load()) {
+            if (n->is_Load() || n->is_LoadStore()) {
               NOT_PRODUCT(fail_eliminate = "Field load";)
             } else {
               NOT_PRODUCT(fail_eliminate = "Not store field referrence";)
--- a/hotspot/src/share/vm/opto/macro.hpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/opto/macro.hpp	Wed Jul 05 16:40:29 2017 +0200
@@ -79,7 +79,7 @@
                               const TypeFunc* slow_call_type,
                               address slow_call_address);
   Node *value_from_mem(Node *mem, BasicType ft, const Type *ftype, const TypeOopPtr *adr_t, Node *alloc);
-  Node *value_from_mem_phi(Node *mem, BasicType ft, const Type *ftype, const TypeOopPtr *adr_t, Node *alloc, int level);
+  Node *value_from_mem_phi(Node *mem, BasicType ft, const Type *ftype, const TypeOopPtr *adr_t, Node *alloc, Node_Stack *value_phis, int level);
 
   bool eliminate_allocate_node(AllocateNode *alloc);
   bool can_eliminate_allocation(AllocateNode *alloc, GrowableArray <SafePointNode *>& safepoints);
--- a/hotspot/src/share/vm/opto/memnode.cpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/opto/memnode.cpp	Wed Jul 05 16:40:29 2017 +0200
@@ -94,14 +94,19 @@
   if (tinst == NULL || !tinst->is_known_instance_field())
     return mchain;  // don't try to optimize non-instance types
   uint instance_id = tinst->instance_id();
+  Node *start_mem = phase->C->start()->proj_out(TypeFunc::Memory);
   Node *prev = NULL;
   Node *result = mchain;
   while (prev != result) {
     prev = result;
+    if (result == start_mem)
+      break;  // hit one of our sentinals
     // skip over a call which does not affect this memory slice
     if (result->is_Proj() && result->as_Proj()->_con == TypeFunc::Memory) {
       Node *proj_in = result->in(0);
-      if (proj_in->is_Call()) {
+      if (proj_in->is_Allocate() && proj_in->_idx == instance_id) {
+        break;  // hit one of our sentinals
+      } else if (proj_in->is_Call()) {
         CallNode *call = proj_in->as_Call();
         if (!call->may_modify(t_adr, phase)) {
           result = call->in(TypeFunc::Memory);
@@ -115,6 +120,8 @@
         }
       } else if (proj_in->is_MemBar()) {
         result = proj_in->in(TypeFunc::Memory);
+      } else {
+        assert(false, "unexpected projection");
       }
     } else if (result->is_MergeMem()) {
       result = step_through_mergemem(phase, result->as_MergeMem(), t_adr, NULL, tty);
@@ -135,7 +142,9 @@
     const TypePtr *t = mphi->adr_type();
     if (t == TypePtr::BOTTOM || t == TypeRawPtr::BOTTOM ||
         t->isa_oopptr() && !t->is_oopptr()->is_known_instance() &&
-        t->is_oopptr()->cast_to_instance_id(t_oop->instance_id()) == t_oop) {
+        t->is_oopptr()->cast_to_exactness(true)
+         ->is_oopptr()->cast_to_ptr_type(t_oop->ptr())
+         ->is_oopptr()->cast_to_instance_id(t_oop->instance_id()) == t_oop) {
       // clone the Phi with our address type
       result = mphi->split_out_instance(t_adr, igvn);
     } else {
--- a/hotspot/src/share/vm/opto/memnode.hpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/opto/memnode.hpp	Wed Jul 05 16:40:29 2017 +0200
@@ -607,6 +607,7 @@
 };
 
 //------------------------------LoadStoreNode---------------------------
+// Note: is_Mem() method returns 'true' for this class.
 class LoadStoreNode : public Node {
 public:
   enum {
--- a/hotspot/src/share/vm/opto/node.hpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/opto/node.hpp	Wed Jul 05 16:40:29 2017 +0200
@@ -1399,6 +1399,10 @@
   uint index() const {
     return _inode_top->indx;
   }
+  uint index_at(uint i) const {
+    assert(_inodes + i <= _inode_top, "in range");
+    return _inodes[i].indx;
+  }
   void set_node(Node *n) {
     _inode_top->node = n;
   }
--- a/hotspot/src/share/vm/opto/parse.hpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/opto/parse.hpp	Wed Jul 05 16:40:29 2017 +0200
@@ -479,7 +479,7 @@
   float   branch_prediction(float &cnt, BoolTest::mask btest, int target_bci);
   bool    seems_never_taken(float prob);
 
-  void    do_ifnull(BoolTest::mask btest);
+  void    do_ifnull(BoolTest::mask btest, Node* c);
   void    do_if(BoolTest::mask btest, Node* c);
   void    repush_if_args();
   void    adjust_map_after_if(BoolTest::mask btest, Node* c, float prob,
--- a/hotspot/src/share/vm/opto/parse2.cpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/opto/parse2.cpp	Wed Jul 05 16:40:29 2017 +0200
@@ -875,6 +875,8 @@
   return prob < PROB_MIN;
 }
 
+//-------------------------------repush_if_args--------------------------------
+// Push arguments of an "if" bytecode back onto the stack by adjusting _sp.
 inline void Parse::repush_if_args() {
 #ifndef PRODUCT
   if (PrintOpto && WizardMode) {
@@ -892,7 +894,7 @@
 }
 
 //----------------------------------do_ifnull----------------------------------
-void Parse::do_ifnull(BoolTest::mask btest) {
+void Parse::do_ifnull(BoolTest::mask btest, Node *c) {
   int target_bci = iter().get_dest();
 
   Block* branch_block = successor_for_bci(target_bci);
@@ -904,7 +906,7 @@
     // (An earlier version of do_ifnull omitted this trap for OSR methods.)
 #ifndef PRODUCT
     if (PrintOpto && Verbose)
-      tty->print_cr("Never-taken backedge stops compilation at bci %d",bci());
+      tty->print_cr("Never-taken edge stops compilation at bci %d",bci());
 #endif
     repush_if_args(); // to gather stats on loop
     // We need to mark this branch as taken so that if we recompile we will
@@ -923,18 +925,7 @@
     return;
   }
 
-  // If this is a backwards branch in the bytecodes, add Safepoint
-  maybe_add_safepoint(target_bci);
-
   explicit_null_checks_inserted++;
-  Node* a = null();
-  Node* b = pop();
-  Node* c = _gvn.transform( new (C, 3) CmpPNode(b, a) );
-
-  // Make a cast-away-nullness that is control dependent on the test
-  const Type *t = _gvn.type(b);
-  const Type *t_not_null = t->join(TypePtr::NOTNULL);
-  Node *cast = new (C, 2) CastPPNode(b,t_not_null);
 
   // Generate real control flow
   Node   *tst = _gvn.transform( new (C, 2) BoolNode( c, btest ) );
@@ -996,7 +987,7 @@
   if (prob == PROB_UNKNOWN) {
 #ifndef PRODUCT
     if (PrintOpto && Verbose)
-      tty->print_cr("Never-taken backedge stops compilation at bci %d",bci());
+      tty->print_cr("Never-taken edge stops compilation at bci %d",bci());
 #endif
     repush_if_args(); // to gather stats on loop
     // We need to mark this branch as taken so that if we recompile we will
@@ -2100,11 +2091,15 @@
     break;
   }
 
-  case Bytecodes::_ifnull:
-    do_ifnull(BoolTest::eq);
-    break;
-  case Bytecodes::_ifnonnull:
-    do_ifnull(BoolTest::ne);
+  case Bytecodes::_ifnull:    btest = BoolTest::eq; goto handle_if_null;
+  case Bytecodes::_ifnonnull: btest = BoolTest::ne; goto handle_if_null;
+  handle_if_null:
+    // If this is a backwards branch in the bytecodes, add Safepoint
+    maybe_add_safepoint(iter().get_dest());
+    a = null();
+    b = pop();
+    c = _gvn.transform( new (C, 3) CmpPNode(b, a) );
+    do_ifnull(btest, c);
     break;
 
   case Bytecodes::_if_acmpeq: btest = BoolTest::eq; goto handle_if_acmp;
--- a/hotspot/src/share/vm/opto/superword.cpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/opto/superword.cpp	Wed Jul 05 16:40:29 2017 +0200
@@ -1196,8 +1196,10 @@
     Node *n = lp()->fast_out(i);
     if (in_bb(n) && (n->is_Phi() && n->bottom_type() == Type::MEMORY)) {
       Node* n_tail  = n->in(LoopNode::LoopBackControl);
-      _mem_slice_head.push(n);
-      _mem_slice_tail.push(n_tail);
+      if (n_tail != n->in(LoopNode::EntryControl)) {
+        _mem_slice_head.push(n);
+        _mem_slice_tail.push(n_tail);
+      }
     }
   }
 
--- a/hotspot/src/share/vm/opto/type.cpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/opto/type.cpp	Wed Jul 05 16:40:29 2017 +0200
@@ -2218,7 +2218,7 @@
   return make(ptr, _offset);
 }
 
-//-----------------------------cast_to_instance-------------------------------
+//-----------------------------cast_to_instance_id----------------------------
 const TypeOopPtr *TypeOopPtr::cast_to_instance_id(int instance_id) const {
   // There are no instances of a general oop.
   // Return self unchanged.
@@ -2610,8 +2610,7 @@
   // Ptr is never Null
   assert( ptr != Null, "NULL pointers are not typed" );
 
-  if ( instance_id > 0 )
-    xk = true;  // instances are always exactly typed
+  assert(instance_id <= 0 || xk || !UseExactTypes, "instances are always exactly typed");
   if (!UseExactTypes)  xk = false;
   if (ptr == Constant) {
     // Note:  This case includes meta-object constants, such as methods.
@@ -2650,16 +2649,10 @@
   return make(ptr(), klass(), klass_is_exact, const_oop(), _offset, _instance_id);
 }
 
-//-----------------------------cast_to_instance-------------------------------
+//-----------------------------cast_to_instance_id----------------------------
 const TypeOopPtr *TypeInstPtr::cast_to_instance_id(int instance_id) const {
   if( instance_id == _instance_id ) return this;
-  bool exact = _klass_is_exact;
-  PTR  ptr_t = _ptr;
-  if ( instance_id > 0 ) { // instances are always exactly typed
-    if (UseExactTypes) exact = true;
-    ptr_t = NotNull;
-  }
-  return make(ptr_t, klass(), exact, const_oop(), _offset, instance_id);
+  return make(_ptr, klass(), _klass_is_exact, const_oop(), _offset, instance_id);
 }
 
 //------------------------------xmeet_unloaded---------------------------------
@@ -2899,6 +2892,7 @@
         xk = above_centerline(ptr) ? tinst_xk : false;
         // Watch out for Constant vs. AnyNull interface.
         if (ptr == Constant)  ptr = NotNull;   // forget it was a constant
+        instance_id = InstanceBot;
       }
       ciObject* o = NULL;  // the Constant value, if any
       if (ptr == Constant) {
@@ -2989,6 +2983,7 @@
     // class hierarchy - which means we have to fall to at least NotNull.
     if( ptr == TopPTR || ptr == AnyNull || ptr == Constant )
       ptr = NotNull;
+    instance_id = InstanceBot;
 
     // Now we find the LCA of Java classes
     ciKlass* k = this_klass->least_common_ancestor(tinst_klass);
@@ -3101,8 +3096,7 @@
   assert(!(k == NULL && ary->_elem->isa_int()),
          "integral arrays must be pre-equipped with a class");
   if (!xk)  xk = ary->ary_must_be_exact();
-  if ( instance_id > 0 )
-    xk = true;  // instances are always exactly typed
+  assert(instance_id <= 0 || xk || !UseExactTypes, "instances are always exactly typed");
   if (!UseExactTypes)  xk = (ptr == Constant);
   return (TypeAryPtr*)(new TypeAryPtr(ptr, NULL, ary, k, xk, offset, instance_id))->hashcons();
 }
@@ -3113,8 +3107,7 @@
          "integral arrays must be pre-equipped with a class");
   assert( (ptr==Constant && o) || (ptr!=Constant && !o), "" );
   if (!xk)  xk = (o != NULL) || ary->ary_must_be_exact();
-  if ( instance_id > 0 )
-    xk = true;  // instances are always exactly typed
+  assert(instance_id <= 0 || xk || !UseExactTypes, "instances are always exactly typed");
   if (!UseExactTypes)  xk = (ptr == Constant);
   return (TypeAryPtr*)(new TypeAryPtr(ptr, o, ary, k, xk, offset, instance_id))->hashcons();
 }
@@ -3134,16 +3127,10 @@
   return make(ptr(), const_oop(), _ary, klass(), klass_is_exact, _offset, _instance_id);
 }
 
-//-----------------------------cast_to_instance-------------------------------
+//-----------------------------cast_to_instance_id----------------------------
 const TypeOopPtr *TypeAryPtr::cast_to_instance_id(int instance_id) const {
   if( instance_id == _instance_id ) return this;
-  bool exact = _klass_is_exact;
-  PTR  ptr_t = _ptr;
-  if ( instance_id > 0 ) { // instances are always exactly typed
-    if (UseExactTypes) exact = true;
-    ptr_t = NotNull;
-  }
-  return make(ptr_t, const_oop(), _ary, klass(), exact, _offset, instance_id);
+  return make(_ptr, const_oop(), _ary, klass(), _klass_is_exact, _offset, instance_id);
 }
 
 //-----------------------------narrow_size_type-------------------------------
@@ -3300,6 +3287,7 @@
       } else {
         // Something like byte[int+] meets char[int+].
         // This must fall to bottom, not (int[-128..65535])[int+].
+        instance_id = InstanceBot;
         tary = TypeAry::make(Type::BOTTOM, tary->_size);
       }
     }
@@ -3316,6 +3304,7 @@
         if( tap->const_oop() != NULL && !o->equals(tap->const_oop()) ) {
           ptr = NotNull;
           o = NULL;
+          instance_id = InstanceBot;
         }
       } else if( above_centerline(_ptr) ) {
         o = tap->const_oop();
--- a/hotspot/src/share/vm/runtime/arguments.cpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/runtime/arguments.cpp	Wed Jul 05 16:40:29 2017 +0200
@@ -153,37 +153,56 @@
   os::init_system_properties_values();
 }
 
-// String containing commands that will be ignored and cause a
-// warning to be issued.  These commands should be accepted
-// for 1.6 but not 1.7.  The string should be cleared at the
-// beginning of 1.7.
-static const char*  obsolete_jvm_flags_1_5_0[] = {
-                                           "UseTrainGC",
-                                           "UseSpecialLargeObjectHandling",
-                                           "UseOversizedCarHandling",
-                                           "TraceCarAllocation",
-                                           "PrintTrainGCProcessingStats",
-                                           "LogOfCarSpaceSize",
-                                           "OversizedCarThreshold",
-                                           "MinTickInterval",
-                                           "DefaultTickInterval",
-                                           "MaxTickInterval",
-                                           "DelayTickAdjustment",
-                                           "ProcessingToTenuringRatio",
-                                           "MinTrainLength",
-                                           0};
+/**
+ * Provide a slightly more user-friendly way of eliminating -XX flags.
+ * When a flag is eliminated, it can be added to this list in order to
+ * continue accepting this flag on the command-line, while issuing a warning
+ * and ignoring the value.  Once the JDK version reaches the 'accept_until'
+ * limit, we flatly refuse to admit the existence of the flag.  This allows
+ * a flag to die correctly over JDK releases using HSX.
+ */
+typedef struct {
+  const char* name;
+  JDK_Version obsoleted_in; // when the flag went away
+  JDK_Version accept_until; // which version to start denying the existence
+} ObsoleteFlag;
 
-bool Arguments::made_obsolete_in_1_5_0(const char *s) {
+static ObsoleteFlag obsolete_jvm_flags[] = {
+  { "UseTrainGC",                    JDK_Version::jdk(5), JDK_Version::jdk(7) },
+  { "UseSpecialLargeObjectHandling", JDK_Version::jdk(5), JDK_Version::jdk(7) },
+  { "UseOversizedCarHandling",       JDK_Version::jdk(5), JDK_Version::jdk(7) },
+  { "TraceCarAllocation",            JDK_Version::jdk(5), JDK_Version::jdk(7) },
+  { "PrintTrainGCProcessingStats",   JDK_Version::jdk(5), JDK_Version::jdk(7) },
+  { "LogOfCarSpaceSize",             JDK_Version::jdk(5), JDK_Version::jdk(7) },
+  { "OversizedCarThreshold",         JDK_Version::jdk(5), JDK_Version::jdk(7) },
+  { "MinTickInterval",               JDK_Version::jdk(5), JDK_Version::jdk(7) },
+  { "DefaultTickInterval",           JDK_Version::jdk(5), JDK_Version::jdk(7) },
+  { "MaxTickInterval",               JDK_Version::jdk(5), JDK_Version::jdk(7) },
+  { "DelayTickAdjustment",           JDK_Version::jdk(5), JDK_Version::jdk(7) },
+  { "ProcessingToTenuringRatio",     JDK_Version::jdk(5), JDK_Version::jdk(7) },
+  { "MinTrainLength",                JDK_Version::jdk(5), JDK_Version::jdk(7) },
+  { "AppendRatio",         JDK_Version::jdk_update(6,10), JDK_Version::jdk(7) },
+  { NULL, JDK_Version(0), JDK_Version(0) }
+};
+
+// Returns true if the flag is obsolete and fits into the range specified
+// for being ignored.  In the case that the flag is ignored, the 'version'
+// value is filled in with the version number when the flag became
+// obsolete so that that value can be displayed to the user.
+bool Arguments::is_newly_obsolete(const char *s, JDK_Version* version) {
   int i = 0;
-  while (obsolete_jvm_flags_1_5_0[i] != NULL) {
+  assert(version != NULL, "Must provide a version buffer");
+  while (obsolete_jvm_flags[i].name != NULL) {
+    const ObsoleteFlag& flag_status = obsolete_jvm_flags[i];
     // <flag>=xxx form
     // [-|+]<flag> form
-    if ((strncmp(obsolete_jvm_flags_1_5_0[i], s,
-               strlen(obsolete_jvm_flags_1_5_0[i])) == 0) ||
+    if ((strncmp(flag_status.name, s, strlen(flag_status.name)) == 0) ||
         ((s[0] == '+' || s[0] == '-') &&
-        (strncmp(obsolete_jvm_flags_1_5_0[i], &s[1],
-               strlen(obsolete_jvm_flags_1_5_0[i])) == 0))) {
-      return true;
+        (strncmp(flag_status.name, &s[1], strlen(flag_status.name)) == 0))) {
+      if (JDK_Version::current().compare(flag_status.accept_until) == -1) {
+          *version = flag_status.obsoleted_in;
+          return true;
+      }
     }
     i++;
   }
@@ -705,14 +724,20 @@
   }
 }
 
-bool Arguments::process_argument(const char* arg, jboolean ignore_unrecognized, FlagValueOrigin origin) {
+bool Arguments::process_argument(const char* arg,
+    jboolean ignore_unrecognized, FlagValueOrigin origin) {
+
+  JDK_Version since = JDK_Version();
 
   if (parse_argument(arg, origin)) {
     // do nothing
-  } else if (made_obsolete_in_1_5_0(arg)) {
+  } else if (is_newly_obsolete(arg, &since)) {
+    enum { bufsize = 256 };
+    char buffer[bufsize];
+    since.to_string(buffer, bufsize);
     jio_fprintf(defaultStream::error_stream(),
-      "Warning: The flag %s has been EOL'd as of 1.5.0 and will"
-      " be ignored\n", arg);
+      "Warning: The flag %s has been EOL'd as of %s and will"
+      " be ignored\n", arg, buffer);
   } else {
     if (!ignore_unrecognized) {
       jio_fprintf(defaultStream::error_stream(),
@@ -2471,6 +2496,9 @@
     if (match_option(option, "-XX:+PrintVMOptions", &tail)) {
       PrintVMOptions = true;
     }
+    if (match_option(option, "-XX:-PrintVMOptions", &tail)) {
+      PrintVMOptions = false;
+    }
   }
 
   // Parse default .hotspotrc settings file
--- a/hotspot/src/share/vm/runtime/arguments.hpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/runtime/arguments.hpp	Wed Jul 05 16:40:29 2017 +0200
@@ -357,9 +357,11 @@
     short* methodsNum, short* methodsMax, char*** methods, bool** allClasses
   );
 
-  // Returns true if the string s is in the list of
-  // flags made obsolete in 1.5.0.
-  static bool made_obsolete_in_1_5_0(const char* s);
+  // Returns true if the string s is in the list of flags that have recently
+  // been made obsolete.  If we detect one of these flags on the command
+  // line, instead of failing we print a warning message and ignore the
+  // flag.  This gives the user a release or so to stop using the flag.
+  static bool is_newly_obsolete(const char* s, JDK_Version* buffer);
 
   static short  CompileOnlyClassesNum;
   static short  CompileOnlyClassesMax;
--- a/hotspot/src/share/vm/runtime/globals.hpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/runtime/globals.hpp	Wed Jul 05 16:40:29 2017 +0200
@@ -589,9 +589,15 @@
   develop(bool, ZapJNIHandleArea, trueInDebug,                              \
           "Zap freed JNI handle space with 0xFEFEFEFE")                     \
                                                                             \
-  develop(bool, ZapUnusedHeapArea, false,                                   \
+  develop(bool, ZapUnusedHeapArea, trueInDebug,                             \
           "Zap unused heap space with 0xBAADBABE")                          \
                                                                             \
+  develop(bool, TraceZapUnusedHeapArea, false,                              \
+          "Trace zapping of unused heap space")                             \
+                                                                            \
+  develop(bool, CheckZapUnusedHeapArea, false,                              \
+          "Check zapping of unused heap space")                             \
+                                                                            \
   develop(bool, PrintVMMessages, true,                                      \
           "Print vm messages on console")                                   \
                                                                             \
--- a/hotspot/src/share/vm/runtime/init.cpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/runtime/init.cpp	Wed Jul 05 16:40:29 2017 +0200
@@ -39,7 +39,6 @@
 void classLoader_init();
 void codeCache_init();
 void VM_Version_init();
-void JDK_Version_init();
 void stubRoutines_init1();
 jint universe_init();  // dependent on codeCache_init and stubRoutines_init
 void interpreter_init();  // before any methods loaded
@@ -88,7 +87,6 @@
   classLoader_init();
   codeCache_init();
   VM_Version_init();
-  JDK_Version_init();
   stubRoutines_init1();
   jint status = universe_init();  // dependent on codeCache_init and stubRoutines_init
   if (status != JNI_OK)
--- a/hotspot/src/share/vm/runtime/java.cpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/runtime/java.cpp	Wed Jul 05 16:40:29 2017 +0200
@@ -563,32 +563,104 @@
   vm_shutdown();
 }
 
-jdk_version_info JDK_Version::_version_info = {0};
-bool JDK_Version::_pre_jdk16_version = false;
-int  JDK_Version::_jdk_version = 0;
+JDK_Version JDK_Version::_current;
 
 void JDK_Version::initialize() {
+  jdk_version_info info;
+  assert(!_current.is_valid(), "Don't initialize twice");
+
   void *lib_handle = os::native_java_library();
-  jdk_version_info_fn_t func =
-    CAST_TO_FN_PTR(jdk_version_info_fn_t, hpi::dll_lookup(lib_handle, "JDK_GetVersionInfo0"));
+  jdk_version_info_fn_t func = CAST_TO_FN_PTR(jdk_version_info_fn_t,
+     os::dll_lookup(lib_handle, "JDK_GetVersionInfo0"));
 
   if (func == NULL) {
     // JDK older than 1.6
-    _pre_jdk16_version = true;
-    return;
-  }
+    _current._partially_initialized = true;
+  } else {
+    (*func)(&info, sizeof(info));
 
-  if (func != NULL) {
-    (*func)(&_version_info, sizeof(_version_info));
+    int major = JDK_VERSION_MAJOR(info.jdk_version);
+    int minor = JDK_VERSION_MINOR(info.jdk_version);
+    int micro = JDK_VERSION_MICRO(info.jdk_version);
+    int build = JDK_VERSION_BUILD(info.jdk_version);
+    if (major == 1 && minor > 4) {
+      // We represent "1.5.0" as "5.0", but 1.4.2 as itself.
+      major = minor;
+      minor = micro;
+      micro = 0;
+    }
+    _current = JDK_Version(major, minor, micro, info.update_version,
+                           info.special_update_version, build,
+                           info.thread_park_blocker == 1);
   }
-  if (jdk_major_version() == 1) {
-    _jdk_version = jdk_minor_version();
-  } else {
-    // If the release version string is changed to n.x.x (e.g. 7.0.0) in a future release
-    _jdk_version = jdk_major_version();
+}
+
+void JDK_Version::fully_initialize(
+    uint8_t major, uint8_t minor, uint8_t micro, uint8_t update) {
+  // This is only called when current is less than 1.6 and we've gotten
+  // far enough in the initialization to determine the exact version.
+  assert(major < 6, "not needed for JDK version >= 6");
+  assert(is_partially_initialized(), "must not initialize");
+  if (major < 5) {
+    // JDK verison sequence: 1.2.x, 1.3.x, 1.4.x, 5.0.x, 6.0.x, etc.
+    micro = minor;
+    minor = major;
+    major = 1;
   }
+  _current = JDK_Version(major, minor, micro, update);
 }
 
 void JDK_Version_init() {
   JDK_Version::initialize();
 }
+
+static int64_t encode_jdk_version(const JDK_Version& v) {
+  return
+    ((int64_t)v.major_version()          << (BitsPerByte * 5)) |
+    ((int64_t)v.minor_version()          << (BitsPerByte * 4)) |
+    ((int64_t)v.micro_version()          << (BitsPerByte * 3)) |
+    ((int64_t)v.update_version()         << (BitsPerByte * 2)) |
+    ((int64_t)v.special_update_version() << (BitsPerByte * 1)) |
+    ((int64_t)v.build_number()           << (BitsPerByte * 0));
+}
+
+int JDK_Version::compare(const JDK_Version& other) const {
+  assert(is_valid() && other.is_valid(), "Invalid version (uninitialized?)");
+  if (!is_partially_initialized() && other.is_partially_initialized()) {
+    return -(other.compare(*this)); // flip the comparators
+  }
+  assert(!other.is_partially_initialized(), "Not initialized yet");
+  if (is_partially_initialized()) {
+    assert(other.major_version() >= 6,
+           "Invalid JDK version comparison during initialization");
+    return -1;
+  } else {
+    uint64_t e = encode_jdk_version(*this);
+    uint64_t o = encode_jdk_version(other);
+    return (e > o) ? 1 : ((e == o) ? 0 : -1);
+  }
+}
+
+void JDK_Version::to_string(char* buffer, size_t buflen) const {
+  size_t index = 0;
+  if (!is_valid()) {
+    jio_snprintf(buffer, buflen, "%s", "(uninitialized)");
+  } else if (is_partially_initialized()) {
+    jio_snprintf(buffer, buflen, "%s", "(uninitialized) pre-1.6.0");
+  } else {
+    index += jio_snprintf(
+        &buffer[index], buflen - index, "%d.%d", _major, _minor);
+    if (_micro > 0) {
+      index += jio_snprintf(&buffer[index], buflen - index, ".%d", _micro);
+    }
+    if (_update > 0) {
+      index += jio_snprintf(&buffer[index], buflen - index, "_%02d", _update);
+    }
+    if (_special > 0) {
+      index += jio_snprintf(&buffer[index], buflen - index, "%c", _special);
+    }
+    if (_build > 0) {
+      index += jio_snprintf(&buffer[index], buflen - index, "-b%02d", _build);
+    }
+  }
+}
--- a/hotspot/src/share/vm/runtime/java.hpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/runtime/java.hpp	Wed Jul 05 16:40:29 2017 +0200
@@ -48,100 +48,163 @@
 extern void vm_exit_during_initialization(const char* error, const char* message = NULL);
 extern void vm_shutdown_during_initialization(const char* error, const char* message = NULL);
 
-class JDK_Version : AllStatic {
+/**
+ * Discovering the JDK_Version during initialization is tricky when the
+ * running JDK is less than JDK6.  For JDK6 and greater, a "GetVersion"
+ * function exists in libjava.so and we simply call it during the
+ * 'initialize()' call to find the version.  For JDKs with version < 6, no
+ * such call exists and we have to probe the JDK in order to determine
+ * the exact version.  This probing cannot happen during late in
+ * the VM initialization process so there's a period of time during
+ * initialization when we don't know anything about the JDK version other than
+ * that it less than version 6.  This is the "partially initialized" time,
+ * when we can answer only certain version queries (such as, is the JDK
+ * version greater than 5?  Answer: no).  Once the JDK probing occurs, we
+ * know the version and are considered fully initialized.
+ */
+class JDK_Version VALUE_OBJ_CLASS_SPEC {
   friend class VMStructs;
+  friend class Universe;
+  friend void JDK_Version_init();
  private:
-  static jdk_version_info _version_info;
-  static bool             _pre_jdk16_version;
-  static int              _jdk_version;  // JDK version number representing the release
-                                         //  i.e. n in 1.n.x (= jdk_minor_version())
+
+  static JDK_Version _current;
+
+  // In this class, we promote the minor version of release to be the
+  // major version for releases >= 5 in anticipation of the JDK doing the
+  // same thing.  For example, we represent "1.5.0" as major version 5 (we
+  // drop the leading 1 and use 5 as the 'major').
+
+  uint8_t _major;
+  uint8_t _minor;
+  uint8_t _micro;
+  uint8_t _update;
+  uint8_t _special;
+  uint8_t _build;
+
+  // If partially initialized, the above fields are invalid and we know
+  // that we're less than major version 6.
+  bool _partially_initialized;
+
+  bool _thread_park_blocker;
+
+  bool is_valid() const {
+    return (_major != 0 || _partially_initialized);
+  }
+
+  // initializes or partially initializes the _current static field
+  static void initialize();
+
+  // Completes initialization for a pre-JDK6 version.
+  static void fully_initialize(uint8_t major, uint8_t minor = 0,
+                               uint8_t micro = 0, uint8_t update = 0);
 
  public:
-  static void initialize();
-  static int  jdk_major_version() { return JDK_VERSION_MAJOR(_version_info.jdk_version); }
-  static int  jdk_minor_version() { return JDK_VERSION_MINOR(_version_info.jdk_version); }
-  static int  jdk_micro_version() { return JDK_VERSION_MICRO(_version_info.jdk_version); }
-  static int  jdk_build_number()  { return JDK_VERSION_BUILD(_version_info.jdk_version); }
+
+  // Returns true if the the current version has only been partially initialized
+  static bool is_partially_initialized() {
+    return _current._partially_initialized;
+  }
+
+  JDK_Version() : _major(0), _minor(0), _micro(0), _update(0),
+                  _special(0), _build(0), _partially_initialized(false),
+                  _thread_park_blocker(false) {}
 
-  static bool is_pre_jdk16_version()        { return _pre_jdk16_version; }
-  static bool is_jdk12x_version()           { assert(is_jdk_version_initialized(), "must have been initialized"); return _jdk_version == 2; }
-  static bool is_jdk13x_version()           { assert(is_jdk_version_initialized(), "must have been initialized"); return _jdk_version == 3; }
-  static bool is_jdk14x_version()           { assert(is_jdk_version_initialized(), "must have been initialized"); return _jdk_version == 4; }
-  static bool is_jdk15x_version()           { assert(is_jdk_version_initialized(), "must have been initialized"); return _jdk_version == 5; }
+  JDK_Version(uint8_t major, uint8_t minor = 0, uint8_t micro = 0,
+              uint8_t update = 0, uint8_t special = 0, uint8_t build = 0,
+              bool thread_park_blocker = false) :
+      _major(major), _minor(minor), _micro(micro), _update(update),
+      _special(special), _build(build), _partially_initialized(false),
+      _thread_park_blocker(thread_park_blocker) {}
 
-  static bool is_jdk16x_version() {
-    if (is_jdk_version_initialized()) {
-      return _jdk_version == 6;
-    } else {
-      assert(is_pre_jdk16_version(), "must have been initialized");
-      return false;
-    }
+  // Returns the current running JDK version
+  static JDK_Version current() { return _current; }
+
+  // Factory methods for convenience
+  static JDK_Version jdk(uint8_t m) {
+    return JDK_Version(m);
+  }
+
+  static JDK_Version jdk_update(uint8_t major, uint8_t update_number) {
+    return JDK_Version(major, 0, 0, update_number);
   }
 
-  static bool is_jdk17x_version() {
-    if (is_jdk_version_initialized()) {
-      return _jdk_version == 7;
+  uint8_t major_version() const          { return _major; }
+  uint8_t minor_version() const          { return _minor; }
+  uint8_t micro_version() const          { return _micro; }
+  uint8_t update_version() const         { return _update; }
+  uint8_t special_update_version() const { return _special; }
+  uint8_t build_number() const           { return _build; }
+
+  bool supports_thread_park_blocker() const {
+    return _thread_park_blocker;
+  }
+
+  // Performs a full ordering comparison using all fields (update, build, etc.)
+  int compare(const JDK_Version& other) const;
+
+  /**
+   * Performs comparison using only the major version, returning negative
+   * if the major version of 'this' is less than the parameter, 0 if it is
+   * equal, and a positive value if it is greater.
+   */
+  int compare_major(int version) const {
+    if (_partially_initialized) {
+      if (version >= 6) {
+        return -1;
+      } else {
+        assert(false, "Can't make this comparison during init time");
+        return -1; // conservative
+      }
     } else {
-      assert(is_pre_jdk16_version(), "must have been initialized");
-      return false;
+      return major_version() - version;
     }
   }
 
-  static bool supports_thread_park_blocker() { return _version_info.thread_park_blocker; }
+  void to_string(char* buffer, size_t buflen) const;
+
+  // Convenience methods for queries on the current major/minor version
+  static bool is_jdk12x_version() {
+    return current().compare_major(2) == 0;
+  }
+
+  static bool is_jdk13x_version() {
+    return current().compare_major(3) == 0;
+  }
+
+  static bool is_jdk14x_version() {
+    return current().compare_major(4) == 0;
+  }
+
+  static bool is_jdk15x_version() {
+    return current().compare_major(5) == 0;
+  }
+
+  static bool is_jdk16x_version() {
+    return current().compare_major(6) == 0;
+  }
+
+  static bool is_jdk17x_version() {
+    return current().compare_major(7) == 0;
+  }
+
+  static bool is_gte_jdk13x_version() {
+    return current().compare_major(3) >= 0;
+  }
 
   static bool is_gte_jdk14x_version() {
-    // Keep the semantics of this that the version number is >= 1.4
-    assert(is_jdk_version_initialized(), "Not initialized");
-    return _jdk_version >= 4;
-  }
-  static bool is_gte_jdk15x_version() {
-    // Keep the semantics of this that the version number is >= 1.5
-    assert(is_jdk_version_initialized(), "Not initialized");
-    return _jdk_version >= 5;
+    return current().compare_major(4) >= 0;
   }
+
+  static bool is_gte_jdk15x_version() {
+    return current().compare_major(5) >= 0;
+  }
+
   static bool is_gte_jdk16x_version() {
-    // Keep the semantics of this that the version number is >= 1.6
-    if (is_jdk_version_initialized()) {
-      return _jdk_version >= 6;
-    } else {
-      assert(is_pre_jdk16_version(), "Not initialized");
-      return false;
-    }
+    return current().compare_major(6) >= 0;
   }
 
   static bool is_gte_jdk17x_version() {
-    // Keep the semantics of this that the version number is >= 1.7
-    if (is_jdk_version_initialized()) {
-      return _jdk_version >= 7;
-    } else {
-      assert(is_pre_jdk16_version(), "Not initialized");
-      return false;
-    }
-  }
-
-  static bool is_jdk_version_initialized() {
-    return _jdk_version > 0;
-  }
-
-  // These methods are defined to deal with pre JDK 1.6 versions
-  static void set_jdk12x_version() {
-    assert(_pre_jdk16_version && !is_jdk_version_initialized(), "must not initialize");
-    _jdk_version = 2;
-    _version_info.jdk_version = (1 << 24) | (2 << 16);
-  }
-  static void set_jdk13x_version() {
-    assert(_pre_jdk16_version && !is_jdk_version_initialized(), "must not initialize");
-    _jdk_version = 3;
-    _version_info.jdk_version = (1 << 24) | (3 << 16);
-  }
-  static void set_jdk14x_version() {
-    assert(_pre_jdk16_version && !is_jdk_version_initialized(), "must not initialize");
-    _jdk_version = 4;
-    _version_info.jdk_version = (1 << 24) | (4 << 16);
-  }
-  static void set_jdk15x_version() {
-    assert(_pre_jdk16_version && !is_jdk_version_initialized(), "must not initialize");
-    _jdk_version = 5;
-    _version_info.jdk_version = (1 << 24) | (5 << 16);
+    return current().compare_major(7) >= 0;
   }
 };
--- a/hotspot/src/share/vm/runtime/os.cpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/runtime/os.cpp	Wed Jul 05 16:40:29 2017 +0200
@@ -336,29 +336,38 @@
     char buffer[JVM_MAXPATHLEN];
     char ebuf[1024];
 
-    // Try to load verify dll first. In 1.3 java dll depends on it and is not always
-    // able to find it when the loading executable is outside the JDK.
+    // Try to load verify dll first. In 1.3 java dll depends on it and is not
+    // always able to find it when the loading executable is outside the JDK.
     // In order to keep working with 1.2 we ignore any loading errors.
-    hpi::dll_build_name(buffer, sizeof(buffer), Arguments::get_dll_dir(), "verify");
-    hpi::dll_load(buffer, ebuf, sizeof(ebuf));
+    dll_build_name(buffer, sizeof(buffer), Arguments::get_dll_dir(), "verify");
+    dll_load(buffer, ebuf, sizeof(ebuf));
 
     // Load java dll
-    hpi::dll_build_name(buffer, sizeof(buffer), Arguments::get_dll_dir(), "java");
-    _native_java_library = hpi::dll_load(buffer, ebuf, sizeof(ebuf));
+    dll_build_name(buffer, sizeof(buffer), Arguments::get_dll_dir(), "java");
+    _native_java_library = dll_load(buffer, ebuf, sizeof(ebuf));
     if (_native_java_library == NULL) {
       vm_exit_during_initialization("Unable to load native library", ebuf);
     }
-    // The JNI_OnLoad handling is normally done by method load in java.lang.ClassLoader$NativeLibrary,
-    // but the VM loads the base library explicitly so we have to check for JNI_OnLoad as well
-    const char *onLoadSymbols[] = JNI_ONLOAD_SYMBOLS;
-    JNI_OnLoad_t JNI_OnLoad = CAST_TO_FN_PTR(JNI_OnLoad_t, hpi::dll_lookup(_native_java_library, onLoadSymbols[0]));
-    if (JNI_OnLoad != NULL) {
-      JavaThread* thread = JavaThread::current();
-      ThreadToNativeFromVM ttn(thread);
-      HandleMark hm(thread);
-      jint ver = (*JNI_OnLoad)(&main_vm, NULL);
-      if (!Threads::is_supported_jni_version_including_1_1(ver)) {
-        vm_exit_during_initialization("Unsupported JNI version");
+  }
+  static jboolean onLoaded = JNI_FALSE;
+  if (onLoaded) {
+    // We may have to wait to fire OnLoad until TLS is initialized.
+    if (ThreadLocalStorage::is_initialized()) {
+      // The JNI_OnLoad handling is normally done by method load in
+      // java.lang.ClassLoader$NativeLibrary, but the VM loads the base library
+      // explicitly so we have to check for JNI_OnLoad as well
+      const char *onLoadSymbols[] = JNI_ONLOAD_SYMBOLS;
+      JNI_OnLoad_t JNI_OnLoad = CAST_TO_FN_PTR(
+          JNI_OnLoad_t, dll_lookup(_native_java_library, onLoadSymbols[0]));
+      if (JNI_OnLoad != NULL) {
+        JavaThread* thread = JavaThread::current();
+        ThreadToNativeFromVM ttn(thread);
+        HandleMark hm(thread);
+        jint ver = (*JNI_OnLoad)(&main_vm, NULL);
+        onLoaded = JNI_TRUE;
+        if (!Threads::is_supported_jni_version_including_1_1(ver)) {
+          vm_exit_during_initialization("Unsupported JNI version");
+        }
       }
     }
   }
--- a/hotspot/src/share/vm/runtime/os.hpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/runtime/os.hpp	Wed Jul 05 16:40:29 2017 +0200
@@ -390,6 +390,10 @@
   static const char*    get_temp_directory();
   static const char*    get_current_directory(char *buf, int buflen);
 
+  // Builds a platform-specific full library path given a ld path and lib name
+  static void           dll_build_name(char* buffer, size_t size,
+                                       const char* pathname, const char* fname);
+
   // Symbol lookup, find nearest function name; basically it implements
   // dladdr() for all platforms. Name of the nearest function is copied
   // to buf. Distance from its base address is returned as offset.
@@ -413,6 +417,9 @@
   // same architecture as Hotspot is running on
   static void* dll_load(const char *name, char *ebuf, int ebuflen);
 
+  // lookup symbol in a shared library
+  static void* dll_lookup(void* handle, const char* name);
+
   // Print out system information; they are called by fatal error handler.
   // Output format may be different on different platforms.
   static void print_os_info(outputStream* st);
--- a/hotspot/src/share/vm/runtime/statSampler.cpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/runtime/statSampler.cpp	Wed Jul 05 16:40:29 2017 +0200
@@ -217,6 +217,7 @@
   "java.class.path",
   "java.endorsed.dirs",
   "java.ext.dirs",
+  "java.version",
   "java.home",
   NULL
 };
--- a/hotspot/src/share/vm/runtime/thread.cpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/runtime/thread.cpp	Wed Jul 05 16:40:29 2017 +0200
@@ -2578,7 +2578,8 @@
 oop JavaThread::current_park_blocker() {
   // Support for JSR-166 locks
   oop thread_oop = threadObj();
-  if (thread_oop != NULL && JDK_Version::supports_thread_park_blocker()) {
+  if (thread_oop != NULL &&
+      JDK_Version::current().supports_thread_park_blocker()) {
     return java_lang_Thread::park_blocker(thread_oop);
   }
   return NULL;
@@ -2755,12 +2756,20 @@
   // For now, just manually iterate through them.
   tc->do_thread(VMThread::vm_thread());
   Universe::heap()->gc_threads_do(tc);
-  tc->do_thread(WatcherThread::watcher_thread());
+  {
+    // Grab the Terminator_lock to prevent watcher_thread from being terminated.
+    MutexLockerEx mu(Terminator_lock, Mutex::_no_safepoint_check_flag);
+    WatcherThread *wt = WatcherThread::watcher_thread();
+    if (wt != NULL)
+      tc->do_thread(wt);
+  }
   // If CompilerThreads ever become non-JavaThreads, add them here
 }
 
 jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) {
 
+  extern void JDK_Version_init();
+
   // Check version
   if (!is_supported_jni_version(args->version)) return JNI_EVERSION;
 
@@ -2776,6 +2785,9 @@
   // Initialize system properties.
   Arguments::init_system_properties();
 
+  // So that JDK version can be used as a discrimintor when parsing arguments
+  JDK_Version_init();
+
   // Parse arguments
   jint parse_result = Arguments::parse(args);
   if (parse_result != JNI_OK) return parse_result;
--- a/hotspot/src/share/vm/runtime/threadLocalStorage.cpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/runtime/threadLocalStorage.cpp	Wed Jul 05 16:40:29 2017 +0200
@@ -42,8 +42,13 @@
 }
 
 void ThreadLocalStorage::init() {
-  assert(ThreadLocalStorage::thread_index() == -1, "More than one attempt to initialize threadLocalStorage");
+  assert(!is_initialized(),
+         "More than one attempt to initialize threadLocalStorage");
   pd_init();
   set_thread_index(os::allocate_thread_local_storage());
   generate_code_for_get_thread();
 }
+
+bool ThreadLocalStorage::is_initialized() {
+    return (thread_index() != -1);
+}
--- a/hotspot/src/share/vm/runtime/threadLocalStorage.hpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/runtime/threadLocalStorage.hpp	Wed Jul 05 16:40:29 2017 +0200
@@ -47,6 +47,7 @@
   // Initialization
   // Called explicitly from VMThread::activate_system instead of init_globals.
   static void init();
+  static bool is_initialized();
 
  private:
   static int     _thread_index;
--- a/hotspot/src/share/vm/runtime/vmStructs.cpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/runtime/vmStructs.cpp	Wed Jul 05 16:40:29 2017 +0200
@@ -761,8 +761,9 @@
   static_field(Abstract_VM_Version,            _vm_minor_version,                             int)                                   \
   static_field(Abstract_VM_Version,            _vm_build_number,                              int)                                   \
                                                                                                                                      \
-  static_field(JDK_Version,                    _pre_jdk16_version,                            bool)                                  \
-  static_field(JDK_Version,                    _jdk_version,                                  int)                                   \
+  static_field(JDK_Version,                    _current,                                      JDK_Version)                           \
+  nonstatic_field(JDK_Version,                 _partially_initialized,                        bool)                                  \
+  nonstatic_field(JDK_Version,                 _major,                                        unsigned char)                         \
                                                                                                                                      \
                                                                                                                                      \
                                                                                                                                      \
--- a/hotspot/src/share/vm/services/threadService.cpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/services/threadService.cpp	Wed Jul 05 16:40:29 2017 +0200
@@ -744,7 +744,7 @@
   }
 
   // Support for JSR-166 locks
-  if (JDK_Version::supports_thread_park_blocker() &&
+  if (JDK_Version::current().supports_thread_park_blocker() &&
         (_thread_status == java_lang_Thread::PARKED ||
          _thread_status == java_lang_Thread::PARKED_TIMED)) {
 
--- a/hotspot/src/share/vm/utilities/globalDefinitions.hpp	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/src/share/vm/utilities/globalDefinitions.hpp	Wed Jul 05 16:40:29 2017 +0200
@@ -97,8 +97,12 @@
 // object size.
 class HeapWord {
   friend class VMStructs;
-private:
+ private:
   char* i;
+#ifdef ASSERT
+ public:
+  char* value() { return i; }
+#endif
 };
 
 // HeapWordSize must be 2^LogHeapWordSize.
--- a/hotspot/test/compiler/6646019/Test.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/test/compiler/6646019/Test.java	Wed Jul 05 16:40:29 2017 +0200
@@ -1,23 +1,24 @@
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
- * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
- *
+ * Copyright 2008 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
  *
  */
 
--- a/hotspot/test/compiler/6689060/Test.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/test/compiler/6689060/Test.java	Wed Jul 05 16:40:29 2017 +0200
@@ -1,24 +1,24 @@
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
- * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
- *
+ * Copyright 2008 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
  *
  */
 
--- a/hotspot/test/compiler/6695810/Test.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/hotspot/test/compiler/6695810/Test.java	Wed Jul 05 16:40:29 2017 +0200
@@ -1,24 +1,24 @@
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
- * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
- *
+ * Copyright 2008 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
  *
  */
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/6700047/Test6700047.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/**
+ * @test
+ * @bug 6700047
+ * @summary C2 failed in idom_no_update
+ * @run main Test6700047
+ */
+
+public class Test6700047 {
+    public static void main(String[] args) {
+        for (int i = 0; i < 100000; i++) {
+            intToLeftPaddedAsciiBytes();
+        }
+    }
+
+    public static int intToLeftPaddedAsciiBytes() {
+        int offset = 40;
+        int q;
+        int r;
+        int         i   = 100;
+        int result = 1;
+        while (offset > 0) {
+            q = (i * 52429);
+            r = i;
+            offset--;
+            i = q;
+            if (i == 0) {
+                break;
+            }
+        }
+        if (offset > 0) {
+            for(int j = 0; j < offset; j++) {
+                result++;
+            }
+        }
+        return result;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/6712835/Test6712835.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,1578 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/**
+ * @test
+ * @bug 6712835
+ * @summary Server compiler fails with assertion (loop_count < K,"infinite loop in PhaseIterGVN::transform")
+ * @run main/othervm -Xcomp Test6712835
+ */
+
+/* Complexity upper bound: 349851 ops */
+
+abstract class Tester_Class_0 {
+    boolean var_1 = true;
+    static double var_2;
+    float var_3 = 1.8301116E38F;
+    final String var_4 = "wck";
+    final static short var_5 = 25624;
+
+
+    public Tester_Class_0()
+    {
+        var_2 = (byte)1.7374809293839066E308;
+        {
+            double var_18 = false ? 8027040614338917376L * var_3 + - (var_2 = var_5) : (var_3 += (char)4.491494085158084E307);
+            var_3 *= ~ ((byte)702579792) / 6600332715431236608L;
+            long var_19 = 0L;
+            var_18 -= 1759091496;
+            do
+            {
+                final long var_20 = (new long[(byte)(var_3 += + +1.6695243696502334E308)][(byte)((byte)1110410742 | ~var_19)])[var_1 & var_1 ? (byte)1047514041090199552L : (byte)var_5][(byte)(var_1 ? 123309551 : - ((byte)5932930312361050112L))];
+                var_19++;
+                final short var_21 = var_5;
+            } while (var_19 < 1 && var_1 ^ var_3 == + ((byte)var_5));
+            {
+                int var_22;
+            }
+            {
+                var_4.endsWith("o");
+            }
+            int var_23 = 0;
+            var_1 &= (var_1 = true);
+            for (byte var_24 = 26; (var_1 = !var_1) && var_23 < 1; var_18 += var_1 ^ (var_1 |= false) ^ true ? var_24 : (byte)1504077779675035648L)
+            {
+                var_18 *= var_23;
+                var_23++;
+                float var_25;
+                (((new Tester_Class_0[var_24][var_24][var_24])[var_24])[var_24 >>= var_19][var_24 &= 6702582681202665472L]).var_3 *= var_5;
+            }
+            var_1 = (var_3 -= var_5) > (byte)func_2(1317089759, var_5, (byte)var_19) % (false & true ? 475183200 : 8947159119888251904L);
+            var_18 /= ~var_19 ^ ((byte)(var_18 %= (int)var_5) >= 6773554922270913536L ? (byte)var_5 : (byte)'u');
+            var_3 = ~ ((byte)var_19);
+        }
+        double var_26 = 0;
+        var_1 &= (var_1 |= ! (var_1 |= true));
+        while (var_26 < 1)
+        {
+            var_2 = 'e';
+            var_26++;
+            var_1 ^= !true | 'j' * ((var_2 = 93384362) + var_5) <= var_5;
+            var_2 = true ? 2056852215 : var_5;
+        }
+        switch ((new char[(byte)var_3])[(byte)(short)var_4.charAt(438929928)] / (new byte[(byte)1779353916050551808L][(byte)+ ~8903539475459755008L])[(byte)836413337621087232L][(byte)784406244])
+        {
+            case 101:
+                var_3 -= var_5;
+                break;
+
+            case 'L':
+
+            case 20:
+                final int var_27 = 2146473580;
+                break;
+
+            case 18:
+
+            default:
+                "mwh".substring((byte)(float)'A' % var_5, ']' | var_5 ^ ~ ((byte)'E'));
+                break;
+
+            case 'H':
+
+        }
+        var_3 = var_5;
+        long var_28;
+        var_28 = (var_1 = 'u' != (var_3 = var_1 ? 1384770002488557568L : ~ ~6691557565676772352L)) ? - ((byte)938410603) : var_5;
+        ((new Tester_Class_0[(byte)var_26])[(byte)'w']).var_3 = (byte)(short)'I';
+        var_2 = (var_1 ^= "sfltwylm".startsWith("ytmeds")) ? 1837260339 * 434565574 : (new double[(byte)var_26])[(byte)var_3];
+    }
+
+
+
+    public boolean equals(Object obj)
+    {
+        var_2 = 785819716 / 'i';
+        switch ((! (var_1 ^= var_1) ^ (! ((false | (var_1 |= var_1)) ^ !false) ? false : (var_1 |= !false)) ? var_1 : ! !var_1 ^ var_1) ? 1426689390 : var_5 * var_5)
+        {
+            case '`':
+
+            case 89:
+
+            case 13:
+                char var_9 = 'W';
+                break;
+
+            case 31:
+
+            case 15:
+
+            case 'm':
+                var_1 &= var_1;
+                break;
+
+            case 'Z':
+
+            case 34:
+                String[] var_10 = (new String[(byte)5534253842608756736L][(byte)'M'])[(byte)8717534666212195328L];
+                break;
+
+            case 124:
+
+        }
+        var_3 += var_5;
+        var_1 |= (var_1 |= (var_1 = (var_1 |= var_5 >= (var_2 = (byte)var_3))));
+        var_1 ^= (var_1 = var_4.endsWith(new String()));
+        var_2 = (var_3 %= 664966429);
+        {
+            var_4.lastIndexOf((int)('i' * (! !true & (true & !var_1) ? (byte)2.2562587635371023E307 : (byte)(var_3 %= var_3)) / var_3), 'P' % (false ? (byte)'N' : (byte)943393108));
+        }
+        var_3 /= false | ! !var_1 ? (char)1.3721055E38F : '\\';
+        if (var_1)
+        {
+            var_4.compareTo("uaqmqwg");
+        }
+        else
+        {
+            var_1 ^= var_1 & (var_1 &= (var_1 ^= (var_1 ^= var_1)));
+        }
+        var_3 *= (new int[(byte)1980200282][(byte)'i'])[(byte)(var_2 = (byte)'O')][false ? (byte)2.4739911E38F : (byte)- ((byte)1.6045903096088714E308)];
+        var_1 = var_5 != (byte)var_5 & (1.5002759009669559E308 < (byte)5110733568033040384L ^ (var_1 ? (var_1 ^= true) : var_1));
+        long var_11;
+        return (var_2 = (byte)'B') < 550125954;
+    }
+
+
+    public static char func_0(final int arg_0, long[] arg_1, final boolean arg_2)
+    {
+        var_2 = (short)(false ? (byte)1.2577737E38F : (byte)'t');
+        "xdf".codePointBefore((!arg_2 ? (byte)1426638765 : (byte)541094055) * ((byte)var_5 / var_5));
+        ((new Tester_Class_0[(byte)(short)(var_2 = 'A')])[(byte)arg_0]).var_3 = 7823141134226481152L;
+        ((new Tester_Class_0[(byte)- ~1368497135389664256L])[!false || true ? (byte)2.5393905E38F : (byte)2.4415902E38F]).var_3 -= (int)(false ? (byte)var_5 : (byte)"musnlk".charAt(785792957));
+        ((new Tester_Class_0[(byte)357672172])[(byte)7.709380171237795E307]).var_3 = arg_0;
+        ((new Tester_Class_0[(byte)var_5])[(byte)('Z' / + + -2.6037312E38F)]).var_3 %= arg_2 ? + - - + - + +4.6761156E37F : (byte)- (var_2 = - - ~3113191255384341504L);
+        (("exseqpham" + "uigdxg").equalsIgnoreCase("oeutvibnv") ? "l" : "qra").replace(false ^ true ? 't' : "jwpf".charAt(+ ((byte)arg_0)), 6.624090730243228E307 > 2.7771497E38F ? 't' : "tcfesyg".charAt(arg_0));
+        ((new Tester_Class_0[(byte)arg_0][(byte)6943189372481268736L])[(byte)2.6713643513095145E307][(byte)var_5]).var_1 &= !"ipgqq".endsWith("aecnyvpmf");
+        ((new Tester_Class_0[(byte)(+ +2158971337956592640L ^ var_5)])[false ? (byte)8594725249859841024L : (byte)var_5]).var_3 = (byte)"jd".charAt((byte)1.6298661301128909E307 << (byte)'B');
+        var_2 = (float)1014982842 * (byte)var_5 * ((new Tester_Class_0[(byte)2.7842814E38F])[(byte)"n".charAt('e' ^ (byte)arg_0)]).var_3;
+        if (false)
+        {
+            ((new Tester_Class_0[(byte)8.702990410251979E307][(byte)8.865924E37F])[(byte)var_5][(byte)+ ((long)var_5)]).var_1 ^= arg_2;
+        }
+        else
+        {
+            ((new Tester_Class_0[(byte)('I' | var_5)])[(byte)('L' + (+ - - (var_2 = 'N') + 1.324025E38F))]).var_3 = var_5 % '[' + (byte)var_5;
+        }
+        ((new Tester_Class_0[(byte)7.41761E37F][(byte)(var_2 = var_5)])[(byte)var_5][(byte)'o']).var_1 &= false;
+        ((new Tester_Class_0[(byte)+ ((byte)7.9065203E37F)])[(byte)var_5]).var_1 ^= 630582880 > - (var_2 = var_5);
+        return 'K';
+    }
+
+    protected float func_1(int arg_0, final Object arg_1, Object arg_2)
+    {
+        var_1 ^= (var_1 ^= true) & !var_1;
+        {
+            var_3 -= var_3;
+            var_2 = var_1 && (var_1 &= ! !true) | + ~3353396000385141760L < 7949306917320622080L ? (byte)306954754 : (byte)var_5;
+            final long var_12 = 1048994076885686272L;
+        }
+        short var_13 = 8706;
+        byte var_14 = (new byte[(byte)6.697464316212731E307])[(byte)var_4.indexOf("clbr", (byte)var_5 + 'F')];
+        ((new Tester_Class_0[var_14][var_14 &= 'b'])[var_14][var_14]).var_1 |= var_14 >= var_3;
+        (((new String[var_14][var_14])[var_14])[var_14]).codePointAt(585064460);
+        var_14 -= 2121015302;
+        var_2 = 1.241922E38F;
+        {
+            (((new Tester_Class_0[var_14][var_14 ^= 'y'])[var_14])[var_14 |= var_14]).var_3 *= 5756647686007829504L;
+        }
+        {
+            var_13--;
+        }
+        double var_15;
+        var_1 = (var_1 = true) ? false : true;
+        arg_0--;
+        return var_3;
+    }
+
+    public final static short func_2(int arg_0, final short arg_1, byte arg_2)
+    {
+        arg_0 %= (((new Tester_Class_0[arg_2][arg_2])[arg_2++][--arg_2]).var_1 |= true) ? 'e' : var_5 >>> arg_2;
+        float var_16 = ((false ? ~3951083684045828096L >>> - -3880809660598466560L : arg_0) ^ arg_1) - 1.1257035E37F;
+        var_2 = var_5 + 3.3679594E38F;
+        arg_2 += true & (((new Tester_Class_0[arg_2])[arg_2 *= 4301185995603340288L]).var_1 = arg_1 != arg_1) ? (var_2 = arg_0) : 988311987505040384L + ']' >>> --arg_2;
+        arg_2 = arg_2;
+        var_16 /= (arg_2 += (arg_0 += (var_16 %= arg_2)) + (var_16 -= arg_2));
+        var_16 += 7416220016668043264L;
+        ((new Tester_Class_0[arg_2])[arg_2]).var_1 &= false;
+        ((new Tester_Class_0[--arg_2])[--arg_2]).var_1 = true | (true & true ? true : false);
+        arg_2 -= (var_2 = 7997355759027275776L);
+        ((new Tester_Class_0[arg_2])[arg_2 %= 8660960251961819136L]).var_3 *= 4180634858198604800L;
+        arg_0 /= -1.3063173E38F;
+        var_2 = arg_2;
+        var_2 = (6266377813429248L ^ 'j') / (!false & (1.1423139843154216E308 >= (var_2 = arg_2) || (((new Tester_Class_0[arg_2])[arg_2]).var_1 ^= true)) ? (short)('e' * arg_0) : var_5);
+        --arg_0;
+        var_2 = (+ - ~8598445599816821760L << arg_1) % 1890075208 & (!true & !true ^ false & false ? 'w' : 'm') % (5614521287604667392L / arg_2) & ~193105176465084416L;
+        arg_2 &= (arg_2 |= arg_0) ^ ((((new Tester_Class_0[arg_2][arg_2])[arg_2])[arg_2]).var_1 ? arg_2 : (new long[arg_2])[arg_2]);
+        ((new Tester_Class_0[arg_2 &= 'V'][arg_2])[arg_2 /= 5486057194586717184L][arg_2 %= var_16]).var_1 |= (new boolean[((new Tester_Class_0[arg_2])[arg_2]).var_1 ? arg_2 : arg_2])[arg_2];
+        return ((((new Tester_Class_0[arg_2][arg_2][arg_2])[--arg_2])[arg_2 |= arg_2][arg_2 %= 6782653882738869248L]).var_1 ? false : !true | "hopq".equalsIgnoreCase("wvm") | "qmhtjvm".endsWith("gewqas")) && ! !false & false ? arg_1 : arg_1;
+    }
+
+    protected final static char func_3(byte arg_0, final int arg_1, final short arg_2, long[] arg_3)
+    {
+        ((new Tester_Class_0[arg_0 ^= 1902924521091955712L])[arg_0]).var_1 &= ((((new Tester_Class_0[arg_0][arg_0])[--arg_0])[arg_0 *= - -1.0959788E38F]).var_1 = false);
+        {
+            var_2 = (new float[arg_0][(byte)1082004329])[arg_0][arg_0 <<= 'T'];
+        }
+        ((new Tester_Class_0[arg_0 >>= arg_1][arg_0])[arg_0][arg_0]).var_1 |= ((new Tester_Class_0[arg_0])[--arg_0]).var_4.startsWith(((new Tester_Class_0[arg_0])[arg_0]).var_4);
+        ((new Tester_Class_0[(byte)var_5])[arg_0]).var_4.substring(273513722, 'f' * 'n').substring((new short[arg_0][arg_0])[arg_0][arg_0] % 'C' >> (arg_3[arg_0] - 's') % ("".charAt(arg_1) & var_5));
+        var_2 = 'Q' + (char)arg_0;
+        {
+            ((new Tester_Class_0[++arg_0])[arg_0]).var_1 ^= !true || !true ? !false ^ false : ! (1.7030813E38F != ~arg_0);
+        }
+        {
+            "jbdu".indexOf(((new Tester_Class_0[arg_0 *= 2628674024589069312L])[arg_0 -= arg_1]).var_4, "gqglwwbab".charAt(~arg_0) >>> 'M');
+        }
+        {
+            --arg_0;
+        }
+        ((new Tester_Class_0[arg_0])[arg_0]).var_1 = 'n' == ('t' | (+9156142987836739584L | 's')) - 2915339344736463872L;
+        int var_17;
+        var_17 = 'k';
+        var_17 = (((new Tester_Class_0[arg_0])[arg_0]).var_1 &= false) ? (short)'q' : arg_2;
+        return '`';
+    }
+
+    public String toString()
+    {
+        String result =  "[\n";
+        result += "Tester_Class_0.var_5 = "; result += Test6712835.Printer.print(var_5);
+        result += "\n";
+        result += "Tester_Class_0.var_4 = "; result += Test6712835.Printer.print(var_4);
+        result += "\n";
+        result += "Tester_Class_0.var_1 = "; result += Test6712835.Printer.print(var_1);
+        result += "\n";
+        result += "Tester_Class_0.var_2 = "; result += Test6712835.Printer.print(var_2);
+        result += "\n";
+        result += "Tester_Class_0.var_3 = "; result += Test6712835.Printer.print(var_3);
+        result += "";
+        result += "\n]";
+        return result;
+    }
+}
+
+
+final class Tester_Class_1 extends Tester_Class_0 {
+    final boolean var_29 = false;
+    static short var_30;
+    Tester_Class_0 var_31;
+
+
+    public Tester_Class_1()
+    {
+        new String();
+        byte var_43 = (var_1 ? var_29 : var_1) ? (byte)(~ ~ ~6520122970162626560L | ~6642750731731981312L) : (byte)(var_30 = var_5);
+        {
+            var_2 = Tester_Class_0.var_5;
+        }
+        ((Tester_Class_0)(new Object[var_43])[var_43]).var_1 = var_29;
+        var_43 += 512311665;
+    }
+
+
+
+
+    final int func_0()
+    {
+        Tester_Class_0.var_2 = var_29 ? (var_29 ? (byte)'D' : (byte)Tester_Class_0.var_5) : (!var_1 ^ var_1 | (var_1 ^= var_1) ? (byte)'J' : (byte)51510881);
+        new String();
+        new String();
+        new String();
+        return 1731501229;
+    }
+
+    private final static void func_1(final String arg_0, final Object arg_1)
+    {
+        long var_32 = ((new Tester_Class_1[(byte)37719380])['I' == Tester_Class_0.var_5 + Tester_Class_0.var_5 ? (byte)(var_30 = (byte)1.3043569561522328E308) : (byte)1.1111420042091164E308]).var_1 ? ~2569063513521638400L - Tester_Class_0.var_5 ^ 'm' : 660383226;
+        ((Tester_Class_0)arg_1).var_3 += (char)8417109805993570304L;
+        var_30 = var_5;
+        var_2 = (new byte[(byte)2102078692])[(byte)7.942050823719592E307];
+        if (((new Tester_Class_1[(byte)224717297])[(byte)2889830453578512384L]).var_1)
+        {
+            Tester_Class_0.var_2 = (new byte[(byte)'C'])[(byte)Tester_Class_0.var_5];
+        }
+        else
+        {
+            var_32 <<= 'u';
+        }
+        Tester_Class_0.var_2 = Tester_Class_0.var_5;
+        final Object var_33 = arg_1;
+        final byte var_34 = 40;
+        ++var_32;
+        (((new Tester_Class_1[var_34][var_34])[var_34][var_34]).var_31 = ((new Tester_Class_0[var_34][var_34])[var_34])[var_34]).var_1 ^= (((new Tester_Class_1[var_34][var_34])[var_34][var_34]).var_31 = (Tester_Class_0)var_33).var_1;
+        ((new Tester_Class_1[var_34])[var_34]).var_31 = (((new Tester_Class_1[var_34])[((new Tester_Class_1[var_34][var_34])[var_34][var_34]).var_1 ? var_34 : var_34]).var_31 = (((new Tester_Class_1[(byte)2.4941036E38F])[var_34]).var_31 = (Tester_Class_0)arg_1));
+    }
+
+    public static int[][] func_2(long arg_0, final float arg_1, short arg_2, final double arg_3)
+    {
+        long var_35;
+        {
+            arg_0++;
+            var_2 = true ? (byte)9.691601510156328E307 : (byte)"a".charAt(~ ((byte)arg_1));
+            if (((new Tester_Class_1[(byte)'\\'][(byte)arg_2])[(byte)arg_2][(byte)arg_0]).var_29)
+            {
+                arg_2++;
+            }
+            else
+            {
+                Tester_Class_0.var_2 = arg_2;
+                var_30 = arg_2;
+                Tester_Class_0.var_2 = arg_0;
+            }
+            arg_2 /= 157487965;
+            arg_2 -= func_2(~ ((byte)arg_0), (short)arg_3, (byte)+2.2503214E38F);
+        }
+        arg_0--;
+        double var_36;
+        arg_0 <<= (arg_0 >>= (arg_0 = 'O'));
+        {
+            arg_0++;
+            --arg_0;
+        }
+        --arg_2;
+        ++arg_2;
+        "gbcrkn".length();
+        var_30 = (short)7.14672E37F;
+        {
+            arg_0 %= (arg_0 >>= (arg_2 *= (byte)1.5835087622116814E308)) % arg_3;
+            var_36 = 'n';
+            int[][] var_37 = new int[(byte)(double)arg_0][(byte)(arg_2 >>= 'o')];
+            if ((byte)1390907656194158592L <= arg_2)
+            {
+                "uuoeps".indexOf("", 899321600);
+            }
+            else
+            {
+                var_36 = - ~ -arg_0;
+            }
+            short var_38 = var_5;
+            var_36 = ~arg_0 + (6482428938632186880L + 6995927649252739072L);
+        }
+        if (((new Tester_Class_1[(byte)arg_1][(byte)arg_2])[(new byte[(byte)arg_0])[(byte)var_5]][(byte)'s']).var_1 = false)
+        {
+            ++arg_0;
+        }
+        else
+        {
+            ((new Tester_Class_1[(byte)2.7176027E38F])[(byte)((arg_2 -= 2.595396436487417E307) % 'p')]).var_1 ^= ((new Tester_Class_1[(byte)4.393706E36F])[false ? (byte)4826960994531808256L : (byte)arg_0]).var_29;
+        }
+        int var_39 = 0;
+        arg_2 <<= 'Y';
+        while (var_39 < 1 && false)
+        {
+            arg_0++;
+            var_39++;
+            Object var_40;
+            ((Tester_Class_0)(var_40 = new long[(byte)3.285531E38F])).var_3 += var_39;
+        }
+        Object var_41;
+        "w".substring(1359453539);
+        return new int[(byte)((arg_2 /= 4.143015135482291E307) - 3.2659622E38F)][(byte)++arg_2];
+    }
+
+    public String toString()
+    {
+        String result =  "[\n";
+        result += "Tester_Class_1.var_5 = "; result += Test6712835.Printer.print(var_5);
+        result += "\n";
+        result += "Tester_Class_1.var_30 = "; result += Test6712835.Printer.print(var_30);
+        result += "\n";
+        result += "Tester_Class_1.var_4 = "; result += Test6712835.Printer.print(var_4);
+        result += "\n";
+        result += "Tester_Class_1.var_1 = "; result += Test6712835.Printer.print(var_1);
+        result += "\n";
+        result += "Tester_Class_1.var_29 = "; result += Test6712835.Printer.print(var_29);
+        result += "\n";
+        result += "Tester_Class_1.var_2 = "; result += Test6712835.Printer.print(var_2);
+        result += "\n";
+        result += "Tester_Class_1.var_3 = "; result += Test6712835.Printer.print(var_3);
+        result += "\n";
+        result += "Tester_Class_1.var_31 = "; result += Test6712835.Printer.print(var_31);
+        result += "";
+        result += "\n]";
+        return result;
+    }
+}
+
+
+final class Tester_Class_2 extends Tester_Class_0 {
+    static float var_44 = 2.7867988E38F;
+    static byte var_45;
+    static long var_46 = 4319798868443575296L;
+
+
+    public Tester_Class_2()
+    {
+        Tester_Class_1.var_30 = (byte)3.1718026E38F;
+        var_45 = (new byte[(byte)'o'])[var_45 = (byte)Tester_Class_0.var_5];
+        Tester_Class_1.var_30 = (Tester_Class_1.var_30 = Tester_Class_0.var_5);
+        if (true)
+        {
+            ++var_46;
+            boolean var_51 = false ? (var_1 &= !var_1) : true;
+            --var_46;
+            if (false)
+            {
+                var_3 *= 6.882788442363403E307;
+            }
+            else
+            {
+                Tester_Class_0.var_2 = '`';
+            }
+            final float var_52 = (var_1 ^= var_1 || (var_1 &= false)) | (var_51 |= (var_51 &= false)) ? (byte)4.751813848964725E307 : (var_3 *= var_5);
+            (false ? var_4 : var_4).startsWith("j" + var_4);
+            var_46++;
+            var_3 %= Tester_Class_1.var_5;
+        }
+        else
+        {
+            Tester_Class_1.var_30 = (var_45 = (var_45 = (var_45 = (byte)Tester_Class_1.var_5)));
+            Tester_Class_1.var_2 = (var_3 -= ~ ((byte)var_46) - 2018787280);
+            Tester_Class_1.var_30 = (Tester_Class_1.var_30 = (Tester_Class_1.var_30 = (Tester_Class_1.var_30 = var_5)));
+        }
+        char var_53;
+        ++var_46;
+        short var_54 = 138;
+        ++var_46;
+        var_2 = 1435782089;
+        Tester_Class_0.var_2 = var_46;
+    }
+
+
+
+
+    protected final boolean func_0(final boolean arg_0, final boolean arg_1)
+    {
+        var_2 = 2.6153986361247174E307;
+        var_45 = (var_45 = (var_45 = (var_45 = (var_45 = (byte)(var_44 += var_46)))));
+        var_46++;
+        long var_47 = 0L;
+        var_3 -= + ((byte)(~var_46 * ~var_46 ^ var_46 % 1910419567));
+        do
+        {
+            ++var_46;
+            var_47++;
+            char var_48 = 'b';
+        } while (var_47 < 2);
+        new Tester_Class_1().var_31 = ((new Tester_Class_1[var_45 = (byte)3.0853839E38F])[(new byte[var_45 = (byte)1.4974966426791287E308])[var_45 = (byte)Tester_Class_0.var_5]]).var_1 ? new Tester_Class_1() : new Tester_Class_1();
+        var_45 = (var_45 = (byte)var_44);
+        double var_49 = 0;
+        var_45 = (byte)(Tester_Class_1.var_30 = Tester_Class_0.var_5);
+        while (((false ^ (var_1 &= var_1) | (var_1 |= arg_0) ? new Tester_Class_1() : new Tester_Class_1()).var_29 ? var_1 : false && (var_1 ^= arg_0)) && (var_49 < 3 && (true ? new Tester_Class_1() : new Tester_Class_1()).var_1))
+        {
+            var_45 = (var_45 = (var_45 = (var_45 = (var_45 = (byte)1.933612E38F))));
+            var_49++;
+            var_45 = (var_45 = (var_45 = (var_45 = (byte)685709636)));
+            long var_50;
+        }
+        var_45 = (var_45 = (var_45 = (byte)var_5));
+        var_46--;
+        return true;
+    }
+
+    public String toString()
+    {
+        String result =  "[\n";
+        result += "Tester_Class_2.var_46 = "; result += Test6712835.Printer.print(var_46);
+        result += "\n";
+        result += "Tester_Class_2.var_2 = "; result += Test6712835.Printer.print(var_2);
+        result += "\n";
+        result += "Tester_Class_2.var_3 = "; result += Test6712835.Printer.print(var_3);
+        result += "\n";
+        result += "Tester_Class_2.var_44 = "; result += Test6712835.Printer.print(var_44);
+        result += "\n";
+        result += "Tester_Class_2.var_5 = "; result += Test6712835.Printer.print(var_5);
+        result += "\n";
+        result += "Tester_Class_2.var_45 = "; result += Test6712835.Printer.print(var_45);
+        result += "\n";
+        result += "Tester_Class_2.var_4 = "; result += Test6712835.Printer.print(var_4);
+        result += "\n";
+        result += "Tester_Class_2.var_1 = "; result += Test6712835.Printer.print(var_1);
+        result += "";
+        result += "\n]";
+        return result;
+    }
+}
+
+
+class Tester_Class_3 extends Tester_Class_0 {
+    static boolean var_55 = true;
+    short var_56;
+    char var_57 = (char)723612093;
+    final static byte var_58 = 118;
+    static float var_59 = true ? -2818156175448416256L : - - (Tester_Class_2.var_44 += var_58);
+    static Tester_Class_1 var_60;
+    byte var_61 = 112;
+    Tester_Class_2[] var_62;
+    static short var_63 = 19813;
+    static double var_64 = (var_55 = true) ? (Tester_Class_1.var_2 = 'M') : Tester_Class_2.var_46;
+
+
+    public Tester_Class_3()
+    {
+        var_56 = var_58;
+        Tester_Class_1 var_65 = var_60 = (var_60 = (var_60 = (new Tester_Class_1[var_61 |= '\\'])[(var_1 = true) || var_55 ? var_58 : var_61]));
+        var_64 /= 1253632965 * '`';
+        Tester_Class_2.var_46 >>>= var_58;
+        (((var_61 = var_58) * (var_55 ? 1641980027 : var_63) >= 1490788063 ? var_65 : var_65).var_29 ? var_65 : var_65).var_31 = (new Tester_Class_2[var_58])[var_58];
+        ++var_63;
+        new String();
+        var_64 += var_55 ? (var_61 >>>= 'Q') : (var_63 <<= var_57);
+        ((new Tester_Class_2().var_3 >= Tester_Class_2.var_46 ? !var_55 : var_4.startsWith(var_4, 586086925)) ? "gjsdhuop" : "juqrt").substring(("pm" + ((new Tester_Class_2[var_61][var_58])[var_58][var_58]).var_4).codePointBefore((~var_61 << 3032688286897486848L) - Tester_Class_1.var_5), (var_61 += 4.0796373033184064E306) >> (Tester_Class_2.var_46 >>> var_58));
+        var_63 -= (var_63 ^= var_57);
+        var_64 = var_5 - (Tester_Class_2.var_46 *= var_57);
+        Tester_Class_2.var_46 &= 7544159045139005440L;
+        var_55 |= false;
+        Tester_Class_2.var_46 = var_61;
+    }
+
+
+
+
+    public String toString()
+    {
+        String result =  "[\n";
+        result += "Tester_Class_3.var_57 = "; result += Test6712835.Printer.print(var_57);
+        result += "\n";
+        result += "Tester_Class_3.var_62 = "; result += Test6712835.Printer.print(var_62);
+        result += "\n";
+        result += "Tester_Class_3.var_2 = "; result += Test6712835.Printer.print(var_2);
+        result += "\n";
+        result += "Tester_Class_3.var_64 = "; result += Test6712835.Printer.print(var_64);
+        result += "\n";
+        result += "Tester_Class_3.var_3 = "; result += Test6712835.Printer.print(var_3);
+        result += "\n";
+        result += "Tester_Class_3.var_59 = "; result += Test6712835.Printer.print(var_59);
+        result += "\n";
+        result += "Tester_Class_3.var_5 = "; result += Test6712835.Printer.print(var_5);
+        result += "\n";
+        result += "Tester_Class_3.var_56 = "; result += Test6712835.Printer.print(var_56);
+        result += "\n";
+        result += "Tester_Class_3.var_63 = "; result += Test6712835.Printer.print(var_63);
+        result += "\n";
+        result += "Tester_Class_3.var_58 = "; result += Test6712835.Printer.print(var_58);
+        result += "\n";
+        result += "Tester_Class_3.var_61 = "; result += Test6712835.Printer.print(var_61);
+        result += "\n";
+        result += "Tester_Class_3.var_4 = "; result += Test6712835.Printer.print(var_4);
+        result += "\n";
+        result += "Tester_Class_3.var_1 = "; result += Test6712835.Printer.print(var_1);
+        result += "\n";
+        result += "Tester_Class_3.var_55 = "; result += Test6712835.Printer.print(var_55);
+        result += "\n";
+        result += "Tester_Class_3.var_60 = "; result += Test6712835.Printer.print(var_60);
+        result += "";
+        result += "\n]";
+        return result;
+    }
+}
+
+
+final class Tester_Class_4 {
+    static long var_66;
+    final long var_67 = 7113579489152300032L * 985636454;
+    int[] var_68;
+    Tester_Class_3 var_69;
+    final long var_70 = Tester_Class_2.var_46 <<= Tester_Class_1.var_5;
+    byte var_71 = Tester_Class_3.var_58;
+
+
+    public Tester_Class_4()
+    {
+        Tester_Class_2.var_46++;
+        (var_69 = new Tester_Class_3()).var_61 += (!true | (Tester_Class_3.var_55 ^= Tester_Class_3.var_55) ? new Tester_Class_3() : new Tester_Class_3()).var_61;
+        final String[][] var_79 = new String[var_71 >>= (Tester_Class_3.var_63 ^= 'm')][((Tester_Class_3)(new Tester_Class_1().var_31 = new Tester_Class_2())).var_61 >>= (var_71 >>>= (Tester_Class_2.var_46 += 465205188010511360L))];
+        ++(var_69 = (var_69 = (var_69 = (Tester_Class_3)(new Object[Tester_Class_3.var_58][var_71])[Tester_Class_3.var_58][var_71]))).var_61;
+        (((new Tester_Class_2[var_71][Tester_Class_3.var_58])[Tester_Class_2.var_45 = var_71])[var_71]).var_3 += (Tester_Class_2.var_46 <<= (Tester_Class_2.var_46 /= 9.03047405760868E307) >> (new Tester_Class_2().var_1 ? 2099696051 : Tester_Class_3.var_63));
+        Tester_Class_3.var_60 = (Tester_Class_3.var_60 = (Tester_Class_3.var_60 = (Tester_Class_3.var_60 = new Tester_Class_1())));
+        char var_80;
+        Tester_Class_3.var_64 += 355712574;
+        ++Tester_Class_2.var_46;
+    }
+
+
+
+
+    private final static Tester_Class_1 func_0(boolean arg_0, double arg_1)
+    {
+        Tester_Class_3.var_60 = (Tester_Class_3.var_60 = new Tester_Class_1());
+        byte var_72 = (byte)Tester_Class_2.var_46;
+        Tester_Class_3.var_60 = (Tester_Class_3.var_60 = (Tester_Class_3.var_60 = (Tester_Class_3.var_60 = (Tester_Class_3.var_60 = new Tester_Class_1()))));
+        float var_73 = 0F;
+        "flfix".offsetByCodePoints((Tester_Class_3.var_63 ^= 3286104714651747328L) + ((Tester_Class_3)(new Tester_Class_0[var_72])[var_72]).var_61, Tester_Class_0.var_5 + Tester_Class_3.var_58);
+        while (var_73 < 2 && (false ? (Tester_Class_3.var_60 = new Tester_Class_1()) : (Tester_Class_1)(new Tester_Class_0[var_72])[var_72]).var_29)
+        {
+            ((Tester_Class_3)(Tester_Class_0)(new Object[var_72])[Tester_Class_3.var_58]).var_61 >>= ((new Tester_Class_4[var_72])[var_72]).var_67;
+            var_73++;
+            new String("blod");
+            --var_72;
+        }
+        ((new Tester_Class_4[Tester_Class_3.var_58][var_72])[new Tester_Class_3().var_61][Tester_Class_3.var_58]).var_69 = new Tester_Class_3();
+        float var_74 = (! ("dkcx".lastIndexOf(Tester_Class_1.var_5 >> - (var_72 >>>= 1433506903139345408L)) == Tester_Class_2.var_46) ? 'O' : 'e' - new Tester_Class_2().var_3) * ~ (var_72 ^= var_72);
+        Tester_Class_3.var_60 = !true ? new Tester_Class_1() : (new Tester_Class_1[Tester_Class_3.var_58])[var_72];
+        ((arg_0 &= Tester_Class_3.var_55 | (Tester_Class_3.var_60 = new Tester_Class_1()).var_29) ? (Tester_Class_3.var_60 = (Tester_Class_1)(new Tester_Class_1().var_31 = new Tester_Class_2())) : (Tester_Class_3.var_60 = (new Tester_Class_1[var_72])[Tester_Class_3.var_58])).var_31 = (new Tester_Class_3[var_72 |= 546982927])[Tester_Class_3.var_58];
+        long var_75 = 0L;
+        final double var_76 = +arg_1;
+        while (var_75 < 1)
+        {
+            short var_77;
+            var_75++;
+            new Tester_Class_3().var_57 = (false & true ? new Tester_Class_3() : new Tester_Class_3()).var_57;
+            (Tester_Class_3.var_60 = (new Tester_Class_1[Tester_Class_3.var_58])[Tester_Class_3.var_58]).var_31 = (new Tester_Class_2[Tester_Class_3.var_58][var_72])[var_72][var_72];
+        }
+        Tester_Class_3.var_64 *= (arg_0 ? (Tester_Class_3.var_55 ^= (arg_0 ^= arg_0)) & ! (Tester_Class_3.var_55 = arg_0) : arg_0) ^ new Tester_Class_1().var_29 ? ++((new Tester_Class_3[var_72][var_72])[(new byte[Tester_Class_3.var_58])[Tester_Class_3.var_58]][(((new Tester_Class_4[var_72][Tester_Class_3.var_58])[Tester_Class_3.var_58][Tester_Class_3.var_58]).var_69 = (new Tester_Class_3[Tester_Class_3.var_58])[Tester_Class_3.var_58]).var_61]).var_57 : 'C';
+        long var_78;
+        var_74 %= (Tester_Class_3.var_55 |= (arg_0 = (arg_0 ^= (arg_0 &= !arg_0)))) ? new Tester_Class_3().var_61 : (Tester_Class_3.var_63 ^= var_72);
+        arg_1 /= (Tester_Class_2.var_46 &= 'W');
+        --(((new Tester_Class_4[var_72])[var_72]).var_69 = (((new Tester_Class_4[var_72])[var_72]).var_69 = new Tester_Class_3())).var_61;
+        return (new Tester_Class_1[var_72][Tester_Class_3.var_58])[var_72][new Tester_Class_3().var_61];
+    }
+
+    public String toString()
+    {
+        String result =  "[\n";
+        result += "Tester_Class_4.var_68 = "; result += Test6712835.Printer.print(var_68);
+        result += "\n";
+        result += "Tester_Class_4.var_66 = "; result += Test6712835.Printer.print(var_66);
+        result += "\n";
+        result += "Tester_Class_4.var_67 = "; result += Test6712835.Printer.print(var_67);
+        result += "\n";
+        result += "Tester_Class_4.var_70 = "; result += Test6712835.Printer.print(var_70);
+        result += "\n";
+        result += "Tester_Class_4.var_71 = "; result += Test6712835.Printer.print(var_71);
+        result += "\n";
+        result += "Tester_Class_4.var_69 = "; result += Test6712835.Printer.print(var_69);
+        result += "";
+        result += "\n]";
+        return result;
+    }
+}
+
+
+final class Tester_Class_5 extends Tester_Class_0 {
+    static boolean var_81;
+    final int var_82 = 174395841;
+    int var_83;
+    byte var_84;
+    boolean var_85 = Tester_Class_3.var_55;
+    static boolean var_86 = Tester_Class_3.var_55;
+
+
+    public Tester_Class_5()
+    {
+        {
+            short var_87 = (new short[Tester_Class_3.var_58][var_84 = Tester_Class_3.var_58])[(((new Tester_Class_4[Tester_Class_3.var_58])[Tester_Class_3.var_58]).var_69 = (Tester_Class_3)(Tester_Class_0)(new Object[Tester_Class_3.var_58])[Tester_Class_3.var_58]).var_61][Tester_Class_3.var_58];
+            Tester_Class_4 var_88 = var_85 ^ (var_81 = false) ? (new Tester_Class_4[Tester_Class_3.var_58])[Tester_Class_3.var_58] : (new Tester_Class_4[Tester_Class_3.var_58])[Tester_Class_3.var_58];
+            {
+                ++var_87;
+            }
+            short var_89;
+            (var_88.var_69 = (new Tester_Class_3[var_88.var_71][var_88.var_71])[var_88.var_71][var_88.var_71]).var_61 += (((Tester_Class_2)(new Tester_Class_1().var_31 = new Tester_Class_2())).var_3 = Tester_Class_3.var_58);
+            var_88 = var_88;
+        }
+        {
+            ++Tester_Class_2.var_46;
+            --Tester_Class_2.var_46;
+        }
+        {
+            Tester_Class_2.var_46++;
+            Tester_Class_3.var_64 /= Tester_Class_3.var_59;
+            ((Tester_Class_4)(new Object[Tester_Class_2.var_45 = Tester_Class_3.var_58])[Tester_Class_3.var_58]).var_71 %= (var_3 /= 3637233239489444864L);
+            ++Tester_Class_2.var_46;
+        }
+        new Tester_Class_3().var_57++;
+        var_85 &= (Tester_Class_3.var_55 |= false);
+        Tester_Class_3.var_60 = new Tester_Class_1();
+        Tester_Class_2.var_46++;
+        ((Tester_Class_3)(true ? (new Tester_Class_2[Tester_Class_3.var_58])[Tester_Class_3.var_58] : (new Tester_Class_0[Tester_Class_3.var_58])[Tester_Class_2.var_45 = Tester_Class_3.var_58])).var_57 *= ((new Tester_Class_3[Tester_Class_3.var_58])[(byte)'`']).var_57;
+        var_3 += (int)Tester_Class_3.var_59 ^ (Tester_Class_2.var_46 -= Tester_Class_2.var_46) % ~((new Tester_Class_4[Tester_Class_3.var_58])[Tester_Class_3.var_58]).var_71;
+        ++Tester_Class_2.var_46;
+        --Tester_Class_2.var_46;
+        var_83 = Tester_Class_3.var_58;
+    }
+
+
+
+
+    public String toString()
+    {
+        String result =  "[\n";
+        result += "Tester_Class_5.var_82 = "; result += Test6712835.Printer.print(var_82);
+        result += "\n";
+        result += "Tester_Class_5.var_83 = "; result += Test6712835.Printer.print(var_83);
+        result += "\n";
+        result += "Tester_Class_5.var_2 = "; result += Test6712835.Printer.print(var_2);
+        result += "\n";
+        result += "Tester_Class_5.var_3 = "; result += Test6712835.Printer.print(var_3);
+        result += "\n";
+        result += "Tester_Class_5.var_5 = "; result += Test6712835.Printer.print(var_5);
+        result += "\n";
+        result += "Tester_Class_5.var_84 = "; result += Test6712835.Printer.print(var_84);
+        result += "\n";
+        result += "Tester_Class_5.var_4 = "; result += Test6712835.Printer.print(var_4);
+        result += "\n";
+        result += "Tester_Class_5.var_1 = "; result += Test6712835.Printer.print(var_1);
+        result += "\n";
+        result += "Tester_Class_5.var_81 = "; result += Test6712835.Printer.print(var_81);
+        result += "\n";
+        result += "Tester_Class_5.var_85 = "; result += Test6712835.Printer.print(var_85);
+        result += "\n";
+        result += "Tester_Class_5.var_86 = "; result += Test6712835.Printer.print(var_86);
+        result += "";
+        result += "\n]";
+        return result;
+    }
+}
+
+
+class Tester_Class_6 extends Tester_Class_0 {
+    long var_90 = 8467263472031702016L;
+    final static int var_91 = 1648594448 * ']';
+    char var_92 = 'x';
+    short var_93 = Tester_Class_3.var_63;
+    Tester_Class_4 var_94;
+    String[] var_95;
+    static short var_96 = Tester_Class_3.var_63 -= 83376045 << 40225606;
+    final static double var_97 = 5.387227213380301E307;
+    final static short var_98 = Tester_Class_3.var_63 &= var_91;
+    byte var_99 = 44;
+
+
+    public Tester_Class_6()
+    {
+        (Tester_Class_3.var_60 = (Tester_Class_1)(new Object[Tester_Class_3.var_58][var_99])[Tester_Class_3.var_58][var_99]).var_31 = true | true ? (Tester_Class_5)(new Object[var_99])[Tester_Class_3.var_58] : (Tester_Class_5)(new Object[Tester_Class_3.var_58])[var_99];
+        var_92 &= 'p';
+        Tester_Class_5.var_81 = (((new Tester_Class_1[var_99][Tester_Class_3.var_58])[Tester_Class_3.var_58])[Tester_Class_3.var_58]).var_29;
+        {
+            {
+                ++Tester_Class_2.var_46;
+                Tester_Class_3.var_2 = var_98;
+                var_93 -= var_96;
+            }
+            Tester_Class_2.var_46--;
+            {
+                (var_5 == (((Tester_Class_3)(new Tester_Class_0[var_99])[Tester_Class_3.var_58]).var_61 /= var_5) ? "fsajxeuao".replace('s', 'K') : var_4).substring('e' >>> var_5).toLowerCase();
+            }
+            var_93 %= ((new Tester_Class_6[Tester_Class_3.var_58])[Tester_Class_3.var_58]).var_90;
+            var_93 /= var_93;
+            if (Tester_Class_5.var_86)
+            {
+                (var_94 = (new Tester_Class_4[var_99])[var_99]).var_69 = (new Tester_Class_3[var_99])[var_99 %= -var_90];
+            }
+            else
+            {
+                --var_96;
+            }
+            var_93 *= 'O';
+            final long var_103 = 7573900518735055872L;
+            --Tester_Class_3.var_63;
+        }
+        Tester_Class_3.var_64 /= var_93;
+        if (true)
+        {
+            --Tester_Class_2.var_46;
+            Tester_Class_5 var_104;
+            final double var_105 = Tester_Class_3.var_64 += Tester_Class_5.var_86 & (new Tester_Class_2().var_1 & ((Tester_Class_3.var_55 = (var_1 ^= Tester_Class_5.var_86) & false) & (Tester_Class_5.var_81 = Tester_Class_5.var_86))) ? (byte)'g' : var_99;
+            Tester_Class_3.var_64 *= var_99;
+        }
+        else
+        {
+            char var_106 = var_92 -= Tester_Class_3.var_58;
+        }
+        double[] var_107 = ((new double[Tester_Class_3.var_58][var_99][var_99])[var_99])[false ? Tester_Class_3.var_58 : Tester_Class_3.var_58];
+        var_99 <<= (Tester_Class_3.var_63 >>= Tester_Class_3.var_58);
+        ++var_99;
+    }
+
+
+
+
+    final static byte func_0(final byte arg_0, final char arg_1, final Tester_Class_5[] arg_2)
+    {
+        ((Tester_Class_4)(new Object[Tester_Class_3.var_58][Tester_Class_3.var_58])[Tester_Class_3.var_58][arg_0]).var_69 = (Tester_Class_3)(new Tester_Class_0[Tester_Class_3.var_58])[Tester_Class_2.var_45 = Tester_Class_3.var_58];
+        long var_100 = 0L;
+        Tester_Class_3.var_64 /= (Tester_Class_5.var_86 = true) || 'o' > (Tester_Class_3.var_63 -= (float)arg_0) ? var_98 : 1.7875238E38F;
+        do
+        {
+            Tester_Class_3.var_64 %= var_5;
+            var_100++;
+            Tester_Class_3.var_64 += var_96 + 'r';
+        } while (true && (var_100 < 1 && (new Tester_Class_1().var_29 ? new Tester_Class_1() : (new Tester_Class_1[arg_0][Tester_Class_3.var_58])[arg_0][Tester_Class_3.var_58]).var_29));
+        (Tester_Class_3.var_55 ^ (Tester_Class_3.var_60 = (Tester_Class_3.var_60 = (Tester_Class_3.var_60 = new Tester_Class_1()))).var_29 ? new Tester_Class_3() : new Tester_Class_3()).var_57 = ((((new Tester_Class_6[Tester_Class_3.var_58][Tester_Class_3.var_58])[Tester_Class_3.var_58][Tester_Class_3.var_58]).var_94 = (((new Tester_Class_6[Tester_Class_3.var_58][Tester_Class_3.var_58])[Tester_Class_3.var_58][arg_0]).var_94 = (new Tester_Class_4[Tester_Class_3.var_58][arg_0])[Tester_Class_3.var_58][Tester_Class_3.var_58])).var_69 = new Tester_Class_3()).var_57;
+        final double var_101 = 1.6798216578519203E308;
+        Tester_Class_3.var_60 = (Tester_Class_3.var_60 = false ? new Tester_Class_1() : (Tester_Class_3.var_60 = new Tester_Class_1()));
+        Tester_Class_2 var_102 = new Tester_Class_2();
+        return Tester_Class_3.var_58;
+    }
+
+    public String toString()
+    {
+        String result =  "[\n";
+        result += "Tester_Class_6.var_92 = "; result += Test6712835.Printer.print(var_92);
+        result += "\n";
+        result += "Tester_Class_6.var_91 = "; result += Test6712835.Printer.print(var_91);
+        result += "\n";
+        result += "Tester_Class_6.var_95 = "; result += Test6712835.Printer.print(var_95);
+        result += "\n";
+        result += "Tester_Class_6.var_90 = "; result += Test6712835.Printer.print(var_90);
+        result += "\n";
+        result += "Tester_Class_6.var_2 = "; result += Test6712835.Printer.print(var_2);
+        result += "\n";
+        result += "Tester_Class_6.var_97 = "; result += Test6712835.Printer.print(var_97);
+        result += "\n";
+        result += "Tester_Class_6.var_3 = "; result += Test6712835.Printer.print(var_3);
+        result += "\n";
+        result += "Tester_Class_6.var_5 = "; result += Test6712835.Printer.print(var_5);
+        result += "\n";
+        result += "Tester_Class_6.var_93 = "; result += Test6712835.Printer.print(var_93);
+        result += "\n";
+        result += "Tester_Class_6.var_96 = "; result += Test6712835.Printer.print(var_96);
+        result += "\n";
+        result += "Tester_Class_6.var_98 = "; result += Test6712835.Printer.print(var_98);
+        result += "\n";
+        result += "Tester_Class_6.var_99 = "; result += Test6712835.Printer.print(var_99);
+        result += "\n";
+        result += "Tester_Class_6.var_4 = "; result += Test6712835.Printer.print(var_4);
+        result += "\n";
+        result += "Tester_Class_6.var_1 = "; result += Test6712835.Printer.print(var_1);
+        result += "\n";
+        result += "Tester_Class_6.var_94 = "; result += Test6712835.Printer.print(var_94);
+        result += "";
+        result += "\n]";
+        return result;
+    }
+}
+
+
+abstract class Tester_Class_7 {
+    final static char var_108 = '_';
+    static Tester_Class_3 var_109;
+    final short var_110 = 4360;
+    short var_111;
+    Object var_112;
+    Tester_Class_4 var_113;
+    static Tester_Class_5 var_114;
+    final short var_115 = Tester_Class_6.var_96;
+    final static float var_116 = Tester_Class_3.var_59;
+
+
+    public Tester_Class_7()
+    {
+        --Tester_Class_2.var_46;
+        --Tester_Class_6.var_96;
+        var_113 = (new Tester_Class_4[new Tester_Class_6().var_99])[Tester_Class_3.var_58];
+        --Tester_Class_2.var_46;
+        Tester_Class_6.var_96--;
+        Tester_Class_3.var_63 -= 'i';
+        if (!Tester_Class_5.var_86)
+        {
+            Tester_Class_3.var_64 %= var_116;
+            if ((Tester_Class_3.var_60 = (Tester_Class_3.var_60 = (Tester_Class_1)(Tester_Class_0)(var_112 = "yosyghjm"))).var_29)
+            {
+                Tester_Class_2.var_46++;
+            }
+            else
+            {
+                (var_114 = (var_114 = (Tester_Class_5)(Tester_Class_0)(var_112 = "bxt"))).var_83 = (Tester_Class_2.var_45 = (Tester_Class_2.var_45 = Tester_Class_3.var_58));
+            }
+            var_114 = (var_114 = (var_114 = (var_114 = (var_114 = (var_114 = (Tester_Class_5)(var_112 = "blrobgg"))))));
+            var_113 = (((Tester_Class_6)(var_112 = "popebwfp")).var_94 = (new Tester_Class_4[Tester_Class_3.var_58])[Tester_Class_3.var_58]);
+        }
+        else
+        {
+            Tester_Class_3.var_60 = new Tester_Class_1();
+        }
+        final Tester_Class_6 var_122 = new Tester_Class_6();
+        var_122.var_92 &= (var_122.var_92 |= var_108);
+        ((new Tester_Class_5[var_122.var_99])[((new Tester_Class_3[Tester_Class_3.var_58])[var_122.var_99--]).var_61]).var_83 = 1708230145;
+    }
+
+
+
+    public boolean equals(Object obj)
+    {
+        (((Tester_Class_5.var_81 = (Tester_Class_5.var_81 = false)) ? (Tester_Class_3.var_55 &= false) : !Tester_Class_3.var_55 & ((Tester_Class_1)obj).var_29) ? (new Tester_Class_2[Tester_Class_3.var_58])[Tester_Class_3.var_58] : (Tester_Class_2)obj).equals((Tester_Class_5.var_86 |= Tester_Class_3.var_55) | (Tester_Class_3.var_55 = Tester_Class_3.var_55) ? obj : (Tester_Class_6)(Tester_Class_0)obj);
+        Tester_Class_3.var_64 *= 2.8258473339654136E307;
+        {
+            final int var_118 = 1248523063;
+            short var_119 = 30906;
+            Tester_Class_3.var_60 = (Tester_Class_3.var_60 = (Tester_Class_1)obj);
+            ((Tester_Class_6)(((Tester_Class_1)obj).var_31 = ((var_113 = (Tester_Class_4)obj).var_69 = (Tester_Class_3)obj))).var_94 = (var_113 = (Tester_Class_4)(var_112 = (Tester_Class_1)obj));
+        }
+        final Tester_Class_1 var_120 = false ^ (((Tester_Class_1)obj).var_1 = !true) ^ (((Tester_Class_6)(Tester_Class_0)obj).var_92 *= (((Tester_Class_3)obj).var_57 |= (Tester_Class_2.var_46 >>= 6986775136305733632L))) < (byte)Tester_Class_6.var_97 ? (Tester_Class_3.var_60 = (Tester_Class_3.var_60 = (Tester_Class_1)obj)) : (true ? (Tester_Class_1)obj : (Tester_Class_1)obj);
+        (var_114 = (var_114 = (Tester_Class_5)obj)).var_83 = (((new Tester_Class_6[Tester_Class_3.var_58])[Tester_Class_3.var_58]).var_92 &= ((Tester_Class_4)obj).var_70 << (Tester_Class_2.var_45 = Tester_Class_3.var_58));
+        var_114 = (Tester_Class_5)obj;
+        obj = ((Tester_Class_3.var_60 = var_120).var_29 ? false : false) ? (new Tester_Class_6[Tester_Class_3.var_58])[Tester_Class_3.var_58] : obj;
+        (var_120.var_29 ? (Tester_Class_6)(obj = (Tester_Class_3.var_60 = var_120)) : (new Tester_Class_6[Tester_Class_3.var_58])[((Tester_Class_3)obj).var_61 ^= Tester_Class_6.var_91]).var_90 ^= 2127530040436251648L;
+        Object var_121;
+        return (new boolean[Tester_Class_3.var_58])[((var_113 = (Tester_Class_4)obj).var_69 = (var_109 = (new Tester_Class_3[Tester_Class_3.var_58][Tester_Class_3.var_58])[Tester_Class_3.var_58][Tester_Class_3.var_58])).var_61];
+    }
+
+
+    public String toString()
+    {
+        String result =  "[\n";
+        result += "Tester_Class_7.var_108 = "; result += Test6712835.Printer.print(var_108);
+        result += "\n";
+        result += "Tester_Class_7.var_116 = "; result += Test6712835.Printer.print(var_116);
+        result += "\n";
+        result += "Tester_Class_7.var_110 = "; result += Test6712835.Printer.print(var_110);
+        result += "\n";
+        result += "Tester_Class_7.var_111 = "; result += Test6712835.Printer.print(var_111);
+        result += "\n";
+        result += "Tester_Class_7.var_115 = "; result += Test6712835.Printer.print(var_115);
+        result += "\n";
+        result += "Tester_Class_7.var_114 = "; result += Test6712835.Printer.print(var_114);
+        result += "\n";
+        result += "Tester_Class_7.var_113 = "; result += Test6712835.Printer.print(var_113);
+        result += "\n";
+        result += "Tester_Class_7.var_109 = "; result += Test6712835.Printer.print(var_109);
+        result += "\n";
+        result += "Tester_Class_7.var_112 = "; result += Test6712835.Printer.print(var_112);
+        result += "";
+        result += "\n]";
+        return result;
+    }
+}
+
+
+class Tester_Class_8 extends Tester_Class_7 {
+    static char var_123;
+    Tester_Class_4 var_124;
+    static short var_125;
+
+
+    public Tester_Class_8()
+    {
+        {
+            Tester_Class_3.var_64 -= (Tester_Class_2.var_46 *= Tester_Class_3.var_64);
+            {
+                Tester_Class_2.var_46--;
+            }
+            ++Tester_Class_3.var_63;
+            Tester_Class_5.var_86 |= true;
+            Tester_Class_6.var_96--;
+        }
+        "w".indexOf(312689020);
+        if (false)
+        {
+            (Tester_Class_7.var_114 = (new Tester_Class_5[Tester_Class_3.var_58])[Tester_Class_3.var_58]).var_83 = 'I';
+        }
+        else
+        {
+            --Tester_Class_6.var_96;
+        }
+        switch (Tester_Class_5.var_86 ? Tester_Class_3.var_58 : Tester_Class_3.var_58)
+        {
+            case 95:
+
+            case 35:
+
+        }
+        Tester_Class_6.var_96--;
+        Tester_Class_3.var_64 *= 4.516167673347119E307;
+        --Tester_Class_3.var_63;
+        {
+            int var_126;
+        }
+        Tester_Class_3.var_60 = new Tester_Class_1();
+        Tester_Class_2.var_46++;
+        ((new Tester_Class_6[Tester_Class_3.var_58])[Tester_Class_3.var_58]).var_99 &= Tester_Class_6.var_91;
+        ((new Tester_Class_1[((new Tester_Class_4[Tester_Class_3.var_58])[Tester_Class_3.var_58]).var_71])[((Tester_Class_3)(var_112 = "fsmtm")).var_61]).var_31 = (Tester_Class_2)(new Tester_Class_0[Tester_Class_3.var_58])[Tester_Class_3.var_58];
+    }
+
+
+
+
+    public String toString()
+    {
+        String result =  "[\n";
+        result += "Tester_Class_8.var_108 = "; result += Test6712835.Printer.print(var_108);
+        result += "\n";
+        result += "Tester_Class_8.var_123 = "; result += Test6712835.Printer.print(var_123);
+        result += "\n";
+        result += "Tester_Class_8.var_116 = "; result += Test6712835.Printer.print(var_116);
+        result += "\n";
+        result += "Tester_Class_8.var_110 = "; result += Test6712835.Printer.print(var_110);
+        result += "\n";
+        result += "Tester_Class_8.var_111 = "; result += Test6712835.Printer.print(var_111);
+        result += "\n";
+        result += "Tester_Class_8.var_115 = "; result += Test6712835.Printer.print(var_115);
+        result += "\n";
+        result += "Tester_Class_8.var_125 = "; result += Test6712835.Printer.print(var_125);
+        result += "\n";
+        result += "Tester_Class_8.var_114 = "; result += Test6712835.Printer.print(var_114);
+        result += "\n";
+        result += "Tester_Class_8.var_113 = "; result += Test6712835.Printer.print(var_113);
+        result += "\n";
+        result += "Tester_Class_8.var_124 = "; result += Test6712835.Printer.print(var_124);
+        result += "\n";
+        result += "Tester_Class_8.var_109 = "; result += Test6712835.Printer.print(var_109);
+        result += "\n";
+        result += "Tester_Class_8.var_112 = "; result += Test6712835.Printer.print(var_112);
+        result += "";
+        result += "\n]";
+        return result;
+    }
+}
+
+
+final class Tester_Class_9 {
+    final static String var_127 = "pxk";
+    Tester_Class_2 var_128;
+    final static char var_129 = '\\';
+    static float var_130;
+    static boolean var_131;
+    final static float var_132 = Tester_Class_3.var_59;
+    static Tester_Class_0 var_133;
+    boolean[] var_134;
+
+
+    public Tester_Class_9()
+    {
+        Tester_Class_2.var_44 -= Tester_Class_3.var_58;
+        Tester_Class_3.var_60 = (Tester_Class_3.var_60 = (Tester_Class_3.var_60 = (new Tester_Class_1[Tester_Class_3.var_58][Tester_Class_3.var_58])[Tester_Class_3.var_58][Tester_Class_3.var_58]));
+        {
+            Tester_Class_8 var_136;
+        }
+        ++Tester_Class_2.var_46;
+        Tester_Class_6.var_96--;
+        var_128 = (var_128 = (var_128 = (Tester_Class_2)(var_133 = (new Tester_Class_1[Tester_Class_3.var_58])[Tester_Class_3.var_58])));
+        ++Tester_Class_6.var_96;
+        ++Tester_Class_2.var_46;
+        Tester_Class_4 var_137;
+        var_128 = (var_128 = (new Tester_Class_2[Tester_Class_3.var_58])[Tester_Class_3.var_58]);
+        (Tester_Class_8.var_114 = (Tester_Class_8.var_114 = (new Tester_Class_5[Tester_Class_3.var_58])[Tester_Class_3.var_58])).var_83 = (((new Tester_Class_4[Tester_Class_3.var_58][Tester_Class_3.var_58])[Tester_Class_3.var_58][Tester_Class_3.var_58]).var_69 = (new Tester_Class_3[Tester_Class_3.var_58][Tester_Class_3.var_58])[Tester_Class_3.var_58][Tester_Class_3.var_58]).var_57++;
+        Tester_Class_2.var_46++;
+    }
+
+
+
+
+    protected static short func_1()
+    {
+        {
+            Tester_Class_3.var_63--;
+        }
+        Tester_Class_3.var_64 *= Tester_Class_2.var_46;
+        short var_135;
+        Tester_Class_3.var_64 -= Tester_Class_6.var_96;
+        return new Tester_Class_6().var_93;
+    }
+
+    public String toString()
+    {
+        String result =  "[\n";
+        result += "Tester_Class_9.var_129 = "; result += Test6712835.Printer.print(var_129);
+        result += "\n";
+        result += "Tester_Class_9.var_134 = "; result += Test6712835.Printer.print(var_134);
+        result += "\n";
+        result += "Tester_Class_9.var_130 = "; result += Test6712835.Printer.print(var_130);
+        result += "\n";
+        result += "Tester_Class_9.var_132 = "; result += Test6712835.Printer.print(var_132);
+        result += "\n";
+        result += "Tester_Class_9.var_131 = "; result += Test6712835.Printer.print(var_131);
+        result += "\n";
+        result += "Tester_Class_9.var_127 = "; result += Test6712835.Printer.print(var_127);
+        result += "\n";
+        result += "Tester_Class_9.var_128 = "; result += Test6712835.Printer.print(var_128);
+        result += "\n";
+        result += "Tester_Class_9.var_133 = "; result += Test6712835.Printer.print(var_133);
+        result += "";
+        result += "\n]";
+        return result;
+    }
+}
+
+
+final class Tester_Class_10 extends Tester_Class_0 {
+    final static byte var_138 = 78;
+    Object var_139;
+    final static boolean var_140 = true;
+    float var_141 = 1.2816267E38F;
+    Tester_Class_8 var_142;
+    static Tester_Class_3 var_143;
+    short var_144 = var_1 ? (Tester_Class_6.var_96 &= 8024552544994698240L) : Tester_Class_0.var_5;
+    final boolean var_145 = var_140;
+    long var_146;
+    float[] var_147;
+
+
+    public Tester_Class_10()
+    {
+        "xuc".codePointCount(new Tester_Class_6().var_99 / ((new Tester_Class_9().var_128 = new Tester_Class_2()).var_1 ? var_138 : (int)(Tester_Class_3.var_64 += Tester_Class_3.var_64)), 882345740);
+        Tester_Class_3.var_64 /= Tester_Class_9.var_132;
+        Tester_Class_9.var_127.indexOf((Tester_Class_7.var_114 = (Tester_Class_8.var_114 = (Tester_Class_5)(var_139 = "mcyagebtv"))).var_83 = var_145 ? (Tester_Class_2.var_45 = Tester_Class_3.var_58) : Tester_Class_6.var_96);
+        --Tester_Class_2.var_46;
+        final float var_148 = 3.0263434E38F;
+        ((Tester_Class_7.var_114 = (Tester_Class_5)(Tester_Class_9.var_133 = new Tester_Class_1())).var_85 & ((Tester_Class_1)(var_139 = new Tester_Class_6())).var_1 ? "gmxwrgik" : Tester_Class_9.var_127).compareTo(var_4);
+        --Tester_Class_2.var_46;
+        new Tester_Class_6();
+        ++Tester_Class_2.var_46;
+        Tester_Class_3.var_60 = Tester_Class_5.var_86 ? new Tester_Class_1() : new Tester_Class_1();
+        {
+            --Tester_Class_6.var_96;
+            ((Tester_Class_7)(var_139 = new Tester_Class_1().var_4)).var_112 = (Tester_Class_3.var_60 = (Tester_Class_3.var_60 = (Tester_Class_1)(var_139 = "gugsy")));
+        }
+        Tester_Class_9.var_133 = (Tester_Class_3.var_60 = new Tester_Class_1());
+        if (var_140 & !var_140)
+        {
+            Tester_Class_6.var_96++;
+        }
+        else
+        {
+            Tester_Class_2.var_46++;
+        }
+        {
+            ++new Tester_Class_6().var_92;
+        }
+        Tester_Class_7.var_109 = (((new Tester_Class_4[Tester_Class_3.var_58])[Tester_Class_3.var_58]).var_69 = (var_143 = new Tester_Class_3()));
+        Tester_Class_3.var_63--;
+    }
+
+
+
+
+    public String toString()
+    {
+        String result =  "[\n";
+        result += "Tester_Class_10.var_147 = "; result += Test6712835.Printer.print(var_147);
+        result += "\n";
+        result += "Tester_Class_10.var_146 = "; result += Test6712835.Printer.print(var_146);
+        result += "\n";
+        result += "Tester_Class_10.var_3 = "; result += Test6712835.Printer.print(var_3);
+        result += "\n";
+        result += "Tester_Class_10.var_141 = "; result += Test6712835.Printer.print(var_141);
+        result += "\n";
+        result += "Tester_Class_10.var_5 = "; result += Test6712835.Printer.print(var_5);
+        result += "\n";
+        result += "Tester_Class_10.var_144 = "; result += Test6712835.Printer.print(var_144);
+        result += "\n";
+        result += "Tester_Class_10.var_138 = "; result += Test6712835.Printer.print(var_138);
+        result += "\n";
+        result += "Tester_Class_10.var_1 = "; result += Test6712835.Printer.print(var_1);
+        result += "\n";
+        result += "Tester_Class_10.var_140 = "; result += Test6712835.Printer.print(var_140);
+        result += "\n";
+        result += "Tester_Class_10.var_145 = "; result += Test6712835.Printer.print(var_145);
+        result += "\n";
+        result += "Tester_Class_10.var_139 = "; result += Test6712835.Printer.print(var_139);
+        result += "\n";
+        result += "Tester_Class_10.var_142 = "; result += Test6712835.Printer.print(var_142);
+        result += "\n";
+        result += "Tester_Class_10.var_2 = "; result += Test6712835.Printer.print(var_2);
+        result += "\n";
+        result += "Tester_Class_10.var_4 = "; result += Test6712835.Printer.print(var_4);
+        result += "\n";
+        result += "Tester_Class_10.var_143 = "; result += Test6712835.Printer.print(var_143);
+        result += "";
+        result += "\n]";
+        return result;
+    }
+}
+
+
+interface Tester_Interface_11 {
+    public Tester_Class_4 func_0(final int arg_0, final byte arg_1);
+    public Tester_Class_2 func_1(Tester_Class_5 arg_0, final Tester_Class_0 arg_1, final int arg_2);
+}
+
+public class Test6712835 {
+    final boolean var_149 = false;
+    Tester_Class_8 var_150;
+    final long var_151 = 8058077687473630208L;
+
+
+    protected final Tester_Class_1 func_0(final Object arg_0, Tester_Class_3 arg_1, final Tester_Class_4 arg_2, int arg_3)
+    {
+        Tester_Class_3.var_60 = (Tester_Class_3.var_60 = (Tester_Class_3.var_60 = (Tester_Class_1)arg_0));
+        --Tester_Class_3.var_63;
+        (var_150 = (((new Tester_Class_10[arg_2.var_71])[(((Tester_Class_6)arg_0).var_94 = arg_2).var_71 &= Tester_Class_3.var_63 << ~arg_2.var_71]).var_142 = (var_150 = (((Tester_Class_10)arg_0).var_142 = (Tester_Class_8)arg_0)))).var_113 = arg_2;
+        Tester_Class_7.var_114 = (Tester_Class_7.var_114 = false ? (Tester_Class_5)arg_0 : (Tester_Class_5)arg_0);
+        ((((arg_1 = arg_1).var_1 |= "lgcrda".equalsIgnoreCase("ontlkst")) ? (Tester_Class_1)arg_0 : (Tester_Class_3.var_60 = (Tester_Class_1)arg_0)).var_29 ? (arg_1 = (Tester_Class_3)(((Tester_Class_7)arg_0).var_112 = (Tester_Class_9)arg_0)) : arg_1).var_57 >>>= ']';
+        Tester_Class_8.var_114 = (Tester_Class_5)arg_0;
+        ((Tester_Class_3.var_55 &= (arg_1.var_1 = true)) ? (Tester_Class_6)(new Tester_Class_0[Tester_Class_3.var_58][Tester_Class_10.var_138])[Tester_Class_10.var_138][Tester_Class_10.var_138] : (Tester_Class_6)arg_0).var_94 = arg_2;
+        {
+            Tester_Class_3.var_55 &= ((Tester_Class_3.var_60 = new Tester_Class_1()).var_1 &= false);
+            Tester_Class_2.var_44 -= (arg_3 |= + ~6610561718704644096L);
+            ((Tester_Class_8)arg_0).var_113 = ((((Tester_Class_10)(Tester_Class_0)arg_0).var_142 = (var_150 = (Tester_Class_8)arg_0)).var_124 = arg_2);
+            (! (false | Tester_Class_5.var_86) ? (Tester_Class_10)arg_0 : (new Tester_Class_10[arg_1.var_61][arg_1.var_61])[Tester_Class_10.var_138][Tester_Class_10.var_138]).var_139 = ((Tester_Class_3.var_60 = (Tester_Class_3.var_60 = (Tester_Class_1)arg_0)).var_31 = (((Tester_Class_9)arg_0).var_128 = (((Tester_Class_9)arg_0).var_128 = (Tester_Class_2)arg_0)));
+        }
+        final Tester_Interface_11 var_152 = !((Tester_Class_1)arg_0).var_29 ^ Tester_Class_5.var_86 ? (new Tester_Interface_11[arg_2.var_71][arg_1.var_61])[arg_1.var_61][arg_1.var_61] : (new Tester_Interface_11[arg_2.var_71][arg_2.var_71])[Tester_Class_10.var_138][Tester_Class_3.var_58];
+        Tester_Class_3.var_64 /= (arg_3 >>= ++((Tester_Class_6)(Tester_Class_0)arg_0).var_92) * Tester_Class_9.var_132;
+        Tester_Class_0 var_153 = (Tester_Class_3.var_60 = (Tester_Class_3.var_60 = (Tester_Class_3.var_60 = (Tester_Class_3.var_60 = (Tester_Class_3.var_60 = (Tester_Class_1)arg_0))))).var_31 = (((new Tester_Class_9[arg_1.var_61])[arg_1.var_61 *= 634692606]).var_128 = !false ? (Tester_Class_2)arg_0 : (Tester_Class_2)arg_0);
+        (Tester_Class_10.var_140 ? (Tester_Class_7)arg_0 : (var_150 = (Tester_Class_8)(Tester_Class_7)arg_0)).var_112 = Tester_Class_3.var_64 != ((((Tester_Class_10)(var_153 = (Tester_Class_8.var_114 = (Tester_Class_5)arg_0))).var_1 |= arg_1.var_1) ? (Tester_Class_6)var_153 : (Tester_Class_6)var_153).var_99-- ? (Tester_Class_7)((var_150 = (Tester_Class_8)arg_0).var_112 = (Tester_Class_10)var_153) : (Tester_Class_7)arg_0;
+        (((new Tester_Class_7[Tester_Class_10.var_138][arg_2.var_71])[Tester_Class_3.var_58])[arg_2.var_71]).var_112 = arg_0;
+        if (!false)
+        {
+            arg_3 <<= (Tester_Class_2.var_46 /= - ((byte)((Tester_Class_10)arg_0).var_144)) - ((Tester_Class_6)arg_0).var_99;
+        }
+        else
+        {
+            ((Tester_Class_7)(((Tester_Class_8)arg_0).var_112 = var_153)).var_113 = arg_2;
+            ((Tester_Class_9)arg_0).var_128 = (((Tester_Class_9)(((Tester_Class_7)arg_0).var_112 = (Tester_Class_7)arg_0)).var_128 = (((Tester_Class_9)arg_0).var_128 = (Tester_Class_2)arg_0));
+        }
+        (((Tester_Class_10)arg_0).var_142 = (Tester_Class_8)arg_0).var_124 = (((Tester_Class_6)var_153).var_94 = arg_2);
+        final char var_154 = arg_1.var_57 %= ((Tester_Class_6)var_153).var_93--;
+        (true ? arg_1 : (arg_1 = arg_1)).equals(arg_0);
+        (Tester_Class_10.var_140 ? (new Tester_Class_6[Tester_Class_10.var_138])[arg_2.var_71] : (new Tester_Class_6[(Tester_Class_10.var_143 = arg_1).var_61])[arg_1.var_61]).var_94 = ((((new Tester_Class_7[arg_2.var_71][arg_1.var_61][Tester_Class_10.var_138])[Tester_Class_10.var_138])[arg_2.var_71 = arg_2.var_71][Tester_Class_10.var_138]).var_113 = (((Tester_Class_7)arg_0).var_113 = arg_2));
+        Tester_Class_3.var_60 = ((Tester_Class_10)(((Tester_Class_7)arg_0).var_112 = (Tester_Class_7)(((Tester_Class_10)var_153).var_139 = new Tester_Class_6[Tester_Class_10.var_138][Tester_Class_10.var_138]))).var_1 ? (Tester_Class_3.var_60 = (Tester_Class_1)var_153) : (Tester_Class_3.var_60 = (Tester_Class_3.var_60 = (Tester_Class_1)(Tester_Class_9.var_133 = (Tester_Class_10)arg_0)));
+        ((Tester_Class_7)(((Tester_Class_10)arg_0).var_139 = new Tester_Class_10[Tester_Class_3.var_58][--arg_2.var_71])).var_112 = new byte[(((Tester_Class_8)(Tester_Class_7)((var_150 = (var_150 = (Tester_Class_8)arg_0)).var_112 = arg_2)).var_113 = (((Tester_Class_7)arg_0).var_113 = arg_2)).var_71];
+        Tester_Class_8 var_155;
+        (Tester_Class_3.var_55 & arg_2.equals(arg_0) ? (Tester_Class_10)var_153 : (Tester_Class_10)var_153).var_3 %= Tester_Class_6.var_91;
+        return ((Tester_Class_3.var_60 = (Tester_Class_3.var_60 = (Tester_Class_3.var_60 = (Tester_Class_3.var_60 = (Tester_Class_1)var_153)))).var_29 ? ! !true : Tester_Class_10.var_140 | Tester_Class_3.var_55) || Tester_Class_3.var_55 ? (Tester_Class_3.var_60 = (Tester_Class_1)(((Tester_Class_10)var_153).var_139 = (Tester_Class_6)var_153)) : new Tester_Class_1();
+    }
+
+    protected Tester_Class_5 func_1(Tester_Class_0 arg_0, final float arg_1)
+    {
+        (!Tester_Class_10.var_140 ? (Tester_Class_6)arg_0 : (Tester_Class_6)arg_0).var_90 /= ((Tester_Class_8.var_109 = (new boolean[Tester_Class_10.var_138][Tester_Class_3.var_58])[((Tester_Class_6)arg_0).var_99][Tester_Class_10.var_138] ? (Tester_Class_3)((Tester_Class_3.var_60 = (Tester_Class_1)arg_0).var_31 = (Tester_Class_6)arg_0) : (Tester_Class_3)arg_0).var_61 *= Tester_Class_3.var_58);
+        {
+            "".toLowerCase();
+        }
+        ((Tester_Class_10)arg_0).var_139 = new Tester_Class_8();
+        arg_0 = (new Tester_Class_6[((Tester_Class_6)arg_0).var_99])[Tester_Class_3.var_58];
+        if (((Tester_Class_10)(arg_0 = (Tester_Class_3.var_60 = (Tester_Class_3.var_60 = (Tester_Class_1)arg_0)))).var_145)
+        {
+            Tester_Class_3.var_63++;
+        }
+        else
+        {
+            ++Tester_Class_2.var_46;
+        }
+        (((Tester_Class_3.var_55 ^= Tester_Class_3.var_55 ^ true) ? (Tester_Class_10)arg_0 : (Tester_Class_10)arg_0).var_145 || true ? (Tester_Class_6)arg_0 : (Tester_Class_6)(((Tester_Class_7)(((Tester_Class_10)arg_0).var_139 = (Tester_Class_10)arg_0)).var_112 = "jlixai")).var_99--;
+        Tester_Class_5.var_81 = Tester_Class_3.var_55 && ! (arg_0.var_1 = arg_0.var_1);
+        {
+            ((new Tester_Class_6[Tester_Class_3.var_58])[(true ? (Tester_Class_6)(Tester_Class_9.var_133 = (Tester_Class_10)arg_0) : (Tester_Class_6)(((Tester_Class_1)arg_0).var_31 = (Tester_Class_10)arg_0)).var_99]).var_90 *= (Tester_Class_3.var_64 %= Tester_Class_3.var_63);
+        }
+        ++Tester_Class_2.var_46;
+        Tester_Class_0 var_156;
+        Tester_Class_2.var_46++;
+        Tester_Class_8.var_114 = (Tester_Class_7.var_114 = (Tester_Class_8.var_114 = (Tester_Class_5)arg_0));
+        Tester_Class_6.func_2((Tester_Class_7.var_114 = (Tester_Class_7.var_114 = (Tester_Class_7.var_114 = (Tester_Class_5)arg_0))).var_83 = (byte)(((Tester_Class_10)arg_0).var_142 = (new Tester_Class_8[Tester_Class_3.var_58][Tester_Class_3.var_58])[Tester_Class_3.var_58][Tester_Class_10.var_138]).var_110, Tester_Class_6.var_96, (new byte[Tester_Class_3.var_58])[Tester_Class_10.var_138]);
+        Tester_Class_7.var_114 = (new Tester_Class_5[Tester_Class_10.var_138])[((Tester_Class_3)arg_0).var_61];
+        boolean var_157 = Tester_Class_10.var_140;
+        (Tester_Class_3.var_60 = (Tester_Class_1)arg_0).var_1 ^= Tester_Class_10.var_140;
+        return Tester_Class_8.var_114 = (Tester_Class_7.var_114 = (Tester_Class_8.var_114 = (Tester_Class_5)arg_0));
+    }
+
+    final static int func_2(Tester_Class_6 arg_0)
+    {
+        new Tester_Class_9();
+        {
+            ++Tester_Class_3.var_63;
+        }
+        new Tester_Class_3().var_57--;
+        Tester_Class_1 var_158;
+        String var_159;
+        --Tester_Class_6.var_96;
+        {
+            new String();
+        }
+        var_159 = (var_159 = arg_0.var_4);
+        {
+            --Tester_Class_2.var_46;
+        }
+        final double var_160 = (Tester_Class_7.var_114 = (Tester_Class_8.var_114 = (Tester_Class_8.var_114 = (Tester_Class_5)(new Tester_Class_0[arg_0.var_99][arg_0.var_99])[Tester_Class_3.var_58][Tester_Class_3.var_58]))).var_1 ? Tester_Class_9.var_132 : Tester_Class_6.var_97;
+        Tester_Class_8 var_161;
+        char var_162 = 'O';
+        Tester_Class_2.var_46++;
+        Tester_Class_6.var_96++;
+        {
+            new String();
+        }
+        ++Tester_Class_6.var_96;
+        var_162 >>= ((new Tester_Class_4[arg_0.var_99])[arg_0.var_99++]).var_70 >> Tester_Class_6.var_91;
+        (Tester_Class_7.var_114 = (Tester_Class_7.var_114 = (new Tester_Class_5[Tester_Class_3.var_58])[++arg_0.var_99])).var_83 = (arg_0.var_93 <<= Tester_Class_7.var_108);
+        --Tester_Class_6.var_96;
+        {
+            new Tester_Class_9().var_128 = new Tester_Class_2();
+        }
+        arg_0 = arg_0;
+        {
+            Tester_Class_9 var_163;
+        }
+        ((Tester_Class_5)(Tester_Class_9.var_133 = arg_0)).var_83 = (arg_0.var_99 >>= Tester_Class_5.var_5);
+        arg_0.var_99 = Tester_Class_10.var_138;
+        Tester_Class_3.var_60 = (var_158 = (Tester_Class_3.var_60 = (Tester_Class_1)(Tester_Class_9.var_133 = arg_0)));
+        return Tester_Class_6.var_91;
+    }
+
+    protected final Tester_Class_9 func_3()
+    {
+        Tester_Class_2.var_44 = 3210658399310388224L;
+        ++Tester_Class_6.var_96;
+        short var_164 = 15978;
+        var_164++;
+        Tester_Class_5.var_81 = true;
+        return Tester_Class_3.var_55 ? new Tester_Class_9() : new Tester_Class_9();
+    }
+
+    final static Tester_Class_10 func_4(Tester_Class_3 arg_0, String arg_1, final byte[] arg_2, final Object arg_3)
+    {
+        Tester_Class_1 var_165;
+        Tester_Class_3.var_63 += new Tester_Class_6().var_92 >= 3821095133162842112L ? (arg_0.var_61 |= Tester_Class_6.var_91) : Tester_Class_10.var_138;
+        return false ? ((var_165 = (Tester_Class_1)arg_3).var_29 ? (Tester_Class_10)arg_3 : (Tester_Class_10)arg_3) : (Tester_Class_10)(Tester_Class_0)arg_3;
+    }
+
+    private static Object func_7(final short arg_0, String arg_1, final Tester_Class_3 arg_2)
+    {
+        Tester_Class_3.var_60 = (new Tester_Class_1[arg_2.var_61])[Tester_Class_10.var_138];
+        return ((new Tester_Class_7[arg_2.var_61 |= Tester_Class_3.var_63])[arg_2.var_61 *= Tester_Class_6.var_98]).var_112 = new Tester_Class_8();
+    }
+
+    public static String execute()
+    {
+        try {
+            Test6712835 t = new Test6712835();
+            try { t.test(); }
+            catch(Throwable e) { }
+            try { return t.toString(); }
+            catch (Throwable e) { return "Error during result conversion to String"; }
+        } catch (Throwable e) { return "Error during test execution"; }
+    }
+
+    public static void main(String[] args)
+    {
+        try {
+            Test6712835 t = new Test6712835();
+            try { t.test(); }
+            catch(Throwable e) { }
+            try { System.out.println(t); }
+            catch(Throwable e) { }
+        } catch (Throwable e) { }
+    }
+
+    private void test()
+    {
+        Tester_Class_3.var_60 = true ? (Tester_Class_3.var_60 = new Tester_Class_1()) : new Tester_Class_1();
+        double var_170 = 0;
+        Tester_Class_9.var_133 = (new Tester_Class_4().var_69 = new Tester_Class_3());
+        new Tester_Class_6();
+        String var_171;
+        new Tester_Class_9();
+        do
+        {
+            new String();
+            var_170++;
+            Tester_Class_3.var_64 = 1.0240330514364089E307;
+            new String();
+            var_171 = (var_171 = Tester_Class_9.var_127);
+            Tester_Class_3.var_63--;
+        } while (var_170 < 525);
+        ((new Tester_Class_10[Tester_Class_10.var_138])[Tester_Class_2.var_45 = Tester_Class_3.var_58]).var_142 = (Tester_Class_8)(Tester_Class_7)(new Tester_Class_10().var_139 = new Tester_Class_2());
+        long var_172 = 0L;
+        Tester_Class_3.var_64 /= (((new Tester_Class_6[Tester_Class_3.var_58])[Tester_Class_10.var_138]).var_99 ^= ((new Tester_Class_6[Tester_Class_3.var_58])[Tester_Class_10.var_138]).var_90) > 9.462466046830147E307 ? new Tester_Class_6().var_99 : Tester_Class_3.var_58;
+        short var_173;
+        (true ? new Tester_Class_2() : (func_3().var_128 = new Tester_Class_2())).var_3 *= (var_150 = new Tester_Class_8()).var_115;
+        (Tester_Class_3.var_60 = new Tester_Class_1()).var_31 = (((new Tester_Class_9[Tester_Class_3.var_58])[Tester_Class_10.var_138]).var_128 = (func_3().var_128 = (func_3().var_128 = (new Tester_Class_9().var_128 = new Tester_Class_2()))));
+        for (((new Tester_Class_10[new Tester_Class_6().var_99])[new Tester_Class_6().var_99++]).var_142 = (new Tester_Class_8[Tester_Class_10.var_138])[Tester_Class_3.var_58]; var_172 < 203 && (Tester_Class_3.var_55 &= (new boolean[Tester_Class_2.var_45 = Tester_Class_3.var_58])[Tester_Class_10.var_138]); Tester_Class_9.var_133 = (Tester_Class_7.var_114 = (new Tester_Class_5[Tester_Class_2.var_45 = Tester_Class_10.var_138][Tester_Class_10.var_138])[Tester_Class_3.var_58][Tester_Class_2.var_45 = Tester_Class_3.var_58]))
+        {
+            var_171 = Tester_Class_9.var_127;
+            var_172++;
+            Tester_Class_3.var_63++;
+            Tester_Class_3.var_60 = (Tester_Class_3.var_60 = (Tester_Class_3.var_60 = (Tester_Class_3.var_60 = (Tester_Class_1)(new Object[Tester_Class_3.var_58][Tester_Class_10.var_138])[Tester_Class_3.var_58][Tester_Class_3.var_58])));
+            ++Tester_Class_2.var_46;
+            Tester_Class_2.var_46--;
+            Tester_Class_3.var_64 -= Tester_Class_3.var_58;
+        }
+        (Tester_Class_3.var_60 = new Tester_Class_1()).var_31 = ((new Tester_Class_8().var_124 = new Tester_Class_4()).var_69 = new Tester_Class_3());
+        int var_174 = 0;
+        ((new Tester_Class_6[Tester_Class_10.var_138][Tester_Class_10.var_138])[Tester_Class_2.var_45 = Tester_Class_10.var_138][Tester_Class_2.var_45 = Tester_Class_3.var_58]).var_92 = 'Z';
+        while ((Tester_Class_9.var_131 = Tester_Class_3.var_55) && (var_174 < 24 && !true))
+        {
+            new Tester_Class_10();
+            var_174++;
+            Tester_Class_3.var_64 %= (((new Tester_Class_6[Tester_Class_3.var_58])[Tester_Class_2.var_45 = Tester_Class_3.var_58]).var_93 ^= (byte)Tester_Class_3.var_59);
+            ((Tester_Class_10)(Tester_Class_9.var_133 = (new Tester_Class_5[((Tester_Class_6)(new Tester_Class_0[Tester_Class_10.var_138])[(byte)(Tester_Class_2.var_46 >>>= Tester_Class_7.var_108)]).var_99])[Tester_Class_10.var_138])).var_139 = (new Tester_Class_10[new Tester_Class_6().var_99][new Tester_Class_4().var_71])[new Tester_Class_4().var_71];
+        }
+        int var_175 = 0;
+        (Tester_Class_10.var_140 ? (Tester_Class_2)(Tester_Class_9.var_133 = (Tester_Class_7.var_114 = (new Tester_Class_5[Tester_Class_10.var_138])[Tester_Class_10.var_138])) : new Tester_Class_2()).var_1 &= Tester_Class_3.var_55;
+        do
+        {
+            Tester_Class_10.var_143 = new Tester_Class_3();
+            var_175++;
+            ++Tester_Class_2.var_46;
+        } while ((false ? true : var_149) | !Tester_Class_10.var_140 && var_175 < 97);
+        Tester_Class_9.var_131 = true;
+        (Tester_Class_3.var_60 = (Tester_Class_3.var_60 = (Tester_Class_3.var_60 = (Tester_Class_3.var_60 = new Tester_Class_1())))).var_1 &= (((new Tester_Class_10().var_1 = !true) ? new Tester_Class_10() : new Tester_Class_10()).var_145 ? new Tester_Class_3() : new Tester_Class_3()).var_1;
+        (true ? func_3() : func_3()).var_128 = ((((Tester_Class_5.var_86 = (Tester_Class_3.var_55 &= !var_149)) ? new Tester_Class_10() : new Tester_Class_10()).var_145 ? new Tester_Class_9() : func_3()).var_128 = var_149 ? new Tester_Class_2() : new Tester_Class_2());
+        Tester_Class_3.var_59 -= (Tester_Class_5.var_81 = new Tester_Class_1().var_29) ^ !true ? 7920143378515332096L : new Tester_Class_6().var_92;
+        ((Tester_Class_3.var_60 = new Tester_Class_1()).var_1 ? (new Tester_Class_5[Tester_Class_10.var_138][Tester_Class_3.var_58])[Tester_Class_3.var_58][Tester_Class_3.var_58] : (Tester_Class_8.var_114 = new Tester_Class_5())).var_83 = Tester_Class_10.var_140 ? (Tester_Class_3.var_63 -= 2.0167496E38F) : ++Tester_Class_3.var_63;
+        double var_176 = 9.327780852480363E307;
+    }
+    public String toString()
+    {
+        String result =  "[\n";
+        result += "Test6712835.var_151 = "; result += Printer.print(var_151);
+        result += "\n";
+        result += "Test6712835.var_149 = "; result += Printer.print(var_149);
+        result += "\n";
+        result += "Test6712835.var_150 = "; result += Printer.print(var_150);
+        result += "";
+        result += "\n]";
+        return result;
+    }
+    static class Printer
+    {
+        public static String print(boolean arg) { return String.valueOf(arg); }
+        public static String print(byte arg)    { return String.valueOf(arg); }
+        public static String print(short arg)   { return String.valueOf(arg); }
+        public static String print(char arg)    { return String.valueOf((int)arg); }
+        public static String print(int arg)     { return String.valueOf(arg); }
+        public static String print(long arg)    { return String.valueOf(arg); }
+        public static String print(float arg)   { return String.valueOf(arg); }
+        public static String print(double arg)  { return String.valueOf(arg); }
+
+
+        public static String print(Object arg)
+        {
+            return print_r(new java.util.Stack(), arg);
+        }
+
+        private static String print_r(java.util.Stack visitedObjects, Object arg)
+        {
+            String result = "";
+            if (arg == null)
+                result += "null";
+            else
+            if (arg.getClass().isArray())
+            {
+                for (int i = 0; i < visitedObjects.size(); i++)
+                    if (visitedObjects.elementAt(i) == arg) return "<recursive>";
+
+                visitedObjects.push(arg);
+
+                final String delimiter = ", ";
+                result += "[";
+
+                if (arg instanceof Object[])
+                {
+                    Object[] array = (Object[]) arg;
+                    for (int i = 0; i < array.length; i++)
+                    {
+                        result += print_r(visitedObjects, array[i]);
+                        if (i < array.length - 1) result += delimiter;
+                    }
+                }
+                else
+                if (arg instanceof boolean[])
+                {
+                    boolean[] array = (boolean[]) arg;
+                    for (int i = 0; i < array.length; i++)
+                    {
+                        result += print(array[i]);
+                        if (i < array.length - 1) result += delimiter;
+                    }
+                }
+                else
+                if (arg instanceof byte[])
+                {
+                    byte[] array = (byte[]) arg;
+                    for (int i = 0; i < array.length; i++)
+                    {
+                        result += print(array[i]);
+                        if (i < array.length - 1) result += delimiter;
+                    }
+                }
+                else
+                if (arg instanceof short[])
+                {
+                    short[] array = (short[]) arg;
+                    for (int i = 0; i < array.length; i++)
+                    {
+                        result += print(array[i]);
+                        if (i < array.length - 1) result += delimiter;
+                    }
+                }
+                else
+                if (arg instanceof char[])
+                {
+                    char[] array = (char[]) arg;
+                    for (int i = 0; i < array.length; i++)
+                    {
+                        result += print(array[i]);
+                        if (i < array.length - 1) result += delimiter;
+                    }
+                }
+                else
+                if (arg instanceof int[])
+                {
+                     int[] array = (int[]) arg;
+                     for (int i = 0; i < array.length; i++)
+                     {
+                        result += print(array[i]);
+                        if (i < array.length - 1) result += delimiter;
+                     }
+                }
+                else
+                if (arg instanceof long[])
+                {
+                    long[] array = (long[]) arg;
+                    for (int i = 0; i < array.length; i++)
+                    {
+                        result += print(array[i]);
+                        if (i < array.length - 1) result += delimiter;
+                    }
+                }
+                else
+                if (arg instanceof float[])
+                {
+                    float[] array = (float[]) arg;
+                    for (int i = 0; i < array.length; i++)
+                    {
+                        result += print(array[i]);
+                        if (i < array.length - 1) result += delimiter;
+                    }
+                }
+                else
+                if (arg instanceof double[])
+                {
+                    double[] array = (double[]) arg;
+                    for (int i = 0; i < array.length; i++)
+                    {
+                        result += print(array[i]);
+                        if (i < array.length - 1) result += delimiter;
+                    }
+                }
+
+                result += "]";
+                visitedObjects.pop();
+
+            } else
+            {
+                result += arg.toString();
+            }
+
+            return result;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/6724218/Test.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @bug 6724218
+ * @summary Fix raise_LCA_above_marks() early termination
+ * @run main/othervm -Xbatch -XX:CompileCommand=exclude,Test.update Test
+ */
+
+public class Test {
+    Test   next  = null;
+    Object value = null;
+
+    static boolean _closed = false;
+    static int size = 0;
+    static Test list  = null;
+    static int cache_size = 0;
+    static Test cache = null;
+
+    Object get(int i) {
+        Test t = list;
+        list = t.next;
+        size -= 1;
+        Object o = t.value;
+        if (i > 0) {
+            t.next = cache;
+            t.value = null;
+            cache = t;
+            cache_size = +1;
+        }
+        return o;
+    }
+
+    void update() {
+        // Exclude compilation of this one.
+        if (size == 0) {
+            Test t;
+            if (cache_size > 0) {
+                t = cache;
+                cache = t.next;
+                cache_size = -1;
+            } else {
+                t = new Test();
+            }
+            t.value = new Object();
+            t.next = list;
+            list = t;
+            size += 1;
+        }
+    }
+
+    synchronized Object test(int i) {
+        while (true) {
+            if (_closed) {
+                return null;
+            } else if (size > 0) {
+                return get(i);
+            }
+            update();
+        }
+    }
+
+    public static void main(String argv[]) throws Exception {
+        Test t = new Test();
+        int lim = 500000;
+        Object o;
+        for (int j = 0; j < lim; j++) {
+            o = t.test(j&1);
+            if (o == null) {
+              throw new Exception("*** Failed on iteration " + j);
+            }
+            if ((j&1) == 0) {
+              t.update();
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/6726999/Test.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,1419 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+/*
+ * @test
+ * @bug 6726999
+ * @summary nsk/stress/jck12a/jck12a010 assert(n != NULL,"Bad immediate dominator info.");
+ * @run main/othervm -Xbatch -XX:CompileCommand=exclude,Test.dummy -XX:+AggressiveOpts Test
+ */
+
+import java.lang.reflect.Array;
+
+class Point {
+  int x;
+  int y;
+}
+
+public class Test {
+
+  void dummy() {
+    // Empty method to verify correctness of DebugInfo.
+    // Use -XX:CompileCommand=exclude,Test.dummy
+  }
+
+  int test0_0_0(int y) {
+    int x = 3;
+    Point p = new Point();
+    dummy();
+    p.x = x;
+    p.y = 3 * x + y;
+    return p.x * p.y;
+  }
+
+  int test0_0_1(int y) {
+    int x = 3;
+    Point p = null;
+    dummy();
+    p = new Point();
+    dummy();
+    p.x = x;
+    p.y = 3 * x + y;
+    return p.x * p.y;
+  }
+
+  int test0_0_2(int y) {
+    int x = 3;
+    Point p = new Point();
+    dummy();
+    p = new Point();
+    dummy();
+    p.x = x;
+    p.y = 3 * x + y;
+    return p.x * p.y;
+  }
+
+  int test0_0_3(int y) {
+    int x = 3;
+    Point p[] = new Point[1];
+    p[0] = new Point();
+    dummy();
+    p[0].x = x;
+    p[0].y = 3 * x + y;
+    return p[0].x * p[0].y;
+  }
+
+  int test0_0_4(int y) {
+    int x = 3;
+    Point p[] = new Point[1];
+    dummy();
+    p[0] = new Point();
+    dummy();
+    p[0].x = x;
+    p[0].y = 3 * x + y;
+    return p[0].x * p[0].y;
+  }
+
+  int test0_0_5(int y) {
+    int x = 3;
+    Point p[] = new Point[1];
+    dummy();
+    p[0] = null;
+    dummy();
+    p[0] = new Point();
+    dummy();
+    p[0].x = x;
+    p[0].y = 3 * x + y;
+    return p[0].x * p[0].y;
+  }
+
+  int test0_0_6(int y) {
+    int x = 3;
+    Point p[] = new Point[1];
+    p[0] = new Point();
+    dummy();
+    p[0] = new Point();
+    dummy();
+    p[0].x = x;
+    p[0].y = 3 * x + y;
+    return p[0].x * p[0].y;
+  }
+
+  int test0_1_3(int y) {
+    int x = 3;
+    Point p1 = new Point();
+    dummy();
+    Point p[] = new Point[1];
+    p[0] = p1;
+    dummy();
+    p[0].x = x;
+    p[0].y = 3 * x + y;
+    return p[0].x * p[0].y;
+  }
+
+  int test0_1_4(int y) {
+    int x = 3;
+    Point p1 = new Point();
+    dummy();
+    Point p[] = new Point[1];
+    dummy();
+    p[0] = p1;
+    dummy();
+    p[0].x = x;
+    p[0].y = 3 * x + y;
+    return p[0].x * p[0].y;
+  }
+
+  int test0_1_5(int y) {
+    int x = 3;
+    Point p1 = new Point();
+    dummy();
+    Point p[] = new Point[1];
+    dummy();
+    p[0] = null;
+    dummy();
+    p[0] = p1;
+    dummy();
+    p[0].x = x;
+    p[0].y = 3 * x + y;
+    return p[0].x * p[0].y;
+  }
+
+  int test0_1_6(int y) {
+    int x = 3;
+    Point p1 = new Point();
+    dummy();
+    Point p2 = new Point();
+    dummy();
+    Point p[] = new Point[1];
+    p[0] = p1;
+    dummy();
+    p[0] = p2;
+    dummy();
+    p[0].x = x;
+    p[0].y = 3 * x + y;
+    return p[0].x * p[0].y;
+  }
+
+  int test1_0_0(int y) {
+    Point p = new Point();
+    if ( (y & 1) == 1 ) {
+      p = new Point();
+    }
+    int x = 3;
+    p.x = x;
+    p.y = 3 * x + y;
+    dummy();
+    return p.x * p.y;
+  }
+
+  int test1_0_1(int y) {
+    Point p = null;
+    if ( (y & 1) == 1 ) {
+      p = new Point();
+    }
+    int x = 3;
+    if ( p == null )
+      return (3 * x + y) * x;
+    p.x = x;
+    p.y = 3 * x + y;
+    dummy();
+    return p.x * p.y;
+  }
+
+  int test1_0_2(int y) {
+    Point p[] = new Point[1];
+    if ( (y & 1) == 1 ) {
+      p[0] = new Point();
+    }
+    int x = 3;
+    if ( p[0] == null )
+      return (3 * x + y) * x;
+    p[0].x = x;
+    p[0].y = 3 * x + y;
+    dummy();
+    return p[0].x * p[0].y;
+  }
+
+  int test1_0_3(int y) {
+    Point p[] = new Point[1];
+    p[0] = null;
+    if ( (y & 1) == 1 ) {
+      p[0] = new Point();
+    }
+    int x = 3;
+    if ( p[0] == null )
+      return (3 * x + y) * x;
+    p[0].x = x;
+    p[0].y = 3 * x + y;
+    dummy();
+    return p[0].x * p[0].y;
+  }
+
+  int test1_0_4(int y) {
+    Point p[] = new Point[1];
+    p[0] = new Point();
+    if ( (y & 1) == 1 ) {
+      p[0] = new Point();
+    }
+    int x = 3;
+    if ( p[0] == null )
+      return (3 * x + y) * x;
+    p[0].x = x;
+    p[0].y = 3 * x + y;
+    dummy();
+    return p[0].x * p[0].y;
+  }
+
+  int test1_0_5(int y) {
+    Point p[] = new Point[1];
+    if ( (y & 1) == 1 ) {
+      p[0] = new Point();
+    } else {
+      p[0] = null;
+    }
+    int x = 3;
+    if ( p[0] == null )
+      return (3 * x + y) * x;
+    p[0].x = x;
+    p[0].y = 3 * x + y;
+    dummy();
+    return p[0].x * p[0].y;
+  }
+
+  int test1_0_6(int y) {
+    Point p[] = new Point[1];
+    if ( (y & 1) == 1 ) {
+      p[0] = new Point();
+    } else {
+      p[0] = new Point();
+    }
+    int x = 3;
+    if ( p[0] == null )
+      return (3 * x + y) * x;
+    p[0].x = x;
+    p[0].y = 3 * x + y;
+    dummy();
+    return p[0].x * p[0].y;
+  }
+
+  int test1_1_0(int y) {
+    Point p = new Point();
+    if ( (y & 1) == 1 ) {
+      dummy();
+      p = new Point();
+      dummy();
+    }
+    int x = 3;
+    p.x = x;
+    p.y = 3 * x + y;
+    dummy();
+    return p.x * p.y;
+  }
+
+  int test1_1_1(int y) {
+    Point p = null;
+    if ( (y & 1) == 1 ) {
+      dummy();
+      p = new Point();
+      dummy();
+    }
+    int x = 3;
+    if ( p == null )
+      return (3 * x + y) * x;
+    p.x = x;
+    p.y = 3 * x + y;
+    dummy();
+    return p.x * p.y;
+  }
+
+  int test1_1_2(int y) {
+    Point p[] = new Point[1];
+    if ( (y & 1) == 1 ) {
+      dummy();
+      p[0] = new Point();
+      dummy();
+    }
+    int x = 3;
+    if ( p[0] == null )
+      return (3 * x + y) * x;
+    p[0].x = x;
+    p[0].y = 3 * x + y;
+    dummy();
+    return p[0].x * p[0].y;
+  }
+
+  int test1_1_3(int y) {
+    Point p[] = new Point[1];
+    dummy();
+    p[0] = null;
+    if ( (y & 1) == 1 ) {
+      dummy();
+      p[0] = new Point();
+      dummy();
+    }
+    int x = 3;
+    if ( p[0] == null )
+      return (3 * x + y) * x;
+    p[0].x = x;
+    p[0].y = 3 * x + y;
+    dummy();
+    return p[0].x * p[0].y;
+  }
+
+  int test1_1_4(int y) {
+    Point p[] = new Point[1];
+    dummy();
+    p[0] = new Point();
+    if ( (y & 1) == 1 ) {
+      dummy();
+      p[0] = new Point();
+      dummy();
+    }
+    int x = 3;
+    if ( p[0] == null )
+      return (3 * x + y) * x;
+    p[0].x = x;
+    p[0].y = 3 * x + y;
+    dummy();
+    return p[0].x * p[0].y;
+  }
+
+  int test1_1_5(int y) {
+    Point p[] = new Point[1];
+    if ( (y & 1) == 1 ) {
+      dummy();
+      p[0] = new Point();
+      dummy();
+    } else {
+      dummy();
+      p[0] = null;
+      dummy();
+    }
+    int x = 3;
+    if ( p[0] == null )
+      return (3 * x + y) * x;
+    p[0].x = x;
+    p[0].y = 3 * x + y;
+    dummy();
+    return p[0].x * p[0].y;
+  }
+
+  int test1_1_6(int y) {
+    Point p[] = new Point[1];
+    if ( (y & 1) == 1 ) {
+      dummy();
+      p[0] = new Point();
+      dummy();
+    } else {
+      dummy();
+      p[0] = new Point();
+      dummy();
+    }
+    int x = 3;
+    if ( p[0] == null )
+      return (3 * x + y) * x;
+    p[0].x = x;
+    p[0].y = 3 * x + y;
+    dummy();
+    return p[0].x * p[0].y;
+  }
+
+  int test1_2_0(int y) {
+    Point p1 = new Point();
+    dummy();
+    Point p = new Point();
+    if ( (y & 1) == 1 ) {
+      dummy();
+      p = p1;
+      dummy();
+    }
+    int x = 3;
+    p.x = x;
+    p.y = 3 * x + y;
+    dummy();
+    return p.x * p.y;
+  }
+
+  int test1_2_1(int y) {
+    Point p1 = new Point();
+    dummy();
+    Point p = null;
+    if ( (y & 1) == 1 ) {
+      dummy();
+      p = p1;
+      dummy();
+    }
+    int x = 3;
+    if ( p == null )
+      return (3 * x + y) * x;
+    p.x = x;
+    p.y = 3 * x + y;
+    dummy();
+    return p.x * p.y;
+  }
+
+  int test1_2_2(int y) {
+    Point p1 = new Point();
+    dummy();
+    Point p[] = new Point[1];
+    if ( (y & 1) == 1 ) {
+      dummy();
+      p[0] = p1;
+      dummy();
+    }
+    int x = 3;
+    if ( p[0] == null )
+      return (3 * x + y) * x;
+    p[0].x = x;
+    p[0].y = 3 * x + y;
+    dummy();
+    return p[0].x * p[0].y;
+  }
+
+  int test1_2_3(int y) {
+    Point p1 = new Point();
+    dummy();
+    Point p[] = new Point[1];
+    dummy();
+    p[0] = null;
+    if ( (y & 1) == 1 ) {
+      dummy();
+      p[0] = p1;
+      dummy();
+    }
+    int x = 3;
+    if ( p[0] == null )
+      return (3 * x + y) * x;
+    p[0].x = x;
+    p[0].y = 3 * x + y;
+    dummy();
+    return p[0].x * p[0].y;
+  }
+
+  int test1_2_4(int y) {
+    Point p1 = new Point();
+    dummy();
+    Point p2 = new Point();
+    dummy();
+    Point p[] = new Point[1];
+    dummy();
+    p[0] = p1;
+    if ( (y & 1) == 1 ) {
+      dummy();
+      p[0] = p2;
+      dummy();
+    }
+    int x = 3;
+    if ( p[0] == null )
+      return (3 * x + y) * x;
+    p[0].x = x;
+    p[0].y = 3 * x + y;
+    dummy();
+    return p[0].x * p[0].y;
+  }
+
+  int test1_2_5(int y) {
+    Point p1 = new Point();
+    dummy();
+    Point p[] = new Point[1];
+    if ( (y & 1) == 1 ) {
+      dummy();
+      p[0] = p1;
+      dummy();
+    } else {
+      dummy();
+      p[0] = null;
+      dummy();
+    }
+    int x = 3;
+    if ( p[0] == null )
+      return (3 * x + y) * x;
+    p[0].x = x;
+    p[0].y = 3 * x + y;
+    dummy();
+    return p[0].x * p[0].y;
+  }
+
+  int test1_2_6(int y) {
+    Point p1 = new Point();
+    dummy();
+    Point p2 = new Point();
+    dummy();
+    Point p[] = new Point[1];
+    if ( (y & 1) == 1 ) {
+      dummy();
+      p[0] = p1;
+      dummy();
+    } else {
+      dummy();
+      p[0] = p2;
+      dummy();
+    }
+    int x = 3;
+    if ( p[0] == null )
+      return (3 * x + y) * x;
+    p[0].x = x;
+    p[0].y = 3 * x + y;
+    dummy();
+    return p[0].x * p[0].y;
+  }
+
+  int test2_0_0(int y) {
+    Point p = new Point();
+    int lim = (y & 3);
+    for (int i = 0; i < lim; i++) {
+      p = new Point();
+    }
+    int x = 3;
+    p.x = x;
+    p.y = 3 * x + y;
+    dummy();
+    return p.x * p.y;
+  }
+
+  int test2_0_1(int y) {
+    Point p = null;
+    int lim = (y & 3);
+    for (int i = 0; i < lim; i++) {
+      p = new Point();
+    }
+    int x = 3;
+    if ( p == null )
+      return (3 * x + y) * x;
+    p.x = x;
+    p.y = 3 * x + y;
+    dummy();
+    return p.x * p.y;
+  }
+
+  int test2_0_2(int y) {
+    Point p[] = new Point[3];
+    int lim = (y & 3);
+    for (int i = 0; i < lim; i++) {
+      p[i] = new Point();
+    }
+    int x = 3;
+    int j = (y & 1);
+    if ( p[j] == null )
+      return (3 * x + y) * x;
+    p[j].x = x;
+    p[j].y = 3 * x + y;
+    dummy();
+    return p[j].x * p[0].y;
+  }
+
+  int test2_0_3(int y) {
+    Point p[] = new Point[3];
+    int j = (y & 1);
+    p[j] = null;
+    int lim = (y & 3);
+    for (int i = 0; i < lim; i++) {
+      p[i] = new Point();
+    }
+    int x = 3;
+    if ( p[j] == null )
+      return (3 * x + y) * x;
+    p[j].x = x;
+    p[j].y = 3 * x + y;
+    dummy();
+    return p[j].x * p[0].y;
+  }
+
+  int test2_0_4(int y) {
+    Point p[] = new Point[3];
+    int j = (y & 1);
+    p[j] = new Point();
+    int lim = (y & 3);
+    for (int i = 0; i < lim; i++) {
+      p[i] = new Point();
+    }
+    int x = 3;
+    if ( p[j] == null )
+      return (3 * x + y) * x;
+    p[j].x = x;
+    p[j].y = 3 * x + y;
+    dummy();
+    return p[j].x * p[0].y;
+  }
+
+  int test2_0_5(int y) {
+    Point p[] = new Point[3];
+    int lim = (y & 3);
+    for (int i = 0; i < lim; i++) {
+      p[i] = new Point();
+    }
+    for (int i = 0; i < lim; i++) {
+      p[i] = null;
+    }
+    int x = 3;
+    int j = (y & 1);
+    if ( p[j] == null )
+      return (3 * x + y) * x;
+    p[j].x = x;
+    p[j].y = 3 * x + y;
+    dummy();
+    return p[j].x * p[0].y;
+  }
+
+  int test2_0_6(int y) {
+    Point p[] = new Point[3];
+    int lim = (y & 3);
+    for (int i = 0; i < lim; i++) {
+      p[i] = new Point();
+    }
+    for (int i = 0; i < lim; i++) {
+      p[i] = new Point();
+    }
+    int x = 3;
+    int j = (y & 1);
+    if ( p[j] == null )
+      return (3 * x + y) * x;
+    p[j].x = x;
+    p[j].y = 3 * x + y;
+    dummy();
+    return p[j].x * p[0].y;
+  }
+
+  int test2_1_0(int y) {
+    Point p = new Point();
+    int lim = (y & 3);
+    for (int i = 0; i < lim; i++) {
+      dummy();
+      p = new Point();
+      dummy();
+    }
+    int x = 3;
+    p.x = x;
+    p.y = 3 * x + y;
+    dummy();
+    return p.x * p.y;
+  }
+
+  int test2_1_1(int y) {
+    Point p = null;
+    int lim = (y & 3);
+    for (int i = 0; i < lim; i++) {
+      dummy();
+      p = new Point();
+      dummy();
+    }
+    int x = 3;
+    if ( p == null )
+      return (3 * x + y) * x;
+    p.x = x;
+    p.y = 3 * x + y;
+    dummy();
+    return p.x * p.y;
+  }
+
+  int test2_1_2(int y) {
+    Point p[] = new Point[3];
+    int lim = (y & 3);
+    for (int i = 0; i < lim; i++) {
+      dummy();
+      p[i] = new Point();
+      dummy();
+    }
+    int x = 3;
+    int j = (y & 1);
+    if ( p[j] == null )
+      return (3 * x + y) * x;
+    p[j].x = x;
+    p[j].y = 3 * x + y;
+    dummy();
+    return p[j].x * p[0].y;
+  }
+
+  int test2_1_3(int y) {
+    Point p[] = new Point[3];
+    dummy();
+    int j = (y & 1);
+    p[j] = null;
+    int lim = (y & 3);
+    for (int i = 0; i < lim; i++) {
+      dummy();
+      p[i] = new Point();
+      dummy();
+    }
+    int x = 3;
+    if ( p[j] == null )
+      return (3 * x + y) * x;
+    p[j].x = x;
+    p[j].y = 3 * x + y;
+    dummy();
+    return p[j].x * p[0].y;
+  }
+
+  int test2_1_4(int y) {
+    Point p[] = new Point[3];
+    dummy();
+    int j = (y & 1);
+    p[j] = new Point();
+    int lim = (y & 3);
+    for (int i = 0; i < lim; i++) {
+      dummy();
+      p[i] = new Point();
+      dummy();
+    }
+    int x = 3;
+    if ( p[j] == null )
+      return (3 * x + y) * x;
+    p[j].x = x;
+    p[j].y = 3 * x + y;
+    dummy();
+    return p[j].x * p[0].y;
+  }
+
+  int test2_1_5(int y) {
+    Point p[] = new Point[3];
+    int lim = (y & 3);
+    for (int i = 0; i < lim; i++) {
+      dummy();
+      p[i] = new Point();
+      dummy();
+    }
+    for (int i = 0; i < lim; i++) {
+      dummy();
+      p[i] = null;
+      dummy();
+    }
+    int x = 3;
+    int j = (y & 1);
+    if ( p[j] == null )
+      return (3 * x + y) * x;
+    p[j].x = x;
+    p[j].y = 3 * x + y;
+    dummy();
+    return p[j].x * p[0].y;
+  }
+
+  int test2_1_6(int y) {
+    Point p[] = new Point[3];
+    int lim = (y & 3);
+    for (int i = 0; i < lim; i++) {
+      dummy();
+      p[i] = new Point();
+      dummy();
+    }
+    for (int i = 0; i < lim; i++) {
+      dummy();
+      p[i] = new Point();
+      dummy();
+    }
+    int x = 3;
+    int j = (y & 1);
+    if ( p[j] == null )
+      return (3 * x + y) * x;
+    p[j].x = x;
+    p[j].y = 3 * x + y;
+    dummy();
+    return p[j].x * p[0].y;
+  }
+
+  int test2_2_0(int y) {
+    Point p1 = new Point();
+    dummy();
+    Point p = new Point();
+    int lim = (y & 3);
+    for (int i = 0; i < lim; i++) {
+      dummy();
+      p = p1;
+      dummy();
+    }
+    int x = 3;
+    p.x = x;
+    p.y = 3 * x + y;
+    dummy();
+    return p.x * p.y;
+  }
+
+  int test2_2_1(int y) {
+    Point p1 = new Point();
+    dummy();
+    Point p = null;
+    int lim = (y & 3);
+    for (int i = 0; i < lim; i++) {
+      dummy();
+      p = p1;
+      dummy();
+    }
+    int x = 3;
+    if ( p == null )
+      return (3 * x + y) * x;
+    p.x = x;
+    p.y = 3 * x + y;
+    dummy();
+    return p.x * p.y;
+  }
+
+  int test2_2_2(int y) {
+    Point p1 = new Point();
+    dummy();
+    Point p[] = new Point[3];
+    int lim = (y & 3);
+    for (int i = 0; i < lim; i++) {
+      dummy();
+      p[i] = p1;
+      dummy();
+    }
+    int x = 3;
+    int j = (y & 1);
+    if ( p[j] == null )
+      return (3 * x + y) * x;
+    p[j].x = x;
+    p[j].y = 3 * x + y;
+    dummy();
+    return p[j].x * p[0].y;
+  }
+
+  int test2_2_3(int y) {
+    Point p1 = new Point();
+    dummy();
+    Point p[] = new Point[3];
+    dummy();
+    int j = (y & 1);
+    p[j] = null;
+    int lim = (y & 3);
+    for (int i = 0; i < lim; i++) {
+      dummy();
+      p[i] = p1;
+      dummy();
+    }
+    int x = 3;
+    if ( p[j] == null )
+      return (3 * x + y) * x;
+    p[j].x = x;
+    p[j].y = 3 * x + y;
+    dummy();
+    return p[j].x * p[0].y;
+  }
+
+  int test2_2_4(int y) {
+    Point p1 = new Point();
+    dummy();
+    Point p2 = new Point();
+    dummy();
+    Point p[] = new Point[3];
+    dummy();
+    int j = (y & 1);
+    p[j] = p1;
+    int lim = (y & 3);
+    for (int i = 0; i < lim; i++) {
+      dummy();
+      p[i] = p2;
+      dummy();
+    }
+    int x = 3;
+    if ( p[j] == null )
+      return (3 * x + y) * x;
+    p[j].x = x;
+    p[j].y = 3 * x + y;
+    dummy();
+    return p[j].x * p[0].y;
+  }
+
+  int test2_2_5(int y) {
+    Point p1 = new Point();
+    dummy();
+    Point p[] = new Point[3];
+    int lim = (y & 3);
+    for (int i = 0; i < lim; i++) {
+      dummy();
+      p[i] = p1;
+      dummy();
+    }
+    for (int i = 0; i < lim; i++) {
+      dummy();
+      p[i] = null;
+      dummy();
+    }
+    int x = 3;
+    int j = (y & 1);
+    if ( p[j] == null )
+      return (3 * x + y) * x;
+    p[j].x = x;
+    p[j].y = 3 * x + y;
+    dummy();
+    return p[j].x * p[0].y;
+  }
+
+  int test2_2_6(int y) {
+    Point p1 = new Point();
+    dummy();
+    Point p2 = new Point();
+    dummy();
+    Point p[] = new Point[3];
+    int lim = (y & 3);
+    for (int i = 0; i < lim; i++) {
+      dummy();
+      p[i] = p1;
+      dummy();
+    }
+    for (int i = 0; i < lim; i++) {
+      dummy();
+      p[i] = p2;
+      dummy();
+    }
+    int x = 3;
+    int j = (y & 1);
+    if ( p[j] == null )
+      return (3 * x + y) * x;
+    p[j].x = x;
+    p[j].y = 3 * x + y;
+    dummy();
+    return p[j].x * p[0].y;
+  }
+
+  public static void main(String args[]) {
+    Test tsr    = new Test();
+    Point p     = new Point();
+    Point ptmp  = p;
+    Class cls   = Point.class;
+    int y = 0;
+    for (int i=0; i<10000; i++) {
+      y = tsr.test0_0_0(y);
+      y = tsr.test0_0_0(y);
+      y = tsr.test0_0_1(y);
+      y = tsr.test0_0_1(y);
+      y = tsr.test0_0_2(y);
+      y = tsr.test0_0_2(y);
+      y = tsr.test0_0_3(y);
+      y = tsr.test0_0_3(y);
+      y = tsr.test0_0_4(y);
+      y = tsr.test0_0_4(y);
+      y = tsr.test0_0_5(y);
+      y = tsr.test0_0_5(y);
+      y = tsr.test0_0_6(y);
+      y = tsr.test0_0_6(y);
+
+      y = tsr.test0_1_3(y);
+      y = tsr.test0_1_3(y);
+      y = tsr.test0_1_4(y);
+      y = tsr.test0_1_4(y);
+      y = tsr.test0_1_5(y);
+      y = tsr.test0_1_5(y);
+      y = tsr.test0_1_6(y);
+      y = tsr.test0_1_6(y);
+
+      y = tsr.test1_0_0(y&~1);
+      y = tsr.test1_0_1(y&~1);
+      y = tsr.test1_0_2(y&~1);
+      y = tsr.test1_0_3(y&~1);
+      y = tsr.test1_0_4(y&~1);
+      y = tsr.test1_0_5(y&~1);
+      y = tsr.test1_0_6(y&~1);
+      y = tsr.test1_0_0((y&~1)+1);
+      y = tsr.test1_0_1((y&~1)+1);
+      y = tsr.test1_0_2((y&~1)+1);
+      y = tsr.test1_0_3((y&~1)+1);
+      y = tsr.test1_0_4((y&~1)+1);
+      y = tsr.test1_0_5((y&~1)+1);
+      y = tsr.test1_0_6((y&~1)+1);
+
+      y = tsr.test1_1_0(y&~1);
+      y = tsr.test1_1_1(y&~1);
+      y = tsr.test1_1_2(y&~1);
+      y = tsr.test1_1_3(y&~1);
+      y = tsr.test1_1_4(y&~1);
+      y = tsr.test1_1_5(y&~1);
+      y = tsr.test1_1_6(y&~1);
+      y = tsr.test1_1_0((y&~1)+1);
+      y = tsr.test1_1_1((y&~1)+1);
+      y = tsr.test1_1_2((y&~1)+1);
+      y = tsr.test1_1_3((y&~1)+1);
+      y = tsr.test1_1_4((y&~1)+1);
+      y = tsr.test1_1_5((y&~1)+1);
+      y = tsr.test1_1_6((y&~1)+1);
+
+      y = tsr.test1_2_0(y&~1);
+      y = tsr.test1_2_1(y&~1);
+      y = tsr.test1_2_2(y&~1);
+      y = tsr.test1_2_3(y&~1);
+      y = tsr.test1_2_4(y&~1);
+      y = tsr.test1_2_5(y&~1);
+      y = tsr.test1_2_6(y&~1);
+      y = tsr.test1_2_0((y&~1)+1);
+      y = tsr.test1_2_1((y&~1)+1);
+      y = tsr.test1_2_2((y&~1)+1);
+      y = tsr.test1_2_3((y&~1)+1);
+      y = tsr.test1_2_4((y&~1)+1);
+      y = tsr.test1_2_5((y&~1)+1);
+      y = tsr.test1_2_6((y&~1)+1);
+
+      y = tsr.test2_0_0(y&~3);
+      y = tsr.test2_0_1(y&~3);
+      y = tsr.test2_0_2(y&~3);
+      y = tsr.test2_0_3(y&~3);
+      y = tsr.test2_0_4(y&~3);
+      y = tsr.test2_0_5(y&~3);
+      y = tsr.test2_0_6(y&~3);
+      y = tsr.test2_0_0((y&~3)+3);
+      y = tsr.test2_0_1((y&~3)+3);
+      y = tsr.test2_0_2((y&~3)+3);
+      y = tsr.test2_0_3((y&~3)+3);
+      y = tsr.test2_0_4((y&~3)+3);
+      y = tsr.test2_0_5((y&~3)+3);
+      y = tsr.test2_0_6((y&~3)+3);
+
+      y = tsr.test2_1_0(y&~3);
+      y = tsr.test2_1_1(y&~3);
+      y = tsr.test2_1_2(y&~3);
+      y = tsr.test2_1_3(y&~3);
+      y = tsr.test2_1_4(y&~3);
+      y = tsr.test2_1_5(y&~3);
+      y = tsr.test2_1_6(y&~3);
+      y = tsr.test2_1_0((y&~3)+3);
+      y = tsr.test2_1_1((y&~3)+3);
+      y = tsr.test2_1_2((y&~3)+3);
+      y = tsr.test2_1_3((y&~3)+3);
+      y = tsr.test2_1_4((y&~3)+3);
+      y = tsr.test2_1_5((y&~3)+3);
+      y = tsr.test2_1_6((y&~3)+3);
+
+      y = tsr.test2_2_0(y&~3);
+      y = tsr.test2_2_1(y&~3);
+      y = tsr.test2_2_2(y&~3);
+      y = tsr.test2_2_3(y&~3);
+      y = tsr.test2_2_4(y&~3);
+      y = tsr.test2_2_5(y&~3);
+      y = tsr.test2_2_6(y&~3);
+      y = tsr.test2_2_0((y&~3)+3);
+      y = tsr.test2_2_1((y&~3)+3);
+      y = tsr.test2_2_2((y&~3)+3);
+      y = tsr.test2_2_3((y&~3)+3);
+      y = tsr.test2_2_4((y&~3)+3);
+      y = tsr.test2_2_5((y&~3)+3);
+      y = tsr.test2_2_6((y&~3)+3);
+
+    }
+    for (int i=0; i<10000; i++) {
+      y = tsr.test0_0_0(y);
+      y = tsr.test0_0_0(y);
+      y = tsr.test0_0_1(y);
+      y = tsr.test0_0_1(y);
+      y = tsr.test0_0_2(y);
+      y = tsr.test0_0_2(y);
+      y = tsr.test0_0_3(y);
+      y = tsr.test0_0_3(y);
+      y = tsr.test0_0_4(y);
+      y = tsr.test0_0_4(y);
+      y = tsr.test0_0_5(y);
+      y = tsr.test0_0_5(y);
+      y = tsr.test0_0_6(y);
+      y = tsr.test0_0_6(y);
+
+      y = tsr.test0_1_3(y);
+      y = tsr.test0_1_3(y);
+      y = tsr.test0_1_4(y);
+      y = tsr.test0_1_4(y);
+      y = tsr.test0_1_5(y);
+      y = tsr.test0_1_5(y);
+      y = tsr.test0_1_6(y);
+      y = tsr.test0_1_6(y);
+
+      y = tsr.test1_0_0(y&~1);
+      y = tsr.test1_0_1(y&~1);
+      y = tsr.test1_0_2(y&~1);
+      y = tsr.test1_0_3(y&~1);
+      y = tsr.test1_0_4(y&~1);
+      y = tsr.test1_0_5(y&~1);
+      y = tsr.test1_0_6(y&~1);
+      y = tsr.test1_0_0((y&~1)+1);
+      y = tsr.test1_0_1((y&~1)+1);
+      y = tsr.test1_0_2((y&~1)+1);
+      y = tsr.test1_0_3((y&~1)+1);
+      y = tsr.test1_0_4((y&~1)+1);
+      y = tsr.test1_0_5((y&~1)+1);
+      y = tsr.test1_0_6((y&~1)+1);
+
+      y = tsr.test1_1_0(y&~1);
+      y = tsr.test1_1_1(y&~1);
+      y = tsr.test1_1_2(y&~1);
+      y = tsr.test1_1_3(y&~1);
+      y = tsr.test1_1_4(y&~1);
+      y = tsr.test1_1_5(y&~1);
+      y = tsr.test1_1_6(y&~1);
+      y = tsr.test1_1_0((y&~1)+1);
+      y = tsr.test1_1_1((y&~1)+1);
+      y = tsr.test1_1_2((y&~1)+1);
+      y = tsr.test1_1_3((y&~1)+1);
+      y = tsr.test1_1_4((y&~1)+1);
+      y = tsr.test1_1_5((y&~1)+1);
+      y = tsr.test1_1_6((y&~1)+1);
+
+      y = tsr.test1_2_0(y&~1);
+      y = tsr.test1_2_1(y&~1);
+      y = tsr.test1_2_2(y&~1);
+      y = tsr.test1_2_3(y&~1);
+      y = tsr.test1_2_4(y&~1);
+      y = tsr.test1_2_5(y&~1);
+      y = tsr.test1_2_6(y&~1);
+      y = tsr.test1_2_0((y&~1)+1);
+      y = tsr.test1_2_1((y&~1)+1);
+      y = tsr.test1_2_2((y&~1)+1);
+      y = tsr.test1_2_3((y&~1)+1);
+      y = tsr.test1_2_4((y&~1)+1);
+      y = tsr.test1_2_5((y&~1)+1);
+      y = tsr.test1_2_6((y&~1)+1);
+
+      y = tsr.test2_0_0(y&~3);
+      y = tsr.test2_0_1(y&~3);
+      y = tsr.test2_0_2(y&~3);
+      y = tsr.test2_0_3(y&~3);
+      y = tsr.test2_0_4(y&~3);
+      y = tsr.test2_0_5(y&~3);
+      y = tsr.test2_0_6(y&~3);
+      y = tsr.test2_0_0((y&~3)+3);
+      y = tsr.test2_0_1((y&~3)+3);
+      y = tsr.test2_0_2((y&~3)+3);
+      y = tsr.test2_0_3((y&~3)+3);
+      y = tsr.test2_0_4((y&~3)+3);
+      y = tsr.test2_0_5((y&~3)+3);
+      y = tsr.test2_0_6((y&~3)+3);
+
+      y = tsr.test2_1_0(y&~3);
+      y = tsr.test2_1_1(y&~3);
+      y = tsr.test2_1_2(y&~3);
+      y = tsr.test2_1_3(y&~3);
+      y = tsr.test2_1_4(y&~3);
+      y = tsr.test2_1_5(y&~3);
+      y = tsr.test2_1_6(y&~3);
+      y = tsr.test2_1_0((y&~3)+3);
+      y = tsr.test2_1_1((y&~3)+3);
+      y = tsr.test2_1_2((y&~3)+3);
+      y = tsr.test2_1_3((y&~3)+3);
+      y = tsr.test2_1_4((y&~3)+3);
+      y = tsr.test2_1_5((y&~3)+3);
+      y = tsr.test2_1_6((y&~3)+3);
+
+      y = tsr.test2_2_0(y&~3);
+      y = tsr.test2_2_1(y&~3);
+      y = tsr.test2_2_2(y&~3);
+      y = tsr.test2_2_3(y&~3);
+      y = tsr.test2_2_4(y&~3);
+      y = tsr.test2_2_5(y&~3);
+      y = tsr.test2_2_6(y&~3);
+      y = tsr.test2_2_0((y&~3)+3);
+      y = tsr.test2_2_1((y&~3)+3);
+      y = tsr.test2_2_2((y&~3)+3);
+      y = tsr.test2_2_3((y&~3)+3);
+      y = tsr.test2_2_4((y&~3)+3);
+      y = tsr.test2_2_5((y&~3)+3);
+      y = tsr.test2_2_6((y&~3)+3);
+
+    }
+    for (int i=0; i<10000; i++) {
+      y = tsr.test0_0_0(y);
+      y = tsr.test0_0_0(y);
+      y = tsr.test0_0_1(y);
+      y = tsr.test0_0_1(y);
+      y = tsr.test0_0_2(y);
+      y = tsr.test0_0_2(y);
+      y = tsr.test0_0_3(y);
+      y = tsr.test0_0_3(y);
+      y = tsr.test0_0_4(y);
+      y = tsr.test0_0_4(y);
+      y = tsr.test0_0_5(y);
+      y = tsr.test0_0_5(y);
+      y = tsr.test0_0_6(y);
+      y = tsr.test0_0_6(y);
+
+      y = tsr.test0_1_3(y);
+      y = tsr.test0_1_3(y);
+      y = tsr.test0_1_4(y);
+      y = tsr.test0_1_4(y);
+      y = tsr.test0_1_5(y);
+      y = tsr.test0_1_5(y);
+      y = tsr.test0_1_6(y);
+      y = tsr.test0_1_6(y);
+
+      y = tsr.test1_0_0(y&~1);
+      y = tsr.test1_0_1(y&~1);
+      y = tsr.test1_0_2(y&~1);
+      y = tsr.test1_0_3(y&~1);
+      y = tsr.test1_0_4(y&~1);
+      y = tsr.test1_0_5(y&~1);
+      y = tsr.test1_0_6(y&~1);
+      y = tsr.test1_0_0((y&~1)+1);
+      y = tsr.test1_0_1((y&~1)+1);
+      y = tsr.test1_0_2((y&~1)+1);
+      y = tsr.test1_0_3((y&~1)+1);
+      y = tsr.test1_0_4((y&~1)+1);
+      y = tsr.test1_0_5((y&~1)+1);
+      y = tsr.test1_0_6((y&~1)+1);
+
+      y = tsr.test1_1_0(y&~1);
+      y = tsr.test1_1_1(y&~1);
+      y = tsr.test1_1_2(y&~1);
+      y = tsr.test1_1_3(y&~1);
+      y = tsr.test1_1_4(y&~1);
+      y = tsr.test1_1_5(y&~1);
+      y = tsr.test1_1_6(y&~1);
+      y = tsr.test1_1_0((y&~1)+1);
+      y = tsr.test1_1_1((y&~1)+1);
+      y = tsr.test1_1_2((y&~1)+1);
+      y = tsr.test1_1_3((y&~1)+1);
+      y = tsr.test1_1_4((y&~1)+1);
+      y = tsr.test1_1_5((y&~1)+1);
+      y = tsr.test1_1_6((y&~1)+1);
+
+      y = tsr.test1_2_0(y&~1);
+      y = tsr.test1_2_1(y&~1);
+      y = tsr.test1_2_2(y&~1);
+      y = tsr.test1_2_3(y&~1);
+      y = tsr.test1_2_4(y&~1);
+      y = tsr.test1_2_5(y&~1);
+      y = tsr.test1_2_6(y&~1);
+      y = tsr.test1_2_0((y&~1)+1);
+      y = tsr.test1_2_1((y&~1)+1);
+      y = tsr.test1_2_2((y&~1)+1);
+      y = tsr.test1_2_3((y&~1)+1);
+      y = tsr.test1_2_4((y&~1)+1);
+      y = tsr.test1_2_5((y&~1)+1);
+      y = tsr.test1_2_6((y&~1)+1);
+
+      y = tsr.test2_0_0(y&~3);
+      y = tsr.test2_0_1(y&~3);
+      y = tsr.test2_0_2(y&~3);
+      y = tsr.test2_0_3(y&~3);
+      y = tsr.test2_0_4(y&~3);
+      y = tsr.test2_0_5(y&~3);
+      y = tsr.test2_0_6(y&~3);
+      y = tsr.test2_0_0((y&~3)+3);
+      y = tsr.test2_0_1((y&~3)+3);
+      y = tsr.test2_0_2((y&~3)+3);
+      y = tsr.test2_0_3((y&~3)+3);
+      y = tsr.test2_0_4((y&~3)+3);
+      y = tsr.test2_0_5((y&~3)+3);
+      y = tsr.test2_0_6((y&~3)+3);
+
+      y = tsr.test2_1_0(y&~3);
+      y = tsr.test2_1_1(y&~3);
+      y = tsr.test2_1_2(y&~3);
+      y = tsr.test2_1_3(y&~3);
+      y = tsr.test2_1_4(y&~3);
+      y = tsr.test2_1_5(y&~3);
+      y = tsr.test2_1_6(y&~3);
+      y = tsr.test2_1_0((y&~3)+3);
+      y = tsr.test2_1_1((y&~3)+3);
+      y = tsr.test2_1_2((y&~3)+3);
+      y = tsr.test2_1_3((y&~3)+3);
+      y = tsr.test2_1_4((y&~3)+3);
+      y = tsr.test2_1_5((y&~3)+3);
+      y = tsr.test2_1_6((y&~3)+3);
+
+      y = tsr.test2_2_0(y&~3);
+      y = tsr.test2_2_1(y&~3);
+      y = tsr.test2_2_2(y&~3);
+      y = tsr.test2_2_3(y&~3);
+      y = tsr.test2_2_4(y&~3);
+      y = tsr.test2_2_5(y&~3);
+      y = tsr.test2_2_6(y&~3);
+      y = tsr.test2_2_0((y&~3)+3);
+      y = tsr.test2_2_1((y&~3)+3);
+      y = tsr.test2_2_2((y&~3)+3);
+      y = tsr.test2_2_3((y&~3)+3);
+      y = tsr.test2_2_4((y&~3)+3);
+      y = tsr.test2_2_5((y&~3)+3);
+      y = tsr.test2_2_6((y&~3)+3);
+
+    }
+
+    int z = 0;
+    y = tsr.test0_0_0(0);
+    System.out.println("After 'test0_0_0' y=" + y);
+    y = tsr.test0_0_1(0);
+    System.out.println("After 'test0_0_1' y=" + y);
+    y = tsr.test0_0_2(0);
+    System.out.println("After 'test0_0_2' y=" + y);
+    y = tsr.test0_0_3(0);
+    System.out.println("After 'test0_0_3' y=" + y);
+    y = tsr.test0_0_4(0);
+    System.out.println("After 'test0_0_4' y=" + y);
+    y = tsr.test0_0_5(0);
+    System.out.println("After 'test0_0_5' y=" + y);
+    y = tsr.test0_0_6(0);
+    System.out.println("After 'test0_0_6' y=" + y);
+    y = tsr.test0_1_3(0);
+    System.out.println("After 'test0_1_3' y=" + y);
+    y = tsr.test0_1_4(0);
+    System.out.println("After 'test0_1_4' y=" + y);
+    y = tsr.test0_1_5(0);
+    System.out.println("After 'test0_1_5' y=" + y);
+    y = tsr.test0_1_6(0);
+    System.out.println("After 'test0_1_6' y=" + y);
+
+    y = tsr.test1_0_0(0);
+    System.out.println("After 'test1_0_0' y=" + y);
+    y = tsr.test1_0_1(0);
+    System.out.println("After 'test1_0_1' y=" + y);
+    y = tsr.test1_0_2(0);
+    System.out.println("After 'test1_0_2' y=" + y);
+    y = tsr.test1_0_3(0);
+    System.out.println("After 'test1_0_3' y=" + y);
+    y = tsr.test1_0_4(0);
+    System.out.println("After 'test1_0_4' y=" + y);
+    y = tsr.test1_0_5(0);
+    System.out.println("After 'test1_0_5' y=" + y);
+    y = tsr.test1_0_6(0);
+    System.out.println("After 'test1_0_6' y=" + y);
+
+    y = tsr.test1_1_0(0);
+    System.out.println("After 'test1_1_0' y=" + y);
+    y = tsr.test1_1_1(0);
+    System.out.println("After 'test1_1_1' y=" + y);
+    y = tsr.test1_1_2(0);
+    System.out.println("After 'test1_1_2' y=" + y);
+    y = tsr.test1_1_3(0);
+    System.out.println("After 'test1_1_3' y=" + y);
+    y = tsr.test1_1_4(0);
+    System.out.println("After 'test1_1_4' y=" + y);
+    y = tsr.test1_1_5(0);
+    System.out.println("After 'test1_1_5' y=" + y);
+    y = tsr.test1_1_6(0);
+    System.out.println("After 'test1_1_6' y=" + y);
+
+    y = tsr.test1_2_0(0);
+    System.out.println("After 'test1_2_0' y=" + y);
+    y = tsr.test1_2_1(0);
+    System.out.println("After 'test1_2_1' y=" + y);
+    y = tsr.test1_2_2(0);
+    System.out.println("After 'test1_2_2' y=" + y);
+    y = tsr.test1_2_3(0);
+    System.out.println("After 'test1_2_3' y=" + y);
+    y = tsr.test1_2_4(0);
+    System.out.println("After 'test1_2_4' y=" + y);
+    y = tsr.test1_2_5(0);
+    System.out.println("After 'test1_2_5' y=" + y);
+    y = tsr.test1_2_6(0);
+    System.out.println("After 'test1_2_6' y=" + y);
+
+    y = tsr.test2_0_0(0);
+    System.out.println("After 'test2_0_0' y=" + y);
+    y = tsr.test2_0_1(0);
+    System.out.println("After 'test2_0_1' y=" + y);
+    y = tsr.test2_0_2(0);
+    System.out.println("After 'test2_0_2' y=" + y);
+    y = tsr.test2_0_3(0);
+    System.out.println("After 'test2_0_3' y=" + y);
+    y = tsr.test2_0_4(0);
+    System.out.println("After 'test2_0_4' y=" + y);
+    y = tsr.test2_0_5(0);
+    System.out.println("After 'test2_0_5' y=" + y);
+    y = tsr.test2_0_6(0);
+    System.out.println("After 'test2_0_6' y=" + y);
+
+    y = tsr.test2_1_0(0);
+    System.out.println("After 'test2_1_0' y=" + y);
+    y = tsr.test2_1_1(0);
+    System.out.println("After 'test2_1_1' y=" + y);
+    y = tsr.test2_1_2(0);
+    System.out.println("After 'test2_1_2' y=" + y);
+    y = tsr.test2_1_3(0);
+    System.out.println("After 'test2_1_3' y=" + y);
+    y = tsr.test2_1_4(0);
+    System.out.println("After 'test2_1_4' y=" + y);
+    y = tsr.test2_1_5(0);
+    System.out.println("After 'test2_1_5' y=" + y);
+    y = tsr.test2_1_6(0);
+    System.out.println("After 'test2_1_6' y=" + y);
+
+    y = tsr.test2_2_0(0);
+    System.out.println("After 'test2_2_0' y=" + y);
+    y = tsr.test2_2_1(0);
+    System.out.println("After 'test2_2_1' y=" + y);
+    y = tsr.test2_2_2(0);
+    System.out.println("After 'test2_2_2' y=" + y);
+    y = tsr.test2_2_3(0);
+    System.out.println("After 'test2_2_3' y=" + y);
+    y = tsr.test2_2_4(0);
+    System.out.println("After 'test2_2_4' y=" + y);
+    y = tsr.test2_2_5(0);
+    System.out.println("After 'test2_2_5' y=" + y);
+    y = tsr.test2_2_6(0);
+    System.out.println("After 'test2_2_6' y=" + y);
+
+  }
+}
--- a/jaxp/.hgtags	Thu Aug 14 22:17:02 2008 -0700
+++ b/jaxp/.hgtags	Wed Jul 05 16:40:29 2017 +0200
@@ -7,3 +7,4 @@
 2d94a238a1641d074e6032dcdceed461d6f85d6a jdk7-b30
 255d64ee287e926e8629dd80bc67690e65eeba30 jdk7-b31
 400a5ee432cc2db9031e06852ddde9264a192b48 jdk7-b32
+95375835527f0bf06124ce984266e2ad5de8a6dc jdk7-b33
--- a/jaxws/.hgtags	Thu Aug 14 22:17:02 2008 -0700
+++ b/jaxws/.hgtags	Wed Jul 05 16:40:29 2017 +0200
@@ -7,3 +7,4 @@
 7f2466f8cc7009702e548d1a763254f546024d7e jdk7-b30
 f978623825364a2ad9c6f51d02fc9424a8b0bc86 jdk7-b31
 e6daca2eced9d84b01255cabcfcc49164c26405e jdk7-b32
+6dcbcfb9551aaa2a80906c28ab48c9a8564e0e64 jdk7-b33
--- a/jdk/.hgtags	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/.hgtags	Wed Jul 05 16:40:29 2017 +0200
@@ -7,3 +7,4 @@
 b6d6877c1155621a175dccd12dc14c54f938fb8b jdk7-b30
 b7474b739d13bacd9972f88ac91f6350b7b0be12 jdk7-b31
 c51121419e30eac5f0fbbce45ff1711c4ce0de28 jdk7-b32
+fa4c0a6cdd25d97d4e6f5d7aa180bcbb0e0d56af jdk7-b33
--- a/jdk/make/common/shared/Defs-windows.gmk	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/make/common/shared/Defs-windows.gmk	Wed Jul 05 16:40:29 2017 +0200
@@ -539,6 +539,8 @@
   WSCRIPT  :=$(call FileExists,$(_WSCRIPT1),$(_WSCRIPT2))
 endif
 WSCRIPT:=$(call AltCheckSpaces,WSCRIPT)
+# batch mode no modal dialogs on errors, please.
+WSCRIPT += -B
 
 # CSCRIPT: path to cscript.exe (used in creating install bundles)
 ifdef ALT_CSCRIPT
@@ -561,6 +563,10 @@
   MSIVAL2    :=$(call FileExists,$(_MSIVAL2_1),$(_MSIVAL2_2))
 endif
 MSIVAL2:=$(call AltCheckSpaces,MSIVAL2)
+# suppress msival2 checks, as it hangs jprt builds
+ifdef SKIP_MSIVAL2
+  MSIVAL2    := $(ECHO)
+endif
 
 # LOGOCUB: path to cub file for (used in validating install msi files)
 ifdef ALT_LOGOCUB
--- a/jdk/make/docs/CORE_PKGS.gmk	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/make/docs/CORE_PKGS.gmk	Wed Jul 05 16:40:29 2017 +0200
@@ -155,6 +155,7 @@
   javax.lang.model.type                          \
   javax.lang.model.util                          \
   javax.management                               \
+  javax.management.event                         \
   javax.management.loading                       \
   javax.management.monitor                       \
   javax.management.relation                      \
--- a/jdk/make/jprt.properties	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/make/jprt.properties	Wed Jul 05 16:40:29 2017 +0200
@@ -55,6 +55,5 @@
 jprt.test.targets=*-*-*-jvm98
 
 # Directories needed to build
-jprt.bundle.src.dirs=make src
 jprt.bundle.exclude.src.dirs=build
 
--- a/jdk/make/netbeans/jconsole/build.properties	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/make/netbeans/jconsole/build.properties	Wed Jul 05 16:40:29 2017 +0200
@@ -44,3 +44,4 @@
 build.release = ${build.jdk.version}-opensource
 build.number = b00
 jconsole.version = ${build.release}-${user.name}-${build.number}
+jconsole.args = -debug
--- a/jdk/make/netbeans/jconsole/build.xml	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/make/netbeans/jconsole/build.xml	Wed Jul 05 16:40:29 2017 +0200
@@ -30,9 +30,9 @@
 -->
 
 <project name="jconsole" default="build" basedir=".">
-    
+
     <import file="../common/shared.xml"/>
-    
+
     <target name="-pre-compile">
         <copy
             file="${root}/src/share/classes/sun/tools/jconsole/Version-template.java"
@@ -42,7 +42,7 @@
             token="@@jconsole_version@@"
             value="${jconsole.version}"/>
     </target>
-    
+
     <target name="-post-compile">
         <mkdir dir="${dist.dir}/lib"/>
         <jar destfile="${dist.dir}/lib/jconsole.jar"
@@ -55,18 +55,19 @@
             </fileset>
         </jar>
     </target>
-    
+
     <target name="run" depends="-init,build">
         <property name="jvm.args" value=""/>
         <java classname="sun.tools.jconsole.JConsole"
               fork="true"
               classpath="${classes.dir}:${bootstrap.jdk}/lib/tools.jar">
             <jvmarg line="${jvm.args}"/>
+            <arg line="${jconsole.args}"/>
         </java>
     </target>
-    
+
     <target name="clean" depends="-init,shared.clean">
         <delete file="${dist.dir}/lib/jconsole.jar"/>
     </target>
-    
+
 </project>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/jmx/event/DaemonThreadFactory.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.jmx.event;
+
+import com.sun.jmx.remote.util.ClassLogger;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class DaemonThreadFactory implements ThreadFactory {
+    public DaemonThreadFactory(String nameTemplate) {
+        this(nameTemplate, null);
+    }
+
+    // nameTemplate should be a format with %d in it, which will be replaced
+    // by a sequence number of threads created by this factory.
+    public DaemonThreadFactory(String nameTemplate, ThreadGroup threadGroup) {
+        if (logger.debugOn()) {
+            logger.debug("DaemonThreadFactory",
+                    "Construct a new daemon factory: "+nameTemplate);
+        }
+
+        if (threadGroup == null) {
+            SecurityManager s = System.getSecurityManager();
+            threadGroup = (s != null) ? s.getThreadGroup() :
+                                  Thread.currentThread().getThreadGroup();
+        }
+
+        this.nameTemplate = nameTemplate;
+        this.threadGroup = threadGroup;
+    }
+
+    public Thread newThread(Runnable r) {
+        final String name =
+                String.format(nameTemplate, threadNumber.getAndIncrement());
+        Thread t = new Thread(threadGroup, r, name, 0);
+        t.setDaemon(true);
+        if (t.getPriority() != Thread.NORM_PRIORITY)
+            t.setPriority(Thread.NORM_PRIORITY);
+
+        if (logger.debugOn()) {
+            logger.debug("newThread",
+                    "Create a new daemon thread with the name "+t.getName());
+        }
+
+        return t;
+    }
+
+    private final String nameTemplate;
+    private final ThreadGroup threadGroup;
+    private final AtomicInteger threadNumber = new AtomicInteger(1);
+
+    private static final ClassLogger logger =
+        new ClassLogger("com.sun.jmx.event", "DaemonThreadFactory");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/jmx/event/EventBuffer.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,252 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.jmx.event;
+
+import com.sun.jmx.remote.util.ClassLogger;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import javax.management.remote.NotificationResult;
+import javax.management.remote.TargetedNotification;
+
+public class EventBuffer {
+
+    public EventBuffer() {
+        this(Integer.MAX_VALUE, null);
+    }
+
+    public EventBuffer(int capacity) {
+        this(capacity, new ArrayList<TargetedNotification>());
+    }
+
+    public EventBuffer(int capacity, final List<TargetedNotification> list) {
+        if (logger.traceOn()) {
+            logger.trace("EventBuffer", "New buffer with the capacity: "
+                    +capacity);
+        }
+        if (capacity < 1) {
+            throw new IllegalArgumentException(
+                    "The capacity must be bigger than 0");
+        }
+
+        if (list == null) {
+            throw new NullPointerException("Null list.");
+        }
+
+        this.capacity = capacity;
+        this.list = list;
+    }
+
+    public void add(TargetedNotification tn) {
+        if (logger.traceOn()) {
+            logger.trace("add", "Add one notif.");
+        }
+
+        synchronized(lock) {
+            if (list.size() == capacity) { // have to throw one
+                passed++;
+                list.remove(0);
+
+                if (logger.traceOn()) {
+                    logger.trace("add", "Over, remove the oldest one.");
+                }
+            }
+
+            list.add(tn);
+            lock.notify();
+        }
+    }
+
+    public void add(TargetedNotification[] tns) {
+        if (tns == null || tns.length == 0) {
+            return;
+        }
+
+        if (logger.traceOn()) {
+            logger.trace("add", "Add notifs: "+tns.length);
+        }
+
+        synchronized(lock) {
+            final int d = list.size() - capacity + tns.length;
+            if (d > 0) { // have to throw
+                passed += d;
+                if (logger.traceOn()) {
+                    logger.trace("add",
+                            "Over, remove the oldest: "+d);
+                }
+                if (tns.length <= capacity){
+                    list.subList(0, d).clear();
+                } else {
+                    list.clear();
+                    TargetedNotification[] tmp =
+                            new TargetedNotification[capacity];
+                    System.arraycopy(tns, tns.length-capacity, tmp, 0, capacity);
+                    tns = tmp;
+                }
+            }
+
+            Collections.addAll(list,tns);
+            lock.notify();
+        }
+    }
+
+    public NotificationResult fetchNotifications(long startSequenceNumber,
+            long timeout,
+            int maxNotifications) {
+        if (logger.traceOn()) {
+            logger.trace("fetchNotifications",
+                    "Being called: "
+                    +startSequenceNumber+" "
+                    +timeout+" "+maxNotifications);
+        }
+        if (startSequenceNumber < 0 ||
+                timeout < 0 ||
+                maxNotifications < 0) {
+            throw new IllegalArgumentException("Negative value.");
+        }
+
+        TargetedNotification[] tns = new TargetedNotification[0];
+        long earliest = startSequenceNumber < passed ?
+            passed : startSequenceNumber;
+        long next = earliest;
+
+        final long startTime = System.currentTimeMillis();
+        long toWait = timeout;
+        synchronized(lock) {
+            int toSkip = (int)(startSequenceNumber - passed);
+
+            // skip those before startSequenceNumber.
+            while (!closed && toSkip > 0) {
+                toWait = timeout - (System.currentTimeMillis() - startTime);
+                if (list.size() == 0) {
+                    if (toWait <= 0) {
+                        // the notification of startSequenceNumber
+                        // does not arrive yet.
+                        return new NotificationResult(startSequenceNumber,
+                                startSequenceNumber,
+                                new TargetedNotification[0]);
+                    }
+
+                    waiting(toWait);
+                    continue;
+                }
+
+                if (toSkip <= list.size()) {
+                    list.subList(0, toSkip).clear();
+                    passed += toSkip;
+
+                    break;
+                } else {
+                    passed += list.size();
+                    toSkip -= list.size();
+
+                    list.clear();
+                }
+            }
+
+            earliest = passed;
+
+            if (list.size() == 0) {
+                toWait = timeout - (System.currentTimeMillis() - startTime);
+
+                waiting(toWait);
+            }
+
+            if (list.size() == 0) {
+                tns = new TargetedNotification[0];
+            } else if (list.size() <= maxNotifications) {
+                tns = list.toArray(new TargetedNotification[0]);
+            } else {
+                tns = new TargetedNotification[maxNotifications];
+                for (int i=0; i<maxNotifications; i++) {
+                    tns[i] = list.get(i);
+                }
+            }
+
+            next = earliest + tns.length;
+        }
+
+        if (logger.traceOn()) {
+            logger.trace("fetchNotifications",
+                    "Return: "+earliest+" "+next+" "+tns.length);
+        }
+
+        return new NotificationResult(earliest, next, tns);
+    }
+
+    public int size() {
+        return list.size();
+    }
+
+    public void addLost(long nb) {
+        synchronized(lock) {
+            passed += nb;
+        }
+    }
+
+    public void close() {
+        if (logger.traceOn()) {
+            logger.trace("clear", "done");
+        }
+
+        synchronized(lock) {
+            list.clear();
+            closed = true;
+            lock.notifyAll();
+        }
+    }
+
+
+    // -------------------------------------------
+    // private classes
+    // -------------------------------------------
+    private void waiting(long timeout) {
+        final long startTime = System.currentTimeMillis();
+        long toWait = timeout;
+        synchronized(lock) {
+            while (!closed && list.size() == 0 && toWait > 0) {
+                try {
+                    lock.wait(toWait);
+
+                    toWait = timeout - (System.currentTimeMillis() - startTime);
+                } catch (InterruptedException ire) {
+                    logger.trace("waiting", ire);
+                    break;
+                }
+            }
+        }
+    }
+
+    private final int capacity;
+    private final List<TargetedNotification> list;
+    private boolean closed;
+
+    private long passed = 0;
+    private final int[] lock = new int[0];
+
+    private static final ClassLogger logger =
+            new ClassLogger("javax.management.event", "EventBuffer");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/jmx/event/EventClientFactory.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.jmx.event;
+
+import javax.management.event.*;
+
+/**
+ * Implemented by objects which are using an {@link EventClient} to
+ * subscribe for Notifications.
+ *
+ */
+public interface EventClientFactory {
+    /**
+     * Returns the {@code EventClient} that the object implementing this
+     * interface uses to subscribe for Notifications. This method returns
+     * {@code null} if no {@code EventClient} can be used - e.g. because
+     * the underlying server does not have any {@link EventDelegate}.
+     *
+     * @return an {@code EventClient} or {@code null}.
+     **/
+    public EventClient getEventClient();
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/jmx/event/EventConnection.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2002-2007 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.jmx.event;
+
+import java.io.IOException;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import javax.management.MBeanServerConnection;
+import javax.management.event.EventClient;
+import javax.management.event.EventClientDelegate;
+import javax.management.event.EventConsumer;
+import javax.management.event.NotificationManager;
+
+/**
+ * Override the methods related to the notification to use the
+ * Event service.
+ */
+public interface EventConnection extends MBeanServerConnection, EventConsumer {
+    public EventClient getEventClient();
+
+    public static class Factory {
+        public static EventConnection make(
+                final MBeanServerConnection mbsc,
+                final EventClient eventClient)
+                throws IOException {
+            if (!mbsc.isRegistered(EventClientDelegate.OBJECT_NAME)) {
+                throw new IOException(
+                        "The server does not support the event service.");
+            }
+            InvocationHandler ih = new InvocationHandler() {
+                public Object invoke(Object proxy, Method method, Object[] args)
+                        throws Throwable {
+                    Class<?> intf = method.getDeclaringClass();
+                    try {
+                        if (intf.isInstance(eventClient))
+                            return method.invoke(eventClient, args);
+                        else
+                            return method.invoke(mbsc, args);
+                    } catch (InvocationTargetException e) {
+                        throw e.getCause();
+                    }
+                }
+            };
+            // It is important to declare NotificationManager.class first
+            // in the array below, so that the relevant addNL and removeNL
+            // methods will show up with method.getDeclaringClass() as
+            // being from that interface and not MBeanServerConnection.
+            return (EventConnection) Proxy.newProxyInstance(
+                    NotificationManager.class.getClassLoader(),
+                    new Class<?>[] {
+                        NotificationManager.class, EventConnection.class,
+                    },
+                    ih);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/jmx/event/EventParams.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.jmx.event;
+
+import com.sun.jmx.mbeanserver.GetPropertyAction;
+import com.sun.jmx.remote.util.ClassLogger;
+import java.security.AccessController;
+import javax.management.event.EventClient;
+
+/**
+ *
+ * @author sjiang
+ */
+public class EventParams {
+    public static final String DEFAULT_LEASE_TIMEOUT =
+            "com.sun.event.lease.time";
+
+
+    @SuppressWarnings("cast") // cast for jdk 1.5
+    public static long getLeaseTimeout() {
+        long timeout = EventClient.DEFAULT_LEASE_TIMEOUT;
+        try {
+            final GetPropertyAction act =
+                  new GetPropertyAction(DEFAULT_LEASE_TIMEOUT);
+            final String s = (String)AccessController.doPrivileged(act);
+            if (s != null) {
+                timeout = Long.parseLong(s);
+            }
+        } catch (RuntimeException e) {
+            logger.fine("getLeaseTimeout", "exception getting property", e);
+        }
+
+        return timeout;
+    }
+
+    /** Creates a new instance of EventParams */
+    private EventParams() {
+    }
+
+    private static final ClassLogger logger =
+            new ClassLogger("javax.management.event", "EventParams");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/jmx/event/LeaseManager.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,146 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.jmx.event;
+
+import com.sun.jmx.remote.util.ClassLogger;
+import java.util.concurrent.Executors;
+import java.util.concurrent.FutureTask;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * <p>Manage a renewable lease.  The lease can be renewed indefinitely
+ * but if the lease runs to its current expiry date without being renewed
+ * then the expiry callback is invoked.  If the lease has already expired
+ * when renewal is attempted then the lease method returns zero.</p>
+ * @author sjiang
+ * @author emcmanus
+ */
+// The synchronization logic of this class is tricky to deal correctly with the
+// case where the lease expires at the same time as the |lease| or |stop| method
+// is called.  If the lease is active then the field |scheduled| represents
+// the expiry task; otherwise |scheduled| is null.  Renewing or stopping the
+// lease involves canceling this task and setting |scheduled| either to a new
+// task (to renew) or to null (to stop).
+//
+// Suppose the expiry task runs at the same time as the |lease| method is called.
+// If the task enters its synchronized block before the method starts, then
+// it will set |scheduled| to null and the method will return 0.  If the method
+// starts before the task enters its synchronized block, then the method will
+// cancel the task which will see that when it later enters the block.
+// Similar reasoning applies to the |stop| method.  It is not expected that
+// different threads will call |lease| or |stop| simultaneously, although the
+// logic should be correct then too.
+public class LeaseManager {
+    public LeaseManager(Runnable callback) {
+        this(callback, EventParams.getLeaseTimeout());
+    }
+
+    public LeaseManager(Runnable callback, long timeout) {
+        if (logger.traceOn()) {
+            logger.trace("LeaseManager", "new manager with lease: "+timeout);
+        }
+        if (callback == null) {
+            throw new NullPointerException("Null callback.");
+        }
+        if (timeout <= 0)
+            throw new IllegalArgumentException("Timeout must be positive: " + timeout);
+
+        this.callback = callback;
+        schedule(timeout);
+    }
+
+    /**
+     * <p>Renew the lease for the given time.  The new time can be shorter
+     * than the previous one, in which case the lease will expire earlier
+     * than it would have.</p>
+     *
+     * <p>Calling this method after the lease has expired will return zero
+     * immediately and have no other effect.</p>
+     *
+     * @param timeout the new lifetime.  If zero, the lease
+     * will expire immediately.
+     */
+    public synchronized long lease(long timeout) {
+        if (logger.traceOn()) {
+            logger.trace("lease", "new lease to: "+timeout);
+        }
+
+        if (timeout < 0)
+            throw new IllegalArgumentException("Negative lease: " + timeout);
+
+        if (scheduled == null)
+            return 0L;
+
+        scheduled.cancel(false);
+
+        if (logger.traceOn())
+            logger.trace("lease", "start lease: "+timeout);
+        schedule(timeout);
+
+        return timeout;
+    }
+
+    private class Expire implements Runnable {
+        ScheduledFuture<?> task;
+
+        public void run() {
+            synchronized (LeaseManager.this) {
+                if (task.isCancelled())
+                    return;
+                scheduled = null;
+            }
+            callback.run();
+        }
+    }
+
+    private synchronized void schedule(long timeout) {
+        Expire expire = new Expire();
+        scheduled = executor.schedule(expire, timeout, TimeUnit.MILLISECONDS);
+        expire.task = scheduled;
+    }
+
+    /**
+     * <p>Cancel the lease without calling the expiry callback.</p>
+     */
+    public synchronized void stop() {
+        logger.trace("stop", "canceling lease");
+        scheduled.cancel(false);
+        scheduled = null;
+    }
+
+    private final Runnable callback;
+    private ScheduledFuture scheduled;  // If null, the lease has expired.
+
+    private final ScheduledExecutorService executor
+            = Executors.newScheduledThreadPool(1,
+            new DaemonThreadFactory("LeaseManager"));
+
+    private static final ClassLogger logger =
+            new ClassLogger("javax.management.event", "LeaseManager");
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/jmx/event/LeaseRenewer.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.jmx.event;
+
+import com.sun.jmx.remote.util.ClassLogger;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+
+/**
+ *
+ * @author sjiang
+ */
+public class LeaseRenewer {
+    public LeaseRenewer(ScheduledExecutorService scheduler, Callable<Long> doRenew) {
+        if (logger.traceOn()) {
+            logger.trace("LeaseRenewer", "New LeaseRenewer.");
+        }
+
+        if (doRenew == null) {
+            throw new NullPointerException("Null job to call server.");
+        }
+
+        this.doRenew = doRenew;
+        nextRenewTime = System.currentTimeMillis();
+
+        this.scheduler = scheduler;
+        future = this.scheduler.schedule(myRenew, 0, TimeUnit.MILLISECONDS);
+    }
+
+    public void close() {
+        if (logger.traceOn()) {
+            logger.trace("close", "Close the lease.");
+        }
+
+        synchronized(lock) {
+            if (closed) {
+                return;
+            } else {
+                closed = true;
+            }
+        }
+
+        try {
+            future.cancel(false); // not interrupt if running
+        } catch (Exception e) {
+            // OK
+            if (logger.debugOn()) {
+                logger.debug("close", "Failed to cancel the leasing job.", e);
+            }
+        }
+    }
+
+    public boolean closed() {
+        synchronized(lock) {
+            return closed;
+        }
+    }
+
+    // ------------------------------
+    // private
+    // ------------------------------
+    private final Runnable myRenew = new Runnable() {
+        public void run() {
+            synchronized(lock) {
+                if (closed()) {
+                    return;
+                }
+            }
+
+            long next = nextRenewTime - System.currentTimeMillis();
+            if (next < MIN_MILLIS) {
+                try {
+                    if (logger.traceOn()) {
+                        logger.trace("myRenew-run", "");
+                    }
+                    next = doRenew.call().longValue();
+
+                } catch (Exception e) {
+                    logger.fine("myRenew-run", "Failed to renew lease", e);
+                    close();
+                }
+
+                if (next > 0 && next < Long.MAX_VALUE) {
+                    next = next/2;
+                    next = (next < MIN_MILLIS) ? MIN_MILLIS : next;
+                } else {
+                    close();
+                }
+            }
+
+            nextRenewTime = System.currentTimeMillis() + next;
+
+            if (logger.traceOn()) {
+                logger.trace("myRenew-run", "Next leasing: "+next);
+            }
+
+            synchronized(lock) {
+                if (!closed) {
+                    future = scheduler.schedule(this, next, TimeUnit.MILLISECONDS);
+                }
+            }
+        }
+    };
+
+    private final Callable<Long> doRenew;
+    private ScheduledFuture future;
+    private boolean closed = false;
+    private long nextRenewTime;
+
+    private final int[] lock = new int[0];
+
+    private final ScheduledExecutorService scheduler;
+
+    private static final long MIN_MILLIS = 50;
+
+    private static final ClassLogger logger =
+            new ClassLogger("javax.management.event", "LeaseRenewer");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/jmx/event/ReceiverBuffer.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.jmx.event;
+
+import com.sun.jmx.remote.util.ClassLogger;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import javax.management.remote.NotificationResult;
+import javax.management.remote.TargetedNotification;
+
+
+public class ReceiverBuffer {
+    public void addNotifs(NotificationResult nr) {
+        if (nr == null) {
+            return;
+        }
+
+        TargetedNotification[] tns = nr.getTargetedNotifications();
+
+        if (logger.traceOn()) {
+            logger.trace("addNotifs", "" + tns.length);
+        }
+
+        long impliedStart = nr.getEarliestSequenceNumber();
+        final long missed = impliedStart - start;
+        start = nr.getNextSequenceNumber();
+
+        if (missed > 0) {
+            if (logger.traceOn()) {
+                logger.trace("addNotifs",
+                        "lost: "+missed);
+            }
+
+            lost += missed;
+        }
+
+        Collections.addAll(notifList, nr.getTargetedNotifications());
+    }
+
+    public TargetedNotification[] removeNotifs() {
+        if (logger.traceOn()) {
+            logger.trace("removeNotifs", String.valueOf(notifList.size()));
+        }
+
+        if (notifList.size() == 0) {
+            return null;
+        }
+
+        TargetedNotification[] ret = notifList.toArray(
+                new TargetedNotification[]{});
+        notifList.clear();
+
+        return ret;
+    }
+
+    public int size() {
+        return notifList.size();
+    }
+
+    public int removeLost() {
+        int ret = lost;
+        lost = 0;
+        return ret;
+    }
+
+    private List<TargetedNotification> notifList
+            = new ArrayList<TargetedNotification>();
+    private long start = 0;
+    private int lost = 0;
+
+    private static final ClassLogger logger =
+            new ClassLogger("javax.management.event", "ReceiverBuffer");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/jmx/event/RepeatedSingletonJob.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.jmx.event;
+
+import com.sun.jmx.remote.util.ClassLogger;
+import java.util.concurrent.Executor;
+import java.util.concurrent.RejectedExecutionException;
+
+/**
+ * <p>A task that is repeatedly run by an Executor.  The task will be
+ * repeated as long as the {@link #isSuspended()} method returns true.  Once
+ * that method returns false, the task is no longer executed until someone
+ * calls {@link #resume()}.</p>
+ * @author sjiang
+ */
+public abstract class RepeatedSingletonJob implements Runnable {
+    public RepeatedSingletonJob(Executor executor) {
+        if (executor == null) {
+            throw new NullPointerException("Null executor!");
+        }
+
+        this.executor = executor;
+    }
+
+    public boolean isWorking() {
+        return working;
+    }
+
+    public void resume() {
+
+        synchronized(this) {
+            if (!working)  {
+                if (logger.traceOn()) {
+                    logger.trace("resume", "");
+                }
+                working = true;
+                execute();
+            }
+        }
+    }
+
+    public abstract void task();
+    public abstract boolean isSuspended();
+
+    public void run() {
+        if (logger.traceOn()) {
+            logger.trace("run", "execute the task");
+        }
+        try {
+            task();
+        } catch (Exception e) {
+            // A correct task() implementation should not throw exceptions.
+            // It may cause isSuspended() to start returning true, though.
+            logger.trace("run", "failed to execute the task", e);
+        }
+
+        synchronized(this) {
+            if (!isSuspended()) {
+                execute();
+            } else {
+                if (logger.traceOn()) {
+                    logger.trace("run", "suspend the task");
+                }
+                working = false;
+            }
+        }
+
+    }
+
+    private void execute() {
+        try {
+            executor.execute(this);
+        } catch (RejectedExecutionException e) {
+            logger.warning(
+                    "setEventReceiver", "Executor threw exception", e);
+            throw new RejectedExecutionException(
+                    "Executor.execute threw exception -" +
+                    "should not be possible", e);
+            // User-supplied Executor should not be configured in a way that
+            // might cause this exception, for example if it is shared between
+            // several client objects and doesn't have capacity for one job
+            // from each one.  CR 6732037 will add text to the spec explaining
+            // the problem.  The rethrown exception will propagate either out
+            // of resume() to user code, or out of run() to the Executor
+            // (which will probably ignore it).
+        }
+    }
+
+    private boolean working = false;
+    private final Executor executor;
+
+    private static final ClassLogger logger =
+            new ClassLogger("javax.management.event", "RepeatedSingletonJob");
+}
--- a/jdk/src/share/classes/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/src/share/classes/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java	Wed Jul 05 16:40:29 2017 +0200
@@ -453,11 +453,12 @@
         final ResourceContext context =
                 unregisterFromRepository(resource, instance, name);
 
-
-        if (instance instanceof MBeanRegistration)
-            postDeregisterInvoke((MBeanRegistration) instance);
-
-        context.done();
+        try {
+            if (instance instanceof MBeanRegistration)
+                postDeregisterInvoke(name,(MBeanRegistration) instance);
+        } finally {
+            context.done();
+        }
     }
 
     public ObjectInstance getObjectInstance(ObjectName name)
@@ -989,10 +990,12 @@
             registerFailed = false;
             registered = true;
         } finally {
-            postRegister(mbean, registered, registerFailed);
+            try {
+                postRegister(logicalName, mbean, registered, registerFailed);
+            } finally {
+                if (registered) context.done();
+            }
         }
-
-        context.done();
         return new ObjectInstance(logicalName, classname);
     }
 
@@ -1051,7 +1054,8 @@
     }
 
     private static void postRegister(
-            DynamicMBean mbean, boolean registrationDone, boolean registerFailed) {
+            ObjectName logicalName, DynamicMBean mbean,
+            boolean registrationDone, boolean registerFailed) {
 
         if (registerFailed && mbean instanceof DynamicMBean2)
             ((DynamicMBean2) mbean).registerFailed();
@@ -1059,11 +1063,19 @@
             if (mbean instanceof MBeanRegistration)
                 ((MBeanRegistration) mbean).postRegister(registrationDone);
         } catch (RuntimeException e) {
+            MBEANSERVER_LOGGER.fine("While registering MBean ["+logicalName+
+                    "]: " + "Exception thrown by postRegister: " +
+                    "rethrowing <"+e+">, but keeping the MBean registered");
             throw new RuntimeMBeanException(e,
-                      "RuntimeException thrown in postRegister method");
+                      "RuntimeException thrown in postRegister method: "+
+                      "rethrowing <"+e+">, but keeping the MBean registered");
         } catch (Error er) {
+            MBEANSERVER_LOGGER.fine("While registering MBean ["+logicalName+
+                    "]: " + "Error thrown by postRegister: " +
+                    "rethrowing <"+er+">, but keeping the MBean registered");
             throw new RuntimeErrorException(er,
-                      "Error thrown in postRegister method");
+                      "Error thrown in postRegister method: "+
+                      "rethrowing <"+er+">, but keeping the MBean registered");
         }
     }
 
@@ -1076,15 +1088,28 @@
         }
     }
 
-    private static void postDeregisterInvoke(MBeanRegistration moi) {
+    private static void postDeregisterInvoke(ObjectName mbean,
+            MBeanRegistration moi) {
         try {
             moi.postDeregister();
         } catch (RuntimeException e) {
+            MBEANSERVER_LOGGER.fine("While unregistering MBean ["+mbean+
+                    "]: " + "Exception thrown by postDeregister: " +
+                    "rethrowing <"+e+">, although the MBean is succesfully " +
+                    "unregistered");
             throw new RuntimeMBeanException(e,
-                         "RuntimeException thrown in postDeregister method");
+                      "RuntimeException thrown in postDeregister method: "+
+                      "rethrowing <"+e+
+                      ">, although the MBean is sucessfully unregistered");
         } catch (Error er) {
+            MBEANSERVER_LOGGER.fine("While unregistering MBean ["+mbean+
+                    "]: " + "Error thrown by postDeregister: " +
+                    "rethrowing <"+er+">, although the MBean is succesfully " +
+                    "unregistered");
             throw new RuntimeErrorException(er,
-                         "Error thrown in postDeregister method");
+                      "Error thrown in postDeregister method: "+
+                      "rethrowing <"+er+
+                      ">, although the MBean is sucessfully unregistered");
         }
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/jmx/interceptor/MBeanServerSupport.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,1341 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.jmx.interceptor;
+
+import com.sun.jmx.mbeanserver.Util;
+import java.io.ObjectInputStream;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.management.Attribute;
+import javax.management.AttributeList;
+import javax.management.AttributeNotFoundException;
+import javax.management.DynamicMBean;
+import javax.management.DynamicWrapperMBean;
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.InstanceNotFoundException;
+import javax.management.IntrospectionException;
+import javax.management.InvalidAttributeValueException;
+import javax.management.JMRuntimeException;
+import javax.management.ListenerNotFoundException;
+import javax.management.MBeanException;
+import javax.management.MBeanInfo;
+import javax.management.MBeanRegistrationException;
+import javax.management.MBeanServer;
+import javax.management.MalformedObjectNameException;
+import javax.management.NotCompliantMBeanException;
+import javax.management.NotificationBroadcaster;
+import javax.management.NotificationEmitter;
+import javax.management.NotificationFilter;
+import javax.management.NotificationListener;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.OperationsException;
+import javax.management.QueryEval;
+import javax.management.QueryExp;
+import javax.management.ReflectionException;
+import javax.management.RuntimeOperationsException;
+import javax.management.loading.ClassLoaderRepository;
+
+/**
+ * <p>Base class for custom implementations of the {@link MBeanServer}
+ * interface. The commonest use of this class is as the {@linkplain
+ * JMXNamespace#getSourceServer() source server} for a {@link
+ * JMXNamespace}, although this class can be used anywhere an {@code
+ * MBeanServer} instance is required. Note that the usual ways to
+ * obtain an {@code MBeanServer} instance are either to use {@link
+ * java.lang.management.ManagementFactory#getPlatformMBeanServer()
+ * ManagementFactory.getPlatformMBeanServer()} or to use the {@code
+ * newMBeanServer} or {@code createMBeanServer} methods from {@link
+ * javax.management.MBeanServerFactory MBeanServerFactory}. {@code
+ * MBeanServerSupport} is for certain cases where those are not
+ * appropriate.</p>
+ *
+ * <p>There are two main use cases for this class: <a
+ * href="#special-purpose">special-purpose MBeanServer implementations</a>,
+ * and <a href="#virtual">namespaces containing Virtual MBeans</a>. The next
+ * sections explain these use cases.</p>
+ *
+ * <p>In the simplest case, a subclass needs to implement only two methods:</p>
+ *
+ * <ul>
+ *     <li>
+ *         {@link #getNames getNames} which returns the name of
+ *         all MBeans handled by this {@code MBeanServer}.
+ *     </li>
+ *     <li>
+ *         {@link #getDynamicMBeanFor getDynamicMBeanFor} which returns a
+ *         {@link DynamicMBean} that can be used to invoke operations and
+ *         obtain meta data (MBeanInfo) on a given MBean.
+ *     </li>
+ * </ul>
+ *
+ * <p>Subclasses can create such {@link DynamicMBean} MBeans on the fly - for
+ * instance, using the class {@link javax.management.StandardMBean}, just for
+ * the duration of an MBeanServer method call.</p>
+ *
+ * <h4 id="special-purpose">Special-purpose MBeanServer implementations</h4>
+ *
+ * <p>In some cases
+ * the general-purpose {@code MBeanServer} that you get from
+ * {@link javax.management.MBeanServerFactory MBeanServerFactory} is not
+ * appropriate.  You might need different security checks, or you might
+ * want a mock {@code MBeanServer} suitable for use in tests, or you might
+ * want a simplified and optimized {@code MBeanServer} for a special purpose.</p>
+ *
+ * <p>As an example of a special-purpose {@code MBeanServer}, the class {@link
+ * javax.management.QueryNotificationFilter QueryNotificationFilter} constructs
+ * an {@code MBeanServer} instance every time it filters a notification,
+ * with just one MBean that represents the notification. Although it could
+ * use {@code MBeanServerFactory.newMBeanServer}, a special-purpose {@code
+ * MBeanServer} will be quicker to create, use less memory, and have simpler
+ * methods that execute faster.</p>
+ *
+ * <p>Here is an example of a special-purpose {@code MBeanServer}
+ * implementation that contains exactly one MBean, which is specified at the
+ * time of creation.</p>
+ *
+ * <pre>
+ * public class SingletonMBeanServer extends MBeanServerSupport {
+ *     private final ObjectName objectName;
+ *     private final DynamicMBean mbean;
+ *
+ *     public SingletonMBeanServer(ObjectName objectName, DynamicMBean mbean) {
+ *         this.objectName = objectName;
+ *         this.mbean = mbean;
+ *     }
+ *
+ *     &#64;Override
+ *     protected {@code Set<ObjectName>} {@link #getNames getNames}() {
+ *         return Collections.singleton(objectName);
+ *     }
+ *
+ *     &#64;Override
+ *     public DynamicMBean {@link #getDynamicMBeanFor
+ *                                getDynamicMBeanFor}(ObjectName name)
+ *             throws InstanceNotFoundException {
+ *         if (objectName.equals(name))
+ *             return mbean;
+ *         else
+ *             throw new InstanceNotFoundException(name);
+ *     }
+ * }
+ * </pre>
+ *
+ * <p>Using this class, you could make an {@code MBeanServer} that contains
+ * a {@link javax.management.timer.Timer Timer} MBean like this:</p>
+ *
+ * <pre>
+ *     Timer timer = new Timer();
+ *     DynamicMBean mbean = new {@link javax.management.StandardMBean
+ *                                     StandardMBean}(timer, TimerMBean.class);
+ *     ObjectName name = new ObjectName("com.example:type=Timer");
+ *     MBeanServer timerMBS = new SingletonMBeanServer(name, mbean);
+ * </pre>
+ *
+ * <p>When {@code getDynamicMBeanFor} always returns the same object for the
+ * same name, as here, notifications work in the expected way: if the object
+ * is a {@link NotificationEmitter} then listeners can be added using
+ * {@link MBeanServer#addNotificationListener(ObjectName, NotificationListener,
+ * NotificationFilter, Object) MBeanServer.addNotificationListener}.  If
+ * {@code getDynamicMBeanFor} does not always return the same object for the
+ * same name, more work is needed to make notifications work, as described
+ * <a href="#notifs">below</a>.</p>
+ *
+ * <h4 id="virtual">Namespaces containing Virtual MBeans</h4>
+ *
+ * <p>Virtual MBeans are MBeans that do not exist as Java objects,
+ * except transiently while they are being accessed.  This is useful when
+ * there might be very many of them, or when keeping track of their creation
+ * and deletion might be expensive or hard.  For example, you might have one
+ * MBean per system process.  With an ordinary {@code MBeanServer}, you would
+ * have to list the system processes in order to create an MBean object for
+ * each one, and you would have to track the arrival and departure of system
+ * processes in order to create or delete the corresponding MBeans.  With
+ * Virtual MBeans, you only need the MBean for a given process at the exact
+ * point where it is referenced with a call such as
+ * {@link MBeanServer#getAttribute MBeanServer.getAttribute}.</p>
+ *
+ * <p>Here is an example of an {@code MBeanServer} implementation that has
+ * one MBean for every system property.  The system property {@code "java.home"}
+ * is represented by the MBean called {@code
+ * com.example:type=Property,name="java.home"}, with an attribute called
+ * {@code Value} that is the value of the property.</p>
+ *
+ * <pre>
+ * public interface PropertyMBean {
+ *     public String getValue();
+ * }
+ *
+ * <a name="PropsMBS"></a>public class PropsMBS extends MBeanServerSupport {
+ *     private static ObjectName newObjectName(String name) {
+ *         try {
+ *             return new ObjectName(name);
+ *         } catch (MalformedObjectNameException e) {
+ *             throw new AssertionError(e);
+ *         }
+ *     }
+ *
+ *     public static class PropertyImpl implements PropertyMBean {
+ *         private final String name;
+ *
+ *         public PropertyImpl(String name) {
+ *             this.name = name;
+ *         }
+ *
+ *         public String getValue() {
+ *             return System.getProperty(name);
+ *         }
+ *     }
+ *
+ *     &#64;Override
+ *     public DynamicMBean {@link #getDynamicMBeanFor
+ *                                getDynamicMBeanFor}(ObjectName name)
+ *             throws InstanceNotFoundException {
+ *
+ *         // Check that the name is a legal one for a Property MBean
+ *         ObjectName namePattern = newObjectName(
+ *                     "com.example:type=Property,name=\"*\"");
+ *         if (!namePattern.apply(name))
+ *             throw new InstanceNotFoundException(name);
+ *
+ *         // Extract the name of the property that the MBean corresponds to
+ *         String propName = ObjectName.unquote(name.getKeyProperty("name"));
+ *         if (System.getProperty(propName) == null)
+ *             throw new InstanceNotFoundException(name);
+ *
+ *         // Construct and return a transient MBean object
+ *         PropertyMBean propMBean = new PropertyImpl(propName);
+ *         return new StandardMBean(propMBean, PropertyMBean.class, false);
+ *     }
+ *
+ *     &#64;Override
+ *     protected {@code Set<ObjectName>} {@link #getNames getNames}() {
+ *         {@code Set<ObjectName> names = new TreeSet<ObjectName>();}
+ *         Properties props = System.getProperties();
+ *         for (String propName : props.stringPropertyNames()) {
+ *             ObjectName objectName = newObjectName(
+ *                     "com.example:type=Property,name=" +
+ *                     ObjectName.quote(propName));
+ *             names.add(objectName);
+ *         }
+ *         return names;
+ *     }
+ * }
+ * </pre>
+ *
+ * <p id="virtual-notif-example">Because the {@code getDynamicMBeanFor} method
+ * returns a different object every time it is called, the default handling
+ * of notifications will not work, as explained <a href="#notifs">below</a>.
+ * In this case it does not matter, because the object returned by {@code
+ * getDynamicMBeanFor} is not a {@code NotificationEmitter}, so {@link
+ * MBeanServer#addNotificationListener(ObjectName, NotificationListener,
+ * NotificationFilter, Object) MBeanServer.addNotificationListener} will
+ * always fail. But if we wanted to extend {@code PropsMBS} so that the MBean
+ * for property {@code "foo"} emitted a notification every time that property
+ * changed, we would need to do it as shown below. (Because there is no API to
+ * be informed when a property changes, this code assumes that some other code
+ * calls the {@code propertyChanged} method every time a property changes.)</p>
+ *
+ * <pre>
+ * public class PropsMBS {
+ *     ...as <a href="#PropsMBS">above</a>...
+ *
+ *     private final {@link VirtualEventManager} vem = new VirtualEventManager();
+ *
+ *     &#64;Override
+ *     public NotificationEmitter {@link #getNotificationEmitterFor
+ *                                       getNotificationEmitterFor}(
+ *             ObjectName name) throws InstanceNotFoundException {
+ *         getDynamicMBeanFor(name);  // check that the name is valid
+ *         return vem.{@link VirtualEventManager#getNotificationEmitterFor
+ *                           getNotificationEmitterFor}(name);
+ *     }
+ *
+ *     public void propertyChanged(String name, String newValue) {
+ *         ObjectName objectName = newObjectName(
+ *                 "com.example:type=Property,name=" + ObjectName.quote(name));
+ *         Notification n = new Notification(
+ *                 "com.example.property.changed", objectName, 0L,
+ *                 "Property " + name + " changed");
+ *         n.setUserData(newValue);
+ *         vem.{@link VirtualEventManager#publish publish}(objectName, n);
+ *     }
+ * }
+ * </pre>
+ *
+ * <h4 id="creation">MBean creation and deletion</h4>
+ *
+ * <p>MBean creation through {@code MBeanServer.createMBean} is disabled
+ * by default. Subclasses which need to support MBean creation
+ * through {@code createMBean} need to implement a single method {@link
+ * #createMBean(String, ObjectName, ObjectName, Object[], String[],
+ * boolean)}.</p>
+ *
+ * <p>Similarly MBean registration and unregistration through {@code
+ * registerMBean} and {@code unregisterMBean} are disabled by default.
+ * Subclasses which need to support MBean registration and
+ * unregistration will need to implement {@link #registerMBean registerMBean}
+ * and {@link #unregisterMBean unregisterMBean}.</p>
+ *
+ * <h4 id="notifs">Notifications</h4>
+ *
+ * <p>By default {@link MBeanServer#addNotificationListener(ObjectName,
+ * NotificationListener, NotificationFilter, Object) addNotificationListener}
+ * is accepted for an MBean <em>{@code name}</em> if {@link #getDynamicMBeanFor
+ * getDynamicMBeanFor}<code>(<em>name</em>)</code> returns an object that is a
+ * {@link NotificationEmitter}.  That is appropriate if
+ * {@code getDynamicMBeanFor}<code>(<em>name</em>)</code> always returns the
+ * same object for the same <em>{@code name}</em>.  But with
+ * Virtual MBeans, every call to {@code getDynamicMBeanFor} returns a new object,
+ * which is discarded as soon as the MBean request has finished.
+ * So a listener added to that object would be immediately forgotten.</p>
+ *
+ * <p>The simplest way for a subclass that defines Virtual MBeans
+ * to support notifications is to create a private {@link VirtualEventManager}
+ * and override the method {@link
+ * #getNotificationEmitterFor getNotificationEmitterFor} as follows:</p>
+ *
+ * <pre>
+ *     private final VirtualEventManager vem = new VirtualEventManager();
+ *
+ *     &#64;Override
+ *     public NotificationEmitter getNotificationEmitterFor(
+ *             ObjectName name) throws InstanceNotFoundException {
+ *         // Check that the name is a valid Virtual MBean.
+ *         // This is the easiest way to do that, but not always the
+ *         // most efficient:
+ *         getDynamicMBeanFor(name);
+ *
+ *         // Return an object that supports add/removeNotificationListener
+ *         // through the VirtualEventManager.
+ *         return vem.getNotificationEmitterFor(name);
+ *     }
+ * </pre>
+ *
+ * <p>A notification <em>{@code n}</em> can then be sent from the Virtual MBean
+ * called <em>{@code name}</em> by calling {@link VirtualEventManager#publish
+ * vem.publish}<code>(<em>name</em>, <em>n</em>)</code>.  See the example
+ * <a href="#virtual-notif-example">above</a>.</p>
+ *
+ * @since Java SE 7
+ */
+public abstract class MBeanServerSupport implements MBeanServer {
+
+    /**
+     * A logger for this class.
+     */
+    private static final Logger LOG =
+            Logger.getLogger(MBeanServerSupport.class.getName());
+
+    /**
+     * <p>Make a new {@code MBeanServerSupport} instance.</p>
+     */
+    protected MBeanServerSupport() {
+    }
+
+    /**
+     * <p>Returns a dynamically created handle that makes it possible to
+     * access the named MBean for the duration of a method call.</p>
+     *
+     * <p>An easy way to create such a {@link DynamicMBean} handle is, for
+     * instance, to create a temporary MXBean instance and to wrap it in
+     * an instance of
+     * {@link javax.management.StandardMBean}.
+     * This handle should remain valid for the duration of the call
+     * but can then be discarded.</p>
+     * @param name the name of the MBean for which a request was received.
+     * @return a {@link DynamicMBean} handle that can be used to invoke
+     * operations on the named MBean.
+     * @throws InstanceNotFoundException if no such MBean is supposed
+     *         to exist.
+     */
+    public abstract DynamicMBean getDynamicMBeanFor(ObjectName name)
+                        throws InstanceNotFoundException;
+
+    /**
+     * <p>Subclasses should implement this method to return
+     * the names of all MBeans handled by this object instance.</p>
+     *
+     * <p>The object returned by getNames() should be safely {@linkplain
+     * Set#iterator iterable} even in the presence of other threads that may
+     * cause the set of names to change. Typically this means one of the
+     * following:</p>
+     *
+     * <ul>
+     * <li>the returned set of names is always the same; or
+     * <li>the returned set of names is an object such as a {@link
+     * java.util.concurrent.CopyOnWriteArraySet CopyOnWriteArraySet} that is
+     * safely iterable even if the set is changed by other threads; or
+     * <li>a new Set is constructed every time this method is called.
+     * </ul>
+     *
+     * @return the names of all MBeans handled by this object.
+     */
+    protected abstract Set<ObjectName> getNames();
+
+    /**
+     * <p>List names matching the given pattern.
+     * The default implementation of this method calls {@link #getNames()}
+     * and returns the subset of those names matching {@code pattern}.</p>
+     *
+     * @param pattern an ObjectName pattern
+     * @return the list of MBean names that match the given pattern.
+     */
+    protected Set<ObjectName> getMatchingNames(ObjectName pattern) {
+        return Util.filterMatchingNames(pattern, getNames());
+    }
+
+    /**
+     * <p>Returns a {@link NotificationEmitter} which can be used to
+     * subscribe or unsubscribe for notifications with the named
+     * mbean.</p>
+     *
+     * <p>The default implementation of this method calls {@link
+     * #getDynamicMBeanFor getDynamicMBeanFor(name)} and returns that object
+     * if it is a {@code NotificationEmitter}, otherwise null. See <a
+     * href="#notifs">above</a> for further discussion of notification
+     * handling.</p>
+     *
+     * @param name The name of the MBean whose notifications are being
+     * subscribed, or unsuscribed.
+     *
+     * @return A {@link NotificationEmitter} that can be used to subscribe or
+     * unsubscribe for notifications emitted by the named MBean, or {@code
+     * null} if the MBean does not emit notifications and should not be
+     * considered as a {@code NotificationEmitter}.
+     *
+     * @throws InstanceNotFoundException if {@code name} is not the name of
+     * an MBean in this {@code MBeanServer}.
+     */
+    public NotificationEmitter getNotificationEmitterFor(ObjectName name)
+            throws InstanceNotFoundException {
+        DynamicMBean mbean = getDynamicMBeanFor(name);
+        if (mbean instanceof NotificationEmitter)
+            return (NotificationEmitter) mbean;
+        else
+            return null;
+    }
+
+    private NotificationEmitter getNonNullNotificationEmitterFor(
+            ObjectName name)
+            throws InstanceNotFoundException {
+        NotificationEmitter emitter = getNotificationEmitterFor(name);
+        if (emitter == null) {
+            IllegalArgumentException iae = new IllegalArgumentException(
+                    "Not a NotificationEmitter: " + name);
+            throw new RuntimeOperationsException(iae);
+        }
+        return emitter;
+    }
+
+    /**
+     * <p>Creates a new MBean in the MBean name space.
+     * This operation is not supported in this base class implementation.</p>
+     * The default implementation of this method always throws an {@link
+     * UnsupportedOperationException}
+     * wrapped in a {@link RuntimeOperationsException}.</p>
+     *
+     * <p>Subclasses may redefine this method to provide an implementation.
+     * All the various flavors of {@code MBeanServer.createMBean} methods
+     * will eventually call this method. A subclass that wishes to
+     * support MBean creation through {@code createMBean} thus only
+     * needs to provide an implementation for this one method.
+     *
+     * @param className The class name of the MBean to be instantiated.
+     * @param name The object name of the MBean. May be null.
+     * @param params An array containing the parameters of the
+     * constructor to be invoked.
+     * @param signature An array containing the signature of the
+     * constructor to be invoked.
+     * @param loaderName The object name of the class loader to be used.
+     * @param useCLR This parameter is {@code true} when this method
+     *        is called from one of the {@code MBeanServer.createMBean} methods
+     *        whose signature does not include the {@code ObjectName} of an
+     *        MBean class loader to use for loading the MBean class.
+     *
+     * @return An <CODE>ObjectInstance</CODE>, containing the
+     * <CODE>ObjectName</CODE> and the Java class name of the newly
+     * instantiated MBean.  If the contained <code>ObjectName</code>
+     * is <code>n</code>, the contained Java class name is
+     * <code>{@link javax.management.MBeanServer#getMBeanInfo
+     * getMBeanInfo(n)}.getClassName()</code>.
+     *
+     * @exception ReflectionException Wraps a
+     * <CODE>java.lang.ClassNotFoundException</CODE> or a
+     * <CODE>java.lang.Exception</CODE> that occurred when trying to
+     * invoke the MBean's constructor.
+     * @exception InstanceAlreadyExistsException The MBean is already
+     * under the control of the MBean server.
+     * @exception MBeanRegistrationException The
+     * <CODE>preRegister</CODE> (<CODE>MBeanRegistration</CODE>
+     * interface) method of the MBean has thrown an exception. The
+     * MBean will not be registered.
+     * @exception MBeanException The constructor of the MBean has
+     * thrown an exception
+     * @exception NotCompliantMBeanException This class is not a JMX
+     * compliant MBean
+     * @exception InstanceNotFoundException The specified class loader
+     * is not registered in the MBean server.
+     * @exception RuntimeOperationsException Wraps either:
+     * <ul>
+     * <li>a <CODE>java.lang.IllegalArgumentException</CODE>: The className
+     * passed in parameter is null, the <CODE>ObjectName</CODE> passed in
+     * parameter contains a pattern or no <CODE>ObjectName</CODE> is specified
+     * for the MBean; or</li>
+     * <li>an {@code UnsupportedOperationException} if creating MBeans is not
+     * supported by this {@code MBeanServer} implementation.
+     * </ul>
+     */
+    public ObjectInstance createMBean(String className,
+            ObjectName name, ObjectName loaderName, Object[] params,
+            String[] signature, boolean useCLR)
+            throws ReflectionException, InstanceAlreadyExistsException,
+            MBeanRegistrationException, MBeanException,
+            NotCompliantMBeanException, InstanceNotFoundException {
+        throw newUnsupportedException("createMBean");
+    }
+
+
+    /**
+     * <p>Attempts to determine whether the named MBean should be
+     * considered as an instance of a given class.  The default implementation
+     * of this method calls {@link #getDynamicMBeanFor getDynamicMBeanFor(name)}
+     * to get an MBean object.  Then its behaviour is the same as the standard
+     * {@link MBeanServer#isInstanceOf MBeanServer.isInstanceOf} method.</p>
+     *
+     * {@inheritDoc}
+     */
+    public boolean isInstanceOf(ObjectName name, String className)
+        throws InstanceNotFoundException {
+
+        final DynamicMBean instance = nonNullMBeanFor(name);
+
+        try {
+            final String mbeanClassName = instance.getMBeanInfo().getClassName();
+
+            if (mbeanClassName.equals(className))
+                return true;
+
+            final Object resource;
+            final ClassLoader cl;
+            if (instance instanceof DynamicWrapperMBean) {
+                DynamicWrapperMBean d = (DynamicWrapperMBean) instance;
+                resource = d.getWrappedObject();
+                cl = d.getWrappedClassLoader();
+            } else {
+                resource = instance;
+                cl = instance.getClass().getClassLoader();
+            }
+
+            final Class<?> classNameClass = Class.forName(className, false, cl);
+
+            if (classNameClass.isInstance(resource))
+                return true;
+
+            if (classNameClass == NotificationBroadcaster.class ||
+                    classNameClass == NotificationEmitter.class) {
+                try {
+                    getNotificationEmitterFor(name);
+                    return true;
+                } catch (Exception x) {
+                    LOG.finest("MBean " + name +
+                            " is not a notification emitter. Ignoring: "+x);
+                    return false;
+                }
+            }
+
+            final Class<?> resourceClass = Class.forName(mbeanClassName, false, cl);
+            return classNameClass.isAssignableFrom(resourceClass);
+        } catch (Exception x) {
+            /* Could be SecurityException or ClassNotFoundException */
+            LOG.logp(Level.FINEST,
+                    MBeanServerSupport.class.getName(),
+                    "isInstanceOf", "Exception calling isInstanceOf", x);
+            return false;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>The default implementation of this method returns the string
+     * "DefaultDomain".</p>
+     */
+    public String getDefaultDomain() {
+        return "DefaultDomain";
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>The default implementation of this method returns
+     * {@link #getNames()}.size().</p>
+     */
+    public Integer getMBeanCount() {
+        return getNames().size();
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>The default implementation of this method first calls {@link #getNames
+     * getNames()} to get a list of all MBean names,
+     * and from this set of names, derives the set of domains which contain
+     * MBeans.</p>
+     */
+    public String[] getDomains() {
+        final Set<ObjectName> names = getNames();
+        final Set<String> res = new TreeSet<String>();
+        for (ObjectName n : names) {
+            if (n == null) continue; // not allowed but you never know.
+            res.add(n.getDomain());
+        }
+        return res.toArray(new String[res.size()]);
+    }
+
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>The default implementation of this method will first
+     * call {@link
+     *    #getDynamicMBeanFor getDynamicMBeanFor(name)} to obtain a handle
+     * to the named MBean,
+     * and then call {@link DynamicMBean#getAttribute getAttribute}
+     * on that {@link DynamicMBean} handle.</p>
+     *
+     * @throws RuntimeOperationsException {@inheritDoc}
+     */
+    public Object getAttribute(ObjectName name, String attribute)
+        throws MBeanException, AttributeNotFoundException,
+               InstanceNotFoundException, ReflectionException {
+        final DynamicMBean mbean = nonNullMBeanFor(name);
+        return mbean.getAttribute(attribute);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>The default implementation of this method will first
+     * call {@link #getDynamicMBeanFor getDynamicMBeanFor(name)}
+     * to obtain a handle to the named MBean,
+     * and then call {@link DynamicMBean#setAttribute setAttribute}
+     * on that {@link DynamicMBean} handle.</p>
+     *
+     * @throws RuntimeOperationsException {@inheritDoc}
+     */
+    public void setAttribute(ObjectName name, Attribute attribute)
+        throws InstanceNotFoundException, AttributeNotFoundException,
+            InvalidAttributeValueException, MBeanException,
+            ReflectionException {
+        final DynamicMBean mbean = nonNullMBeanFor(name);
+        mbean.setAttribute(attribute);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>The default implementation of this method will first
+     * call {@link #getDynamicMBeanFor getDynamicMBeanFor(name)} to obtain a
+     * handle to the named MBean,
+     * and then call {@link DynamicMBean#getAttributes getAttributes}
+     * on that {@link DynamicMBean} handle.</p>
+     *
+     * @throws RuntimeOperationsException {@inheritDoc}
+     */
+    public AttributeList getAttributes(ObjectName name,
+            String[] attributes) throws InstanceNotFoundException,
+            ReflectionException {
+        final DynamicMBean mbean = nonNullMBeanFor(name);
+        return mbean.getAttributes(attributes);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>The default implementation of this method will first
+     * call {@link #getDynamicMBeanFor getDynamicMBeanFor(name)} to obtain a
+     * handle to the named MBean,
+     * and then call {@link DynamicMBean#setAttributes setAttributes}
+     * on that {@link DynamicMBean} handle.</p>
+     *
+     * @throws RuntimeOperationsException {@inheritDoc}
+     */
+    public AttributeList setAttributes(ObjectName name, AttributeList attributes)
+        throws InstanceNotFoundException, ReflectionException {
+        final DynamicMBean mbean = nonNullMBeanFor(name);
+        return mbean.setAttributes(attributes);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>The default implementation of this method will first
+     * call {@link #getDynamicMBeanFor getDynamicMBeanFor(name)} to obtain a
+     * handle to the named MBean,
+     * and then call {@link DynamicMBean#invoke invoke}
+     * on that {@link DynamicMBean} handle.</p>
+     */
+    public Object invoke(ObjectName name, String operationName,
+                Object[] params, String[] signature)
+                throws InstanceNotFoundException, MBeanException,
+                       ReflectionException {
+        final DynamicMBean mbean = nonNullMBeanFor(name);
+        return mbean.invoke(operationName, params, signature);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>The default implementation of this method will first
+     * call {@link #getDynamicMBeanFor getDynamicMBeanFor(name)} to obtain a
+     * handle to the named MBean,
+     * and then call {@link DynamicMBean#getMBeanInfo getMBeanInfo}
+     * on that {@link DynamicMBean} handle.</p>
+     */
+    public MBeanInfo getMBeanInfo(ObjectName name)
+        throws InstanceNotFoundException, IntrospectionException,
+               ReflectionException {
+        final DynamicMBean mbean = nonNullMBeanFor(name);
+        return mbean.getMBeanInfo();
+   }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>The default implementation of this method will call
+     * {@link #getDynamicMBeanFor getDynamicMBeanFor(name)}.<!--
+     * -->{@link DynamicMBean#getMBeanInfo getMBeanInfo()}.<!--
+     * -->{@link MBeanInfo#getClassName getClassName()} to get the
+     * class name to combine with {@code name} to produce a new
+     * {@code ObjectInstance}.</p>
+     */
+    public ObjectInstance getObjectInstance(ObjectName name)
+            throws InstanceNotFoundException {
+        final DynamicMBean mbean = nonNullMBeanFor(name);
+        final String className = mbean.getMBeanInfo().getClassName();
+        return new ObjectInstance(name, className);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>The default implementation of this method will first call {@link
+     * #getDynamicMBeanFor getDynamicMBeanFor(name)} to obtain a handle to the
+     * named MBean. If {@code getDynamicMBeanFor} returns an object, {@code
+     * isRegistered} will return true. If {@code getDynamicMBeanFor} returns
+     * null or throws {@link InstanceNotFoundException}, {@code isRegistered}
+     * will return false.</p>
+     *
+     * @throws RuntimeOperationsException {@inheritDoc}
+     */
+    public boolean isRegistered(ObjectName name) {
+        try {
+            final DynamicMBean mbean = getDynamicMBeanFor(name);
+            return mbean!=null;
+        } catch (InstanceNotFoundException x) {
+            if (LOG.isLoggable(Level.FINEST))
+                LOG.finest("MBean "+name+" is not registered: "+x);
+            return false;
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>The default implementation of this method will first
+     * call {@link #queryNames queryNames}
+     * to get a list of all matching MBeans, and then, for each returned name,
+     * call {@link #getObjectInstance getObjectInstance(name)}.</p>
+     */
+    public Set<ObjectInstance> queryMBeans(ObjectName pattern, QueryExp query) {
+        final Set<ObjectName> names = queryNames(pattern, query);
+        if (names.isEmpty()) return Collections.emptySet();
+        final Set<ObjectInstance> mbeans = new HashSet<ObjectInstance>();
+        for (ObjectName name : names) {
+            try {
+                mbeans.add(getObjectInstance(name));
+            } catch (SecurityException x) { // DLS: OK
+                continue;
+            } catch (InstanceNotFoundException x) { // DLS: OK
+                continue;
+            }
+        }
+        return mbeans;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>The default implementation of this method calls {@link #getMatchingNames
+     * getMatchingNames(pattern)} to obtain a list of MBeans matching
+     * the given name pattern. If the {@code query} parameter is null,
+     * this will be the result. Otherwise, it will evaluate the
+     * {@code query} parameter for each of the returned names, exactly
+     * as an {@code MBeanServer} would. This might result in
+     * {@link #getDynamicMBeanFor getDynamicMBeanFor} being called
+     * several times for each returned name.</p>
+     */
+    public Set<ObjectName> queryNames(ObjectName pattern, QueryExp query) {
+        try {
+            final Set<ObjectName> res = getMatchingNames(pattern);
+            return filterListOfObjectNames(res, query);
+        } catch (Exception x) {
+            LOG.fine("Unexpected exception raised in queryNames: "+x);
+            LOG.log(Level.FINEST, "Unexpected exception raised in queryNames", x);
+        }
+        // We reach here only when an exception was raised.
+        //
+        return Collections.emptySet();
+    }
+
+    private final static boolean apply(final QueryExp query,
+                  final ObjectName on,
+                  final MBeanServer srv) {
+        boolean res = false;
+        MBeanServer oldServer = QueryEval.getMBeanServer();
+        query.setMBeanServer(srv);
+        try {
+            res = query.apply(on);
+        } catch (Exception e) {
+            LOG.finest("QueryExp.apply threw exception, returning false." +
+                    " Cause: "+e);
+            res = false;
+        } finally {
+           /*
+            * query.setMBeanServer is probably
+            * QueryEval.setMBeanServer so put back the old
+            * value.  Since that method uses a ThreadLocal
+            * variable, this code is only needed for the
+            * unusual case where the user creates a custom
+            * QueryExp that calls a nested query on another
+            * MBeanServer.
+            */
+            query.setMBeanServer(oldServer);
+        }
+        return res;
+    }
+
+    /**
+     * Filters a {@code Set<ObjectName>} according to a pattern and a query.
+     * This might be quite inefficient for virtual name spaces.
+     */
+    Set<ObjectName>
+            filterListOfObjectNames(Set<ObjectName> list,
+                                    QueryExp query) {
+        if (list.isEmpty() || query == null)
+            return list;
+
+        // create a new result set
+        final Set<ObjectName> result = new HashSet<ObjectName>();
+
+        for (ObjectName on : list) {
+            // if on doesn't match query exclude it.
+            if (apply(query, on, this))
+                result.add(on);
+        }
+        return result;
+    }
+
+
+    // Don't use {@inheritDoc}, because we don't want to say that the
+    // MBeanServer replaces a reference to the MBean by its ObjectName.
+    /**
+     * <p>Adds a listener to a registered MBean. A notification emitted by
+     * the MBean will be forwarded to the listener.</p>
+     *
+     * <p>This implementation calls
+     * {@link #getNotificationEmitterFor getNotificationEmitterFor}
+     * and invokes {@code addNotificationListener} on the
+     * {@link NotificationEmitter} it returns.
+     *
+     * @see #getDynamicMBeanFor getDynamicMBeanFor
+     * @see #getNotificationEmitterFor getNotificationEmitterFor
+     */
+    public void addNotificationListener(ObjectName name,
+            NotificationListener listener, NotificationFilter filter,
+            Object handback) throws InstanceNotFoundException {
+        final NotificationEmitter emitter =
+                getNonNullNotificationEmitterFor(name);
+        emitter.addNotificationListener(listener, filter, handback);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation calls
+     * {@link #getNotificationEmitterFor getNotificationEmitterFor}
+     * and invokes {@code removeNotificationListener} on the
+     * {@link NotificationEmitter} it returns.
+     * @see #getDynamicMBeanFor getDynamicMBeanFor
+     * @see #getNotificationEmitterFor getNotificationEmitterFor
+     */
+    public void removeNotificationListener(ObjectName name,
+            NotificationListener listener)
+            throws InstanceNotFoundException, ListenerNotFoundException {
+        final NotificationEmitter emitter =
+                getNonNullNotificationEmitterFor(name);
+        emitter.removeNotificationListener(listener);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation calls
+     * {@link #getNotificationEmitterFor getNotificationEmitterFor}
+     * and invokes {@code removeNotificationListener} on the
+     * {@link NotificationEmitter} it returns.
+     * @see #getDynamicMBeanFor getDynamicMBeanFor
+     * @see #getNotificationEmitterFor getNotificationEmitterFor
+     */
+    public void removeNotificationListener(ObjectName name,
+            NotificationListener listener, NotificationFilter filter,
+            Object handback)
+            throws InstanceNotFoundException, ListenerNotFoundException {
+        NotificationEmitter emitter =
+                getNonNullNotificationEmitterFor(name);
+        emitter.removeNotificationListener(listener);
+    }
+
+
+    /**
+     * <p>Adds a listener to a registered MBean.</p>
+     *
+     * <p>The default implementation of this method first calls
+     * {@link #getDynamicMBeanFor getDynamicMBeanFor(listenerName)}.
+     * If that successfully returns an object, call it {@code
+     * mbean}, then (a) if {@code mbean} is an instance of {@link
+     * NotificationListener} then this method calls {@link
+     * #addNotificationListener(ObjectName, NotificationListener,
+     * NotificationFilter, Object) addNotificationListener(name, mbean, filter,
+     * handback)}, otherwise (b) this method throws an exception as specified
+     * for this case.</p>
+     *
+     * <p>This default implementation is not appropriate for Virtual MBeans,
+     * although that only matters if the object returned by {@code
+     * getDynamicMBeanFor} can be an instance of
+     * {@code NotificationListener}.</p>
+     *
+     * @throws RuntimeOperationsException {@inheritDoc}
+     */
+    public void addNotificationListener(ObjectName name, ObjectName listenerName,
+            NotificationFilter filter, Object handback)
+            throws InstanceNotFoundException {
+        NotificationListener listener = getListenerMBean(listenerName);
+        addNotificationListener(name, listener, filter, handback);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This operation is not supported in this base class implementation.
+     * The default implementation of this method always throws
+     * {@link RuntimeOperationsException} wrapping
+     * {@link UnsupportedOperationException}.</p>
+     *
+     * @throws javax.management.RuntimeOperationsException wrapping
+     *        {@link UnsupportedOperationException}
+     */
+    public void removeNotificationListener(ObjectName name,
+            ObjectName listenerName)
+            throws InstanceNotFoundException, ListenerNotFoundException {
+        NotificationListener listener = getListenerMBean(listenerName);
+        removeNotificationListener(name, listener);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This operation is not supported in this base class implementation.
+     * The default implementation of this method always throws
+     * {@link RuntimeOperationsException} wrapping
+     * {@link UnsupportedOperationException}.</p>
+     *
+     * @throws javax.management.RuntimeOperationsException wrapping
+     *        {@link UnsupportedOperationException}
+     */
+    public void removeNotificationListener(ObjectName name,
+            ObjectName listenerName, NotificationFilter filter,
+            Object handback)
+            throws InstanceNotFoundException, ListenerNotFoundException {
+        NotificationListener listener = getListenerMBean(listenerName);
+        removeNotificationListener(name, listener, filter, handback);
+    }
+
+    private NotificationListener getListenerMBean(ObjectName listenerName)
+            throws InstanceNotFoundException {
+        Object mbean = getDynamicMBeanFor(listenerName);
+        if (mbean instanceof NotificationListener)
+            return (NotificationListener) mbean;
+        else {
+            throw newIllegalArgumentException(
+                    "MBean is not a NotificationListener: " + listenerName);
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This operation is not supported in this base class implementation.
+     * The default implementation of this method always throws
+     * {@link InstanceNotFoundException} wrapping
+     * {@link UnsupportedOperationException}.</p>
+     *
+     * @return the default implementation of this method never returns.
+     * @throws javax.management.RuntimeOperationsException wrapping
+     *        {@link UnsupportedOperationException}
+     */
+    public ClassLoader getClassLoader(ObjectName loaderName)
+            throws InstanceNotFoundException {
+        final UnsupportedOperationException failed =
+                new UnsupportedOperationException("getClassLoader");
+        final InstanceNotFoundException x =
+                new InstanceNotFoundException(String.valueOf(loaderName));
+        x.initCause(failed);
+        throw x;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>The default implementation of this method calls
+     * {@link #getDynamicMBeanFor getDynamicMBeanFor(mbeanName)} and applies
+     * the logic just described to the result.</p>
+     */
+    public ClassLoader getClassLoaderFor(ObjectName mbeanName)
+            throws InstanceNotFoundException {
+        final DynamicMBean mbean = nonNullMBeanFor(mbeanName);
+        if (mbean instanceof DynamicWrapperMBean)
+            return ((DynamicWrapperMBean) mbean).getWrappedClassLoader();
+        else
+            return mbean.getClass().getClassLoader();
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>The default implementation of this method returns a
+     * {@link ClassLoaderRepository} containing exactly one loader,
+     * the {@linkplain Thread#getContextClassLoader() context class loader}
+     * for the current thread.
+     * Subclasses can override this method to return a different
+     * {@code ClassLoaderRepository}.</p>
+     */
+    public ClassLoaderRepository getClassLoaderRepository() {
+        // We return a new ClassLoaderRepository each time this
+        // method is called. This is by design, because the
+        // SingletonClassLoaderRepository is a very small object and
+        // getClassLoaderRepository() will not be called very often
+        // (the connector server calls it once) - in the context of
+        // MBeanServerSupport there's a very good chance that this method will
+        // *never* be called.
+        ClassLoader ccl = Thread.currentThread().getContextClassLoader();
+        return Util.getSingleClassLoaderRepository(ccl);
+    }
+
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This operation is not supported in this base class implementation.
+     * The default implementation of this method always throws
+     * {@link RuntimeOperationsException} wrapping
+     * {@link UnsupportedOperationException}.</p>
+     * @throws javax.management.RuntimeOperationsException wrapping
+     *        {@link UnsupportedOperationException}
+     */
+    public ObjectInstance registerMBean(Object object, ObjectName name)
+            throws InstanceAlreadyExistsException, MBeanRegistrationException,
+            NotCompliantMBeanException {
+        throw newUnsupportedException("registerMBean");
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This operation is not supported in this base class implementation.
+     * The default implementation of this method always throws
+     * {@link RuntimeOperationsException} wrapping
+     * {@link UnsupportedOperationException}.
+     * @throws javax.management.RuntimeOperationsException wrapping
+     *        {@link UnsupportedOperationException}
+     */
+    public void unregisterMBean(ObjectName name)
+            throws InstanceNotFoundException, MBeanRegistrationException {
+        throw newUnsupportedException("unregisterMBean");
+    }
+
+    /**
+     * Calls {@link #createMBean(String, ObjectName,
+     *           ObjectName, Object[], String[], boolean)
+     * createMBean(className, name, null, params, signature, true)};
+     */
+    public final ObjectInstance createMBean(String className, ObjectName name,
+            Object[] params, String[] signature)
+            throws ReflectionException, InstanceAlreadyExistsException,
+            MBeanRegistrationException, MBeanException,
+            NotCompliantMBeanException {
+        try {
+            return safeCreateMBean(className, name, null, params, signature, true);
+        } catch (InstanceNotFoundException ex) {
+            // should not happen!
+            throw new MBeanException(ex, "Unexpected exception: " + ex);
+        }
+    }
+
+    /**
+     * Calls {@link #createMBean(String, ObjectName,
+     *           ObjectName, Object[], String[], boolean)
+     * createMBean(className,name, loaderName, params, signature, false)};
+     */
+    public final ObjectInstance createMBean(String className, ObjectName name,
+            ObjectName loaderName, Object[] params, String[] signature)
+            throws ReflectionException, InstanceAlreadyExistsException,
+            MBeanRegistrationException, MBeanException,
+            NotCompliantMBeanException, InstanceNotFoundException {
+        return safeCreateMBean(className, name, loaderName, params, signature, false);
+    }
+
+    /**
+     * Calls {@link #createMBean(String, ObjectName,
+     *           ObjectName, Object[], String[], boolean)
+     * createMBean(className, name, null, null, null, true)};
+     */
+    public final ObjectInstance createMBean(String className, ObjectName name)
+        throws ReflectionException, InstanceAlreadyExistsException,
+            MBeanRegistrationException, MBeanException,
+            NotCompliantMBeanException {
+        try {
+            return safeCreateMBean(className, name, null, null, null, true);
+        } catch (InstanceNotFoundException ex) {
+            // should not happen!
+            throw new MBeanException(ex, "Unexpected exception: " + ex);
+        }
+    }
+
+    /**
+     * Calls {@link #createMBean(String, ObjectName,
+     *           ObjectName, Object[], String[], boolean)
+     * createMBean(className, name, loaderName, null, null, false)};
+     */
+    public final ObjectInstance createMBean(String className, ObjectName name,
+            ObjectName loaderName)
+            throws ReflectionException, InstanceAlreadyExistsException,
+            MBeanRegistrationException, MBeanException,
+            NotCompliantMBeanException, InstanceNotFoundException {
+        return safeCreateMBean(className, name, loaderName, null, null, false);
+    }
+
+    // make sure all exceptions are correctly wrapped in a JMXException
+    private ObjectInstance safeCreateMBean(String className,
+            ObjectName name, ObjectName loaderName, Object[] params,
+            String[] signature, boolean useRepository)
+            throws ReflectionException, InstanceAlreadyExistsException,
+            MBeanRegistrationException, MBeanException,
+            NotCompliantMBeanException, InstanceNotFoundException {
+        try {
+            return createMBean(className, name, loaderName, params,
+                               signature, useRepository);
+        } catch (ReflectionException x) { throw x;
+        } catch (InstanceAlreadyExistsException x) { throw x;
+        } catch (MBeanRegistrationException x) { throw x;
+        } catch (MBeanException x) { throw x;
+        } catch (NotCompliantMBeanException x) { throw x;
+        } catch (InstanceNotFoundException x) { throw x;
+        } catch (SecurityException x) { throw x;
+        } catch (JMRuntimeException x) { throw x;
+        } catch (RuntimeException x) {
+            throw new RuntimeOperationsException(x, x.toString());
+        } catch (Exception x) {
+            throw new MBeanException(x, x.toString());
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This operation is not supported in this base class implementation.
+     * The default implementation of this method always throws
+     * {@link RuntimeOperationsException} wrapping
+     * {@link UnsupportedOperationException}.</p>
+     *
+     * @throws javax.management.RuntimeOperationsException wrapping
+     *        {@link UnsupportedOperationException}
+     */
+    public Object instantiate(String className)
+            throws ReflectionException, MBeanException {
+        throw new UnsupportedOperationException("Not applicable.");
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This operation is not supported in this base class implementation.
+     * The default implementation of this method always throws
+     * {@link RuntimeOperationsException} wrapping
+     * {@link UnsupportedOperationException}.</p>
+     *
+     * @throws javax.management.RuntimeOperationsException wrapping
+     *        {@link UnsupportedOperationException}
+     */
+    public Object instantiate(String className, ObjectName loaderName)
+            throws ReflectionException, MBeanException,
+            InstanceNotFoundException {
+        throw new UnsupportedOperationException("Not applicable.");
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This operation is not supported in this base class implementation.
+     * The default implementation of this method always throws
+     * {@link RuntimeOperationsException} wrapping
+     * {@link UnsupportedOperationException}.</p>
+     *
+     * @throws javax.management.RuntimeOperationsException wrapping
+     *        {@link UnsupportedOperationException}
+     */
+    public Object instantiate(String className, Object[] params,
+            String[] signature) throws ReflectionException, MBeanException {
+        throw new UnsupportedOperationException("Not applicable.");
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This operation is not supported in this base class implementation.
+     * The default implementation of this method always throws
+     * {@link RuntimeOperationsException} wrapping
+     * {@link UnsupportedOperationException}.</p>
+     *
+     * @throws javax.management.RuntimeOperationsException wrapping
+     *        {@link UnsupportedOperationException}
+     */
+    public Object instantiate(String className, ObjectName loaderName,
+            Object[] params, String[] signature)
+            throws ReflectionException, MBeanException,
+            InstanceNotFoundException {
+        throw new UnsupportedOperationException("Not applicable.");
+    }
+
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This operation is not supported in this base class implementation.
+     * The default implementation of this method always throws
+     * {@link RuntimeOperationsException} wrapping
+     * {@link UnsupportedOperationException}.</p>
+     *
+     * @throws javax.management.RuntimeOperationsException wrapping
+     *        {@link UnsupportedOperationException}
+     */
+    @Deprecated
+    public ObjectInputStream deserialize(ObjectName name, byte[] data)
+            throws InstanceNotFoundException, OperationsException {
+        throw new UnsupportedOperationException("Not applicable.");
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This operation is not supported in this base class implementation.
+     * The default implementation of this method always throws
+     * {@link RuntimeOperationsException} wrapping
+     * {@link UnsupportedOperationException}.</p>
+     *
+     * @throws javax.management.RuntimeOperationsException wrapping
+     *        {@link UnsupportedOperationException}
+     */
+    @Deprecated
+    public ObjectInputStream deserialize(String className, byte[] data)
+            throws OperationsException, ReflectionException {
+        throw new UnsupportedOperationException("Not applicable.");
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This operation is not supported in this base class implementation.
+     * The default implementation of this method always throws
+     * {@link RuntimeOperationsException} wrapping
+     * {@link UnsupportedOperationException}.</p>
+     *
+     * @throws javax.management.RuntimeOperationsException wrapping
+     *        {@link UnsupportedOperationException}
+     */
+    @Deprecated
+    public ObjectInputStream deserialize(String className,
+            ObjectName loaderName, byte[] data)
+            throws InstanceNotFoundException, OperationsException,
+            ReflectionException {
+        throw new UnsupportedOperationException("Not applicable.");
+    }
+
+
+    // Calls getDynamicMBeanFor, and throws an InstanceNotFoundException
+    // if the returned mbean is null.
+    // The DynamicMBean returned by this method is thus guaranteed to be
+    // non null.
+    //
+    private DynamicMBean nonNullMBeanFor(ObjectName name)
+            throws InstanceNotFoundException {
+        if (name == null)
+            throw newIllegalArgumentException("Null ObjectName");
+        if (name.getDomain().equals("")) {
+            String defaultDomain = getDefaultDomain();
+            try {
+                // XXX change to ObjectName.switchDomain
+                // current code DOES NOT PRESERVE the order of keys
+                name = new ObjectName(defaultDomain, name.getKeyPropertyList());
+            } catch (Exception e) {
+                throw newIllegalArgumentException(
+                        "Illegal default domain: " + defaultDomain);
+            }
+        }
+        final DynamicMBean mbean = getDynamicMBeanFor(name);
+        if (mbean!=null) return mbean;
+        throw new InstanceNotFoundException(String.valueOf(name));
+    }
+
+    static RuntimeException newUnsupportedException(String operation) {
+        return new RuntimeOperationsException(
+            new UnsupportedOperationException(
+                operation+": Not supported in this namespace"));
+    }
+
+    static RuntimeException newIllegalArgumentException(String msg) {
+        return new RuntimeOperationsException(
+                new IllegalArgumentException(msg));
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/jmx/interceptor/SingleMBeanForwarder.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,414 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.jmx.interceptor;
+
+import com.sun.jmx.mbeanserver.Util;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Set;
+import java.util.TreeSet;
+import javax.management.Attribute;
+import javax.management.AttributeList;
+import javax.management.AttributeNotFoundException;
+import javax.management.DynamicMBean;
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.InstanceNotFoundException;
+import javax.management.IntrospectionException;
+import javax.management.InvalidAttributeValueException;
+import javax.management.ListenerNotFoundException;
+import javax.management.MBeanException;
+import javax.management.MBeanInfo;
+import javax.management.MBeanRegistrationException;
+import javax.management.MBeanServer;
+import javax.management.NotCompliantMBeanException;
+import javax.management.NotificationEmitter;
+import javax.management.NotificationFilter;
+import javax.management.NotificationListener;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.QueryExp;
+import javax.management.ReflectionException;
+import javax.management.remote.IdentityMBeanServerForwarder;
+
+public class SingleMBeanForwarder extends IdentityMBeanServerForwarder {
+
+    private final ObjectName mbeanName;
+    private DynamicMBean mbean;
+
+    private MBeanServer mbeanMBS = new MBeanServerSupport() {
+
+        @Override
+        public DynamicMBean getDynamicMBeanFor(ObjectName name)
+                throws InstanceNotFoundException {
+            if (mbeanName.equals(name)) {
+                return mbean;
+            } else {
+                throw new InstanceNotFoundException(name.toString());
+            }
+        }
+
+        @Override
+        protected Set<ObjectName> getNames() {
+            return Collections.singleton(mbeanName);
+        }
+
+        @Override
+        public NotificationEmitter getNotificationEmitterFor(
+                ObjectName name) {
+            if (mbean instanceof NotificationEmitter)
+                return (NotificationEmitter) mbean;
+            return null;
+        }
+
+    };
+
+    public SingleMBeanForwarder(ObjectName mbeanName, DynamicMBean mbean) {
+        this.mbeanName = mbeanName;
+        setSingleMBean(mbean);
+    }
+
+    protected void setSingleMBean(DynamicMBean mbean) {
+        this.mbean = mbean;
+    }
+
+    @Override
+    public void addNotificationListener(ObjectName name, ObjectName listener,
+                                         NotificationFilter filter,
+                                         Object handback)
+            throws InstanceNotFoundException {
+        if (mbeanName.equals(name))
+            mbeanMBS.addNotificationListener(name, listener, filter, handback);
+        else
+            super.addNotificationListener(name, listener, filter, handback);
+    }
+
+    @Override
+    public void addNotificationListener(ObjectName name,
+                                         NotificationListener listener,
+                                         NotificationFilter filter,
+                                         Object handback)
+            throws InstanceNotFoundException {
+        if (mbeanName.equals(name))
+            mbeanMBS.addNotificationListener(name, listener, filter, handback);
+        else
+            super.addNotificationListener(name, listener, filter, handback);
+    }
+
+    @Override
+    public ObjectInstance createMBean(String className, ObjectName name,
+                                       ObjectName loaderName, Object[] params,
+                                       String[] signature)
+            throws ReflectionException,
+                   InstanceAlreadyExistsException,
+                   MBeanRegistrationException,
+                   MBeanException,
+                   NotCompliantMBeanException,
+                   InstanceNotFoundException {
+        if (mbeanName.equals(name))
+            throw new InstanceAlreadyExistsException(mbeanName.toString());
+        else
+            return super.createMBean(className, name, loaderName, params, signature);
+    }
+
+    @Override
+    public ObjectInstance createMBean(String className, ObjectName name,
+                                       Object[] params, String[] signature)
+            throws ReflectionException, InstanceAlreadyExistsException,
+                   MBeanRegistrationException, MBeanException,
+                   NotCompliantMBeanException {
+        if (mbeanName.equals(name))
+            throw new InstanceAlreadyExistsException(mbeanName.toString());
+        return super.createMBean(className, name, params, signature);
+    }
+
+    @Override
+    public ObjectInstance createMBean(String className, ObjectName name,
+                                       ObjectName loaderName)
+            throws ReflectionException,
+                   InstanceAlreadyExistsException,
+                   MBeanRegistrationException,
+                   MBeanException,
+                   NotCompliantMBeanException,
+                   InstanceNotFoundException {
+        if (mbeanName.equals(name))
+            throw new InstanceAlreadyExistsException(mbeanName.toString());
+        return super.createMBean(className, name, loaderName);
+    }
+
+    @Override
+    public ObjectInstance createMBean(String className, ObjectName name)
+            throws ReflectionException,
+                   InstanceAlreadyExistsException,
+                   MBeanRegistrationException,
+                   MBeanException,
+                   NotCompliantMBeanException {
+        if (mbeanName.equals(name))
+            throw new InstanceAlreadyExistsException(mbeanName.toString());
+        return super.createMBean(className, name);
+    }
+
+    @Override
+    public Object getAttribute(ObjectName name, String attribute)
+            throws MBeanException,
+                   AttributeNotFoundException,
+                   InstanceNotFoundException,
+                   ReflectionException {
+        if (mbeanName.equals(name))
+            return mbeanMBS.getAttribute(name, attribute);
+        else
+            return super.getAttribute(name, attribute);
+    }
+
+    @Override
+    public AttributeList getAttributes(ObjectName name, String[] attributes)
+            throws InstanceNotFoundException, ReflectionException {
+        if (mbeanName.equals(name))
+            return mbeanMBS.getAttributes(name, attributes);
+        else
+            return super.getAttributes(name, attributes);
+    }
+
+    @Override
+    public ClassLoader getClassLoader(ObjectName loaderName)
+            throws InstanceNotFoundException {
+        if (mbeanName.equals(loaderName))
+            return mbeanMBS.getClassLoader(loaderName);
+        else
+            return super.getClassLoader(loaderName);
+    }
+
+    @Override
+    public ClassLoader getClassLoaderFor(ObjectName name)
+            throws InstanceNotFoundException {
+        if (mbeanName.equals(name))
+            return mbeanMBS.getClassLoaderFor(name);
+        else
+            return super.getClassLoaderFor(name);
+    }
+
+    @Override
+    public String[] getDomains() {
+        TreeSet<String> domainSet =
+                new TreeSet<String>(Arrays.asList(super.getDomains()));
+        domainSet.add(mbeanName.getDomain());
+        return domainSet.toArray(new String[domainSet.size()]);
+    }
+
+    @Override
+    public Integer getMBeanCount() {
+        Integer count = super.getMBeanCount();
+        if (!super.isRegistered(mbeanName))
+            count++;
+        return count;
+    }
+
+    @Override
+    public MBeanInfo getMBeanInfo(ObjectName name)
+            throws InstanceNotFoundException,
+                   IntrospectionException,
+                   ReflectionException {
+        if (mbeanName.equals(name))
+            return mbeanMBS.getMBeanInfo(name);
+        else
+            return super.getMBeanInfo(name);
+    }
+
+    @Override
+    public ObjectInstance getObjectInstance(ObjectName name)
+            throws InstanceNotFoundException {
+        if (mbeanName.equals(name))
+            return mbeanMBS.getObjectInstance(name);
+        else
+            return super.getObjectInstance(name);
+    }
+
+    @Override
+    public Object invoke(ObjectName name, String operationName, Object[] params,
+                          String[] signature)
+            throws InstanceNotFoundException,
+                   MBeanException,
+                   ReflectionException {
+        if (mbeanName.equals(name))
+            return mbeanMBS.invoke(name, operationName, params, signature);
+        else
+            return super.invoke(name, operationName, params, signature);
+    }
+
+    @Override
+    public boolean isInstanceOf(ObjectName name, String className)
+            throws InstanceNotFoundException {
+        if (mbeanName.equals(name))
+            return mbeanMBS.isInstanceOf(name, className);
+        else
+            return super.isInstanceOf(name, className);
+    }
+
+    @Override
+    public boolean isRegistered(ObjectName name) {
+        if (mbeanName.equals(name))
+            return true;
+        else
+            return super.isRegistered(name);
+    }
+
+    /**
+     * This is a ugly hack. Although jmx.context//*:* matches jmx.context//:*
+     * queryNames(jmx.context//*:*,null) must not return jmx.context//:*
+     * @param  pattern the pattern to match against. must not be null.
+     * @return true if mbeanName can be included, false if it must not.
+     */
+    private boolean applies(ObjectName pattern) {
+        // we know pattern is not null.
+        if (!pattern.apply(mbeanName))
+            return false;
+
+//        final String dompat = pattern.getDomain();
+//        if (!dompat.contains(JMXNamespaces.NAMESPACE_SEPARATOR))
+//            return true; // We already checked that patterns apply.
+//
+//        if (mbeanName.getDomain().endsWith(JMXNamespaces.NAMESPACE_SEPARATOR)) {
+//            // only matches if pattern ends with //
+//            return dompat.endsWith(JMXNamespaces.NAMESPACE_SEPARATOR);
+//        }
+
+        // should not come here, unless mbeanName contains a // in the
+        // middle of its domain, which would be weird.
+        // let query on mbeanMBS proceed and take care of that.
+        //
+        return true;
+    }
+
+    @Override
+    public Set<ObjectInstance> queryMBeans(ObjectName name, QueryExp query) {
+        Set<ObjectInstance> names = super.queryMBeans(name, query);
+        if (name == null || applies(name) ) {
+            // Don't assume mbs.queryNames returns a writable set.
+            names = Util.cloneSet(names);
+            names.addAll(mbeanMBS.queryMBeans(name, query));
+        }
+        return names;
+    }
+
+    @Override
+    public Set<ObjectName> queryNames(ObjectName name, QueryExp query) {
+        Set<ObjectName> names = super.queryNames(name, query);
+        if (name == null || applies(name)) {
+            // Don't assume mbs.queryNames returns a writable set.
+            names = Util.cloneSet(names);
+            names.addAll(mbeanMBS.queryNames(name, query));
+        }
+        return names;
+    }
+
+
+    @Override
+    public ObjectInstance registerMBean(Object object, ObjectName name)
+            throws InstanceAlreadyExistsException,
+                   MBeanRegistrationException,
+                   NotCompliantMBeanException {
+        if (mbeanName.equals(name))
+            throw new InstanceAlreadyExistsException(mbeanName.toString());
+        else
+            return super.registerMBean(object, name);
+    }
+
+    @Override
+    public void removeNotificationListener(ObjectName name,
+                                            NotificationListener listener,
+                                            NotificationFilter filter,
+                                            Object handback)
+            throws InstanceNotFoundException,
+                   ListenerNotFoundException {
+        if (mbeanName.equals(name))
+            mbeanMBS.removeNotificationListener(name, listener, filter, handback);
+        else
+            super.removeNotificationListener(name, listener, filter, handback);
+    }
+
+    @Override
+    public void removeNotificationListener(ObjectName name,
+                                            NotificationListener listener)
+            throws InstanceNotFoundException, ListenerNotFoundException {
+        if (mbeanName.equals(name))
+            mbeanMBS.removeNotificationListener(name, listener);
+        else
+            super.removeNotificationListener(name, listener);
+    }
+
+    @Override
+    public void removeNotificationListener(ObjectName name, ObjectName listener,
+                                            NotificationFilter filter,
+                                            Object handback)
+            throws InstanceNotFoundException,
+                   ListenerNotFoundException {
+        if (mbeanName.equals(name))
+            mbeanMBS.removeNotificationListener(name, listener, filter, handback);
+        else
+            super.removeNotificationListener(name, listener, filter, handback);
+    }
+
+    @Override
+    public void removeNotificationListener(ObjectName name, ObjectName listener)
+            throws InstanceNotFoundException, ListenerNotFoundException {
+        if (mbeanName.equals(name))
+            mbeanMBS.removeNotificationListener(name, listener);
+        else
+            super.removeNotificationListener(name, listener);
+    }
+
+    @Override
+    public void setAttribute(ObjectName name, Attribute attribute)
+            throws InstanceNotFoundException,
+                   AttributeNotFoundException,
+                   InvalidAttributeValueException,
+                   MBeanException,
+                   ReflectionException {
+        if (mbeanName.equals(name))
+            mbeanMBS.setAttribute(name, attribute);
+        else
+            super.setAttribute(name, attribute);
+    }
+
+    @Override
+    public AttributeList setAttributes(ObjectName name,
+                                        AttributeList attributes)
+            throws InstanceNotFoundException, ReflectionException {
+        if (mbeanName.equals(name))
+            return mbeanMBS.setAttributes(name, attributes);
+        else
+            return super.setAttributes(name, attributes);
+    }
+
+    @Override
+    public void unregisterMBean(ObjectName name)
+            throws InstanceNotFoundException,
+                   MBeanRegistrationException {
+        if (mbeanName.equals(name))
+            mbeanMBS.unregisterMBean(name);
+        else
+            super.unregisterMBean(name);
+    }
+}
--- a/jdk/src/share/classes/com/sun/jmx/interceptor/package.html	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/src/share/classes/com/sun/jmx/interceptor/package.html	Wed Jul 05 16:40:29 2017 +0200
@@ -29,5 +29,8 @@
 </head>
 <body bgcolor="white">
     Provides specific classes to <B>Sun JMX Reference Implementation</B>.
+ <p><b>
+ This API is a Sun internal API and is subject to changes without notice.
+ </b></p>
 </BODY>
 </HTML>
--- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/DefaultMXBeanMappingFactory.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/DefaultMXBeanMappingFactory.java	Wed Jul 05 16:40:29 2017 +0200
@@ -825,7 +825,7 @@
             final TabularData table = (TabularData) openValue;
             final Collection<CompositeData> rows = cast(table.values());
             final Map<Object, Object> valueMap =
-                sortedMap ? newSortedMap() : newMap();
+                sortedMap ? newSortedMap() : newInsertionOrderMap();
             for (CompositeData row : rows) {
                 final Object key =
                     keyMapping.fromOpenValue(row.get("key"));
--- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanInjector.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanInjector.java	Wed Jul 05 16:40:29 2017 +0200
@@ -172,7 +172,7 @@
          * reference.
          *
          * So we accept a Field if it has a @Resource annotation and either
-         * (a) its type is ObjectName or a subclass and its @Resource type is
+         * (a) its type is exactly ObjectName and its @Resource type is
          * compatible with ObjectName (e.g. it is Object); or
          * (b) its type is compatible with ObjectName and its @Resource type
          * is exactly ObjectName.  Fields that meet these criteria will not
--- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanSupport.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanSupport.java	Wed Jul 05 16:40:29 2017 +0200
@@ -25,7 +25,6 @@
 
 package com.sun.jmx.mbeanserver;
 
-import static com.sun.jmx.mbeanserver.Util.*;
 
 import javax.management.Attribute;
 import javax.management.AttributeList;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/PerThreadGroupPool.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,71 @@
+/*
+ * Copyright 1999-2007 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.jmx.mbeanserver;
+
+import java.lang.ref.WeakReference;
+import java.util.concurrent.ThreadPoolExecutor;
+
+/**
+ * <p>A factory for ThreadPoolExecutor objects that allows the same object to
+ * be shared by all users of the factory that are in the same ThreadGroup.</p>
+ */
+// We return a ThreadPoolExecutor rather than the more general ExecutorService
+// because we need to be able to call allowCoreThreadTimeout so that threads in
+// the pool will eventually be destroyed when the pool is no longer in use.
+// Otherwise these threads would keep the ThreadGroup alive forever.
+public class PerThreadGroupPool<T extends ThreadPoolExecutor> {
+    private final WeakIdentityHashMap<ThreadGroup, WeakReference<T>> map =
+            WeakIdentityHashMap.make();
+
+    public static interface Create<T extends ThreadPoolExecutor> {
+        public T createThreadPool(ThreadGroup group);
+    }
+
+    private PerThreadGroupPool() {}
+
+    public static <T extends ThreadPoolExecutor> PerThreadGroupPool<T> make() {
+        return new PerThreadGroupPool<T>();
+    }
+
+    public synchronized T getThreadPoolExecutor(Create<T> create) {
+        // Find out if there's already an existing executor for the calling
+        // thread and reuse it. Otherwise, create a new one and store it in
+        // the executors map. If there is a SecurityManager, the group of
+        // System.getSecurityManager() is used, else the group of the calling
+        // thread.
+        SecurityManager s = System.getSecurityManager();
+        ThreadGroup group = (s != null) ? s.getThreadGroup() :
+            Thread.currentThread().getThreadGroup();
+        WeakReference<T> wr = map.get(group);
+        T executor = (wr == null) ? null : wr.get();
+        if (executor == null) {
+            executor = create.createThreadPool(group);
+            executor.allowCoreThreadTimeOut(true);
+            map.put(group, new WeakReference<T>(executor));
+        }
+        return executor;
+    }
+}
--- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/Util.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/Util.java	Wed Jul 05 16:40:29 2017 +0200
@@ -38,10 +38,13 @@
 import java.util.Map;
 import java.util.Set;
 import java.util.SortedMap;
+import java.util.SortedSet;
 import java.util.TreeMap;
+import java.util.TreeSet;
 import java.util.WeakHashMap;
 import javax.management.MalformedObjectNameException;
 import javax.management.ObjectName;
+import javax.management.loading.ClassLoaderRepository;
 
 public class Util {
     static <K, V> Map<K, V> newMap() {
@@ -142,4 +145,97 @@
         return hash;
     }
 
+    /**
+     * Filters a set of ObjectName according to a given pattern.
+     *
+     * @param pattern the pattern that the returned names must match.
+     * @param all     the set of names to filter.
+     * @return a set of ObjectName from which non matching names
+     *         have been removed.
+     */
+    public static Set<ObjectName> filterMatchingNames(ObjectName pattern,
+                                        Set<ObjectName> all) {
+        // If no pattern, just return all names
+        if (pattern == null
+                || all.isEmpty()
+                || ObjectName.WILDCARD.equals(pattern))
+            return all;
+
+        // If there's a pattern, do the matching.
+        final Set<ObjectName> res = equivalentEmptySet(all);
+        for (ObjectName n : all) if (pattern.apply(n)) res.add(n);
+        return res;
+    }
+
+    /**
+     * An abstract ClassLoaderRepository that contains a single class loader.
+     **/
+    private final static class SingleClassLoaderRepository
+            implements ClassLoaderRepository {
+        private final ClassLoader singleLoader;
+
+        SingleClassLoaderRepository(ClassLoader loader) {
+            this.singleLoader = loader;
+        }
+
+        ClassLoader getSingleClassLoader() {
+           return singleLoader;
+        }
+
+        private Class<?> loadClass(String className, ClassLoader loader)
+                throws ClassNotFoundException {
+            return Class.forName(className, false, loader);
+        }
+
+        public Class<?> loadClass(String className)
+                throws ClassNotFoundException {
+            return loadClass(className, getSingleClassLoader());
+        }
+
+        public Class<?> loadClassWithout(ClassLoader exclude,
+                String className) throws ClassNotFoundException {
+            final ClassLoader loader = getSingleClassLoader();
+            if (exclude != null && exclude.equals(loader))
+                throw new ClassNotFoundException(className);
+            return loadClass(className, loader);
+        }
+
+        public Class<?> loadClassBefore(ClassLoader stop, String className)
+                throws ClassNotFoundException {
+            return loadClassWithout(stop, className);
+        }
+    }
+
+    /**
+     * Returns a ClassLoaderRepository that contains a single class loader.
+     * @param loader the class loader contained in the returned repository.
+     * @return a ClassLoaderRepository that contains the single loader.
+     */
+    public static ClassLoaderRepository getSingleClassLoaderRepository(
+            final ClassLoader loader) {
+        return new SingleClassLoaderRepository(loader);
+    }
+
+    public static <T> Set<T> cloneSet(Set<T> set) {
+        if (set instanceof SortedSet) {
+            @SuppressWarnings("unchecked")
+            SortedSet<T> sset = (SortedSet<T>) set;
+            set = new TreeSet<T>(sset.comparator());
+            set.addAll(sset);
+        } else
+            set = new HashSet<T>(set);
+        return set;
+    }
+
+    public static <T> Set<T> equivalentEmptySet(Set<T> set) {
+        if (set instanceof SortedSet) {
+            @SuppressWarnings("unchecked")
+            SortedSet<T> sset = (SortedSet<T>) set;
+            set = new TreeSet<T>(sset.comparator());
+        } else if (set != null) {
+            set = new HashSet<T>(set.size());
+        } else
+            set = new HashSet<T>();
+        return set;
+    }
 }
--- a/jdk/src/share/classes/com/sun/jmx/remote/internal/ClientNotifForwarder.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/src/share/classes/com/sun/jmx/remote/internal/ClientNotifForwarder.java	Wed Jul 05 16:40:29 2017 +0200
@@ -576,6 +576,7 @@
             int notFoundCount = 0;
 
             NotificationResult result = null;
+            long firstEarliest = -1;
 
             while (result == null && !shouldStop()) {
                 NotificationResult nr;
@@ -598,6 +599,8 @@
                     return null;
 
                 startSequenceNumber = nr.getNextSequenceNumber();
+                if (firstEarliest < 0)
+                    firstEarliest = nr.getEarliestSequenceNumber();
 
                 try {
                     // 1 notif to skip possible missing class
@@ -628,6 +631,17 @@
                     (notFoundCount == 1 ? "" : "s") +
                     " because classes were missing locally";
                 lostNotifs(msg, notFoundCount);
+                // Even if result.getEarliestSequenceNumber() is now greater than
+                // it was initially, meaning some notifs have been dropped
+                // from the buffer, we don't want the caller to see that
+                // because it is then likely to renotify about the lost notifs.
+                // So we put back the first value of earliestSequenceNumber
+                // that we saw.
+                if (result != null) {
+                    result = new NotificationResult(
+                            firstEarliest, result.getNextSequenceNumber(),
+                            result.getTargetedNotifications());
+                }
             }
 
             return result;
--- a/jdk/src/share/classes/com/sun/jmx/remote/internal/ProxyInputStream.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/src/share/classes/com/sun/jmx/remote/internal/ProxyInputStream.java	Wed Jul 05 16:40:29 2017 +0200
@@ -33,10 +33,8 @@
 import org.omg.CORBA.Context;
 import org.omg.CORBA.NO_IMPLEMENT;
 import org.omg.CORBA.ORB;
-import org.omg.CORBA.Principal;
 import org.omg.CORBA.TypeCode;
 import org.omg.CORBA.portable.BoxedValueHelper;
-import org.omg.CORBA_2_3.portable.InputStream;
 
 @SuppressWarnings("deprecation")
 public class ProxyInputStream extends org.omg.CORBA_2_3.portable.InputStream {
@@ -160,54 +158,71 @@
         return in.read_any();
     }
 
-    public Principal read_Principal() {
+    /**
+     * @deprecated
+     */
+    @Override
+    @Deprecated
+    public org.omg.CORBA.Principal read_Principal() {
         return in.read_Principal();
     }
 
+    @Override
     public int read() throws IOException {
         return in.read();
     }
 
+    @Override
     public BigDecimal read_fixed() {
         return in.read_fixed();
     }
 
+    @Override
     public Context read_Context() {
         return in.read_Context();
     }
 
+    @Override
     public org.omg.CORBA.Object read_Object(java.lang.Class clz) {
         return in.read_Object(clz);
     }
 
+    @Override
     public ORB orb() {
         return in.orb();
     }
 
+    @Override
     public Serializable read_value() {
         return narrow().read_value();
     }
 
+    @Override
     public Serializable read_value(Class clz) {
         return narrow().read_value(clz);
     }
 
+    @Override
     public Serializable read_value(BoxedValueHelper factory) {
         return narrow().read_value(factory);
     }
 
+    @Override
     public Serializable read_value(String rep_id) {
         return narrow().read_value(rep_id);
     }
 
+    @Override
     public Serializable read_value(Serializable value) {
         return narrow().read_value(value);
     }
 
+    @Override
     public Object read_abstract_interface() {
         return narrow().read_abstract_interface();
     }
 
+    @Override
     public Object read_abstract_interface(Class clz) {
         return narrow().read_abstract_interface(clz);
     }
--- a/jdk/src/share/classes/com/sun/jmx/remote/internal/ProxyRef.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/src/share/classes/com/sun/jmx/remote/internal/ProxyRef.java	Wed Jul 05 16:40:29 2017 +0200
@@ -31,8 +31,6 @@
 import java.lang.reflect.Method;
 import java.rmi.Remote;
 import java.rmi.RemoteException;
-import java.rmi.server.Operation;
-import java.rmi.server.RemoteCall;
 import java.rmi.server.RemoteObject;
 import java.rmi.server.RemoteRef;
 
@@ -54,7 +52,11 @@
         ref.writeExternal(out);
     }
 
-    public void invoke(RemoteCall call) throws Exception {
+    /**
+     * @deprecated
+     */
+    @Deprecated
+    public void invoke(java.rmi.server.RemoteCall call) throws Exception {
         ref.invoke(call);
     }
 
@@ -63,7 +65,11 @@
         return ref.invoke(obj, method, params, opnum);
     }
 
-    public void done(RemoteCall call) throws RemoteException {
+    /**
+     * @deprecated
+     */
+    @Deprecated
+    public void done(java.rmi.server.RemoteCall call) throws RemoteException {
         ref.done(call);
     }
 
@@ -71,7 +77,12 @@
         return ref.getRefClass(out);
     }
 
-    public RemoteCall newCall(RemoteObject obj, Operation[] op, int opnum,
+    /**
+     * @deprecated
+     */
+    @Deprecated
+    public java.rmi.server.RemoteCall newCall(RemoteObject obj,
+            java.rmi.server.Operation[] op, int opnum,
                               long hash) throws RemoteException {
         return ref.newCall(obj, op, opnum, hash);
     }
--- a/jdk/src/share/classes/com/sun/jmx/remote/internal/ServerNotifForwarder.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/src/share/classes/com/sun/jmx/remote/internal/ServerNotifForwarder.java	Wed Jul 05 16:40:29 2017 +0200
@@ -25,16 +25,16 @@
 
 package com.sun.jmx.remote.internal;
 
+import com.sun.jmx.mbeanserver.Util;
 import com.sun.jmx.remote.security.NotificationAccessController;
 import com.sun.jmx.remote.util.ClassLogger;
 import com.sun.jmx.remote.util.EnvHelp;
 import java.io.IOException;
 import java.security.AccessControlContext;
 import java.security.AccessController;
+import java.security.PrivilegedAction;
 import java.security.PrivilegedActionException;
 import java.security.PrivilegedExceptionAction;
-import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -67,9 +67,9 @@
         connectionTimeout = EnvHelp.getServerConnectionTimeout(env);
         checkNotificationEmission = EnvHelp.computeBooleanFromString(
             env,
-            "jmx.remote.x.check.notification.emission");
-        notificationAccessController = (NotificationAccessController)
-            env.get("com.sun.jmx.remote.notification.access.controller");
+            "jmx.remote.x.check.notification.emission",false);
+        notificationAccessController =
+                EnvHelp.getNotificationAccessController(env);
     }
 
     public Integer addNotificationListener(final ObjectName name,
@@ -88,9 +88,7 @@
         checkMBeanPermission(name, "addNotificationListener");
         if (notificationAccessController != null) {
             notificationAccessController.addNotificationListener(
-                connectionId,
-                name,
-                Subject.getSubject(AccessController.getContext()));
+                connectionId, name, getSubject());
         }
         try {
             boolean instanceOf =
@@ -160,9 +158,7 @@
         checkMBeanPermission(name, "removeNotificationListener");
         if (notificationAccessController != null) {
             notificationAccessController.removeNotificationListener(
-                connectionId,
-                name,
-                Subject.getSubject(AccessController.getContext()));
+                connectionId, name, getSubject());
         }
 
         Exception re = null;
@@ -312,6 +308,10 @@
     // PRIVATE METHODS
     //----------------
 
+    private Subject getSubject() {
+        return Subject.getSubject(AccessController.getContext());
+    }
+
     private void checkState() throws IOException {
         synchronized(terminationLock) {
             if (terminated) {
@@ -332,7 +332,13 @@
      */
     private void checkMBeanPermission(final ObjectName name,
         final String actions)
-        throws InstanceNotFoundException, SecurityException {
+            throws InstanceNotFoundException, SecurityException {
+        checkMBeanPermission(mbeanServer, name, actions);
+    }
+
+    public static void checkMBeanPermission(
+            final MBeanServer mbs, final ObjectName name, final String actions)
+            throws InstanceNotFoundException, SecurityException {
         SecurityManager sm = System.getSecurityManager();
         if (sm != null) {
             AccessControlContext acc = AccessController.getContext();
@@ -342,7 +348,7 @@
                     new PrivilegedExceptionAction<ObjectInstance>() {
                         public ObjectInstance run()
                         throws InstanceNotFoundException {
-                            return mbeanServer.getObjectInstance(name);
+                            return mbs.getObjectInstance(name);
                         }
                 });
             } catch (PrivilegedActionException e) {
@@ -364,14 +370,12 @@
                                               TargetedNotification tn) {
         try {
             if (checkNotificationEmission) {
-                checkMBeanPermission(name, "addNotificationListener");
+                checkMBeanPermission(
+                        name, "addNotificationListener");
             }
             if (notificationAccessController != null) {
                 notificationAccessController.fetchNotification(
-                        connectionId,
-                        name,
-                        tn.getNotification(),
-                        Subject.getSubject(AccessController.getContext()));
+                        connectionId, name, tn.getNotification(), getSubject());
             }
             return true;
         } catch (SecurityException e) {
--- a/jdk/src/share/classes/com/sun/jmx/remote/security/FileLoginModule.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/src/share/classes/com/sun/jmx/remote/security/FileLoginModule.java	Wed Jul 05 16:40:29 2017 +0200
@@ -25,6 +25,7 @@
 
 package com.sun.jmx.remote.security;
 
+import com.sun.jmx.mbeanserver.GetPropertyAction;
 import java.io.BufferedInputStream;
 import java.io.File;
 import java.io.FileInputStream;
@@ -47,8 +48,6 @@
 import com.sun.jmx.remote.util.EnvHelp;
 import sun.management.jmxremote.ConnectorBootstrap;
 
-import sun.security.action.GetPropertyAction;
-
 /**
  * This {@link LoginModule} performs file-based authentication.
  *
@@ -479,7 +478,7 @@
             if (userSuppliedPasswordFile || hasJavaHomePermission) {
                 throw e;
             } else {
-                FilePermission fp =
+                final FilePermission fp =
                         new FilePermission(passwordFileDisplayName, "read");
                 AccessControlException ace = new AccessControlException(
                         "access denied " + fp.toString());
@@ -488,10 +487,13 @@
             }
         }
         try {
-            BufferedInputStream bis = new BufferedInputStream(fis);
-            userCredentials = new Properties();
-            userCredentials.load(bis);
-            bis.close();
+            final BufferedInputStream bis = new BufferedInputStream(fis);
+            try {
+                userCredentials = new Properties();
+                userCredentials.load(bis);
+            } finally {
+                bis.close();
+            }
         } finally {
             fis.close();
         }
--- a/jdk/src/share/classes/com/sun/jmx/remote/util/EnvHelp.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/src/share/classes/com/sun/jmx/remote/util/EnvHelp.java	Wed Jul 05 16:40:29 2017 +0200
@@ -40,9 +40,6 @@
 import java.util.TreeSet;
 
 import java.security.AccessController;
-import java.security.PrivilegedAction;
-import java.security.PrivilegedActionException;
-import java.security.PrivilegedExceptionAction;
 
 import javax.management.ObjectName;
 import javax.management.MBeanServer;
@@ -50,6 +47,9 @@
 import javax.management.remote.JMXConnectorFactory;
 import javax.management.remote.JMXConnectorServerFactory;
 import com.sun.jmx.mbeanserver.GetPropertyAction;
+import com.sun.jmx.remote.security.NotificationAccessController;
+import javax.management.remote.JMXConnector;
+import javax.management.remote.JMXConnectorServer;
 
 public class EnvHelp {
 
@@ -346,7 +346,24 @@
      */
     public static long getFetchTimeout(Map env) {
         return getIntegerAttribute(env, FETCH_TIMEOUT, 60000L, 0,
-                                   Long.MAX_VALUE);
+                Long.MAX_VALUE);
+    }
+
+    /**
+     * <p>Name of the attribute that specifies an object that will check
+     * accesses to add/removeNotificationListener and also attempts to
+     * receive notifications.  The value associated with this attribute
+     * should be a <code>NotificationAccessController</code> object.
+     * The default value is null.</p>
+     * This field is not public because of its com.sun dependency.
+     */
+    public static final String NOTIF_ACCESS_CONTROLLER =
+            "com.sun.jmx.remote.notification.access.controller";
+
+    public static NotificationAccessController getNotificationAccessController(
+            Map env) {
+        return (env == null) ? null :
+            (NotificationAccessController) env.get(NOTIF_ACCESS_CONTROLLER);
     }
 
     /**
@@ -470,24 +487,24 @@
     }
 
     /**
-       The value of this attribute, if present, is a string specifying
-       what other attributes should not appear in
-       JMXConnectorServer.getAttributes().  It is a space-separated
-       list of attribute patterns, where each pattern is either an
-       attribute name, or an attribute prefix followed by a "*"
-       character.  The "*" has no special significance anywhere except
-       at the end of a pattern.  By default, this list is added to the
-       list defined by {@link #DEFAULT_HIDDEN_ATTRIBUTES} (which
-       uses the same format).  If the value of this attribute begins
-       with an "=", then the remainder of the string defines the
-       complete list of attribute patterns.
+     * The value of this attribute, if present, is a string specifying
+     * what other attributes should not appear in
+     * JMXConnectorServer.getAttributes().  It is a space-separated
+     * list of attribute patterns, where each pattern is either an
+     * attribute name, or an attribute prefix followed by a "*"
+     * character.  The "*" has no special significance anywhere except
+     * at the end of a pattern.  By default, this list is added to the
+     * list defined by {@link #DEFAULT_HIDDEN_ATTRIBUTES} (which
+     * uses the same format).  If the value of this attribute begins
+     * with an "=", then the remainder of the string defines the
+     * complete list of attribute patterns.
      */
     public static final String HIDDEN_ATTRIBUTES =
         "jmx.remote.x.hidden.attributes";
 
     /**
-       Default list of attributes not to show.
-       @see #HIDDEN_ATTRIBUTES
+     * Default list of attributes not to show.
+     * @see #HIDDEN_ATTRIBUTES
      */
     /* This list is copied directly from the spec, plus
        java.naming.security.*.  Most of the attributes here would have
@@ -651,6 +668,8 @@
      * @param env the environment map.
      * @param prop the name of the property in the environment map whose
      * returned string value must be converted into a boolean value.
+     * @param systemProperty if true, consult a system property of the
+     * same name if there is no entry in the environment map.
      *
      * @return
      *   <ul>
@@ -671,16 +690,73 @@
      * @throws ClassCastException if {@code env.get(prop)} cannot be cast
      * to {@code String}.
      */
-    public static boolean computeBooleanFromString(Map env, String prop)
-        throws IllegalArgumentException, ClassCastException {
+    public static boolean computeBooleanFromString(
+            Map env, String prop, boolean systemProperty) {
+
+        if (env == null)
+            throw new IllegalArgumentException("env map cannot be null");
+
+        // returns a default value of 'false' if no property is found...
+        return computeBooleanFromString(env,prop,systemProperty,false);
+    }
+
+    /**
+     * Computes a boolean value from a string value retrieved from a
+     * property in the given map.
+     *
+     * @param env the environment map.
+     * @param prop the name of the property in the environment map whose
+     * returned string value must be converted into a boolean value.
+     * @param systemProperty if true, consult a system property of the
+     * same name if there is no entry in the environment map.
+     * @param defaultValue a default value to return in case no property
+     *        was defined.
+     *
+     * @return
+     *   <ul>
+     *   <li>{@code defaultValue} if {@code env.get(prop)} is {@code null}
+     *       and {@code systemProperty} is {@code false}</li>
+     *   <li>{@code defaultValue} if {@code env.get(prop)} is {@code null}
+     *       and {@code systemProperty} is {@code true} and
+     *       {@code System.getProperty(prop)} is {@code null}</li>
+     *   <li>{@code false} if {@code env.get(prop)} is {@code null}
+     *       and {@code systemProperty} is {@code true} and
+     *       {@code System.getProperty(prop).equalsIgnoreCase("false")}
+     *       is {@code true}</li>
+     *   <li>{@code true} if {@code env.get(prop)} is {@code null}
+     *       and {@code systemProperty} is {@code true} and
+     *       {@code System.getProperty(prop).equalsIgnoreCase("true")}
+     *       is {@code true}</li>
+     *   <li>{@code false} if
+     *       {@code ((String)env.get(prop)).equalsIgnoreCase("false")}
+     *       is {@code true}</li>
+     *   <li>{@code true} if
+     *       {@code ((String)env.get(prop)).equalsIgnoreCase("true")}
+     *       is {@code true}</li>
+     *   </ul>
+     *
+     * @throws IllegalArgumentException if {@code env} is {@code null} or
+     * {@code env.get(prop)} is not {@code null} and
+     * {@code ((String)env.get(prop)).equalsIgnoreCase("false")} and
+     * {@code ((String)env.get(prop)).equalsIgnoreCase("true")} are
+     * {@code false}.
+     * @throws ClassCastException if {@code env.get(prop)} cannot be cast
+     * to {@code String}.
+     */
+    public static boolean computeBooleanFromString(
+            Map env, String prop, boolean systemProperty, boolean defaultValue) {
 
         if (env == null)
             throw new IllegalArgumentException("env map cannot be null");
 
         String stringBoolean = (String) env.get(prop);
+        if (stringBoolean == null && systemProperty) {
+            stringBoolean =
+                    AccessController.doPrivileged(new GetPropertyAction(prop));
+        }
 
         if (stringBoolean == null)
-            return false;
+            return defaultValue;
         else if (stringBoolean.equalsIgnoreCase("true"))
             return true;
         else if (stringBoolean.equalsIgnoreCase("false"))
@@ -703,6 +779,65 @@
         return new Hashtable<K, V>(m);
     }
 
+    /**
+     * Returns true if the parameter JMXConnector.USE_EVENT_SERVICE is set to a
+     * String equals "true" by ignoring case in the map or in the System.
+     */
+    public static boolean eventServiceEnabled(Map env) {
+        return computeBooleanFromString(env, JMXConnector.USE_EVENT_SERVICE, true);
+    }
+
+    /**
+     * Returns true if the parameter JMXConnectorServer.DELEGATE_TO_EVENT_SERVICE
+     * is set to a String equals "true" (ignores case).
+     * If the property DELEGATE_TO_EVENT_SERVICE is not set, returns
+     * a default value of "true".
+     */
+    public static boolean delegateToEventService(Map env) {
+        return computeBooleanFromString(env,
+                JMXConnectorServer.DELEGATE_TO_EVENT_SERVICE, true, true);
+    }
+
+//    /**
+//     * <p>Name of the attribute that specifies an EventRelay object to use.
+//     */
+//    public static final String EVENT_RELAY =
+//            "jmx.remote.x.event.relay";
+//
+//
+//    /**
+//     * Returns an EventRelay object. The default one is FetchingEventRelay.
+//     * If {@code EVENT_RELAY} is specified in {@code env} as a key,
+//     * its value will be returned as an EventRelay object, if the value is
+//     * not of type {@code EventRelay}, the default {@code FetchingEventRelay}
+//     * will be returned.
+//     * If {@code EVENT_RELAY} is not specified but {@code ENABLE_EVENT_RELAY}
+//     * is specified as a key and its value is <code true>, the default {@code FetchingEventRelay}
+//     * will be returned.
+//     */
+//    public static EventRelay getEventRelay(Map env) {
+//        Map info = env == null ?
+//            Collections.EMPTY_MAP : env;
+//
+//        Object o = env.get(EVENT_RELAY);
+//        if (o instanceof EventRelay) {
+//            return (EventRelay)o;
+//        } else if (o != null) {
+//            logger.warning("getEventRelay",
+//                    "The user specified object is not an EventRelay object, " +
+//                    "using the default class FetchingEventRelay.");
+//
+//            return new FetchingEventRelay();
+//        }
+//
+//        if (enableEventRelay(env)) {
+//            return new FetchingEventRelay();
+//        }
+//
+//        return null;
+//    }
+
+
     private static final class SinkOutputStream extends OutputStream {
         public void write(byte[] b, int off, int len) {}
         public void write(int b) {}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/jmx/remote/util/EventClientConnection.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,471 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.jmx.remote.util;
+
+import com.sun.jmx.event.EventClientFactory;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.Arrays;
+import java.util.concurrent.Callable;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.management.MBeanServerConnection;
+import javax.management.NotificationFilter;
+import javax.management.NotificationListener;
+import javax.management.ObjectName;
+import javax.management.event.EventClient;
+import javax.management.event.EventClientDelegate;
+
+/**
+ * Class EventClientConnection - a {@link Proxy} that wraps an
+ * {@link MBeanServerConnection} and an {@link EventClient}.
+ * All methods are routed to the underlying {@code MBeanServerConnection},
+ * except add/remove notification listeners which are routed to the
+ * {@code EventClient}.
+ * The caller only sees an {@code MBeanServerConnection} which uses an
+ * {@code EventClient} behind the scenes.
+ *
+ * @author Sun Microsystems, Inc.
+ */
+public class EventClientConnection implements InvocationHandler,
+        EventClientFactory {
+
+    /**
+     * A logger for this class.
+     **/
+    private static final Logger LOG =
+            Logger.getLogger(EventClientConnection.class.getName());
+
+    private static final String NAMESPACE_SEPARATOR = "//";
+    private static final int NAMESPACE_SEPARATOR_LENGTH =
+            NAMESPACE_SEPARATOR.length();
+
+    /**
+     * Creates a new {@code EventClientConnection}.
+     * @param  connection The underlying MBeanServerConnection.
+     */
+    public EventClientConnection(MBeanServerConnection connection) {
+        this(connection,null);
+    }
+
+    /**
+     * Creates a new {@code EventClientConnection}.
+     * @param connection The underlying MBeanServerConnection.
+     * @param eventClientFactory a factory object that will be invoked
+     *        to create an {@link EventClient} when needed.
+     *        The {@code EventClient} is created lazily, when it is needed
+     *        for the first time. If null, a default factory will be used
+     *        (see {@link #createEventClient}).
+     */
+    public EventClientConnection(MBeanServerConnection connection,
+                                 Callable<EventClient> eventClientFactory) {
+
+        if (connection == null) {
+            throw new IllegalArgumentException("Null connection");
+        }
+        this.connection = connection;
+        if (eventClientFactory == null) {
+            eventClientFactory = new Callable<EventClient>() {
+                public final EventClient call() throws Exception {
+                    return createEventClient(EventClientConnection.this.connection);
+                }
+            };
+        }
+        this.eventClientFactory = eventClientFactory;
+        this.lock = new ReentrantLock();
+     }
+
+    /**
+     * <p>The MBean server connection through which the methods of
+     * a proxy using this handler are forwarded.</p>
+     *
+     * @return the MBean server connection.
+     *
+     * @since 1.6
+     */
+    public MBeanServerConnection getMBeanServerConnection() {
+        return connection;
+    }
+
+
+
+
+    /**
+     * Creates a new EventClientConnection proxy instance.
+     *
+     * @param <T> The underlying {@code MBeanServerConnection} - which should
+     *        not be using the Event Service itself.
+     * @param interfaceClass {@code MBeanServerConnection.class}, or a subclass.
+     * @param eventClientFactory a factory used to create the EventClient.
+     *        If null, a default factory is used (see {@link
+     *        #createEventClient}).
+     * @return the new proxy instance, which will route add/remove notification
+     *         listener calls through an {@code EventClient}.
+     *
+     */
+    private static <T extends MBeanServerConnection> T
+            newProxyInstance(T connection,
+            Class<T> interfaceClass, Callable<EventClient> eventClientFactory) {
+        final InvocationHandler handler =
+                new EventClientConnection(connection,eventClientFactory);
+        final Class[] interfaces =
+                new Class[] {interfaceClass, EventClientFactory.class};
+
+        Object proxy =
+                Proxy.newProxyInstance(interfaceClass.getClassLoader(),
+                interfaces,
+                handler);
+        return interfaceClass.cast(proxy);
+    }
+
+
+    public Object invoke(Object proxy, Method method, Object[] args)
+            throws Throwable {
+        final String methodName = method.getName();
+
+        // add/remove notification listener are routed to the EventClient
+        if (methodName.equals("addNotificationListener")
+            || methodName.equals("removeNotificationListener")) {
+            final Class[] sig = method.getParameterTypes();
+            if (sig.length>1 &&
+                    NotificationListener.class.isAssignableFrom(sig[1])) {
+                return invokeBroadcasterMethod(proxy,method,args);
+            }
+        }
+
+        // subscribe/unsubscribe are also routed to the EventClient.
+        final Class clazz = method.getDeclaringClass();
+        if (clazz.equals(EventClientFactory.class)) {
+            return invokeEventClientSubscriberMethod(proxy,method,args);
+        }
+
+        // local or not: equals, toString, hashCode
+        if (shouldDoLocally(proxy, method))
+            return doLocally(proxy, method, args);
+
+        return call(connection,method,args);
+    }
+
+    // The purpose of this method is to unwrap InvocationTargetException,
+    // in order to avoid throwing UndeclaredThrowableException for
+    // declared exceptions.
+    //
+    // When calling method.invoke(), any exception thrown by the invoked
+    // method will be wrapped in InvocationTargetException. If we don't
+    // unwrap this exception, the proxy will always throw
+    // UndeclaredThrowableException, even for runtime exceptions.
+    //
+    private Object call(final Object obj, final Method m,
+            final Object[] args)
+        throws Throwable {
+        try {
+            return m.invoke(obj,args);
+        } catch (InvocationTargetException x) {
+            final Throwable xx = x.getTargetException();
+            if (xx == null) throw x;
+            else throw xx;
+        }
+    }
+
+    /**
+     * Route add/remove notification listener to the event client.
+     **/
+    private Object invokeBroadcasterMethod(Object proxy, Method method,
+                                           Object[] args) throws Exception {
+        final String methodName = method.getName();
+        final int nargs = (args == null) ? 0 : args.length;
+
+        if (nargs < 1) {
+           final String msg =
+                    "Bad arg count: " + nargs;
+           throw new IllegalArgumentException(msg);
+        }
+
+        final ObjectName mbean = (ObjectName) args[0];
+        final EventClient client = getEventClient();
+
+        // Fails if client is null AND the MBean we try to listen to is
+        // in a subnamespace. We fail here because we know this will not
+        // work.
+        //
+        // Note that if the wrapped MBeanServerConnection points to a an
+        // earlier agent (JDK 1.6 or earlier), then the EventClient will
+        // be null (we can't use the event service with earlier JDKs).
+        //
+        // In principle a null client indicates that the remote VM is of
+        // an earlier version, in which case it shouldn't contain any namespace.
+        //
+        // So having a null client AND an MBean contained in a namespace is
+        // clearly an error case.
+        //
+        if (client == null) {
+            final String domain = mbean.getDomain();
+            final int index = domain.indexOf(NAMESPACE_SEPARATOR);
+            if (index > -1 && index <
+                    (domain.length()-NAMESPACE_SEPARATOR_LENGTH)) {
+                throw new UnsupportedOperationException(method.getName()+
+                        " on namespace "+domain.substring(0,index+
+                        NAMESPACE_SEPARATOR_LENGTH));
+            }
+        }
+
+        if (methodName.equals("addNotificationListener")) {
+            /* The various throws of IllegalArgumentException here
+               should not happen, since we know what the methods in
+               NotificationBroadcaster and NotificationEmitter
+               are.  */
+            if (nargs != 4) {
+                final String msg =
+                    "Bad arg count to addNotificationListener: " + nargs;
+                throw new IllegalArgumentException(msg);
+            }
+            /* Other inconsistencies will produce ClassCastException
+               below.  */
+
+            final NotificationListener listener = (NotificationListener) args[1];
+            final NotificationFilter filter = (NotificationFilter) args[2];
+            final Object handback = args[3];
+
+            if (client != null) {
+                // general case
+                client.addNotificationListener(mbean,listener,filter,handback);
+            } else {
+                // deprecated case. Only works for mbean in local namespace.
+                connection.addNotificationListener(mbean,listener,filter,
+                                                   handback);
+            }
+            return null;
+
+        } else if (methodName.equals("removeNotificationListener")) {
+
+            /* NullPointerException if method with no args, but that
+               shouldn't happen because removeNL does have args.  */
+            NotificationListener listener = (NotificationListener) args[1];
+
+            switch (nargs) {
+            case 2:
+                if (client != null) {
+                    // general case
+                    client.removeNotificationListener(mbean,listener);
+                } else {
+                    // deprecated case. Only works for mbean in local namespace.
+                    connection.removeNotificationListener(mbean, listener);
+                }
+                return null;
+
+            case 4:
+                NotificationFilter filter = (NotificationFilter) args[2];
+                Object handback = args[3];
+                if (client != null) {
+                    client.removeNotificationListener(mbean,
+                                                      listener,
+                                                      filter,
+                                                      handback);
+                } else {
+                    connection.removeNotificationListener(mbean,
+                                                      listener,
+                                                      filter,
+                                                      handback);
+                }
+                return null;
+
+            default:
+                final String msg =
+                    "Bad arg count to removeNotificationListener: " + nargs;
+                throw new IllegalArgumentException(msg);
+            }
+
+        } else {
+            throw new IllegalArgumentException("Bad method name: " +
+                                               methodName);
+        }
+    }
+
+    private boolean shouldDoLocally(Object proxy, Method method) {
+        final String methodName = method.getName();
+        if ((methodName.equals("hashCode") || methodName.equals("toString"))
+            && method.getParameterTypes().length == 0
+                && isLocal(proxy, method))
+            return true;
+        if (methodName.equals("equals")
+            && Arrays.equals(method.getParameterTypes(),
+                new Class[] {Object.class})
+                && isLocal(proxy, method))
+            return true;
+        return false;
+    }
+
+    private Object doLocally(Object proxy, Method method, Object[] args) {
+        final String methodName = method.getName();
+
+        if (methodName.equals("equals")) {
+
+            if (this == args[0]) {
+                return true;
+            }
+
+            if (!(args[0] instanceof Proxy)) {
+                return false;
+            }
+
+            final InvocationHandler ihandler =
+                Proxy.getInvocationHandler(args[0]);
+
+            if (ihandler == null ||
+                !(ihandler instanceof EventClientConnection)) {
+                return false;
+            }
+
+            final EventClientConnection handler =
+                (EventClientConnection)ihandler;
+
+            return connection.equals(handler.connection) &&
+                proxy.getClass().equals(args[0].getClass());
+        } else if (methodName.equals("hashCode")) {
+            return connection.hashCode();
+        }
+
+        throw new RuntimeException("Unexpected method name: " + methodName);
+    }
+
+    private static boolean isLocal(Object proxy, Method method) {
+        final Class<?>[] interfaces = proxy.getClass().getInterfaces();
+        if(interfaces == null) {
+            return true;
+        }
+
+        final String methodName = method.getName();
+        final Class<?>[] params = method.getParameterTypes();
+        for (Class<?> intf : interfaces) {
+            try {
+                intf.getMethod(methodName, params);
+                return false; // found method in one of our interfaces
+            } catch (NoSuchMethodException nsme) {
+                // OK.
+            }
+        }
+
+        return true;  // did not find in any interface
+    }
+
+    /**
+     * Return the EventClient used by this object. Can be null if the
+     * remote VM is of an earlier JDK version which doesn't have the
+     * event service.<br>
+     * This method will invoke the event client factory the first time
+     * it is called.
+     **/
+    public final EventClient getEventClient()  {
+        if (initialized) return client;
+        try {
+            if (!lock.tryLock(TRYLOCK_TIMEOUT,TimeUnit.SECONDS))
+                throw new IllegalStateException("can't acquire lock");
+            try {
+                client = eventClientFactory.call();
+                initialized = true;
+            } finally {
+                lock.unlock();
+            }
+        } catch (RuntimeException x) {
+            throw x;
+        } catch (Exception x) {
+            throw new IllegalStateException("Can't create EventClient: "+x,x);
+        }
+        return client;
+    }
+
+    /**
+     * Returns an event client for the wrapped {@code MBeanServerConnection}.
+     * This is the method invoked by the default event client factory.
+     * @param connection the  wrapped {@code MBeanServerConnection}.
+     **/
+    protected EventClient createEventClient(MBeanServerConnection connection)
+        throws Exception {
+        final ObjectName name =
+           EventClientDelegate.OBJECT_NAME;
+        if (connection.isRegistered(name)) {
+            return new EventClient(connection);
+        }
+        return null;
+    }
+
+    /**
+     * Creates a new {@link MBeanServerConnection} that goes through an
+     * {@link EventClient} to receive/subscribe to notifications.
+     * @param connection the underlying {@link MBeanServerConnection}.
+     *        The given <code>connection</code> shouldn't be already
+     *        using an {@code EventClient}.
+     * @param eventClientFactory a factory object that will be invoked
+     *        to create an {@link EventClient} when needed.
+     *        The {@code EventClient} is created lazily, when it is needed
+     *        for the first time. If null, a default factory will be used
+     *        (see {@link #createEventClient}).
+     * @return the
+     **/
+    public static MBeanServerConnection getEventConnectionFor(
+                    MBeanServerConnection connection,
+                    Callable<EventClient> eventClientFactory) {
+        // if c already uses an EventClient no need to create a new one.
+        //
+        if (connection instanceof EventClientFactory
+            && eventClientFactory != null)
+            throw new IllegalArgumentException("connection already uses EventClient");
+
+        if (connection instanceof EventClientFactory)
+            return connection;
+
+        // create a new proxy using an event client.
+        //
+        if (LOG.isLoggable(Level.FINE))
+            LOG.fine("Creating EventClient for: "+connection);
+        return newProxyInstance(connection,
+                MBeanServerConnection.class,
+                eventClientFactory);
+    }
+
+    private Object invokeEventClientSubscriberMethod(Object proxy,
+            Method method, Object[] args) throws Throwable {
+        return call(this,method,args);
+    }
+
+    // Maximum lock timeout in seconds. Obviously arbitrary.
+    //
+    private final static short TRYLOCK_TIMEOUT = 3;
+
+    private final MBeanServerConnection connection;
+    private final Callable<EventClient> eventClientFactory;
+    private final Lock lock;
+    private volatile EventClient client = null;
+    private volatile boolean initialized = false;
+
+}
--- a/jdk/src/share/classes/com/sun/jmx/snmp/tasks/ThreadService.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/src/share/classes/com/sun/jmx/snmp/tasks/ThreadService.java	Wed Jul 05 16:40:29 2017 +0200
@@ -45,15 +45,9 @@
         minThreads = threadNumber;
         threadList = new ExecutorThread[threadNumber];
 
-//      for (int i=0; i<threadNumber; i++) {
-//          threadList[i] = new ExecutorThread();
-//          threadList[i].start();
-//      }
-
         priority = Thread.currentThread().getPriority();
         cloader = Thread.currentThread().getContextClassLoader();
 
-//System.out.println("---jsl: ThreadService: running threads = "+threadNumber);
     }
 
 // public methods
@@ -89,7 +83,6 @@
 
         synchronized(jobList) {
             jobList.add(jobList.size(), task);
-//System.out.println("jsl-ThreadService: added job "+addedJobs++);
 
             jobList.notify();
         }
@@ -196,8 +189,6 @@
                     try {
                         idle--;
                         job.run();
-//System.out.println("jsl-ThreadService: done job "+doneJobs++);
-
                     } catch (Exception e) {
                         // TODO
                         e.printStackTrace();
@@ -228,7 +219,6 @@
                     ExecutorThread et = new ExecutorThread();
                     et.start();
                     threadList[currThreds++] = et;
-//System.out.println("jsl-ThreadService: create new thread: "+currThreds);
                 }
             }
         }
--- a/jdk/src/share/classes/java/util/Timer.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/src/share/classes/java/util/Timer.java	Wed Jul 05 16:40:29 2017 +0200
@@ -25,6 +25,7 @@
 
 package java.util;
 import java.util.Date;
+import java.util.concurrent.atomic.AtomicInteger;
 
 /**
  * A facility for threads to schedule tasks for future execution in a
@@ -92,12 +93,12 @@
      * and the timer thread consumes, executing timer tasks as appropriate,
      * and removing them from the queue when they're obsolete.
      */
-    private TaskQueue queue = new TaskQueue();
+    private final TaskQueue queue = new TaskQueue();
 
     /**
      * The timer thread.
      */
-    private TimerThread thread = new TimerThread(queue);
+    private final TimerThread thread = new TimerThread(queue);
 
     /**
      * This object causes the timer's task execution thread to exit
@@ -106,7 +107,7 @@
      * Timer as such a finalizer would be susceptible to a subclass's
      * finalizer forgetting to call it.
      */
-    private Object threadReaper = new Object() {
+    private final Object threadReaper = new Object() {
         protected void finalize() throws Throwable {
             synchronized(queue) {
                 thread.newTasksMayBeScheduled = false;
@@ -116,12 +117,11 @@
     };
 
     /**
-     * This ID is used to generate thread names.  (It could be replaced
-     * by an AtomicInteger as soon as they become available.)
+     * This ID is used to generate thread names.
      */
-    private static int nextSerialNumber = 0;
-    private static synchronized int serialNumber() {
-        return nextSerialNumber++;
+    private final static AtomicInteger nextSerialNumber = new AtomicInteger(0);
+    private static int serialNumber() {
+        return nextSerialNumber.getAndIncrement();
     }
 
     /**
@@ -387,6 +387,11 @@
         if (time < 0)
             throw new IllegalArgumentException("Illegal execution time.");
 
+        // Constrain value of period sufficiently to prevent numeric
+        // overflow while still being effectively infinitely large.
+        if (Math.abs(period) > (Long.MAX_VALUE >> 1))
+            period >>= 1;
+
         synchronized(queue) {
             if (!thread.newTasksMayBeScheduled)
                 throw new IllegalStateException("Timer already cancelled.");
--- a/jdk/src/share/classes/java/util/concurrent/ScheduledThreadPoolExecutor.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/src/share/classes/java/util/concurrent/ScheduledThreadPoolExecutor.java	Wed Jul 05 16:40:29 2017 +0200
@@ -223,8 +223,7 @@
         }
 
         public long getDelay(TimeUnit unit) {
-            long d = unit.convert(time - now(), TimeUnit.NANOSECONDS);
-            return d;
+            return unit.convert(time - now(), TimeUnit.NANOSECONDS);
         }
 
         public int compareTo(Delayed other) {
@@ -264,7 +263,7 @@
             if (p > 0)
                 time += p;
             else
-                time = now() - p;
+                time = triggerTime(-p);
         }
 
         public boolean cancel(boolean mayInterruptIfRunning) {
@@ -473,6 +472,38 @@
     }
 
     /**
+     * Returns the trigger time of a delayed action.
+     */
+    private long triggerTime(long delay, TimeUnit unit) {
+        return triggerTime(unit.toNanos((delay < 0) ? 0 : delay));
+    }
+
+    /**
+     * Returns the trigger time of a delayed action.
+     */
+    long triggerTime(long delay) {
+        return now() +
+            ((delay < (Long.MAX_VALUE >> 1)) ? delay : overflowFree(delay));
+    }
+
+    /**
+     * Constrains the values of all delays in the queue to be within
+     * Long.MAX_VALUE of each other, to avoid overflow in compareTo.
+     * This may occur if a task is eligible to be dequeued, but has
+     * not yet been, while some other task is added with a delay of
+     * Long.MAX_VALUE.
+     */
+    private long overflowFree(long delay) {
+        Delayed head = (Delayed) super.getQueue().peek();
+        if (head != null) {
+            long headDelay = head.getDelay(TimeUnit.NANOSECONDS);
+            if (headDelay < 0 && (delay - headDelay < 0))
+                delay = Long.MAX_VALUE + headDelay;
+        }
+        return delay;
+    }
+
+    /**
      * @throws RejectedExecutionException {@inheritDoc}
      * @throws NullPointerException       {@inheritDoc}
      */
@@ -481,10 +512,9 @@
                                        TimeUnit unit) {
         if (command == null || unit == null)
             throw new NullPointerException();
-        if (delay < 0) delay = 0;
-        long triggerTime = now() + unit.toNanos(delay);
         RunnableScheduledFuture<?> t = decorateTask(command,
-            new ScheduledFutureTask<Void>(command, null, triggerTime));
+            new ScheduledFutureTask<Void>(command, null,
+                                          triggerTime(delay, unit)));
         delayedExecute(t);
         return t;
     }
@@ -498,10 +528,9 @@
                                            TimeUnit unit) {
         if (callable == null || unit == null)
             throw new NullPointerException();
-        if (delay < 0) delay = 0;
-        long triggerTime = now() + unit.toNanos(delay);
         RunnableScheduledFuture<V> t = decorateTask(callable,
-            new ScheduledFutureTask<V>(callable, triggerTime));
+            new ScheduledFutureTask<V>(callable,
+                                       triggerTime(delay, unit)));
         delayedExecute(t);
         return t;
     }
@@ -519,12 +548,10 @@
             throw new NullPointerException();
         if (period <= 0)
             throw new IllegalArgumentException();
-        if (initialDelay < 0) initialDelay = 0;
-        long triggerTime = now() + unit.toNanos(initialDelay);
         ScheduledFutureTask<Void> sft =
             new ScheduledFutureTask<Void>(command,
                                           null,
-                                          triggerTime,
+                                          triggerTime(initialDelay, unit),
                                           unit.toNanos(period));
         RunnableScheduledFuture<Void> t = decorateTask(command, sft);
         sft.outerTask = t;
@@ -545,12 +572,10 @@
             throw new NullPointerException();
         if (delay <= 0)
             throw new IllegalArgumentException();
-        if (initialDelay < 0) initialDelay = 0;
-        long triggerTime = now() + unit.toNanos(initialDelay);
         ScheduledFutureTask<Void> sft =
             new ScheduledFutureTask<Void>(command,
                                           null,
-                                          triggerTime,
+                                          triggerTime(initialDelay, unit),
                                           unit.toNanos(-delay));
         RunnableScheduledFuture<Void> t = decorateTask(command, sft);
         sft.outerTask = t;
--- a/jdk/src/share/classes/javax/management/ImmutableDescriptor.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/src/share/classes/javax/management/ImmutableDescriptor.java	Wed Jul 05 16:40:29 2017 +0200
@@ -128,13 +128,13 @@
      * @throws InvalidObjectException if the read object has invalid fields.
      */
     private Object readResolve() throws InvalidObjectException {
-        if (names.length == 0 && getClass() == ImmutableDescriptor.class)
-            return EMPTY_DESCRIPTOR;
 
         boolean bad = false;
         if (names == null || values == null || names.length != values.length)
             bad = true;
         if (!bad) {
+            if (names.length == 0 && getClass() == ImmutableDescriptor.class)
+                return EMPTY_DESCRIPTOR;
             final Comparator<String> compare = String.CASE_INSENSITIVE_ORDER;
             String lastName = ""; // also catches illegal null name
             for (int i = 0; i < names.length; i++) {
--- a/jdk/src/share/classes/javax/management/MBeanRegistration.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/src/share/classes/javax/management/MBeanRegistration.java	Wed Jul 05 16:40:29 2017 +0200
@@ -158,7 +158,19 @@
     /**
      * Allows the MBean to perform any operations needed after having been
      * registered in the MBean server or after the registration has failed.
-     *
+     * <p>If the implementation of this method throws a {@link RuntimeException}
+     * or an {@link Error}, the MBean Server will rethrow those inside
+     * a {@link RuntimeMBeanException} or {@link RuntimeErrorException},
+     * respectively. However, throwing an exception in {@code postRegister}
+     * will not change the state of the MBean:
+     * if the MBean was already registered ({@code registrationDone} is
+     * {@code true}), the MBean will remain registered. </p>
+     * <p>This might be confusing for the code calling {@code createMBean()}
+     * or {@code registerMBean()}, as such code might assume that MBean
+     * registration has failed when such an exception is raised.
+     * Therefore it is recommended that implementations of
+     * {@code postRegister} do not throw Runtime Exceptions or Errors if it
+     * can be avoided.</p>
      * @param registrationDone Indicates whether or not the MBean has
      * been successfully registered in the MBean server. The value
      * false means that the registration phase has failed.
@@ -178,6 +190,17 @@
     /**
      * Allows the MBean to perform any operations needed after having been
      * unregistered in the MBean server.
+     * <p>If the implementation of this method throws a {@link RuntimeException}
+     * or an {@link Error}, the MBean Server will rethrow those inside
+     * a {@link RuntimeMBeanException} or {@link RuntimeErrorException},
+     * respectively. However, throwing an excepption in {@code postDeregister}
+     * will not change the state of the MBean:
+     * the MBean was already successfully deregistered and will remain so. </p>
+     * <p>This might be confusing for the code calling
+     * {@code unregisterMBean()}, as it might assume that MBean deregistration
+     * has failed. Therefore it is recommended that implementations of
+     * {@code postDeregister} do not throw Runtime Exceptions or Errors if it
+     * can be avoided.</p>
      */
     public void postDeregister();
 
--- a/jdk/src/share/classes/javax/management/MBeanServer.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/src/share/classes/javax/management/MBeanServer.java	Wed Jul 05 16:40:29 2017 +0200
@@ -50,8 +50,8 @@
  * server.  A Java object cannot be registered in the MBean server
  * unless it is a JMX compliant MBean.</p>
  *
- * <p id="notif">When an MBean is registered or unregistered in the MBean server
- * a {@link javax.management.MBeanServerNotification
+ * <p id="notif">When an MBean is registered or unregistered in the
+ * MBean server a {@link javax.management.MBeanServerNotification
  * MBeanServerNotification} Notification is emitted. To register an
  * object as listener to MBeanServerNotifications you should call the
  * MBean server method {@link #addNotificationListener
@@ -262,6 +262,8 @@
      * {@inheritDoc}
      * <p>If this method successfully creates an MBean, a notification
      * is sent as described <a href="#notif">above</a>.</p>
+     *
+     * @throws RuntimeOperationsException {@inheritDoc}
      */
     public ObjectInstance createMBean(String className, ObjectName name)
             throws ReflectionException, InstanceAlreadyExistsException,
@@ -272,6 +274,8 @@
      * {@inheritDoc}
      * <p>If this method successfully creates an MBean, a notification
      * is sent as described <a href="#notif">above</a>.</p>
+     *
+     * @throws RuntimeOperationsException {@inheritDoc}
      */
     public ObjectInstance createMBean(String className, ObjectName name,
                                       ObjectName loaderName)
@@ -283,6 +287,8 @@
      * {@inheritDoc}
      * <p>If this method successfully creates an MBean, a notification
      * is sent as described <a href="#notif">above</a>.</p>
+     *
+     * @throws RuntimeOperationsException {@inheritDoc}
      */
     public ObjectInstance createMBean(String className, ObjectName name,
                                       Object params[], String signature[])
@@ -294,6 +300,8 @@
      * {@inheritDoc}
      * <p>If this method successfully creates an MBean, a notification
      * is sent as described <a href="#notif">above</a>.</p>
+     *
+     * @throws RuntimeOperationsException {@inheritDoc}
      */
     public ObjectInstance createMBean(String className, ObjectName name,
                                       ObjectName loaderName, Object params[],
@@ -328,11 +336,30 @@
      * <CODE>preRegister</CODE> (<CODE>MBeanRegistration</CODE>
      * interface) method of the MBean has thrown an exception. The
      * MBean will not be registered.
+     * @exception RuntimeMBeanException If the <CODE>postRegister</CODE>
+     * (<CODE>MBeanRegistration</CODE> interface) method of the MBean throws a
+     * <CODE>RuntimeException</CODE>, the <CODE>registerMBean<CODE> method will
+     * throw a <CODE>RuntimeMBeanException</CODE>, although the MBean
+     * registration succeeded. In such a case, the MBean will be actually
+     * registered even though the <CODE>registerMBean<CODE> method
+     * threw an exception.  Note that <CODE>RuntimeMBeanException</CODE> can
+     * also be thrown by <CODE>preRegister</CODE>, in which case the MBean
+     * will not be registered.
+     * @exception RuntimeErrorException If the <CODE>postRegister</CODE>
+     * (<CODE>MBeanRegistration</CODE> interface) method of the MBean throws an
+     * <CODE>Error</CODE>, the <CODE>registerMBean<CODE> method will
+     * throw a <CODE>RuntimeErrorException</CODE>, although the MBean
+     * registration succeeded. In such a case, the MBean will be actually
+     * registered even though the <CODE>registerMBean<CODE> method
+     * threw an exception.  Note that <CODE>RuntimeErrorException</CODE> can
+     * also be thrown by <CODE>preRegister</CODE>, in which case the MBean
+     * will not be registered.
      * @exception NotCompliantMBeanException This object is not a JMX
      * compliant MBean
      * @exception RuntimeOperationsException Wraps a
      * <CODE>java.lang.IllegalArgumentException</CODE>: The object
      * passed in parameter is null or no object name is specified.
+     * @see javax.management.MBeanRegistration
      */
     public ObjectInstance registerMBean(Object object, ObjectName name)
             throws InstanceAlreadyExistsException, MBeanRegistrationException,
@@ -343,6 +370,8 @@
      *
      * <p>If this method successfully unregisters an MBean, a notification
      * is sent as described <a href="#notif">above</a>.</p>
+     *
+     * @throws RuntimeOperationsException {@inheritDoc}
      */
     public void unregisterMBean(ObjectName name)
             throws InstanceNotFoundException, MBeanRegistrationException;
@@ -358,6 +387,9 @@
     public Set<ObjectName> queryNames(ObjectName name, QueryExp query);
 
     // doc comment inherited from MBeanServerConnection
+    /**
+     * @throws RuntimeOperationsException {@inheritDoc}
+     */
     public boolean isRegistered(ObjectName name);
 
     /**
@@ -370,21 +402,33 @@
     public Integer getMBeanCount();
 
     // doc comment inherited from MBeanServerConnection
+    /**
+     * @throws RuntimeOperationsException {@inheritDoc}
+     */
     public Object getAttribute(ObjectName name, String attribute)
             throws MBeanException, AttributeNotFoundException,
                    InstanceNotFoundException, ReflectionException;
 
     // doc comment inherited from MBeanServerConnection
+    /**
+     * @throws RuntimeOperationsException {@inheritDoc}
+     */
     public AttributeList getAttributes(ObjectName name, String[] attributes)
             throws InstanceNotFoundException, ReflectionException;
 
     // doc comment inherited from MBeanServerConnection
+    /**
+     * @throws RuntimeOperationsException {@inheritDoc}
+     */
     public void setAttribute(ObjectName name, Attribute attribute)
             throws InstanceNotFoundException, AttributeNotFoundException,
                    InvalidAttributeValueException, MBeanException,
                    ReflectionException;
 
     // doc comment inherited from MBeanServerConnection
+    /**
+     * @throws RuntimeOperationsException {@inheritDoc}
+     */
     public AttributeList setAttributes(ObjectName name,
                                        AttributeList attributes)
         throws InstanceNotFoundException, ReflectionException;
@@ -401,14 +445,23 @@
     // doc comment inherited from MBeanServerConnection
     public String[] getDomains();
 
-    // doc comment inherited from MBeanServerConnection
+    // doc comment inherited from MBeanServerConnection, plus:
+    /**
+     * {@inheritDoc}
+     * If the source of the notification
+     * is a reference to an MBean object, the MBean server will replace it
+     * by that MBean's ObjectName.  Otherwise the source is unchanged.
+     */
     public void addNotificationListener(ObjectName name,
                                         NotificationListener listener,
                                         NotificationFilter filter,
                                         Object handback)
             throws InstanceNotFoundException;
 
-    // doc comment inherited from MBeanServerConnection
+    /**
+     * {@inheritDoc}
+     * @throws RuntimeOperationsException {@inheritDoc}
+     */
     public void addNotificationListener(ObjectName name,
                                         ObjectName listener,
                                         NotificationFilter filter,
--- a/jdk/src/share/classes/javax/management/MBeanServerConnection.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/src/share/classes/javax/management/MBeanServerConnection.java	Wed Jul 05 16:40:29 2017 +0200
@@ -29,6 +29,7 @@
 // java import
 import java.io.IOException;
 import java.util.Set;
+import javax.management.event.NotificationManager;
 
 
 /**
@@ -39,7 +40,7 @@
  *
  * @since 1.5
  */
-public interface MBeanServerConnection {
+public interface MBeanServerConnection extends NotificationManager {
     /**
      * <p>Instantiates and registers an MBean in the MBean server.  The
      * MBean server will use its {@link
@@ -75,6 +76,24 @@
      * <CODE>preRegister</CODE> (<CODE>MBeanRegistration</CODE>
      * interface) method of the MBean has thrown an exception. The
      * MBean will not be registered.
+     * @exception RuntimeMBeanException If the <CODE>postRegister</CODE>
+     * (<CODE>MBeanRegistration</CODE> interface) method of the MBean throws a
+     * <CODE>RuntimeException</CODE>, the <CODE>createMBean<CODE> method will
+     * throw a <CODE>RuntimeMBeanException</CODE>, although the MBean creation
+     * and registration succeeded. In such a case, the MBean will be actually
+     * registered even though the <CODE>createMBean<CODE> method
+     * threw an exception. Note that <CODE>RuntimeMBeanException</CODE> can
+     * also be thrown by <CODE>preRegister</CODE>, in which case the MBean
+     * will not be registered.
+     * @exception RuntimeErrorException If the <CODE>postRegister</CODE>
+     * (<CODE>MBeanRegistration</CODE> interface) method of the MBean throws an
+     * <CODE>Error</CODE>, the <CODE>createMBean<CODE> method will
+     * throw a <CODE>RuntimeErrorException</CODE>, although the MBean creation
+     * and registration succeeded. In such a case, the MBean will be actually
+     * registered even though the <CODE>createMBean<CODE> method
+     * threw an exception.  Note that <CODE>RuntimeErrorException</CODE> can
+     * also be thrown by <CODE>preRegister</CODE>, in which case the MBean
+     * will not be registered.
      * @exception MBeanException The constructor of the MBean has
      * thrown an exception
      * @exception NotCompliantMBeanException This class is not a JMX
@@ -86,7 +105,7 @@
      * is specified for the MBean.
      * @exception IOException A communication problem occurred when
      * talking to the MBean server.
-     *
+     * @see javax.management.MBeanRegistration
      */
     public ObjectInstance createMBean(String className, ObjectName name)
             throws ReflectionException, InstanceAlreadyExistsException,
@@ -129,6 +148,24 @@
      * <CODE>preRegister</CODE> (<CODE>MBeanRegistration</CODE>
      * interface) method of the MBean has thrown an exception. The
      * MBean will not be registered.
+     * @exception RuntimeMBeanException If the <CODE>postRegister</CODE>
+     * (<CODE>MBeanRegistration</CODE> interface) method of the MBean throws a
+     * <CODE>RuntimeException</CODE>, the <CODE>createMBean<CODE> method will
+     * throw a <CODE>RuntimeMBeanException</CODE>, although the MBean creation
+     * and registration succeeded. In such a case, the MBean will be actually
+     * registered even though the <CODE>createMBean<CODE> method
+     * threw an exception.  Note that <CODE>RuntimeMBeanException</CODE> can
+     * also be thrown by <CODE>preRegister</CODE>, in which case the MBean
+     * will not be registered.
+     * @exception RuntimeErrorException If the <CODE>postRegister</CODE>
+     * (<CODE>MBeanRegistration</CODE> interface) method of the MBean throws an
+     * <CODE>Error</CODE>, the <CODE>createMBean<CODE> method will
+     * throw a <CODE>RuntimeErrorException</CODE>, although the MBean creation
+     * and registration succeeded. In such a case, the MBean will be actually
+     * registered even though the <CODE>createMBean<CODE> method
+     * threw an exception.  Note that <CODE>RuntimeErrorException</CODE> can
+     * also be thrown by <CODE>preRegister</CODE>, in which case the MBean
+     * will not be registered.
      * @exception MBeanException The constructor of the MBean has
      * thrown an exception
      * @exception NotCompliantMBeanException This class is not a JMX
@@ -142,6 +179,7 @@
      * is specified for the MBean.
      * @exception IOException A communication problem occurred when
      * talking to the MBean server.
+     * @see javax.management.MBeanRegistration
      */
     public ObjectInstance createMBean(String className, ObjectName name,
                                       ObjectName loaderName)
@@ -185,6 +223,24 @@
      * <CODE>preRegister</CODE> (<CODE>MBeanRegistration</CODE>
      * interface) method of the MBean has thrown an exception. The
      * MBean will not be registered.
+     * @exception RuntimeMBeanException If the <CODE>postRegister</CODE>
+     * (<CODE>MBeanRegistration</CODE> interface) method of the MBean throws a
+     * <CODE>RuntimeException</CODE>, the <CODE>createMBean<CODE> method will
+     * throw a <CODE>RuntimeMBeanException</CODE>, although the MBean creation
+     * and registration succeeded. In such a case, the MBean will be actually
+     * registered even though the <CODE>createMBean<CODE> method
+     * threw an exception.  Note that <CODE>RuntimeMBeanException</CODE> can
+     * also be thrown by <CODE>preRegister</CODE>, in which case the MBean
+     * will not be registered.
+     * @exception RuntimeErrorException If the <CODE>postRegister</CODE>
+     * (<CODE>MBeanRegistration</CODE> interface) method of the MBean throws an
+     * <CODE>Error</CODE>, the <CODE>createMBean<CODE> method will
+     * throw a <CODE>RuntimeErrorException</CODE>, although the MBean creation
+     * and registration succeeded. In such a case, the MBean will be actually
+     * registered even though the <CODE>createMBean<CODE> method
+     * threw an exception.  Note that <CODE>RuntimeErrorException</CODE> can
+     * also be thrown by <CODE>preRegister</CODE>, in which case the MBean
+     * will not be registered.
      * @exception MBeanException The constructor of the MBean has
      * thrown an exception
      * @exception NotCompliantMBeanException This class is not a JMX
@@ -196,7 +252,7 @@
      * is specified for the MBean.
      * @exception IOException A communication problem occurred when
      * talking to the MBean server.
-     *
+     * @see javax.management.MBeanRegistration
      */
     public ObjectInstance createMBean(String className, ObjectName name,
                                       Object params[], String signature[])
@@ -239,6 +295,24 @@
      * <CODE>preRegister</CODE> (<CODE>MBeanRegistration</CODE>
      * interface) method of the MBean has thrown an exception. The
      * MBean will not be registered.
+     * @exception RuntimeMBeanException If the <CODE>postRegister</CODE>
+     * (<CODE>MBeanRegistration</CODE> interface) method of the MBean throws a
+     * <CODE>RuntimeException</CODE>, the <CODE>createMBean<CODE> method will
+     * throw a <CODE>RuntimeMBeanException</CODE>, although the MBean creation
+     * and registration succeeded. In such a case, the MBean will be actually
+     * registered even though the <CODE>createMBean<CODE> method
+     * threw an exception.  Note that <CODE>RuntimeMBeanException</CODE> can
+     * also be thrown by <CODE>preRegister</CODE>, in which case the MBean
+     * will not be registered.
+     * @exception RuntimeErrorException If the <CODE>postRegister</CODE> method
+     * (<CODE>MBeanRegistration</CODE> interface) method of the MBean throws an
+     * <CODE>Error</CODE>, the <CODE>createMBean<CODE> method will
+     * throw a <CODE>RuntimeErrorException</CODE>, although the MBean creation
+     * and registration succeeded. In such a case, the MBean will be actually
+     * registered even though the <CODE>createMBean<CODE> method
+     * threw an exception.  Note that <CODE>RuntimeErrorException</CODE> can
+     * also be thrown by <CODE>preRegister</CODE>, in which case the MBean
+     * will not be registered.
      * @exception MBeanException The constructor of the MBean has
      * thrown an exception
      * @exception NotCompliantMBeanException This class is not a JMX
@@ -252,7 +326,7 @@
      * is specified for the MBean.
      * @exception IOException A communication problem occurred when
      * talking to the MBean server.
-     *
+     * @see javax.management.MBeanRegistration
      */
     public ObjectInstance createMBean(String className, ObjectName name,
                                       ObjectName loaderName, Object params[],
@@ -275,6 +349,24 @@
      * @exception MBeanRegistrationException The preDeregister
      * ((<CODE>MBeanRegistration</CODE> interface) method of the MBean
      * has thrown an exception.
+     * @exception RuntimeMBeanException If the <CODE>postDeregister</CODE>
+     * (<CODE>MBeanRegistration</CODE> interface) method of the MBean throws a
+     * <CODE>RuntimeException</CODE>, the <CODE>unregisterMBean<CODE> method
+     * will throw a <CODE>RuntimeMBeanException</CODE>, although the MBean
+     * unregistration succeeded. In such a case, the MBean will be actually
+     * unregistered even though the <CODE>unregisterMBean<CODE> method
+     * threw an exception.  Note that <CODE>RuntimeMBeanException</CODE> can
+     * also be thrown by <CODE>preDeregister</CODE>, in which case the MBean
+     * will remain registered.
+     * @exception RuntimeErrorException If the <CODE>postDeregister</CODE>
+     * (<CODE>MBeanRegistration</CODE> interface) method of the MBean throws an
+     * <CODE>Error</CODE>, the <CODE>unregisterMBean<CODE> method will
+     * throw a <CODE>RuntimeErrorException</CODE>, although the MBean
+     * unregistration succeeded. In such a case, the MBean will be actually
+     * unregistered even though the <CODE>unregisterMBean<CODE> method
+     * threw an exception.  Note that <CODE>RuntimeMBeanException</CODE> can
+     * also be thrown by <CODE>preDeregister</CODE>, in which case the MBean
+     * will remain registered.
      * @exception RuntimeOperationsException Wraps a
      * <CODE>java.lang.IllegalArgumentException</CODE>: The object
      * name in parameter is null or the MBean you are when trying to
@@ -282,7 +374,7 @@
      * MBeanServerDelegate} MBean.
      * @exception IOException A communication problem occurred when
      * talking to the MBean server.
-     *
+     * @see javax.management.MBeanRegistration
      */
     public void unregisterMBean(ObjectName name)
             throws InstanceNotFoundException, MBeanRegistrationException,
@@ -585,32 +677,7 @@
     public String[] getDomains()
             throws IOException;
 
-    /**
-     * <p>Adds a listener to a registered MBean.</p>
-     *
-     * <P> A notification emitted by an MBean will be forwarded by the
-     * MBeanServer to the listener.  If the source of the notification
-     * is a reference to an MBean object, the MBean server will replace it
-     * by that MBean's ObjectName.  Otherwise the source is unchanged.
-     *
-     * @param name The name of the MBean on which the listener should
-     * be added.
-     * @param listener The listener object which will handle the
-     * notifications emitted by the registered MBean.
-     * @param filter The filter object. If filter is null, no
-     * filtering will be performed before handling notifications.
-     * @param handback The context to be sent to the listener when a
-     * notification is emitted.
-     *
-     * @exception InstanceNotFoundException The MBean name provided
-     * does not match any of the registered MBeans.
-     * @exception IOException A communication problem occurred when
-     * talking to the MBean server.
-     *
-     * @see #removeNotificationListener(ObjectName, NotificationListener)
-     * @see #removeNotificationListener(ObjectName, NotificationListener,
-     * NotificationFilter, Object)
-     */
+    // doc inherited from NotificationManager
     public void addNotificationListener(ObjectName name,
                                         NotificationListener listener,
                                         NotificationFilter filter,
@@ -727,65 +794,13 @@
             throws InstanceNotFoundException, ListenerNotFoundException,
                    IOException;
 
-
-    /**
-     * <p>Removes a listener from a registered MBean.</p>
-     *
-     * <P> If the listener is registered more than once, perhaps with
-     * different filters or callbacks, this method will remove all
-     * those registrations.
-     *
-     * @param name The name of the MBean on which the listener should
-     * be removed.
-     * @param listener The listener to be removed.
-     *
-     * @exception InstanceNotFoundException The MBean name provided
-     * does not match any of the registered MBeans.
-     * @exception ListenerNotFoundException The listener is not
-     * registered in the MBean.
-     * @exception IOException A communication problem occurred when
-     * talking to the MBean server.
-     *
-     * @see #addNotificationListener(ObjectName, NotificationListener,
-     * NotificationFilter, Object)
-     */
+    // doc inherited from NotificationManager
     public void removeNotificationListener(ObjectName name,
                                            NotificationListener listener)
             throws InstanceNotFoundException, ListenerNotFoundException,
                    IOException;
 
-    /**
-     * <p>Removes a listener from a registered MBean.</p>
-     *
-     * <p>The MBean must have a listener that exactly matches the
-     * given <code>listener</code>, <code>filter</code>, and
-     * <code>handback</code> parameters.  If there is more than one
-     * such listener, only one is removed.</p>
-     *
-     * <p>The <code>filter</code> and <code>handback</code> parameters
-     * may be null if and only if they are null in a listener to be
-     * removed.</p>
-     *
-     * @param name The name of the MBean on which the listener should
-     * be removed.
-     * @param listener The listener to be removed.
-     * @param filter The filter that was specified when the listener
-     * was added.
-     * @param handback The handback that was specified when the
-     * listener was added.
-     *
-     * @exception InstanceNotFoundException The MBean name provided
-     * does not match any of the registered MBeans.
-     * @exception ListenerNotFoundException The listener is not
-     * registered in the MBean, or it is not registered with the given
-     * filter and handback.
-     * @exception IOException A communication problem occurred when
-     * talking to the MBean server.
-     *
-     * @see #addNotificationListener(ObjectName, NotificationListener,
-     * NotificationFilter, Object)
-     *
-     */
+    // doc inherited from NotificationManager
     public void removeNotificationListener(ObjectName name,
                                            NotificationListener listener,
                                            NotificationFilter filter,
--- a/jdk/src/share/classes/javax/management/MBeanServerNotification.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/src/share/classes/javax/management/MBeanServerNotification.java	Wed Jul 05 16:40:29 2017 +0200
@@ -38,56 +38,64 @@
  *
  * @since 1.5
  */
- public class MBeanServerNotification extends Notification   {
-
-
-     /* Serial version */
-     private static final long serialVersionUID = 2876477500475969677L;
-
-     /**
-      * Notification type denoting that an MBean has been registered. Value is "JMX.mbean.registered".
-      */
-     public static final String REGISTRATION_NOTIFICATION = "JMX.mbean.registered" ;
-
-     /**
-      * Notification type denoting that an MBean has been unregistered. Value is "JMX.mbean.unregistered".
-      */
-     public static final String UNREGISTRATION_NOTIFICATION = "JMX.mbean.unregistered" ;
-
-
-     /**
-      * @serial The object names of the MBeans concerned by this notification
-      */
-     private final ObjectName objectName;
+public class MBeanServerNotification extends Notification {
 
 
-     /**
-      * Creates an MBeanServerNotification object specifying object names of
-      * the MBeans that caused the notification and the specified notification type.
-      *
-      * @param type A string denoting the type of the
-      * notification. Set it to one these values: {@link
-      * #REGISTRATION_NOTIFICATION}, {@link
-      * #UNREGISTRATION_NOTIFICATION}.
-      * @param source The MBeanServerNotification object responsible
-      * for forwarding MBean server notification.
-      * @param sequenceNumber A sequence number that can be used to order
-      * received notifications.
-      * @param objectName The object name of the MBean that caused the notification.
-      *
-      */
-     public MBeanServerNotification(String type, Object source, long sequenceNumber, ObjectName objectName ) {
-         super (type,source,sequenceNumber) ;
-         this.objectName =  objectName ;
-     }
+    /* Serial version */
+    private static final long serialVersionUID = 2876477500475969677L;
+    /**
+     * Notification type denoting that an MBean has been registered.
+     * Value is "JMX.mbean.registered".
+     */
+    public static final String REGISTRATION_NOTIFICATION =
+            "JMX.mbean.registered";
+    /**
+     * Notification type denoting that an MBean has been unregistered.
+     * Value is "JMX.mbean.unregistered".
+     */
+    public static final String UNREGISTRATION_NOTIFICATION =
+            "JMX.mbean.unregistered";
+    /**
+     * @serial The object names of the MBeans concerned by this notification
+     */
+    private final ObjectName objectName;
 
-     /**
-      * Returns the  object name of the MBean that caused the notification.
-      *
-      * @return the object name of the MBean that caused the notification.
-      */
-     public ObjectName getMBeanName()  {
-         return objectName ;
-     }
+    /**
+     * Creates an MBeanServerNotification object specifying object names of
+     * the MBeans that caused the notification and the specified notification
+     * type.
+     *
+     * @param type A string denoting the type of the
+     * notification. Set it to one these values: {@link
+     * #REGISTRATION_NOTIFICATION}, {@link
+     * #UNREGISTRATION_NOTIFICATION}.
+     * @param source The MBeanServerNotification object responsible
+     * for forwarding MBean server notification.
+     * @param sequenceNumber A sequence number that can be used to order
+     * received notifications.
+     * @param objectName The object name of the MBean that caused the
+     * notification.
+     *
+     */
+    public MBeanServerNotification(String type, Object source,
+            long sequenceNumber, ObjectName objectName) {
+        super(type, source, sequenceNumber);
+        this.objectName = objectName;
+    }
+
+    /**
+     * Returns the  object name of the MBean that caused the notification.
+     *
+     * @return the object name of the MBean that caused the notification.
+     */
+    public ObjectName getMBeanName() {
+        return objectName;
+    }
+
+    @Override
+    public String toString() {
+        return super.toString() + "[mbeanName=" + objectName + "]";
+
+    }
 
  }
--- a/jdk/src/share/classes/javax/management/MXBean.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/src/share/classes/javax/management/MXBean.java	Wed Jul 05 16:40:29 2017 +0200
@@ -33,7 +33,6 @@
 import java.lang.annotation.Target;
 
 // remaining imports are for Javadoc
-import java.beans.ConstructorProperties;
 import java.io.InvalidObjectException;
 import java.lang.management.MemoryUsage;
 import java.lang.reflect.UndeclaredThrowableException;
@@ -865,7 +864,8 @@
         <em>J</em>.</p></li>
 
       <li><p>Otherwise, if <em>J</em> has at least one public
-        constructor with a {@link ConstructorProperties} annotation, then one
+        constructor with a {@link java.beans.ConstructorProperties
+        ConstructorProperties} annotation, then one
         of those constructors (not necessarily always the same one)
         will be called to reconstruct an instance of <em>J</em>.
         Every such annotation must list as many strings as the
@@ -1081,9 +1081,10 @@
       MXBean is determined as follows.</p>
 
     <ul>
-      <li><p>If an {@link JMX.MBeanOptions} argument is supplied to
+      <li><p>If a {@link JMX.MBeanOptions} argument is supplied to
           the {@link StandardMBean} constructor that makes an MXBean,
-          or to the {@link JMX#newMXBeanProxy JMX.newMXBeanProxy}
+          or to the {@link JMX#newMBeanProxy(MBeanServerConnection,
+          ObjectName, Class, JMX.MBeanOptions) JMX.newMBeanProxy}
           method, and the {@code MBeanOptions} object defines a non-null
           {@code MXBeanMappingFactory}, then that is the value of
           <code><em>f</em></code>.</p></li>
--- a/jdk/src/share/classes/javax/management/ObjectName.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/src/share/classes/javax/management/ObjectName.java	Wed Jul 05 16:40:29 2017 +0200
@@ -38,9 +38,6 @@
 import java.util.HashMap;
 import java.util.Hashtable;
 import java.util.Map;
-import javax.management.MBeanServer;
-import javax.management.MalformedObjectNameException;
-import javax.management.QueryExp;
 
 /**
  * <p>Represents the object name of an MBean, or a pattern that can
@@ -1160,9 +1157,19 @@
             //
             //in.defaultReadObject();
             final ObjectInputStream.GetField fields = in.readFields();
+            String propListString =
+                    (String)fields.get("propertyListString", "");
+
+            // 6616825: take care of property patterns
+            final boolean propPattern =
+                    fields.get("propertyPattern" , false);
+            if (propPattern) {
+                propListString =
+                        (propListString.length()==0?"*":(propListString+",*"));
+            }
+
             cn = (String)fields.get("domain", "default")+
-                ":"+
-                (String)fields.get("propertyListString", "");
+                ":"+ propListString;
         } else {
             // Read an object serialized in the new serial form
             //
@@ -1796,6 +1803,7 @@
      * @return True if <code>object</code> is an ObjectName whose
      * canonical form is equal to that of this ObjectName.
      */
+    @Override
     public boolean equals(Object object)  {
 
         // same object case
@@ -1819,6 +1827,7 @@
      * Returns a hash code for this object name.
      *
      */
+    @Override
     public int hashCode() {
         return _canonicalName.hashCode();
     }
--- a/jdk/src/share/classes/javax/management/QueryParser.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/src/share/classes/javax/management/QueryParser.java	Wed Jul 05 16:40:29 2017 +0200
@@ -312,7 +312,7 @@
             if (e > 0)
                 ss = s.substring(0, e);
             ss = ss.replace("0", "").replace(".", "");
-            if (!ss.isEmpty())
+            if (!ss.equals(""))
                 throw new NumberFormatException("Underflow: " + s);
         }
         return d;
--- a/jdk/src/share/classes/javax/management/StringValueExp.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/src/share/classes/javax/management/StringValueExp.java	Wed Jul 05 16:40:29 2017 +0200
@@ -85,6 +85,7 @@
     /* There is no need for this method, because if a query is being
        evaluated a StringValueExp can only appear inside a QueryExp,
        and that QueryExp will itself have done setMBeanServer.  */
+    @Deprecated
     public void setMBeanServer(MBeanServer s)  { }
 
     /**
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/javax/management/event/EventClient.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,1068 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package javax.management.event;
+
+import com.sun.jmx.event.DaemonThreadFactory;
+import com.sun.jmx.event.LeaseRenewer;
+import com.sun.jmx.event.ReceiverBuffer;
+import com.sun.jmx.event.RepeatedSingletonJob;
+import com.sun.jmx.mbeanserver.PerThreadGroupPool;
+import com.sun.jmx.remote.util.ClassLogger;
+
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Executor;
+
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicLong;
+import javax.management.InstanceNotFoundException;
+import javax.management.ListenerNotFoundException;
+import javax.management.MBeanNotificationInfo;
+import javax.management.MBeanServerConnection;
+import javax.management.Notification;
+import javax.management.NotificationBroadcasterSupport;
+import javax.management.NotificationFilter;
+import javax.management.NotificationListener;
+import javax.management.ObjectName;
+import javax.management.remote.JMXConnector;
+import javax.management.remote.NotificationResult;
+import javax.management.remote.TargetedNotification;
+
+/**
+ * <p>This class is used to manage its notification listeners on the client
+ * side in the same way as on the MBean server side. This class needs to work
+ * with an {@link EventClientDelegateMBean} on the server side.</p>
+ *
+ * <P>A user can specify an {@link EventRelay} object to specify how to receive
+ * notifications forwarded by the {@link EventClientDelegateMBean}. By default,
+ * the class {@link FetchingEventRelay} is used.</p>
+ *
+ * <p>A user can specify an {@link java.util.concurrent.Executor Executor}
+ * to distribute notifications to local listeners. If no executor is
+ * specified, the thread in the {@link EventRelay} which calls {@link
+ * EventReceiver#receive EventReceiver.receive} will be reused to distribute
+ * the notifications (in other words, to call the {@link
+ * NotificationListener#handleNotification handleNotification} method of the
+ * appropriate listeners). It is useful to make a separate thread do this
+ * distribution in some cases. For example, if network communication is slow,
+ * the forwarding thread can concentrate on communication while, locally,
+ * the distributing thread distributes the received notifications. Another
+ * usage is to share a thread pool between many clients, for scalability.
+ * Note, though, that if the {@code Executor} can create more than one thread
+ * then it is possible that listeners will see notifications in a different
+ * order from the order in which they were sent.</p>
+ *
+ * <p>An object of this class sends notifications to listeners added with
+ * {@link #addEventClientListener}.  The {@linkplain Notification#getType()
+ * type} of each such notification is one of {@link #FAILED}, {@link #NONFATAL},
+ * or {@link #NOTIFS_LOST}.</p>
+ *
+ * @since JMX 2.0
+ */
+public class EventClient implements EventConsumer, NotificationManager {
+
+    /**
+     * <p>A notification string type used by an {@code EventClient} object
+     * to inform a listener added by {@link #addEventClientListener} that
+     * it failed to get notifications from a remote server, and that it is
+     * possible that no more notifications will be delivered.</p>
+     *
+     * @see #addEventClientListener
+     * @see EventReceiver#failed
+     */
+    public static final String FAILED = "jmx.event.service.failed";
+
+    /**
+     * <p>Reports that an unexpected exception has been received by the {@link
+     * EventRelay} object but that it is non-fatal. For example, a notification
+     * received is not serializable or its class is not found.</p>
+     *
+     * @see #addEventClientListener
+     * @see EventReceiver#nonFatal
+     */
+    public static final String NONFATAL = "jmx.event.service.nonfatal";
+
+    /**
+     * <p>A notification string type used by an {@code EventClient} object to
+     * inform a listener added by {@code #addEventClientListener} that it
+     * has detected that notifications have been lost.  The {@link
+     * Notification#getUserData() userData} of the notification is a Long which
+     * is an upper bound on the number of lost notifications that have just
+     * been detected.</p>
+     *
+     * @see #addEventClientListener
+     */
+    public static final String NOTIFS_LOST = "jmx.event.service.notifs.lost";
+
+    /**
+     * The default lease time, {@value}, in milliseconds.
+     *
+     * @see EventClientDelegateMBean#lease
+     */
+    public static final long DEFAULT_LEASE_TIMEOUT = 300000;
+
+    /**
+     * <p>Constructs a default {@code EventClient} object.</p>
+     *
+     * <p>This object creates a {@link FetchingEventRelay} object to
+     * receive notifications forwarded by the {@link EventClientDelegateMBean}.
+     * The {@link EventClientDelegateMBean} that it works with is the
+     * one registered with the {@linkplain EventClientDelegate#OBJECT_NAME
+     * default ObjectName}.  The thread from the {@link FetchingEventRelay}
+     * object that fetches the notifications is also used to distribute them.
+     *
+     * @param conn An {@link MBeanServerConnection} object used to communicate
+     * with an {@link EventClientDelegateMBean} MBean.
+     *
+     * @throws IllegalArgumentException If {@code conn} is null.
+     * @throws IOException If an I/O error occurs when communicating with the
+     * {@code EventClientDelegateMBean}.
+     */
+    public EventClient(MBeanServerConnection conn) throws IOException {
+        this(EventClientDelegate.getProxy(conn));
+    }
+
+    /**
+     * Constructs an {@code EventClient} object with a specified
+     * {@link EventClientDelegateMBean}.
+     *
+     * <p>This object creates a {@link FetchingEventRelay} object to receive
+     * notifications forwarded by the {@link EventClientDelegateMBean}.  The
+     * thread from the {@link FetchingEventRelay} object that fetches the
+     * notifications is also used to distribute them.
+     *
+     * @param delegate An {@link EventClientDelegateMBean} object to work with.
+     *
+     * @throws IllegalArgumentException If {@code delegate} is null.
+     * @throws IOException If an I/O error occurs when communicating with the
+     * the {@link EventClientDelegateMBean}.
+     */
+    public EventClient(EventClientDelegateMBean delegate)
+    throws IOException {
+        this(delegate, null, null, null, DEFAULT_LEASE_TIMEOUT);
+    }
+
+    /**
+     * Constructs an {@code EventClient} object with the specified
+     * {@link EventClientDelegateMBean}, {@link EventRelay}
+     * object, and distributing thread.
+     *
+     * @param delegate An {@link EventClientDelegateMBean} object to work with.
+     * Usually, this will be a proxy constructed using
+     * {@link EventClientDelegate#getProxy}.
+     * @param eventRelay An object used to receive notifications
+     * forwarded by the {@link EventClientDelegateMBean}. If {@code null}, a
+     * {@link FetchingEventRelay} object will be used.
+     * @param distributingExecutor Used to distribute notifications to local
+     * listeners. If {@code null}, the thread that calls {@link
+     * EventReceiver#receive EventReceiver.receive} from the {@link EventRelay}
+     * object is used.
+     * @param leaseScheduler An object that will be used to schedule the
+     * periodic {@linkplain EventClientDelegateMBean#lease lease updates}.
+     * If {@code null}, a default scheduler will be used.
+     * @param requestedLeaseTime The lease time used to keep this client alive
+     * in the {@link EventClientDelegateMBean}.  A value of zero is equivalent
+     * to the {@linkplain #DEFAULT_LEASE_TIMEOUT default value}.
+     *
+     * @throws IllegalArgumentException If {@code delegate} is null.
+     * @throws IOException If an I/O error occurs when communicating with the
+     * {@link EventClientDelegateMBean}.
+     */
+    public EventClient(EventClientDelegateMBean delegate,
+            EventRelay eventRelay,
+            Executor distributingExecutor,
+            ScheduledExecutorService leaseScheduler,
+            long requestedLeaseTime)
+            throws IOException {
+        if (delegate == null) {
+            throw new IllegalArgumentException("Null EventClientDelegateMBean");
+        }
+
+        if (requestedLeaseTime == 0)
+            requestedLeaseTime = DEFAULT_LEASE_TIMEOUT;
+        else if (requestedLeaseTime < 0) {
+            throw new IllegalArgumentException(
+                    "Negative lease time: " + requestedLeaseTime);
+        }
+
+        eventClientDelegate = delegate;
+
+        if (eventRelay != null) {
+            this.eventRelay = eventRelay;
+        } else {
+            try {
+                this.eventRelay = new FetchingEventRelay(delegate);
+            } catch (IOException ioe) {
+                throw ioe;
+            } catch (Exception e) {
+                // impossible?
+                final IOException ioee = new IOException(e.toString());
+                ioee.initCause(e);
+                throw ioee;
+            }
+        }
+
+        if (distributingExecutor == null)
+            distributingExecutor = callerExecutor;
+        this.distributingExecutor = distributingExecutor;
+        this.dispatchingJob = new DispatchingJob();
+
+        clientId = this.eventRelay.getClientId();
+
+        this.requestedLeaseTime = requestedLeaseTime;
+        if (leaseScheduler == null)
+            leaseScheduler = defaultLeaseScheduler();
+        leaseRenewer = new LeaseRenewer(leaseScheduler, renewLease);
+
+        if (logger.traceOn()) {
+            logger.trace("init", "New EventClient: "+clientId);
+        }
+    }
+
+    private static ScheduledExecutorService defaultLeaseScheduler() {
+        // The default lease scheduler uses a ScheduledThreadPoolExecutor
+        // with a maximum of 20 threads.  This means that if you have many
+        // EventClient instances and some of them get blocked (because of an
+        // unresponsive network, for example), then even the instances that
+        // are connected to responsive servers may have their leases expire.
+        // XXX check if the above is true and possibly fix.
+        PerThreadGroupPool.Create<ScheduledThreadPoolExecutor> create =
+                new PerThreadGroupPool.Create<ScheduledThreadPoolExecutor>() {
+            public ScheduledThreadPoolExecutor createThreadPool(ThreadGroup group) {
+                ThreadFactory daemonThreadFactory = new DaemonThreadFactory(
+                        "EventClient lease renewer %d");
+                ScheduledThreadPoolExecutor exec = new ScheduledThreadPoolExecutor(
+                        20, daemonThreadFactory);
+                exec.setKeepAliveTime(3, TimeUnit.SECONDS);
+                exec.allowCoreThreadTimeOut(true);
+                return exec;
+            }
+        };
+        return leaseRenewerThreadPool.getThreadPoolExecutor(create);
+
+    }
+
+    /**
+     * <p>Closes this EventClient, removes all listeners and stops receiving
+     * notifications.</p>
+     *
+     * <p>This method calls {@link
+     * EventClientDelegateMBean#removeClient(String)} and {@link
+     * EventRelay#stop}.  Both operations occur even if one of them
+     * throws an {@code IOException}.
+     *
+     * @throws IOException if an I/O error occurs when communicating with
+     * {@link EventClientDelegateMBean}, or if {@link EventRelay#stop}
+     * throws an {@code IOException}.
+     */
+    public void close() throws IOException {
+        if (logger.traceOn()) {
+            logger.trace("close", clientId);
+        }
+
+        synchronized(listenerInfoMap) {
+            if (closed) {
+                return;
+            }
+
+            closed = true;
+            listenerInfoMap.clear();
+        }
+
+        if (leaseRenewer != null)
+            leaseRenewer.close();
+
+        IOException ioe = null;
+        try {
+            eventRelay.stop();
+        } catch (IOException e) {
+            ioe = e;
+            logger.debug("close", "EventRelay.stop", e);
+        }
+
+        try {
+            eventClientDelegate.removeClient(clientId);
+        } catch (Exception e) {
+            if (e instanceof IOException)
+                ioe = (IOException) e;
+            else
+                ioe = new IOException(e);
+            logger.debug("close",
+                    "Got exception when removing "+clientId, e);
+        }
+
+        if (ioe != null)
+            throw ioe;
+    }
+
+    /**
+     * <p>Determine if this {@code EventClient} is closed.</p>
+     *
+     * @return True if the {@code EventClient} is closed.
+     */
+    public boolean closed() {
+        return closed;
+    }
+
+    /**
+     * <p>Return the {@link EventRelay} associated with this
+     * {@code EventClient}.</p>
+     *
+     * @return The {@link EventRelay} object used.
+     */
+    public EventRelay getEventRelay() {
+        return eventRelay;
+    }
+
+    /**
+     * <p>Return the lease time that this {@code EventClient} requests
+     * on every lease renewal.</p>
+     *
+     * @return The requested lease time.
+     *
+     * @see EventClientDelegateMBean#lease
+     */
+    public long getRequestedLeaseTime() {
+        return requestedLeaseTime;
+    }
+
+    /**
+     * @see javax.management.MBeanServerConnection#addNotificationListener(
+     * ObjectName, NotificationListener, NotificationFilter, Object).
+     */
+    public void addNotificationListener(ObjectName name,
+            NotificationListener listener,
+            NotificationFilter filter,
+            Object handback)
+            throws InstanceNotFoundException, IOException {
+        if (logger.traceOn()) {
+            logger.trace("addNotificationListener", "");
+        }
+
+        checkState();
+
+        Integer listenerId;
+        try {
+            listenerId =
+                    eventClientDelegate.addListener(clientId, name, filter);
+        } catch (EventClientNotFoundException ecnfe) {
+            final IOException ioe = new IOException();
+            ioe.initCause(ecnfe);
+            throw ioe;
+        }
+
+        synchronized(listenerInfoMap) {
+            listenerInfoMap.put(listenerId,  new ListenerInfo(
+                    name,
+                    listener,
+                    filter,
+                    handback,
+                    false));
+        }
+
+        startListening();
+    }
+
+    /**
+     * @see javax.management.MBeanServerConnection#removeNotificationListener(
+     * ObjectName, NotificationListener).
+     */
+    public void removeNotificationListener(ObjectName name,
+            NotificationListener listener)
+            throws InstanceNotFoundException,
+            ListenerNotFoundException,
+            IOException {
+        if (logger.traceOn()) {
+            logger.trace("removeNotificationListener", "");
+        }
+        checkState();
+
+        for (Integer id : getListenerInfo(name, listener, false)) {
+            removeListener(id);
+        }
+    }
+
+    /**
+     * @see javax.management.MBeanServerConnection#removeNotificationListener(
+     * ObjectName, NotificationListener, NotificationFilter, Object).
+     */
+    public void removeNotificationListener(ObjectName name,
+            NotificationListener listener,
+            NotificationFilter filter,
+            Object handback)
+            throws InstanceNotFoundException,
+            ListenerNotFoundException,
+            IOException {
+        if (logger.traceOn()) {
+            logger.trace("removeNotificationListener", "with all arguments.");
+        }
+        checkState();
+        final Integer listenerId =
+                getListenerInfo(name, listener, filter, handback, false);
+
+        removeListener(listenerId);
+    }
+
+    /**
+     * @see javax.management.event.EventConsumer#unsubscribe(
+     * ObjectName, NotificationListener).
+     */
+    public void unsubscribe(ObjectName name,
+            NotificationListener listener)
+            throws ListenerNotFoundException, IOException {
+        if (logger.traceOn()) {
+            logger.trace("unsubscribe", "");
+        }
+        checkState();
+        final Integer listenerId =
+                getMatchedListenerInfo(name, listener, true);
+
+        synchronized(listenerInfoMap) {
+            if (listenerInfoMap.remove(listenerId) == null) {
+                throw new ListenerNotFoundException();
+            }
+        }
+
+        stopListening();
+
+        try {
+            eventClientDelegate.removeListenerOrSubscriber(clientId, listenerId);
+        } catch (InstanceNotFoundException e) {
+            logger.trace("unsubscribe", "removeSubscriber", e);
+        } catch (EventClientNotFoundException cnfe) {
+            logger.trace("unsubscribe", "removeSubscriber", cnfe);
+        }
+    }
+
+    /**
+     * @see javax.management.event.EventConsumer#subscribe(
+     * ObjectName, NotificationListener, NotificationFilter, Object).
+     */
+    public void subscribe(ObjectName name,
+            NotificationListener listener,
+            NotificationFilter filter,
+            Object handback) throws IOException {
+        if (logger.traceOn()) {
+            logger.trace("subscribe", "");
+        }
+
+        checkState();
+
+        Integer listenerId;
+        try {
+            listenerId =
+                    eventClientDelegate.addSubscriber(clientId, name, filter);
+        } catch (EventClientNotFoundException ecnfe) {
+            final IOException ioe = new IOException();
+            ioe.initCause(ecnfe);
+            throw ioe;
+        }
+
+        synchronized(listenerInfoMap) {
+            listenerInfoMap.put(listenerId,  new ListenerInfo(
+                    name,
+                    listener,
+                    filter,
+                    handback,
+                    true));
+        }
+
+        startListening();
+    }
+
+    /**
+     * <p>Adds a set of listeners to the remote MBeanServer.  This method can
+     * be used to copy the listeners from one {@code EventClient} to another.</p>
+     *
+     * <p>A listener is represented by a {@link ListenerInfo} object. The listener
+     * is added by calling {@link #subscribe(ObjectName,
+     * NotificationListener, NotificationFilter, Object)} if the method
+     * {@link ListenerInfo#isSubscription() isSubscription}
+     * returns {@code true}; otherwise it is added by calling
+     * {@link #addNotificationListener(ObjectName, NotificationListener,
+     * NotificationFilter, Object)}.</p>
+     *
+     * <P>The method returns the listeners which were added successfully. The
+     * elements in the returned collection are a subset of the elements in
+     * {@code infoList}. If all listeners were added successfully, the two
+     * collections are the same. If no listener was added successfully, the
+     * returned collection is empty.</p>
+     *
+     * @param listeners the listeners to add.
+     *
+     * @return The listeners that were added successfully.
+     *
+     * @throws IOException If an I/O error occurs.
+     *
+     * @see #getListeners()
+     */
+    public Collection<ListenerInfo> addListeners(Collection<ListenerInfo> listeners)
+    throws IOException {
+        if (logger.traceOn()) {
+            logger.trace("addListeners", "");
+        }
+
+        checkState();
+
+        if (listeners == null || listeners.isEmpty())
+            return Collections.emptySet();
+
+        final List<ListenerInfo> list = new ArrayList<ListenerInfo>();
+        for (ListenerInfo l : listeners) {
+            try {
+                if (l.isSubscription()) {
+                    subscribe(l.getObjectName(),
+                            l.getListener(),
+                            l.getFilter(),
+                            l.getHandback());
+                } else {
+                    addNotificationListener(l.getObjectName(),
+                            l.getListener(),
+                            l.getFilter(),
+                            l.getHandback());
+                }
+
+                list.add(l);
+            } catch (Exception e) {
+                if (logger.traceOn()) {
+                    logger.trace("addListeners", "failed to add: "+l, e);
+                }
+            }
+        }
+
+        return list;
+    }
+
+    /**
+     * Returns the set of listeners that have been added through
+     * this {@code EventClient} and not subsequently removed.
+     *
+     * @return A collection of listener information. Empty if there are no
+     * current listeners or if this {@code EventClient} has been {@linkplain
+     * #close closed}.
+     *
+     * @see #addListeners
+     */
+    public Collection<ListenerInfo> getListeners() {
+        if (logger.traceOn()) {
+            logger.trace("getListeners", "");
+        }
+
+        synchronized(listenerInfoMap) {
+            return Collections.unmodifiableCollection(listenerInfoMap.values());
+        }
+    }
+
+    /**
+     * Adds a listener to receive the {@code EventClient} notifications specified in
+     * {@link #getEventClientNotificationInfo}.
+     *
+     * @param listener A listener to receive {@code EventClient} notifications.
+     * @param filter A filter to select which notifications are to be delivered
+     * to the listener, or {@code null} if all notifications are to be delivered.
+     * @param handback An object to be given to the listener along with each
+     * notification. Can be null.
+     * @throws NullPointerException If listener is null.
+     * @see #removeEventClientListener
+     */
+    public void addEventClientListener(NotificationListener listener,
+            NotificationFilter filter,
+            Object handback) {
+        if (logger.traceOn()) {
+            logger.trace("addEventClientListener", "");
+        }
+        broadcaster.addNotificationListener(listener, filter, handback);
+    }
+
+    /**
+     * Removes a listener added to receive {@code EventClient} notifications specified in
+     * {@link #getEventClientNotificationInfo}.
+     *
+     * @param listener A listener to receive {@code EventClient} notifications.
+     * @throws NullPointerException If listener is null.
+     * @throws ListenerNotFoundException If the listener is not added to
+     * this {@code EventClient}.
+     */
+    public void removeEventClientListener(NotificationListener listener)
+    throws ListenerNotFoundException {
+        if (logger.traceOn()) {
+            logger.trace("removeEventClientListener", "");
+        }
+        broadcaster.removeNotificationListener(listener);
+    }
+
+    /**
+     * <p>Get the types of notification that an {@code EventClient} can send
+     * to listeners added with {@link #addEventClientListener
+     * addEventClientListener}.</p>
+     *
+     * @return Types of notification emitted by this {@code EventClient}.
+     *
+     * @see #FAILED
+     * @see #NONFATAL
+     * @see #NOTIFS_LOST
+     */
+    public MBeanNotificationInfo[] getEventClientNotificationInfo() {
+        return myInfo.clone();
+    }
+
+    private static boolean match(ListenerInfo li,
+            ObjectName name,
+            NotificationListener listener,
+            boolean subscribed) {
+        return li.getObjectName().equals(name) &&
+                li.getListener() == listener &&
+                li.isSubscription() == subscribed;
+    }
+
+    private static boolean match(ListenerInfo li,
+            ObjectName name,
+            NotificationListener listener,
+            NotificationFilter filter,
+            Object handback,
+            boolean subscribed) {
+        return li.getObjectName().equals(name) &&
+                li.getFilter() == filter &&
+                li.getListener() == listener &&
+                li.getHandback() == handback &&
+                li.isSubscription() == subscribed;
+    }
+
+// ---------------------------------------------------
+// private classes
+// ---------------------------------------------------
+    private class DispatchingJob extends RepeatedSingletonJob {
+        public DispatchingJob() {
+            super(distributingExecutor);
+        }
+
+        public boolean isSuspended() {
+            return closed || buffer.size() == 0;
+        }
+
+        public void task() {
+            TargetedNotification[] tns ;
+            int lost = 0;
+
+            synchronized(buffer) {
+                tns = buffer.removeNotifs();
+                lost = buffer.removeLost();
+            }
+
+            if ((tns == null || tns.length == 0)
+            && lost == 0) {
+                return;
+            }
+
+            // forwarding
+            if (tns != null && tns.length > 0) {
+                if (logger.traceOn()) {
+                    logger.trace("DispatchingJob-task",
+                            "Forwarding: "+tns.length);
+                }
+                for (TargetedNotification tn : tns) {
+                    final ListenerInfo li = listenerInfoMap.get(tn.getListenerID());
+                    try {
+                        li.getListener().handleNotification(tn.getNotification(),
+                                li.getHandback());
+                    } catch (Exception e) {
+                        logger.fine(
+                                "DispatchingJob.task", "listener got exception", e);
+                    }
+                }
+            }
+
+            if (lost > 0) {
+                if (logger.traceOn()) {
+                    logger.trace("DispatchingJob-task",
+                            "lost: "+lost);
+                }
+                final Notification n = new Notification(NOTIFS_LOST,
+                        EventClient.this,
+                        myNotifCounter.getAndIncrement(),
+                        System.currentTimeMillis(),
+                        "Lost notifications.");
+                n.setUserData(new Long(lost));
+                broadcaster.sendNotification(n);
+            }
+        }
+    }
+
+
+    private class EventReceiverImpl implements EventReceiver {
+        public void receive(NotificationResult nr) {
+            if (logger.traceOn()) {
+                logger.trace("MyEventReceiver-receive", "");
+            }
+
+            synchronized(buffer) {
+                buffer.addNotifs(nr);
+
+                dispatchingJob.resume();
+            }
+        }
+
+        public void failed(Throwable t) {
+            if (logger.traceOn()) {
+                logger.trace("MyEventReceiver-failed", "", t);
+            }
+            final Notification n = new Notification(FAILED,
+                    this,
+                    myNotifCounter.getAndIncrement(),
+                    System.currentTimeMillis());
+            n.setSource(t);
+            broadcaster.sendNotification(n);
+        }
+
+        public void nonFatal(Exception e) {
+            if (logger.traceOn()) {
+                logger.trace("MyEventReceiver-nonFatal", "", e);
+            }
+
+            final Notification n = new Notification(NONFATAL,
+                    this,
+                    myNotifCounter.getAndIncrement(),
+                    System.currentTimeMillis());
+            n.setSource(e);
+            broadcaster.sendNotification(n);
+        }
+    }
+
+// ----------------------------------------------------
+// private class
+// ----------------------------------------------------
+
+
+// ----------------------------------------------------
+// private methods
+// ----------------------------------------------------
+    private Integer getListenerInfo(ObjectName name,
+            NotificationListener listener,
+            NotificationFilter filter,
+            Object handback,
+            boolean subscribed) throws ListenerNotFoundException {
+
+        synchronized(listenerInfoMap) {
+            for (Map.Entry<Integer, ListenerInfo> entry :
+                    listenerInfoMap.entrySet()) {
+                ListenerInfo li = entry.getValue();
+                if (match(li, name, listener, filter, handback, subscribed)) {
+                    return entry.getKey();
+                }
+            }
+        }
+
+        throw new ListenerNotFoundException();
+    }
+
+    private Integer getMatchedListenerInfo(ObjectName name,
+            NotificationListener listener,
+            boolean subscribed) throws ListenerNotFoundException {
+
+        synchronized(listenerInfoMap) {
+            for (Map.Entry<Integer, ListenerInfo> entry :
+                    listenerInfoMap.entrySet()) {
+                ListenerInfo li = entry.getValue();
+                if (li.getObjectName().equals(name) &&
+                        li.getListener() == listener &&
+                        li.isSubscription() == subscribed) {
+                    return entry.getKey();
+                }
+            }
+        }
+
+        throw new ListenerNotFoundException();
+    }
+
+    private Collection<Integer> getListenerInfo(ObjectName name,
+            NotificationListener listener,
+            boolean subscribed) throws ListenerNotFoundException {
+
+        final ArrayList<Integer> ids = new ArrayList<Integer>();
+        synchronized(listenerInfoMap) {
+            for (Map.Entry<Integer, ListenerInfo> entry :
+                    listenerInfoMap.entrySet()) {
+                ListenerInfo li = entry.getValue();
+                if (match(li, name, listener, subscribed)) {
+                    ids.add(entry.getKey());
+                }
+            }
+        }
+
+        if (ids.isEmpty()) {
+            throw new ListenerNotFoundException();
+        }
+
+        return ids;
+    }
+
+    private void checkState() throws IOException {
+        synchronized(listenerInfoMap) {
+            if (closed) {
+                throw new IOException("Ended!");
+            }
+        }
+    }
+
+    private void startListening() throws IOException {
+        synchronized(listenerInfoMap) {
+            if (!startedListening && listenerInfoMap.size() > 0) {
+                eventRelay.setEventReceiver(myReceiver);
+            }
+
+            startedListening = true;
+
+            if (logger.traceOn()) {
+                logger.trace("startListening", "listening");
+            }
+        }
+    }
+
+    private void stopListening() throws IOException {
+        synchronized(listenerInfoMap) {
+            if (listenerInfoMap.size() == 0 && startedListening) {
+                eventRelay.setEventReceiver(null);
+
+                startedListening = false;
+
+                if (logger.traceOn()) {
+                    logger.trace("stopListening", "non listening");
+                }
+            }
+        }
+    }
+
+    private void removeListener(Integer id)
+    throws InstanceNotFoundException,
+            ListenerNotFoundException,
+            IOException {
+        synchronized(listenerInfoMap) {
+            if (listenerInfoMap.remove(id) == null) {
+                throw new ListenerNotFoundException();
+            }
+
+            stopListening();
+        }
+
+        try {
+            eventClientDelegate.removeListenerOrSubscriber(clientId, id);
+        } catch (EventClientNotFoundException cnfe) {
+            logger.trace("removeListener", "ecd.removeListener", cnfe);
+        }
+    }
+
+
+// ----------------------------------------------------
+// private variables
+// ----------------------------------------------------
+    private static final ClassLogger logger =
+            new ClassLogger("javax.management.event", "EventClient");
+
+    private final Executor distributingExecutor;
+    private final EventClientDelegateMBean eventClientDelegate;
+    private final EventRelay eventRelay;
+    private volatile String clientId = null;
+    private final long requestedLeaseTime;
+
+    private final ReceiverBuffer buffer = new ReceiverBuffer();
+
+    private final EventReceiverImpl myReceiver =
+            new EventReceiverImpl();
+    private final DispatchingJob dispatchingJob;
+
+    private final HashMap<Integer, ListenerInfo> listenerInfoMap =
+            new HashMap<Integer, ListenerInfo>();
+
+    private volatile boolean closed = false;
+
+    private volatile boolean startedListening = false;
+
+    // Could change synchronization here. But at worst a race will mean
+    // sequence numbers are not contiguous, which may not matter much.
+    private final AtomicLong myNotifCounter = new AtomicLong();
+
+    private final static MBeanNotificationInfo[] myInfo =
+            new MBeanNotificationInfo[] {
+        new MBeanNotificationInfo(
+                new String[] {FAILED, NOTIFS_LOST},
+                Notification.class.getName(), "")};
+
+    private final NotificationBroadcasterSupport broadcaster =
+            new NotificationBroadcasterSupport();
+
+    private final static Executor callerExecutor = new Executor() {
+        // DirectExecutor using caller thread
+        public void execute(Runnable r) {
+            r.run();
+        }
+    };
+
+    private static void checkInit(final MBeanServerConnection conn,
+            final ObjectName delegateName)
+            throws IOException {
+        if (conn == null) {
+            throw new IllegalArgumentException("No connection specified");
+        }
+        if (delegateName != null &&
+                (!conn.isRegistered(delegateName))) {
+            throw new IllegalArgumentException(
+                    delegateName +
+                    ": not found");
+        }
+        if (delegateName == null &&
+                (!conn.isRegistered(
+                EventClientDelegate.OBJECT_NAME))) {
+            throw new IllegalArgumentException(
+                    EventClientDelegate.OBJECT_NAME +
+                    ": not found");
+        }
+    }
+
+// ----------------------------------------------------
+// private event lease issues
+// ----------------------------------------------------
+    private Callable<Long> renewLease = new Callable<Long>() {
+        public Long call() throws IOException, EventClientNotFoundException {
+            return eventClientDelegate.lease(clientId, requestedLeaseTime);
+        }
+    };
+
+    private final LeaseRenewer leaseRenewer;
+
+// ------------------------------------------------------------------------
+    /**
+     * Constructs an {@code MBeanServerConnection} that uses an {@code EventClient} object,
+     * if the underlying connection has an {@link EventClientDelegateMBean}.
+     * <P> The {@code EventClient} object creates a default
+     * {@link FetchingEventRelay} object to
+     * receive notifications forwarded by the {@link EventClientDelegateMBean}.
+     * The {@link EventClientDelegateMBean} it works with is the
+     * default one registered with the ObjectName
+     * {@link EventClientDelegate#OBJECT_NAME
+     * OBJECT_NAME}.
+     * The thread from the {@link FetchingEventRelay} object that fetches the
+     * notifications is also used to distribute them.
+     *
+     * @param conn An {@link MBeanServerConnection} object used to communicate
+     * with an {@link EventClientDelegateMBean}.
+     * @throws IllegalArgumentException If the value of {@code conn} is null,
+     *         or the default {@link EventClientDelegateMBean} is not registered.
+     * @throws IOException If an I/O error occurs.
+     */
+    public static MBeanServerConnection getEventClientConnection(
+            final MBeanServerConnection conn)
+            throws IOException {
+        return getEventClientConnection(conn, null);
+    }
+
+    /**
+     * Constructs an MBeanServerConnection that uses an {@code EventClient}
+     * object with a user-specific {@link EventRelay}
+     * object.
+     * <P>
+     * The {@link EventClientDelegateMBean} which it works with is the
+     * default one registered with the ObjectName
+     * {@link EventClientDelegate#OBJECT_NAME
+     * OBJECT_NAME}
+     * The thread that calls {@link EventReceiver#receive
+     * EventReceiver.receive} from the {@link EventRelay} object is used
+     * to distribute notifications to their listeners.
+     *
+     * @param conn An {@link MBeanServerConnection} object used to communicate
+     * with an {@link EventClientDelegateMBean}.
+     * @param eventRelay A user-specific object used to receive notifications
+     * forwarded by the {@link EventClientDelegateMBean}. If null, the default
+     * {@link FetchingEventRelay} object is used.
+     * @throws IllegalArgumentException If the value of {@code conn} is null,
+     *         or the default {@link EventClientDelegateMBean} is not registered.
+     * @throws IOException If an I/O error occurs.
+     */
+    public static MBeanServerConnection getEventClientConnection(
+            final MBeanServerConnection conn,
+            final EventRelay eventRelay)
+            throws IOException {
+
+        if (newEventConn == null) {
+            throw new IllegalArgumentException(
+                    "Class not found: EventClientConnection");
+        }
+
+        checkInit(conn,null);
+        final Callable<EventClient> factory = new Callable<EventClient>() {
+            final public EventClient call() throws Exception {
+                EventClientDelegateMBean ecd = EventClientDelegate.getProxy(conn);
+                return new EventClient(ecd, eventRelay, null, null,
+                        DEFAULT_LEASE_TIMEOUT);
+            }
+        };
+
+        try {
+            return (MBeanServerConnection)newEventConn.invoke(null,
+                    conn, factory);
+        } catch (Exception e) {
+            throw new IllegalArgumentException(e);
+        }
+    }
+
+    private static Method newEventConn = null;
+    static {
+        try {
+            Class<?> c = Class.forName(
+                    "com.sun.jmx.remote.util.EventClientConnection",
+                    false, Thread.currentThread().getContextClassLoader());
+            newEventConn = c.getMethod("getEventConnectionFor",
+                    MBeanServerConnection.class, Callable.class);
+        } catch (Exception e) {
+            // OK: we're running in a subset of our classes
+        }
+    }
+
+    /**
+     * <p>Get the client id of this {@code EventClient} in the
+     * {@link EventClientDelegateMBean}.
+     *
+     * @return the client id.
+     *
+     * @see EventClientDelegateMBean#addClient(String, Object[], String[])
+     * EventClientDelegateMBean.addClient
+     */
+    public String getClientId() {
+        return clientId;
+    }
+
+    private static final PerThreadGroupPool<ScheduledThreadPoolExecutor>
+            leaseRenewerThreadPool = PerThreadGroupPool.make();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/javax/management/event/EventClientDelegate.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,766 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ * @since JMX 2.0
+ */
+
+package javax.management.event;
+
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.UUID;
+
+import javax.management.InstanceNotFoundException;
+import javax.management.ListenerNotFoundException;
+import javax.management.Notification;
+import javax.management.NotificationFilter;
+import javax.management.NotificationListener;
+import javax.management.ObjectName;
+import javax.management.remote.NotificationResult;
+import com.sun.jmx.event.EventBuffer;
+import com.sun.jmx.event.LeaseManager;
+import com.sun.jmx.interceptor.SingleMBeanForwarder;
+import com.sun.jmx.mbeanserver.Util;
+import com.sun.jmx.remote.util.ClassLogger;
+import java.lang.ref.WeakReference;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Proxy;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedExceptionAction;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.Set;
+import java.util.WeakHashMap;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicInteger;
+import javax.management.DynamicMBean;
+import javax.management.MBeanException;
+import javax.management.MBeanPermission;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerConnection;
+import javax.management.MBeanServerDelegate;
+import javax.management.MBeanServerInvocationHandler;
+import javax.management.MBeanServerNotification;
+import javax.management.ObjectInstance;
+import javax.management.StandardMBean;
+import javax.management.remote.MBeanServerForwarder;
+
+/**
+ * This is the default implementation of the MBean
+ * {@link EventClientDelegateMBean}.
+ */
+public class EventClientDelegate implements EventClientDelegateMBean {
+
+    private EventClientDelegate(MBeanServer server) {
+        if (server == null) {
+            throw new NullPointerException("Null MBeanServer.");
+        }
+
+        if (logger.traceOn()) {
+            logger.trace("EventClientDelegate", "new one");
+        }
+        mbeanServer = server;
+        eventSubscriber = EventSubscriber.getEventSubscriber(mbeanServer);
+    }
+
+    /**
+     * Returns an {@code EventClientDelegate} instance for the given
+     * {@code MBeanServer}.  Calling this method more than once with the same
+     * {@code server} argument may return the same object or a different object
+     * each time.  See {@link EventClientDelegateMBean} for an example use of
+     * this method.
+     *
+     * @param server An MBean server instance to work with.
+     * @return An {@code EventClientDelegate} instance.
+     * @throws NullPointerException If {@code server} is null.
+     */
+    public static EventClientDelegate getEventClientDelegate(MBeanServer server) {
+        EventClientDelegate delegate = null;
+        synchronized(delegateMap) {
+            final WeakReference wrf = delegateMap.get(server);
+            delegate = (wrf == null) ? null : (EventClientDelegate)wrf.get();
+
+            if (delegate == null) {
+                delegate = new EventClientDelegate(server);
+                try {
+                    // TODO: this may not work with federated MBean, because
+                    // the delegate will *not* emit notifications for those MBeans.
+                    delegate.mbeanServer.addNotificationListener(
+                            MBeanServerDelegate.DELEGATE_NAME,
+                            delegate.cleanListener, null, null);
+                } catch (InstanceNotFoundException e) {
+                    logger.fine(
+                            "getEventClientDelegate",
+                            "Could not add MBeanServerDelegate listener", e);
+                }
+                delegateMap.put(server,
+                                new WeakReference<EventClientDelegate>(delegate));
+            }
+        }
+
+        return delegate;
+    }
+
+    // Logic for the MBeanServerForwarder that simulates the existence of the
+    // EventClientDelegate MBean. Things are complicated by the fact that
+    // there may not be anything in the chain after this forwarder when it is
+    // created - the connection to a real MBeanServer might only come later.
+    // Recall that there are two ways of creating a JMXConnectorServer -
+    // either you specify its MBeanServer when you create it, or you specify
+    // no MBeanServer and register it in an MBeanServer later. In the latter
+    // case, the forwarder chain points nowhere until this registration
+    // happens. Since EventClientDelegate wants to add a listener to the
+    // MBeanServerDelegate, we can't create an EventClientDelegate until
+    // there is an MBeanServer. So the forwarder initially has
+    // a dummy ECD where every method throws an exception, and
+    // the real ECD is created as soon as doing so does not produce an
+    // exception.
+    // TODO: rewrite so that the switch from the dummy to the real ECD happens
+    // just before we would otherwise have thrown UnsupportedOperationException.
+    // This is more correct, because it's not guaranteed that we will see the
+    // moment where the real MBeanServer is attached, if it happens by virtue
+    // of a setMBeanServer on some other forwarder later in the chain.
+
+    private static class Forwarder extends SingleMBeanForwarder {
+
+        private static class UnsupportedInvocationHandler
+                implements InvocationHandler {
+            public Object invoke(Object proxy, Method method, Object[] args)
+                    throws Throwable {
+                throw new UnsupportedOperationException(
+                        "EventClientDelegate unavailable: no MBeanServer, or " +
+                        "MBeanServer inaccessible");
+            }
+        }
+
+        private static DynamicMBean makeUnsupportedECD() {
+            EventClientDelegateMBean unsupported = (EventClientDelegateMBean)
+                Proxy.newProxyInstance(
+                    EventClientDelegateMBean.class.getClassLoader(),
+                    new Class<?>[] {EventClientDelegateMBean.class},
+                    new UnsupportedInvocationHandler());
+            return new StandardMBean(
+                unsupported, EventClientDelegateMBean.class, false);
+        }
+
+        private volatile boolean madeECD;
+
+        Forwarder() {
+            super(OBJECT_NAME, makeUnsupportedECD());
+        }
+
+        @Override
+        public synchronized void setMBeanServer(final MBeanServer mbs) {
+            super.setMBeanServer(mbs);
+
+            if (!madeECD) {
+                try {
+                    EventClientDelegate ecd =
+                        AccessController.doPrivileged(
+                            new PrivilegedAction<EventClientDelegate>() {
+                                public EventClientDelegate run() {
+                                    return getEventClientDelegate(Forwarder.this);
+                                }
+                            });
+                    DynamicMBean mbean = new StandardMBean(
+                            ecd, EventClientDelegateMBean.class, false);
+                    setSingleMBean(mbean);
+                    madeECD = true;
+                } catch (Exception e) {
+                    // OK: assume no MBeanServer
+                    logger.fine("setMBeanServer", "isRegistered", e);
+                }
+            }
+        }
+    }
+
+    /**
+     * <p>Create a new {@link MBeanServerForwarder} that simulates the existence
+     * of an {@code EventClientDelegateMBean} with the {@linkplain
+     * #OBJECT_NAME default name}.  This forwarder intercepts MBean requests
+     * that are targeted for that MBean and handles them itself.  All other
+     * requests are forwarded to the next element in the forwarder chain.</p>
+     *
+     * @return a new {@code MBeanServerForwarder} that simulates the existence
+     * of an {@code EventClientDelegateMBean}.
+     */
+    public static MBeanServerForwarder newForwarder() {
+        return new Forwarder();
+    }
+
+    /**
+     * Returns a proxy of the default {@code EventClientDelegateMBean}.
+     *
+     * @param conn An {@link MBeanServerConnection} to work with.
+     */
+    @SuppressWarnings("cast") // cast for jdk 1.5
+    public static EventClientDelegateMBean getProxy(MBeanServerConnection conn) {
+        return  (EventClientDelegateMBean)MBeanServerInvocationHandler.
+                newProxyInstance(conn,
+                OBJECT_NAME,
+                EventClientDelegateMBean.class,
+                false);
+    }
+
+    public String addClient(String className, Object[] params, String[] sig)
+    throws MBeanException {
+        return addClient(className, null, params, sig, true);
+    }
+
+    public String addClient(String className,
+            ObjectName classLoader,
+            Object[] params,
+            String[] sig) throws MBeanException {
+        return addClient(className, classLoader, params, sig, false);
+    }
+
+    private String addClient(String className,
+            ObjectName classLoader,
+            Object[] params,
+            String[] sig,
+            boolean classLoaderRepository) throws MBeanException {
+        try {
+            return addClientX(
+                    className, classLoader, params, sig, classLoaderRepository);
+        } catch (RuntimeException e) {
+            throw e;
+        } catch (Exception e) {
+            throw new MBeanException(e);
+        }
+    }
+
+    private String addClientX(String className,
+            ObjectName classLoader,
+            Object[] params,
+            String[] sig,
+            boolean classLoaderRepository) throws Exception {
+        if (className == null) {
+            throw new IllegalArgumentException("Null class name.");
+        }
+
+        final Object o;
+
+        // The special treatment of standard EventForwarders is so that no
+        // special permissions are necessary to use them.  Otherwise you
+        // couldn't use EventClient if you didn't have permission to call
+        // MBeanServer.instantiate.  We do require that permission for
+        // non-standard forwarders, because otherwise you could instantiate
+        // any class with possibly adverse consequences.  We also avoid using
+        // MBeanInstantiator because it looks up constructors by loading each
+        // class in the sig array, which means a remote user could cause any
+        // class to be loaded.  That's probably not hugely risky but still.
+        if (className.startsWith("javax.management.event.")) {
+            Class<?> c = Class.forName(
+                    className, false, this.getClass().getClassLoader());
+            Constructor<?> foundCons = null;
+            if (sig == null)
+                sig = new String[0];
+            for (Constructor cons : c.getConstructors()) {
+                Class<?>[] types = cons.getParameterTypes();
+                String[] consSig = new String[types.length];
+                for (int i = 0; i < types.length; i++)
+                    consSig[i] = types[i].getName();
+                if (Arrays.equals(sig, consSig)) {
+                    foundCons = cons;
+                    break;
+                }
+            }
+            if (foundCons == null) {
+                throw new NoSuchMethodException(
+                        "Constructor for " + className + " with argument types " +
+                        Arrays.toString(sig));
+            }
+            o = foundCons.newInstance(params);
+        } else if (classLoaderRepository) {
+            o = mbeanServer.instantiate(className, params, sig);
+        } else {
+            o = mbeanServer.instantiate(className, classLoader, params, sig);
+        }
+
+        if (!(o instanceof EventForwarder)) {
+            throw new IllegalArgumentException(
+                    className+" is not an EventForwarder class.");
+        }
+
+        final EventForwarder forwarder = (EventForwarder)o;
+        final String clientId = UUID.randomUUID().toString();
+        ClientInfo clientInfo = new ClientInfo(clientId, forwarder);
+
+        clientInfoMap.put(clientId, clientInfo);
+
+        forwarder.setClientId(clientId);
+
+        if (logger.traceOn()) {
+            logger.trace("addClient", clientId);
+        }
+
+        return clientId;
+    }
+
+    public Integer[] getListenerIds(String clientId)
+    throws IOException, EventClientNotFoundException {
+        ClientInfo clientInfo = getClientInfo(clientId);
+
+        if (clientInfo == null) {
+            throw new EventClientNotFoundException("The client is not found.");
+        }
+
+        Map<Integer, AddedListener> listenerInfoMap = clientInfo.listenerInfoMap;
+        synchronized (listenerInfoMap) {
+            Set<Integer> ids = listenerInfoMap.keySet();
+            return ids.toArray(new Integer[ids.size()]);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>The execution of this method includes a call to
+     * {@link MBeanServer#addNotificationListener(ObjectName,
+     * NotificationListener, NotificationFilter, Object)}.</p>
+     */
+    public Integer addListener(String clientId,
+            final ObjectName name,
+            NotificationFilter filter)
+            throws EventClientNotFoundException, InstanceNotFoundException {
+
+        if (logger.traceOn()) {
+            logger.trace("addListener", "");
+        }
+
+        return getClientInfo(clientId).addListenerInfo(name, filter);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>The execution of this method can include call to
+     * {@link MBeanServer#removeNotificationListener(ObjectName,
+     * NotificationListener, NotificationFilter, Object)}.</p>
+     */
+    public void removeListenerOrSubscriber(String clientId, Integer listenerId)
+    throws InstanceNotFoundException,
+            ListenerNotFoundException,
+            EventClientNotFoundException,
+            IOException {
+        if (logger.traceOn()) {
+            logger.trace("removeListener", ""+listenerId);
+        }
+        getClientInfo(clientId).removeListenerInfo(listenerId);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>The execution of this method includes a call to
+     * {@link MBeanServer#addNotificationListener(ObjectName,
+     * NotificationListener, NotificationFilter, Object)} for
+     * every MBean matching {@code name}.  If {@code name} is
+     * an {@code ObjectName} pattern, then the execution of this
+     * method will include a call to {@link MBeanServer#queryNames}.</p>
+     */
+    public Integer addSubscriber(String clientId, ObjectName name,
+            NotificationFilter filter)
+            throws EventClientNotFoundException, IOException {
+        if (logger.traceOn()) {
+            logger.trace("addSubscriber", "");
+        }
+        return getClientInfo(clientId).subscribeListenerInfo(name, filter);
+    }
+
+    public NotificationResult fetchNotifications(String clientId,
+            long startSequenceNumber,
+            int maxNotifs,
+            long timeout)
+            throws EventClientNotFoundException {
+        if (logger.traceOn()) {
+            logger.trace("fetchNotifications", "for "+clientId);
+        }
+        return getClientInfo(clientId).fetchNotifications(startSequenceNumber,
+                maxNotifs,
+                timeout);
+    }
+
+    public void removeClient(String clientId)
+    throws EventClientNotFoundException {
+        if (clientId == null)
+            throw new EventClientNotFoundException("Null clientId");
+        if (logger.traceOn()) {
+            logger.trace("removeClient", clientId);
+        }
+        ClientInfo ci = null;
+        ci = clientInfoMap.remove(clientId);
+
+        if (ci == null) {
+            throw new EventClientNotFoundException("clientId is "+clientId);
+        } else {
+            ci.clean();
+        }
+    }
+
+    public long lease(String clientId, long timeout)
+    throws IOException, EventClientNotFoundException {
+        if (logger.traceOn()) {
+            logger.trace("lease", "for "+clientId);
+        }
+        return getClientInfo(clientId).lease(timeout);
+    }
+
+    // ------------------------------------
+    // private classes
+    // ------------------------------------
+    private class ClientInfo {
+        String clientId;
+        EventBuffer buffer;
+        NotificationListener clientListener;
+        Map<Integer, AddedListener> listenerInfoMap =
+                new HashMap<Integer, AddedListener>();
+
+        ClientInfo(String clientId, EventForwarder forwarder) {
+            this.clientId = clientId;
+            this.forwarder = forwarder;
+            clientListener =
+                    new ForwardingClientListener(listenerInfoMap, forwarder);
+        }
+
+        Integer addOrSubscribeListenerInfo(
+                ObjectName name, NotificationFilter filter, boolean subscribe)
+                throws InstanceNotFoundException, IOException {
+
+            final Integer listenerId = nextListenerId();
+            AddedListener listenerInfo = new AddedListener(
+                    listenerId, filter, name, subscribe);
+            if (subscribe) {
+                eventSubscriber.subscribe(name,
+                        clientListener,
+                        filter,
+                        listenerInfo);
+            } else {
+                mbeanServer.addNotificationListener(name,
+                        clientListener,
+                        filter,
+                        listenerInfo);
+            }
+
+            synchronized(listenerInfoMap) {
+                listenerInfoMap.put(listenerId, listenerInfo);
+            }
+
+            return listenerId;
+        }
+
+        Integer addListenerInfo(ObjectName name,
+                NotificationFilter filter) throws InstanceNotFoundException {
+            try {
+                return addOrSubscribeListenerInfo(name, filter, false);
+            } catch (IOException e) { // can't happen
+                logger.warning(
+                        "EventClientDelegate.addListenerInfo",
+                        "unexpected exception", e);
+                throw new RuntimeException(e);
+            }
+        }
+
+        Integer subscribeListenerInfo(ObjectName name,
+                NotificationFilter filter) throws IOException {
+            try {
+                return addOrSubscribeListenerInfo(name, filter, true);
+            } catch (InstanceNotFoundException e) { // can't happen
+                logger.warning(
+                        "EventClientDelegate.subscribeListenerInfo",
+                        "unexpected exception", e);
+                throw new RuntimeException(e);
+            }
+        }
+
+        private final AtomicInteger nextListenerId = new AtomicInteger();
+
+        private Integer nextListenerId() {
+            return nextListenerId.getAndIncrement();
+        }
+
+        NotificationResult fetchNotifications(long startSequenceNumber,
+                int maxNotifs,
+                long timeout) {
+
+            if (!(forwarder instanceof FetchingEventForwarder)) {
+                throw new IllegalArgumentException(
+                        "This client is using Event Postal Service!");
+            }
+
+            return ((FetchingEventForwarder)forwarder).
+                    fetchNotifications(startSequenceNumber,
+                        maxNotifs, timeout);
+        }
+
+        void removeListenerInfo(Integer listenerId)
+        throws InstanceNotFoundException, ListenerNotFoundException, IOException {
+            AddedListener listenerInfo;
+            synchronized(listenerInfoMap) {
+                listenerInfo = listenerInfoMap.remove(listenerId);
+            }
+
+            if (listenerInfo == null) {
+                throw new ListenerNotFoundException("The listener is not found.");
+            }
+
+            if (listenerInfo.subscription) {
+                eventSubscriber.unsubscribe(listenerInfo.name,
+                        clientListener);
+            } else {
+                mbeanServer.removeNotificationListener(listenerInfo.name,
+                        clientListener,
+                        listenerInfo.filter,
+                        listenerInfo);
+            }
+        }
+
+        void clean(ObjectName name) {
+            synchronized(listenerInfoMap) {
+                for (Map.Entry<Integer, AddedListener> entry :
+                        listenerInfoMap.entrySet()) {
+                    AddedListener li = entry.getValue();
+                    if (name.equals(li.name)) {
+                        listenerInfoMap.remove(entry.getKey());
+                    }
+                }
+            }
+        }
+
+        void clean() {
+            synchronized(listenerInfoMap) {
+                for (AddedListener li : listenerInfoMap.values()) {
+                    try {
+                        mbeanServer.removeNotificationListener(li.name,
+                                clientListener);
+                    } catch (Exception e) {
+                        logger.trace("ClientInfo.clean", "removeNL", e);
+                    }
+                }
+                listenerInfoMap.clear();
+            }
+
+            try {
+                forwarder.close();
+            } catch (Exception e) {
+                logger.trace(
+                        "ClientInfo.clean", "forwarder.close", e);
+            }
+
+            if (leaseManager != null) {
+                leaseManager.stop();
+            }
+        }
+
+        long lease(long timeout) {
+            return leaseManager.lease(timeout);
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) {
+                return true;
+            }
+
+            if (o instanceof ClientInfo &&
+                    clientId.equals(((ClientInfo)o).clientId)) {
+                return true;
+            }
+
+            return false;
+        }
+
+        @Override
+        public int hashCode() {
+            return clientId.hashCode();
+        }
+
+        private EventForwarder forwarder = null;
+
+        private final Runnable leaseExpiryCallback = new Runnable() {
+            public void run() {
+                try {
+                    removeClient(clientId);
+                } catch (Exception e) {
+                    logger.trace(
+                            "ClientInfo.leaseExpiryCallback", "removeClient", e);
+                }
+            }
+        };
+
+        private LeaseManager leaseManager = new LeaseManager(leaseExpiryCallback);
+    }
+
+    private class ForwardingClientListener implements NotificationListener {
+        public ForwardingClientListener(Map<Integer, AddedListener> listenerInfoMap,
+                EventForwarder forwarder) {
+            this.listenerInfoMap = listenerInfoMap;
+            this.forwarder = forwarder;
+        }
+
+        public void handleNotification(Notification n, Object o) {
+            if (n == null || (!(o instanceof AddedListener))) {
+                if (logger.traceOn()) {
+                    logger.trace("ForwardingClientListener-handleNotification",
+                            "received a unknown notif");
+                }
+                return;
+            }
+
+            AddedListener li = (AddedListener) o;
+
+            if (checkListenerPermission(li.name,li.acc)) {
+                try {
+                    forwarder.forward(n, li.listenerId);
+                } catch (Exception e) {
+                    if (logger.traceOn()) {
+                        logger.trace(
+                                "ForwardingClientListener-handleNotification",
+                                "forwarding failed.", e);
+                    }
+                }
+            }
+        }
+
+        private final Map<Integer, AddedListener> listenerInfoMap;
+        private final EventForwarder forwarder;
+    }
+
+    private class AddedListener {
+        final int listenerId;
+        final NotificationFilter filter;
+        final ObjectName name;
+        final boolean subscription;
+        final AccessControlContext acc;
+
+        public AddedListener(
+                int listenerId,
+                NotificationFilter filter,
+                ObjectName name,
+                boolean subscription) {
+            this.listenerId = listenerId;
+            this.filter = filter;
+            this.name = name;
+            this.subscription = subscription;
+            acc = AccessController.getContext();
+        }
+    }
+
+    private class CleanListener implements NotificationListener {
+        public void handleNotification(Notification notification,
+                Object handback) {
+            if (notification instanceof MBeanServerNotification) {
+                if (MBeanServerNotification.UNREGISTRATION_NOTIFICATION.equals(
+                        notification.getType())) {
+                    final ObjectName name =
+                            ((MBeanServerNotification)notification).getMBeanName();
+
+                    final Collection <ClientInfo> list =
+                            Collections.unmodifiableCollection(clientInfoMap.values());
+
+                    for (ClientInfo ci : list) {
+                        ci.clean(name);
+                    }
+                }
+
+            }
+        }
+    }
+
+    // -------------------------------------------------
+    // private method
+    // -------------------------------------------------
+    private ClientInfo getClientInfo(String clientId)
+    throws EventClientNotFoundException {
+        ClientInfo clientInfo = null;
+        clientInfo = clientInfoMap.get(clientId);
+
+        if (clientInfo == null) {
+            throw new EventClientNotFoundException("The client is not found.");
+        }
+
+        return clientInfo;
+    }
+
+    /**
+     * Explicitly check the MBeanPermission for
+     * the current access control context.
+     */
+    private boolean checkListenerPermission(final ObjectName name,
+            final AccessControlContext acc) {
+        if (logger.traceOn()) {
+            logger.trace("checkListenerPermission", "");
+        }
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            try {
+                ObjectInstance oi = (ObjectInstance) AccessController.doPrivileged(
+                        new PrivilegedExceptionAction<Object>() {
+                    public Object run()
+                    throws InstanceNotFoundException {
+                        return mbeanServer.getObjectInstance(name);
+                    }
+                });
+
+                String classname = oi.getClassName();
+                MBeanPermission perm = new MBeanPermission(
+                        classname,
+                        null,
+                        name,
+                        "addNotificationListener");
+                sm.checkPermission(perm, acc);
+            } catch (Exception e) {
+                if (logger.debugOn()) {
+                    logger.debug("checkListenerPermission", "refused.", e);
+                }
+                return false;
+            }
+        }
+        return true;
+    }
+
+    // ------------------------------------
+    // private variables
+    // ------------------------------------
+    private final MBeanServer mbeanServer;
+    private volatile String mbeanServerName = null;
+    private Map<String, ClientInfo> clientInfoMap =
+            new ConcurrentHashMap<String, ClientInfo>();
+
+    private final CleanListener cleanListener = new CleanListener();
+    private final EventSubscriber eventSubscriber;
+
+    private static final ClassLogger logger =
+            new ClassLogger("javax.management.event", "EventClientDelegate");
+
+    private static final
+            Map<MBeanServer, WeakReference<EventClientDelegate>> delegateMap =
+            new WeakHashMap<MBeanServer, WeakReference<EventClientDelegate>>();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/javax/management/event/EventClientDelegateMBean.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,318 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package javax.management.event;
+
+import com.sun.jmx.mbeanserver.Util;
+import java.io.IOException;
+import javax.management.InstanceNotFoundException;
+import javax.management.ListenerNotFoundException;
+import javax.management.MBeanException;
+import javax.management.NotificationFilter;
+import javax.management.ObjectName;
+import javax.management.remote.NotificationResult;
+
+/**
+ * <p>This interface specifies necessary methods on the MBean server
+ * side for a JMX remote client to manage its notification listeners as
+ * if they are local.
+ * Users do not usually work directly with this MBean; instead, the {@link
+ * EventClient} class is designed to be used directly by the user.</p>
+ *
+ * <p>A default implementation of this interface can be added to an MBean
+ * Server in one of several ways.</p>
+ *
+ * <ul>
+ * <li><p>The most usual is to insert an {@link
+ * javax.management.remote.MBeanServerForwarder MBeanServerForwarder} between
+ * the {@linkplain javax.management.remote.JMXConnectorServer Connector Server}
+ * and the MBean Server, that will intercept accesses to the Event Client
+ * Delegate MBean and treat them as the real MBean would. This forwarder is
+ * inserted by default with the standard RMI Connector Server, and can also
+ * be created explicitly using {@link EventClientDelegate#newForwarder()}.
+ *
+ * <li><p>A variant on the above is to replace the MBean Server that is
+ * used locally with a forwarder as described above.  Since
+ * {@code MBeanServerForwarder} extends {@code MBeanServer}, you can use
+ * a forwarder anywhere you would have used the original MBean Server.  The
+ * code to do this replacement typically looks something like this:</p>
+ *
+ * <pre>
+ * MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();  // or whatever
+ * MBeanServerForwarder mbsf = EventClientDelegate.newForwarder();
+ * mbsf.setMBeanServer(mbs);
+ * mbs = mbsf;
+ * // now use mbs just as you did before, but it will have an EventClientDelegate
+ * </pre>
+ *
+ * <li><p>The final way is to create an instance of {@link EventClientDelegate}
+ * and register it in the MBean Server under the standard {@linkplain
+ * #OBJECT_NAME name}:</p>
+ *
+ * <pre>
+ * MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();  // or whatever
+ * EventClientDelegate ecd = EventClientDelegate.getEventClientDelegate(mbs);
+ * mbs.registerMBean(ecd, EventClientDelegateMBean.OBJECT_NAME);
+ * <pre>
+ * </ul>
+ *
+ * @since JMX 2.0
+ */
+public interface EventClientDelegateMBean {
+    /**
+     * The string representation of {@link #OBJECT_NAME}.
+     */
+    // This shouldn't really be necessary but an apparent javadoc bug
+    // meant that the {@value} tags didn't work if this was a
+    // field in EventClientDelegate, even a public field.
+    public static final String OBJECT_NAME_STRING =
+            "javax.management.event:type=EventClientDelegate";
+
+    /**
+     * The standard <code>ObjectName</code> used to register the default
+     * <code>EventClientDelegateMBean</code>.  The name is
+     * <code>{@value #OBJECT_NAME_STRING}</code>.
+     */
+    public final static ObjectName OBJECT_NAME =
+            Util.newObjectName(OBJECT_NAME_STRING);
+
+    /**
+     * A unique listener identifier specified for an EventClient.
+     * Any notification associated with this id is intended for
+     * the EventClient which receives the notification, rather than
+     * a listener added using that EventClient.
+     */
+    public static final int EVENT_CLIENT_LISTENER_ID = -100;
+
+    /**
+     * Adds a new client to the <code>EventClientDelegateMBean</code> with
+     * a user-specified
+     * {@link EventForwarder} to forward notifications to the client. The
+     * <code>EventForwarder</code> is created by calling
+     * {@link javax.management.MBeanServer#instantiate(String, Object[],
+     * String[])}.
+     *
+     * @param className The class name used to create an
+     * {@code EventForwarder}.
+     * @param params An array containing the parameters of the constructor to
+     * be invoked.
+     * @param sig An array containing the signature of the constructor to be
+     * invoked
+     * @return A client identifier.
+     * @exception IOException Reserved for a remote call to throw on the client
+     * side.
+     * @exception MBeanException An exception thrown when creating the user
+     * specified <code>EventForwarder</code>.
+     */
+    public String addClient(String className, Object[] params, String[] sig)
+    throws IOException, MBeanException;
+
+    /**
+     * Adds a new client to the <code>EventClientDelegateMBean</code> with
+     * a user-specified
+     * {@link EventForwarder} to forward notifications to the client. The
+     * <code>EventForwarder</code> is created by calling
+     * {@link javax.management.MBeanServer#instantiate(String, ObjectName,
+     * Object[], String[])}. A user-specified class loader is used to create
+     * this <code>EventForwarder</code>.
+     *
+     * @param className The class name used to create an
+     * {@code EventForwarder}.
+     * @param classLoader An ObjectName registered as a
+     *        <code>ClassLoader</code> MBean.
+     * @param params An array containing the parameters of the constructor to
+     * be invoked.
+     * @param sig An array containing the signature of the constructor to be
+     * invoked
+     * @return A client identifier.
+     * @exception IOException Reserved for a remote call to throw on the client
+     * side.
+     * @exception MBeanException An exception thrown when creating the user
+     * specified <code>EventForwarder</code>.
+     */
+    public String addClient(String className,
+            ObjectName classLoader,
+            Object[] params,
+            String[] sig) throws IOException, MBeanException;
+
+    /**
+     * Removes an added client. Calling this method will remove all listeners
+     * added with the client.
+     *
+     * @exception EventClientNotFoundException If the {@code clientId} is
+     * not found.
+     * @exception IOException Reserved for a remote call to throw on the client
+     * side.
+     */
+    public void removeClient(String clientID)
+    throws EventClientNotFoundException, IOException;
+
+    /**
+     * Returns the identifiers of listeners added or subscribed to with the
+     * specified client identifier.
+     * <P> If no listener is currently registered with the client, an empty
+     * array is returned.
+     * @param clientID The client identifier with which the listeners are
+     * added or subscribed to.
+     * @return An array of listener identifiers.
+     * @exception EventClientNotFoundException If the {@code clientId} is
+     * not found.
+     * @exception IOException Reserved for a remote call to throw on the client
+     * side.
+     */
+    public Integer[] getListenerIds(String clientID)
+    throws EventClientNotFoundException, IOException;
+
+    /**
+     * Adds a listener to receive notifications from an MBean and returns
+     * a non-negative integer as the identifier of the listener.
+     * <P>This method is called by an {@link EventClient} to implement the
+     * method  {@link EventClient#addNotificationListener(ObjectName,
+     * NotificationListener, NotificationFilter, Object)}.
+     *
+     * @param name The name of the MBean onto which the listener should be added.
+     * @param filter The filter object. If  {@code filter} is null,
+     *        no filtering will be performed before handling notifications.
+     * @param clientId The client identifier with which the listener is added.
+     * @return A listener identifier.
+     * @throws EventClientNotFoundException Thrown if the {@code clientId} is
+     * not found.
+     * @throws InstanceNotFoundException Thrown if the MBean is not found.
+     * @throws IOException Reserved for a remote call to throw on the client
+     * side.
+     */
+    public Integer addListener(String clientId,
+            ObjectName name,
+            NotificationFilter filter)
+            throws InstanceNotFoundException, EventClientNotFoundException,
+            IOException;
+
+
+    /**
+     * <p>Subscribes a listener to receive notifications from an MBean or a
+     * set of MBeans represented by an {@code ObjectName} pattern.  (It is
+     * not an error if no MBeans match the pattern at the time this method is
+     * called.)</p>
+     *
+     * <p>Returns a non-negative integer as the identifier of the listener.</p>
+     *
+     * <p>This method is called by an {@link EventClient} to execute its
+     * method {@link EventClient#subscribe(ObjectName, NotificationListener,
+     * NotificationFilter, Object)}.</p>
+     *
+     * @param clientId The remote client's identifier.
+     * @param name The name of an MBean or an {@code ObjectName} pattern
+     * representing a set of MBeans to which the listener should listen.
+     * @param filter The filter object. If {@code filter} is null, no
+     * filtering will be performed before notifications are handled.
+     *
+     * @return A listener identifier.
+     *
+     * @throws IllegalArgumentException If the {@code name} or
+     * {@code listener} is null.
+     * @throws EventClientNotFoundException If the client ID is not found.
+     * @throws IOException Reserved for a remote client to throw if
+     * an I/O error occurs.
+     *
+     * @see EventConsumer#subscribe(ObjectName, NotificationListener,
+     * NotificationFilter,Object)
+     * @see #removeListenerOrSubscriber(String, Integer)
+     */
+    public Integer addSubscriber(String clientId, ObjectName name,
+            NotificationFilter filter)
+            throws EventClientNotFoundException, IOException;
+
+    /**
+     * Removes a listener, to stop receiving notifications.
+     * <P> This method is called by an {@link EventClient} to execute its
+     * methods {@link EventClient#removeNotificationListener(ObjectName,
+     * NotificationListener, NotificationFilter, Object)},
+     * {@link EventClient#removeNotificationListener(ObjectName,
+     * NotificationListener)}, and {@link EventClient#unsubscribe}.
+     *
+     * @param clientId The client identifier with which the listener was added.
+     * @param listenerId The listener identifier to be removed. This must be
+     * an identifier returned by a previous {@link #addListener addListener}
+     * or {@link #addSubscriber addSubscriber} call.
+     *
+     * @throws InstanceNotFoundException if the MBean on which the listener
+     * was added no longer exists.
+     * @throws ListenerNotFoundException if there is no listener with the
+     * given {@code listenerId}.
+     * @throws EventClientNotFoundException if the {@code clientId} is
+     * not found.
+     * @throws IOException Reserved for a remote call to throw on the client
+     * side.
+     */
+    public void removeListenerOrSubscriber(String clientId, Integer listenerId)
+    throws InstanceNotFoundException, ListenerNotFoundException,
+            EventClientNotFoundException, IOException;
+
+    /**
+     * Called by a client to fetch notifications that are to be sent to its
+     * listeners.
+     *
+     * @param clientId The client's identifier.
+     * @param startSequenceNumber The first sequence number to
+     * consider.
+     * @param timeout The maximum waiting time.
+     * @param maxNotifs The maximum number of notifications to return.
+     *
+     * @throws EventClientNotFoundException Thrown if the {@code clientId} is
+     * not found.
+     * @throws IllegalArgumentException if the client was {@linkplain
+     * #addClient(String, Object[], String[]) added} with an {@link
+     * EventForwarder} that is not a {@link FetchingEventForwarder}.
+     * @throws IOException Reserved for a remote call to throw on the client
+     * side.
+     */
+    public NotificationResult fetchNotifications(String clientId,
+            long startSequenceNumber,
+            int maxNotifs,
+            long timeout)
+            throws EventClientNotFoundException, IOException;
+
+    /**
+     * An {@code EventClient} calls this method to keep its {@code clientId}
+     * alive in this MBean. The client will be removed if the lease times out.
+     *
+     * @param clientId The client's identifier.
+     * @param timeout The time in milliseconds by which the lease is to be
+     * extended.  The value zero has no special meaning, so it will cause the
+     * lease to time out immediately.
+     *
+     * @return The new lifetime of the lease in milliseconds.  This may be
+     * different from the requested time.
+     *
+     * @throws EventClientNotFoundException if the {@code clientId} is
+     * not found.
+     * @throws IOException reserved for a remote call to throw on the client
+     * side.
+     * @throws IllegalArgumentException if {@code clientId} is null or
+     * {@code timeout} is negative.
+     */
+    public long lease(String clientId, long timeout)
+    throws IOException, EventClientNotFoundException;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/javax/management/event/EventClientNotFoundException.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package javax.management.event;
+
+import javax.management.JMException;
+
+/**
+ * Thrown if an event client identifier is unknown.
+ */
+public class EventClientNotFoundException extends JMException {
+
+    /* Serial version */
+    private static final long serialVersionUID = -3910667345840643089L;
+
+    /**
+     *Constructs a {@code ClientNotFoundException} without a detail message.
+     */
+    public EventClientNotFoundException() {
+        super();
+    }
+
+    /**
+     * Constructs a {@code ClientNotFoundException} with the specified detail message.
+     * @param message The message.
+     */
+    public EventClientNotFoundException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs a {@code ClientNotFoundException} with the specified detail message
+     * and cause.
+     *
+     * @param message The message.
+     * @param cause The cause (which is saved for later retrieval by the
+     * {@code Throwable.getCause()} method). A null value is permitted, and indicates
+     * that the cause is non-existent or unknown.
+     */
+    public EventClientNotFoundException(String message, Throwable cause) {
+        super(message);
+
+        initCause(cause);
+    }
+
+    /**
+     * Constructs a new exception with the specified cause.
+     * @param cause The cause (which is saved for later retrieval by the
+     * {@code Throwable.getCause()} method). A null value is permitted, and indicates
+     * that the cause is non-existent or unknown.
+     */
+    public EventClientNotFoundException(Throwable cause) {
+        super();
+
+        initCause(cause);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/javax/management/event/EventConsumer.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package javax.management.event;
+
+import java.io.IOException;
+import javax.management.ListenerNotFoundException;
+import javax.management.NotificationFilter;
+import javax.management.NotificationListener;
+import javax.management.ObjectName;
+
+/**
+ * This interface specifies methods to subscribe a listener to receive events
+ * from an MBean or a set of MBeans. The MBeans can already be registered in
+ * an MBean server, or they can be pending registration, or they can be MBeans
+ * that will never be registered, or they can be MBeans that will be registered
+ * then unregistered.
+ * @since JMX 2.0
+ */
+public interface EventConsumer {
+    /**
+     * <p>Subscribes a listener to receive events from an MBean or a set
+     * of MBeans represented by an {@code ObjectName} pattern.</p>
+     *
+     * <P> An event emitted by an MBean is forwarded to every listener that was
+     * subscribed with the name of that MBean, or with a pattern that matches
+     * that name.</p>
+     *
+     * @param name The name of an MBean or an {@code ObjectName} pattern
+     * representing a set of MBeans to which the listener should listen.
+     * @param listener The listener object that will handle the
+     * notifications emitted by the MBeans.
+     * @param filter The filter object. If {@code filter} is null, no
+     * filtering will be performed before notification handling.
+     * @param handback The context to be sent to the listener when a
+     * notification is emitted.
+     *
+     * @throws IllegalArgumentException If the {@code name} or
+     * {@code listener} is null.
+     * @throws IOException for a remote client, thrown if
+     * an I/O error occurs.
+     * @see #unsubscribe(ObjectName, NotificationListener)
+     */
+    public void subscribe(ObjectName name,
+            NotificationListener listener,
+            NotificationFilter filter,
+            Object handback)
+            throws IOException;
+
+    /**
+     * <p>Unsubscribes a listener which is listening to an MBean or a set of
+     * MBeans represented by an {@code ObjectName} pattern.</p>
+     *
+     * <p>The listener to be removed must have been added by the {@link
+     * #subscribe subscribe} method with the given {@code name}. If the {@code
+     * name} is a pattern, then the {@code subscribe} must have used the same
+     * pattern. If the same listener has been subscribed more than once to the
+     * {@code name}, perhaps with different filters or handbacks, then all such
+     * listeners are removed.</p>
+     *
+     * @param name The name of the MBean or an {@code ObjectName} pattern
+     * representing a set of MBeans to which the listener was subscribed.
+     * @param listener A listener that was previously subscribed to the
+     * MBean(s).
+     *
+     * @throws ListenerNotFoundException The given {@code listener} was not
+     * subscribed to the given {@code name}.
+     * @throws IOException for a remote client, thrown if
+     * an I/O error occurs.
+     *
+     * @see #subscribe
+     */
+    public void unsubscribe(ObjectName name,
+            NotificationListener listener)
+            throws ListenerNotFoundException, IOException;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/javax/management/event/EventForwarder.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package javax.management.event;
+
+import java.io.IOException;
+import javax.management.Notification;
+
+/**
+ * This interface can be used to specify a custom forwarding mechanism for
+ * {@code EventClientDelegateMBean} to forward events to the client.
+ *
+ * @see <a href="package-summary.html#transports">Custom notification
+ * transports</a>
+ */
+public interface EventForwarder {
+    /**
+     * Forwards a notification.
+     * @param n The notification to be forwarded to a remote listener.
+     * @param listenerId The identifier of the listener to receive the notification.
+     * @throws IOException If it is closed or an I/O error occurs.
+     */
+    public void forward(Notification n, Integer listenerId)
+        throws IOException;
+
+    /**
+     * Informs the {@code EventForwarder} to shut down.
+     * <p> After this method is called, any call to the method
+     * {@link #forward forward(Notification, Integer)} may get an {@code IOException}.
+     * @throws IOException If an I/O error occurs.
+     */
+    public void close() throws IOException;
+
+    /**
+     * Sets an event client identifier created by {@link EventClientDelegateMBean}.
+     * <P> This method will be called just after this {@code EventForwarder}
+     * is constructed and before calling the {@code forward} method to forward any
+     * notifications.
+     */
+    public void setClientId(String clientId) throws IOException;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/javax/management/event/EventReceiver.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package javax.management.event;
+
+import javax.management.remote.NotificationResult;
+
+/**
+ * An object implementing this interface is passed by an {@link EventClient}
+ * to its {@link EventRelay}, to allow the {@code EventRelay} to communicate
+ * received notifications to the {@code EventClient}.
+ *
+ * @see <a href="package-summary.html#transports">Custom notification
+ * transports</a>
+ */
+public interface EventReceiver {
+
+    /**
+     * This method is implemented by {@code EventClient} as a callback to
+     * receive notifications from {@code EventRelay}.
+     * <P>The notifications are included in an object specified by the class
+     * {@link NotificationResult}. In
+     * addition to a set of notifications, the class object also contains two values:
+     * {@code earliestSequenceNumber} and {@code nextSequenceNumber}.
+     * These two values determine whether any notifications have been lost.
+     * The {@code nextSequenceNumber} value of the last time is compared
+     * to the received value {@code earliestSequenceNumber}. If the
+     * received {@code earliesSequenceNumber} is greater, than the difference
+     * signifies the number of lost notifications. A sender should
+     * ensure the sequence of notifications sent, meaning that the value
+     * {@code earliestSequenceNumber} of the next return should be always equal to
+     * or greater than the value {@code nextSequenceNumber} of the last return.
+     *
+     * @param nr the received notifications and sequence numbers.
+     */
+    public void receive(NotificationResult nr);
+
+    /**
+     * Allows the {@link EventRelay} to report when it receives an unexpected
+     * exception, which may be fatal and which may make it stop receiving
+     * notifications.
+     *
+     * @param t The unexpected exception received while {@link EventRelay} was running.
+     */
+    public void failed(Throwable t);
+
+    /**
+     * Allows the {@link EventRelay} to report when it receives an unexpected
+     * exception that is not fatal. For example, a notification received is not
+     * serializable or its class is not found.
+     *
+     * @param e The unexpected exception received while notifications are being received.
+     */
+    public void nonFatal(Exception e);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/javax/management/event/EventRelay.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package javax.management.event;
+
+import java.io.IOException;
+import java.util.concurrent.Executors;  // for javadoc
+import java.util.concurrent.ScheduledFuture;
+
+/**
+ * This interface is used to specify a way to receive
+ * notifications from a remote MBean server and then to forward the notifications
+ * to an {@link EventClient}.
+ *
+ * @see <a href="package-summary.html#transports">Custom notification
+ * transports</a>
+ */
+public interface EventRelay {
+    /**
+     * Returns an identifier that is used by this {@code EventRelay} to identify
+     * the client when communicating with the {@link EventClientDelegateMBean}.
+     * <P> This identifier is obtained by calling
+     * {@link EventClientDelegateMBean#addClient(String, Object[], String[])
+     * EventClientDelegateMBean.addClient}.
+     * <P> It is the {@code EventRelay} that calls {@code EventClientDelegateMBean} to obtain
+     * the client identifier because it is the {@code EventRelay} that decides
+     * how to get notifications from the {@code EventClientDelegateMBean},
+     * by creating the appropriate {@link EventForwarder}.
+     *
+     * @return A client identifier.
+     * @throws IOException If an I/O error occurs when communicating with
+     * the {@code EventClientDelegateMBean}.
+     */
+    public String getClientId() throws IOException;
+
+    /**
+     * This method is called by {@link EventClient} to register a callback
+     * to receive notifications from an {@link EventClientDelegateMBean} object.
+     * A {@code null} value is allowed, which means that the {@code EventClient} suspends
+     * reception of notifications, so that the {@code EventRelay} can decide to stop receiving
+     * notifications from its {@code EventForwarder}.
+     *
+     * @param eventReceiver An {@link EventClient} callback to receive
+     * events.
+     */
+    public void setEventReceiver(EventReceiver eventReceiver);
+
+    /**
+     * Stops receiving and forwarding notifications and performs any necessary
+     * cleanup.  After calling this method, the {@link EventClient} will never
+     * call any other methods of this object.
+     *
+     * @throws IOException If an I/O exception appears.
+     *
+     * @see EventClient#close
+     */
+    public void stop() throws IOException;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/javax/management/event/EventSubscriber.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,381 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package javax.management.event;
+
+import com.sun.jmx.remote.util.ClassLogger;
+import java.io.IOException;
+import java.lang.ref.WeakReference;
+import java.lang.reflect.Method;
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.WeakHashMap;
+import javax.management.InstanceNotFoundException;
+import javax.management.ListenerNotFoundException;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerConnection;
+import javax.management.MBeanServerDelegate;
+import javax.management.MBeanServerNotification;
+import javax.management.Notification;
+import javax.management.NotificationBroadcaster;
+import javax.management.NotificationFilter;
+import javax.management.NotificationListener;
+import javax.management.ObjectName;
+import javax.management.Query;
+import javax.management.QueryEval;
+import javax.management.QueryExp;
+
+/**
+ * <p>An object that can be used to subscribe for notifications from all MBeans
+ * in an MBeanServer that match a pattern.  For example, to listen for
+ * notifications from all MBeans in the MBeanServer {@code mbs} that match
+ * {@code com.example:type=Controller,name=*} you could write:</p>
+ *
+ * <pre>
+ * EventSubscriber subscriber = EventSubscriber.getEventSubscriber(mbs);
+ * ObjectName pattern = new ObjectName("com.example:type=Controller,name=*");
+ * NotificationListener myListener = ...;
+ * NotificationFilter myFilter = null;  // or whatever
+ * Object handback = null;              // or whatever
+ * subscriber.subscribe(pattern, myListener, myFilter, myHandback);
+ * </pre>
+ */
+public class EventSubscriber implements EventConsumer {
+    /**
+     * Returns an {@code EventSubscriber} object to subscribe for notifications
+     * from the given {@code MBeanServer}.  Calling this method more
+     * than once with the same parameter may or may not return the same object.
+     *
+     * @param mbs the {@code MBeanServer} containing MBeans to be subscribed to.
+     * @return An {@code EventSubscriber} object.
+     *
+     * @throws NullPointerException if mbs is null.
+     */
+    public static EventSubscriber getEventSubscriber(MBeanServer mbs) {
+        if (mbs == null)
+            throw new NullPointerException("Null MBeanServer");
+
+        EventSubscriber eventSubscriber = null;
+        synchronized (subscriberMap) {
+            final WeakReference<EventSubscriber> wrf = subscriberMap.get(mbs);
+            eventSubscriber = (wrf == null) ? null : wrf.get();
+
+            if (eventSubscriber == null) {
+                eventSubscriber = new EventSubscriber(mbs);
+
+                subscriberMap.put(mbs,
+                        new WeakReference<EventSubscriber>(eventSubscriber));
+            }
+        }
+
+        return eventSubscriber;
+    }
+
+    private EventSubscriber(final MBeanServer mbs) {
+        logger.trace("EventSubscriber", "create a new one");
+        this.mbeanServer = mbs;
+
+        Exception x = null;
+        try {
+            AccessController.doPrivileged(
+                    new PrivilegedExceptionAction<Void>() {
+                public Void run() throws Exception {
+                    mbs.addNotificationListener(
+                            MBeanServerDelegate.DELEGATE_NAME,
+                            myMBeanServerListener, null, null);
+                    return null;
+                }
+            });
+        } catch (PrivilegedActionException ex) {
+            x = ex.getException();
+        }
+
+        // handle possible exceptions.
+        //
+        // Fail unless x is null or x is instance of InstanceNotFoundException
+        // The logic here is that if the MBeanServerDelegate is not present,
+        // we will assume that the connection will not emit any
+        // MBeanServerNotifications.
+        //
+        if (x != null && !(x instanceof InstanceNotFoundException)) {
+            if (x instanceof RuntimeException)
+                throw (RuntimeException) x;
+            throw new RuntimeException(
+                    "Can't add listener to MBean server delegate: " + x, x);
+        }
+    }
+
+    public void subscribe(ObjectName name,
+            NotificationListener listener,
+            NotificationFilter filter,
+            Object handback)
+            throws IOException {
+
+        if (logger.traceOn())
+            logger.trace("subscribe", "" + name);
+
+        if (name == null)
+            throw new IllegalArgumentException("Null MBean name");
+
+        if (listener == null)
+            throw new IllegalArgumentException("Null listener");
+
+        final ListenerInfo li = new ListenerInfo(listener, filter, handback);
+        List<ListenerInfo> list;
+
+        Map<ObjectName, List<ListenerInfo>> map;
+        Set<ObjectName> names;
+        if (name.isPattern()) {
+            map = patternSubscriptionMap;
+            names = mbeanServer.queryNames(name, notificationBroadcasterExp);
+        } else {
+            map = exactSubscriptionMap;
+            names = Collections.singleton(name);
+        }
+
+        synchronized (map) {
+            list = map.get(name);
+            if (list == null) {
+                list = new ArrayList<ListenerInfo>();
+                map.put(name, list);
+            }
+            list.add(li);
+        }
+
+        for (ObjectName mbeanName : names) {
+            try {
+                mbeanServer.addNotificationListener(mbeanName,
+                                                    listener,
+                                                    filter,
+                                                    handback);
+            } catch (Exception e) {
+                logger.fine("subscribe", "addNotificationListener", e);
+            }
+        }
+    }
+
+    public void unsubscribe(ObjectName name,
+            NotificationListener listener)
+            throws ListenerNotFoundException, IOException {
+
+        if (logger.traceOn())
+            logger.trace("unsubscribe", "" + name);
+
+        if (name == null)
+            throw new IllegalArgumentException("Null MBean name");
+
+        if (listener == null)
+            throw new ListenerNotFoundException();
+
+        Map<ObjectName, List<ListenerInfo>> map;
+        Set<ObjectName> names;
+
+        if (name.isPattern()) {
+            map = patternSubscriptionMap;
+            names = mbeanServer.queryNames(name, notificationBroadcasterExp);
+        } else {
+            map = exactSubscriptionMap;
+            names = Collections.singleton(name);
+        }
+
+        final ListenerInfo li = new ListenerInfo(listener, null, null);
+        List<ListenerInfo> list;
+        synchronized (map) {
+            list = map.get(name);
+            if (list == null || !list.remove(li))
+                throw new ListenerNotFoundException();
+
+            if (list.isEmpty())
+                map.remove(name);
+        }
+
+        for (ObjectName mbeanName : names) {
+            try {
+                mbeanServer.removeNotificationListener(mbeanName, li.listener);
+            } catch (Exception e) {
+                logger.fine("unsubscribe", "removeNotificationListener", e);
+            }
+        }
+    }
+
+    // ---------------------------------
+    // private stuff
+    // ---------------------------------
+    // used to receive MBeanServerNotification
+    private NotificationListener myMBeanServerListener =
+            new NotificationListener() {
+        public void handleNotification(Notification n, Object hb) {
+            if (!(n instanceof MBeanServerNotification) ||
+                    !MBeanServerNotification.
+                    REGISTRATION_NOTIFICATION.equals(n.getType())) {
+                return;
+            }
+
+            final ObjectName name =
+                    ((MBeanServerNotification)n).getMBeanName();
+            try {
+                if (!mbeanServer.isInstanceOf(name,
+                        NotificationBroadcaster.class.getName())) {
+                    return;
+                }
+            } catch (Exception e) {
+                // The only documented exception is InstanceNotFoundException,
+                // which could conceivably happen if the MBean is unregistered
+                // immediately after being registered.
+                logger.fine("myMBeanServerListener.handleNotification",
+                        "isInstanceOf", e);
+                return;
+            }
+
+            final List<ListenerInfo> listeners = new ArrayList<ListenerInfo>();
+
+            // If there are subscribers for the exact name that has just arrived
+            // then add their listeners to the list.
+            synchronized (exactSubscriptionMap) {
+                List<ListenerInfo> exactListeners = exactSubscriptionMap.get(name);
+                if (exactListeners != null)
+                    listeners.addAll(exactListeners);
+            }
+
+            // For every subscription pattern that matches the new name,
+            // add all the listeners for that pattern to "listeners".
+            synchronized (patternSubscriptionMap) {
+                for (ObjectName on : patternSubscriptionMap.keySet()) {
+                    if (on.apply(name)) {
+                        listeners.addAll(patternSubscriptionMap.get(on));
+                    }
+                }
+            }
+
+            // Add all the listeners just found to the new MBean.
+            for (ListenerInfo li : listeners) {
+                try {
+                    mbeanServer.addNotificationListener(
+                            name,
+                            li.listener,
+                            li.filter,
+                            li.handback);
+                } catch (Exception e) {
+                    logger.fine("myMBeanServerListener.handleNotification",
+                            "addNotificationListener", e);
+                }
+            }
+        }
+    };
+
+    private static class ListenerInfo {
+        public final NotificationListener listener;
+        public final NotificationFilter filter;
+        public final Object handback;
+
+        public ListenerInfo(NotificationListener listener,
+                NotificationFilter filter,
+                Object handback) {
+
+            if (listener == null)
+                throw new IllegalArgumentException("Null listener");
+
+            this.listener = listener;
+            this.filter = filter;
+            this.handback = handback;
+        }
+
+        /* Two ListenerInfo instances are equal if they have the same
+         * NotificationListener.  This means that we can use List.remove
+         * to implement the two-argument removeNotificationListener.
+         */
+        @Override
+        public boolean equals(Object o) {
+            if (o == this)
+                return true;
+
+            if (!(o instanceof ListenerInfo))
+                return false;
+
+            return listener.equals(((ListenerInfo)o).listener);
+        }
+
+        @Override
+        public int hashCode() {
+            return listener.hashCode();
+        }
+    }
+
+    // ---------------------------------
+    // private methods
+    // ---------------------------------
+    // ---------------------------------
+    // private variables
+    // ---------------------------------
+    private final MBeanServer mbeanServer;
+
+    private final Map<ObjectName, List<ListenerInfo>> exactSubscriptionMap =
+            new HashMap<ObjectName, List<ListenerInfo>>();
+    private final Map<ObjectName, List<ListenerInfo>> patternSubscriptionMap =
+            new HashMap<ObjectName, List<ListenerInfo>>();
+
+
+
+    // trace issues
+    private static final ClassLogger logger =
+            new ClassLogger("javax.management.event", "EventSubscriber");
+
+    // Compatibility code, so we can run on Tiger:
+    private static final QueryExp notificationBroadcasterExp;
+    static {
+        QueryExp broadcasterExp;
+        try {
+            final Method m = Query.class.getMethod("isInstanceOf",
+                    new Class[] {String.class});
+            broadcasterExp = (QueryExp)m.invoke(Query.class,
+                    new Object[] {NotificationBroadcaster.class.getName()});
+        } catch (Exception e) {
+            broadcasterExp = new BroadcasterQueryExp();
+        }
+        notificationBroadcasterExp = broadcasterExp;
+    }
+    private static class BroadcasterQueryExp extends QueryEval implements QueryExp {
+        private static final long serialVersionUID = 1234L;
+        public boolean apply(ObjectName name) {
+            try {
+                return getMBeanServer().isInstanceOf(
+                        name, NotificationBroadcaster.class.getName());
+            } catch (Exception e) {
+                return false;
+            }
+        }
+    }
+
+    private static final
+            Map<MBeanServerConnection, WeakReference<EventSubscriber>> subscriberMap =
+            new WeakHashMap<MBeanServerConnection, WeakReference<EventSubscriber>>();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/javax/management/event/FetchingEventForwarder.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package javax.management.event;
+
+import com.sun.jmx.event.EventBuffer;
+import com.sun.jmx.remote.util.ClassLogger;
+import java.io.IOException;
+import java.util.List;
+import javax.management.Notification;
+import javax.management.remote.NotificationResult;
+import javax.management.remote.TargetedNotification;
+
+/**
+ * This class is used by {@link FetchingEventRelay}. When
+ * {@link FetchingEventRelay} calls {@link
+ * EventClientDelegateMBean#addClient(String, Object[], String[])} to get a new
+ * client identifier, it uses
+ * this class name as the first argument to ask {@code EventClientDelegateMBean}
+ * to create an object of this class.
+ * Then {@code EventClientDelegateMBean} forwards client notifications
+ * to this object.
+ * When {@link FetchingEventRelay} calls
+ * {@link EventClientDelegateMBean#fetchNotifications(String, long, int, long)}
+ * to fetch notifications, the {@code EventClientDelegateMBean} will forward
+ * the call to this object.
+ */
+public class FetchingEventForwarder implements EventForwarder {
+
+    /**
+     * Construct a new {@code FetchingEventForwarder} with the given
+     * buffer size.
+     * @param bufferSize the size of the buffer that will store notifications
+     * until they have been fetched and acknowledged by the client.
+     */
+    public FetchingEventForwarder(int bufferSize) {
+        if (logger.traceOn()) {
+            logger.trace("Constructor", "buffer size is "+bufferSize);
+        }
+
+        buffer = new EventBuffer(bufferSize);
+        this.bufferSize = bufferSize;
+    }
+
+    /**
+     * Called by an {@link EventClientDelegateMBean} to forward a user call
+     * {@link EventClientDelegateMBean#fetchNotifications(String, long, int, long)}.
+     * A call of this method is considered to acknowledge reception of all
+     * notifications whose sequence numbers are less the
+     * {@code startSequenceNumber}, so all these notifications can be deleted
+     * from this object.
+     *
+     * @param startSequenceNumber The first sequence number to
+     * consider.
+     * @param timeout The maximum waiting time in milliseconds.
+     * If no notifications have arrived after this period of time, the call
+     * will return with an empty list of notifications.
+     * @param maxNotifs The maximum number of notifications to return.
+     */
+    public NotificationResult fetchNotifications(long startSequenceNumber,
+            int maxNotifs, long timeout) {
+        if (logger.traceOn()) {
+            logger.trace("fetchNotifications",
+                    startSequenceNumber+" "+
+                    maxNotifs+" "+
+                    timeout);
+        }
+
+        return buffer.fetchNotifications(startSequenceNumber,
+                    timeout,
+                    maxNotifs);
+    }
+
+    /**
+     * {@inheritDoc}
+     * In this implementation, the notification is stored in the local buffer
+     * waiting for {@link #fetchNotifications fetchNotifications} to pick
+     * it up.
+     */
+    public void forward(Notification n, Integer listenerId) throws IOException {
+        if (logger.traceOn()) {
+            logger.trace("forward", n+" "+listenerId);
+        }
+
+        buffer.add(new TargetedNotification(n, listenerId));
+    }
+
+    public void close() throws IOException {
+        if (logger.traceOn()) {
+            logger.trace("close", "");
+        }
+
+        buffer.close();
+    }
+
+    public void setClientId(String clientId) throws IOException {
+        if (logger.traceOn()) {
+            logger.trace("setClientId", clientId);
+        }
+        this.clientId = clientId;
+    }
+
+    /**
+     * Sets a user specific list to save notifications in server side
+     * before forwarding to an FetchingEventRelay in client side.
+     * <P> This method should be called before any notification is
+     * forwarded to this forwader.
+     *
+     * @param list a user specific list to save notifications
+     */
+    protected void setList(List<TargetedNotification> list) {
+        if (logger.traceOn()) {
+            logger.trace("setList", "");
+        }
+
+        if (clientId == null) {
+            buffer = new EventBuffer(bufferSize, list);
+        } else {
+            throw new IllegalStateException();
+        }
+    }
+
+    private EventBuffer buffer;
+    private int bufferSize;
+    private String clientId;
+
+    private static final ClassLogger logger =
+            new ClassLogger("javax.management.event", "FetchingEventForwarder");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/javax/management/event/FetchingEventRelay.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,389 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package javax.management.event;
+
+import com.sun.jmx.event.DaemonThreadFactory;
+import com.sun.jmx.event.RepeatedSingletonJob;
+import com.sun.jmx.remote.util.ClassLogger;
+import java.io.IOException;
+import java.io.NotSerializableException;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import java.util.concurrent.RejectedExecutionException;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.TimeUnit;
+import javax.management.MBeanException;
+import javax.management.remote.NotificationResult;
+
+/**
+ * This class is an implementation of the {@link EventRelay} interface. It calls
+ * {@link EventClientDelegateMBean#fetchNotifications
+ * fetchNotifications(String, long, int, long)} to get
+ * notifications and then forwards them to an {@link EventReceiver} object.
+ *
+ * @since JMX 2.0
+ */
+public class FetchingEventRelay implements EventRelay {
+    /**
+     * The default buffer size: {@value #DEFAULT_BUFFER_SIZE}.
+     */
+    public final static int DEFAULT_BUFFER_SIZE = 1000;
+
+    /**
+     * The default waiting timeout: {@value #DEFAULT_WAITING_TIMEOUT}
+     * in millseconds when fetching notifications from
+     * an {@code EventClientDelegateMBean}.
+     */
+    public final static long DEFAULT_WAITING_TIMEOUT = 60000;
+
+    /**
+     * The default maximum notifications to fetch every time:
+     * {@value #DEFAULT_MAX_NOTIFICATIONS}.
+     */
+    public final static int DEFAULT_MAX_NOTIFICATIONS = DEFAULT_BUFFER_SIZE;
+
+    /**
+     * Constructs a default {@code FetchingEventRelay} object by using the default
+     * configuration: {@code DEFAULT_BUFFER_SIZE}, {@code DEFAULT_WAITING_TIMEOUT}
+     * {@code DEFAULT_MAX_NOTIFICATIONS}. A single thread is created
+     * to do fetching.
+     *
+     * @param delegate The {@code EventClientDelegateMBean} to work with.
+     * @throws IOException If failed to work with the {@code delegate}.
+     * @throws MBeanException if unable to add a client to the remote
+     * {@code EventClientDelegateMBean} (see {@link
+     * EventClientDelegateMBean#addClient(String, Object[], String[])
+     * EventClientDelegateMBean.addClient}).
+     * @throws IllegalArgumentException If {@code delegate} is {@code null}.
+     */
+    public FetchingEventRelay(EventClientDelegateMBean delegate)
+    throws IOException, MBeanException {
+        this(delegate, null);
+    }
+
+    /**
+     * Constructs a {@code FetchingEventRelay} object by using the default
+     * configuration: {@code DEFAULT_BUFFER_SIZE}, {@code DEFAULT_WAITING_TIMEOUT}
+     * {@code DEFAULT_MAX_NOTIFICATIONS}, with a user-specific executor to do
+     * the fetching.
+     *
+     * @param delegate The {@code EventClientDelegateMBean} to work with.
+     * @param executor Used to do the fetching. A new thread is created if
+     * {@code null}.
+     * @throws IOException If failed to work with the {@code delegate}.
+     * @throws MBeanException if unable to add a client to the remote
+     * {@code EventClientDelegateMBean} (see {@link
+     * EventClientDelegateMBean#addClient(String, Object[], String[])
+     * EventClientDelegateMBean.addClient}).
+     * @throws IllegalArgumentException If {@code delegate} is {@code null}.
+     */
+    public FetchingEventRelay(EventClientDelegateMBean delegate,
+            Executor executor) throws IOException, MBeanException {
+        this(delegate,
+                DEFAULT_BUFFER_SIZE,
+                DEFAULT_WAITING_TIMEOUT,
+                DEFAULT_MAX_NOTIFICATIONS,
+                executor);
+    }
+
+    /**
+     * Constructs a {@code FetchingEventRelay} object with user-specific
+     * configuration and executor to fetch notifications via the
+     * {@link EventClientDelegateMBean}.
+     *
+     * @param delegate The {@code EventClientDelegateMBean} to work with.
+     * @param bufferSize The buffer size for saving notifications in
+     * {@link EventClientDelegateMBean} before they are fetched.
+     * @param timeout The waiting time in millseconds when fetching
+     * notifications from an {@code EventClientDelegateMBean}.
+     * @param maxNotifs The maximum notifications to fetch every time.
+     * @param executor Used to do the fetching. A new thread is created if
+     * {@code null}.
+     * @throws IOException if failed to communicate with the {@code delegate}.
+     * @throws MBeanException if unable to add a client to the remote
+     * {@code EventClientDelegateMBean} (see {@link
+     * EventClientDelegateMBean#addClient(String, Object[], String[])
+     * EventClientDelegateMBean.addClient}).
+     * @throws IllegalArgumentException If {@code delegate} is {@code null}.
+     */
+    public FetchingEventRelay(EventClientDelegateMBean delegate,
+            int bufferSize,
+            long timeout,
+            int maxNotifs,
+            Executor executor) throws IOException, MBeanException {
+        this(delegate,
+                bufferSize,
+                timeout,
+                maxNotifs,
+                executor,
+                FetchingEventForwarder.class.getName(),
+                new Object[] {bufferSize},
+                new String[] {int.class.getName()});
+    }
+
+    /**
+     * Constructs a {@code FetchingEventRelay} object with user-specific
+     * configuration and executor to fetch notifications via the
+     * {@link EventClientDelegateMBean}.
+     *
+     * @param delegate The {@code EventClientDelegateMBean} to work with.
+     * @param bufferSize The buffer size for saving notifications in
+     * {@link EventClientDelegateMBean} before they are fetched.
+     * @param timeout The waiting time in millseconds when fetching
+     * notifications from an {@code EventClientDelegateMBean}.
+     * @param maxNotifs The maximum notifications to fetch every time.
+     * @param executor Used to do the fetching.
+     * @param forwarderName the class name of a user specific EventForwarder
+     * to create in server to forward notifications to this object. The class
+     * should be a subclass of the class {@link FetchingEventForwarder}.
+     * @param params the parameters passed to create {@code forwarderName}
+     * @param sig the signature of the {@code params}
+     * @throws IOException if failed to communicate with the {@code delegate}.
+     * @throws MBeanException if unable to add a client to the remote
+     * {@code EventClientDelegateMBean} (see {@link
+     * EventClientDelegateMBean#addClient(String, Object[], String[])
+     * EventClientDelegateMBean.addClient}).
+     * @throws IllegalArgumentException if {@code bufferSize} or
+     * {@code maxNotifs} is less than {@code 1}
+     * @throws NullPointerException if {@code delegate} is {@code null}.
+     */
+    public FetchingEventRelay(EventClientDelegateMBean delegate,
+            int bufferSize,
+            long timeout,
+            int maxNotifs,
+            Executor executor,
+            String forwarderName,
+            Object[] params,
+            String[] sig) throws IOException, MBeanException {
+
+        if (logger.traceOn()) {
+            logger.trace("FetchingEventRelay", "delegateMBean "+
+                    bufferSize+" "+
+                    timeout+" "+
+                    maxNotifs+" "+
+                    executor+" "+
+                    forwarderName+" ");
+        }
+
+        if(delegate == null) {
+            throw new NullPointerException("Null EventClientDelegateMBean!");
+        }
+
+
+        if (bufferSize<=1) {
+            throw new IllegalArgumentException(
+                    "The bufferSize cannot be less than 1, no meaning.");
+        }
+
+        if (maxNotifs<=1) {
+            throw new IllegalArgumentException(
+                    "The maxNotifs cannot be less than 1, no meaning.");
+        }
+
+        clientId = delegate.addClient(
+                forwarderName,
+                params,
+                sig);
+
+        this.delegate = delegate;
+        this.timeout = timeout;
+        this.maxNotifs = maxNotifs;
+
+        if (executor == null) {
+            executor = Executors.newSingleThreadScheduledExecutor(
+                    daemonThreadFactory);
+        }
+        this.executor = executor;
+        if (executor instanceof ScheduledExecutorService)
+            leaseScheduler = (ScheduledExecutorService) executor;
+        else {
+            leaseScheduler = Executors.newSingleThreadScheduledExecutor(
+                    daemonThreadFactory);
+        }
+
+        startSequenceNumber = 0;
+        fetchingJob = new MyJob();
+    }
+
+    public void setEventReceiver(EventReceiver eventReceiver) {
+        if (logger.traceOn()) {
+            logger.trace("setEventReceiver", ""+eventReceiver);
+        }
+
+        EventReceiver old = this.eventReceiver;
+        synchronized(fetchingJob) {
+            this.eventReceiver = eventReceiver;
+            if (old == null && eventReceiver != null)
+                fetchingJob.resume();
+        }
+    }
+
+    public String getClientId() {
+        return clientId;
+    }
+
+    public void stop() {
+        if (logger.traceOn()) {
+            logger.trace("stop", "");
+        }
+        synchronized(fetchingJob) {
+            if (stopped) {
+                return;
+            }
+
+            stopped = true;
+            clientId = null;
+        }
+    }
+
+    private class MyJob extends RepeatedSingletonJob {
+        public MyJob() {
+            super(executor);
+        }
+
+        public boolean isSuspended() {
+            boolean b;
+            synchronized(FetchingEventRelay.this) {
+                b = stopped ||
+                        (eventReceiver == null) ||
+                        (clientId == null);
+            }
+
+            if (logger.traceOn()) {
+                logger.trace("-MyJob-isSuspended", ""+b);
+            }
+            return b;
+        }
+
+        public void task() {
+            logger.trace("MyJob-task", "");
+            long fetchTimeout = timeout;
+            NotificationResult nr = null;
+            Throwable failedExcep = null;
+            try {
+                nr = delegate.fetchNotifications(
+                        clientId,
+                        startSequenceNumber,
+                        maxNotifs,
+                        fetchTimeout);
+            } catch (Exception e) {
+                if (isSerialOrClassNotFound(e)) {
+                    try {
+                        nr = fetchOne();
+                    } catch (Exception ee) {
+                        failedExcep = e;
+                    }
+                } else {
+                    failedExcep = e;
+                }
+            }
+
+            if (failedExcep != null &&
+                    !isSuspended()) {
+                logger.fine("MyJob-task",
+                        "Failed to fetch notification, stopping...", failedExcep);
+                try {
+                    eventReceiver.failed(failedExcep);
+                } catch (Exception e) {
+                    logger.trace(
+                            "MyJob-task", "exception from eventReceiver.failed", e);
+                }
+
+                stop();
+            } else if (nr != null) {
+                try {
+                    eventReceiver.receive(nr);
+                } catch (RuntimeException e) {
+                    logger.trace(
+                            "MyJob-task",
+                            "exception delivering notifs to EventClient", e);
+                } finally {
+                    startSequenceNumber = nr.getNextSequenceNumber();
+                }
+            }
+        }
+    }
+
+    private NotificationResult fetchOne() throws Exception {
+        logger.trace("fetchOne", "");
+
+        while (true) {
+            try {
+                // 1 notif to skip possible missing class
+                return delegate.fetchNotifications(
+                        clientId,
+                        startSequenceNumber,
+                        1,
+                        timeout);
+            } catch (Exception e) {
+                if (isSerialOrClassNotFound(e)) { // skip and continue
+                    if (logger.traceOn()) {
+                        logger.trace("fetchOne", "Ignore", e);
+                    }
+                    eventReceiver.nonFatal(e);
+                    startSequenceNumber++;
+                } else {
+                    throw e;
+                }
+            }
+        }
+    }
+
+    static boolean isSerialOrClassNotFound(Exception e) {
+        Throwable cause = e.getCause();
+
+        while (cause != null &&
+                !(cause instanceof ClassNotFoundException) &&
+                !(cause instanceof NotSerializableException)) {
+            cause = cause.getCause();
+        }
+
+        return (cause instanceof ClassNotFoundException ||
+                cause instanceof NotSerializableException);
+    }
+
+    private long startSequenceNumber = 0;
+    private EventReceiver eventReceiver = null;
+    private final EventClientDelegateMBean delegate;
+    private String clientId;
+    private boolean stopped = false;
+    private volatile ScheduledFuture<?> leaseRenewalFuture;
+
+    private final Executor executor;
+    private final ScheduledExecutorService leaseScheduler;
+    private final MyJob fetchingJob;
+
+    private final long timeout;
+    private final int maxNotifs;
+
+    private static final ClassLogger logger =
+            new ClassLogger("javax.management.event",
+            "FetchingEventRelay");
+    private static final ThreadFactory daemonThreadFactory =
+                    new DaemonThreadFactory("FetchingEventRelay-executor");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/javax/management/event/ListenerInfo.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,169 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package javax.management.event;
+
+import javax.management.NotificationFilter;
+import javax.management.NotificationListener;
+import javax.management.ObjectName;
+
+/**
+ * This class specifies all the information required to register a user listener into
+ * a remote MBean server. This class is not serializable because a user listener
+ * is not serialized in order to be sent to the remote server.
+ *
+ * @since JMX 2.0
+ */
+public class ListenerInfo {
+
+    /**
+     * Constructs a {@code ListenerInfo} object.
+     *
+     * @param name The name of the MBean to which the listener should
+     * be added.
+     * @param listener The listener object which will handle the
+     * notifications emitted by the MBean.
+     * @param filter The filter object. If the filter is null, no
+     * filtering will be performed before notifications are handled.
+     * @param handback The context to be sent to the listener when a
+     * notification is emitted.
+     * @param isSubscription If true, the listener is subscribed via
+     * an {@code EventManager}. Otherwise it is added to a registered MBean.
+     */
+    public ListenerInfo(ObjectName name,
+            NotificationListener listener,
+            NotificationFilter filter,
+            Object handback,
+            boolean isSubscription) {
+        this.name = name;
+        this.listener = listener;
+        this.filter = filter;
+        this.handback = handback;
+        this.isSubscription = isSubscription;
+    }
+
+    /**
+     * Returns an MBean or an MBean pattern that the listener listens to.
+     *
+     * @return An MBean or an MBean pattern.
+     */
+    public ObjectName getObjectName() {
+        return name;
+    }
+
+    /**
+     * Returns the listener.
+     *
+     * @return The listener.
+     */
+    public NotificationListener getListener() {
+        return listener;
+    }
+
+    /**
+     * Returns the listener filter.
+     *
+     * @return The filter.
+     */
+    public NotificationFilter getFilter() {
+        return filter;
+    }
+
+    /**
+     * Returns the listener handback.
+     *
+     * @return The handback.
+     */
+    public Object getHandback() {
+        return handback;
+    }
+
+    /**
+     * Returns true if this is a subscription listener.
+     *
+     * @return True if this is a subscription listener.
+     *
+     * @see EventClient#addListeners
+     */
+    public boolean isSubscription() {
+        return isSubscription;
+    }
+
+    /**
+     * <p>Indicates whether some other object is "equal to" this one.
+     * The return value is true if and only if {@code o} is an instance of
+     * {@code ListenerInfo} and has equal values for all of its properties.</p>
+     */
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+
+        if (!(o instanceof ListenerInfo)) {
+            return false;
+        }
+
+        ListenerInfo li = (ListenerInfo)o;
+
+        boolean ret = name.equals(li.name) &&
+                (listener == li.listener) &&
+                (isSubscription == li.isSubscription);
+
+        if (filter != null) {
+            ret &= filter.equals(li.filter);
+        } else {
+            ret &= (li.filter == null);
+        }
+
+        if (handback != null) {
+            ret &= handback.equals(li.handback);
+        } else {
+            ret &= (li.handback == null);
+        }
+
+        return ret;
+    }
+
+    @Override
+    public int hashCode() {
+        return name.hashCode() + listener.hashCode();
+    }
+
+    @Override
+    public String toString() {
+        return name.toString() + "_" +
+                listener + "_" +
+                filter + "_" +
+                handback + "_" +
+                isSubscription;
+    }
+
+    private final ObjectName name;
+    private final NotificationListener listener;
+    private final NotificationFilter filter;
+    private final Object handback;
+    private final boolean isSubscription;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/javax/management/event/NotificationManager.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package javax.management.event;
+
+import java.io.IOException;
+import javax.management.InstanceNotFoundException;
+import javax.management.ListenerNotFoundException;
+import javax.management.NotificationFilter;
+import javax.management.NotificationListener;
+import javax.management.ObjectName;
+
+/**
+ * This interface specifies methods to add and remove notification listeners
+ * on named MBeans.
+ */
+public interface NotificationManager {
+    /**
+     * <p>Adds a listener to a registered MBean.
+     * Notifications emitted by the MBean will be forwarded
+     * to the listener.
+     *
+     * @param name The name of the MBean on which the listener should
+     * be added.
+     * @param listener The listener object which will handle the
+     * notifications emitted by the registered MBean.
+     * @param filter The filter object. If filter is null, no
+     * filtering will be performed before handling notifications.
+     * @param handback The context to be sent to the listener when a
+     * notification is emitted.
+     *
+     * @exception InstanceNotFoundException The MBean name provided
+     * does not match any of the registered MBeans.
+     * @exception IOException A communication problem occurred when
+     * talking to the MBean server.
+     *
+     * @see #removeNotificationListener(ObjectName, NotificationListener)
+     * @see #removeNotificationListener(ObjectName, NotificationListener,
+     * NotificationFilter, Object)
+     */
+    public void addNotificationListener(ObjectName name,
+            NotificationListener listener,
+            NotificationFilter filter,
+            Object handback)
+            throws InstanceNotFoundException,
+            IOException;
+
+    /**
+     * <p>Removes a listener from a registered MBean.</p>
+     *
+     * <P> If the listener is registered more than once, perhaps with
+     * different filters or callbacks, this method will remove all
+     * those registrations.
+     *
+     * @param name The name of the MBean on which the listener should
+     * be removed.
+     * @param listener The listener to be removed.
+     *
+     * @exception InstanceNotFoundException The MBean name provided
+     * does not match any of the registered MBeans.
+     * @exception ListenerNotFoundException The listener is not
+     * registered in the MBean.
+     * @exception IOException A communication problem occurred when
+     * talking to the MBean server.
+     *
+     * @see #addNotificationListener(ObjectName, NotificationListener,
+     * NotificationFilter, Object)
+     */
+    public void removeNotificationListener(ObjectName name,
+            NotificationListener listener)
+            throws InstanceNotFoundException,
+            ListenerNotFoundException,
+            IOException;
+
+    /**
+     * <p>Removes a listener from a registered MBean.</p>
+     *
+     * <p>The MBean must have a listener that exactly matches the
+     * given <code>listener</code>, <code>filter</code>, and
+     * <code>handback</code> parameters.  If there is more than one
+     * such listener, only one is removed.</p>
+     *
+     * <p>The <code>filter</code> and <code>handback</code> parameters
+     * may be null if and only if they are null in a listener to be
+     * removed.</p>
+     *
+     * @param name The name of the MBean on which the listener should
+     * be removed.
+     * @param listener The listener to be removed.
+     * @param filter The filter that was specified when the listener
+     * was added.
+     * @param handback The handback that was specified when the
+     * listener was added.
+     *
+     * @exception InstanceNotFoundException The MBean name provided
+     * does not match any of the registered MBeans.
+     * @exception ListenerNotFoundException The listener is not
+     * registered in the MBean, or it is not registered with the given
+     * filter and handback.
+     * @exception IOException A communication problem occurred when
+     * talking to the MBean server.
+     *
+     * @see #addNotificationListener(ObjectName, NotificationListener,
+     * NotificationFilter, Object)
+     *
+     */
+    public void removeNotificationListener(ObjectName name,
+            NotificationListener listener,
+            NotificationFilter filter,
+            Object handback)
+            throws InstanceNotFoundException,
+            ListenerNotFoundException,
+            IOException;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/javax/management/event/RMIPushEventForwarder.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,198 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package javax.management.event;
+
+import com.sun.jmx.event.DaemonThreadFactory;
+import com.sun.jmx.event.RepeatedSingletonJob;
+import com.sun.jmx.remote.util.ClassLogger;
+import java.rmi.RemoteException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import javax.management.Notification;
+import javax.management.remote.NotificationResult;
+import javax.management.remote.TargetedNotification;
+
+
+/**
+ * This class is used by {@link RMIPushEventRelay}. When
+ * {@link RMIPushEventRelay} calls {@link
+ * EventClientDelegateMBean#addClient(String, Object[], String[])} to get a new
+ * client identifier, it uses this class name as the
+ * first argument to ask {@code EventClientDelegateMBean} to create an object of
+ * this class.
+ * Then {@code EventClientDelegateMBean} forwards client notifications
+ * to this object. This object then continues forwarding the notifications
+ * to the {@code RMIPushEventRelay}.
+ */
+public class RMIPushEventForwarder implements EventForwarder {
+    private static final int DEFAULT_BUFFER_SIZE = 6000;
+
+    /**
+     * Creates a new instance of {@code RMIPushEventForwarder}.
+     *
+     * @param receiver An RMI stub exported to receive notifications
+     * from this object for its {@link RMIPushEventRelay}.
+     *
+     * @param bufferSize The maximum number of notifications to store
+     * while waiting for the last remote send to complete.
+     */
+    public RMIPushEventForwarder(RMIPushServer receiver, int bufferSize) {
+        if (logger.traceOn()) {
+            logger.trace("RMIEventForwarder", "new one");
+        }
+
+        if (bufferSize < 0) {
+            throw new IllegalArgumentException(
+                    "Negative buffer size: " + bufferSize);
+        } else if (bufferSize == 0)
+            bufferSize = DEFAULT_BUFFER_SIZE;
+
+        if (receiver == null) {
+            throw new NullPointerException();
+        }
+
+        this.receiver = receiver;
+        this.buffer = new ArrayBlockingQueue<TargetedNotification>(bufferSize);
+    }
+
+    public void forward(Notification n, Integer listenerId) {
+        if (logger.traceOn()) {
+            logger.trace("forward", "to the listener: "+listenerId);
+        }
+        synchronized(sendingJob) {
+            TargetedNotification tn = new TargetedNotification(n, listenerId);
+            while (!buffer.offer(tn)) {
+                buffer.remove();
+                passed++;
+            }
+            sendingJob.resume();
+        }
+    }
+
+    public void close() {
+        if (logger.traceOn()) {
+            logger.trace("close", "called");
+        }
+
+        synchronized(sendingJob) {
+            ended = true;
+            buffer.clear();
+        }
+    }
+
+    public void setClientId(String clientId) {
+        if (logger.traceOn()) {
+            logger.trace("setClientId", clientId);
+        }
+    }
+
+    private class SendingJob extends RepeatedSingletonJob {
+        public SendingJob() {
+            super(executor);
+        }
+
+        public boolean isSuspended() {
+            return ended || buffer.isEmpty();
+        }
+
+        public void task() {
+            final long earliest = passed;
+
+            List<TargetedNotification> tns =
+                    new ArrayList<TargetedNotification>(buffer.size());
+            synchronized(sendingJob) {
+                buffer.drainTo(tns);
+                passed += tns.size();
+            }
+
+            if (logger.traceOn()) {
+                logger.trace("SendingJob-task", "sending: "+tns.size());
+            }
+
+            if (!tns.isEmpty()) {
+                try {
+                    TargetedNotification[] tnArray =
+                            new TargetedNotification[tns.size()];
+                    tns.toArray(tnArray);
+                    receiver.receive(new NotificationResult(earliest, passed, tnArray));
+                } catch (RemoteException e) {
+                    if (logger.debugOn()) {
+                        logger.debug("SendingJob-task",
+                                "Got exception to forward notifs.", e);
+                    }
+
+                    long currentLost = passed - earliest;
+                    if (FetchingEventRelay.isSerialOrClassNotFound(e)) {
+                        // send one by one
+                        long tmpPassed = earliest;
+                        for (TargetedNotification tn : tns) {
+                            try {
+                                receiver.receive(new NotificationResult(earliest,
+                                        ++tmpPassed, new TargetedNotification[]{tn}));
+                            } catch (RemoteException ioee) {
+                                logger.trace(
+                                        "SendingJob-task", "send to remote", ioee);
+                                // sends nonFatal notifs?
+                            }
+                        }
+
+                        currentLost = passed - tmpPassed;
+                    }
+
+                    if (currentLost > 0) { // inform of the lost.
+                        try {
+                            receiver.receive(new NotificationResult(
+                                    passed, passed,
+                                    new TargetedNotification[]{}));
+                        } catch (RemoteException ee) {
+                            logger.trace(
+                                    "SendingJob-task", "receiver.receive", ee);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    private long passed = 0;
+
+    private static final ExecutorService executor =
+            Executors.newCachedThreadPool(
+            new DaemonThreadFactory("RMIEventForwarder Executor"));
+    private final SendingJob sendingJob = new SendingJob();
+
+    private final BlockingQueue<TargetedNotification> buffer;
+
+    private final RMIPushServer receiver;
+    private boolean ended = false;
+
+    private static final ClassLogger logger =
+            new ClassLogger("javax.management.event", "RMIEventForwarder");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/javax/management/event/RMIPushEventRelay.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,161 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package javax.management.event;
+
+import com.sun.jmx.remote.util.ClassLogger;
+import java.io.IOException;
+import java.rmi.NoSuchObjectException;
+import java.rmi.RemoteException;
+import java.rmi.server.UnicastRemoteObject;
+import java.rmi.server.RMIClientSocketFactory;
+import java.rmi.server.RMIServerSocketFactory;
+import javax.management.MBeanException;
+import javax.management.remote.NotificationResult;
+
+/**
+ * This class is an implementation of the {@link EventRelay} interface, using
+ * push mode. It exports an RMI object that {@link RMIPushEventForwarder} uses
+ * to forward notifications.
+ *
+ * @since JMX 2.0
+ */
+public class RMIPushEventRelay implements EventRelay {
+    /**
+     * Constructs a default {@code RMIPushEventRelay} object
+     * and exports its {@linkplain RMIPushServer notification
+     * receiver} on any free port. This constructor is equivalent
+     * to {@link #RMIPushEventRelay(EventClientDelegateMBean,
+     * int, RMIClientSocketFactory, RMIServerSocketFactory, int)
+     * RMIPushEventRelay(delegate, 0, null, null, <em>&lt;default buffer
+     * size&gt;</em>)}.
+     *
+     * @param delegate The {@link EventClientDelegateMBean} proxy to work with.
+     * @throws IOException if failed to communicate with
+     * {@link EventClientDelegateMBean}.
+     * @throws MBeanException if the {@link EventClientDelegateMBean} failed
+     * to create an {@code EventForwarder} for this object.
+     */
+    public RMIPushEventRelay(EventClientDelegateMBean delegate)
+    throws IOException, MBeanException {
+        this(delegate, 0, null,  null, 0);
+    }
+
+    /**
+     * Constructs a {@code RMIPushEventRelay} object and exports its
+     * {@linkplain RMIPushServer notification receiver} on a specified port.
+     *
+     * @param delegate The {@link EventClientDelegateMBean} proxy to work with.
+     * @param port The port used to export an RMI object to receive notifications
+     * from a server. If the port is zero, an anonymous port is used.
+     * @param csf The client socket factory used to export the RMI object.
+     * Can be null.
+     * @param ssf The server socket factory used to export the RMI object.
+     * Can be null.
+     * @param bufferSize The number of notifications held on the server
+     * while waiting for the previous transmission to complete.  A value of
+     * zero means the default buffer size.
+     *
+     * @throws IOException if failed to communicate with
+     * {@link EventClientDelegateMBean}.
+     * @throws MBeanException if the {@link EventClientDelegateMBean} failed
+     * to create an {@code EventForwarder} for this object.
+     *
+     * @see RMIPushEventForwarder#RMIPushEventForwarder(RMIPushServer, int)
+     */
+    public RMIPushEventRelay(EventClientDelegateMBean delegate,
+            int port,
+            RMIClientSocketFactory csf,
+            RMIServerSocketFactory ssf,
+            int bufferSize)
+            throws IOException, MBeanException {
+
+        UnicastRemoteObject.exportObject(exportedReceiver, port, csf, ssf);
+
+        clientId = delegate.addClient(
+                RMIPushEventForwarder.class.getName(),
+                new Object[] {exportedReceiver, bufferSize},
+                new String[] {RMIPushServer.class.getName(),
+                              int.class.getName()});
+    }
+
+    public String getClientId() {
+        return clientId;
+    }
+
+    public void setEventReceiver(EventReceiver receiver) {
+        if (logger.traceOn()) {
+            logger.trace("setEventReceiver", ""+receiver);
+        }
+        synchronized(lock) {
+            this.receiver = receiver;
+        }
+    }
+
+    public void stop() {
+        if (logger.traceOn()) {
+            logger.trace("stop", "");
+        }
+        synchronized(lock) {
+            if (stopped) {
+                return;
+            } else {
+                stopped = true;
+            }
+
+            if (clientId == null) {
+                return;
+            }
+
+            try {
+                UnicastRemoteObject.unexportObject(exportedReceiver, true);
+            } catch (NoSuchObjectException nsoe) {
+                logger.fine("RMIPushEventRelay.stop", "unexport", nsoe);
+                // OK: we wanted it unexported, and apparently it already is
+            }
+        }
+    }
+
+    private volatile String clientId;
+    private volatile EventReceiver receiver;
+
+    private RMIPushServer exportedReceiver = new RMIPushServer() {
+        public void receive(NotificationResult nr) throws RemoteException {
+            if (logger.traceOn()) {
+                logger.trace("EventPusherImpl-receive","");
+            }
+            receiver.receive(nr);
+            // Any exception will be sent back to the client.
+        }
+    };
+
+    private boolean stopped = false;
+
+    private final int[] lock = new int[0];
+
+    private static final ClassLogger logger =
+            new ClassLogger("javax.management.event",
+            "PushEventRelay");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/javax/management/event/RMIPushServer.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package javax.management.event;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import javax.management.remote.NotificationResult;
+
+/**
+ * The {@link RMIPushEventRelay} exports an RMI object of this class and
+ * sends a client stub for that object to the associated
+ * {@link RMIPushEventForwarder} in a remote MBean server.  The
+ * {@code RMIPushEventForwarder} then sends notifications to the
+ * RMI object.
+ */
+public interface RMIPushServer extends Remote {
+    /**
+     * <p>Dispatch the notifications in {@code nr} to the {@link RMIPushEventRelay}
+     * associated with this object.</p>
+     * @param nr the notification result to dispatch.
+     * @throws java.rmi.RemoteException if the remote invocation of this method
+     * failed.
+     */
+    public void receive(NotificationResult nr) throws RemoteException;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/javax/management/event/package-info.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,312 @@
+/**
+ * <p>Defines the <em>Event Service</em>, which provides extended support
+ * for JMX notifications.</p>
+ *
+ * <p>The Event Service provides greater control over
+ * notification handling than the default technique using {@link
+ * javax.management.MBeanServer#addNotificationListener(ObjectName,
+ * NotificationListener, NotificationFilter, Object)
+ * MBeanServer.addNotificationListener} or {@link
+ * javax.management.MBeanServerConnection#addNotificationListener(ObjectName,
+ * NotificationListener, NotificationFilter, Object)
+ * MBeanServerConnection.addNotificationListener}.</p>
+ *
+ * <p>Here are some reasons you may want to use the Event Service:</p>
+ *
+ * <ul>
+ * <li>To receive notifications from a set of MBeans defined by an
+ * ObjectName pattern, such as {@code com.example.config:type=Cache,*}.
+ *
+ * <li>When the notification-handling behavior of the connector you are
+ * using does not match your requirements.  For example, with the standard
+ * RMI connector you can lose notifications if there are very many of them
+ * in the MBean Server you are connected to, even if you are only listening
+ * for a small proportion of them.
+ *
+ * <li>To change the threading behavior of notification dispatch.
+ *
+ * <li>To define a different transport for notifications, for example to
+ * arrange for them to be delivered through the Java Message Service (<a
+ * href="http://java.sun.com/jms">JMS</a>).  The Event Service comes with
+ * one alternative transport as standard, a "push-mode" RMI transport.
+ *
+ * <li>To handle notifications on behalf of MBeans (often virtual) in a
+ * namespace.
+ * </ul>
+ *
+ * <p>The Event Service is new in version 2.0 of the JMX API, which is the
+ * version introduced in version 7 of the Java SE platform.  It is not usually
+ * possible to use the Event Service when connecting remotely to an
+ * MBean Server that is running an earlier version.</p>
+ *
+ *
+ * <h3 id="handlingremote">Handling remote notifications with the Event
+ * Service</h3>
+ *
+ * <p>Prior to version 2.0 of the JMX API, every connector
+ * had to include logic to handle notifications. The standard {@linkplain
+ * javax.management.remote.rmi RMI} and JMXMP connectors defined by <a
+ * href="http://jcp.org/en/jsr/detail?id=160">JSR 160</a> handle notifications
+ * in a way that is not always appropriate for applications. Specifically,
+ * the connector server adds one listener to every MBean that might emit
+ * notifications, and adds all received notifications to a fixed-size
+ * buffer. This means that if there are very many notifications, a
+ * remote client may miss some, even if it is only registered for a
+ * very small subset of notifications. Furthermore, since every {@link
+ * javax.management.NotificationBroadcaster NotificationBroadcaster} MBean
+ * gets a listener from the connector server, MBeans cannot usefully optimize
+ * by only sending notifications when there is a listener. Finally, since
+ * the connector server uses just one listener per MBean, MBeans cannot
+ * impose custom behavior per listener, such as security checks or localized
+ * notifications.</p>
+ *
+ * <p>The Event Service does not have these restrictions.  The RMI connector
+ * that is included in this version of the JMX API uses the Event Service by
+ * default, although it can be configured to have the previous behavior if
+ * required.</p>
+ *
+ * <p>The Event Service can be used with <em>any</em> connector via the
+ * method {@link javax.management.event.EventClient#getEventClientConnection
+ * EventClient.getEventClientConnection}, like this:</p>
+ *
+ * <pre>
+ * JMXConnector conn = ...;
+ * MBeanServerConnection mbsc = conn.getMBeanServerConnection();
+ * MBeanServerConnection eventMbsc = EventClient.getEventClientConnection(mbsc);
+ * </pre>
+ *
+ * <p>If you add listeners using {@code eventMbsc.addNotificationListener}
+ * instead of {@code mbsc.addNotificationListener}, then they will be handled
+ * by the Event Service rather than by the connector's notification system.</p>
+ *
+ * <p>For the Event Service to work, either the {@link
+ * javax.management.event.EventClientDelegateMBean EventClientDelegateMBean}
+ * must be registered in the MBean Server, or the connector server must
+ * be configured to simulate the existence of this MBean, for example
+ * using {@link javax.management.event.EventClientDelegate#newForwarder()
+ * EventClientDelegate.newForwarder()}. The standard RMI connector is so
+ * configured by default. The {@code EventClientDelegateMBean} documentation
+ * has further details.</p>
+ *
+ *
+ * <h3 id="subscribepattern">Receiving notifications from a set of MBeans</h3>
+ *
+ * <p>The Event Server allows you to receive notifications from every MBean
+ * that matches an {@link javax.management.ObjectName ObjectName} pattern.
+ * For local clients (in the same JVM as the MBean Server), the {@link
+ * javax.management.event.EventSubscriber EventSubscriber} class can be used for
+ * this. For remote clients, or if the same code is to be used locally and
+ * remotely, use an
+ * {@link javax.management.event.EventClient EventClient}.</p>
+ *
+ * <p>EventSubscriber and EventClient correctly handle the case where a new
+ * MBean is registered under a name that matches the pattern. Notifications
+ * from the new MBean will also be received.</p>
+ *
+ * <p>Here is how to receive notifications from all MBeans in a local
+ * {@code MBeanServer} that match {@code com.example.config:type=Cache,*}:</p>
+ *
+ * <pre>
+ * MBeanServer mbs = ...;
+ * NotificationListener listener = ...;
+ * ObjectName pattern = new ObjectName("com.example.config:type=Cache,*");
+ * EventSubscriber esub = EventSubscriber.getEventSubscriber(mbs);
+ * esub.{@link javax.management.event.EventSubscriber#subscribe
+ * subscribe}(pattern, listener, null, null);
+ * </pre>
+ *
+ * <p>Here is how to do the same thing remotely:</p>
+ *
+ * <pre>
+ * MBeanServerConnection mbsc = jmxConnector.getMBeanServerConnection();
+ * EventClient events = new EventClient(mbsc);
+ * NotificationListener listener = ...;
+ * ObjectName pattern = new ObjectName("com.example.config:type=Cache,*");
+ * events.{@link javax.management.event.EventClient#subscribe
+ * subscribe}(pattern, listener, null, null);
+ * </pre>
+ *
+ *
+ * <h3 id="threading">Controlling threading behavior for notification
+ * dispatch</h3>
+ *
+ * <p>The EventClient class can be used to control threading of listener
+ * dispatch.  For example, to arrange for all listeners to be invoked
+ * in the same thread, you can create an {@code EventClient} like this:</p>
+ *
+ * <pre>
+ * MBeanServerConnection mbsc = ...;
+ * Executor singleThreadExecutor = {@link
+ * java.util.concurrent.Executors#newSingleThreadExecutor()
+ * Executors.newSingleThreadExecutor}();
+ * EventClient events = new EventClient(
+ *         mbsc, null, singleThreadExecutor, EventClient.DEFAULT_LEASE_TIMEOUT);
+ * events.addNotificationListener(...);
+ * events.subscribe(...);
+ * </pre>
+ *
+ *
+ * <h3 id="leasing">Leasing</h3>
+ *
+ * <p>The {@code EventClient} uses a <em>lease</em> mechanism to ensure
+ * that resources are eventually released on the server even if the client
+ * does not explicitly clean up.  (This can happen through network
+ * partitioning, for example.)</p>
+ *
+ * <p>When an {@code EventClient} registers with the {@code
+ * EventClientDelegateMBean} using one of the {@code addClient} methods,
+ * an initial lease is created with a default expiry time. The {@code
+ * EventClient} requests an explicit lease shortly after that, with a
+ * configurable expiry time. Then the {@code EventClient} periodically
+ * <em>renews</em> the lease before it expires, typically about half way
+ * through the lifetime of the lease. If at any point the lease reaches
+ * the expiry time of the last renewal then it expires, and {@code
+ * EventClient} is unregistered as if it had called the {@link
+ * javax.management.event.EventClientDelegateMBean#removeClient removeClient}
+ * method.</p>
+ *
+ *
+ * <h3 id="transports">Custom notification transports</h3>
+ *
+ * <p>When you create an {@code EventClient}, you can define the transport
+ * that it uses to deliver notifications. The transport might use the
+ * Java Message Service (<a href="http://java.sun.com/jms">JMS</a>) or
+ * any other communication system. Specifying a transport is useful for
+ * example when you want different network behavior from the default, or
+ * different reliability guarantees. The default transport calls {@link
+ * javax.management.event.EventClientDelegateMBean#fetchNotifications
+ * EventClientDelegateMBean.fetchNotifications} repeatedly, which usually means
+ * that there must be a network connection permanently open between the client
+ * and the server. If the same client is connected to many servers this can
+ * cause scalability problems.  If notifications are relatively rare, then
+ * JMS or the {@linkplain javax.management.event.RMIPushEventRelay push-mode
+ * RMI transport} may be more suitable.</p>
+ *
+ * <p>A transport is implemented by an {@link javax.management.event.EventRelay
+ * EventRelay} on the client side and a corresponding {@link
+ * javax.management.event.EventForwarder EventForwarder}
+ * on the server side. An example is the {@link
+ * javax.management.event.RMIPushEventRelay RMIPushEventRelay} and its
+ * {@link javax.management.event.RMIPushEventForwarder RMIPushEventForwarder}.</p>
+ *
+ * <p>To use a given transport with an {@code EventClient}, you first create
+ * an instance of its {@code EventRelay}. Typically the {@code EventRelay}'s
+ * constructor will have a parameter of type {@code MBeanServerConnection}
+ * or {@code EventClientDelegateMBean}, so that it can communicate with the
+ * {@code EventClientDelegateMBean} in the server. For example, the {@link
+ * javax.management.event.RMIPushEventForwarder RMIPushEventForwarder}'s constructors
+ * all take an {@code EventClientDelegateMBean} parameter, which is expected to
+ * be a {@linkplain javax.management.JMX#newMBeanProxy(MBeanServerConnection,
+ * ObjectName, Class) proxy} for the {@code EventClientDelegateMBean} in the
+ * server.</p>
+ *
+ * <p>When it is created, the {@code EventRelay} will call
+ * {@link javax.management.event.EventClientDelegateMBean#addClient(String,
+ * Object[], String[]) EventClientDelegateMBean.addClient}.  It passes the
+ * name of the {@code EventForwarder} class and its constructor parameters.
+ * The {@code EventClientDelegateMBean} will instantiate this class using
+ * {@link javax.management.MBeanServer#instantiate(String, Object[], String[])
+ * MBeanServer.instantiate}, and it will return a unique <em>client id</em>.</p>
+ *
+ * <p>Then you pass the newly-created {@code EventRelay} to one of the {@code
+ * EventClient} constructors, and you have an {@code EventClient} that uses the
+ * chosen transport.</p>
+ *
+ * <p>For example, when you create an {@code RMIPushEventRelay}, it
+ * uses {@code MBeanServerDelegateMBean.addClient} to create an {@code
+ * RMIEventForwarder} in the server. Notifications will then be delivered
+ * through an RMI communication from the {@code RMIEventForwarder} to the
+ * {@code RMIPushEventRelay}.</p>
+ *
+ *
+ * <h4 id="writingcustomtransport">Writing a custom transport</h4>
+ *
+ * <p>To write a custom transport, you need to understand the sequence
+ * of events when an {@code EventRelay} and its corresponding {@code
+ * EventForwarder} are created, and when a notification is sent from the {@code
+ * EventForwarder} to the {@code EventRelay}.</p>
+ *
+ * <p>When an {@code EventRelay} is created:</p>
+ *
+ * <ul>
+ * <li><p>The {@code EventRelay} must call {@code
+ * EventClientDelegateMBean.addClient} with the name of the {@code
+ * EventForwarder} and the constructor parameters.</p>
+ *
+ * <li><p>{@code EventClientDelegateMBean.addClient} will do the following
+ * steps:</p>
+ *
+ * <ul>
+ * <li>create the {@code EventForwarder} using {@code MBeanServer.instantiate};
+ * <li>allocate a unique client id;
+ * <li>call the new {@code EventForwarder}'s {@link
+ * javax.management.event.EventForwarder#setClientId setClientId} method with
+ * the new client id;
+ * <li>return the client id to the caller.
+ * </ul>
+ *
+ * </ul>
+ *
+ * <p>When an {@code EventClient} is created with an {@code EventRelay}
+ * parameter, it calls {@link javax.management.event.EventRelay#setEventReceiver
+ * EventRelay.setEventReceiver} with an {@code EventReceiver} that the
+ * {@code EventRelay} will use to deliver notifications.</p>
+ *
+ * <p>When a listener is added using the {@code EventClient}, the
+ * {@code EventRelay} and {@code EventForwarder} are not involved.</p>
+ *
+ * <p>When an MBean emits a notification and a listener has been added
+ * to that MBean using the {@code EventClient}:</p>
+ *
+ * <ul>
+ * <li><p>The {@code EventForwarder}'s
+ * {@link javax.management.event.EventForwarder#forward forward} method
+ * is called with the notification and a <em>listener id</em>.</p>
+ *
+ * <li><p>The {@code EventForwarder} sends the notification and listener id
+ * to the {@code EventRelay} using the custom transport.</p>
+ *
+ * <li><p>The {@code EventRelay} delivers the notification by calling
+ * {@link javax.management.event.EventReceiver#receive EventReceiver.receive}.</p>
+ * </ul>
+ *
+ * <p>When the {@code EventClient} is closed ({@link
+ * javax.management.event.EventClient#close EventClient.close}):</p>
+ *
+ * <ul>
+ * <li><p>The {@code EventClient} calls {@link
+ * javax.management.event.EventRelay#stop EventRelay.stop}.</p>
+ *
+ * <li><p>The {@code EventClient} calls {@link
+ * javax.management.event.EventClientDelegateMBean#removeClient
+ * EventClientDelegateMBean.removeClient}.</p>
+ *
+ * <li><p>The {@code EventClientDelegateMBean} removes any listeners it
+ * had added on behalf of this {@code EventClient}.</p>
+ *
+ * <li><p>The {@code EventClientDelegateMBean} calls
+ * {@link javax.management.event.EventForwarder#close EventForwarder.close}.</p>
+ * </ul>
+ *
+ *
+ * <h4 id="threading">Threading and buffering</h3>
+ *
+ * <p>The {@link javax.management.event.EventForwarder#forward
+ * EventForwarder.forward} method may be called in the thread that the
+ * source MBean is using to send its notification.  MBeans can expect
+ * that notification sending does not block.  Therefore a {@code forward}
+ * method will typically add the notification to a queue, with a separate
+ * thread that takes notifications off the queue and sends them.</p>
+ *
+ * <p>An {@code EventRelay} does not usually need to buffer notifications
+ * before giving them to
+ * {@link javax.management.event.EventReceiver#receive EventReceiver.receive}.
+ * Although by default each such notification will be sent to potentially-slow
+ * listeners, if this is a problem then an {@code Executor} can be given to
+ * the {@code EventClient} constructor to cause the listeners to be called
+ * in a different thread.</p>
+ *
+ * @since 1.7
+ */
+
+package javax.management.event;
--- a/jdk/src/share/classes/javax/management/loading/MLet.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/src/share/classes/javax/management/loading/MLet.java	Wed Jul 05 16:40:29 2017 +0200
@@ -1154,21 +1154,29 @@
       */
      private synchronized String loadLibraryAsResource(String libname) {
          try {
-             InputStream is = getResourceAsStream(libname.replace(File.separatorChar,'/'));
+             InputStream is = getResourceAsStream(
+                     libname.replace(File.separatorChar,'/'));
              if (is != null) {
-                 File directory = new File(libraryDirectory);
-                 directory.mkdirs();
-                 File file = File.createTempFile(libname + ".", null, directory);
-                 file.deleteOnExit();
-                 FileOutputStream fileOutput = new FileOutputStream(file);
-                 int c;
-                 while ((c = is.read()) != -1) {
-                     fileOutput.write(c);
-                 }
-                 is.close();
-                 fileOutput.close();
-                 if (file.exists()) {
-                     return file.getAbsolutePath();
+                 try {
+                     File directory = new File(libraryDirectory);
+                     directory.mkdirs();
+                     File file = File.createTempFile(libname + ".", null,
+                             directory);
+                     file.deleteOnExit();
+                     FileOutputStream fileOutput = new FileOutputStream(file);
+                     try {
+                         int c;
+                         while ((c = is.read()) != -1) {
+                             fileOutput.write(c);
+                         }
+                     } finally {
+                         fileOutput.close();
+                     }
+                     if (file.exists()) {
+                         return file.getAbsolutePath();
+                     }
+                 } finally {
+                     is.close();
                  }
              }
          } catch (Exception e) {
--- a/jdk/src/share/classes/javax/management/modelmbean/ModelMBeanInfoSupport.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/src/share/classes/javax/management/modelmbean/ModelMBeanInfoSupport.java	Wed Jul 05 16:40:29 2017 +0200
@@ -373,7 +373,7 @@
                     "getDescriptors(String)", "Entry");
         }
 
-        if ((inDescriptorType == null) || (inDescriptorType.isEmpty())) {
+        if ((inDescriptorType == null) || (inDescriptorType.equals(""))) {
             inDescriptorType = "all";
         }
 
@@ -616,7 +616,7 @@
             inDescriptor = new DescriptorSupport();
         }
 
-        if ((inDescriptorType == null) || (inDescriptorType.isEmpty())) {
+        if ((inDescriptorType == null) || (inDescriptorType.equals(""))) {
             inDescriptorType =
                     (String) inDescriptor.getFieldValue("descriptorType");
 
--- a/jdk/src/share/classes/javax/management/modelmbean/RequiredModelMBean.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/src/share/classes/javax/management/modelmbean/RequiredModelMBean.java	Wed Jul 05 16:40:29 2017 +0200
@@ -1123,7 +1123,7 @@
         if (tracing) {
             MODELMBEAN_LOGGER.logp(Level.FINER,
                 RequiredModelMBean.class.getName(),"resolveMethod",
-                  "resolving " + targetClass + "." + opMethodName);
+                  "resolving " + targetClass.getName() + "." + opMethodName);
         }
 
         final Class[] argClasses;
--- a/jdk/src/share/classes/javax/management/openmbean/CompositeDataSupport.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/src/share/classes/javax/management/openmbean/CompositeDataSupport.java	Wed Jul 05 16:40:29 2017 +0200
@@ -355,6 +355,7 @@
      * @return  <code>true</code> if the specified object is equal to this
      * <code>CompositeDataSupport</code> instance.
      */
+    @Override
     public boolean equals(Object obj) {
         if (this == obj) {
             return true;
@@ -419,6 +420,7 @@
      *
      * @return the hash code value for this <code>CompositeDataSupport</code> instance
      */
+    @Override
     public int hashCode() {
         int hashcode = compositeType.hashCode();
 
@@ -457,16 +459,28 @@
      *
      * @return  a string representation of this <code>CompositeDataSupport</code> instance
      */
+    @Override
     public String toString() {
-
         return new StringBuilder()
             .append(this.getClass().getName())
             .append("(compositeType=")
             .append(compositeType.toString())
             .append(",contents=")
-            .append(contents.toString())
+            .append(contentString())
             .append(")")
             .toString();
     }
 
+    private String contentString() {
+        StringBuilder sb = new StringBuilder("{");
+        String sep = "";
+        for (Map.Entry<String, Object> entry : contents.entrySet()) {
+            sb.append(sep).append(entry.getKey()).append("=");
+            String s = Arrays.deepToString(new Object[] {entry.getValue()});
+            sb.append(s.substring(1, s.length() - 1));
+            sep = ", ";
+        }
+        sb.append("}");
+        return sb.toString();
+    }
 }
--- a/jdk/src/share/classes/javax/management/openmbean/MXBeanMapping.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/src/share/classes/javax/management/openmbean/MXBeanMapping.java	Wed Jul 05 16:40:29 2017 +0200
@@ -108,6 +108,9 @@
  * <p>If we are unable to modify the {@code MyLinkedList} class,
  * we can define an {@link MXBeanMappingFactory}.  See the documentation
  * of that class for further details.</p>
+ *
+ * @see <a href="../MXBean.html#custom">MXBean specification, section
+ * "Custom MXBean type mappings"</a>
  */
 public abstract class MXBeanMapping {
     private final Type javaType;
--- a/jdk/src/share/classes/javax/management/openmbean/MXBeanMappingFactory.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/src/share/classes/javax/management/openmbean/MXBeanMappingFactory.java	Wed Jul 05 16:40:29 2017 +0200
@@ -82,6 +82,9 @@
  * appears in, or we can supply the factory to a {@link
  * javax.management.StandardMBean StandardMBean} constructor or MXBean
  * proxy.</p>
+ *
+ * @see <a href="../MXBean.html#custom">MXBean specification, section
+ * "Custom MXBean type mappings"</a>
  */
 public abstract class MXBeanMappingFactory {
     /**
--- a/jdk/src/share/classes/javax/management/openmbean/TabularDataSupport.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/src/share/classes/javax/management/openmbean/TabularDataSupport.java	Wed Jul 05 16:40:29 2017 +0200
@@ -29,15 +29,18 @@
 
 // java import
 //
+import com.sun.jmx.mbeanserver.GetPropertyAction;
 import java.io.IOException;
 import java.io.ObjectInputStream;
 import java.io.Serializable;
+import java.security.AccessController;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Iterator;
+import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -79,12 +82,13 @@
     /**
      * @serial This tabular data instance's contents: a {@link HashMap}
      */
+    // field cannot be final because of clone method
     private Map<Object,CompositeData> dataMap;
 
     /**
      * @serial This tabular data instance's tabular type
      */
-    private TabularType tabularType;
+    private final TabularType tabularType;
 
     /**
      * The array of item names that define the index used for rows (convenience field)
@@ -109,7 +113,7 @@
      */
     public TabularDataSupport(TabularType tabularType) {
 
-        this(tabularType, 101, 0.75f);
+        this(tabularType, 16, 0.75f);
     }
 
     /**
@@ -141,10 +145,18 @@
         List<String> tmpNames = tabularType.getIndexNames();
         this.indexNamesArray = tmpNames.toArray(new String[tmpNames.size()]);
 
+        // Since LinkedHashMap was introduced in SE 1.4, it's conceivable even
+        // if very unlikely that we might be the server of a 1.3 client.  In
+        // that case you'll need to set this property.  See CR 6334663.
+        String useHashMapProp = AccessController.doPrivileged(
+                new GetPropertyAction("jmx.tabular.data.hash.map"));
+        boolean useHashMap = "true".equalsIgnoreCase(useHashMapProp);
+
         // Construct the empty contents HashMap
         //
-        this.dataMap =
-            new HashMap<Object,CompositeData>(initialCapacity, loadFactor);
+        this.dataMap = useHashMap ?
+            new HashMap<Object,CompositeData>(initialCapacity, loadFactor) :
+            new LinkedHashMap<Object, CompositeData>(initialCapacity, loadFactor);
     }
 
 
--- a/jdk/src/share/classes/javax/management/relation/RelationService.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/src/share/classes/javax/management/relation/RelationService.java	Wed Jul 05 16:40:29 2017 +0200
@@ -108,7 +108,7 @@
     // the value HashMap mapping:
     //       <relation id> -> ArrayList of <role name>
     // to track where a given MBean is referenced.
-    private Map<ObjectName,Map<String,List<String>>>
+    private final Map<ObjectName,Map<String,List<String>>>
         myRefedMBeanObjName2RelIdsMap =
             new HashMap<ObjectName,Map<String,List<String>>>();
 
@@ -1492,7 +1492,7 @@
         // Clones the list of notifications to be able to still receive new
         // notifications while proceeding those ones
         List<MBeanServerNotification> localUnregNtfList;
-        synchronized(myUnregNtfList) {
+        synchronized(myRefedMBeanObjName2RelIdsMap) {
             localUnregNtfList =
                 new ArrayList<MBeanServerNotification>(myUnregNtfList);
             // Resets list
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/javax/management/remote/IdentityMBeanServerForwarder.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,303 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package javax.management.remote;
+
+import java.io.ObjectInputStream;
+import java.util.Set;
+import javax.management.Attribute;
+import javax.management.AttributeList;
+import javax.management.AttributeNotFoundException;
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.InstanceNotFoundException;
+import javax.management.IntrospectionException;
+import javax.management.InvalidAttributeValueException;
+import javax.management.ListenerNotFoundException;
+import javax.management.MBeanException;
+import javax.management.MBeanInfo;
+import javax.management.MBeanRegistrationException;
+import javax.management.MBeanServer;
+import javax.management.NotCompliantMBeanException;
+import javax.management.NotificationFilter;
+import javax.management.NotificationListener;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.OperationsException;
+import javax.management.QueryExp;
+import javax.management.ReflectionException;
+import javax.management.loading.ClassLoaderRepository;
+
+/**
+ * An {@link MBeanServerForwarder} that forwards all {@link MBeanServer}
+ * operations unchanged to the next {@code MBeanServer} in the chain.
+ * This class is typically subclassed to override some but not all methods.
+ */
+public class IdentityMBeanServerForwarder implements MBeanServerForwarder {
+
+    private MBeanServer next;
+
+    /**
+     * <p>Construct a forwarder that has no next {@code MBeanServer}.
+     * The resulting object will be unusable until {@link #setMBeanServer
+     * setMBeanServer} is called to establish the next item in the chain.</p>
+     */
+    public IdentityMBeanServerForwarder() {
+    }
+
+    /**
+     * <p>Construct a forwarder that forwards to the given {@code MBeanServer}.
+     * It is not an error for {@code next} to be null, but the resulting object
+     * will be unusable until {@link #setMBeanServer setMBeanServer} is called
+     * to establish the next item in the chain.</p>
+     */
+    public IdentityMBeanServerForwarder(MBeanServer next) {
+        this.next = next;
+    }
+
+    public synchronized MBeanServer getMBeanServer() {
+        return next;
+    }
+
+    public synchronized void setMBeanServer(MBeanServer mbs) {
+        next = mbs;
+    }
+
+    private synchronized MBeanServer next() {
+        return next;
+    }
+
+    public void unregisterMBean(ObjectName name)
+            throws InstanceNotFoundException, MBeanRegistrationException {
+        next().unregisterMBean(name);
+    }
+
+    public AttributeList setAttributes(ObjectName name,
+                                        AttributeList attributes)
+            throws InstanceNotFoundException, ReflectionException {
+        return next().setAttributes(name, attributes);
+    }
+
+    public void setAttribute(ObjectName name, Attribute attribute)
+            throws InstanceNotFoundException, AttributeNotFoundException,
+                   InvalidAttributeValueException, MBeanException,
+                   ReflectionException {
+        next().setAttribute(name, attribute);
+    }
+
+    public void removeNotificationListener(ObjectName name,
+                                            NotificationListener listener,
+                                            NotificationFilter filter,
+                                            Object handback)
+            throws InstanceNotFoundException, ListenerNotFoundException {
+        next().removeNotificationListener(name, listener, filter, handback);
+    }
+
+    public void removeNotificationListener(ObjectName name,
+                                            NotificationListener listener)
+            throws InstanceNotFoundException, ListenerNotFoundException {
+        next().removeNotificationListener(name, listener);
+    }
+
+    public void removeNotificationListener(ObjectName name, ObjectName listener,
+                                            NotificationFilter filter,
+                                            Object handback)
+            throws InstanceNotFoundException, ListenerNotFoundException {
+        next().removeNotificationListener(name, listener, filter, handback);
+    }
+
+    public void removeNotificationListener(ObjectName name, ObjectName listener)
+            throws InstanceNotFoundException, ListenerNotFoundException {
+        next().removeNotificationListener(name, listener);
+    }
+
+    public ObjectInstance registerMBean(Object object, ObjectName name)
+            throws InstanceAlreadyExistsException, MBeanRegistrationException,
+                   NotCompliantMBeanException {
+        return next().registerMBean(object, name);
+    }
+
+    public Set<ObjectName> queryNames(ObjectName name, QueryExp query) {
+        return next().queryNames(name, query);
+    }
+
+    public Set<ObjectInstance> queryMBeans(ObjectName name, QueryExp query) {
+        return next().queryMBeans(name, query);
+    }
+
+    public boolean isRegistered(ObjectName name) {
+        return next().isRegistered(name);
+    }
+
+    public boolean isInstanceOf(ObjectName name, String className)
+            throws InstanceNotFoundException {
+        return next().isInstanceOf(name, className);
+    }
+
+    public Object invoke(ObjectName name, String operationName, Object[] params,
+                          String[] signature)
+            throws InstanceNotFoundException, MBeanException,
+                   ReflectionException {
+        return next().invoke(name, operationName, params, signature);
+    }
+
+    public Object instantiate(String className, ObjectName loaderName,
+                               Object[] params, String[] signature)
+            throws ReflectionException, MBeanException,
+                   InstanceNotFoundException {
+        return next().instantiate(className, loaderName, params, signature);
+    }
+
+    public Object instantiate(String className, Object[] params,
+                               String[] signature)
+            throws ReflectionException, MBeanException {
+        return next().instantiate(className, params, signature);
+    }
+
+    public Object instantiate(String className, ObjectName loaderName)
+            throws ReflectionException, MBeanException,
+                   InstanceNotFoundException {
+        return next().instantiate(className, loaderName);
+    }
+
+    public Object instantiate(String className)
+            throws ReflectionException, MBeanException {
+        return next().instantiate(className);
+    }
+
+    public ObjectInstance getObjectInstance(ObjectName name)
+            throws InstanceNotFoundException {
+        return next().getObjectInstance(name);
+    }
+
+    public MBeanInfo getMBeanInfo(ObjectName name)
+            throws InstanceNotFoundException, IntrospectionException,
+                   ReflectionException {
+        return next().getMBeanInfo(name);
+    }
+
+    public Integer getMBeanCount() {
+        return next().getMBeanCount();
+    }
+
+    public String[] getDomains() {
+        return next().getDomains();
+    }
+
+    public String getDefaultDomain() {
+        return next().getDefaultDomain();
+    }
+
+    public ClassLoaderRepository getClassLoaderRepository() {
+        return next().getClassLoaderRepository();
+    }
+
+    public ClassLoader getClassLoaderFor(ObjectName mbeanName)
+            throws InstanceNotFoundException {
+        return next().getClassLoaderFor(mbeanName);
+    }
+
+    public ClassLoader getClassLoader(ObjectName loaderName)
+            throws InstanceNotFoundException {
+        return next().getClassLoader(loaderName);
+    }
+
+    public AttributeList getAttributes(ObjectName name, String[] attributes)
+            throws InstanceNotFoundException, ReflectionException {
+        return next().getAttributes(name, attributes);
+    }
+
+    public Object getAttribute(ObjectName name, String attribute)
+            throws MBeanException, AttributeNotFoundException,
+                   InstanceNotFoundException, ReflectionException {
+        return next().getAttribute(name, attribute);
+    }
+
+    @Deprecated
+    public ObjectInputStream deserialize(String className,
+                                          ObjectName loaderName,
+                                          byte[] data)
+            throws InstanceNotFoundException, OperationsException,
+                   ReflectionException {
+        return next().deserialize(className, loaderName, data);
+    }
+
+    @Deprecated
+    public ObjectInputStream deserialize(String className, byte[] data)
+            throws OperationsException, ReflectionException {
+        return next().deserialize(className, data);
+    }
+
+    @Deprecated
+    public ObjectInputStream deserialize(ObjectName name, byte[] data)
+            throws InstanceNotFoundException, OperationsException {
+        return next().deserialize(name, data);
+    }
+
+    public ObjectInstance createMBean(String className, ObjectName name,
+                                       ObjectName loaderName, Object[] params,
+                                       String[] signature)
+            throws ReflectionException, InstanceAlreadyExistsException,
+                   MBeanRegistrationException, MBeanException,
+                   NotCompliantMBeanException, InstanceNotFoundException {
+        return next().createMBean(className, name, loaderName, params, signature);
+    }
+
+    public ObjectInstance createMBean(String className, ObjectName name,
+                                       Object[] params, String[] signature)
+            throws ReflectionException, InstanceAlreadyExistsException,
+                   MBeanRegistrationException, MBeanException,
+                   NotCompliantMBeanException {
+        return next().createMBean(className, name, params, signature);
+    }
+
+    public ObjectInstance createMBean(String className, ObjectName name,
+                                       ObjectName loaderName)
+            throws ReflectionException, InstanceAlreadyExistsException,
+                   MBeanRegistrationException, MBeanException,
+                   NotCompliantMBeanException, InstanceNotFoundException {
+        return next().createMBean(className, name, loaderName);
+    }
+
+    public ObjectInstance createMBean(String className, ObjectName name)
+            throws ReflectionException, InstanceAlreadyExistsException,
+                   MBeanRegistrationException, MBeanException,
+                   NotCompliantMBeanException {
+        return next().createMBean(className, name);
+    }
+
+    public void addNotificationListener(ObjectName name, ObjectName listener,
+                                         NotificationFilter filter,
+                                         Object handback)
+            throws InstanceNotFoundException {
+        next().addNotificationListener(name, listener, filter, handback);
+    }
+
+    public void addNotificationListener(ObjectName name,
+                                         NotificationListener listener,
+                                         NotificationFilter filter,
+                                         Object handback)
+            throws InstanceNotFoundException {
+        next().addNotificationListener(name, listener, filter, handback);
+    }
+}
--- a/jdk/src/share/classes/javax/management/remote/JMXConnector.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/src/share/classes/javax/management/remote/JMXConnector.java	Wed Jul 05 16:40:29 2017 +0200
@@ -57,6 +57,26 @@
      public static final String CREDENTIALS =
          "jmx.remote.credentials";
 
+     /**
+      * <p>Name of the attribute that specifies whether to use the
+      * {@linkplain javax.management.event Event Service} to handle
+      * notifications for this connector.  The value associated with
+      * this attribute, if any, is a String, which must be equal,
+      * ignoring case, to {@code "true"} or {@code "false"}.</p>
+      *
+      * <p>Not all connectors will understand this attribute, but the
+      * standard {@linkplain javax.management.remote.rmi.RMIConnector
+      * RMI Connector} does.</p>
+      *
+      * <p>If this attribute is not present, then the system property of the
+      * same name (<code>{@value}</code>) is consulted. If that is not set
+      * either, then the Event Service is not used.</p>
+      *
+      * @since 1.7
+      */
+     public static final String USE_EVENT_SERVICE =
+         "jmx.remote.use.event.service";
+
     /**
      * <p>Establishes the connection to the connector server.  This
      * method is equivalent to {@link #connect(Map)
--- a/jdk/src/share/classes/javax/management/remote/JMXConnectorServer.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/src/share/classes/javax/management/remote/JMXConnectorServer.java	Wed Jul 05 16:40:29 2017 +0200
@@ -26,17 +26,21 @@
 
 package javax.management.remote;
 
+import com.sun.jmx.remote.util.EnvHelp;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 
+import java.util.NoSuchElementException;
+import javax.management.MBeanInfo;  // for javadoc
 import javax.management.MBeanNotificationInfo;
 import javax.management.MBeanRegistration;
 import javax.management.MBeanServer;
 import javax.management.Notification;
 import javax.management.NotificationBroadcasterSupport;
 import javax.management.ObjectName;
+import javax.management.event.EventClientDelegate;
 
 /**
  * <p>Superclass of every connector server.  A connector server is
@@ -75,6 +79,48 @@
     public static final String AUTHENTICATOR =
         "jmx.remote.authenticator";
 
+     /**
+      * <p>Name of the attribute that specifies whether this connector
+      * server can delegate notification handling to the
+      * {@linkplain javax.management.event Event Service}.
+      * The value associated with
+      * this attribute, if any, is a String, which must be equal,
+      * ignoring case, to {@code "true"} or {@code "false"}.</p>
+      *
+      * <p>Not all connector servers will understand this attribute, but the
+      * standard {@linkplain javax.management.remote.rmi.RMIConnectorServer
+      * RMI Connector Server} does.</p>
+      *
+      * <p>If this attribute is not present, then the system property of the
+      * same name (<code>{@value}</code>) is consulted. If that is not set
+      * either, then the Event Service is used if the connector server
+      * supports it.</p>
+      *
+      * @since 1.7
+      */
+     public static final String DELEGATE_TO_EVENT_SERVICE =
+         "jmx.remote.delegate.event.service";
+
+     /**
+      * <p>Name of the attribute that specifies whether this connector
+      * server simulates the existence of the {@link EventClientDelegate}
+      * MBean. The value associated with this attribute, if any, must
+      * be a string that is equal to {@code "true"} or {@code "false"},
+      * ignoring case. If it is {@code "true"}, then the connector server
+      * will simulate an EventClientDelegate MBean, as described in {@link
+      * EventClientDelegate#newForwarder}. This MBean is needed for {@link
+      * javax.management.event.EventClient EventClient} to function correctly.</p>
+      *
+      * <p>Not all connector servers will understand this attribute, but the
+      * standard {@linkplain javax.management.remote.rmi.RMIConnectorServer
+      * RMI Connector Server} does.  For a connector server that understands
+      * this attribute, the default value is {@code "true"}.</p>
+      *
+      * @since 1.7
+      */
+     public static final String EVENT_CLIENT_DELEGATE_FORWARDER =
+         "jmx.remote.event.client.delegate.forwarder";
+
     /**
      * <p>Constructs a connector server that will be registered as an
      * MBean in the MBean server it is attached to.  This constructor
@@ -89,34 +135,274 @@
     /**
      * <p>Constructs a connector server that is attached to the given
      * MBean server.  A connector server that is created in this way
-     * can be registered in a different MBean server.</p>
+     * can be registered in a different MBean server, or not registered
+     * in any MBean server.</p>
      *
      * @param mbeanServer the MBean server that this connector server
      * is attached to.  Null if this connector server will be attached
      * to an MBean server by being registered in it.
      */
     public JMXConnectorServer(MBeanServer mbeanServer) {
-        this.mbeanServer = mbeanServer;
+        insertUserMBeanServer(mbeanServer);
     }
 
     /**
      * <p>Returns the MBean server that this connector server is
-     * attached to.</p>
+     * attached to, or the first in a chain of user-added
+     * {@link MBeanServerForwarder}s, if any.</p>
      *
      * @return the MBean server that this connector server is attached
      * to, or null if it is not yet attached to an MBean server.
+     *
+     * @see #setMBeanServerForwarder
+     * @see #getSystemMBeanServer
      */
     public synchronized MBeanServer getMBeanServer() {
-        return mbeanServer;
+        return userMBeanServer;
+    }
+
+    public synchronized void setMBeanServerForwarder(MBeanServerForwarder mbsf) {
+        if (mbsf == null)
+            throw new IllegalArgumentException("Invalid null argument: mbsf");
+
+        if (userMBeanServer != null)
+            mbsf.setMBeanServer(userMBeanServer);
+        insertUserMBeanServer(mbsf);
     }
 
-    public synchronized void setMBeanServerForwarder(MBeanServerForwarder mbsf)
-    {
+    /**
+     * <p>Remove a forwarder from the chain of forwarders.  The forwarder can
+     * be in the system chain or the user chain.  On successful return from
+     * this method, the first occurrence in the chain of an object that is
+     * {@linkplain Object#equals equal} to {@code mbsf} will have been
+     * removed.</p>
+     * @param mbsf the forwarder to remove
+     * @throws NoSuchElementException if there is no occurrence of {@code mbsf}
+     * in the chain.
+     * @throws IllegalArgumentException if {@code mbsf} is null.
+     */
+    public synchronized void removeMBeanServerForwarder(MBeanServerForwarder mbsf) {
         if (mbsf == null)
             throw new IllegalArgumentException("Invalid null argument: mbsf");
 
-        if (mbeanServer !=  null) mbsf.setMBeanServer(mbeanServer);
-        mbeanServer = mbsf;
+        MBeanServerForwarder prev = null;
+        MBeanServer curr = systemMBeanServer;
+        while (curr instanceof MBeanServerForwarder && !mbsf.equals(curr)) {
+            prev = (MBeanServerForwarder) curr;
+            curr = prev.getMBeanServer();
+        }
+        if (!(curr instanceof MBeanServerForwarder))
+            throw new NoSuchElementException("MBeanServerForwarder not in chain");
+        MBeanServerForwarder deleted = (MBeanServerForwarder) curr;
+        MBeanServer next = deleted.getMBeanServer();
+        if (prev != null)
+            prev.setMBeanServer(next);
+        if (systemMBeanServer == deleted)
+            systemMBeanServer = next;
+        if (userMBeanServer == deleted)
+            userMBeanServer = next;
+    }
+
+    /*
+     * Set userMBeanServer to mbs and arrange for the end of the chain of
+     * system MBeanServerForwarders to point to it.  See the comment before
+     * the systemMBeanServer and userMBeanServer field declarations.
+     */
+    private void insertUserMBeanServer(MBeanServer mbs) {
+        MBeanServerForwarder lastSystemMBSF = null;
+        for (MBeanServer mbsi = systemMBeanServer;
+             mbsi != userMBeanServer;
+             mbsi = lastSystemMBSF.getMBeanServer()) {
+            lastSystemMBSF = (MBeanServerForwarder) mbsi;
+        }
+        userMBeanServer = mbs;
+        if (lastSystemMBSF == null)
+            systemMBeanServer = mbs;
+        else
+            lastSystemMBSF.setMBeanServer(mbs);
+    }
+
+    /**
+     * <p>Returns the first item in the chain of system and then user
+     * forwarders.  In the simplest case, a {@code JMXConnectorServer}
+     * is connected directly to an {@code MBeanServer}.  But there can
+     * also be a chain of {@link MBeanServerForwarder}s between the two.
+     * This chain consists of two sub-chains: first the <em>system chain</em>
+     * and then the <em>user chain</em>.  Incoming requests are given to the
+     * first forwarder in the system chain.  Each forwarder can handle
+     * a request itself, or more usually forward it to the next forwarder,
+     * perhaps with some extra behavior such as logging or security
+     * checking before or after the forwarding.  The last forwarder in
+     * the system chain is followed by the first forwarder in the user
+     * chain.</p>
+     *
+     * <p>The <em>system chain</em> is usually
+     * defined by a connector server based on the environment Map;
+     * see {@link JMXConnectorServerFactory#newJMXConnectorServer}.  Allowing the
+     * connector server to define its forwarders in this way ensures that
+     * they are in the correct order - some forwarders need to be inserted
+     * before others for correct behavior.  It is possible to modify the
+     * system chain, for example using {@link #setSystemMBeanServerForwarder} or
+     * {@link #removeMBeanServerForwarder}, but in that case the system
+     * chain is no longer guaranteed to be correct.</p>
+     *
+     * <p>The <em>user chain</em> is defined by calling {@link
+     * #setMBeanServerForwarder} to insert forwarders at the head of the user
+     * chain.</p>
+     *
+     * <p>If there are no forwarders in either chain, then both
+     * {@link #getMBeanServer()} and {@code getSystemMBeanServer()} will
+     * return the {@code MBeanServer} for this connector server.  If there
+     * are forwarders in the user chain but not the system chain, then
+     * both methods will return the first forwarder in the user chain.
+     * If there are forwarders in the system chain but not the user chain,
+     * then {@code getSystemMBeanServer()} will return the first forwarder
+     * in the system chain, and {@code getMBeanServer()} will return the
+     * {@code MBeanServer} for this connector server.  Finally, if there
+     * are forwarders in each chain then {@code getSystemMBeanServer()}
+     * will return the first forwarder in the system chain, and {@code
+     * getMBeanServer()} will return the first forwarder in the user chain.</p>
+     *
+     * <p>This code illustrates how the chains can be traversed:</p>
+     *
+     * <pre>
+     * JMXConnectorServer cs;
+     * System.out.println("system chain:");
+     * MBeanServer mbs = cs.getSystemMBeanServer();
+     * while (true) {
+     *     if (mbs == cs.getMBeanServer())
+     *         System.out.println("user chain:");
+     *     if (!(mbs instanceof MBeanServerForwarder))
+     *         break;
+     *     MBeanServerForwarder mbsf = (MBeanServerForwarder) mbs;
+     *     System.out.println("--forwarder: " + mbsf);
+     *     mbs = mbsf.getMBeanServer();
+     * }
+     * System.out.println("--MBean Server");
+     * </pre>
+     *
+     * @return the first item in the system chain of forwarders.
+     *
+     * @see #setSystemMBeanServerForwarder
+     */
+    public synchronized MBeanServer getSystemMBeanServer() {
+        return systemMBeanServer;
+    }
+
+    /**
+     * <p>Inserts an object that intercepts requests for the MBean server
+     * that arrive through this connector server.  This object will be
+     * supplied as the <code>MBeanServer</code> for any new connection
+     * created by this connector server.  Existing connections are
+     * unaffected.</p>
+     *
+     * <p>This method can be called more than once with different
+     * {@link MBeanServerForwarder} objects.  The result is a chain
+     * of forwarders.  The last forwarder added is the first in the chain.</p>
+     *
+     * <p>This method modifies the system chain of {@link MBeanServerForwarder}s.
+     * Usually user code should change the user chain instead, via
+     * {@link #setMBeanServerForwarder}.</p>
+     *
+     * <p>Not all connector servers support a system chain of forwarders.
+     * Calling this method on a connector server that does not will produce an
+     * {@link UnsupportedOperationException}.</p>
+     *
+     * <p>Suppose {@code mbs} is the result of {@link #getSystemMBeanServer()}
+     * before calling this method.  If {@code mbs} is not null, then
+     * {@code mbsf.setMBeanServer(mbs)} will be called.  If doing so
+     * produces an exception, this method throws the same exception without
+     * any other effect.  If {@code mbs} is null, or if the call to
+     * {@code mbsf.setMBeanServer(mbs)} succeeds, then this method will
+     * return normally and {@code getSystemMBeanServer()} will then return
+     * {@code mbsf}.</p>
+     *
+     * <p>The result of {@link #getMBeanServer()} is unchanged by this method.</p>
+     *
+     * @param mbsf the new <code>MBeanServerForwarder</code>.
+     *
+     * @throws IllegalArgumentException if the call to {@link
+     * MBeanServerForwarder#setMBeanServer mbsf.setMBeanServer} fails
+     * with <code>IllegalArgumentException</code>, or if
+     * <code>mbsf</code> is null.
+     *
+     * @throws UnsupportedOperationException if
+     * {@link #supportsSystemMBeanServerForwarder} returns false.
+     *
+     * @see #getSystemMBeanServer()
+     */
+    public synchronized void setSystemMBeanServerForwarder(
+            MBeanServerForwarder mbsf) {
+        if (mbsf == null)
+            throw new IllegalArgumentException("Invalid null argument: mbsf");
+        mustSupportSystemMBSF();
+
+        if (systemMBeanServer != null)
+            mbsf.setMBeanServer(systemMBeanServer);
+        systemMBeanServer = mbsf;
+    }
+
+    /**
+     * <p>Returns true if this connector server supports a system chain of
+     * {@link MBeanServerForwarder}s.  The default implementation of this
+     * method returns false.  Connector servers that do support the system
+     * chain must override this method to return true.
+     *
+     * @return true if this connector server supports the system chain of
+     * forwarders.
+     */
+    public boolean supportsSystemMBeanServerForwarder() {
+        return false;
+    }
+
+    private void mustSupportSystemMBSF() {
+        if (!supportsSystemMBeanServerForwarder()) {
+            throw new UnsupportedOperationException(
+                    "System MBeanServerForwarder not supported by this " +
+                    "connector server");
+        }
+    }
+
+    /**
+     * <p>Install {@link MBeanServerForwarder}s in the system chain
+     * based on the attributes in the given {@code Map}.  A connector
+     * server that {@linkplain #supportsSystemMBeanServerForwarder supports}
+     * a system chain of {@code MBeanServerForwarder}s can call this method
+     * to add forwarders to that chain based on the contents of {@code env}.
+     * In order:</p>
+     *
+     * <ul>
+     *
+     * <li>If {@link #EVENT_CLIENT_DELEGATE_FORWARDER} is absent, or is
+     * present with the value {@code "true"}, then a forwarder with the
+     * functionality of {@link EventClientDelegate#newForwarder} is inserted
+     * at the start of the system chain.</li>
+     *
+     * </ul>
+     *
+     * <p>For {@code EVENT_CLIENT_DELEGATE_FORWARDER}, if the
+     * attribute is absent from the {@code Map} and a system property
+     * of the same name is defined, then the value of the system
+     * property is used as if it were in the {@code Map}.
+     *
+     * <p>Attributes in {@code env} that are not listed above are ignored
+     * by this method.</p>
+     *
+     * @throws UnsupportedOperationException if {@link
+     * #supportsSystemMBeanServerForwarder} is false.
+     */
+    protected void installStandardForwarders(Map<String, ?> env) {
+        mustSupportSystemMBSF();
+
+        // Remember that forwarders must be added in reverse order!
+
+        boolean ecd = EnvHelp.computeBooleanFromString(
+                env, EVENT_CLIENT_DELEGATE_FORWARDER, false, true);
+
+        if (ecd) {
+            MBeanServerForwarder mbsf = EventClientDelegate.newForwarder();
+            setSystemMBeanServerForwarder(mbsf);
+        }
     }
 
     public String[] getConnectionIds() {
@@ -359,8 +645,8 @@
                                                ObjectName name) {
         if (mbs == null || name == null)
             throw new NullPointerException("Null MBeanServer or ObjectName");
-        if (mbeanServer == null) {
-            mbeanServer = mbs;
+        if (userMBeanServer == null) {
+            insertUserMBeanServer(mbs);
             myName = name;
         }
         return name;
@@ -394,10 +680,53 @@
         myName = null;
     }
 
-    /**
-     * The MBeanServer used by this server to execute a client request.
+    /*
+     * Fields describing the chains of forwarders (MBeanServerForwarders).
+     * In the general case, the forwarders look something like this:
+     *
+     * systemMBeanServer          userMBeanServer
+     * |                          |
+     * v                          v
+     * mbsf1 -> mbsf2 -> mbsf3 -> mbsf4 -> mbsf5 -> mbs
+     *
+     * Here, each mbsfi is an MBeanServerForwarder, and the arrows
+     * illustrate its getMBeanServer() method.  The last MBeanServerForwarder
+     * can point to an MBeanServer that is not instanceof MBeanServerForwarder,
+     * here mbs.
+     *
+     * Initially, the chain can be empty if this JMXConnectorServer was
+     * constructed without an MBeanServer.  In this case, both systemMBS
+     * and userMBS will be null.  If there is initially an MBeanServer,
+     * then both systemMBS and userMBS will point to it.
+     *
+     * Whenever userMBS is changed, the system chain must be updated. If there
+     * are forwarders in the system chain (between systemMBS and userMBS in the
+     * picture above), then the last one must point to the old value of userMBS
+     * (possibly null). It must be updated to point to the new value. If there
+     * are no forwarders in the system chain, then systemMBS must be updated to
+     * the new value of userMBS. The invariant is that starting from systemMBS
+     * and repeatedly calling MBSF.getMBeanServer() you will end up at
+     * userMBS.  The implication is that you will not see any MBeanServer
+     * object on the way that is not also an MBeanServerForwarder.
+     *
+     * The method insertUserMBeanServer contains the logic to change userMBS
+     * and adjust the system chain appropriately.
+     *
+     * If userMBS is null and this JMXConnectorServer is registered in an
+     * MBeanServer, then userMBS becomes that MBeanServer, and the system
+     * chain must be updated as just described.
+     *
+     * When systemMBS is updated, there is no effect on userMBS. The system
+     * chain may contain forwarders even though the user chain is empty
+     * (there is no MBeanServer). In that case an attempt to forward an
+     * incoming request through the chain will fall off the end and fail with a
+     * NullPointerException. Usually a connector server will refuse to start()
+     * if it is not attached to an MBS, so this situation should not arise.
      */
-    private MBeanServer mbeanServer = null;
+
+    private MBeanServer userMBeanServer;
+
+    private MBeanServer systemMBeanServer;
 
     /**
      * The name used to registered this server in an MBeanServer.
--- a/jdk/src/share/classes/javax/management/remote/JMXConnectorServerFactory.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/src/share/classes/javax/management/remote/JMXConnectorServerFactory.java	Wed Jul 05 16:40:29 2017 +0200
@@ -35,10 +35,8 @@
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map;
-import java.util.ServiceLoader;
 
 import javax.management.MBeanServer;
-import javax.management.ObjectName;
 
 /**
  * <p>Factory to create JMX API connector servers.  There
@@ -172,7 +170,8 @@
      * loader MBean name.  This class loader is used to deserialize objects in
      * requests received from the client, possibly after consulting an
      * MBean-specific class loader.  The value associated with this
-     * attribute is an instance of {@link ObjectName}.</p>
+     * attribute is an instance of {@link javax.management.ObjectName
+     * ObjectName}.</p>
      */
     public static final String DEFAULT_CLASS_LOADER_NAME =
         "jmx.remote.default.class.loader.name";
--- a/jdk/src/share/classes/javax/management/remote/JMXConnectorServerMBean.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/src/share/classes/javax/management/remote/JMXConnectorServerMBean.java	Wed Jul 05 16:40:29 2017 +0200
@@ -105,23 +105,34 @@
     public boolean isActive();
 
     /**
-     * <p>Adds an object that intercepts requests for the MBean server
+     * <p>Inserts an object that intercepts requests for the MBean server
      * that arrive through this connector server.  This object will be
      * supplied as the <code>MBeanServer</code> for any new connection
      * created by this connector server.  Existing connections are
      * unaffected.</p>
      *
-     * <p>If this connector server is already associated with an
+     * <p>This method can be called more than once with different
+     * {@link MBeanServerForwarder} objects.  The result is a chain
+     * of forwarders.  The last forwarder added is the first in the chain.
+     * In more detail:</p>
+     *
+     * <ul>
+     * <li><p>If this connector server is already associated with an
      * <code>MBeanServer</code> object, then that object is given to
      * {@link MBeanServerForwarder#setMBeanServer
      * mbsf.setMBeanServer}.  If doing so produces an exception, this
      * method throws the same exception without any other effect.</p>
      *
-     * <p>If this connector is not already associated with an
+     * <li><p>If this connector is not already associated with an
      * <code>MBeanServer</code> object, or if the
      * <code>mbsf.setMBeanServer</code> call just mentioned succeeds,
      * then <code>mbsf</code> becomes this connector server's
      * <code>MBeanServer</code>.</p>
+     * </ul>
+     *
+     * <p>A connector server may support two chains of forwarders,
+     * a system chain and a user chain.  See {@link
+     * JMXConnectorServer#setSystemMBeanServerForwarder} for details.</p>
      *
      * @param mbsf the new <code>MBeanServerForwarder</code>.
      *
@@ -129,6 +140,8 @@
      * MBeanServerForwarder#setMBeanServer mbsf.setMBeanServer} fails
      * with <code>IllegalArgumentException</code>.  This includes the
      * case where <code>mbsf</code> is null.
+     *
+     * @see JMXConnectorServer#setSystemMBeanServerForwarder
      */
     public void setMBeanServerForwarder(MBeanServerForwarder mbsf);
 
--- a/jdk/src/share/classes/javax/management/remote/rmi/RMIConnectionImpl.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/src/share/classes/javax/management/remote/rmi/RMIConnectionImpl.java	Wed Jul 05 16:40:29 2017 +0200
@@ -25,10 +25,12 @@
 
 package javax.management.remote.rmi;
 
+import com.sun.jmx.mbeanserver.Util;
 import static com.sun.jmx.mbeanserver.Util.cast;
 import com.sun.jmx.remote.internal.ServerCommunicatorAdmin;
 import com.sun.jmx.remote.internal.ServerNotifForwarder;
 import com.sun.jmx.remote.security.JMXSubjectDomainCombiner;
+import com.sun.jmx.remote.security.NotificationAccessController;
 import com.sun.jmx.remote.security.SubjectDelegator;
 import com.sun.jmx.remote.util.ClassLoaderWithRepository;
 import com.sun.jmx.remote.util.ClassLogger;
@@ -36,6 +38,7 @@
 import com.sun.jmx.remote.util.OrderClassLoaders;
 
 import java.io.IOException;
+import java.lang.reflect.UndeclaredThrowableException;
 import java.rmi.MarshalledObject;
 import java.rmi.UnmarshalException;
 import java.rmi.server.Unreferenced;
@@ -56,19 +59,24 @@
 import javax.management.InstanceNotFoundException;
 import javax.management.IntrospectionException;
 import javax.management.InvalidAttributeValueException;
+import javax.management.JMX;
 import javax.management.ListenerNotFoundException;
 import javax.management.MBeanException;
 import javax.management.MBeanInfo;
 import javax.management.MBeanRegistrationException;
 import javax.management.MBeanServer;
 import javax.management.NotCompliantMBeanException;
+import javax.management.Notification;
 import javax.management.NotificationFilter;
 import javax.management.ObjectInstance;
 import javax.management.ObjectName;
 import javax.management.QueryExp;
 import javax.management.ReflectionException;
 import javax.management.RuntimeOperationsException;
-import javax.management.loading.ClassLoaderRepository;
+import javax.management.event.EventClientDelegate;
+import javax.management.event.EventClientDelegateMBean;
+import javax.management.event.EventClientNotFoundException;
+import javax.management.event.FetchingEventForwarder;
 import javax.management.remote.JMXServerErrorException;
 import javax.management.remote.NotificationResult;
 import javax.management.remote.TargetedNotification;
@@ -149,28 +157,16 @@
                 new PrivilegedAction<ClassLoaderWithRepository>() {
                     public ClassLoaderWithRepository run() {
                         return new ClassLoaderWithRepository(
-                                              getClassLoaderRepository(),
-                                              dcl);
+                                      mbeanServer.getClassLoaderRepository(),
+                                      dcl);
                     }
                 });
-
         serverCommunicatorAdmin = new
           RMIServerCommunicatorAdmin(EnvHelp.getServerConnectionTimeout(env));
 
         this.env = env;
     }
 
-    private synchronized ServerNotifForwarder getServerNotifFwd() {
-        // Lazily created when first use. Mainly when
-        // addNotificationListener is first called.
-        if (serverNotifForwarder == null)
-            serverNotifForwarder =
-                new ServerNotifForwarder(mbeanServer,
-                                         env,
-                                         rmiServer.getNotifBuffer(),
-                                         connectionId);
-        return serverNotifForwarder;
-    }
 
     public String getConnectionId() throws IOException {
         // We should call reqIncomming() here... shouldn't we?
@@ -181,6 +177,7 @@
         final boolean debug = logger.debugOn();
         final String  idstr = (debug?"["+this.toString()+"]":null);
 
+        final SubscriptionManager mgr;
         synchronized (this) {
             if (terminated) {
                 if (debug) logger.debug("close",idstr + " already terminated.");
@@ -195,11 +192,12 @@
                 serverCommunicatorAdmin.terminate();
             }
 
-            if (serverNotifForwarder != null) {
-                serverNotifForwarder.terminate();
-            }
+            mgr = subscriptionManager;
+            subscriptionManager = null;
         }
 
+        if (mgr != null) mgr.terminate();
+
         rmiServer.clientClosed(this);
 
         if (debug) logger.debug("close",idstr + " closed.");
@@ -955,8 +953,7 @@
         int i=0;
         ClassLoader targetCl;
         NotificationFilter[] filterValues =
-        new NotificationFilter[names.length];
-        Object params[];
+            new NotificationFilter[names.length];
         Integer[] ids = new Integer[names.length];
         final boolean debug=logger.debugOn();
 
@@ -991,8 +988,7 @@
             // remove all registered listeners
             for (int j=0; j<i; j++) {
                 try {
-                    getServerNotifFwd().removeNotificationListener(names[j],
-                                                                   ids[j]);
+                    doRemoveListener(names[j],ids[j]);
                 } catch (Exception eee) {
                     // strange
                 }
@@ -1240,22 +1236,299 @@
             final long csn = clientSequenceNumber;
             final int mn = maxNotifications;
             final long t = timeout;
-            PrivilegedAction<NotificationResult> action =
-                new PrivilegedAction<NotificationResult>() {
-                    public NotificationResult run() {
-                        return getServerNotifFwd().fetchNotifs(csn, t, mn);
+
+            final PrivilegedExceptionAction<NotificationResult> action =
+                new PrivilegedExceptionAction<NotificationResult>() {
+                    public NotificationResult run() throws IOException {
+                            return doFetchNotifs(csn, t, mn);
                     }
             };
-            if (acc == null)
-                return action.run();
-            else
-                return AccessController.doPrivileged(action, acc);
+            try {
+                if (acc == null)
+                    return action.run();
+                else
+                    return AccessController.doPrivileged(action, acc);
+            } catch (IOException x) {
+                throw x;
+            } catch (RuntimeException x) {
+                throw x;
+            } catch (Exception x) {
+                // should not happen
+                throw new UndeclaredThrowableException(x);
+            }
+
         } finally {
             serverCommunicatorAdmin.rspOutgoing();
         }
     }
 
     /**
+     * This is an abstraction class that let us use the legacy
+     * ServerNotifForwarder and the new EventClientDelegateMBean
+     * indifferently.
+     **/
+    private static interface SubscriptionManager {
+        public void removeNotificationListener(ObjectName name, Integer id)
+            throws InstanceNotFoundException, ListenerNotFoundException, IOException;
+        public void removeNotificationListener(ObjectName name, Integer[] ids)
+            throws Exception;
+        public NotificationResult fetchNotifications(long csn, long timeout, int maxcount)
+            throws IOException;
+        public Integer addNotificationListener(ObjectName name, NotificationFilter filter)
+            throws InstanceNotFoundException, IOException;
+        public void terminate()
+            throws IOException;
+    }
+
+    /**
+     * A SubscriptionManager that uses a ServerNotifForwarder.
+     **/
+    private static class LegacySubscriptionManager implements SubscriptionManager {
+        private final ServerNotifForwarder forwarder;
+        LegacySubscriptionManager(ServerNotifForwarder forwarder) {
+            this.forwarder = forwarder;
+        }
+
+        public void removeNotificationListener(ObjectName name, Integer id)
+            throws InstanceNotFoundException, ListenerNotFoundException,
+                IOException {
+            forwarder.removeNotificationListener(name,id);
+        }
+
+        public void removeNotificationListener(ObjectName name, Integer[] ids)
+            throws Exception {
+            forwarder.removeNotificationListener(name,ids);
+        }
+
+        public NotificationResult fetchNotifications(long csn, long timeout, int maxcount) {
+            return forwarder.fetchNotifs(csn,timeout,maxcount);
+        }
+
+        public Integer addNotificationListener(ObjectName name,
+                NotificationFilter filter)
+            throws InstanceNotFoundException, IOException {
+            return forwarder.addNotificationListener(name,filter);
+        }
+
+        public void terminate() {
+            forwarder.terminate();
+        }
+    }
+
+    /**
+     * A SubscriptionManager that uses an EventClientDelegateMBean.
+     **/
+    private static class EventSubscriptionManager
+            implements SubscriptionManager {
+        private final MBeanServer mbeanServer;
+        private final EventClientDelegateMBean delegate;
+        private final NotificationAccessController notifAC;
+        private final boolean checkNotificationEmission;
+        private final String clientId;
+        private final String connectionId;
+
+        EventSubscriptionManager(
+                MBeanServer mbeanServer,
+                EventClientDelegateMBean delegate,
+                Map<String, ?> env,
+                String clientId,
+                String connectionId) {
+            this.mbeanServer = mbeanServer;
+            this.delegate = delegate;
+            this.notifAC = EnvHelp.getNotificationAccessController(env);
+            this.checkNotificationEmission =
+                EnvHelp.computeBooleanFromString(
+                    env, "jmx.remote.x.check.notification.emission", false);
+            this.clientId = clientId;
+            this.connectionId = connectionId;
+        }
+
+        @SuppressWarnings("serial")  // no serialVersionUID
+        private class AccessControlFilter implements NotificationFilter {
+            private final NotificationFilter wrapped;
+            private final ObjectName name;
+
+            AccessControlFilter(ObjectName name, NotificationFilter wrapped) {
+                this.name = name;
+                this.wrapped = wrapped;
+            }
+
+            public boolean isNotificationEnabled(Notification notification) {
+                try {
+                    if (checkNotificationEmission) {
+                        ServerNotifForwarder.checkMBeanPermission(
+                                mbeanServer, name, "addNotificationListener");
+                    }
+                    notifAC.fetchNotification(
+                            connectionId, name, notification, getSubject());
+                    return (wrapped == null) ? true :
+                        wrapped.isNotificationEnabled(notification);
+                } catch (InstanceNotFoundException e) {
+                    return false;
+                } catch (SecurityException e) {
+                    return false;
+                }
+            }
+
+        }
+
+        public Integer addNotificationListener(
+                ObjectName name, NotificationFilter filter)
+                throws InstanceNotFoundException, IOException {
+            if (notifAC != null) {
+                notifAC.addNotificationListener(connectionId, name, getSubject());
+                filter = new AccessControlFilter(name, filter);
+            }
+            try {
+                return delegate.addListener(clientId,name,filter);
+            } catch (EventClientNotFoundException x) {
+                throw new IOException("Unknown clientId: "+clientId,x);
+            }
+        }
+
+        public void removeNotificationListener(ObjectName name, Integer id)
+                throws InstanceNotFoundException, ListenerNotFoundException,
+                       IOException {
+            if (notifAC != null)
+                notifAC.removeNotificationListener(connectionId, name, getSubject());
+            try {
+                delegate.removeListenerOrSubscriber(clientId,id);
+            } catch (EventClientNotFoundException x) {
+                throw new IOException("Unknown clientId: "+clientId,x);
+            }
+        }
+
+        public void removeNotificationListener(ObjectName name, Integer[] ids)
+                throws InstanceNotFoundException, ListenerNotFoundException,
+                       IOException {
+            if (notifAC != null)
+                notifAC.removeNotificationListener(connectionId, name, getSubject());
+            try {
+                for (Integer id : ids)
+                    delegate.removeListenerOrSubscriber(clientId,id);
+            } catch (EventClientNotFoundException x) {
+                throw new IOException("Unknown clientId: "+clientId,x);
+            }
+        }
+
+        public NotificationResult fetchNotifications(long csn, long timeout,
+                int maxcount)
+            throws IOException {
+            try {
+                // For some reason the delegate doesn't accept a negative
+                // sequence number. However legacy clients will always call
+                // fetchNotifications with a negative sequence number, when
+                // they call it for the first time.
+                // In that case, we will use 0 instead.
+                //
+                return delegate.fetchNotifications(
+                        clientId, Math.max(csn, 0), maxcount, timeout);
+            } catch (EventClientNotFoundException x) {
+                throw new IOException("Unknown clientId: "+clientId,x);
+            }
+        }
+
+        public void terminate()
+            throws IOException {
+            try {
+                delegate.removeClient(clientId);
+            } catch (EventClientNotFoundException x) {
+                throw new IOException("Unknown clientId: "+clientId,x);
+            }
+        }
+
+        private static Subject getSubject() {
+            return Subject.getSubject(AccessController.getContext());
+        }
+    }
+
+    /**
+     * Creates a SubscriptionManager that uses either the legacy notifications
+     * mechanism (ServerNotifForwarder) or the new event service
+     * (EventClientDelegateMBean) depending on which option was passed in
+     * the connector's map.
+     **/
+    private SubscriptionManager createSubscriptionManager()
+        throws IOException {
+        if (EnvHelp.delegateToEventService(env) &&
+                mbeanServer.isRegistered(EventClientDelegate.OBJECT_NAME)) {
+            final EventClientDelegateMBean mbean =
+                    JMX.newMBeanProxy(mbeanServer,
+                        EventClientDelegate.OBJECT_NAME,
+                        EventClientDelegateMBean.class);
+            String clientId;
+            try {
+                 clientId =
+                    mbean.addClient(
+                FetchingEventForwarder.class.getName(),
+                new Object[] {EnvHelp.getNotifBufferSize(env)},
+                new String[] {int.class.getName()});
+            } catch (Exception e) {
+                if (e instanceof IOException)
+                    throw (IOException) e;
+                else
+                    throw new IOException(e);
+            }
+
+            // we're going to call remove client...
+            try {
+                mbean.lease(clientId, Long.MAX_VALUE);
+            } catch (EventClientNotFoundException x) {
+                throw new IOException("Unknown clientId: "+clientId,x);
+            }
+            return new EventSubscriptionManager(mbeanServer, mbean, env,
+                    clientId, connectionId);
+        } else {
+            final ServerNotifForwarder serverNotifForwarder =
+                new ServerNotifForwarder(mbeanServer,
+                                         env,
+                                         rmiServer.getNotifBuffer(),
+                                         connectionId);
+             return new LegacySubscriptionManager(serverNotifForwarder);
+        }
+    }
+
+    /**
+     * Lazy creation of a  SubscriptionManager.
+     **/
+    private synchronized SubscriptionManager getSubscriptionManager()
+        throws IOException {
+        // Lazily created when first use. Mainly when
+        // addNotificationListener is first called.
+
+        if (subscriptionManager == null) {
+             subscriptionManager = createSubscriptionManager();
+        }
+        return subscriptionManager;
+    }
+
+    // calls SubscriptionManager.
+    private void doRemoveListener(ObjectName name, Integer id)
+        throws InstanceNotFoundException, ListenerNotFoundException,
+            IOException {
+           getSubscriptionManager().removeNotificationListener(name,id);
+    }
+
+    // calls SubscriptionManager.
+    private void doRemoveListener(ObjectName name, Integer[] ids)
+        throws Exception {
+           getSubscriptionManager().removeNotificationListener(name,ids);
+    }
+
+    // calls SubscriptionManager.
+    private NotificationResult doFetchNotifs(long csn, long timeout, int maxcount)
+         throws IOException {
+         return getSubscriptionManager().fetchNotifications(csn, timeout, maxcount);
+    }
+
+    // calls SubscriptionManager.
+    private Integer doAddListener(ObjectName name, NotificationFilter filter)
+         throws InstanceNotFoundException, IOException {
+         return getSubscriptionManager().addNotificationListener(name,filter);
+    }
+
+
+    /**
      * <p>Returns a string representation of this object.  In general,
      * the <code>toString</code> method returns a string that
      * "textually represents" this object. The result should be a
@@ -1313,16 +1586,6 @@
     // private methods
     //------------------------------------------------------------------------
 
-    private ClassLoaderRepository getClassLoaderRepository() {
-        return
-            AccessController.doPrivileged(
-                new PrivilegedAction<ClassLoaderRepository>() {
-                    public ClassLoaderRepository run() {
-                        return mbeanServer.getClassLoaderRepository();
-                    }
-                });
-    }
-
     private ClassLoader getClassLoader(final ObjectName name)
         throws InstanceNotFoundException {
         try {
@@ -1482,9 +1745,8 @@
             return null;
 
         case ADD_NOTIFICATION_LISTENERS:
-            return getServerNotifFwd().addNotificationListener(
-                                                (ObjectName)params[0],
-                                                (NotificationFilter)params[1]);
+            return doAddListener((ObjectName)params[0],
+                                 (NotificationFilter)params[1]);
 
         case ADD_NOTIFICATION_LISTENER_OBJECTNAME:
             mbeanServer.addNotificationListener((ObjectName)params[0],
@@ -1494,9 +1756,7 @@
             return null;
 
         case REMOVE_NOTIFICATION_LISTENER:
-            getServerNotifFwd().removeNotificationListener(
-                                                   (ObjectName)params[0],
-                                                   (Integer[])params[1]);
+            doRemoveListener((ObjectName)params[0],(Integer[])params[1]);
             return null;
 
         case REMOVE_NOTIFICATION_LISTENER_OBJECTNAME:
@@ -1709,23 +1969,21 @@
     private final static int
         REMOVE_NOTIFICATION_LISTENER                            = 19;
     private final static int
-        REMOVE_NOTIFICATION_LISTENER_FILTER_HANDBACK            = 20;
+        REMOVE_NOTIFICATION_LISTENER_OBJECTNAME                 = 20;
     private final static int
-        REMOVE_NOTIFICATION_LISTENER_OBJECTNAME                 = 21;
-    private final static int
-        REMOVE_NOTIFICATION_LISTENER_OBJECTNAME_FILTER_HANDBACK = 22;
+        REMOVE_NOTIFICATION_LISTENER_OBJECTNAME_FILTER_HANDBACK = 21;
     private final static int
-        SET_ATTRIBUTE                                           = 23;
+        SET_ATTRIBUTE                                           = 22;
     private final static int
-        SET_ATTRIBUTES                                          = 24;
+        SET_ATTRIBUTES                                          = 23;
     private final static int
-        UNREGISTER_MBEAN                                        = 25;
+        UNREGISTER_MBEAN                                        = 24;
 
     // SERVER NOTIFICATION
     //--------------------
 
-    private ServerNotifForwarder serverNotifForwarder;
-    private Map env;
+    private SubscriptionManager subscriptionManager;
+    private Map<String, ?> env;
 
     // TRACES & DEBUG
     //---------------
--- a/jdk/src/share/classes/javax/management/remote/rmi/RMIConnector.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/src/share/classes/javax/management/remote/rmi/RMIConnector.java	Wed Jul 05 16:40:29 2017 +0200
@@ -25,6 +25,9 @@
 
 package javax.management.remote.rmi;
 
+import com.sun.jmx.event.DaemonThreadFactory;
+import com.sun.jmx.event.EventConnection;
+import com.sun.jmx.mbeanserver.PerThreadGroupPool;
 import com.sun.jmx.remote.internal.ClientCommunicatorAdmin;
 import com.sun.jmx.remote.internal.ClientListenerInfo;
 import com.sun.jmx.remote.internal.ClientNotifForwarder;
@@ -68,6 +71,12 @@
 import java.util.Properties;
 import java.util.Set;
 import java.util.WeakHashMap;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.Executor;
+import java.util.concurrent.LinkedBlockingDeque;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
 import javax.management.Attribute;
 import javax.management.AttributeList;
 import javax.management.AttributeNotFoundException;
@@ -75,6 +84,7 @@
 import javax.management.InstanceNotFoundException;
 import javax.management.IntrospectionException;
 import javax.management.InvalidAttributeValueException;
+import javax.management.JMX;
 import javax.management.ListenerNotFoundException;
 import javax.management.MBeanException;
 import javax.management.MBeanInfo;
@@ -92,6 +102,8 @@
 import javax.management.ObjectName;
 import javax.management.QueryExp;
 import javax.management.ReflectionException;
+import javax.management.event.EventClient;
+import javax.management.event.EventClientDelegateMBean;
 import javax.management.remote.JMXConnectionNotification;
 import javax.management.remote.JMXConnector;
 import javax.management.remote.JMXConnectorFactory;
@@ -280,8 +292,8 @@
             // client-side environment property is set to "true".
             //
             boolean checkStub = EnvHelp.computeBooleanFromString(
-                usemap,
-                "jmx.remote.x.check.stub");
+                    usemap,
+                    "jmx.remote.x.check.stub",false);
             if (checkStub) checkStub(stub, rmiServerImplStubClass);
 
             // Connect IIOP Stub if needed.
@@ -318,6 +330,8 @@
             //
             connectionId = getConnectionId();
 
+            eventServiceEnabled = EnvHelp.eventServiceEnabled(env);
+
             Notification connectedNotif =
                 new JMXConnectionNotification(JMXConnectionNotification.OPENED,
                                               this,
@@ -327,6 +341,8 @@
                                               null);
             sendNotification(connectedNotif);
 
+            // whether or not event service
+
             if (tracing) logger.trace("connect",idstr + " done...");
         } catch (IOException e) {
             if (tracing)
@@ -378,13 +394,42 @@
             throw new IOException("Not connected");
         }
 
-        MBeanServerConnection mbsc = rmbscMap.get(delegationSubject);
-        if (mbsc != null)
-            return mbsc;
+        MBeanServerConnection rmbsc = rmbscMap.get(delegationSubject);
+        if (rmbsc != null) {
+            return rmbsc;
+        }
+
+        rmbsc = new RemoteMBeanServerConnection(delegationSubject);
+        if (eventServiceEnabled) {
+            EventClientDelegateMBean ecd = JMX.newMBeanProxy(
+                    rmbsc, EventClientDelegateMBean.OBJECT_NAME,
+                    EventClientDelegateMBean.class);
+            EventClient ec = new EventClient(ecd, null, defaultExecutor(), null,
+                    EventClient.DEFAULT_LEASE_TIMEOUT);
 
-        mbsc = new RemoteMBeanServerConnection(delegationSubject);
-        rmbscMap.put(delegationSubject, mbsc);
-        return mbsc;
+            rmbsc = EventConnection.Factory.make(rmbsc, ec);
+            ec.addEventClientListener(
+                    lostNotifListener, null, null);
+        }
+        rmbscMap.put(delegationSubject, rmbsc);
+        return rmbsc;
+    }
+
+    private static Executor defaultExecutor() {
+        PerThreadGroupPool.Create<ThreadPoolExecutor> create =
+                new PerThreadGroupPool.Create<ThreadPoolExecutor>() {
+            public ThreadPoolExecutor createThreadPool(ThreadGroup group) {
+                ThreadFactory daemonThreadFactory = new DaemonThreadFactory(
+                        "RMIConnector listener dispatch %d");
+                ThreadPoolExecutor exec = new ThreadPoolExecutor(
+                        1, 10, 1, TimeUnit.SECONDS,
+                        new LinkedBlockingDeque<Runnable>(),
+                        daemonThreadFactory);
+                exec.allowCoreThreadTimeOut(true);
+                return exec;
+            }
+        };
+        return listenerDispatchThreadPool.getThreadPoolExecutor(create);
     }
 
     public void
@@ -466,6 +511,17 @@
             communicatorAdmin.terminate();
         }
 
+        // close all EventClient
+        for (MBeanServerConnection rmbsc : rmbscMap.values()) {
+            if (rmbsc instanceof EventConnection) {
+                try {
+                    ((EventConnection)rmbsc).getEventClient().close();
+                } catch (Exception e) {
+                    // OK
+                }
+            }
+        }
+
         if (rmiNotifClient != null) {
             try {
                 rmiNotifClient.terminate();
@@ -592,17 +648,18 @@
         }
 
         if (debug) logger.debug("addListenersWithSubjects","registered "
-                                + listenerIDs.length + " listener(s)");
+                + ((listenerIDs==null)?0:listenerIDs.length)
+                + " listener(s)");
         return listenerIDs;
     }
 
     //--------------------------------------------------------------------
     // Implementation of MBeanServerConnection
     //--------------------------------------------------------------------
-    private class RemoteMBeanServerConnection
-        implements MBeanServerConnection {
+    private class RemoteMBeanServerConnection implements MBeanServerConnection {
+        private Subject delegationSubject;
 
-        private Subject delegationSubject;
+        public EventClient eventClient = null;
 
         public RemoteMBeanServerConnection() {
             this(null);
@@ -1205,6 +1262,7 @@
                        IOException {
 
             final boolean debug = logger.debugOn();
+
             if (debug)
                 logger.debug("addNotificationListener" +
                              "(ObjectName,NotificationListener,"+
@@ -1226,8 +1284,9 @@
         public void removeNotificationListener(ObjectName name,
                                                NotificationListener listener)
                 throws InstanceNotFoundException,
-                       ListenerNotFoundException,
-                       IOException {
+                ListenerNotFoundException,
+                IOException {
+
             final boolean debug = logger.debugOn();
 
             if (debug) logger.debug("removeNotificationListener"+
@@ -1804,6 +1863,26 @@
         terminated = false;
 
         connectionBroadcaster = new NotificationBroadcasterSupport();
+
+        lostNotifListener =
+                new NotificationListener() {
+            public void handleNotification(Notification n, Object hb) {
+                if (n != null && EventClient.NOTIFS_LOST.equals(n.getType())) {
+                    Long lost = (Long)n.getUserData();
+                    final String msg =
+                            "May have lost up to " + lost +
+                            " notification" + (lost.longValue() == 1 ? "" : "s");
+                    sendNotification(new JMXConnectionNotification(
+                            JMXConnectionNotification.NOTIFS_LOST,
+                            RMIConnector.this,
+                            connectionId,
+                            clientNotifCounter++,
+                            msg,
+                            lost));
+
+                }
+            }
+        };
     }
 
     //--------------------------------------------------------------------
@@ -2528,6 +2607,11 @@
 
     private transient ClientCommunicatorAdmin communicatorAdmin;
 
+    private boolean eventServiceEnabled;
+//    private transient EventRelay eventRelay;
+
+    private transient NotificationListener lostNotifListener;
+
     /**
      * A static WeakReference to an {@link org.omg.CORBA.ORB ORB} to
      * connect unconnected stubs.
@@ -2546,4 +2630,7 @@
     private static String strings(final String[] strs) {
         return objects(strs);
     }
+
+    private static final PerThreadGroupPool<ThreadPoolExecutor> listenerDispatchThreadPool =
+            PerThreadGroupPool.make();
 }
--- a/jdk/src/share/classes/javax/management/remote/rmi/RMIConnectorServer.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/src/share/classes/javax/management/remote/rmi/RMIConnectorServer.java	Wed Jul 05 16:40:29 2017 +0200
@@ -230,6 +230,8 @@
 
         this.address = url;
         this.rmiServerImpl = rmiServerImpl;
+
+        installStandardForwarders(this.attributes);
     }
 
     /**
@@ -380,8 +382,8 @@
 
         try {
             if (tracing) logger.trace("start", "setting default class loader");
-            defaultClassLoader =
-                EnvHelp.resolveServerClassLoader(attributes, getMBeanServer());
+            defaultClassLoader = EnvHelp.resolveServerClassLoader(
+                    attributes, getSystemMBeanServer());
         } catch (InstanceNotFoundException infc) {
             IllegalArgumentException x = new
                 IllegalArgumentException("ClassLoader not found: "+infc);
@@ -396,7 +398,7 @@
         else
             rmiServer = newServer();
 
-        rmiServer.setMBeanServer(getMBeanServer());
+        rmiServer.setMBeanServer(getSystemMBeanServer());
         rmiServer.setDefaultClassLoader(defaultClassLoader);
         rmiServer.setRMIConnectorServer(this);
         rmiServer.export();
@@ -413,7 +415,7 @@
 
                 final boolean rebind = EnvHelp.computeBooleanFromString(
                     attributes,
-                    JNDI_REBIND_ATTRIBUTE);
+                    JNDI_REBIND_ATTRIBUTE,false);
 
                 if (tracing)
                     logger.trace("start", JNDI_REBIND_ATTRIBUTE + "=" + rebind);
@@ -590,11 +592,39 @@
         return Collections.unmodifiableMap(map);
     }
 
-    public synchronized
-        void setMBeanServerForwarder(MBeanServerForwarder mbsf) {
+    @Override
+    public synchronized void setMBeanServerForwarder(MBeanServerForwarder mbsf) {
+        MBeanServer oldSMBS = getSystemMBeanServer();
         super.setMBeanServerForwarder(mbsf);
+        if (oldSMBS != getSystemMBeanServer())
+            updateMBeanServer();
+        // If the system chain of MBeanServerForwarders is not empty, then
+        // there is no need to call rmiServerImpl.setMBeanServer, because
+        // it is pointing to the head of the system chain and that has not
+        // changed.  (The *end* of the system chain will have been changed
+        // to point to mbsf.)
+    }
+
+    private void updateMBeanServer() {
         if (rmiServerImpl != null)
-            rmiServerImpl.setMBeanServer(getMBeanServer());
+            rmiServerImpl.setMBeanServer(getSystemMBeanServer());
+    }
+
+    @Override
+    public synchronized void setSystemMBeanServerForwarder(
+            MBeanServerForwarder mbsf) {
+        super.setSystemMBeanServerForwarder(mbsf);
+        updateMBeanServer();
+    }
+
+    /**
+     * {@inheritDoc}
+     * @return true, since this connector server does support a system chain
+     * of forwarders.
+     */
+    @Override
+    public boolean supportsSystemMBeanServerForwarder() {
+        return true;
     }
 
     /* We repeat the definitions of connection{Opened,Closed,Failed}
--- a/jdk/src/share/classes/sun/tools/jconsole/inspector/TableSorter.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/src/share/classes/sun/tools/jconsole/inspector/TableSorter.java	Wed Jul 05 16:40:29 2017 +0200
@@ -25,71 +25,78 @@
 
 package sun.tools.jconsole.inspector;
 
-import java.util.*;
-import java.awt.event.*;
-import javax.swing.table.*;
-import javax.swing.event.*;
 
 // Imports for picking up mouse events from the JTable.
 
-import java.awt.event.MouseAdapter;
 import java.awt.event.MouseEvent;
-import java.awt.event.InputEvent;
+import java.awt.event.MouseListener;
+import java.util.Vector;
 import javax.swing.JTable;
+import javax.swing.event.TableModelEvent;
+import javax.swing.event.TableModelListener;
+import javax.swing.table.DefaultTableModel;
 import javax.swing.table.JTableHeader;
 import javax.swing.table.TableColumnModel;
+import sun.tools.jconsole.JConsole;
 
 @SuppressWarnings("serial")
 public class TableSorter extends DefaultTableModel implements MouseListener {
     private boolean ascending = true;
     private TableColumnModel columnModel;
     private JTable tableView;
-    private Vector<TableModelListener> listenerList;
+    private Vector<TableModelListener> evtListenerList;
     private int sortColumn = 0;
 
     private int[] invertedIndex;
 
     public TableSorter() {
         super();
-        listenerList = new Vector<TableModelListener>();
+        evtListenerList = new Vector<TableModelListener>();
     }
 
     public TableSorter(Object[] columnNames, int numRows) {
         super(columnNames,numRows);
-        listenerList = new Vector<TableModelListener>();
+        evtListenerList = new Vector<TableModelListener>();
     }
 
+    @Override
     public void newDataAvailable(TableModelEvent e) {
         super.newDataAvailable(e);
         invertedIndex = new int[getRowCount()];
-        for (int i=0;i<invertedIndex.length;i++) {
+        for (int i = 0; i < invertedIndex.length; i++) {
             invertedIndex[i] = i;
         }
-        sort(this.sortColumn);
+        sort(this.sortColumn, this.ascending);
     }
 
+    @Override
     public void addTableModelListener(TableModelListener l) {
-        listenerList.add(l);
+        evtListenerList.add(l);
         super.addTableModelListener(l);
     }
 
+    @Override
     public void removeTableModelListener(TableModelListener l) {
-        listenerList.remove(l);
+        evtListenerList.remove(l);
         super.removeTableModelListener(l);
     }
 
     private void removeListeners() {
-        for(TableModelListener tnl : listenerList)
+        for(TableModelListener tnl : evtListenerList)
             super.removeTableModelListener(tnl);
     }
 
     private void restoreListeners() {
-        for(TableModelListener tnl : listenerList)
+        for(TableModelListener tnl : evtListenerList)
             super.addTableModelListener(tnl);
     }
 
     @SuppressWarnings("unchecked")
-    public int compare(Object o1, Object o2) {
+    private int compare(Object o1, Object o2) {
+        // take care of the case where both o1 & o2 are null. Needed to keep
+        // the method symetric. Without this quickSort gives surprising results.
+        if (o1 == o2)
+            return 0;
         if (o1==null)
             return 1;
         if (o2==null)
@@ -104,18 +111,40 @@
         }
     }
 
-    public void sort(int column) {
+    private void sort(int column, boolean isAscending) {
+        final XMBeanAttributes attrs =
+                (tableView instanceof XMBeanAttributes)
+                ?(XMBeanAttributes) tableView
+                :null;
+
+        // We cannot sort rows when a cell is being
+        // edited - so we're going to cancel cell editing here if needed.
+        // This might happen when the user is editing a row, and clicks on
+        // another row without validating. In that case there are two events
+        // that compete: one is the validation of the value that was previously
+        // edited, the other is the mouse click that opens the new editor.
+        //
+        // When we reach here the previous value is already validated, and the
+        // old editor is closed, but the new editor might have opened.
+        // It's this new editor that wil be cancelled here, if needed.
+        //
+        if (attrs != null && attrs.isEditing())
+            attrs.cancelCellEditing();
+
         // remove registered listeners
         removeListeners();
         // do the sort
-        //n2sort(column);
-        quickSort(0,getRowCount()-1,column);
+
+        if (JConsole.isDebug()) {
+            System.err.println("sorting table against column="+column
+                    +" ascending="+isAscending);
+        }
+        quickSort(0,getRowCount()-1,column,isAscending);
         // restore registered listeners
         restoreListeners();
-        this.sortColumn = column;
+
         // update row heights in XMBeanAttributes (required by expandable cells)
-        if (tableView instanceof XMBeanAttributes) {
-            XMBeanAttributes attrs = (XMBeanAttributes) tableView;
+        if (attrs != null) {
             for (int i = 0; i < getRowCount(); i++) {
                 Vector data = (Vector) dataVector.elementAt(i);
                 attrs.updateRowHeight(data.elementAt(1), i);
@@ -123,21 +152,21 @@
         }
     }
 
-    private synchronized boolean compareS(Object s1, Object s2) {
-        if (ascending)
+    private boolean compareS(Object s1, Object s2, boolean isAscending) {
+        if (isAscending)
             return (compare(s1,s2) > 0);
         else
             return (compare(s1,s2) < 0);
     }
 
-    private synchronized boolean compareG(Object s1, Object s2) {
-        if (ascending)
+    private boolean compareG(Object s1, Object s2, boolean isAscending) {
+        if (isAscending)
             return (compare(s1,s2) < 0);
         else
             return (compare(s1,s2) > 0);
     }
 
-    private synchronized void quickSort(int lo0,int hi0, int key) {
+    private void quickSort(int lo0,int hi0, int key, boolean isAscending) {
         int lo = lo0;
         int hi = hi0;
         Object mid;
@@ -153,14 +182,14 @@
                          * from the left Index.
                          */
                         while( ( lo < hi0 ) &&
-                               ( compareS(mid,getValueAt(lo,key)) ))
+                               ( compareS(mid,getValueAt(lo,key), isAscending) ))
                             ++lo;
 
                         /* find an element that is smaller than or equal to
                          * the partition element starting from the right Index.
                          */
                         while( ( hi > lo0 ) &&
-                               ( compareG(mid,getValueAt(hi,key)) ))
+                               ( compareG(mid,getValueAt(hi,key), isAscending) ))
                             --hi;
 
                         // if the indexes have not crossed, swap
@@ -177,27 +206,17 @@
                                  * must now sort the left partition.
                                  */
                 if( lo0 < hi )
-                    quickSort(lo0, hi , key);
+                    quickSort(lo0, hi , key, isAscending);
 
                                 /* If the left index has not reached the right
                                  * side of array
                                  * must now sort the right partition.
                                  */
                 if( lo <= hi0 )
-                    quickSort(lo, hi0 , key);
+                    quickSort(lo, hi0 , key, isAscending);
             }
     }
 
-    public void n2sort(int column) {
-        for (int i = 0; i < getRowCount(); i++) {
-            for (int j = i+1; j < getRowCount(); j++) {
-                if (compare(getValueAt(i,column),getValueAt(j,column)) == -1) {
-                    swap(i, j, column);
-                }
-            }
-        }
-    }
-
     private Vector getRow(int row) {
         return (Vector) dataVector.elementAt(row);
     }
@@ -207,7 +226,7 @@
         dataVector.setElementAt(data,row);
     }
 
-    public void swap(int i, int j, int column) {
+    private void swap(int i, int j, int column) {
         Vector data = getRow(i);
         setRow(getRow(j),i);
         setRow(data,j);
@@ -223,11 +242,12 @@
 
     public void sortByColumn(int column, boolean ascending) {
         this.ascending = ascending;
-        sort(column);
+        this.sortColumn = column;
+        sort(column,ascending);
     }
 
-    public int[] getInvertedIndex() {
-        return invertedIndex;
+    public int getIndexOfRow(int row) {
+        return invertedIndex[row];
     }
 
     // Add a mouse listener to the Table to trigger a table sort
@@ -243,6 +263,14 @@
         int viewColumn = columnModel.getColumnIndexAtX(e.getX());
         int column = tableView.convertColumnIndexToModel(viewColumn);
         if (e.getClickCount() == 1 && column != -1) {
+            if (tableView instanceof XTable) {
+                XTable attrs = (XTable) tableView;
+                // inform the table view that the rows are going to be sorted
+                // against the values in a given column. This gives the
+                // chance to the table view to close its editor - if needed.
+                //
+                attrs.sortRequested(column);
+            }
             tableView.invalidate();
             sortByColumn(column);
             tableView.validate();
--- a/jdk/src/share/classes/sun/tools/jconsole/inspector/XMBeanAttributes.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/src/share/classes/sun/tools/jconsole/inspector/XMBeanAttributes.java	Wed Jul 05 16:40:29 2017 +0200
@@ -25,31 +25,49 @@
 
 package sun.tools.jconsole.inspector;
 
-import javax.swing.*;
-import javax.swing.event.*;
-import javax.swing.table.*;
-import javax.swing.tree.*;
-import java.awt.BorderLayout;
-import java.awt.Color;
-import java.awt.GridLayout;
-import java.awt.FlowLayout;
+
 import java.awt.Component;
 import java.awt.EventQueue;
-import java.awt.event.*;
-import java.awt.Insets;
 import java.awt.Dimension;
-import java.util.*;
-import java.io.*;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.io.IOException;
 
 import java.lang.reflect.Array;
 
-import javax.management.*;
+import java.util.EventObject;
+import java.util.HashMap;
+import java.util.WeakHashMap;
+
+import java.util.concurrent.ExecutionException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.management.JMException;
+import javax.management.MBeanInfo;
+import javax.management.MBeanAttributeInfo;
+import javax.management.AttributeList;
+import javax.management.Attribute;
 import javax.management.openmbean.CompositeData;
 import javax.management.openmbean.TabularData;
 
+import javax.swing.JComponent;
+import javax.swing.JOptionPane;
+import javax.swing.JTable;
+import javax.swing.JTextField;
+import javax.swing.SwingWorker;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.TableModelEvent;
+import javax.swing.event.TableModelListener;
+import javax.swing.table.DefaultTableCellRenderer;
+import javax.swing.table.DefaultTableModel;
+import javax.swing.table.TableCellEditor;
+import javax.swing.table.TableCellRenderer;
+import javax.swing.table.TableColumn;
+import javax.swing.table.TableColumnModel;
+import javax.swing.table.TableModel;
+
 import sun.tools.jconsole.Resources;
 import sun.tools.jconsole.MBeansTab;
-import sun.tools.jconsole.Plotter;
 import sun.tools.jconsole.JConsole;
 import sun.tools.jconsole.ProxyClient.SnapshotMBeanServerConnection;
 
@@ -61,12 +79,14 @@
   COMPULSORY to not call the JMX world in synchronized blocks */
 @SuppressWarnings("serial")
 public class XMBeanAttributes extends XTable {
+
+    final Logger LOGGER =
+            Logger.getLogger(XMBeanAttributes.class.getPackage().getName());
+
     private final static String[] columnNames =
     {Resources.getText("Name"),
      Resources.getText("Value")};
 
-    private boolean editable = true;
-
     private XMBean mbean;
     private MBeanInfo mbeanInfo;
     private MBeanAttributeInfo[] attributesInfo;
@@ -75,9 +95,8 @@
     private HashMap<String, Object> viewableAttributes;
     private WeakHashMap<XMBean, HashMap<String, ZoomedCell>> viewersCache =
             new WeakHashMap<XMBean, HashMap<String, ZoomedCell>>();
-    private TableModelListener attributesListener;
+    private final TableModelListener attributesListener;
     private MBeansTab mbeansTab;
-    private XTable table;
     private TableCellEditor valueCellEditor = new ValueCellEditor();
     private int rowMinHeight = -1;
     private AttributesMouseListener mouseListener = new AttributesMouseListener();
@@ -89,8 +108,8 @@
         super();
         this.mbeansTab = mbeansTab;
         ((DefaultTableModel)getModel()).setColumnIdentifiers(columnNames);
-        getModel().addTableModelListener(attributesListener =
-                                         new AttributesListener(this));
+        attributesListener = new AttributesListener(this);
+        getModel().addTableModelListener(attributesListener);
         getColumnModel().getColumn(NAME_COLUMN).setPreferredWidth(40);
 
         addMouseListener(mouseListener);
@@ -99,6 +118,7 @@
         addKeyListener(new Utils.CopyKeyAdapter());
     }
 
+    @Override
     public synchronized Component prepareRenderer(TableCellRenderer renderer,
                                                   int row, int column) {
         //In case we have a repaint thread that is in the process of
@@ -124,6 +144,7 @@
                 setRowHeight(row, rowMinHeight);
     }
 
+    @Override
     public synchronized TableCellRenderer getCellRenderer(int row,
             int column) {
         //In case we have a repaint thread that is in the process of
@@ -169,26 +190,40 @@
     }
 
     public void cancelCellEditing() {
-        TableCellEditor editor = getCellEditor();
-        if (editor != null) {
-            editor.cancelCellEditing();
+        if (LOGGER.isLoggable(Level.FINER)) {
+            LOGGER.finer("Cancel Editing Row: "+getEditingRow());
+        }
+        final TableCellEditor tableCellEditor = getCellEditor();
+        if (tableCellEditor != null) {
+            tableCellEditor.cancelCellEditing();
         }
     }
 
     public void stopCellEditing() {
-        TableCellEditor editor = getCellEditor();
-        if (editor != null) {
-            editor.stopCellEditing();
+        if (LOGGER.isLoggable(Level.FINER)) {
+            LOGGER.finer("Stop Editing Row: "+getEditingRow());
+        }
+        final TableCellEditor tableCellEditor = getCellEditor();
+        if (tableCellEditor != null) {
+            tableCellEditor.stopCellEditing();
         }
     }
 
-    public final boolean editCellAt(int row, int column, EventObject e) {
+    @Override
+    public final boolean editCellAt(final int row, final int column, EventObject e) {
+        if (LOGGER.isLoggable(Level.FINER)) {
+            LOGGER.finer("editCellAt(row="+row+", col="+column+
+                    ", e="+e+")");
+        }
+        if (JConsole.isDebug()) {
+            System.err.println("edit: "+getValueName(row)+"="+getValue(row));
+        }
         boolean retVal = super.editCellAt(row, column, e);
         if (retVal) {
-            TableCellEditor editor =
+            final TableCellEditor tableCellEditor =
                     getColumnModel().getColumn(column).getCellEditor();
-            if (editor == valueCellEditor) {
-                ((JComponent) editor).requestFocus();
+            if (tableCellEditor == valueCellEditor) {
+                ((JComponent) tableCellEditor).requestFocus();
             }
         }
         return retVal;
@@ -213,6 +248,10 @@
     public void setValueAt(Object value, int row, int column) {
         if (!isCellError(row, column) && isColumnEditable(column) &&
             isWritable(row) && Utils.isEditableType(getClassName(row))) {
+            if (JConsole.isDebug()) {
+                System.err.println("validating [row="+row+", column="+column+
+                        "]: "+getValueName(row)+"="+value);
+            }
             super.setValueAt(value, row, column);
         }
     }
@@ -256,12 +295,14 @@
         }
     }
 
-
     public Object getValue(int row) {
-        return ((DefaultTableModel) getModel()).getValueAt(row, VALUE_COLUMN);
+        final Object val = ((DefaultTableModel) getModel())
+                .getValueAt(row, VALUE_COLUMN);
+        return val;
     }
 
     //tool tip only for editable column
+    @Override
     public String getToolTip(int row, int column) {
         if (isCellError(row, column)) {
             return (String) unavailableAttributes.get(getValueName(row));
@@ -302,6 +343,7 @@
      * Override JTable method in order to make any call to this method
      * atomic with TableModel elements.
      */
+    @Override
     public synchronized int getRowCount() {
         return super.getRowCount();
     }
@@ -332,24 +374,67 @@
         return isViewable;
     }
 
-    public void loadAttributes(final XMBean mbean, MBeanInfo mbeanInfo) {
+    // Call this in EDT
+    public void loadAttributes(final XMBean mbean, final MBeanInfo mbeanInfo) {
+
+        final SwingWorker<Runnable,Void> load =
+                new SwingWorker<Runnable,Void>() {
+            @Override
+            protected Runnable doInBackground() throws Exception {
+                return doLoadAttributes(mbean,mbeanInfo);
+            }
+
+            @Override
+            protected void done() {
+                try {
+                    final Runnable updateUI = get();
+                    if (updateUI != null) updateUI.run();
+                } catch (RuntimeException x) {
+                    throw x;
+                } catch (ExecutionException x) {
+                    if(JConsole.isDebug()) {
+                       System.err.println(
+                               "Exception raised while loading attributes: "
+                               +x.getCause());
+                       x.printStackTrace();
+                    }
+                } catch (InterruptedException x) {
+                    if(JConsole.isDebug()) {
+                       System.err.println(
+                            "Interrupted while loading attributes: "+x);
+                       x.printStackTrace();
+                    }
+                }
+            }
+
+        };
+        mbeansTab.workerAdd(load);
+    }
+
+    // Don't call this in EDT, but execute returned Runnable inside
+    // EDT - typically in the done() method of a SwingWorker
+    // This method can return null.
+    private Runnable doLoadAttributes(final XMBean mbean, MBeanInfo infoOrNull)
+        throws JMException, IOException {
         // To avoid deadlock with events coming from the JMX side,
         // we retrieve all JMX stuff in a non synchronized block.
 
-        if(mbean == null) return;
+        if(mbean == null) return null;
+        final MBeanInfo curMBeanInfo =
+                (infoOrNull==null)?mbean.getMBeanInfo():infoOrNull;
 
-        final MBeanAttributeInfo[] attributesInfo = mbeanInfo.getAttributes();
-        final HashMap<String, Object> attributes =
-            new HashMap<String, Object>(attributesInfo.length);
-        final HashMap<String, Object> unavailableAttributes =
-            new HashMap<String, Object>(attributesInfo.length);
-        final HashMap<String, Object> viewableAttributes =
-            new HashMap<String, Object>(attributesInfo.length);
+        final MBeanAttributeInfo[] attrsInfo = curMBeanInfo.getAttributes();
+        final HashMap<String, Object> attrs =
+            new HashMap<String, Object>(attrsInfo.length);
+        final HashMap<String, Object> unavailableAttrs =
+            new HashMap<String, Object>(attrsInfo.length);
+        final HashMap<String, Object> viewableAttrs =
+            new HashMap<String, Object>(attrsInfo.length);
         AttributeList list = null;
 
         try {
-            list = mbean.getAttributes(attributesInfo);
-        } catch (Exception e) {
+            list = mbean.getAttributes(attrsInfo);
+        }catch(Exception e) {
             if (JConsole.isDebug()) {
                 System.err.println("Error calling getAttributes() on MBean \"" +
                                    mbean.getObjectName() + "\". JConsole will " +
@@ -359,18 +444,18 @@
             }
             list = new AttributeList();
             //Can't load all attributes, do it one after each other.
-            for(int i = 0; i < attributesInfo.length; i++) {
+            for(int i = 0; i < attrsInfo.length; i++) {
                 String name = null;
                 try {
-                    name = attributesInfo[i].getName();
+                    name = attrsInfo[i].getName();
                     Object value =
-                        mbean.getMBeanServerConnection().getAttribute(mbean.getObjectName(), name);
+                        mbean.getMBeanServerConnection().
+                        getAttribute(mbean.getObjectName(), name);
                     list.add(new Attribute(name, value));
                 }catch(Exception ex) {
-                    if(attributesInfo[i].isReadable()) {
-                        unavailableAttributes.put(name,
-                                                  Utils.getActualException(ex).
-                                                  toString());
+                    if(attrsInfo[i].isReadable()) {
+                        unavailableAttrs.put(name,
+                                Utils.getActualException(ex).toString());
                     }
                 }
             }
@@ -380,22 +465,22 @@
             for (int i=0;i<att_length;i++) {
                 Attribute attribute = (Attribute) list.get(i);
                 if(isViewable(attribute)) {
-                    viewableAttributes.put(attribute.getName(),
+                    viewableAttrs.put(attribute.getName(),
                                            attribute.getValue());
                 }
                 else
-                    attributes.put(attribute.getName(),attribute.getValue());
+                    attrs.put(attribute.getName(),attribute.getValue());
 
             }
             // if not all attributes are accessible,
             // check them one after the other.
-            if (att_length < attributesInfo.length) {
-                for (int i=0;i<attributesInfo.length;i++) {
-                    MBeanAttributeInfo attributeInfo = attributesInfo[i];
-                    if (!attributes.containsKey(attributeInfo.getName()) &&
-                        !viewableAttributes.containsKey(attributeInfo.
+            if (att_length < attrsInfo.length) {
+                for (int i=0;i<attrsInfo.length;i++) {
+                    MBeanAttributeInfo attributeInfo = attrsInfo[i];
+                    if (!attrs.containsKey(attributeInfo.getName()) &&
+                        !viewableAttrs.containsKey(attributeInfo.
                                                         getName()) &&
-                        !unavailableAttributes.containsKey(attributeInfo.
+                        !unavailableAttrs.containsKey(attributeInfo.
                                                            getName())) {
                         if (attributeInfo.isReadable()) {
                             // getAttributes didn't help resolving the
@@ -408,16 +493,13 @@
                                     mbean.getObjectName(), attributeInfo.getName());
                                 //What happens if now it is ok?
                                 // Be pragmatic, add it to readable...
-                                attributes.put(attributeInfo.getName(),
+                                attrs.put(attributeInfo.getName(),
                                                v);
                             }catch(Exception e) {
                                 //Put the exception that will be displayed
                                 // in tooltip
-                                unavailableAttributes.put(attributeInfo.
-                                                          getName(),
-                                                          Utils.
-                                                          getActualException(e)
-                                                          .toString());
+                                unavailableAttrs.put(attributeInfo.getName(),
+                                        Utils.getActualException(e).toString());
                             }
                         }
                     }
@@ -426,10 +508,10 @@
         }
         catch(Exception e) {
             //sets all attributes unavailable except the writable ones
-            for (int i=0;i<attributesInfo.length;i++) {
-                MBeanAttributeInfo attributeInfo = attributesInfo[i];
+            for (int i=0;i<attrsInfo.length;i++) {
+                MBeanAttributeInfo attributeInfo = attrsInfo[i];
                 if (attributeInfo.isReadable()) {
-                    unavailableAttributes.put(attributeInfo.getName(),
+                    unavailableAttrs.put(attributeInfo.getName(),
                                               Utils.getActualException(e).
                                               toString());
                 }
@@ -438,40 +520,36 @@
         //end of retrieval
 
         //one update at a time
-        synchronized(this) {
+        return new Runnable() {
+            public void run() {
+                synchronized (XMBeanAttributes.this) {
+                    XMBeanAttributes.this.mbean = mbean;
+                    XMBeanAttributes.this.mbeanInfo = curMBeanInfo;
+                    XMBeanAttributes.this.attributesInfo = attrsInfo;
+                    XMBeanAttributes.this.attributes = attrs;
+                    XMBeanAttributes.this.unavailableAttributes = unavailableAttrs;
+                    XMBeanAttributes.this.viewableAttributes = viewableAttrs;
 
-            this.mbean = mbean;
-            this.mbeanInfo = mbeanInfo;
-            this.attributesInfo = attributesInfo;
-            this.attributes = attributes;
-            this.unavailableAttributes = unavailableAttributes;
-            this.viewableAttributes = viewableAttributes;
-
-            EventQueue.invokeLater(new Runnable() {
-                public void run() {
                     DefaultTableModel tableModel =
                             (DefaultTableModel) getModel();
 
-                    // don't listen to these events
-                    tableModel.removeTableModelListener(attributesListener);
-
                     // add attribute information
-                    emptyTable();
+                    emptyTable(tableModel);
 
                     addTableData(tableModel,
-                                 mbean,
-                                 attributesInfo,
-                                 attributes,
-                                 unavailableAttributes,
-                                 viewableAttributes);
+                            mbean,
+                            attrsInfo,
+                            attrs,
+                            unavailableAttrs,
+                            viewableAttrs);
 
                     // update the model with the new data
                     tableModel.newDataAvailable(new TableModelEvent(tableModel));
                     // re-register for change events
                     tableModel.addTableModelListener(attributesListener);
                 }
-            });
-        }
+            }
+        };
     }
 
     void collapse(String attributeName, final Component c) {
@@ -534,22 +612,80 @@
         return cell;
     }
 
-     public void refreshAttributes() {
-         SnapshotMBeanServerConnection mbsc = mbeansTab.getSnapshotMBeanServerConnection();
-         mbsc.flush();
-         stopCellEditing();
-         loadAttributes(mbean, mbeanInfo);
+    // This is called by XSheet when the "refresh" button is pressed.
+    // In this case we will commit any pending attribute values by
+    // calling 'stopCellEditing'.
+    //
+    public void refreshAttributes() {
+         refreshAttributes(true);
+    }
+
+    // refreshAttributes(false) is called by tableChanged().
+    // in this case we must not call stopCellEditing, because it's already
+    // been called - e.g.
+    // lostFocus/mousePressed -> stopCellEditing -> setValueAt -> tableChanged
+    //                        -> refreshAttributes(false)
+    //
+    // Can be called in EDT - as long as the implementation of
+    // mbeansTab.getCachedMBeanServerConnection() and mbsc.flush() doesn't
+    // change
+    //
+    private void refreshAttributes(final boolean stopCellEditing) {
+         SwingWorker<Void,Void> sw = new SwingWorker<Void,Void>() {
+
+            @Override
+            protected Void doInBackground() throws Exception {
+                SnapshotMBeanServerConnection mbsc =
+                mbeansTab.getSnapshotMBeanServerConnection();
+                mbsc.flush();
+                return null;
+            }
+
+            @Override
+            protected void done() {
+                try {
+                    get();
+                    if (stopCellEditing) stopCellEditing();
+                    loadAttributes(mbean, mbeanInfo);
+                } catch (Exception x) {
+                    if (JConsole.isDebug()) {
+                        x.printStackTrace();
+                    }
+                }
+            }
+         };
+         mbeansTab.workerAdd(sw);
      }
+    // We need to call stop editing here - otherwise edits are lost
+    // when resizing the table.
+    //
+    @Override
+    public void columnMarginChanged(ChangeEvent e) {
+        if (isEditing()) stopCellEditing();
+        super.columnMarginChanged(e);
+    }
+
+    // We need to call stop editing here - otherwise the edited value
+    // is transferred to the wrong row...
+    //
+    @Override
+    void sortRequested(int column) {
+        if (isEditing()) stopCellEditing();
+        super.sortRequested(column);
+    }
 
 
-     public void emptyTable() {
-         synchronized(this) {
-             ((DefaultTableModel) getModel()).
-                 removeTableModelListener(attributesListener);
-             super.emptyTable();
-         }
+    @Override
+    public synchronized void emptyTable() {
+         emptyTable((DefaultTableModel)getModel());
      }
 
+    // Call this in synchronized block.
+    private void emptyTable(DefaultTableModel model) {
+         model.removeTableModelListener(attributesListener);
+         super.emptyTable();
+    }
+
     private boolean isViewable(Attribute attribute) {
         Object data = attribute.getValue();
         return XDataViewer.isViewableValue(data);
@@ -659,6 +795,7 @@
 
     class AttributesMouseListener extends MouseAdapter {
 
+        @Override
         public void mousePressed(MouseEvent e) {
             if(e.getButton() == MouseEvent.BUTTON1) {
                 if(e.getClickCount() >= 2) {
@@ -674,8 +811,10 @@
         }
     }
 
+    @SuppressWarnings("serial")
     class ValueCellEditor extends XTextFieldEditor {
         // implements javax.swing.table.TableCellEditor
+        @Override
         public Component getTableCellEditorComponent(JTable table,
                                                      Object value,
                                                      boolean isSelected,
@@ -727,6 +866,7 @@
         }
     }
 
+    @SuppressWarnings("serial")
     class MaximizedCellRenderer extends  DefaultTableCellRenderer {
         Component comp;
         MaximizedCellRenderer(Component comp) {
@@ -736,6 +876,7 @@
                 comp.setPreferredSize(new Dimension((int) d.getWidth(), 200));
             }
         }
+        @Override
         public Component getTableCellRendererComponent(JTable table,
                                                        Object value,
                                                        boolean isSelected,
@@ -818,6 +959,7 @@
             return minHeight;
         }
 
+        @Override
         public String toString() {
 
             if(value == null) return null;
@@ -854,45 +996,82 @@
             this.component = component;
         }
 
+        // Call this in EDT
         public void tableChanged(final TableModelEvent e) {
-            final TableModel model = (TableModel)e.getSource();
             // only post changes to the draggable column
             if (isColumnEditable(e.getColumn())) {
-                mbeansTab.workerAdd(new Runnable() {
-                        public void run() {
-                            try {
-                                Object tableValue =
-                                    model.getValueAt(e.getFirstRow(),
-                                                     e.getColumn());
-                                // if it's a String, try construct new value
-                                // using the defined type.
-                                if (tableValue instanceof String) {
-                                    tableValue =
-                                        Utils.createObjectFromString(getClassName(e.getFirstRow()), // type
-                                                                     (String)tableValue);// value
-                                }
-                                String attributeName =
-                                    getValueName(e.getFirstRow());
-                                Attribute attribute =
-                                    new Attribute(attributeName,tableValue);
-                                mbean.setAttribute(attribute);
-                            }
-                            catch (Throwable ex) {
-                                if (JConsole.isDebug()) {
-                                    ex.printStackTrace();
-                                }
-                                ex = Utils.getActualException(ex);
+                final TableModel model = (TableModel)e.getSource();
+                Object tableValue = model.getValueAt(e.getFirstRow(),
+                                                 e.getColumn());
+
+                if (LOGGER.isLoggable(Level.FINER)) {
+                    LOGGER.finer("tableChanged: firstRow="+e.getFirstRow()+
+                        ", lastRow="+e.getLastRow()+", column="+e.getColumn()+
+                        ", value="+tableValue);
+                }
+                // if it's a String, try construct new value
+                // using the defined type.
+                if (tableValue instanceof String) {
+                    try {
+                        tableValue =
+                            Utils.createObjectFromString(getClassName(e.getFirstRow()), // type
+                            (String)tableValue);// value
+                    } catch (Throwable ex) {
+                        popupAndLog(ex,"tableChanged",
+                                "Problem setting attribute");
+                    }
+                }
+                final String attributeName = getValueName(e.getFirstRow());
+                final Attribute attribute =
+                      new Attribute(attributeName,tableValue);
+                setAttribute(attribute, "tableChanged");
+            }
+        }
 
-                                String message = (ex.getMessage() != null) ? ex.getMessage() : ex.toString();
-                                EventQueue.invokeLater(new ThreadDialog(component,
-                                                                        message+"\n",
-                                                                        Resources.getText("Problem setting attribute"),
-                                                                        JOptionPane.ERROR_MESSAGE));
-                            }
-                            refreshAttributes();
+        // Call this in EDT
+        private void setAttribute(final Attribute attribute, final String method) {
+            final SwingWorker<Void,Void> setAttribute =
+                    new SwingWorker<Void,Void>() {
+                @Override
+                protected Void doInBackground() throws Exception {
+                    try {
+                        if (JConsole.isDebug()) {
+                            System.err.println("setAttribute("+
+                                    attribute.getName()+
+                                "="+attribute.getValue()+")");
                         }
-                    });
-            }
+                        mbean.setAttribute(attribute);
+                    } catch (Throwable ex) {
+                        popupAndLog(ex,method,"Problem setting attribute");
+                    }
+                    return null;
+                }
+                @Override
+                protected void done() {
+                    try {
+                        get();
+                    } catch (Exception x) {
+                        if (JConsole.isDebug())
+                            x.printStackTrace();
+                    }
+                    refreshAttributes(false);
+                }
+
+            };
+            mbeansTab.workerAdd(setAttribute);
+        }
+
+        // Call this outside EDT
+        private void popupAndLog(Throwable ex, String method, String key) {
+            ex = Utils.getActualException(ex);
+            if (JConsole.isDebug()) ex.printStackTrace();
+
+            String message = (ex.getMessage() != null) ? ex.getMessage()
+                    : ex.toString();
+            EventQueue.invokeLater(
+                    new ThreadDialog(component, message+"\n",
+                                     Resources.getText(key),
+                                     JOptionPane.ERROR_MESSAGE));
         }
     }
 }
--- a/jdk/src/share/classes/sun/tools/jconsole/inspector/XPlotter.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/src/share/classes/sun/tools/jconsole/inspector/XPlotter.java	Wed Jul 05 16:40:29 2017 +0200
@@ -37,6 +37,7 @@
         super(unit);
         this.table = table;
     }
+    @Override
     public void addValues(long time, long... values) {
         super.addValues(time, values);
         table.repaint();
--- a/jdk/src/share/classes/sun/tools/jconsole/inspector/XSheet.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/src/share/classes/sun/tools/jconsole/inspector/XSheet.java	Wed Jul 05 16:40:29 2017 +0200
@@ -25,18 +25,39 @@
 
 package sun.tools.jconsole.inspector;
 
-import java.awt.*;
-import java.awt.event.*;
-import java.io.*;
-import javax.management.*;
-import javax.swing.*;
-import javax.swing.border.*;
-import javax.swing.tree.*;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.IOException;
+
+import javax.management.IntrospectionException;
+import javax.management.NotificationListener;
+import javax.management.MBeanInfo;
+import javax.management.InstanceNotFoundException;
+import javax.management.ReflectionException;
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanOperationInfo;
+import javax.management.MBeanNotificationInfo;
+import javax.management.Notification;
+import javax.swing.BorderFactory;
+import javax.swing.JButton;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+import javax.swing.SwingWorker;
+import javax.swing.border.LineBorder;
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.DefaultTreeModel;
+
 import sun.tools.jconsole.*;
 import sun.tools.jconsole.inspector.XNodeInfo.Type;
 
 import static sun.tools.jconsole.Resources.*;
-import static sun.tools.jconsole.Utilities.*;
 
 @SuppressWarnings("serial")
 public class XSheet extends JPanel
@@ -344,34 +365,41 @@
             return;
         }
         mbean = (XMBean) uo.getData();
-        SwingWorker<Void, Void> sw = new SwingWorker<Void, Void>() {
+        final XMBean xmb = mbean;
+        SwingWorker<MBeanInfo,Void> sw = new SwingWorker<MBeanInfo,Void>() {
             @Override
-            public Void doInBackground() throws InstanceNotFoundException,
+            public MBeanInfo doInBackground() throws InstanceNotFoundException,
                     IntrospectionException, ReflectionException, IOException {
-                mbeanAttributes.loadAttributes(mbean, mbean.getMBeanInfo());
-                return null;
+                MBeanInfo mbi = xmb.getMBeanInfo();
+                return mbi;
             }
             @Override
             protected void done() {
                 try {
-                    get();
-                    if (!isSelectedNode(node, currentNode)) {
-                        return;
+                    MBeanInfo mbi = get();
+                    if (mbi != null && mbi.getAttributes() != null &&
+                            mbi.getAttributes().length > 0) {
+
+                        mbeanAttributes.loadAttributes(xmb, mbi);
+
+                        if (!isSelectedNode(node, currentNode)) {
+                            return;
+                        }
+                        invalidate();
+                        mainPanel.removeAll();
+                        JPanel borderPanel = new JPanel(new BorderLayout());
+                        borderPanel.setBorder(BorderFactory.createTitledBorder(
+                                Resources.getText("Attribute values")));
+                        borderPanel.add(new JScrollPane(mbeanAttributes));
+                        mainPanel.add(borderPanel, BorderLayout.CENTER);
+                        // add the refresh button to the south panel
+                        southPanel.removeAll();
+                        southPanel.add(refreshButton, BorderLayout.SOUTH);
+                        southPanel.setVisible(true);
+                        refreshButton.setEnabled(true);
+                        validate();
+                        repaint();
                     }
-                    invalidate();
-                    mainPanel.removeAll();
-                    JPanel borderPanel = new JPanel(new BorderLayout());
-                    borderPanel.setBorder(BorderFactory.createTitledBorder(
-                            Resources.getText("Attribute values")));
-                    borderPanel.add(new JScrollPane(mbeanAttributes));
-                    mainPanel.add(borderPanel, BorderLayout.CENTER);
-                    // add the refresh button to the south panel
-                    southPanel.removeAll();
-                    southPanel.add(refreshButton, BorderLayout.SOUTH);
-                    southPanel.setVisible(true);
-                    refreshButton.setEnabled(true);
-                    validate();
-                    repaint();
                 } catch (Exception e) {
                     Throwable t = Utils.getActualException(e);
                     if (JConsole.isDebug()) {
@@ -704,13 +732,7 @@
             JButton button = (JButton) e.getSource();
             // Refresh button
             if (button == refreshButton) {
-                new SwingWorker<Void, Void>() {
-                    @Override
-                    public Void doInBackground() {
-                        refreshAttributes();
-                        return null;
-                    }
-                }.execute();
+                refreshAttributes();
                 return;
             }
             // Clear button
--- a/jdk/src/share/classes/sun/tools/jconsole/inspector/XTable.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/src/share/classes/sun/tools/jconsole/inspector/XTable.java	Wed Jul 05 16:40:29 2017 +0200
@@ -25,10 +25,13 @@
 
 package sun.tools.jconsole.inspector;
 
-import javax.swing.*;
-import javax.swing.table.*;
-import java.awt.*;
-import java.io.*;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Font;
+import javax.swing.JTable;
+import javax.swing.table.DefaultTableCellRenderer;
+import javax.swing.table.DefaultTableModel;
+import javax.swing.table.TableCellRenderer;
 
 public abstract class XTable extends JTable {
     static final int NAME_COLUMN = 0;
@@ -38,8 +41,9 @@
 
     public XTable () {
         super();
-        TableSorter sorter;
-        setModel(sorter = new TableSorter());
+        @SuppressWarnings("serial")
+        final TableSorter sorter = new TableSorter();
+        setModel(sorter);
         sorter.addMouseListenerToHeaderInTable(this);
         setRowSelectionAllowed(false);
         setColumnSelectionAllowed(false);
@@ -55,6 +59,14 @@
     }
 
     /**
+     * Called by TableSorter if a mouse event requests to sort the rows.
+     * @param column the column against which the rows are sorted
+     */
+    void sortRequested(int column) {
+        // This is a hook for subclasses
+    }
+
+    /**
      * This returns the select index as the table was at initialization
      */
     public int getSelectedIndex() {
@@ -67,7 +79,7 @@
     public int convertRowToIndex(int row) {
         if (row == -1) return row;
         if (getModel() instanceof TableSorter) {
-            return (((TableSorter) getModel()).getInvertedIndex()[row]);
+            return ((TableSorter) getModel()).getIndexOfRow(row);
         } else {
             return row;
         }
@@ -97,6 +109,7 @@
     //JTable re-implementation
 
     //attribute can be editable even if unavailable
+    @Override
     public boolean isCellEditable(int row, int col) {
         return ((isTableEditable() && isColumnEditable(col)
                  &&  isWritable(row)
@@ -118,6 +131,7 @@
      * This method sets read write rows to be blue, and other rows to be their
      * default rendered colour.
      */
+    @Override
     public TableCellRenderer getCellRenderer(int row, int column) {
         DefaultTableCellRenderer tcr =
             (DefaultTableCellRenderer) super.getCellRenderer(row,column);
@@ -146,6 +160,7 @@
         return tcr;
     }
 
+    @Override
     public Component prepareRenderer(TableCellRenderer renderer,
                                      int row, int column) {
         Component comp = super.prepareRenderer(renderer, row, column);
--- a/jdk/src/share/classes/sun/tools/jconsole/inspector/XTextFieldEditor.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/src/share/classes/sun/tools/jconsole/inspector/XTextFieldEditor.java	Wed Jul 05 16:40:29 2017 +0200
@@ -26,22 +26,30 @@
 package sun.tools.jconsole.inspector;
 
 import java.awt.Component;
+import java.awt.event.ActionEvent;
+import java.awt.event.FocusAdapter;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
 import java.util.EventObject;
-import java.awt.event.*;
-import java.awt.dnd.DragSourceDropEvent;
-import javax.swing.*;
-import javax.swing.event.*;
-import javax.swing.table.*;
+import javax.swing.JMenuItem;
+import javax.swing.JTable;
+import javax.swing.JTextField;
+import javax.swing.event.CellEditorListener;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.EventListenerList;
+import javax.swing.table.TableCellEditor;
 
 @SuppressWarnings("serial")
 public class XTextFieldEditor extends XTextField implements TableCellEditor {
 
-    protected EventListenerList listenerList = new EventListenerList();
+    protected EventListenerList evtListenerList = new EventListenerList();
     protected ChangeEvent changeEvent = new ChangeEvent(this);
 
     private FocusListener editorFocusListener = new FocusAdapter() {
+        @Override
         public void focusLost(FocusEvent e) {
-            fireEditingStopped();
+            // fireEditingStopped();
+            // must not call fireEditingStopped() here!
         }
     };
 
@@ -51,6 +59,7 @@
     }
 
     //edition stopped ou JMenuItem selection & JTextField selection
+    @Override
     public void  actionPerformed(ActionEvent e) {
         super.actionPerformed(e);
         if ((e.getSource() instanceof JMenuItem) ||
@@ -67,16 +76,16 @@
     //TableCellEditor implementation
 
     public void addCellEditorListener(CellEditorListener listener) {
-        listenerList.add(CellEditorListener.class,listener);
+        evtListenerList.add(CellEditorListener.class,listener);
     }
 
     public void removeCellEditorListener(CellEditorListener listener) {
-        listenerList.remove(CellEditorListener.class, listener);
+        evtListenerList.remove(CellEditorListener.class, listener);
     }
 
     protected void fireEditingStopped() {
         CellEditorListener listener;
-        Object[] listeners = listenerList.getListenerList();
+        Object[] listeners = evtListenerList.getListenerList();
         for (int i=0;i< listeners.length;i++) {
             if (listeners[i] == CellEditorListener.class) {
                 listener = (CellEditorListener) listeners[i+1];
@@ -87,7 +96,7 @@
 
     protected void fireEditingCanceled() {
         CellEditorListener listener;
-        Object[] listeners = listenerList.getListenerList();
+        Object[] listeners = evtListenerList.getListenerList();
         for (int i=0;i< listeners.length;i++) {
             if (listeners[i] == CellEditorListener.class) {
                 listener = (CellEditorListener) listeners[i+1];
--- a/jdk/test/com/sun/jdi/Solaris32AndSolaris64Test.sh	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/test/com/sun/jdi/Solaris32AndSolaris64Test.sh	Wed Jul 05 16:40:29 2017 +0200
@@ -25,7 +25,7 @@
 
 #
 #   @test       Solaris32AndSolaris64Test.sh
-#   @bug        4478312 4780570 4913748
+#   @bug        4478312 4780570 4913748 6730273
 #   @summary    Test debugging with mixed 32/64bit VMs.
 #   @author     Tim Bell
 #   Based on test/java/awt/TEMPLATE/AutomaticShellTest.sh
@@ -177,8 +177,14 @@
 if [ ! -r ${filename} ] ; then
     filename=$TESTCLASSES/../@debuggeeVMOptions
 fi
+# Remove -d32, -d64 if present, and remove -XX:[+-]UseCompressedOops 
+# if present since it is illegal in 32 bit mode.
 if [ -r ${filename} ] ; then
-    DEBUGGEEFLAGS=`cat ${filename} | sed -e 's/-d32//g' -e 's/-d64//g'`
+    DEBUGGEEFLAGS=`cat ${filename} | sed \
+                        -e 's/-d32//g' \
+                        -e 's/-d64//g' \
+                        -e 's/-XX:.UseCompressedOops//g' \
+                        `
 fi
 
 #
--- a/jdk/test/java/lang/management/ManagementFactory/ThreadMXBeanProxy.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/test/java/lang/management/ManagementFactory/ThreadMXBeanProxy.java	Wed Jul 05 16:40:29 2017 +0200
@@ -60,8 +60,8 @@
         thread.setDaemon(true);
         thread.start();
 
-        // wait until myThread acquires mutex
-        while (!mutex.isLocked()) {
+        // wait until myThread acquires mutex and lock owner is set.
+        while (!(mutex.isLocked() && mutex.getLockOwner() == thread)) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
@@ -73,17 +73,17 @@
 
         // validate the local access
         ThreadInfo[] infos = getThreadMXBean().getThreadInfo(ids, true, true);
-        if (ids.length != 1) {
+        if (infos.length != 1) {
             throw new RuntimeException("Returned ThreadInfo[] of length=" +
-                ids.length + ". Expected to be 1.");
+                infos.length + ". Expected to be 1.");
         }
         thread.checkThreadInfo(infos[0]);
 
         // validate the remote access
         infos = mbean.getThreadInfo(ids, true, true);
-        if (ids.length != 1) {
+        if (infos.length != 1) {
             throw new RuntimeException("Returned ThreadInfo[] of length=" +
-                ids.length + ". Expected to be 1.");
+                infos.length + ". Expected to be 1.");
         }
         thread.checkThreadInfo(infos[0]);
 
@@ -160,8 +160,7 @@
             LockInfo[] syncs = info.getLockedSynchronizers();
             if (syncs.length != OWNED_SYNCS) {
                 throw new RuntimeException("Number of locked syncs = " +
-                    syncs.length +
-                    " not matched. Expected: " + OWNED_SYNCS);
+                        syncs.length + " not matched. Expected: " + OWNED_SYNCS);
             }
             AbstractOwnableSynchronizer s = mutex.getSync();
             String lockName = s.getClass().getName();
@@ -174,7 +173,6 @@
                 throw new RuntimeException("LockInfo: " + syncs[0] +
                     " IdentityHashCode not matched. Expected: " + hcode);
             }
-
         }
     }
     static class Mutex implements Lock, java.io.Serializable {
@@ -214,6 +212,10 @@
                 s.defaultReadObject();
                 setState(0); // reset to unlocked state
             }
+
+            protected Thread getLockOwner() {
+                return getExclusiveOwnerThread();
+            }
         }
 
         // The sync object does all the hard work. We just forward to it.
@@ -232,6 +234,8 @@
             return sync.tryAcquireNanos(1, unit.toNanos(timeout));
         }
 
+        public Thread getLockOwner()     { return sync.getLockOwner(); }
+
         public AbstractOwnableSynchronizer getSync() { return sync; }
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/Timer/DelayOverflow.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @bug 6730507
+ * @summary java.util.Timer schedule delay Long.MAX_VALUE causes task to execute multiple times
+ * @author Chris Hegarty
+ * @author Martin Buchholz
+ */
+
+import java.util.Date;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.concurrent.*;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class DelayOverflow
+{
+    void scheduleNow(Timer timer, TimerTask task, int how) {
+        switch (how) {
+            case 0 :
+                timer.schedule(task, new Date(), Long.MAX_VALUE);
+                break;
+            case 1:
+                timer.schedule(task, 0L, Long.MAX_VALUE);
+                break;
+            case 2:
+                timer.scheduleAtFixedRate(task, new Date(), Long.MAX_VALUE);
+                break;
+            case 3:
+                timer.scheduleAtFixedRate(task, 0L, Long.MAX_VALUE);
+                break;
+            default:
+                fail(String.valueOf(how));
+        }
+    }
+
+    void sleep(long millis) {
+        try { Thread.sleep(millis); }
+        catch (Throwable t) { unexpected(t); }
+    }
+
+    /** Checks that scheduledExecutionTime returns a "recent" time. */
+    void checkScheduledExecutionTime(TimerTask task) {
+        long t = System.currentTimeMillis()
+            - task.scheduledExecutionTime();
+        check(t >= 0 && t < 1000 * 600);
+    }
+
+    void test(String[] args) throws Throwable {
+        for (int how=0; how<4; how++) {
+            final CountDownLatch done = new CountDownLatch(1);
+            final AtomicInteger count = new AtomicInteger(0);
+            final Timer timer = new Timer();
+            final TimerTask task = new TimerTask() {
+                @Override
+                public void run() {
+                    checkScheduledExecutionTime(this);
+                    count.incrementAndGet();
+                    done.countDown();
+                }};
+
+            scheduleNow(timer, task, how);
+            done.await();
+            equal(count.get(), 1);
+            checkScheduledExecutionTime(task);
+            if (new java.util.Random().nextBoolean())
+                sleep(10);
+            check(task.cancel());
+            timer.cancel();
+            checkScheduledExecutionTime(task);
+        }
+    }
+
+    //--------------------- Infrastructure ---------------------------
+    volatile int passed = 0, failed = 0;
+    void pass() {passed++;}
+    void fail() {failed++; Thread.dumpStack();}
+    void fail(String msg) {System.err.println(msg); fail();}
+    void unexpected(Throwable t) {failed++; t.printStackTrace();}
+    void check(boolean cond) {if (cond) pass(); else fail();}
+    void equal(Object x, Object y) {
+        if (x == null ? y == null : x.equals(y)) pass();
+        else fail(x + " not equal to " + y);}
+    public static void main(String[] args) throws Throwable {
+        Class<?> k = new Object(){}.getClass().getEnclosingClass();
+        try {k.getMethod("instanceMain",String[].class)
+                .invoke( k.newInstance(), (Object) args);}
+        catch (Throwable e) {throw e.getCause();}}
+    public void instanceMain(String[] args) throws Throwable {
+        try {test(args);} catch (Throwable t) {unexpected(t);}
+        System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
+        if (failed > 0) throw new AssertionError("Some tests failed");}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/concurrent/ScheduledThreadPoolExecutor/DelayOverflow.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,161 @@
+/*
+ * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @bug 6725789
+ * @summary Check for long overflow in task time comparison.
+ */
+
+import java.util.concurrent.*;
+
+public class DelayOverflow {
+    static void waitForNanoTimeTick() {
+        for (long t0 = System.nanoTime(); t0 == System.nanoTime(); )
+            ;
+    }
+
+    void scheduleNow(ScheduledThreadPoolExecutor pool,
+                     Runnable r, int how) {
+        switch (how) {
+        case 0:
+            pool.schedule(r, 0, TimeUnit.MILLISECONDS);
+            break;
+        case 1:
+            pool.schedule(Executors.callable(r), 0, TimeUnit.DAYS);
+            break;
+        case 2:
+            pool.scheduleWithFixedDelay(r, 0, 1000, TimeUnit.NANOSECONDS);
+            break;
+        case 3:
+            pool.scheduleAtFixedRate(r, 0, 1000, TimeUnit.MILLISECONDS);
+            break;
+        default:
+            fail(String.valueOf(how));
+        }
+    }
+
+    void scheduleAtTheEndOfTime(ScheduledThreadPoolExecutor pool,
+                                Runnable r, int how) {
+        switch (how) {
+        case 0:
+            pool.schedule(r, Long.MAX_VALUE, TimeUnit.MILLISECONDS);
+            break;
+        case 1:
+            pool.schedule(Executors.callable(r), Long.MAX_VALUE, TimeUnit.DAYS);
+            break;
+        case 2:
+            pool.scheduleWithFixedDelay(r, Long.MAX_VALUE, 1000, TimeUnit.NANOSECONDS);
+            break;
+        case 3:
+            pool.scheduleAtFixedRate(r, Long.MAX_VALUE, 1000, TimeUnit.MILLISECONDS);
+            break;
+        default:
+            fail(String.valueOf(how));
+        }
+    }
+
+    /**
+     * Attempts to test exhaustively and deterministically, all 20
+     * possible ways that one task can be scheduled in the maximal
+     * distant future, while at the same time an existing tasks's time
+     * has already expired.
+     */
+    void test(String[] args) throws Throwable {
+        for (int nowHow = 0; nowHow < 4; nowHow++) {
+            for (int thenHow = 0; thenHow < 4; thenHow++) {
+
+                final ScheduledThreadPoolExecutor pool
+                    = new ScheduledThreadPoolExecutor(1);
+                final CountDownLatch runLatch     = new CountDownLatch(1);
+                final CountDownLatch busyLatch    = new CountDownLatch(1);
+                final CountDownLatch proceedLatch = new CountDownLatch(1);
+                final Runnable notifier = new Runnable() {
+                        public void run() { runLatch.countDown(); }};
+                final Runnable neverRuns = new Runnable() {
+                        public void run() { fail(); }};
+                final Runnable keepPoolBusy = new Runnable() {
+                        public void run() {
+                            try {
+                                busyLatch.countDown();
+                                proceedLatch.await();
+                            } catch (Throwable t) { unexpected(t); }
+                        }};
+                pool.schedule(keepPoolBusy, 0, TimeUnit.SECONDS);
+                busyLatch.await();
+                scheduleNow(pool, notifier, nowHow);
+                waitForNanoTimeTick();
+                scheduleAtTheEndOfTime(pool, neverRuns, thenHow);
+                proceedLatch.countDown();
+
+                check(runLatch.await(10L, TimeUnit.SECONDS));
+                equal(runLatch.getCount(), 0L);
+
+                pool.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
+                pool.shutdown();
+            }
+
+            final int nowHowCopy = nowHow;
+            final ScheduledThreadPoolExecutor pool
+                = new ScheduledThreadPoolExecutor(1);
+            final CountDownLatch runLatch = new CountDownLatch(1);
+            final Runnable notifier = new Runnable() {
+                    public void run() { runLatch.countDown(); }};
+            final Runnable scheduleNowScheduler = new Runnable() {
+                    public void run() {
+                        try {
+                            scheduleNow(pool, notifier, nowHowCopy);
+                            waitForNanoTimeTick();
+                        } catch (Throwable t) { unexpected(t); }
+                    }};
+            pool.scheduleWithFixedDelay(scheduleNowScheduler,
+                                        0, Long.MAX_VALUE,
+                                        TimeUnit.NANOSECONDS);
+
+            check(runLatch.await(10L, TimeUnit.SECONDS));
+            equal(runLatch.getCount(), 0L);
+
+            pool.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
+            pool.shutdown();
+        }
+    }
+
+    //--------------------- Infrastructure ---------------------------
+    volatile int passed = 0, failed = 0;
+    void pass() {passed++;}
+    void fail() {failed++; Thread.dumpStack();}
+    void fail(String msg) {System.err.println(msg); fail();}
+    void unexpected(Throwable t) {failed++; t.printStackTrace();}
+    void check(boolean cond) {if (cond) pass(); else fail();}
+    void equal(Object x, Object y) {
+        if (x == null ? y == null : x.equals(y)) pass();
+        else fail(x + " not equal to " + y);}
+    public static void main(String[] args) throws Throwable {
+        Class<?> k = new Object(){}.getClass().getEnclosingClass();
+        try {k.getMethod("instanceMain",String[].class)
+                .invoke( k.newInstance(), (Object) args);}
+        catch (Throwable e) {throw e.getCause();}}
+    public void instanceMain(String[] args) throws Throwable {
+        try {test(args);} catch (Throwable t) {unexpected(t);}
+        System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
+        if (failed > 0) throw new AssertionError("Some tests failed");}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/MBeanServer/DynamicWrapperMBeanTest.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,164 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test DynamicWrapperMBeanTest
+ * @bug 6624232
+ * @summary Test the DynamicWrapperMBean interface
+ * @author Eamonn McManus
+ */
+
+import java.lang.management.ManagementFactory;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.management.StandardMBean;
+import javax.management.modelmbean.ModelMBeanInfo;
+import javax.management.modelmbean.ModelMBeanInfoSupport;
+import javax.management.modelmbean.ModelMBeanOperationInfo;
+import javax.management.modelmbean.RequiredModelMBean;
+import static javax.management.StandardMBean.Options;
+
+public class DynamicWrapperMBeanTest {
+    public static interface WrappedMBean {
+        public void sayHello();
+    }
+    public static class Wrapped implements WrappedMBean {
+        public void sayHello() {
+            System.out.println("Hello");
+        }
+    }
+
+    private static String failure;
+
+    public static void main(String[] args) throws Exception {
+        if (Wrapped.class.getClassLoader() ==
+                StandardMBean.class.getClassLoader()) {
+            throw new Exception(
+                    "TEST ERROR: Resource and StandardMBean have same ClassLoader");
+        }
+
+        Options wrappedVisOpts = new Options();
+        wrappedVisOpts.setWrappedObjectVisible(true);
+        Options wrappedInvisOpts = new Options();
+        wrappedInvisOpts.setWrappedObjectVisible(false);
+        assertEquals("Options withWrappedObjectVisible(false)",
+                     new Options(), wrappedInvisOpts);
+
+        Wrapped resource = new Wrapped();
+
+        StandardMBean visible =
+                new StandardMBean(resource, WrappedMBean.class, wrappedVisOpts);
+        StandardMBean invisible =
+                new StandardMBean(resource, WrappedMBean.class, wrappedInvisOpts);
+
+        assertEquals("getResource withWrappedObjectVisible(true)",
+                resource, visible.getWrappedObject());
+        assertEquals("getResource withWrappedObjectVisible(false)",
+                invisible, invisible.getWrappedObject());
+
+        System.out.println("===Testing StandardMBean===");
+
+        ObjectName visibleName = new ObjectName("a:type=visible");
+        ObjectName invisibleName = new ObjectName("a:type=invisible");
+        MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
+        mbs.registerMBean(visible, visibleName);
+        mbs.registerMBean(invisible, invisibleName);
+
+        assertEquals("ClassLoader for visible resource",
+                Wrapped.class.getClassLoader(),
+                mbs.getClassLoaderFor(visibleName));
+        assertEquals("ClassLoader for invisible resource",
+                StandardMBean.class.getClassLoader(),
+                mbs.getClassLoaderFor(invisibleName));
+
+        assertEquals("isInstanceOf(WrappedMBean) for visible wrapped",
+                true, mbs.isInstanceOf(visibleName, WrappedMBean.class.getName()));
+        assertEquals("isInstanceOf(WrappedMBean) for invisible wrapped",
+                false, mbs.isInstanceOf(invisibleName, WrappedMBean.class.getName()));
+        assertEquals("isInstanceOf(StandardMBean) for visible wrapped",
+                false, mbs.isInstanceOf(visibleName, StandardMBean.class.getName()));
+        assertEquals("isInstanceOf(StandardMBean) for invisible wrapped",
+                true, mbs.isInstanceOf(invisibleName, StandardMBean.class.getName()));
+
+        mbs.unregisterMBean(visibleName);
+        mbs.unregisterMBean(invisibleName);
+
+        System.out.println("===Testing RequiredModelMBean===");
+
+        // Godawful Model MBeans...
+        ModelMBeanOperationInfo mmboi = new ModelMBeanOperationInfo(
+                "say hello to the nice man", Wrapped.class.getMethod("sayHello"));
+        ModelMBeanInfo visibleMmbi = new ModelMBeanInfoSupport(
+                Wrapped.class.getName(), "Visible wrapped", null, null,
+                new ModelMBeanOperationInfo[] {mmboi}, null);
+        ModelMBeanInfo invisibleMmbi = new ModelMBeanInfoSupport(
+                Wrapped.class.getName(), "Invisible wrapped", null, null,
+                new ModelMBeanOperationInfo[] {mmboi}, null);
+        RequiredModelMBean visibleRmmb = new RequiredModelMBean(visibleMmbi);
+        RequiredModelMBean invisibleRmmb = new RequiredModelMBean(invisibleMmbi);
+        visibleRmmb.setManagedResource(resource, "VisibleObjectReference");
+        invisibleRmmb.setManagedResource(resource, "ObjectReference");
+
+        mbs.registerMBean(visibleRmmb, visibleName);
+        mbs.registerMBean(invisibleRmmb, invisibleName);
+
+        assertEquals("ClassLoader for visible wrapped",
+                Wrapped.class.getClassLoader(),
+                mbs.getClassLoaderFor(visibleName));
+        assertEquals("ClassLoader for invisible wrapped",
+                StandardMBean.class.getClassLoader(),
+                mbs.getClassLoaderFor(invisibleName));
+
+        assertEquals("isInstanceOf(WrappedMBean) for visible resource",
+                true, mbs.isInstanceOf(visibleName, WrappedMBean.class.getName()));
+        assertEquals("isInstanceOf(WrappedMBean) for invisible resource",
+                false, mbs.isInstanceOf(invisibleName, WrappedMBean.class.getName()));
+        assertEquals("isInstanceOf(RequiredModelMBean) for visible resource",
+                false, mbs.isInstanceOf(visibleName, RequiredModelMBean.class.getName()));
+        assertEquals("isInstanceOf(RequiredModelMBean) for invisible resource",
+                true, mbs.isInstanceOf(invisibleName, RequiredModelMBean.class.getName()));
+
+        if (failure != null)
+            throw new Exception("TEST FAILED: " + failure);
+    }
+
+    private static void assertEquals(String what, Object expect, Object actual) {
+        if (equal(expect, actual))
+            System.out.println("OK: " + what + " = " + expect);
+        else
+            fail(what + " should be " + expect + ", is " + actual);
+    }
+
+    private static boolean equal(Object x, Object y) {
+        if (x == y)
+            return true;
+        if (x == null || y == null)
+            return false;
+        return x.equals(y);
+    }
+
+    private static void fail(String why) {
+        failure = why;
+        System.out.println("FAIL: " + why);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/MBeanServer/MBeanServerNotificationTest.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @bug 6689505
+ * @summary Checks that MBeanServerNotification.toString contains the
+ *          MBean name.
+ * @author Daniel Fuchs
+ * @compile MBeanServerNotificationTest.java
+ * @run main MBeanServerNotificationTest
+ */
+
+import com.sun.jmx.mbeanserver.Util;
+import javax.management.*;
+import java.util.concurrent.*;
+
+public class MBeanServerNotificationTest {
+    final static String[] names = {
+        ":type=Wombat", "wombat:type=Wombat",null,
+    };
+    public static void main(String[] args) throws Exception {
+        System.out.println("Test that MBeanServerNotification.toString " +
+                "contains the name of the MBean being registered " +
+                "or unregistered.");
+        int failures = 0;
+        final MBeanServer mbs = MBeanServerFactory.createMBeanServer();
+        for (String str:names) {
+            try {
+                final ObjectName name = (str==null)?null:new ObjectName(str);
+                failures+=test(mbs, name, name!=null);
+            } catch(Exception x) {
+                x.printStackTrace(System.out);
+                System.out.println("Test failed for: "+str);
+                failures++;
+            }
+        }
+        if (failures == 0)
+            System.out.println("Test passed");
+        else {
+            System.out.println("TEST FAILED: " + failures + " failure(s)");
+            System.exit(1);
+        }
+    }
+
+    private static enum Registration {
+        REGISTER(MBeanServerNotification.REGISTRATION_NOTIFICATION),
+        UNREGISTER(MBeanServerNotification.UNREGISTRATION_NOTIFICATION);
+        final String type;
+        private Registration(String type) {this.type = type;}
+        public int test(MBeanServerNotification n, ObjectName name) {
+            int failures = 0;
+            System.out.println("Testing: "+n);
+            if (!n.toString().endsWith("[type="+type+
+                "][message="+n.getMessage()+
+                "][mbeanName="+name+"]")) {
+                System.err.println("Test failed for "+ type+
+                   " ["+name+"]: "+n);
+                failures++;
+            }
+            return failures;
+        }
+        public MBeanServerNotification create(ObjectName name) {
+            return new MBeanServerNotification(type,
+                MBeanServerDelegate.DELEGATE_NAME, next(), name);
+        }
+        private static long next = 0;
+        private static synchronized long next() {return next++;}
+
+    }
+
+    private static int test(MBeanServer mbs, ObjectName name,
+                            boolean register)
+            throws Exception {
+        System.out.println("--------" + name + "--------");
+
+        int failures = 0;
+        for (Registration reg : Registration.values()) {
+            failures = reg.test(reg.create(name), name);
+        }
+        if (!register) return failures;
+
+        final ArrayBlockingQueue<Notification> queue =
+                new ArrayBlockingQueue<Notification>(10);
+        final NotificationListener listener = new NotificationListener() {
+            public void handleNotification(Notification notification,
+                    Object handback) {
+                try {
+                    queue.put(notification);
+                } catch(Exception x) {
+                    x.printStackTrace(System.out);
+                }
+            }
+        };
+        mbs.addNotificationListener(MBeanServerDelegate.DELEGATE_NAME,
+                listener, null, name);
+        final ObjectInstance oi = mbs.registerMBean(new Wombat(), name);
+        try {
+            failures+=Registration.REGISTER.test((MBeanServerNotification)
+                queue.poll(2, TimeUnit.SECONDS), oi.getObjectName());
+        } finally {
+            mbs.unregisterMBean(oi.getObjectName());
+            failures+=Registration.UNREGISTER.test((MBeanServerNotification)
+                queue.poll(2, TimeUnit.SECONDS), oi.getObjectName());
+        }
+        return failures;
+    }
+
+    public static interface WombatMBean {}
+    public static class Wombat implements WombatMBean {}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/MBeanServer/OldMBeanServerTest.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,1410 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.Serializable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.management.ManagementFactory;
+import java.lang.ref.WeakReference;
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.WeakHashMap;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import javax.management.Attribute;
+import javax.management.AttributeList;
+import javax.management.AttributeNotFoundException;
+import javax.management.DynamicMBean;
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.InstanceNotFoundException;
+import javax.management.IntrospectionException;
+import javax.management.InvalidAttributeValueException;
+import javax.management.ListenerNotFoundException;
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanConstructorInfo;
+import javax.management.MBeanException;
+import javax.management.MBeanInfo;
+import javax.management.MBeanNotificationInfo;
+import javax.management.MBeanOperationInfo;
+import javax.management.MBeanRegistration;
+import javax.management.MBeanRegistrationException;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerBuilder;
+import javax.management.MBeanServerConnection;
+import javax.management.MBeanServerDelegate;
+import javax.management.MBeanServerFactory;
+import javax.management.MBeanServerNotification;
+import javax.management.MalformedObjectNameException;
+import javax.management.NotCompliantMBeanException;
+import javax.management.Notification;
+import javax.management.NotificationBroadcaster;
+import javax.management.NotificationBroadcasterSupport;
+import javax.management.NotificationEmitter;
+import javax.management.NotificationFilter;
+import javax.management.NotificationListener;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.OperationsException;
+import javax.management.QueryEval;
+import javax.management.QueryExp;
+import javax.management.ReflectionException;
+import javax.management.RuntimeErrorException;
+import javax.management.RuntimeMBeanException;
+import javax.management.StandardMBean;
+import javax.management.loading.ClassLoaderRepository;
+import javax.management.remote.JMXConnector;
+import javax.management.remote.JMXConnectorFactory;
+import javax.management.remote.JMXConnectorServer;
+import javax.management.remote.JMXConnectorServerFactory;
+import javax.management.remote.JMXServiceURL;
+
+/*
+ * @test OldMBeanServerTest.java
+ * @bug 5072268
+ * @summary Test that nothing assumes a post-1.2 MBeanServer
+ * @author Eamonn McManus
+ * @run main/othervm -ea OldMBeanServerTest
+ */
+
+/*
+ * We defined the MBeanServerBuilder class and the associated system
+ * property javax.management.builder.initial in version 1.2 of the JMX
+ * spec.  That amounts to a guarantee that someone can set the property
+ * to an MBeanServer that only knows about JMX 1.2 semantics, and if they
+ * only do JMX 1.2 operations, everything should work.  This test is a
+ * sanity check that ensures we don't inadvertently make any API changes
+ * that stop that from being true.  It includes a complete (if slow)
+ * MBeanServer implementation.  That implementation doesn't replicate the
+ * mandated exception behaviour everywhere, though, since there's lots of
+ * arbitrary cruft in that.  Also, the behaviour of concurrent unregisterMBean
+ * calls is incorrect in detail.
+ */
+
+public class OldMBeanServerTest {
+    private static MBeanServerConnection mbsc;
+    private static String failure;
+
+    public static void main(String[] args) throws Exception {
+        if (!OldMBeanServerTest.class.desiredAssertionStatus())
+            throw new Exception("Test must be run with -ea");
+
+        System.setProperty("javax.management.builder.initial",
+                OldMBeanServerBuilder.class.getName());
+        assert MBeanServerFactory.newMBeanServer() instanceof OldMBeanServer;
+
+        System.out.println("=== RUNNING TESTS WITH LOCAL MBEANSERVER ===");
+        runTests(new Callable<MBeanServerConnection>() {
+            public MBeanServerConnection call() {
+                return MBeanServerFactory.newMBeanServer();
+            }
+        }, null);
+
+        System.out.println("=== RUNNING TESTS THROUGH CONNECTOR ===");
+        ConnectionBuilder builder = new ConnectionBuilder();
+        runTests(builder, builder);
+
+        if (failure == null)
+            System.out.println("TEST PASSED");
+        else
+            throw new Exception("TEST FAILED: " + failure);
+    }
+
+    private static class ConnectionBuilder
+            implements Callable<MBeanServerConnection>, Runnable {
+        private JMXConnector connector;
+        public MBeanServerConnection call() {
+            MBeanServer mbs = MBeanServerFactory.newMBeanServer();
+            try {
+                JMXServiceURL url = new JMXServiceURL("service:jmx:rmi://");
+                JMXConnectorServer cs =
+                    JMXConnectorServerFactory.newJMXConnectorServer(
+                        url, null, mbs);
+                cs.start();
+                JMXServiceURL addr = cs.getAddress();
+                connector = JMXConnectorFactory.connect(addr);
+                return connector.getMBeanServerConnection();
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+        }
+        public void run() {
+            if (connector != null) {
+                try {
+                    connector.close();
+                } catch (IOException e) {
+                    throw new RuntimeException(e);
+                }
+            }
+        }
+    }
+
+    private static void runTests(
+            Callable<MBeanServerConnection> maker, Runnable breaker)
+    throws Exception {
+        for (Method m : OldMBeanServerTest.class.getDeclaredMethods()) {
+            if (Modifier.isStatic(m.getModifiers()) &&
+                    m.getName().startsWith("test") &&
+                    m.getParameterTypes().length == 0) {
+                ExpectException expexc = m.getAnnotation(ExpectException.class);
+                mbsc = maker.call();
+                try {
+                    m.invoke(null);
+                    if (expexc != null) {
+                        failure =
+                                m.getName() + " did not got expected exception " +
+                                expexc.value().getName();
+                        System.out.println(failure);
+                    } else
+                        System.out.println(m.getName() + " OK");
+                } catch (InvocationTargetException ite) {
+                    Throwable t = ite.getCause();
+                    String prob = null;
+                    if (expexc != null) {
+                        if (expexc.value().isInstance(t)) {
+                            System.out.println(m.getName() + " OK (got expected " +
+                                    expexc.value().getName() + ")");
+                        } else
+                            prob = "got wrong exception";
+                    } else
+                        prob = "got exception";
+                    if (prob != null) {
+                        failure = m.getName() + ": " + prob + " " +
+                                t.getClass().getName();
+                        System.out.println(failure);
+                        t.printStackTrace(System.out);
+                    }
+                } finally {
+                    if (breaker != null)
+                        breaker.run();
+                }
+            }
+        }
+    }
+
+    @Retention(RetentionPolicy.RUNTIME)
+    private static @interface ExpectException {
+        Class<? extends Exception> value();
+    }
+
+    public static interface BoringMBean {
+        public String getName();
+        public int add(int x, int y);
+    }
+
+    // This class is Serializable so we can createMBean a StandardMBean
+    // that contains it.  Not recommended practice in general --
+    // should we have a StandardMBean constructor that takes a class
+    // name and constructor parameters?
+    public static class Boring implements BoringMBean, Serializable {
+        public String getName() {
+            return "Jessica";
+        }
+
+        public int add(int x, int y) {
+            return x + y;
+        }
+    }
+
+    public static interface BoringNotifierMBean extends BoringMBean {
+        public void send();
+    }
+
+    public static class BoringNotifier
+            extends Boring implements BoringNotifierMBean, NotificationBroadcaster {
+        private final NotificationBroadcasterSupport nbs =
+                new NotificationBroadcasterSupport();
+
+        public void addNotificationListener(
+                NotificationListener listener, NotificationFilter filter, Object handback)
+        throws IllegalArgumentException {
+            nbs.addNotificationListener(listener, filter, handback);
+        }
+
+        public void removeNotificationListener(NotificationListener listener)
+        throws ListenerNotFoundException {
+            nbs.removeNotificationListener(listener);
+        }
+
+        public MBeanNotificationInfo[] getNotificationInfo() {
+            return null;
+        }
+
+        public void send() {
+            Notification n = new Notification("type.type", this, 0L);
+            nbs.sendNotification(n);
+        }
+    }
+
+    private static class CountListener implements NotificationListener {
+        volatile int count;
+        public void handleNotification(Notification n, Object h) {
+            if (h == null)
+                h = 1;
+            count += (Integer) h;
+        }
+        void waitForCount(int expect) throws InterruptedException {
+            long deadline = System.currentTimeMillis() + 2000L;
+            while (count < expect && System.currentTimeMillis() < deadline)
+                Thread.sleep(1);
+            assert count == expect;
+        }
+    }
+
+    private static void testBasic() throws Exception {
+        CountListener countListener = new CountListener();
+        mbsc.addNotificationListener(
+                MBeanServerDelegate.DELEGATE_NAME, countListener, null, null);
+        assert countListener.count == 0;
+        ObjectName name = new ObjectName("a:b=c");
+        if (mbsc instanceof MBeanServer)
+            ((MBeanServer) mbsc).registerMBean(new Boring(), name);
+        else
+            mbsc.createMBean(Boring.class.getName(), name);
+        countListener.waitForCount(1);
+        assert mbsc.isRegistered(name);
+        assert mbsc.queryNames(null, null).contains(name);
+        assert mbsc.getAttribute(name, "Name").equals("Jessica");
+        assert mbsc.invoke(
+                name, "add", new Object[] {2, 3}, new String[] {"int", "int"})
+                .equals(5);
+        mbsc.unregisterMBean(name);
+        countListener.waitForCount(2);
+        assert !mbsc.isRegistered(name);
+        assert !mbsc.queryNames(null, null).contains(name);
+
+        mbsc.createMBean(BoringNotifier.class.getName(), name);
+        countListener.waitForCount(3);
+        CountListener boringListener = new CountListener();
+        class AlwaysNotificationFilter implements NotificationFilter {
+            public boolean isNotificationEnabled(Notification notification) {
+                return true;
+            }
+        }
+        mbsc.addNotificationListener(
+                name, boringListener, new AlwaysNotificationFilter(), 5);
+        mbsc.invoke(name, "send", null, null);
+        boringListener.waitForCount(5);
+    }
+
+    private static void testPrintAttrs() throws Exception {
+        printAttrs(mbsc, null);
+    }
+
+    private static void testPlatformMBeanServer() throws Exception {
+        MBeanServer pmbs = ManagementFactory.getPlatformMBeanServer();
+        assert pmbs instanceof OldMBeanServer;
+        // Preceding assertion could be violated if at some stage we wrap
+        // the Platform MBeanServer.  In that case we can still check that
+        // it is ultimately an OldMBeanServer for example by adding a
+        // counter to getAttribute and checking that it is incremented
+        // when we call pmbs.getAttribute.
+
+        printAttrs(pmbs, UnsupportedOperationException.class);
+        ObjectName memoryMXBeanName =
+                new ObjectName(ManagementFactory.MEMORY_MXBEAN_NAME);
+        pmbs.invoke(memoryMXBeanName, "gc", null, null);
+    }
+
+    private static void printAttrs(
+            MBeanServerConnection mbsc1, Class<? extends Exception> expectX)
+    throws Exception {
+        Set<ObjectName> names = mbsc1.queryNames(null, null);
+        for (ObjectName name : names) {
+            System.out.println(name + ":");
+            MBeanInfo mbi = mbsc1.getMBeanInfo(name);
+            MBeanAttributeInfo[] mbais = mbi.getAttributes();
+            for (MBeanAttributeInfo mbai : mbais) {
+                String attr = mbai.getName();
+                Object value;
+                try {
+                    value = mbsc1.getAttribute(name, attr);
+                } catch (Exception e) {
+                    if (expectX != null && expectX.isInstance(e))
+                        value = "<" + e + ">";
+                    else
+                        throw e;
+                }
+                String s = "  " + attr + " = " + value;
+                if (s.length() > 80)
+                    s = s.substring(0, 77) + "...";
+                System.out.println(s);
+            }
+        }
+    }
+
+    private static void testJavaxManagementStandardMBean() throws Exception {
+        ObjectName name = new ObjectName("a:b=c");
+        Object mbean = new StandardMBean(new Boring(), BoringMBean.class);
+        mbsc.createMBean(
+                StandardMBean.class.getName(), name,
+                new Object[] {new Boring(), BoringMBean.class},
+                new String[] {Object.class.getName(), Class.class.getName()});
+        assert mbsc.getAttribute(name, "Name").equals("Jessica");
+        assert mbsc.invoke(
+                name, "add", new Object[] {2, 3}, new String[] {"int", "int"})
+                .equals(5);
+        mbsc.unregisterMBean(name);
+    }
+
+    private static void testConnector() throws Exception {
+    }
+
+    public static class OldMBeanServerBuilder extends MBeanServerBuilder {
+        public MBeanServer newMBeanServer(
+                String defaultDomain, MBeanServer outer, MBeanServerDelegate delegate) {
+            return new OldMBeanServer(defaultDomain, delegate);
+        }
+    }
+
+    public static class OldMBeanServer implements MBeanServer {
+        // We pretend there's a ClassLoader MBean representing the Class Loader
+        // Repository and intercept references to it where necessary to keep up
+        // the pretence.  This allows us to fake the right behaviour for
+        // the omitted-ClassLoader versions of createMBean and instantiate
+        // (which are not the same as passing a null for the ClassLoader parameter
+        // of the versions that have one).
+        private static final ObjectName clrName;
+        static {
+            try {
+                clrName =
+                        new ObjectName("JMImplementation:type=ClassLoaderRepository");
+            } catch (MalformedObjectNameException e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+        private final ConcurrentMap<ObjectName, DynamicMBean> mbeans =
+                new ConcurrentHashMap<ObjectName, DynamicMBean>();
+        private final ConcurrentMap<ObjectName, ListenerTable> listenerMap =
+                new ConcurrentHashMap<ObjectName, ListenerTable>();
+        private final String defaultDomain;
+        private final MBeanServerDelegate delegate;
+        private final ClassLoaderRepositoryImpl clr =
+                new ClassLoaderRepositoryImpl();
+
+        OldMBeanServer(String defaultDomain, MBeanServerDelegate delegate) {
+            this.defaultDomain = defaultDomain;
+            this.delegate = delegate;
+            try {
+                registerMBean(delegate, MBeanServerDelegate.DELEGATE_NAME);
+            } catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+        public ObjectInstance createMBean(String className, ObjectName name)
+        throws ReflectionException, InstanceAlreadyExistsException,
+                MBeanRegistrationException, MBeanException,
+                NotCompliantMBeanException {
+            return createMBean(className, name, null, null);
+        }
+
+        public ObjectInstance createMBean(
+                String className, ObjectName name, ObjectName loaderName)
+        throws ReflectionException, InstanceAlreadyExistsException,
+                MBeanRegistrationException, MBeanException,
+                NotCompliantMBeanException, InstanceNotFoundException {
+            return createMBean(className, name, loaderName, null, null);
+        }
+
+        public ObjectInstance createMBean(
+                String className, ObjectName name, Object[] params, String[] signature)
+        throws ReflectionException, InstanceAlreadyExistsException,
+                MBeanRegistrationException, MBeanException,
+                NotCompliantMBeanException {
+            try {
+                return createMBean(className, name, clrName, params, signature);
+            } catch (InstanceNotFoundException ex) {
+                throw new RuntimeException(ex);  // can't happen
+            }
+        }
+
+        public ObjectInstance createMBean(
+                String className, ObjectName name, ObjectName loaderName,
+                Object[] params, String[] signature)
+        throws ReflectionException, InstanceAlreadyExistsException,
+                MBeanRegistrationException, MBeanException,
+                NotCompliantMBeanException, InstanceNotFoundException {
+            Object mbean = instantiate(className, loaderName, params, signature);
+            return registerMBean(mbean, name);
+        }
+
+        private void forbidJMImpl(ObjectName name) {
+            if (name.getDomain().equals("JMImplementation") &&
+                    mbeans.containsKey(MBeanServerDelegate.DELEGATE_NAME))
+                throw new IllegalArgumentException("JMImplementation reserved");
+        }
+
+        public ObjectInstance registerMBean(Object object, ObjectName name)
+        throws InstanceAlreadyExistsException, MBeanRegistrationException,
+                NotCompliantMBeanException {
+            forbidJMImpl(name);
+            if (name.isPattern())
+                throw new IllegalArgumentException(name.toString());
+            // This is the only place we check for wildcards.  Since you
+            // can't register a wildcard name, other operations that supply
+            // one will get InstanceNotFoundException when they look it up.
+
+            DynamicMBean mbean;
+            if (object instanceof DynamicMBean)
+                mbean = (DynamicMBean) object;
+            else
+                mbean = standardToDynamic(object);
+            MBeanRegistration reg = mbeanRegistration(object);
+            try {
+                name = reg.preRegister(this, name);
+            } catch (Exception e) {
+                throw new MBeanRegistrationException(e);
+            }
+            DynamicMBean put = mbeans.putIfAbsent(name, mbean);
+            if (put != null) {
+                reg.postRegister(false);
+                throw new InstanceAlreadyExistsException(name.toString());
+            }
+            reg.postRegister(true);
+
+            if (object instanceof ClassLoader)
+                clr.addLoader((ClassLoader) object);
+
+            Notification n = new MBeanServerNotification(
+                    MBeanServerNotification.REGISTRATION_NOTIFICATION,
+                    MBeanServerDelegate.DELEGATE_NAME,
+                    0,
+                    name);
+            delegate.sendNotification(n);
+
+            String className = mbean.getMBeanInfo().getClassName();
+            return new ObjectInstance(name, className);
+        }
+
+        public void unregisterMBean(ObjectName name)
+        throws InstanceNotFoundException, MBeanRegistrationException {
+
+            forbidJMImpl(name);
+
+            DynamicMBean mbean = getMBean(name);
+            if (mbean == null)
+                throw new InstanceNotFoundException(name.toString());
+
+            MBeanRegistration reg = mbeanRegistration(mbean);
+            try {
+                reg.preDeregister();
+            } catch (Exception e) {
+                throw new MBeanRegistrationException(e);
+            }
+            if (!mbeans.remove(name, mbean))
+                throw new InstanceNotFoundException(name.toString());
+                // This is incorrect because we've invoked preDeregister
+
+            Object userMBean = getUserMBean(mbean);
+            if (userMBean instanceof ClassLoader)
+                clr.removeLoader((ClassLoader) userMBean);
+
+            Notification n = new MBeanServerNotification(
+                    MBeanServerNotification.REGISTRATION_NOTIFICATION,
+                    MBeanServerDelegate.DELEGATE_NAME,
+                    0,
+                    name);
+            delegate.sendNotification(n);
+
+            reg.postDeregister();
+        }
+
+        public ObjectInstance getObjectInstance(ObjectName name)
+        throws InstanceNotFoundException {
+            DynamicMBean mbean = getMBean(name);
+            return new ObjectInstance(name, mbean.getMBeanInfo().getClassName());
+        }
+
+        private static class TrueQueryExp implements QueryExp {
+            public boolean apply(ObjectName name) {
+                return true;
+            }
+
+            public void setMBeanServer(MBeanServer s) {}
+        }
+        private static final QueryExp trueQuery = new TrueQueryExp();
+
+        public Set<ObjectInstance> queryMBeans(ObjectName name, QueryExp query) {
+            Set<ObjectInstance> instances = newSet();
+            if (name == null)
+                name = ObjectName.WILDCARD;
+            if (query == null)
+                query = trueQuery;
+            MBeanServer oldMBS = QueryEval.getMBeanServer();
+            try {
+                query.setMBeanServer(this);
+                for (ObjectName n : mbeans.keySet()) {
+                    if (name.apply(n)) {
+                        try {
+                            if (query.apply(n))
+                                instances.add(getObjectInstance(n));
+                        } catch (Exception e) {
+                            // OK: Ignore this MBean in the result
+                        }
+                    }
+                }
+            } finally {
+                query.setMBeanServer(oldMBS);
+            }
+            return instances;
+        }
+
+        public Set<ObjectName> queryNames(ObjectName name, QueryExp query) {
+            Set<ObjectInstance> instances = queryMBeans(name, query);
+            Set<ObjectName> names = newSet();
+            for (ObjectInstance instance : instances)
+                names.add(instance.getObjectName());
+            return names;
+        }
+
+        public boolean isRegistered(ObjectName name) {
+            return mbeans.containsKey(name);
+        }
+
+        public Integer getMBeanCount() {
+            return mbeans.size();
+        }
+
+        public Object getAttribute(ObjectName name, String attribute)
+        throws MBeanException, AttributeNotFoundException,
+                InstanceNotFoundException, ReflectionException {
+            return getMBean(name).getAttribute(attribute);
+        }
+
+        public AttributeList getAttributes(ObjectName name, String[] attributes)
+        throws InstanceNotFoundException, ReflectionException {
+            return getMBean(name).getAttributes(attributes);
+        }
+
+        public void setAttribute(ObjectName name, Attribute attribute)
+        throws InstanceNotFoundException, AttributeNotFoundException,
+                InvalidAttributeValueException, MBeanException,
+                ReflectionException {
+            getMBean(name).setAttribute(attribute);
+        }
+
+        public AttributeList setAttributes(
+                ObjectName name, AttributeList attributes)
+        throws InstanceNotFoundException, ReflectionException {
+            return getMBean(name).setAttributes(attributes);
+        }
+
+        public Object invoke(
+                ObjectName name, String operationName, Object[] params,
+                String[] signature)
+        throws InstanceNotFoundException, MBeanException, ReflectionException {
+            return getMBean(name).invoke(operationName, params, signature);
+        }
+
+        public String getDefaultDomain() {
+            return defaultDomain;
+        }
+
+        public String[] getDomains() {
+            Set<String> domains = newSet();
+            for (ObjectName name : mbeans.keySet())
+                domains.add(name.getDomain());
+            return domains.toArray(new String[0]);
+        }
+
+        // ClassCastException if MBean is not a NotificationBroadcaster
+        public void addNotificationListener(
+                ObjectName name, NotificationListener listener,
+                NotificationFilter filter, Object handback)
+                throws InstanceNotFoundException {
+            NotificationBroadcaster userMBean =
+                    (NotificationBroadcaster) getUserMBean(name);
+            NotificationListener wrappedListener =
+                  wrappedListener(name, userMBean, listener);
+            userMBean.addNotificationListener(wrappedListener, filter, handback);
+        }
+
+        public void addNotificationListener(
+                ObjectName name, ObjectName listener,
+                NotificationFilter filter, Object handback)
+                throws InstanceNotFoundException {
+            NotificationListener nl =
+                    (NotificationListener) getUserMBean(listener);
+            addNotificationListener(name, nl, filter, handback);
+        }
+
+        public void removeNotificationListener(
+                ObjectName name, ObjectName listener)
+                throws InstanceNotFoundException, ListenerNotFoundException {
+            NotificationListener nl =
+                    (NotificationListener) getUserMBean(listener);
+            removeNotificationListener(name, nl);
+        }
+
+        public void removeNotificationListener(
+                ObjectName name, ObjectName listener,
+                NotificationFilter filter, Object handback)
+                throws InstanceNotFoundException, ListenerNotFoundException {
+            NotificationListener nl =
+                    (NotificationListener) getUserMBean(listener);
+            removeNotificationListener(name, nl, filter, handback);
+        }
+
+        public void removeNotificationListener(
+                ObjectName name, NotificationListener listener)
+                throws InstanceNotFoundException, ListenerNotFoundException {
+            NotificationBroadcaster userMBean =
+                    (NotificationBroadcaster) getUserMBean(name);
+            NotificationListener wrappedListener =
+                  wrappedListener(name, userMBean, listener);
+            userMBean.removeNotificationListener(wrappedListener);
+        }
+
+        public void removeNotificationListener(
+                ObjectName name, NotificationListener listener,
+                NotificationFilter filter, Object handback)
+                throws InstanceNotFoundException, ListenerNotFoundException {
+            NotificationEmitter userMBean =
+                    (NotificationEmitter) getMBean(name);
+            NotificationListener wrappedListener =
+                  wrappedListener(name, userMBean, listener);
+            userMBean.removeNotificationListener(wrappedListener, filter, handback);
+        }
+
+        public MBeanInfo getMBeanInfo(ObjectName name)
+        throws InstanceNotFoundException, IntrospectionException,
+                ReflectionException {
+            return getMBean(name).getMBeanInfo();
+        }
+
+        public boolean isInstanceOf(ObjectName name, String className)
+        throws InstanceNotFoundException {
+            DynamicMBean mbean = getMBean(name);
+            String mbeanClassName = mbean.getMBeanInfo().getClassName();
+            if (className.equals(mbeanClassName))
+                return true;
+            ClassLoader loader = getUserMBean(mbean).getClass().getClassLoader();
+            try {
+                Class<?> mbeanClass = Class.forName(mbeanClassName, false, loader);
+                Class<?> isInstClass = Class.forName(className, false, loader);
+                return isInstClass.isAssignableFrom(mbeanClass);
+            } catch (ClassNotFoundException e) {
+                return false;
+            }
+        }
+
+        public Object instantiate(String className)
+        throws ReflectionException, MBeanException {
+            return instantiate(className, null, null);
+        }
+
+        public Object instantiate(String className, ObjectName loaderName)
+        throws ReflectionException, MBeanException, InstanceNotFoundException {
+            return instantiate(className, loaderName, null, null);
+        }
+
+        public Object instantiate(
+                String className, Object[] params, String[] signature)
+        throws ReflectionException, MBeanException {
+            try {
+                return instantiate(className, clrName, params, signature);
+            } catch (InstanceNotFoundException e) {
+                throw new RuntimeException(e);  // can't happen
+            }
+        }
+
+        public Object instantiate(
+                String className, ObjectName loaderName,
+                Object[] params, String[] signature)
+        throws ReflectionException, MBeanException, InstanceNotFoundException {
+
+            if (params == null)
+                params = new Object[0];
+            if (signature == null)
+                signature = new String[0];
+
+            ClassLoader loader;
+            if (loaderName == null)
+                loader = this.getClass().getClassLoader();
+            else if (loaderName.equals(clrName))
+                loader = clr;
+            else
+                loader = (ClassLoader) getMBean(loaderName);
+
+            Class<?> c;
+            try {
+                c = Class.forName(className, false, loader);
+            } catch (ClassNotFoundException e) {
+                throw new ReflectionException(e);
+            }
+
+            Constructor[] constrs = c.getConstructors();
+            Constructor found = null;
+            findconstr:
+            for (Constructor constr : constrs) {
+                Class<?>[] cTypes = constr.getParameterTypes();
+                if (cTypes.length == signature.length) {
+                    for (int i = 0; i < cTypes.length; i++) {
+                        if (!cTypes[i].getName().equals(signature[i]))
+                            continue findconstr;
+                    }
+                    found = constr;
+                    break findconstr;
+                }
+            }
+            if (found == null) {
+                Exception x = new NoSuchMethodException(
+                        className + Arrays.toString(signature));
+                throw new ReflectionException(x);
+            }
+            return invokeSomething(found, null, params);
+        }
+
+        @Deprecated
+        public ObjectInputStream deserialize(ObjectName name, byte[] data)
+        throws InstanceNotFoundException, OperationsException {
+            throw new UnsupportedOperationException();
+        }
+
+        @Deprecated
+        public ObjectInputStream deserialize(String className, byte[] data)
+        throws OperationsException, ReflectionException {
+            throw new UnsupportedOperationException();
+        }
+
+        @Deprecated
+        public ObjectInputStream deserialize(
+                String className, ObjectName loaderName, byte[] data)
+        throws InstanceNotFoundException, OperationsException, ReflectionException {
+            throw new UnsupportedOperationException();
+        }
+
+        public ClassLoader getClassLoaderFor(ObjectName mbeanName)
+        throws InstanceNotFoundException {
+            DynamicMBean mbean = getMBean(mbeanName);
+            Object userMBean = getUserMBean(mbean);
+            return userMBean.getClass().getClassLoader();
+        }
+
+        public ClassLoader getClassLoader(ObjectName loaderName)
+        throws InstanceNotFoundException {
+            return (ClassLoader) getMBean(loaderName);
+        }
+
+        public ClassLoaderRepository getClassLoaderRepository() {
+            return new ClassLoaderRepository() {
+                public Class<?> loadClass(String className)
+                throws ClassNotFoundException {
+                    return clr.loadClass(className);
+                }
+
+                public Class<?> loadClassWithout(
+                        ClassLoader exclude, String className)
+                throws ClassNotFoundException {
+                    return clr.loadClassWithout(exclude, className);
+                }
+
+                public Class<?> loadClassBefore(
+                        ClassLoader stop, String className)
+                throws ClassNotFoundException {
+                    return clr.loadClassBefore(stop, className);
+                }
+            };
+        }
+
+        private static class ClassLoaderRepositoryImpl
+                extends ClassLoader implements ClassLoaderRepository {
+            private List<ClassLoader> loaders = newList();
+            {
+                loaders.add(this.getClass().getClassLoader());
+                // We also behave as if the system class loader were in
+                // the repository, since we do nothing to stop delegation
+                // to the parent, which is the system class loader, and
+                // that delegation happens before our findClass is called.
+            }
+
+            void addLoader(ClassLoader loader) {
+                loaders.add(loader);
+            }
+
+            void removeLoader(ClassLoader loader) {
+                if (!loaders.remove(loader))
+                    throw new RuntimeException("Loader was not in CLR!");
+            }
+
+            public Class<?> loadClassWithout(
+                    ClassLoader exclude, String className)
+                    throws ClassNotFoundException {
+                return loadClassWithoutBefore(exclude, null, className);
+            }
+
+            public Class<?> loadClassBefore(ClassLoader stop, String className)
+            throws ClassNotFoundException {
+                return loadClassWithoutBefore(null, stop, className);
+            }
+
+            private Class<?> loadClassWithoutBefore(
+                    ClassLoader exclude, ClassLoader stop, String className)
+                    throws ClassNotFoundException {
+                for (ClassLoader loader : loaders) {
+                    if (loader == exclude)
+                        continue;
+                    if (loader == stop)
+                        break;
+                    try {
+                        return Class.forName(className, false, loader);
+                    } catch (ClassNotFoundException e) {
+                        // OK: try others
+                    }
+                }
+                throw new ClassNotFoundException(className);
+            }
+
+            @Override
+            protected Class<?> findClass(String className)
+            throws ClassNotFoundException {
+                return loadClassWithout(null, className);
+            }
+        }
+
+        /* There is zero or one ListenerTable per MBean.
+         * The ListenerTable stuff is complicated.  We want to rewrite the
+         * source of notifications so that if the source of a notification
+         * from the MBean X is a reference to X itself, it gets replaced
+         * by X's ObjectName.  To do this, we wrap the user's listener in
+         * a RewriteListener.  But if the same listener is added a second
+         * time (perhaps with a different filter or handback) we must
+         * reuse the same RewriteListener so that the two-argument
+         * removeNotificationListener(ObjectName,NotificationListener) will
+         * correctly remove both listeners. This means we must remember the
+         * mapping from listener to WrappedListener.  But if the MBean
+         * discards its listeners (as a result of removeNL or spontaneously)
+         * then we don't want to keep a reference to the WrappedListener.
+         * So we have tons of WeakReferences.  The key in the ListenerTable
+         * is an IdentityListener, which wraps the user's listener to ensure
+         * that identity and not equality is used during the lookup, even if
+         * the user's listener has an equals method.  The value in the
+         * ListenerTable is a WeakReference wrapping a RewriteListener wrapping
+         * the same IdentityListener.  Since the RewriteListener is what is
+         * added to the user's MBean, the WeakReference won't disappear as long
+         * as the MBean still has this listener.  And since it references the
+         * IdentityListener, that won't disappear either.  But once the
+         * RewriteListener is no longer referenced by the user's MBean,
+         * there's nothing to stop its WeakReference from being cleared,
+         * and then corresponding IdentityListener that is now only weakly
+         * referenced from the key in the table.
+         */
+        private static class ListenerTable
+                extends WeakHashMap<NotificationListener,
+                                    WeakReference<NotificationListener>> {
+        }
+
+        private static class IdentityListener implements NotificationListener {
+            private final NotificationListener userListener;
+
+            IdentityListener(NotificationListener userListener) {
+                this.userListener = userListener;
+            }
+
+            public void handleNotification(
+                    Notification notification, Object handback) {
+                userListener.handleNotification(notification, handback);
+            }
+
+            @Override
+            public boolean equals(Object o) {
+                return (this == o);
+            }
+
+            @Override
+            public int hashCode() {
+                return System.identityHashCode(this);
+            }
+        }
+
+        private static class RewriteListener implements NotificationListener {
+            private final ObjectName name;
+            private final Object userMBean;
+            private final NotificationListener userListener;
+
+            RewriteListener(
+                    ObjectName name, Object userMBean,
+                    NotificationListener userListener) {
+                this.name = name;
+                this.userMBean = userMBean;
+                this.userListener = userListener;
+            }
+
+            public void handleNotification(
+                    Notification notification, Object handback) {
+                if (notification.getSource() == userMBean)
+                    notification.setSource(name);
+                userListener.handleNotification(notification, handback);
+            }
+        }
+
+        private NotificationListener wrappedListener(
+                ObjectName name, Object userMBean, NotificationListener userListener)
+        throws InstanceNotFoundException {
+            ListenerTable table = new ListenerTable();
+            ListenerTable oldTable = listenerMap.putIfAbsent(name, table);
+            if (oldTable != null)
+                table = oldTable;
+            NotificationListener identityListener =
+                    new IdentityListener(userListener);
+            synchronized (table) {
+                NotificationListener rewriteListener = null;
+                WeakReference<NotificationListener> wr =
+                        table.get(identityListener);
+                if (wr != null)
+                    rewriteListener = wr.get();
+                if (rewriteListener == null) {
+                    rewriteListener = new RewriteListener(
+                            name, userMBean, identityListener);
+                    wr = new WeakReference<NotificationListener>(rewriteListener);
+                    table.put(identityListener, wr);
+                }
+                return rewriteListener;
+            }
+        }
+
+        private DynamicMBean getMBean(ObjectName name)
+        throws InstanceNotFoundException {
+            DynamicMBean mbean = mbeans.get(name);
+            if (mbean == null)
+                throw new InstanceNotFoundException(name.toString());
+            return mbean;
+        }
+
+        private static interface WrapDynamicMBean extends DynamicMBean {
+            public Object getWrappedMBean();
+        }
+
+        private static class StandardWrapper
+                implements WrapDynamicMBean, MBeanRegistration {
+            private final Map<String, AttrMethods> attrMap = newMap();
+            private final Map<String, List<Method>> opMap = newMap();
+            private static class AttrMethods {
+                Method getter, setter;
+            }
+
+            private final Object std;
+
+            StandardWrapper(Object std) throws NotCompliantMBeanException {
+                this.std = std;
+                Class<?> intf = mbeanInterface(std.getClass());
+                try {
+                    initMaps(intf);
+                } catch (NotCompliantMBeanException e) {
+                    throw e;
+                } catch (Exception e) {
+                    NotCompliantMBeanException x =
+                            new NotCompliantMBeanException(e.getMessage());
+                    x.initCause(e);
+                    throw x;
+                }
+            }
+
+            private static Class<?> mbeanInterface(Class<?> c)
+            throws NotCompliantMBeanException {
+                do {
+                    Class<?>[] intfs = c.getInterfaces();
+                    String intfName = c.getName() + "MBean";
+                    for (Class<?> intf : intfs) {
+                        if (intf.getName().equals(intfName))
+                            return intf;
+                    }
+                    c = c.getSuperclass();
+                } while (c != null);
+                throw new NotCompliantMBeanException(
+                        "Does not match Standard or Dynamic MBean patterns: " +
+                        c.getName());
+            }
+
+            private void initMaps(Class<?> intf) throws NotCompliantMBeanException {
+                Method[] methods = intf.getMethods();
+
+                for (Method m : methods) {
+                    final String name = m.getName();
+                    final int nParams = m.getParameterTypes().length;
+
+                    String attrName = "";
+                    if (name.startsWith("get"))
+                        attrName = name.substring(3);
+                    else if (name.startsWith("is")
+                    && m.getReturnType() == boolean.class)
+                        attrName = name.substring(2);
+
+                    if (attrName.length() != 0 && m.getParameterTypes().length == 0
+                            && m.getReturnType() != void.class) {
+                        // It's a getter
+                        // Check we don't have both isX and getX
+                        AttrMethods am = attrMap.get(attrName);
+                        if (am == null)
+                            am = new AttrMethods();
+                        else {
+                            if (am.getter != null) {
+                                final String msg = "Attribute " + attrName +
+                                        " has more than one getter";
+                                throw new NotCompliantMBeanException(msg);
+                            }
+                        }
+                        am.getter = m;
+                        attrMap.put(attrName, am);
+                    } else if (name.startsWith("set") && name.length() > 3
+                            && m.getParameterTypes().length == 1 &&
+                            m.getReturnType() == void.class) {
+                        // It's a setter
+                        attrName = name.substring(3);
+                        AttrMethods am = attrMap.get(attrName);
+                        if (am == null)
+                            am = new AttrMethods();
+                        else if (am.setter != null) {
+                            final String msg = "Attribute " + attrName +
+                                    " has more than one setter";
+                            throw new NotCompliantMBeanException(msg);
+                        }
+                        am.setter = m;
+                        attrMap.put(attrName, am);
+                    } else {
+                        // It's an operation
+                        List<Method> ops = opMap.get(name);
+                        if (ops == null)
+                            ops = newList();
+                        ops.add(m);
+                        opMap.put(name, ops);
+                    }
+                }
+                /* Check that getters and setters are consistent. */
+                for (Map.Entry<String, AttrMethods> entry : attrMap.entrySet()) {
+                    AttrMethods am = entry.getValue();
+                    if (am.getter != null && am.setter != null &&
+                            am.getter.getReturnType() != am.setter.getParameterTypes()[0]) {
+                        final String msg = "Getter and setter for " + entry.getKey() +
+                                " have inconsistent types";
+                        throw new NotCompliantMBeanException(msg);
+                    }
+                }
+            }
+
+            public Object getAttribute(String attribute)
+            throws AttributeNotFoundException, MBeanException, ReflectionException {
+                AttrMethods am = attrMap.get(attribute);
+                if (am == null || am.getter == null)
+                    throw new AttributeNotFoundException(attribute);
+                return invokeMethod(am.getter);
+            }
+
+            public void setAttribute(Attribute attribute)
+            throws AttributeNotFoundException, InvalidAttributeValueException,
+                    MBeanException, ReflectionException {
+                String name = attribute.getName();
+                AttrMethods am = attrMap.get(name);
+                if (am == null || am.setter == null)
+                    throw new AttributeNotFoundException(name);
+                invokeMethod(am.setter, attribute.getValue());
+            }
+
+            public AttributeList getAttributes(String[] attributes) {
+                AttributeList list = new AttributeList();
+                for (String attr : attributes) {
+                    try {
+                        list.add(new Attribute(attr, getAttribute(attr)));
+                    } catch (Exception e) {
+                        // OK: ignore per spec
+                    }
+                }
+                return list;
+            }
+
+            public AttributeList setAttributes(AttributeList attributes) {
+                AttributeList list = new AttributeList();
+                // We carefully avoid using any new stuff from AttributeList here!
+                for (Iterator<?> it = attributes.iterator(); it.hasNext(); ) {
+                    Attribute attr = (Attribute) it.next();
+                    try {
+                        setAttribute(attr);
+                        list.add(attr);
+                    } catch (Exception e) {
+                        // OK: ignore per spec
+                    }
+                }
+                return list;
+            }
+
+            public Object invoke(String actionName, Object[] params, String[] signature)
+            throws MBeanException, ReflectionException {
+                if (params == null)
+                    params = new Object[0];
+                if (signature == null)
+                    signature = new String[0];
+                List<Method> methods = opMap.get(actionName);
+                if (methods == null) {
+                    Exception x = new NoSuchMethodException(actionName);
+                    throw new MBeanException(x);
+                }
+                Method found = null;
+                methodloop:
+                for (Method m : methods) {
+                    Class<?>[] msig = m.getParameterTypes();
+                    if (msig.length != signature.length)
+                        continue methodloop;
+                    for (int i = 0; i < msig.length; i++) {
+                        if (!msig[i].getName().equals(signature[i]))
+                            continue methodloop;
+                    }
+                    found = m;
+                    break methodloop;
+                }
+                if (found == null) {
+                    Exception x = new NoSuchMethodException(
+                            actionName + Arrays.toString(signature));
+                    throw new MBeanException(x);
+                }
+                return invokeMethod(found, params);
+            }
+
+            public MBeanInfo getMBeanInfo() {
+                // Attributes
+                List<MBeanAttributeInfo> attrs = newList();
+                for (Map.Entry<String, AttrMethods> attr : attrMap.entrySet()) {
+                    String name = attr.getKey();
+                    AttrMethods am = attr.getValue();
+                    try {
+                        attrs.add(new MBeanAttributeInfo(
+                                name, name, am.getter, am.setter));
+                    } catch (IntrospectionException e) { // grrr
+                        throw new RuntimeException(e);
+                    }
+                }
+
+                // Operations
+                List<MBeanOperationInfo> ops = newList();
+                for (Map.Entry<String, List<Method>> op : opMap.entrySet()) {
+                    String name = op.getKey();
+                    List<Method> methods = op.getValue();
+                    for (Method m : methods)
+                        ops.add(new MBeanOperationInfo(name, m));
+                }
+
+                // Constructors
+                List<MBeanConstructorInfo> constrs = newList();
+                for (Constructor constr : std.getClass().getConstructors())
+                    constrs.add(new MBeanConstructorInfo("Constructor", constr));
+
+                // Notifications
+                MBeanNotificationInfo[] notifs;
+                if (std instanceof NotificationBroadcaster)
+                    notifs = ((NotificationBroadcaster) std).getNotificationInfo();
+                else
+                    notifs = null;
+
+                String className = std.getClass().getName();
+                return new MBeanInfo(
+                        className, className,
+                        attrs.toArray(new MBeanAttributeInfo[0]),
+                        constrs.toArray(new MBeanConstructorInfo[0]),
+                        ops.toArray(new MBeanOperationInfo[0]),
+                        notifs);
+            }
+
+            private Object invokeMethod(Method m, Object... args)
+            throws MBeanException, ReflectionException {
+                return invokeSomething(m, std,args);
+            }
+
+            public ObjectName preRegister(MBeanServer server, ObjectName name)
+            throws Exception {
+                return mbeanRegistration(std).preRegister(server, name);
+            }
+
+            public void postRegister(Boolean registrationDone) {
+                mbeanRegistration(std).postRegister(registrationDone);
+            }
+
+            public void preDeregister() throws Exception {
+                mbeanRegistration(std).preDeregister();
+            }
+
+            public void postDeregister() {
+                mbeanRegistration(std).postDeregister();
+            }
+
+            public Object getWrappedMBean() {
+                return std;
+            }
+        }
+
+        private DynamicMBean standardToDynamic(Object std)
+        throws NotCompliantMBeanException {
+            return new StandardWrapper(std);
+        }
+
+//        private static class NotifWrapper
+//                implements WrapDynamicMBean, NotificationEmitter {
+//            private final DynamicMBean mbean;
+//
+//            NotifWrapper(DynamicMBean mbean) {
+//                this.mbean = mbean;
+//            }
+//
+//            public Object getAttribute(String attribute)
+//            throws AttributeNotFoundException, MBeanException, ReflectionException {
+//                return mbean.getAttribute(attribute);
+//            }
+//
+//            public void setAttribute(Attribute attribute)
+//            throws AttributeNotFoundException, InvalidAttributeValueException,
+//                    MBeanException, ReflectionException {
+//                mbean.setAttribute(attribute);
+//            }
+//
+//            public AttributeList getAttributes(String[] attributes) {
+//                return mbean.getAttributes(attributes);
+//            }
+//
+//            public AttributeList setAttributes(AttributeList attributes) {
+//                return mbean.setAttributes(attributes);
+//            }
+//
+//            public Object invoke(
+//                    String actionName, Object[] params, String[] signature)
+//                    throws MBeanException, ReflectionException {
+//                return mbean.invoke(actionName, params, signature);
+//            }
+//
+//            public MBeanInfo getMBeanInfo() {
+//                return mbean.getMBeanInfo();
+//            }
+//
+//            public void removeNotificationListener(
+//                    NotificationListener listener, NotificationFilter filter, Object handback)
+//            throws ListenerNotFoundException {
+//                ((NotificationEmitter) mbean).removeNotificationListener(
+//                        listener, filter, handback);
+//                // ClassCastException if MBean is not an emitter
+//            }
+//
+//            public void addNotificationListener(
+//                    NotificationListener listener, NotificationFilter filter, Object handback)
+//            throws IllegalArgumentException {
+//                ((NotificationBroadcaster) mbean).addNotificationListener(
+//                        listener, filter, handback);
+//            }
+//
+//            public void removeNotificationListener(NotificationListener listener)
+//            throws ListenerNotFoundException {
+//                ((NotificationBroadcaster) mbean).removeNotificationListener(listener);
+//            }
+//
+//            public MBeanNotificationInfo[] getNotificationInfo() {
+//                return ((NotificationBroadcaster) mbean).getNotificationInfo();
+//            }
+//
+//            public Object getWrappedMBean() {
+//                return getUserMBean(mbean);
+//            }
+//        }
+
+        private static Object invokeSomething(
+                AccessibleObject ao, Object target, Object[] args)
+        throws MBeanException, ReflectionException {
+            try {
+                if (ao instanceof Method)
+                    return ((Method) ao).invoke(target, args);
+                else
+                    return ((Constructor) ao).newInstance(args);
+            } catch (InvocationTargetException e) {
+                try {
+                    throw e.getCause();
+                } catch (RuntimeException x) {
+                    throw new RuntimeMBeanException(x);
+                } catch (Error x) {
+                    throw new RuntimeErrorException(x);
+                } catch (Exception x) {
+                    throw new MBeanException(x);
+                } catch (Throwable x) {
+                    throw new RuntimeException(x); // neither Error nor Exception!
+                }
+            } catch (Exception e) {
+                throw new ReflectionException(e);
+            }
+        }
+
+        private static Object getUserMBean(DynamicMBean mbean) {
+            if (mbean instanceof WrapDynamicMBean)
+                return ((WrapDynamicMBean) mbean).getWrappedMBean();
+            return mbean;
+        }
+
+        private Object getUserMBean(ObjectName name)
+        throws InstanceNotFoundException {
+            return getUserMBean(getMBean(name));
+        }
+
+        private static final MBeanRegistration noRegistration =
+                new MBeanRegistration() {
+            public ObjectName preRegister(MBeanServer server, ObjectName name) {
+                return name;
+            }
+
+            public void postRegister(Boolean registrationDone) {
+            }
+
+            public void preDeregister() throws Exception {
+            }
+
+            public void postDeregister() {
+            }
+        };
+
+        private static MBeanRegistration mbeanRegistration(Object object) {
+            if (object instanceof MBeanRegistration)
+                return (MBeanRegistration) object;
+            else
+                return noRegistration;
+        }
+
+        private static <E> List<E> newList() {
+            return new ArrayList<E>();
+        }
+
+        private static <K, V> Map<K, V> newMap() {
+            return new HashMap<K, V>();
+        }
+
+        private static <E> Set<E> newSet() {
+            return new HashSet<E>();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/MBeanServer/PostExceptionTest.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,516 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @bug 6730926
+ * @summary Check behaviour of MBeanServer when postRegister and postDeregister
+ *          throw exceptions.
+ * @author Daniel Fuchs
+ * @compile PostExceptionTest.java
+ * @run main PostExceptionTest
+ */
+
+import javax.management.*;
+import java.io.Serializable;
+import java.net.URL;
+import java.util.EnumSet;
+import javax.management.loading.MLet;
+
+public class PostExceptionTest {
+
+    /**
+     * A test case where we instantiate an ExceptionalWombatMBean (or a
+     * subclass of it) which will throw the exception {@code t} from within
+     * the methods indicated by {@code where}
+     */
+    public static class Case {
+        public final Throwable t;
+        public final EnumSet<WHERE> where;
+        public Case(Throwable t,EnumSet<WHERE> where) {
+            this.t=t; this.where=where;
+        }
+    }
+
+    // Various methods to create an instance of Case in a single line
+    // --------------------------------------------------------------
+
+    public static Case caze(Throwable t, WHERE w) {
+        return new Case(t,EnumSet.of(w));
+    }
+    public static Case caze(Throwable t, EnumSet<WHERE> where) {
+        return new Case(t,where);
+    }
+    public static Case caze(Throwable t, WHERE w, WHERE... rest) {
+        return new Case(t,EnumSet.of(w,rest));
+    }
+
+    /**
+     * Here is the list of our test cases:
+     */
+    public static Case[] cases ={
+        caze(new RuntimeException(),WHERE.PREREGISTER),
+        caze(new RuntimeException(),WHERE.POSTREGISTER),
+        caze(new RuntimeException(),WHERE.POSTREGISTER, WHERE.PREDEREGISTER),
+        caze(new RuntimeException(),WHERE.POSTREGISTER, WHERE.POSTDEREGISTER),
+        caze(new Exception(),WHERE.PREREGISTER),
+        caze(new Exception(),WHERE.POSTREGISTER),
+        caze(new Exception(),WHERE.POSTREGISTER, WHERE.PREDEREGISTER),
+        caze(new Exception(),WHERE.POSTREGISTER, WHERE.POSTDEREGISTER),
+        caze(new Error(),WHERE.PREREGISTER),
+        caze(new Error(),WHERE.POSTREGISTER),
+        caze(new Error(),WHERE.POSTREGISTER, WHERE.PREDEREGISTER),
+        caze(new Error(),WHERE.POSTREGISTER, WHERE.POSTDEREGISTER),
+        caze(new RuntimeException(),EnumSet.allOf(WHERE.class)),
+        caze(new Exception(),EnumSet.allOf(WHERE.class)),
+        caze(new Error(),EnumSet.allOf(WHERE.class)),
+    };
+
+    public static void main(String[] args) throws Exception {
+        System.out.println("Test behaviour of MBeanServer when postRegister " +
+                "or postDeregister throw exceptions");
+        MBeanServer mbs = MBeanServerFactory.newMBeanServer();
+        int failures = 0;
+        final ObjectName n = new ObjectName("test:type=Wombat");
+
+        // We're going to test each cases, using each of the 4 createMBean
+        // forms + registerMBean in turn to create the MBean.
+        // Wich method is used to create the MBean is indicated by "how"
+        //
+        for (Case caze:cases) {
+            for (CREATE how : CREATE.values()) {
+                failures+=test(mbs,n,how,caze.t,caze.where);
+            }
+        }
+        if (failures == 0)
+            System.out.println("Test passed");
+        else {
+            System.out.println("TEST FAILED: " + failures + " failure(s)");
+            System.exit(1);
+        }
+    }
+
+    // Execute a test case composed of:
+    // mbs:   The MBeanServer where the MBean will be registered,
+    // name:  The name of that MBean
+    // how:   How will the MBean be created/registered (which MBeanServer
+    //        method)
+    // t:     The exception/error that the MBean will throw
+    // where: In which pre/post register/deregister method the exception/error
+    //        will be thrown
+    //
+    private static int test(MBeanServer mbs, ObjectName name, CREATE how,
+            Throwable t, EnumSet<WHERE> where)
+            throws Exception {
+        System.out.println("-------<"+how+"> / <"+t+"> / "+ where + "-------");
+
+        int failures = 0;
+        ObjectInstance oi = null;
+        Exception reg = null;    // exception thrown by create/register
+        Exception unreg = null;  // exception thrown by unregister
+        try {
+            // Create the MBean
+            oi = how.create(t, where, mbs, name);
+        } catch (Exception xx) {
+            reg=xx;
+        }
+        final ObjectName n = (oi==null)?name:oi.getObjectName();
+        final boolean isRegistered = mbs.isRegistered(n);
+        try {
+            // If the MBean is registered, unregister it
+            if (isRegistered) mbs.unregisterMBean(n);
+        } catch (Exception xxx) {
+            unreg=xxx;
+        }
+        final boolean isUnregistered = !mbs.isRegistered(n);
+        if (!isUnregistered) {
+            // if the MBean is still registered (preDeregister threw an
+            // exception) signify to the MBean that it now should stop
+            // throwing anaything and unregister it.
+            JMX.newMBeanProxy(mbs, n, ExceptionalWombatMBean.class).end();
+            mbs.unregisterMBean(n);
+        }
+
+        // Now analyze the result. If we didn't ask the MBean to throw any
+        // exception then reg should be null.
+        if (where.isEmpty() && reg!=null) {
+            System.out.println("Unexpected registration exception: "+
+                    reg);
+            throw new RuntimeException("Unexpected registration exception: "+
+                    reg,reg);
+        }
+
+        // If we didn't ask the MBean to throw any exception then unreg should
+        // also be null.
+        if (where.isEmpty() && unreg!=null) {
+            System.out.println("Unexpected unregistration exception: "+
+                    unreg);
+            throw new RuntimeException("Unexpected unregistration exception: "+
+                    unreg,unreg);
+        }
+
+        // If we asked the MBean to throw an exception in either of preRegister
+        // or postRegister, then reg should not be null.
+        if ((where.contains(WHERE.PREREGISTER)
+            || where.contains(WHERE.POSTREGISTER))&& reg==null) {
+            System.out.println("Expected registration exception not " +
+                    "thrown by "+where);
+            throw new RuntimeException("Expected registration exception not " +
+                    "thrown by "+where);
+        }
+
+        // If we asked the MBean not to throw any exception in preRegister
+        // then the MBean should have been registered, unregisterMBean should
+        // have been called.
+        // If we asked the MBean to throw an exception in either of preDeregister
+        // or postDeregister, then unreg should not be null.
+        if ((where.contains(WHERE.PREDEREGISTER)
+            || where.contains(WHERE.POSTDEREGISTER))&& unreg==null
+            && !where.contains(WHERE.PREREGISTER)) {
+            System.out.println("Expected unregistration exception not " +
+                    "thrown by "+where);
+            throw new RuntimeException("Expected unregistration exception not " +
+                    "thrown by "+where);
+        }
+
+        // If we asked the MBean to throw an exception in preRegister
+        // then the MBean should not have been registered.
+        if (where.contains(WHERE.PREREGISTER)) {
+            if (isRegistered) {
+                System.out.println("MBean is still registered [" +
+                        where+
+                        "]: "+name+" / "+reg);
+                throw new RuntimeException("MBean is still registered [" +
+                        where+
+                        "]: "+name+" / "+reg,reg);
+            }
+        }
+
+        // If we asked the MBean not to throw an exception in preRegister,
+        // but to throw an exception in postRegister, then the MBean should
+        // have been registered.
+        if (where.contains(WHERE.POSTREGISTER) &&
+                !where.contains(WHERE.PREREGISTER)) {
+            if (!isRegistered) {
+                System.out.println("MBean is already unregistered [" +
+                        where+
+                        "]: "+name+" / "+reg);
+                throw new RuntimeException("MBean is already unregistered [" +
+                        where+
+                        "]: "+name+" / "+reg,reg);
+            }
+        }
+
+        // If we asked the MBean to throw an exception in preRegister,
+        // check that the exception we caught was as expected.
+        //
+        if (where.contains(WHERE.PREREGISTER)) {
+            WHERE.PREREGISTER.check(reg, t);
+        } else if (where.contains(WHERE.POSTREGISTER)) {
+            // If we asked the MBean to throw an exception in postRegister,
+            // check that the exception we caught was as expected.
+            // We don't do this check if we asked the MBean to also throw an
+            // exception in pre register, because postRegister will not have
+            // been called.
+            WHERE.POSTREGISTER.check(reg, t);
+        }
+
+        if (!isRegistered) return failures;
+
+        // The MBean was registered, so unregisterMBean was called. Check
+        // unregisterMBean exceptions...
+        //
+
+        // If we asked the MBean to throw an exception in preDeregister
+        // then the MBean should not have been deregistered.
+        if (where.contains(WHERE.PREDEREGISTER)) {
+            if (isUnregistered) {
+                System.out.println("MBean is already unregistered [" +
+                        where+
+                        "]: "+name+" / "+unreg);
+                throw new RuntimeException("MBean is already unregistered [" +
+                        where+
+                        "]: "+name+" / "+unreg,unreg);
+            }
+        }
+
+        // If we asked the MBean not to throw an exception in preDeregister,
+        // but to throw an exception in postDeregister, then the MBean should
+        // have been deregistered.
+        if (where.contains(WHERE.POSTDEREGISTER) &&
+                !where.contains(WHERE.PREDEREGISTER)) {
+            if (!isUnregistered) {
+                System.out.println("MBean is not unregistered [" +
+                        where+
+                        "]: "+name+" / "+unreg);
+                throw new RuntimeException("MBean is not unregistered [" +
+                        where+
+                        "]: "+name+" / "+unreg,unreg);
+            }
+        }
+
+        // If we asked the MBean to throw an exception in preDeregister,
+        // check that the exception we caught was as expected.
+        //
+        if (where.contains(WHERE.PREDEREGISTER)) {
+            WHERE.PREDEREGISTER.check(unreg, t);
+        } else if (where.contains(WHERE.POSTDEREGISTER)) {
+            // If we asked the MBean to throw an exception in postDeregister,
+            // check that the exception we caught was as expected.
+            // We don't do this check if we asked the MBean to also throw an
+            // exception in pre register, because postRegister will not have
+            // been called.
+            WHERE.POSTDEREGISTER.check(unreg, t);
+        }
+        return failures;
+    }
+
+    /**
+     * This enum lists the 4 methods in MBeanRegistration.
+     */
+    public static enum WHERE {
+
+        PREREGISTER, POSTREGISTER, PREDEREGISTER, POSTDEREGISTER;
+
+        // Checks that an exception thrown by the MBeanServer correspond to
+        // what is expected when an MBean throws an exception in this
+        // MBeanRegistration method ("this" is one of the 4 enum values above)
+        //
+        public void check(Exception thrown, Throwable t)
+                throws Exception {
+           if (t instanceof RuntimeException) {
+               if (!(thrown instanceof RuntimeMBeanException)) {
+                   System.out.println("Expected RuntimeMBeanException, got "+
+                           thrown);
+                   throw new Exception("Expected RuntimeMBeanException, got "+
+                           thrown);
+               }
+           } else if (t instanceof Error) {
+               if (!(thrown instanceof RuntimeErrorException)) {
+                   System.out.println("Expected RuntimeErrorException, got "+
+                           thrown);
+                   throw new Exception("Expected RuntimeErrorException, got "+
+                           thrown);
+               }
+           } else if (t instanceof Exception) {
+               if (EnumSet.of(POSTDEREGISTER,POSTREGISTER).contains(this)) {
+                   if (!(thrown instanceof RuntimeMBeanException)) {
+                       System.out.println("Expected RuntimeMBeanException, got "+
+                           thrown);
+                       throw new Exception("Expected RuntimeMBeanException, got "+
+                           thrown);
+                   }
+                   if (! (thrown.getCause() instanceof RuntimeException)) {
+                       System.out.println("Bad cause: " +
+                               "expected RuntimeException, " +
+                           "got <"+thrown.getCause()+">");
+                       throw new Exception("Bad cause: " +
+                               "expected RuntimeException, " +
+                           "got <"+thrown.getCause()+">");
+                   }
+               }
+               if (EnumSet.of(PREDEREGISTER,PREREGISTER).contains(this)) {
+                   if (!(thrown instanceof MBeanRegistrationException)) {
+                       System.out.println("Expected " +
+                               "MBeanRegistrationException, got "+
+                           thrown);
+                       throw new Exception("Expected " +
+                               "MBeanRegistrationException, got "+
+                           thrown);
+                   }
+                   if (! (thrown.getCause() instanceof Exception)) {
+                       System.out.println("Bad cause: " +
+                               "expected Exception, " +
+                           "got <"+thrown.getCause()+">");
+                       throw new Exception("Bad cause: " +
+                               "expected Exception, " +
+                           "got <"+thrown.getCause()+">");
+                   }
+               }
+           }
+
+        }
+    }
+
+    /**
+     * This enum lists the 5 methods to create and register an
+     * ExceptionalWombat MBean
+     */
+    public static enum CREATE {
+
+        CREATE1() {
+            // Creates an ExceptionalWombat MBean using createMBean form #1
+            public ObjectInstance create(Throwable t, EnumSet<WHERE> where,
+                    MBeanServer server, ObjectName name) throws Exception {
+                ExceptionallyHackyWombat.t = t;
+                ExceptionallyHackyWombat.w = where;
+                return server.createMBean(
+                        ExceptionallyHackyWombat.class.getName(),
+                        name);
+            }
+        },
+        CREATE2() {
+            // Creates an ExceptionalWombat MBean using createMBean form #2
+            public ObjectInstance create(Throwable t, EnumSet<WHERE> where,
+                    MBeanServer server, ObjectName name) throws Exception {
+                ExceptionallyHackyWombat.t = t;
+                ExceptionallyHackyWombat.w = where;
+                final ObjectName loaderName = registerMLet(server);
+                return server.createMBean(
+                        ExceptionallyHackyWombat.class.getName(),
+                        name, loaderName);
+            }
+        },
+        CREATE3() {
+            // Creates an ExceptionalWombat MBean using createMBean form #3
+            public ObjectInstance create(Throwable t, EnumSet<WHERE> where,
+                    MBeanServer server, ObjectName name) throws Exception {
+                final Object[] params = {t, where};
+                final String[] signature = {Throwable.class.getName(),
+                    EnumSet.class.getName()
+                };
+                return server.createMBean(
+                        ExceptionalWombat.class.getName(), name,
+                        params, signature);
+            }
+        },
+        CREATE4() {
+            // Creates an ExceptionalWombat MBean using createMBean form #4
+            public ObjectInstance create(Throwable t, EnumSet<WHERE> where,
+                    MBeanServer server, ObjectName name) throws Exception {
+                final Object[] params = {t, where};
+                final String[] signature = {Throwable.class.getName(),
+                    EnumSet.class.getName()
+                };
+                return server.createMBean(
+                        ExceptionalWombat.class.getName(), name,
+                        registerMLet(server), params, signature);
+            }
+        },
+        REGISTER() {
+            // Creates an ExceptionalWombat MBean using registerMBean
+            public ObjectInstance create(Throwable t, EnumSet<WHERE> where,
+                    MBeanServer server, ObjectName name) throws Exception {
+                final ExceptionalWombat wombat =
+                        new ExceptionalWombat(t, where);
+                return server.registerMBean(wombat, name);
+            }
+        };
+
+        // Creates an ExceptionalWombat MBean using the method denoted by this
+        // Enum value - one of CREATE1, CREATE2, CREATE3, CREATE4, or REGISTER.
+        public abstract ObjectInstance create(Throwable t, EnumSet<WHERE> where,
+                MBeanServer server, ObjectName name) throws Exception;
+
+        // This is a bit of a hack - we use an MLet that delegates to the
+        // System ClassLoader so that we can use createMBean form #2 and #3
+        // while still using the same class loader (system).
+        // This is necessary to make the ExceptionallyHackyWombatMBean work ;-)
+        //
+        public ObjectName registerMLet(MBeanServer server) throws Exception {
+            final ObjectName name = new ObjectName("test:type=MLet");
+            if (server.isRegistered(name)) {
+                return name;
+            }
+            final MLet mlet = new MLet(new URL[0],
+                    ClassLoader.getSystemClassLoader());
+            return server.registerMBean(mlet, name).getObjectName();
+        }
+    }
+
+    /**
+     *A Wombat MBean that can throw exceptions or errors in any of the
+     * MBeanRegistration methods.
+     */
+    public static interface ExceptionalWombatMBean {
+        // Tells the MBean to stop throwing exceptions - we sometime
+        // need to call this at the end of the test so that we can
+        // actually unregister the MBean.
+        public void end();
+    }
+
+    /**
+     *A Wombat MBean that can throw exceptions or errors in any of the
+     * MBeanRegistration methods.
+     */
+    public static class ExceptionalWombat
+            implements ExceptionalWombatMBean, MBeanRegistration {
+
+        private final Throwable throwable;
+        private final EnumSet<WHERE> where;
+        private volatile boolean end=false;
+
+        public ExceptionalWombat(Throwable t, EnumSet<WHERE> where) {
+            this.throwable=t; this.where=where;
+        }
+        private Exception doThrow() {
+            if (throwable instanceof Error)
+                throw (Error)throwable;
+            if (throwable instanceof RuntimeException)
+                throw (RuntimeException)throwable;
+            return (Exception)throwable;
+        }
+        public ObjectName preRegister(MBeanServer server, ObjectName name)
+                throws Exception {
+            if (!end && where.contains(WHERE.PREREGISTER))
+                throw doThrow();
+            return name;
+        }
+
+        public void postRegister(Boolean registrationDone) {
+            if (!end && where.contains(WHERE.POSTREGISTER))
+                throw new RuntimeException(doThrow());
+        }
+
+        public void preDeregister() throws Exception {
+            if (!end && where.contains(WHERE.PREDEREGISTER))
+                throw doThrow();
+        }
+
+        public void postDeregister() {
+            if (!end && where.contains(WHERE.POSTREGISTER))
+                throw new RuntimeException(doThrow());
+        }
+
+        public void end() {
+            this.end=true;
+        }
+    }
+
+    /**
+     * This is a big ugly hack to call createMBean form #1 and #2 - where
+     * the empty constructor is used. Since we still want to supply parameters
+     * to the ExceptionalWombat super class, we temporarily store these
+     * parameter value in a static volatile before calling create MBean.
+     * Of course this only works because our test is sequential and single
+     * threaded, and nobody but our test uses this ExceptionallyHackyWombat.
+     */
+    public static class ExceptionallyHackyWombat extends ExceptionalWombat {
+        public static volatile Throwable  t;
+        public static volatile EnumSet<WHERE> w;
+        public ExceptionallyHackyWombat() {
+            super(t,w);
+        }
+    }
+
+}
--- a/jdk/test/javax/management/ObjectName/SerialCompatTest.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/test/javax/management/ObjectName/SerialCompatTest.java	Wed Jul 05 16:40:29 2017 +0200
@@ -23,9 +23,9 @@
 
 /*
  * @test
- * @bug 6211220
+ * @bug 6211220 6616825
  * @summary Test that jmx.serial.form=1.0 works for ObjectName
- * @author Eamonn McManus
+ * @author Eamonn McManus, Daniel Fuchs
  * @run clean SerialCompatTest
  * @run build SerialCompatTest
  * @run main/othervm SerialCompatTest
@@ -36,19 +36,8 @@
 import javax.management.ObjectName;
 
 public class SerialCompatTest {
-    public static void main(String[] args) throws Exception {
-        System.setProperty("jmx.serial.form", "1.0");
 
-        /* Check that we really are in jmx.serial.form=1.0 mode.
-           The property is frozen the first time the ObjectName class
-           is referenced so checking that it is set to the correct
-           value now is not enough.  */
-        ObjectStreamClass osc = ObjectStreamClass.lookup(ObjectName.class);
-        if (osc.getFields().length != 6) {
-            throw new Exception("Not using old serial form: fields: " +
-                                Arrays.asList(osc.getFields()));
-            // new serial form has no fields, uses writeObject
-        }
+    public static void check6211220() throws Exception {
 
         ObjectName on = new ObjectName("a:b=c");
         ByteArrayOutputStream bos = new ByteArrayOutputStream();
@@ -62,56 +51,214 @@
 
         // if the bug is present, these will get NullPointerException
         for (int i = 0; i <= 11; i++) {
+            String msg = "6211220 case(" + i + ")";
             try {
                 switch (i) {
-                case 0:
-                    check(on1.getDomain().equals("a")); break;
-                case 1:
-                    check(on1.getCanonicalName().equals("a:b=c")); break;
-                case 2:
-                    check(on1.getKeyPropertyListString().equals("b=c")); break;
-                case 3:
-                    check(on1.getCanonicalKeyPropertyListString().equals("b=c"));
-                    break;
-                case 4:
-                    check(on1.getKeyProperty("b").equals("c")); break;
-                case 5:
-                    check(on1.getKeyPropertyList()
-                          .equals(Collections.singletonMap("b", "c"))); break;
-                case 6:
-                    check(!on1.isDomainPattern()); break;
-                case 7:
-                    check(!on1.isPattern()); break;
-                case 8:
-                    check(!on1.isPropertyPattern()); break;
-                case 9:
-                    check(on1.equals(on)); break;
-                case 10:
-                    check(on.equals(on1)); break;
-                case 11:
-                    check(on1.apply(on)); break;
-                default:
-                    throw new Exception("Test incorrect: case: " + i);
+                    case 0:
+                        check(msg, on1.getDomain().equals("a"));
+                        break;
+                    case 1:
+                        check(msg, on1.getCanonicalName().equals("a:b=c"));
+                        break;
+                    case 2:
+                        check(msg, on1.getKeyPropertyListString()
+                                .equals("b=c"));
+                        break;
+                    case 3:
+                        check(msg, on1.getCanonicalKeyPropertyListString()
+                                .equals("b=c"));
+                        break;
+                    case 4:
+                        check(msg, on1.getKeyProperty("b").equals("c"));
+                        break;
+                    case 5:
+                        check(msg, on1.getKeyPropertyList()
+                                .equals(Collections.singletonMap("b", "c")));
+                        break;
+                    case 6:
+                        check(msg, !on1.isDomainPattern());
+                        break;
+                    case 7:
+                        check(msg, !on1.isPattern());
+                        break;
+                    case 8:
+                        check(msg, !on1.isPropertyPattern());
+                        break;
+                    case 9:
+                        check(msg, on1.equals(on));
+                        break;
+                    case 10:
+                        check(msg, on.equals(on1));
+                        break;
+                    case 11:
+                        check(msg, on1.apply(on));
+                        break;
+                    default:
+                        throw new Exception(msg + ": Test incorrect");
                 }
             } catch (Exception e) {
-                System.out.println("Test failed with exception:");
+                System.out.println(msg + ": Test failed with exception:");
                 e.printStackTrace(System.out);
                 failed = true;
             }
         }
 
-        if (failed)
-            throw new Exception("Some tests failed");
-        else
-            System.out.println("All tests passed");
+        if (failed) {
+            throw new Exception("Some tests for 6211220 failed");
+        } else {
+            System.out.println("All tests for 6211220 passed");
+        }
     }
 
-    private static void check(boolean condition) {
+    static void checkName(String testname, ObjectName on)
+            throws Exception {
+        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        ObjectOutputStream oos = new ObjectOutputStream(bos);
+        oos.writeObject(on);
+        oos.close();
+        byte[] bytes = bos.toByteArray();
+        ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
+        ObjectInputStream ois = new ObjectInputStream(bis);
+        ObjectName on1 = (ObjectName) ois.readObject();
+        // if the bug is present, these will get NullPointerException
+        for (int i = 0; i <= 11; i++) {
+            String msg = testname + " case(" + i + ")";
+            try {
+                switch (i) {
+                    case 0:
+                        check(msg, on1.getDomain().equals(on.getDomain()));
+                        break;
+                    case 1:
+                        check(msg, on1.getCanonicalName().
+                                equals(on.getCanonicalName()));
+                        break;
+                    case 2:
+                        check(msg, on1.getKeyPropertyListString().
+                                equals(on.getKeyPropertyListString()));
+                        break;
+                    case 3:
+                        check(msg, on1.getCanonicalKeyPropertyListString().
+                                equals(on.getCanonicalKeyPropertyListString()));
+                        break;
+                    case 4:
+                        for (Object ko : on1.getKeyPropertyList().keySet()) {
+                            final String key = (String) ko;
+                            check(msg, on1.getKeyProperty(key).
+                                    equals(on.getKeyProperty(key)));
+                        }
+                        for (Object ko : on.getKeyPropertyList().keySet()) {
+                            final String key = (String) ko;
+                            check(msg, on1.getKeyProperty(key).
+                                    equals(on.getKeyProperty(key)));
+                        }
+                    case 5:
+                        check(msg, on1.getKeyPropertyList()
+                                .equals(on.getKeyPropertyList()));
+                        break;
+                    case 6:
+                        check(msg, on1.isDomainPattern()==on.isDomainPattern());
+                        break;
+                    case 7:
+                        check(msg, on1.isPattern() == on.isPattern());
+                        break;
+                    case 8:
+                        check(msg,
+                              on1.isPropertyPattern()==on.isPropertyPattern());
+                        break;
+                    case 9:
+                        check(msg, on1.equals(on));
+                        break;
+                    case 10:
+                        check(msg, on.equals(on1));
+                        break;
+                    case 11:
+                        if (!on.isPattern()) {
+                            check(msg, on1.apply(on));
+                        }
+                        break;
+                    default:
+                        throw new Exception("Test incorrect: case: " + i);
+                }
+            } catch (Exception e) {
+                System.out.println("Test (" + i + ") failed with exception:");
+                e.printStackTrace(System.out);
+                failed = true;
+            }
+        }
+
+    }
+    private static String[] names6616825 = {
+        "a:b=c", "a:b=c,*", "*:*", ":*", ":b=c", ":b=c,*",
+        "a:*,b=c", ":*", ":*,b=c", "*x?:k=\"x\\*z\"", "*x?:k=\"x\\*z\",*",
+        "*x?:*,k=\"x\\*z\"", "*x?:k=\"x\\*z\",*,b=c"
+    };
+
+    static void check6616825() throws Exception {
+        System.out.println("Testing 616825");
+        for (String n : names6616825) {
+            final ObjectName on;
+            try {
+                on = new ObjectName(n);
+            } catch (Exception x) {
+                failed = true;
+                System.out.println("Unexpected failure for 6616825 [" + n +
+                        "]: " + x);
+                x.printStackTrace(System.out);
+                continue;
+            }
+            try {
+                checkName("616825 " + n, on);
+            } catch (Exception x) {
+                failed = true;
+                System.out.println("6616825 failed for [" + n + "]: " + x);
+                x.printStackTrace(System.out);
+            }
+        }
+
+        if (failed) {
+            throw new Exception("Some tests for 6616825 failed");
+        } else {
+            System.out.println("All tests for 6616825 passed");
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        System.setProperty("jmx.serial.form", "1.0");
+
+        /* Check that we really are in jmx.serial.form=1.0 mode.
+        The property is frozen the first time the ObjectName class
+        is referenced so checking that it is set to the correct
+        value now is not enough.  */
+        ObjectStreamClass osc = ObjectStreamClass.lookup(ObjectName.class);
+        if (osc.getFields().length != 6) {
+            throw new Exception("Not using old serial form: fields: " +
+                    Arrays.asList(osc.getFields()));
+        // new serial form has no fields, uses writeObject
+        }
+
+        try {
+            check6211220();
+        } catch (Exception x) {
+            System.err.println(x.getMessage());
+        }
+        try {
+            check6616825();
+        } catch (Exception x) {
+            System.err.println(x.getMessage());
+        }
+
+        if (failed) {
+            throw new Exception("Some tests failed");
+        } else {
+            System.out.println("All tests passed");
+        }
+    }
+
+    private static void check(String msg, boolean condition) {
         if (!condition) {
-            new Throwable("Test failed").printStackTrace(System.out);
+            new Throwable("Test failed " + msg).printStackTrace(System.out);
             failed = true;
         }
     }
-
     private static boolean failed;
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/eventService/AddRemoveListenerTest.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,371 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test AddRemoveListenerTest.java
+ * @bug 5108776
+ * @summary Basic test for EventClient to see internal thread management.
+ * @author Shanliang JIANG
+ * @run clean AddRemoveListenerTest
+ * @run build AddRemoveListenerTest
+ * @run main AddRemoveListenerTest
+ */
+
+import java.io.IOException;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.Notification;
+import javax.management.NotificationBroadcasterSupport;
+import javax.management.NotificationFilter;
+import javax.management.NotificationListener;
+import javax.management.ObjectName;
+import javax.management.event.EventClient;
+import javax.management.event.EventClientDelegate;
+import javax.management.event.EventClientDelegateMBean;
+import javax.management.event.FetchingEventRelay;
+import javax.management.event.RMIPushEventRelay;
+import javax.management.remote.JMXConnector;
+import javax.management.remote.JMXConnectorFactory;
+import javax.management.remote.JMXConnectorServer;
+import javax.management.remote.JMXConnectorServerFactory;
+import javax.management.remote.JMXServiceURL;
+
+
+// This thread creates a single MBean that emits a number of parallel
+// sequences of notifications.  Each sequence is distinguished by an id
+// and each id corresponds to a thread that is filtering the notifications
+// so it only sees its own ones.  The notifications for a given id have
+// contiguous sequence numbers and each thread checks that the notifications
+// it receives do indeed have these numbers.  If notifications are lost or
+// if the different sequences interfere with each other then the test will
+// fail.  As an added tweak, a "noise" thread periodically causes notifications
+// to be emitted that do not correspond to any sequence and do not have any id.
+public class AddRemoveListenerTest {
+
+    private static MBeanServer mbeanServer = MBeanServerFactory.createMBeanServer();
+    private static ObjectName emitter;
+    private static NotificationSender emitterImpl;
+    private static JMXServiceURL url;
+    private static JMXConnectorServer server;
+
+    private static int toSend = 100;
+    private static final long bigWaiting = 10000;
+    private static int counter = 0;
+    private static int jobs = 10;
+    private static int endedJobs = 0;
+
+    private static volatile String failure;
+
+    public static void main(String[] args) throws Exception {
+        System.out.println(">>> Test on multiple adding/removing listeners.");
+
+        // for 1.5
+        if (System.getProperty("java.version").startsWith("1.5") &&
+                !mbeanServer.isRegistered(EventClientDelegateMBean.OBJECT_NAME)) {
+            System.out.print("Working on "+System.getProperty("java.version")+
+                    " register "+EventClientDelegateMBean.OBJECT_NAME);
+
+            mbeanServer.registerMBean(EventClientDelegate.
+                    getEventClientDelegate(mbeanServer),
+                    EventClientDelegateMBean.OBJECT_NAME);
+        }
+
+        emitter = new ObjectName("Default:name=NotificationSender");
+        emitterImpl = new NotificationSender();
+        mbeanServer.registerMBean(emitterImpl, emitter);
+
+        String[] types = new String[]{"PushEventRelay", "FetchingEventRelay"};
+        String[] protos = new String[]{"rmi", "iiop", "jmxmp"};
+        for (String prot : protos) {
+            url = new JMXServiceURL(prot, null, 0);
+
+            try {
+                server =
+                        JMXConnectorServerFactory.newJMXConnectorServer(url,
+                        null, mbeanServer);
+                server.start();
+            } catch (Exception e) {
+                System.out.println(">>> Skip "+prot+", not supported.");
+                continue;
+            }
+
+            url = server.getAddress();
+
+            // noise
+            Thread noise = new Thread(new Runnable() {
+                public void run() {
+                    while (true) {
+                        emitterImpl.sendNotif(1, null);
+                        try {
+                            Thread.sleep(10);
+                        } catch (Exception e) {
+                            // OK
+                        }
+                    }
+                }
+            });
+            noise.setDaemon(true);
+            noise.start();
+
+            try {
+                for (String type: types) {
+                    System.out.println("\n\n>>> Testing "+type+" on "+url+" ...");
+                    JMXConnector conn = newConn();
+                    try {
+                        testType(type, conn);
+                    } finally {
+                        conn.close();
+                        System.out.println(">>> Testing "+type+" on "+url+" ... done");
+                    }
+                }
+            } finally {
+                server.stop();
+            }
+        }
+    }
+
+    private static void testType(String type, JMXConnector conn) throws Exception {
+        Thread[] threads = new Thread[jobs];
+        for (int i=0; i<jobs; i++) {
+            threads[i] = new Thread(new Job(type, conn));
+            threads[i].setDaemon(true);
+            threads[i].start();
+        }
+
+        // to wait
+        long toWait = bigWaiting*jobs;
+        long stopTime = System.currentTimeMillis() + toWait;
+
+        synchronized(AddRemoveListenerTest.class) {
+            while (endedJobs < jobs && toWait > 0 && failure == null) {
+                AddRemoveListenerTest.class.wait(toWait);
+                toWait = stopTime - System.currentTimeMillis();
+            }
+        }
+
+        if (endedJobs != jobs && failure == null) {
+            throw new RuntimeException("Need to set bigger waiting timeout?");
+        }
+
+        endedJobs = 0;
+    }
+
+    public static class Job implements Runnable {
+        public Job(String type, JMXConnector conn) {
+            this.type = type;
+            this.conn = conn;
+        }
+        public void run() {
+            try {
+                test(type, conn);
+
+                synchronized(AddRemoveListenerTest.class) {
+                    endedJobs++;
+                    if (endedJobs>=jobs) {
+                        AddRemoveListenerTest.class.notify();
+                    }
+                }
+            } catch (RuntimeException re) {
+                throw re;
+            } catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+        private final String type;
+        private final JMXConnector conn;
+    }
+
+    private static void test(String type, JMXConnector conn) throws Exception {
+        EventClient ec = newEventClient(type, conn);
+        try {
+            test(type, conn, ec);
+        } finally {
+            ec.close();
+        }
+    }
+
+    private static void test(String type, JMXConnector conn, EventClient ec)
+            throws Exception {
+        String id = getId();
+
+        Listener listener = new Listener(id);
+        Filter filter = new Filter(id);
+
+        System.out.println(">>> ("+id+") To receive notifications "+toSend);
+        ec.addNotificationListener(emitter,
+                listener, filter, null);
+
+        emitterImpl.sendNotif(toSend, id);
+        listener.waitNotifs(bigWaiting, toSend);
+        if (listener.received != toSend) {
+            throw new RuntimeException(">>> ("+id+") Expected to receive: "
+                    +toSend+", but got: "+listener.received);
+        }
+
+        listener.clear();
+        ec.removeNotificationListener(emitter, listener, filter, null);
+
+        System.out.println(">>> ("+id+") Repeat adding and removing ...");
+        for (int j=0; j<10; j++) {
+            ec.addNotificationListener(emitter, dummyListener, null, id);
+            Thread.yield(); // allow to start listening
+            ec.removeNotificationListener(emitter, dummyListener, null, id);
+        }
+
+        System.out.println(">>> ("+id+") To receive again notifications "+toSend);
+        ec.addNotificationListener(emitter,
+                listener, filter, null);
+
+        emitterImpl.sendNotif(toSend, id);
+        listener.waitNotifs(bigWaiting, toSend);
+        Thread.yield(); //any duplicated?
+        if (listener.received != toSend) {
+            throw new RuntimeException("("+id+") Expected to receive: "
+                    +toSend+", but got: "+listener.received);
+        }
+    }
+
+//--------------------------
+// private classes
+//--------------------------
+
+    private static class Listener implements NotificationListener {
+        public Listener(String id) {
+            this.id = id;
+        }
+        public void handleNotification(Notification notif, Object handback) {
+            if (!id.equals(notif.getUserData())) {
+                System.out.println("("+id+") Filter error, my id is: "+id+
+                        ", but got "+notif.getUserData());
+                System.exit(1);
+            }
+
+            synchronized (this) {
+                received++;
+
+                if(++sequenceNB != notif.getSequenceNumber()) {
+                    fail("(" + id + ") Wrong sequence number, expected: "
+                            +sequenceNB+", but got: "+notif.getSequenceNumber());
+                }
+                if (received >= toSend || failure != null) {
+                    this.notify();
+                }
+            }
+        }
+
+        public void waitNotifs(long timeout, int nb) throws Exception {
+            long toWait = timeout;
+            long stopTime = System.currentTimeMillis() + timeout;
+            synchronized(this) {
+                while (received < nb && toWait > 0 && failure == null) {
+                    this.wait(toWait);
+                    toWait = stopTime - System.currentTimeMillis();
+                }
+            }
+        }
+
+        public void clear() {
+            synchronized(this) {
+                received = 0;
+                sequenceNB = -1;
+            }
+        }
+
+        private String id;
+        private int received = 0;
+
+        private long sequenceNB = -1;
+    }
+
+    private static class Filter implements NotificationFilter {
+        public Filter(String id) {
+            this.id = id;
+        }
+
+        public boolean isNotificationEnabled(Notification n) {
+            return id.equals(n.getUserData());
+        }
+        private String id;
+    }
+
+    private static NotificationListener dummyListener = new NotificationListener() {
+        public void handleNotification(Notification notif, Object handback) {
+        }
+    };
+
+    public static class NotificationSender extends NotificationBroadcasterSupport
+            implements NotificationSenderMBean {
+
+        /**
+         * Send Notification objects.
+         *
+         * @param nb The number of notifications to send
+         */
+        public void sendNotif(int nb, String userData) {
+            long sequenceNumber = 0;
+            for (int i = 0; i<nb; i++) {
+                Notification notif = new Notification(myType, this, sequenceNumber++);
+                notif.setUserData(userData);
+                sendNotification(notif);
+            }
+        }
+
+
+        private final String myType = "notification.my_notification";
+    }
+
+    public interface NotificationSenderMBean {
+        public void sendNotif(int nb, String userData);
+    }
+
+    private static JMXConnector newConn() throws IOException {
+        return JMXConnectorFactory.connect(url);
+    }
+
+    private static EventClient newEventClient(String type, JMXConnector conn)
+            throws Exception {
+        EventClientDelegateMBean proxy =
+                EventClientDelegate.getProxy(conn.getMBeanServerConnection());
+        if (type.equals("PushEventRelay")) {
+            return new EventClient(proxy,
+                    new RMIPushEventRelay(proxy), null, null, 60000);
+        } else if (type.equals("FetchingEventRelay")) {
+            return new EventClient(proxy,
+                    new FetchingEventRelay(proxy), null, null, 60000);
+        } else {
+            throw new RuntimeException("Wrong event client type: "+type);
+        }
+    }
+
+    private static String getId() {
+        synchronized(AddRemoveListenerTest.class) {
+            return String.valueOf(counter++);
+        }
+    }
+
+    private static void fail(String msg) {
+        System.out.println("FAIL: " + msg);
+        failure = msg;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/eventService/CustomForwarderTest.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,348 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test CustomForwarderTest
+ * @bug 5108776
+ * @summary Test that a custom EventForwarder can be added
+ * @author Eamonn McManus
+ */
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.lang.management.ManagementFactory;
+import java.net.DatagramPacket;
+import java.net.DatagramSocket;
+import java.net.SocketAddress;
+import java.util.Map;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerInvocationHandler;
+import javax.management.Notification;
+import javax.management.NotificationBroadcasterSupport;
+import javax.management.NotificationFilter;
+import javax.management.NotificationListener;
+import javax.management.ObjectName;
+import javax.management.event.EventClient;
+import javax.management.event.EventClientDelegate;
+import javax.management.event.EventClientDelegateMBean;
+import javax.management.event.EventForwarder;
+import javax.management.event.EventReceiver;
+import javax.management.event.EventRelay;
+import javax.management.remote.MBeanServerForwarder;
+import javax.management.remote.NotificationResult;
+import javax.management.remote.TargetedNotification;
+
+public class CustomForwarderTest {
+    public static class UdpEventRelay implements EventRelay {
+        private final EventClientDelegateMBean delegate;
+        private final DatagramSocket socket;
+        private final AtomicBoolean closed = new AtomicBoolean();
+        private final String clientId;
+        private EventReceiver receiver;
+
+        public UdpEventRelay(EventClientDelegateMBean delegate)
+        throws IOException {
+            this.delegate = delegate;
+            this.socket = new DatagramSocket();
+            try {
+                clientId = delegate.addClient(
+                        UdpEventForwarder.class.getName(),
+                        new Object[] {socket.getLocalSocketAddress()},
+                        new String[] {SocketAddress.class.getName()});
+            } catch (IOException e) {
+                throw e;
+            } catch (RuntimeException e) {
+                throw e;
+            } catch (Exception e) {
+                final IOException ioe =
+                        new IOException("Exception creating EventForwarder");
+                ioe.initCause(e);
+                throw ioe;
+            }
+            Thread t = new Thread(new Receiver());
+            t.setDaemon(true);
+            t.start();
+        }
+
+        public String getClientId() throws IOException {
+            return clientId;
+        }
+
+        public void setEventReceiver(EventReceiver eventReceiver) {
+            this.receiver = eventReceiver;
+        }
+
+        public void stop() throws IOException {
+            closed.set(true);
+            socket.close();
+        }
+
+        private class Receiver implements Runnable {
+            public void run() {
+                byte[] buf = new byte[1024];
+                DatagramPacket packet = new DatagramPacket(buf, buf.length);
+                while (true) {
+                    try {
+                        socket.receive(packet);
+                    } catch (IOException e) {
+                        if (closed.get()) {
+                            System.out.println("Receiver got exception: " + e);
+                            System.out.println("Normal because it has been closed");
+                            return;
+                        } else {
+                            System.err.println("UNEXPECTED EXCEPTION IN RECEIVER:");
+                            e.printStackTrace();
+                            System.exit(1);
+                        }
+                    }
+                    try {
+                        ByteArrayInputStream bin = new ByteArrayInputStream(buf);
+                        ObjectInputStream oin = new ObjectInputStream(bin);
+                        NotificationResult nr = (NotificationResult)
+                                oin.readObject();
+                        receiver.receive(nr);
+                    } catch (Exception e) {
+                        System.err.println("UNEXPECTED EXCEPTION IN RECEIVER:");
+                        e.printStackTrace();
+                        System.exit(1);
+                    }
+                }
+            }
+        }
+    }
+
+    public static class UdpEventForwarder implements EventForwarder {
+        private final DatagramSocket socket;
+        private final AtomicLong seqNo = new AtomicLong(0);
+        private static volatile boolean drop;
+
+        public UdpEventForwarder(SocketAddress addr) throws IOException {
+            this.socket = new DatagramSocket();
+            socket.connect(addr);
+        }
+
+        public static void setDrop(boolean drop) {
+            UdpEventForwarder.drop = drop;
+        }
+
+        public void forward(Notification n, Integer listenerId) throws IOException {
+            long nextSeqNo = seqNo.incrementAndGet();
+            long thisSeqNo = nextSeqNo - 1;
+            TargetedNotification tn = new TargetedNotification(n, listenerId);
+            NotificationResult nr = new NotificationResult(
+                    thisSeqNo, nextSeqNo, new TargetedNotification[] {tn});
+            ByteArrayOutputStream bout = new ByteArrayOutputStream();
+            ObjectOutputStream oout = new ObjectOutputStream(bout);
+            oout.writeObject(nr);
+            oout.close();
+            byte[] bytes = bout.toByteArray();
+            DatagramPacket packet = new DatagramPacket(bytes, bytes.length);
+            if (!drop)
+                socket.send(packet);
+        }
+
+        public void close() throws IOException {
+            socket.close();
+        }
+
+        public void setClientId(String clientId) throws IOException {
+            // Nothing to do.
+        }
+    }
+
+    public static interface EmptyMBean {}
+
+    public static class Empty
+            extends NotificationBroadcasterSupport implements EmptyMBean {
+        public void send(Notification n) {
+            super.sendNotification(n);
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
+        MBeanServerForwarder mbsf = EventClientDelegate.newForwarder();
+        mbsf.setMBeanServer(mbs);
+        mbs = mbsf;
+
+        // for 1.5
+        if (System.getProperty("java.version").startsWith("1.5") &&
+                !mbs.isRegistered(EventClientDelegateMBean.OBJECT_NAME)) {
+            System.out.print("Working on "+System.getProperty("java.version")+
+                    " register "+EventClientDelegateMBean.OBJECT_NAME);
+
+            mbs.registerMBean(EventClientDelegate.
+                    getEventClientDelegate(mbs),
+                    EventClientDelegateMBean.OBJECT_NAME);
+        }
+
+        ObjectName name = new ObjectName("a:b=c");
+        Empty mbean = new Empty();
+        mbs.registerMBean(mbean, name);
+
+        EventClientDelegateMBean delegate = (EventClientDelegateMBean)
+            MBeanServerInvocationHandler.newProxyInstance(
+                mbs,
+                EventClientDelegateMBean.OBJECT_NAME,
+                EventClientDelegateMBean.class,
+                false);
+        EventRelay relay = new UdpEventRelay(delegate);
+        EventClient client = new EventClient(delegate, relay, null, null, 0L);
+
+        final Semaphore lostCountSema = new Semaphore(0);
+        NotificationListener lostListener = new NotificationListener() {
+            public void handleNotification(Notification notification, Object handback) {
+                if (notification.getType().equals(EventClient.NOTIFS_LOST)) {
+                    System.out.println("Got lost-notifs notif: count=" +
+                            notification.getUserData());
+                    lostCountSema.release(((Long) notification.getUserData()).intValue());
+                } else
+                    System.out.println("Mysterious EventClient notif: " + notification);
+            }
+        };
+        client.addEventClientListener(lostListener, null, null);
+
+        final BlockingQueue<Notification> notifQueue =
+                new ArrayBlockingQueue<Notification>(10);
+        NotificationListener countListener = new NotificationListener() {
+            public void handleNotification(Notification notification, Object handback) {
+                System.out.println("Received: " + notification);
+                notifQueue.add(notification);
+                if (!"tiddly".equals(handback)) {
+                    System.err.println("TEST FAILED: bad handback: " + handback);
+                    System.exit(1);
+                }
+            }
+        };
+
+        final AtomicInteger filterCount = new AtomicInteger(0);
+        NotificationFilter countFilter = new NotificationFilter() {
+            private static final long serialVersionUID = 1234L;
+
+            public boolean isNotificationEnabled(Notification notification) {
+                System.out.println("Filter called for: " + notification);
+                filterCount.incrementAndGet();
+                return true;
+            }
+        };
+
+        client.addNotificationListener(name, countListener, countFilter, "tiddly");
+
+        assertEquals("Initial notif count", 0, notifQueue.size());
+        assertEquals("Initial filter count", 0, filterCount.get());
+
+        Notification n = nextNotif(name);
+        mbean.send(n);
+
+        System.out.println("Waiting for notification to arrive...");
+
+        Notification n1 = notifQueue.poll(10, TimeUnit.SECONDS);
+
+        assertEquals("Received notif", n, n1);
+        assertEquals("Notif queue size after receive", 0, notifQueue.size());
+        assertEquals("Filter count after notif", 1, filterCount.get());
+        assertEquals("Lost notif count", 0, lostCountSema.availablePermits());
+
+        System.out.println("Dropping notifs");
+
+        UdpEventForwarder.setDrop(true);
+        for (int i = 0; i < 3; i++)
+            mbean.send(nextNotif(name));
+        UdpEventForwarder.setDrop(false);
+
+        Thread.sleep(2);
+        assertEquals("Notif queue size after drops", 0, notifQueue.size());
+
+        System.out.println("Turning off dropping and sending a notif");
+        n = nextNotif(name);
+        mbean.send(n);
+
+        System.out.println("Waiting for dropped notifications to be detected...");
+        boolean acquired = lostCountSema.tryAcquire(3, 5, TimeUnit.SECONDS);
+        assertEquals("Correct count of lost notifs", true, acquired);
+
+        n1 = notifQueue.poll(10, TimeUnit.SECONDS);
+        assertEquals("Received non-dropped notif", n, n1);
+
+        assertEquals("Notif queue size", 0, notifQueue.size());
+        assertEquals("Filter count after drops", 5, filterCount.get());
+
+        Thread.sleep(10);
+        assertEquals("Further lost-notifs", 0, lostCountSema.availablePermits());
+
+        client.close();
+
+        System.out.println("TEST PASSED");
+    }
+
+    private static AtomicLong nextSeqNo = new AtomicLong(0);
+    private static Notification nextNotif(ObjectName name) {
+        long n = nextSeqNo.incrementAndGet();
+        return new Notification("type", name, n, "" + n);
+    }
+
+    private static void assertEquals(String what, Object expected, Object got) {
+        if (equals(expected, got))
+            System.out.println(what + " = " + expected + ", as expected");
+        else {
+            Map<Thread, StackTraceElement[]> traces = Thread.getAllStackTraces();
+            for (Thread t : traces.keySet()) {
+                System.out.println(t.getName());
+                for (StackTraceElement elmt : traces.get(t)) {
+                    System.out.println("    " + elmt);
+                }
+            }
+            throw new RuntimeException(
+                    "TEST FAILED: " + what + " is " + got + "; should be " +
+                    expected);
+        }
+    }
+
+    private static boolean equals(Object expected, Object got) {
+        if (!(expected instanceof Notification))
+            return expected.equals(got);
+        if (expected.getClass() != got.getClass())
+            return false;
+        // Notification doesn't override Object.equals so two distinct
+        // notifs are never equal even if they have the same contents.
+        // Although the test doesn't serialize the notifs, if at some
+        // stage it did then it would fail because the deserialized notif
+        // was not equal to the original one.  Therefore we compare enough
+        // notif fields to detect when notifs really are different.
+        Notification en = (Notification) expected;
+        Notification gn = (Notification) got;
+        return (en.getType().equals(gn.getType()) &&
+                en.getSource().equals(gn.getSource()) &&
+                en.getSequenceNumber() == gn.getSequenceNumber());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/eventService/EventClientExecutorTest.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,191 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @bug 5108776
+ * @summary Test that the various Executor parameters in an EventClient do
+ * what they are supposed to.
+ * @author Eamonn McManus
+ */
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ThreadFactory;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.Notification;
+import javax.management.NotificationBroadcasterSupport;
+import javax.management.NotificationListener;
+import javax.management.ObjectName;
+import javax.management.event.EventClient;
+import javax.management.event.EventClientDelegate;
+import javax.management.event.EventClientDelegateMBean;
+import javax.management.event.FetchingEventRelay;
+import javax.management.remote.MBeanServerForwarder;
+
+public class EventClientExecutorTest {
+    private static volatile String failure;
+    private static final Set testedPrefixes = new HashSet();
+
+    public static void main(String[] args) throws Exception {
+        Executor fetchExecutor = Executors.newSingleThreadExecutor(
+                new NamedThreadFactory("FETCH"));
+        Executor listenerExecutor = Executors.newSingleThreadExecutor(
+                new NamedThreadFactory("LISTENER"));
+        ScheduledExecutorService leaseScheduler =
+            Executors.newSingleThreadScheduledExecutor(
+                new NamedThreadFactory("LEASE"));
+
+        MBeanServer mbs = MBeanServerFactory.newMBeanServer();
+        MBeanServerForwarder mbsf = EventClientDelegate.newForwarder();
+        mbsf.setMBeanServer(mbs);
+        mbs = mbsf;
+
+        EventClientDelegateMBean ecd = EventClientDelegate.getProxy(mbs);
+        ecd = (EventClientDelegateMBean) Proxy.newProxyInstance(
+                EventClientDelegateMBean.class.getClassLoader(),
+                new Class<?>[] {EventClientDelegateMBean.class},
+                new DelegateCheckIH(ecd));
+
+        ObjectName mbeanName = new ObjectName("d:type=Notifier");
+        Notifier notifier = new Notifier();
+        mbs.registerMBean(notifier, mbeanName);
+
+        FetchingEventRelay eventRelay = new FetchingEventRelay(
+                ecd, fetchExecutor);
+        EventClient ec = new EventClient(
+                ecd, eventRelay, listenerExecutor, leaseScheduler, 1000L);
+        NotificationListener checkListener = new NotificationListener() {
+            public void handleNotification(Notification notification,
+                                           Object handback) {
+                assertThreadName("listener dispatch", "LISTENER");
+            }
+        };
+        ec.addNotificationListener(mbeanName, checkListener, null, null);
+
+        mbs.invoke(mbeanName, "send", null, null);
+
+        // Now wait until we have seen all three thread types.
+        long deadline = System.currentTimeMillis() + 5000;
+        synchronized (testedPrefixes) {
+            while (testedPrefixes.size() < 3 && failure == null) {
+                long remain = deadline - System.currentTimeMillis();
+                if (remain <= 0) {
+                    fail("Timed out waiting for all three thread types to show, " +
+                            "saw only " + testedPrefixes);
+                    break;
+                }
+                try {
+                    testedPrefixes.wait(remain);
+                } catch (InterruptedException e) {
+                    fail("Unexpected InterruptedException");
+                    break;
+                }
+            }
+        }
+
+        // We deliberately don't close the EventClient to check that it has
+        // not created any non-daemon threads.
+
+        if (failure != null)
+            throw new Exception("TEST FAILED: " + failure);
+        else
+            System.out.println("TEST PASSED");
+    }
+
+    public static interface NotifierMBean {
+        public void send();
+    }
+
+    public static class Notifier extends NotificationBroadcasterSupport
+            implements NotifierMBean {
+        public void send() {
+            Notification n = new Notification("a.b.c", this, 0L);
+            sendNotification(n);
+        }
+    }
+
+    static void fail(String why) {
+        System.out.println("FAIL: " + why);
+        failure = why;
+    }
+
+    static void assertThreadName(String what, String prefix) {
+        String name = Thread.currentThread().getName();
+        if (!name.startsWith(prefix)) {
+            fail("Wrong thread for " + what + ": " + name);
+            return;
+        }
+
+        synchronized (testedPrefixes) {
+            if (testedPrefixes.add(prefix))
+                testedPrefixes.notify();
+        }
+    }
+
+    private static class DelegateCheckIH implements InvocationHandler {
+        private final EventClientDelegateMBean ecd;
+
+        public DelegateCheckIH(EventClientDelegateMBean ecd) {
+            this.ecd = ecd;
+        }
+
+        public Object invoke(Object proxy, Method method, Object[] args)
+                throws Throwable {
+            String methodName = method.getName();
+            if (methodName.equals("fetchNotifications"))
+                assertThreadName("fetchNotifications", "FETCH");
+            else if (methodName.equals("lease"))
+                assertThreadName("lease renewal", "LEASE");
+            try {
+                return method.invoke(ecd, args);
+            } catch (InvocationTargetException e) {
+                throw e.getCause();
+            }
+        }
+    }
+
+    private static class NamedThreadFactory implements ThreadFactory {
+        private final String namePrefix;
+        private int count;
+
+        NamedThreadFactory(String namePrefix) {
+            this.namePrefix = namePrefix;
+        }
+
+        public synchronized Thread newThread(Runnable r) {
+            Thread t = new Thread(r);
+            t.setName(namePrefix + " " + ++count);
+            t.setDaemon(true);
+            return t;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/eventService/EventDelegateSecurityTest.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,289 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @bug 5108776
+ * @summary Test that the EventClientDelegate MBean does not require extra
+ * permissions compared with plain addNotificationListener.
+ * @author Eamonn McManus
+ * @run main/othervm -Dxjava.security.debug=policy,access,failure EventDelegateSecurityTest
+ */
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.lang.management.ManagementFactory;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.AllPermission;
+import java.security.PrivilegedExceptionAction;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.SynchronousQueue;
+import java.util.concurrent.TimeUnit;
+import javax.management.MBeanPermission;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerConnection;
+import javax.management.Notification;
+import javax.management.NotificationBroadcasterSupport;
+import javax.management.NotificationListener;
+import javax.management.ObjectName;
+import javax.management.event.EventClient;
+import javax.management.remote.JMXAuthenticator;
+import javax.management.remote.JMXConnector;
+import javax.management.remote.JMXConnectorFactory;
+import javax.management.remote.JMXConnectorServer;
+import javax.management.remote.JMXConnectorServerFactory;
+import javax.management.remote.JMXPrincipal;
+import javax.management.remote.JMXServiceURL;
+import javax.management.remote.MBeanServerForwarder;
+import javax.security.auth.Subject;
+
+public class EventDelegateSecurityTest {
+    private static final BlockingQueue<Notification> notifQ =
+            new SynchronousQueue<Notification>();
+
+    private static volatile long seqNo;
+    private static volatile long expectSeqNo;
+
+    private static class QueueListener implements NotificationListener {
+        public void handleNotification(Notification notification,
+                                       Object handback) {
+            try {
+                notifQ.put(notification);
+            } catch (InterruptedException e) {
+                throw new AssertionError(e);
+            }
+        }
+    }
+    private static final NotificationListener queueListener = new QueueListener();
+
+    public static interface SenderMBean {
+        public void send();
+    }
+
+    public static class Sender
+            extends NotificationBroadcasterSupport implements SenderMBean {
+        public void send() {
+            Notification n = new Notification("x", this, seqNo++);
+            sendNotification(n);
+        }
+    }
+
+    private static class LimitInvocationHandler implements InvocationHandler {
+        private MBeanServer nextMBS;
+        private final Set<String> allowedMethods = new HashSet<String>();
+
+        void allow(String... names) {
+            synchronized (allowedMethods) {
+                allowedMethods.addAll(Arrays.asList(names));
+            }
+        }
+
+        public Object invoke(Object proxy, Method m, Object[] args)
+                throws Throwable {
+            System.out.println(
+                    "filter: " + m.getName() +
+                    ((args == null) ? "[]" : Arrays.deepToString(args)));
+            String name = m.getName();
+
+            if (name.equals("getMBeanServer"))
+                return nextMBS;
+
+            if (name.equals("setMBeanServer")) {
+                nextMBS = (MBeanServer) args[0];
+                return null;
+            }
+
+            if (m.getDeclaringClass() == Object.class ||
+                    allowedMethods.contains(name)) {
+                try {
+                    return m.invoke(nextMBS, args);
+                } catch (InvocationTargetException e) {
+                    throw e.getCause();
+                }
+            } else {
+                System.out.println("...refused");
+                throw new SecurityException(
+                        "Method refused: " + m.getDeclaringClass().getName() +
+                        "." + m.getName() +
+                        ((args == null) ? "[]" : Arrays.deepToString(args)));
+            }
+        }
+
+    }
+
+    private static interface MakeConnectorServer {
+        public JMXConnectorServer make(JMXServiceURL url) throws IOException;
+    }
+
+
+    public static void main(String[] args) throws Exception {
+        JMXPrincipal rootPrincipal = new JMXPrincipal("root");
+        Subject rootSubject = new Subject();
+        rootSubject.getPrincipals().add(rootPrincipal);
+        Subject.doAsPrivileged(rootSubject, new PrivilegedExceptionAction<Void>() {
+            public Void run() throws Exception {
+                mainAsRoot();
+                return null;
+            }
+        }, null);
+    }
+
+    private static void mainAsRoot() throws Exception {
+        AccessControlContext acc = AccessController.getContext();
+        Subject subject = Subject.getSubject(acc);
+        System.out.println("Subject: " + subject);
+        final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
+        ObjectName name = new ObjectName("a:b=c");
+        mbs.registerMBean(new Sender(), name);
+
+        System.out.println("Test with no installed security");
+        test(mbs, name, new MakeConnectorServer() {
+            public JMXConnectorServer make(JMXServiceURL url) throws IOException {
+                return
+                    JMXConnectorServerFactory.newJMXConnectorServer(url, null, null);
+            }
+        });
+
+        System.out.println("Test with filtering MBeanServerForwarder");
+        LimitInvocationHandler limitIH = new LimitInvocationHandler();
+        // We allow getClassLoaderRepository because the ConnectorServer
+        // calls it so any real checking MBeanServerForwarder must accept it.
+        limitIH.allow(
+                "addNotificationListener", "removeNotificationListener",
+                "getClassLoaderRepository"
+                );
+        final MBeanServerForwarder limitMBSF = (MBeanServerForwarder)
+            Proxy.newProxyInstance(
+                MBeanServerForwarder.class.getClassLoader(),
+                new Class<?>[] {MBeanServerForwarder.class},
+                limitIH);
+        // We go to considerable lengths to ensure that the ConnectorServer has
+        // no MBeanServer when the EventClientDelegate forwarder is activated,
+        // so that the calls it makes when it is later linked to an MBeanServer
+        // go through the limitMBSF.
+        test(mbs, name, new MakeConnectorServer() {
+            public JMXConnectorServer make(JMXServiceURL url) throws IOException {
+                JMXConnectorServer cs =
+                    JMXConnectorServerFactory.newJMXConnectorServer(url, null, null);
+                limitMBSF.setMBeanServer(mbs);
+                cs.setMBeanServerForwarder(limitMBSF);
+                return cs;
+            }
+        });
+
+        final File policyFile =
+                File.createTempFile("EventDelegateSecurityTest", ".policy");
+        PrintWriter pw = new PrintWriter(policyFile);
+        String JMXPrincipal = JMXPrincipal.class.getName();
+        String AllPermission = AllPermission.class.getName();
+        String MBeanPermission = MBeanPermission.class.getName();
+        pw.println("grant principal " + JMXPrincipal + " \"root\" {");
+        pw.println("    permission " + AllPermission + ";");
+        pw.println("};");
+        pw.println("grant principal " + JMXPrincipal + " \"user\" {");
+        pw.println("    permission " + MBeanPermission + " \"*\", " +
+                " \"addNotificationListener\";");
+        pw.println("    permission " + MBeanPermission + " \"*\", " +
+                " \"removeNotificationListener\";");
+        pw.println("};");
+        pw.close();
+        Runtime.getRuntime().addShutdownHook(new Thread() {
+            @Override
+            public void run() {
+                policyFile.delete();
+            }
+        });
+        System.setProperty("java.security.policy", policyFile.getAbsolutePath());
+        System.setSecurityManager(new SecurityManager());
+        test(mbs, name, new MakeConnectorServer() {
+            public JMXConnectorServer make(JMXServiceURL url) throws IOException {
+                Map<String, Object> env = new HashMap<String, Object>();
+                env.put(JMXConnectorServer.AUTHENTICATOR, new JMXAuthenticator() {
+                    public Subject authenticate(Object credentials) {
+                        Subject s = new Subject();
+                        s.getPrincipals().add(new JMXPrincipal("user"));
+                        return s;
+                    }
+                });
+                return
+                    JMXConnectorServerFactory.newJMXConnectorServer(url, env, null);
+            }
+        });
+    }
+
+    private static void test(MBeanServer mbs, ObjectName name) throws Exception {
+        test(mbs, name, null);
+    }
+
+    private static void test(
+            MBeanServer mbs, ObjectName name, MakeConnectorServer make)
+            throws Exception {
+        JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///");
+        JMXConnectorServer cs = make.make(url);
+        ObjectName csName = new ObjectName("a:type=ConnectorServer");
+        mbs.registerMBean(cs, csName);
+        cs.start();
+        try {
+            JMXServiceURL addr = cs.getAddress();
+            JMXConnector cc = JMXConnectorFactory.connect(addr);
+            MBeanServerConnection mbsc = cc.getMBeanServerConnection();
+            test(mbs, mbsc, name);
+            cc.close();
+            mbs.unregisterMBean(csName);
+        } finally {
+            cs.stop();
+        }
+    }
+
+    private static void test(
+            MBeanServer mbs, MBeanServerConnection mbsc, ObjectName name)
+            throws Exception {
+        EventClient ec = new EventClient(mbsc);
+        ec.addNotificationListener(name, queueListener, null, null);
+        mbs.invoke(name, "send", null, null);
+
+        Notification n = notifQ.poll(5, TimeUnit.SECONDS);
+        if (n == null)
+            throw new Exception("FAILED: notif not delivered");
+        if (n.getSequenceNumber() != expectSeqNo) {
+            throw new Exception(
+                    "FAILED: notif seqno " + n.getSequenceNumber() +
+                    " should be " + expectSeqNo);
+        }
+        expectSeqNo++;
+
+        ec.removeNotificationListener(name, queueListener);
+        ec.close();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/eventService/EventManagerTest.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,221 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test EventManagerTest.java 1.8 08/01/22
+ * @bug 5108776
+ * @summary Basic test for EventManager.
+ * @author Shanliang JIANG
+ * @run clean EventManagerTest
+ * @run build EventManagerTest
+ * @run main EventManagerTest
+ */
+
+import javax.management.MBeanNotificationInfo;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerConnection;
+import javax.management.MBeanServerFactory;
+import javax.management.Notification;
+import javax.management.NotificationBroadcasterSupport;
+import javax.management.NotificationListener;
+import javax.management.ObjectName;
+import javax.management.event.*;
+import javax.management.remote.JMXConnector;
+import javax.management.remote.JMXConnectorFactory;
+import javax.management.remote.JMXConnectorServer;
+import javax.management.remote.JMXConnectorServerFactory;
+import javax.management.remote.JMXServiceURL;
+
+/**
+ *
+ */
+public class EventManagerTest {
+    private static MBeanServer mbeanServer;
+    private static ObjectName emitter;
+    private static JMXServiceURL url;
+    private static JMXConnectorServer server;
+    private static JMXConnector conn;
+    private static MBeanServerConnection client;
+
+    /**
+     * @param args the command line arguments
+     */
+    public static void main(String[] args) throws Exception {
+        System.out.println(">>> EventManagerTest-main basic tests ...");
+        mbeanServer = MBeanServerFactory.createMBeanServer();
+
+        // for 1.5
+        if (System.getProperty("java.version").startsWith("1.5") &&
+                !mbeanServer.isRegistered(EventClientDelegateMBean.OBJECT_NAME)) {
+            System.out.print("Working on "+System.getProperty("java.version")+
+                    " register "+EventClientDelegateMBean.OBJECT_NAME);
+
+            mbeanServer.registerMBean(EventClientDelegate.
+                    getEventClientDelegate(mbeanServer),
+                    EventClientDelegateMBean.OBJECT_NAME);
+        }
+
+        emitter = new ObjectName("Default:name=NotificationEmitter");
+
+        url = new JMXServiceURL("rmi", null, 0) ;
+        server =
+                JMXConnectorServerFactory.newJMXConnectorServer(url, null, mbeanServer);
+        server.start();
+
+        url = server.getAddress();
+        conn = JMXConnectorFactory.connect(url, null);
+        client = conn.getMBeanServerConnection();
+
+        mbeanServer.registerMBean(new NotificationEmitter(), emitter);
+
+        boolean succeed;
+
+        System.out.println(">>> EventManagerTest-main: using the fetching EventRelay...");
+        succeed = test(new EventClient(client));
+
+        System.out.println(">>> EventManagerTest-main: using the pushing EventRelay...");
+        EventClientDelegateMBean ecd = EventClientDelegate.getProxy(client);
+        succeed &= test(new EventClient(ecd,
+                new RMIPushEventRelay(ecd),
+                null, null,
+                EventClient.DEFAULT_LEASE_TIMEOUT));
+
+        conn.close();
+        server.stop();
+
+        if (succeed) {
+            System.out.println(">>> EventManagerTest-main: PASSE!");
+        } else {
+            System.out.println("\n>>> EventManagerTest-main: FAILED!");
+            System.exit(1);
+        }
+    }
+
+    public static boolean test(EventClient efClient) throws Exception {
+        // add listener from the client side
+        Listener listener = new Listener();
+        efClient.subscribe(emitter, listener, null, null);
+
+        // ask to send notifs
+        Object[] params = new Object[] {new Integer(sendNB)};
+        String[] signatures = new String[] {"java.lang.Integer"};
+        client.invoke(emitter, "sendNotifications", params, signatures);
+
+        // waiting
+        long toWait = 6000;
+        long stopTime = System.currentTimeMillis() + toWait;
+
+        synchronized(listener) {
+            while(listener.received < sendNB && toWait > 0) {
+                listener.wait(toWait);
+                toWait = stopTime - System.currentTimeMillis();
+            }
+        }
+
+        // clean
+        System.out.println(">>> EventManagerTest-test: cleaning...");
+        efClient.unsubscribe(emitter, listener);
+        efClient.close();
+
+        if (listener.received != sendNB) {
+            System.out.println(">>> EventManagerTest-test: FAILED! Expected to receive "+sendNB+", but got "+listener.received);
+
+            return false;
+        } else if (listener.seqErr > 0) {
+            System.out.println(">>> EventManagerTest-test: FAILED! The receiving sequence is not correct.");
+
+            return false;
+        } else {
+            System.out.println(">>> EventManagerTest-test: got all expected "+listener.received);
+            return true;
+        }
+    }
+
+    private static class Listener implements NotificationListener {
+        public int received = 0;
+        public int seqErr = 0;
+
+        private long lastSeq = -1;
+
+        public void handleNotification(Notification notif, Object handback) {
+            if (!myType.equals(notif.getType())) {
+                System.out.println(">>> EventManagerTest-Listener: got unexpected notif: "+notif);
+                System.exit(1);
+            }
+
+            if (lastSeq == -1) {
+                lastSeq = notif.getSequenceNumber();
+            } else if (notif.getSequenceNumber() - lastSeq++ != 1) {
+                seqErr++;
+            }
+
+            //System.out.println(">>> EventManagerTest-Listener: got notif "+notif.getSequenceNumber());
+
+            synchronized(this) {
+                if (++received >= sendNB) {
+                    this.notify();
+                }
+            }
+        }
+    }
+
+    public static class NotificationEmitter extends NotificationBroadcasterSupport
+            implements NotificationEmitterMBean {
+
+        public MBeanNotificationInfo[] getNotificationInfo() {
+            final String[] ntfTypes = {myType};
+
+            final MBeanNotificationInfo[] ntfInfoArray  = {
+                new MBeanNotificationInfo(ntfTypes,
+                        "javax.management.Notification",
+                        "Notifications sent by the NotificationEmitter")};
+
+                        return ntfInfoArray;
+        }
+
+        /**
+         * Send Notification objects.
+         *
+         * @param nb The number of notifications to send
+         */
+        public void sendNotifications(Integer nb) {
+            Notification notif;
+            for (int i=1; i<=nb.intValue(); i++) {
+                notif = new Notification(myType, this, count++);
+                notif.setUserData("jsl");
+                //System.out.println(">>> EventManagerService-NotificationEmitter-sendNotifications: "+i);
+
+                sendNotification(notif);
+            }
+        }
+    }
+
+    public interface NotificationEmitterMBean {
+        public void sendNotifications(Integer nb);
+    }
+
+    private static int sendNB = 120;
+    private static long count = 0;
+
+    private static final String myType = "notification.my_notification";
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/eventService/FetchingTest.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,276 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @bug 5108776
+ * @summary Basic test for EventClient.
+ * @author Shanliang JIANG
+ * @run clean FetchingTest MyFetchingEventForwarder
+ * @run build FetchingTest MyFetchingEventForwarder
+ * @run main FetchingTest MyFetchingEventForwarder
+ */
+
+import javax.management.MBeanServer;
+import javax.management.MBeanServerConnection;
+import javax.management.MBeanServerFactory;
+import javax.management.Notification;
+import javax.management.NotificationBroadcasterSupport;
+import javax.management.NotificationListener;
+import javax.management.ObjectName;
+import javax.management.event.EventClient;
+import javax.management.event.EventClientDelegate;
+import javax.management.event.EventClientDelegateMBean;
+import javax.management.event.FetchingEventRelay;
+import javax.management.event.RMIPushEventForwarder;
+import javax.management.event.RMIPushServer;
+import javax.management.remote.JMXConnector;
+import javax.management.remote.JMXConnectorFactory;
+import javax.management.remote.JMXConnectorServer;
+import javax.management.remote.JMXConnectorServerFactory;
+import javax.management.remote.JMXServiceURL;
+
+public class FetchingTest {
+    private static MBeanServer mbeanServer;
+    private static ObjectName emitter;
+    private static JMXServiceURL url;
+    private static JMXConnectorServer server;
+    private static JMXConnector conn;
+    private static MBeanServerConnection client;
+    private static long WAITING_TIME = 6000;
+
+    /**
+     * @param args the command line arguments
+     */
+    public static void main(String[] args) throws Exception {
+
+        System.out.println(">>> FetchingTest-main basic tests ...");
+        mbeanServer = MBeanServerFactory.createMBeanServer();
+
+        // for 1.5
+        if (System.getProperty("java.version").startsWith("1.5") &&
+                !mbeanServer.isRegistered(EventClientDelegateMBean.OBJECT_NAME)) {
+            System.out.print("Working on "+System.getProperty("java.version")+
+                    " register "+EventClientDelegateMBean.OBJECT_NAME);
+
+            mbeanServer.registerMBean(EventClientDelegate.
+                    getEventClientDelegate(mbeanServer),
+                    EventClientDelegateMBean.OBJECT_NAME);
+        }
+
+        emitter = new ObjectName("Default:name=NotificationEmitter");
+        mbeanServer.registerMBean(new NotificationEmitter(), emitter);
+        boolean succeed = true;
+
+        final String[] protos = new String[] {"rmi", "iiop", "jmxmp"};
+        for (String proto : protos) {
+            System.out.println(">>> FetchingTest-main: testing on "+proto);
+
+            try {
+                url = new JMXServiceURL(proto, null, 0) ;
+                server = JMXConnectorServerFactory.
+                        newJMXConnectorServer(url, null, mbeanServer);
+                server.start();
+            } catch (Exception e) {
+                // OK
+                System.out.println(">>> FetchingTest-main: skip the proto "+proto);
+                continue;
+            }
+
+            url = server.getAddress();
+            conn = JMXConnectorFactory.connect(url, null);
+            client = conn.getMBeanServerConnection();
+
+            succeed &= test();
+
+            conn.close();
+            server.stop();
+
+            System.out.println(
+                    ">>> FetchingTest-main: testing on "+proto+" done.");
+        }
+
+        if (succeed) {
+            System.out.println(">>> FetchingTest-main: PASSED!");
+        } else {
+            System.out.println("\n>>> FetchingTest-main: FAILED!");
+            System.exit(1);
+        }
+    }
+
+    public static boolean test() throws Exception {
+        System.out.println(">>> FetchingTest-test: " +
+                "using the default fetching forwarder ...");
+        EventClient eventClient =
+                new EventClient(client);
+
+        Listener listener = new Listener();
+        eventClient.addNotificationListener(emitter, listener, null, null);
+
+        // ask to send notifs
+        Object[] params = new Object[] {new Integer(sendNB)};
+        String[] signatures = new String[] {"java.lang.Integer"};
+        conn.getMBeanServerConnection().invoke(emitter,
+                "sendNotifications", params, signatures);
+
+        if (listener.waitNotif(WAITING_TIME) != sendNB) {
+            System.out.println(
+                    ">>> FetchingTest-test: FAILED! Expected to receive "+
+                    sendNB+", but got "+listener.received);
+
+            return false;
+        }
+
+        System.out.println(
+                ">>> ListenerTest-test: got all expected "+listener.received);
+        //eventClient.removeNotificationListener(emitter, listener);
+        eventClient.close();
+
+        System.out.println(">>> FetchingTest-test: " +
+                "using a user specific List ...");
+
+        FetchingEventRelay fer = new FetchingEventRelay(
+                EventClientDelegate.getProxy(client),
+                1000, 1000L, 1000, null,
+                MyFetchingEventForwarder.class.getName(),
+                null, null);
+
+        eventClient = new EventClient(
+                EventClientDelegate.getProxy(client), fer, null, null, 10000);
+
+        eventClient.addNotificationListener(emitter, listener, null, null);
+        listener.received = 0;
+
+        conn.getMBeanServerConnection().invoke(emitter,
+                "sendNotifications", params, signatures);
+
+        if (listener.waitNotif(WAITING_TIME) != sendNB) {
+            System.out.println(
+                    ">>> FetchingTest-test: FAILED! Expected to receive "+
+                    sendNB+", but got "+listener.received);
+
+            return false;
+        }
+
+        System.out.println(
+                ">>> FetchingTest-test: got all expected "+listener.received);
+
+        if (!MyFetchingEventForwarder.shared.isUsed()) {
+            System.out.println(
+                    ">>> FetchingTest-test: FAILED! The user specific list" +
+                        "is not used!");
+
+            return false;
+        }
+
+        System.out.println(">>> Negative test to add an EventClient" +
+                " with a non EventForwarder object.");
+        try {
+            MyFetchingEventForwarder.shared.setAgain();
+
+            System.out.println(
+                    ">>> FetchingTest-test: FAILED! No expected exception" +
+                    "when setting the list after the forwarder started.");
+
+            return false;
+        } catch (IllegalStateException ise) {
+            // OK
+            System.out.println(
+                    ">>> FetchingTest-test: Got expected exception: " + ise);
+        }
+
+        eventClient.close();
+
+        try {
+            fer = new FetchingEventRelay(
+                EventClientDelegate.getProxy(client),
+                1000, 1000L, 1000, null,
+                Object.class.getName(),
+                null, null);
+
+                eventClient = new EventClient(
+                        EventClientDelegate.getProxy(client), fer, null, null, 10000);
+
+                System.out.println(
+                    ">>> FetchingTest-test: FAILED! No expected exception" +
+                    "when creating an illegal EventForwarder");
+        } catch (IllegalArgumentException iae) {
+            // OK
+            // iae.printStackTrace();
+        }
+
+        return true;
+    }
+
+    private static class Listener implements NotificationListener {
+        public void handleNotification(Notification notif, Object handback) {
+            synchronized(this) {
+                if (++received >= sendNB) {
+                    this.notify();
+                }
+            }
+
+            //System.out.println(">>> FetchingTest-Listener: received = "+received);
+        }
+
+        public int waitNotif(long timeout) throws Exception {
+            synchronized(this) {
+                long stopTime = System.currentTimeMillis() + timeout;
+                long toWait = timeout;
+                while (toWait > 0 && received < sendNB) {
+                        this.wait(toWait);
+                    toWait = stopTime - System.currentTimeMillis();
+                }
+            }
+
+            return received;
+        }
+
+        public static int received = 0;
+    }
+
+    public static class NotificationEmitter extends NotificationBroadcasterSupport
+            implements NotificationEmitterMBean {
+
+        public void sendNotifications(Integer nb) {
+            System.out.println(
+                    ">>> FetchingTest-NotificationEmitter-sendNotifications: "+nb);
+            Notification notif;
+            for (int i=1; i<=nb.intValue(); i++) {
+                notif = new Notification(myType, this, count++);
+                sendNotification(notif);
+            }
+        }
+    }
+
+    public interface NotificationEmitterMBean {
+        public void sendNotifications(Integer nb);
+    }
+
+
+
+    private static int sendNB = 20;
+    private static int count = 0;
+
+    private static final String myType = "notification.my_notification";
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/eventService/LeaseManagerDeadlockTest.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @bug 6717789
+ * @summary Check that a lock is not held when a LeaseManager expires.
+ * @author Eamonn McManus
+ */
+
+import com.sun.jmx.event.LeaseManager;
+import java.lang.management.ManagementFactory;
+import java.lang.management.ThreadMXBean;
+import java.util.Arrays;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
+public class LeaseManagerDeadlockTest {
+    public static String failure;
+    public static LeaseManager leaseManager;
+    public static Semaphore callbackThreadCompleted = new Semaphore(0);
+    public static Object lock = new Object();
+
+    public static Runnable triggerDeadlock = new Runnable() {
+        public void run() {
+            Runnable pingLeaseManager = new Runnable() {
+                public void run() {
+                    System.out.println("Ping thread starts");
+                    synchronized (lock) {
+                        leaseManager.lease(1);
+                    }
+                    System.out.println("Ping thread completes");
+                }
+            };
+            Thread t = new Thread(pingLeaseManager);
+            t.start();
+            try {
+                Thread.sleep(10);  // enough time for ping thread to grab lock
+                synchronized (lock) {
+                    t.join();
+                }
+            } catch (InterruptedException e) {
+                fail(e.toString());
+            }
+            System.out.println("Callback thread completes");
+            callbackThreadCompleted.release();
+        }
+    };
+
+    public static void main(String[] args) throws Exception {
+        // Also test that we can shorten the lease from its initial value.
+        leaseManager = new LeaseManager(triggerDeadlock, 1000000);
+        leaseManager.lease(1L);
+
+        boolean callbackRan =
+                callbackThreadCompleted.tryAcquire(3, TimeUnit.SECONDS);
+
+        if (!callbackRan) {
+            fail("Callback did not complete - probable deadlock");
+            ThreadMXBean threads = ManagementFactory.getThreadMXBean();
+            System.out.println(Arrays.toString(threads.findDeadlockedThreads()));
+            System.out.println("PRESS RETURN");
+            System.in.read();
+        }
+
+        if (failure == null)
+            System.out.println("TEST PASSED");
+        else
+            throw new Exception("TEST FAILED: " + failure);
+    }
+
+    public static void fail(String why) {
+        System.out.println("TEST FAILS: " + why);
+        failure = why;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/eventService/LeaseTest.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,361 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test LeaseTest.java 1.6 08/01/22
+ * @bug 5108776
+ * @summary Basic test for Event service leasing.
+ * @author Shanliang JIANG
+ * @run clean LeaseTest
+ * @run build LeaseTest
+ * @run main LeaseTest
+ */
+
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import javax.management.ListenerNotFoundException;
+import javax.management.MBeanNotificationInfo;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.Notification;
+import javax.management.NotificationBroadcasterSupport;
+import javax.management.NotificationFilter;
+import javax.management.NotificationListener;
+import javax.management.ObjectName;
+import javax.management.event.EventClient;
+import javax.management.event.EventClientDelegate;
+import javax.management.event.EventClientDelegateMBean;
+import javax.management.event.EventClientNotFoundException;
+import javax.management.event.FetchingEventRelay;
+import javax.management.remote.JMXConnector;
+import javax.management.remote.JMXConnectorFactory;
+import javax.management.remote.JMXConnectorServer;
+import javax.management.remote.JMXConnectorServerFactory;
+import javax.management.remote.JMXServiceURL;
+
+public class LeaseTest {
+
+    private static MBeanServer mbeanServer = MBeanServerFactory.createMBeanServer();
+    private static List<Notification> notifList = new ArrayList<Notification>();
+    private static ObjectName emitter;
+    private static NotificationEmitter emitterImpl;
+    private static JMXServiceURL url;
+    private static JMXConnectorServer server;
+    private static JMXConnector conn;
+    private static Listener listener = new Listener();
+
+    private static long leaseTime = 100;
+    private static final int multiple = 5;
+    private static final long bigWaiting = 6000;
+
+    public static void main(String[] args) throws Exception {
+        System.out.println(">>> Test the event service lease");
+
+        // for 1.5
+        if (System.getProperty("java.version").startsWith("1.5") &&
+                !mbeanServer.isRegistered(EventClientDelegateMBean.OBJECT_NAME)) {
+            System.out.print("Working on "+System.getProperty("java.version")+
+                    " register "+EventClientDelegateMBean.OBJECT_NAME);
+
+            mbeanServer.registerMBean(EventClientDelegate.
+                    getEventClientDelegate(mbeanServer),
+                    EventClientDelegateMBean.OBJECT_NAME);
+        }
+
+        System.setProperty("com.sun.event.lease.time",
+                String.valueOf(leaseTime));
+        emitter = new ObjectName("Default:name=NotificationEmitter");
+        emitterImpl = new NotificationEmitter();
+        mbeanServer.registerMBean(emitterImpl, emitter);
+
+        String[] types = new String[]{"PushingEventRelay", "FetchingEventRelay"};
+        String[] protos = new String[]{"rmi", "iiop", "jmxmp"};
+        for (String prot : protos) {
+            url = new JMXServiceURL(prot, null, 0);
+
+            try {
+                server =
+                JMXConnectorServerFactory.newJMXConnectorServer(url,
+                null, mbeanServer);
+                server.start();
+            } catch (Exception e) {
+                System.out.println(">>> Skip "+prot+", not support.");
+                continue;
+            }
+
+            url = server.getAddress();
+
+            try {
+                for (String type: types) {
+                    test(type);
+                }
+            } finally {
+                server.stop();
+            }
+        }
+    }
+
+    private static void test(String type) throws Exception {
+        System.out.println("\n\n>>> Testing "+type+" on "+url+" ...");
+        newConn();
+        EventClient ec = newEventClient(type);
+
+        ec.addNotificationListener(emitter,
+                listener, null, null);
+
+        System.out.println(">>> Send a notification and should receive it.");
+        emitterImpl.sendNotif(++counter);
+
+        if (!waitNotif(bigWaiting, counter)) {
+            throw new RuntimeException(">>> Failed to receive notif.");
+        }
+
+        System.out.println(">>> Sleep 3 times of requested lease time.");
+        Thread.sleep(leaseTime*3);
+        System.out.println(">>> Send again a notification and should receive it.");
+        emitterImpl.sendNotif(++counter);
+
+        if (!waitNotif(bigWaiting, counter)) {
+            throw new RuntimeException(">>> Failed to receive notif.");
+        }
+
+        System.out.println(">>> Close the client connection: "+
+                conn.getConnectionId());
+        conn.close();
+
+        System.out.println(">>> Waiting lease timeout to do clean.");
+
+        if (!emitterImpl.waitingClean(leaseTime*multiple)) {
+            throw new RuntimeException(
+                    ">>> The event lease failed to do clean: "+
+                    emitterImpl.listenerSize);
+        } else {
+            System.out.println(">>> The listener has been removed.");
+        }
+
+        // Check that the client id has indeed been removed, by trying to
+        // remove it again, which should fail.
+        newConn();
+        try {
+            EventClientDelegateMBean proxy =
+                EventClientDelegate.getProxy(conn.getMBeanServerConnection());
+            proxy.removeClient(ec.getEventRelay().getClientId());
+
+            throw new RuntimeException(
+                    ">>> The client id is not removed.");
+        } catch (EventClientNotFoundException ecnfe) {
+            // OK
+            System.out.println(">>> The client id has been removed.");
+        }
+        conn.close();
+
+        System.out.println(">>> Reconnect to the server.");
+        newConn();
+
+        System.out.println(">>> Create a new EventClient and add the listeners" +
+                " in the failed EventClient into new EventClient");
+        EventClient newEC = newEventClient(type);
+        newEC.addListeners(ec.getListeners());
+        // We expect ec.close() to get IOException because we closed the
+        // underlying connection.
+        try {
+            ec.close();
+            throw new RuntimeException(">>> EventClient.close did not throw " +
+                    "expected IOException");
+        } catch (IOException e) {
+            System.out.println(">>> EventClient.close threw expected exception: " + e);
+        }
+
+        emitterImpl.sendNotif(++counter);
+
+        if (!waitNotif(bigWaiting, counter)) {
+            throw new RuntimeException(">>> The event client failed to add " +
+                    "all old registered listeners after re-connection.");
+        } else {
+            System.out.println(">>> Successfully received notification from" +
+                    " new EventClient.");
+        }
+
+        System.out.println(">>> Clean the failed EventClient.");
+        ec.close();
+        if (ec.getListeners().size() != 0) {
+            throw new RuntimeException(">>> The event client fails to do clean.");
+        }
+
+        System.out.println(">>> Clean the new EventClient.");
+        newEC.close();
+        if (newEC.getListeners().size() != 0) {
+            throw new RuntimeException(">>> The event client fails to do clean.");
+        }
+
+        conn.close();
+        System.out.println(">>> Testing "+type+" on "+url+" ... done");
+    }
+
+    private static boolean waitNotif(long time, int sequenceNumber)
+    throws Exception {
+        synchronized(notifList) {
+            if (search(sequenceNumber)) {
+                return true;
+            }
+
+            long stopTime = System.currentTimeMillis() + time;
+            long toWait = time;
+            while (toWait > 0) {
+                notifList.wait(toWait);
+
+                if (search(sequenceNumber)) {
+                    return true;
+                }
+
+                toWait = stopTime - System.currentTimeMillis();
+            }
+
+            return false;
+        }
+    }
+
+    private static boolean search(int sequenceNumber) {
+        while(notifList.size() > 0) {
+            Notification n = notifList.remove(0);
+            if (n.getSequenceNumber() == sequenceNumber) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+//--------------------------
+// private classes
+//--------------------------
+
+    private static class Listener implements NotificationListener {
+        public void handleNotification(Notification notif, Object handback) {
+            synchronized (notifList) {
+                notifList.add(notif);
+                notifList.notify();
+            }
+        }
+    }
+
+    public static class NotificationEmitter extends NotificationBroadcasterSupport
+            implements NotificationEmitterMBean {
+
+        public MBeanNotificationInfo[] getNotificationInfo() {
+            final String[] ntfTypes = {myType};
+
+            final MBeanNotificationInfo[] ntfInfoArray  = {
+                new MBeanNotificationInfo(ntfTypes,
+                        "javax.management.Notification",
+                        "Notifications sent by the NotificationEmitter")};
+
+            return ntfInfoArray;
+        }
+
+        /**
+         * Send Notification objects.
+         *
+         * @param nb The number of notifications to send
+         */
+        public void sendNotif(int sequenceNumber) {
+            Notification notif = new Notification(myType, this, sequenceNumber);
+            sendNotification(notif);
+        }
+
+        public void addNotificationListener(NotificationListener listener,
+                NotificationFilter filter, Object handback) {
+            super.addNotificationListener(listener, filter, handback);
+
+            listenerSize++;
+        }
+
+        public void removeNotificationListener(NotificationListener listener)
+        throws ListenerNotFoundException {
+            super.removeNotificationListener(listener);
+            listenerSize--;
+
+            synchronized(this) {
+                if (listenerSize == 0) {
+                    this.notifyAll();
+                }
+            }
+        }
+
+        public void removeNotificationListener(NotificationListener listener,
+                NotificationFilter filter, Object handback)
+                throws ListenerNotFoundException {
+            super.removeNotificationListener(listener, filter, handback);
+            listenerSize--;
+
+            synchronized(this) {
+                if (listenerSize == 0) {
+                    this.notifyAll();
+                }
+            }
+        }
+
+        public boolean waitingClean(long timeout) throws Exception {
+            synchronized(this) {
+                long stopTime = System.currentTimeMillis() + timeout;
+                long toWait = timeout;
+                while (listenerSize != 0 && toWait > 0) {
+                    this.wait(toWait);
+                    toWait = stopTime - System.currentTimeMillis();
+                }
+            }
+
+            return listenerSize == 0;
+        }
+
+        public int listenerSize = 0;
+
+        private final String myType = "notification.my_notification";
+    }
+
+    public interface NotificationEmitterMBean {
+        public void sendNotif(int sequenceNumber);
+    }
+
+    private static void newConn() throws IOException {
+        conn = JMXConnectorFactory.connect(url);
+    }
+
+    private static EventClient newEventClient(String type) throws Exception {
+        EventClientDelegateMBean proxy =
+                EventClientDelegate.getProxy(conn.getMBeanServerConnection());
+        if (type.equals("PushingEventRelay")) {
+            return new EventClient(proxy,
+                    new FetchingEventRelay(proxy), null, null, leaseTime);
+        } else if (type.equals("FetchingEventRelay")) {
+            return new EventClient(proxy,
+                    new FetchingEventRelay(proxy), null, null, leaseTime);
+        } else {
+            throw new RuntimeException("Wrong event client type: "+type);
+        }
+    }
+
+    private static int counter = 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/eventService/ListenerTest.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,224 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test ListenerTest.java 1.7 08/01/22
+ * @bug 5108776
+ * @summary Basic test for EventClient.
+ * @author Shanliang JIANG
+ * @run clean ListenerTest
+ * @run build ListenerTest
+ * @run main ListenerTest
+ */
+
+import javax.management.MBeanNotificationInfo;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerConnection;
+import javax.management.MBeanServerFactory;
+import javax.management.Notification;
+import javax.management.NotificationBroadcasterSupport;
+import javax.management.NotificationListener;
+import javax.management.ObjectName;
+import javax.management.event.*;
+import javax.management.remote.JMXConnector;
+import javax.management.remote.JMXConnectorFactory;
+import javax.management.remote.JMXConnectorServer;
+import javax.management.remote.JMXConnectorServerFactory;
+import javax.management.remote.JMXServiceURL;
+
+/**
+ *
+ */
+public class ListenerTest {
+    private static MBeanServer mbeanServer;
+    private static ObjectName emitter;
+    private static JMXServiceURL url;
+    private static JMXConnectorServer server;
+    private static JMXConnector conn;
+    private static MBeanServerConnection client;
+
+    /**
+     * @param args the command line arguments
+     */
+    public static void main(String[] args) throws Exception {
+
+        System.out.println(">>> ListenerTest-main basic tests ...");
+        mbeanServer = MBeanServerFactory.createMBeanServer();
+
+        // for 1.5
+        if (System.getProperty("java.version").startsWith("1.5") &&
+                !mbeanServer.isRegistered(EventClientDelegateMBean.OBJECT_NAME)) {
+            System.out.print("Working on "+System.getProperty("java.version")+
+                    " register "+EventClientDelegateMBean.OBJECT_NAME);
+
+            mbeanServer.registerMBean(EventClientDelegate.
+                    getEventClientDelegate(mbeanServer),
+                    EventClientDelegateMBean.OBJECT_NAME);
+        }
+
+        emitter = new ObjectName("Default:name=NotificationEmitter");
+
+        url = new JMXServiceURL("rmi", null, 0) ;
+        server =
+                JMXConnectorServerFactory.newJMXConnectorServer(url, null, mbeanServer);
+        server.start();
+
+        url = server.getAddress();
+        conn = JMXConnectorFactory.connect(url, null);
+        client = conn.getMBeanServerConnection();
+
+        mbeanServer.registerMBean(new NotificationEmitter(), emitter);
+
+        boolean succeed;
+
+        System.out.println(">>> ListenerTest-main: using the fetching EventRelay...");
+        succeed = test(new EventClient(client));
+
+        System.out.println(">>> ListenerTest-main: using the pushing EventRelay...");
+        EventClientDelegateMBean ecd = EventClientDelegate.getProxy(client);
+        succeed &= test(new EventClient(ecd,
+                new RMIPushEventRelay(ecd),
+                null, null,
+                EventClient.DEFAULT_LEASE_TIMEOUT));
+
+        conn.close();
+        server.stop();
+
+        if (succeed) {
+            System.out.println(">>> ListenerTest-main: PASSED!");
+        } else {
+            System.out.println("\n>>> ListenerTest-main: FAILED!");
+            System.exit(1);
+        }
+    }
+
+    public static boolean test(EventClient efClient) throws Exception {
+        // add listener from the client side
+        Listener listener = new Listener();
+        efClient.addNotificationListener(emitter, listener, null, null);
+
+        // ask to send notifs
+        Object[] params = new Object[] {new Integer(sendNB)};
+        String[] signatures = new String[] {"java.lang.Integer"};
+        client.invoke(emitter, "sendNotifications", params, signatures);
+
+        // waiting
+        long toWait = 6000;
+        long stopTime = System.currentTimeMillis() + toWait;
+
+        synchronized(listener) {
+            while(listener.received < sendNB && toWait > 0) {
+                listener.wait(toWait);
+                toWait = stopTime - System.currentTimeMillis();
+            }
+        }
+
+        // clean
+        efClient.removeNotificationListener(emitter, listener, null, null);
+        efClient.close();
+
+        if (listener.received != sendNB) {
+            System.out.println(">>> ListenerTest-test: FAILED! Expected to receive "+sendNB+", but got "+listener.received);
+
+            return false;
+        } else if (listener.seqErr > 0) {
+            System.out.println(">>> ListenerTest-test: FAILED! The receiving sequence is not correct.");
+
+            return false;
+        } else {
+            System.out.println(">>> ListenerTest-test: got all expected "+listener.received);
+            return true;
+        }
+    }
+
+    private static class Listener implements NotificationListener {
+        public int received = 0;
+        public int seqErr = 0;
+
+        private long lastSeq = -1;
+
+        public void handleNotification(Notification notif, Object handback) {
+            if (!myType.equals(notif.getType())) {
+                System.out.println(">>> EventManagerTest-Listener: got unexpected notif: "+notif);
+                System.exit(1);
+            }
+
+            if (lastSeq == -1) {
+                lastSeq = notif.getSequenceNumber();
+            } else if (notif.getSequenceNumber() - lastSeq++ != 1) {
+                seqErr++;
+            }
+
+            System.out.println(">>> ListenerTest-Listener: got notif "+notif.getSequenceNumber());
+
+            synchronized(this) {
+                if (++received >= sendNB) {
+                    this.notify();
+                }
+            }
+
+            System.out.println(">>> ListenerTest-Listener: received = "+received);
+        }
+    }
+
+    public static class NotificationEmitter extends NotificationBroadcasterSupport
+            implements NotificationEmitterMBean {
+
+        public MBeanNotificationInfo[] getNotificationInfo() {
+            final String[] ntfTypes = {myType};
+
+            final MBeanNotificationInfo[] ntfInfoArray  = {
+                new MBeanNotificationInfo(ntfTypes,
+                        "javax.management.Notification",
+                        "Notifications sent by the NotificationEmitter")};
+
+                        return ntfInfoArray;
+        }
+
+        /**
+         * Send Notification objects.
+         *
+         * @param nb The number of notifications to send
+         */
+        public void sendNotifications(Integer nb) {
+            Notification notif;
+            for (int i=1; i<=nb.intValue(); i++) {
+                notif = new Notification(myType, this, count++);
+                //System.out.println(">>> ListenerTest-NotificationEmitter-sendNotifications: "+i);
+
+                sendNotification(notif);
+            }
+        }
+
+
+    }
+
+    public interface NotificationEmitterMBean {
+        public void sendNotifications(Integer nb);
+    }
+
+    private static int sendNB = 20;
+    private static int count = 0;
+
+    private static final String myType = "notification.my_notification";
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/eventService/MyFetchingEventForwarder.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,53 @@
+/*
+ * MyList.java
+ *
+ * Created on Oct 23, 2007, 2:45:57 PM
+ *
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+/**
+ *
+ * @author sjiang
+ */
+
+import java.io.IOException;
+import java.util.ArrayList;
+import javax.management.event.FetchingEventForwarder;
+
+public class MyFetchingEventForwarder extends FetchingEventForwarder {
+
+    public MyFetchingEventForwarder() {
+        super(1000);
+        shared = this;
+        setList(myList);
+    }
+
+    public void setAgain() {
+        setList(myList);
+    }
+
+    public void setClientId(String clientId) throws IOException {
+        used = true;
+        super.setClientId(clientId);
+    }
+
+    public boolean isUsed() {
+        return used;
+    }
+
+    private class MyList<TargetedNotification>
+            extends ArrayList<TargetedNotification> {
+
+        public boolean add(TargetedNotification e) {
+            used = true;
+
+            return super.add(e);
+        }
+    }
+
+    public MyList myList = new MyList();
+    public static MyFetchingEventForwarder shared;
+    private boolean used = false;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/eventService/NotSerializableNotifTest.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,227 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+
+/*
+ * @test NotSerializableNotifTest.java 1.5 08/01/22
+ * @bug 5108776
+ * @summary Basic test for EventClient.
+ * @author Shanliang JIANG
+ * @run clean NotSerializableNotifTest
+ * @run build NotSerializableNotifTest
+ * @run main NotSerializableNotifTest
+ */
+
+
+// JMX imports
+//
+import javax.management.* ;
+import javax.management.event.EventClient;
+import javax.management.event.EventClientDelegate;
+import javax.management.event.EventClientDelegateMBean;
+import javax.management.event.EventRelay;
+import javax.management.event.FetchingEventRelay;
+
+import javax.management.remote.*;
+import javax.management.remote.JMXServiceURL;
+
+public class NotSerializableNotifTest {
+    private static MBeanServer mbeanServer =
+        MBeanServerFactory.createMBeanServer();
+    private static ObjectName emitter;
+    private static int port = 2468;
+
+    private static String[] protocols;
+
+    private static final int sentNotifs = 50;
+
+    public static void main(String[] args) throws Exception {
+        System.out.println(">>> Test to send a not serializable notification");
+
+        // for 1.5
+        if (System.getProperty("java.version").startsWith("1.5") &&
+                !mbeanServer.isRegistered(EventClientDelegateMBean.OBJECT_NAME)) {
+            System.out.print("Working on "+System.getProperty("java.version")+
+                    " register "+EventClientDelegateMBean.OBJECT_NAME);
+
+            mbeanServer.registerMBean(EventClientDelegate.
+                    getEventClientDelegate(mbeanServer),
+                    EventClientDelegateMBean.OBJECT_NAME);
+        }
+
+        NotificationEmitter nm = new NotificationEmitter();
+        emitter = new ObjectName("Default:name=NotificationEmitter");
+        mbeanServer.registerMBean(nm, emitter);
+        String proto = "rmi";
+
+        System.out.println(">>> Test for protocol " + proto);
+
+        JMXServiceURL url = new JMXServiceURL(proto, null, 0);
+
+        JMXConnectorServer server =
+            JMXConnectorServerFactory.newJMXConnectorServer(url, null, mbeanServer);
+
+        server.start();
+
+        url = server.getAddress();
+        JMXConnector conn = JMXConnectorFactory.connect(url, null);
+        MBeanServerConnection client = conn.getMBeanServerConnection();
+
+        EventClientDelegateMBean ecd = EventClientDelegate.getProxy(client);
+        EventRelay eventRelay = new FetchingEventRelay(
+                ecd,
+                FetchingEventRelay.DEFAULT_BUFFER_SIZE,
+                10,
+                FetchingEventRelay.DEFAULT_MAX_NOTIFICATIONS,
+                null);
+        EventClient ec = new EventClient(ecd, eventRelay, null, null,
+                EventClient.DEFAULT_LEASE_TIMEOUT);
+
+        // add listener from the client side
+        Listener listener = new Listener();
+        ec.addNotificationListener(emitter, listener, null, null);
+
+        LostListener lostListener = new LostListener();
+        ec.addEventClientListener(lostListener, null, null);
+
+        // ask to send one not serializable notif
+        System.out.println(">>> sending not serializable notifs ...");
+
+        Object[] params = new Object[] {new Integer(sentNotifs)};
+        String[] signatures = new String[] {"java.lang.Integer"};
+        client.invoke(emitter, "sendNotserializableNotifs", params, signatures);
+
+//      nm.sendNotserializableNotifs(sentNotifs);
+//      nm.sendNotifications(1);
+
+        // waiting
+        synchronized(lostListener) {
+            if (lostListener.lostCount != sentNotifs) {
+                lostListener.wait(6000);
+            }
+        }
+
+        Thread.sleep(100);
+
+        if (lostListener.lostCount != sentNotifs) {
+            System.out.println(">>> FAILED. Expected "+sentNotifs+", but got "+lostListener.lostCount);
+            System.exit(1);
+        }
+
+        System.out.println(">>> Passed.");
+
+        ec.close();
+        conn.close();
+        server.stop();
+    }
+
+
+//--------------------------
+// private classes
+//--------------------------
+    private static class Listener implements NotificationListener {
+        public void handleNotification(Notification n, Object handback) {
+            System.out.println(">>> Listener: receive: "+n);
+        }
+    }
+
+
+    private static class LostListener implements NotificationListener {
+        public void handleNotification(Notification n, Object handback) {
+             if (!EventClient.NOTIFS_LOST.equals(n.getType())) {
+                return;
+            }
+
+            if (!(n.getUserData() instanceof Long)) {
+                System.out.println(">>> Listener: JMXConnectionNotification userData " +
+                                   "not a Long: " + n.getUserData());
+                System.exit(1);
+            } else {
+                int lost = ((Long) n.getUserData()).intValue();
+                lostCount += lost;
+                if (lostCount >= sentNotifs) {
+                    synchronized(this) {
+                        this.notifyAll();
+                    }
+                }
+            }
+
+        }
+
+
+        private int lostCount = 0;
+    }
+
+    public static class NotificationEmitter extends NotificationBroadcasterSupport
+        implements NotificationEmitterMBean {
+
+        public MBeanNotificationInfo[] getNotificationInfo() {
+            final String[] ntfTypes = {myType};
+
+            final MBeanNotificationInfo[] ntfInfoArray  = {
+                new MBeanNotificationInfo(ntfTypes,
+                                          "javax.management.Notification",
+                                          "Notifications sent by the NotificationEmitter")};
+
+            return ntfInfoArray;
+        }
+
+        /**
+         * Send not serializable Notifications.
+         *
+         * @param nb The number of notifications to send
+         */
+        public void sendNotserializableNotifs(Integer nb) {
+
+            Notification notif;
+            for (int i=1; i<=nb.intValue(); i++) {
+                notif = new Notification(myType, this, i);
+
+                notif.setUserData(new Object());
+                sendNotification(notif);
+            }
+        }
+
+        /**
+         * Send Notification objects.
+         *
+         * @param nb The number of notifications to send
+         */
+        public void sendNotifications(Integer nb) {
+            Notification notif;
+            for (int i=1; i<=nb.intValue(); i++) {
+                notif = new Notification(myType, this, i);
+
+                sendNotification(notif);
+            }
+        }
+
+        private final String myType = "notification.my_notification";
+    }
+
+    public interface NotificationEmitterMBean {
+        public void sendNotifications(Integer nb);
+
+        public void sendNotserializableNotifs(Integer nb);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/eventService/PublishTest.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,184 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+import javax.management.MBeanServer;
+import javax.management.MBeanServerConnection;
+import javax.management.MBeanServerFactory;
+import javax.management.Notification;
+import javax.management.NotificationListener;
+import javax.management.ObjectName;
+import javax.management.event.*;
+import javax.management.remote.JMXConnector;
+import javax.management.remote.JMXConnectorFactory;
+import javax.management.remote.JMXConnectorServer;
+import javax.management.remote.JMXConnectorServerFactory;
+import javax.management.remote.JMXServiceURL;
+
+/**
+ *
+ */
+public class PublishTest {
+    private static MBeanServer mbeanServer;
+    private static EventManager eventManager;
+    private static ObjectName emitter;
+    private static JMXServiceURL url;
+    private static JMXConnectorServer server;
+    private static JMXConnector conn;
+    private static MBeanServerConnection client;
+
+    /**
+     * @param args the command line arguments
+     */
+    public static void main(String[] args) throws Exception {
+        System.out.println(">>> PublishTest-main basic tests ...");
+        mbeanServer = MBeanServerFactory.createMBeanServer();
+
+        // for 1.5
+        if (System.getProperty("java.version").startsWith("1.5") &&
+                !mbeanServer.isRegistered(EventClientDelegateMBean.OBJECT_NAME)) {
+            System.out.print("Working on "+System.getProperty("java.version")+
+                    " register "+EventClientDelegateMBean.OBJECT_NAME);
+
+            mbeanServer.registerMBean(EventClientDelegate.
+                    getEventClientDelegate(mbeanServer),
+                    EventClientDelegateMBean.OBJECT_NAME);
+        }
+
+        eventManager = EventManager.getEventManager(mbeanServer);
+
+        emitter = new ObjectName("Default:name=NotificationEmitter");
+
+        url = new JMXServiceURL("rmi", null, 0) ;
+        server =
+                JMXConnectorServerFactory.newJMXConnectorServer(url, null, mbeanServer);
+        server.start();
+
+        url = server.getAddress();
+        conn = JMXConnectorFactory.connect(url, null);
+        client = conn.getMBeanServerConnection();
+
+        boolean succeed;
+
+        System.out.println(">>> PublishTest-main: using the fetching EventRelay...");
+        succeed = test(new EventClient(client));
+
+        System.out.println(">>> PublishTest-main: using the pushing EventRelay...");
+        succeed &= test(new EventClient(client,
+                new RMIPushEventRelay(EventClientDelegate.getProxy(client)),
+                null,
+                EventClient.DEFAULT_LEASE_TIMEOUT));
+
+        conn.close();
+        server.stop();
+
+        if (succeed) {
+            System.out.println(">>> PublishTest-main: PASSE!");
+        } else {
+            System.out.println("\n>>> PublishTest-main: FAILED!");
+            System.exit(1);
+        }
+    }
+
+    public static boolean test(EventClient efClient) throws Exception {
+        // add listener from the client side
+        Listener listener = new Listener();
+        efClient.subscribe(emitter, listener, null, null);
+
+        ObjectName other = new ObjectName("Default:name=other");
+        // publish notifs
+        for (int i=0; i<sendNB; i++) {
+            Notification notif = new Notification(myType, emitter, count++);
+            Notification notif2 = new Notification(myType, other, 0);
+            //System.out.println(">>> EventManagerService-NotificationEmitter-sendNotifications: "+i);
+
+            eventManager.publish(emitter, notif);
+            eventManager.publish(other, notif2); // should not received
+        }
+
+        // waiting
+        long toWait = 6000;
+        long stopTime = System.currentTimeMillis() + toWait;
+
+        synchronized(listener) {
+            while(listener.received < sendNB && toWait > 0) {
+                listener.wait(toWait);
+                toWait = stopTime - System.currentTimeMillis();
+            }
+        }
+
+        // clean
+        efClient.unsubscribe(emitter, listener);
+        efClient.close();
+
+        if (listener.received != sendNB) {
+            System.out.println(">>> PublishTest-test: FAILED! Expected to receive "+sendNB+", but got "+listener.received);
+
+            return false;
+        } else if (listener.seqErr > 0) {
+            System.out.println(">>> PublishTest-test: FAILED! The receiving sequence is not correct.");
+
+            return false;
+        } else {
+            System.out.println(">>> PublishTest-test: got all expected "+listener.received);
+            return true;
+        }
+    }
+
+    private static class Listener implements NotificationListener {
+        public int received = 0;
+        public int seqErr = 0;
+
+        private long lastSeq = -1;
+
+        public void handleNotification(Notification notif, Object handback) {
+            if (!myType.equals(notif.getType())) {
+                System.out.println(">>> PublishTest-Listener: got unexpected notif: "+notif);
+                System.exit(1);
+            } else if (!emitter.equals(notif.getSource())) {
+                System.out.println(">>> PublishTest-Listener: unknown ObjectName: "+notif.getSource());
+                System.exit(1);
+            }
+
+            if (lastSeq == -1) {
+                lastSeq = notif.getSequenceNumber();
+            } else if (notif.getSequenceNumber() - lastSeq++ != 1) {
+                seqErr++;
+            }
+
+            System.out.println(">>> PublishTest-Listener: got notif "+notif.getSequenceNumber());
+
+            synchronized(this) {
+                if (++received >= sendNB) {
+                    this.notify();
+                }
+            }
+
+            System.out.println(">>> PublishTest-Listener: received = "+received);
+        }
+    }
+
+    private static int sendNB = 20;
+    private static long count = 0;
+
+    private static final String myType = "notification.my_notification";
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/eventService/ReconnectableConnectorTest.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,488 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test ReconnectableJMXConnector
+ * @bug 5108776
+ * @summary Check that the Event Service can be used to build a
+ * ReconnectableJMXConnector.
+ * @author Eamonn McManus
+ */
+
+import java.io.IOException;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.Date;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+import javax.management.ListenerNotFoundException;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerConnection;
+import javax.management.MBeanServerFactory;
+import javax.management.Notification;
+import javax.management.NotificationBroadcasterSupport;
+import javax.management.NotificationFilter;
+import javax.management.NotificationListener;
+import javax.management.ObjectName;
+import javax.management.event.EventClient;
+import javax.management.remote.JMXConnectionNotification;
+import javax.management.remote.JMXConnector;
+import javax.management.remote.JMXConnectorFactory;
+import javax.management.remote.JMXConnectorServer;
+import javax.management.remote.JMXConnectorServerFactory;
+import javax.management.remote.JMXServiceURL;
+import javax.security.auth.Subject;
+
+/*
+ * This test checks that it is possible to use the Event Service to create
+ * a "reconnectable connector".
+ *
+ * In the JMX Remote API, we deliberately specified that a connector client
+ * (JMXConnector) that encounters a network failure is then permanently broken.
+ * The idea being that adding recovery logic to the basic connector client
+ * would make it much more complicated and less reliable, and the logic would
+ * in any case never correspond to what a given situation needs. Some of
+ * the tough questions are: Should the connector try to mask the failure by
+ * blocking operations until the failure is resolved? How long should the
+ * connector try to reestablish the connection before giving up? Rather than
+ * try to solve this problem in the connector, we suggested that people who
+ * wanted to recover from network failures could implement the JMXConnector
+ * interface themselves so that it forwards to a wrapped JMXConnector that can
+ * be replaced in case of network failure.
+ *
+ * This works fine except that the connector client has state,
+ * in the form of listeners added by the user through the
+ * MBeanServerConnection.addNotificationListener method. It's possible
+ * for the wrapper to keep track of these listeners as well as forwarding
+ * them to the wrapped JMXConnector, so that it can reapply them to
+ * a replacement JMXConnector after failure recover. But it's quite
+ * tricky, particularly because of the two- and four-argument versions of
+ * removeNotificationListener.
+ *
+ * The Event Service can take care of this for you through the EventClient
+ * class. Listeners added through that class are implemented in a way that
+ * doesn't require the connector client to maintain any state, so they should
+ * continue to work transparently after replacing the wrapped JMXConnector.
+ * This test is a proof of concept that shows it works.  Quite a number of
+ * details would need to be changed to build a reliable reconnectable
+ * connector.
+ *
+ * The test simulates network failure by rewrapping the wrapped JMXConnector's
+ * MBeanServerConnection (MBSC) in a "breakable" MBSC which we can cause
+ * to stop working.  We do this in two phases.  The first phase suspends
+ * any MBSC calls just at the point where they would return to the caller.
+ * The goal here is to block an EventClientDelegateMBean.fetchNotifications
+ * operation when it has received notifications but not yet delivered them
+ * to the EventClient.  This is the most delicate point where a breakage
+ * can occur, because the EventClientDelegate must not drop those notifs
+ * from its buffer until another fetchNotifs call arrives with a later
+ * sequence number (which is an implicit ack of the previous set of
+ * notifs).  Once the fetchNotifs call is suspended, we "kill" the MBSC,
+ * causing it to throw IOException from this and any other calls.  That
+ * triggers the reconnect logic, which will make a new MBSC and issue
+ * the same fetchNotifs call to it.
+ *
+ * The test could be improved by synchronizing explicitly between the
+ * breakable MBSC and the mainline, so we only proceed to kill the MBSC
+ * when we are sure that the fetchNotifs call is blocked.  As it is,
+ * we have a small delay which both ensures that no notifs are delivered
+ * while the connection is suspended, and if the machine is fast enough
+ * allows the fetchNotifs call to reach the blocking point.
+ */
+public class ReconnectableConnectorTest {
+    private static class ReconnectableJMXConnector implements JMXConnector {
+        private final JMXServiceURL url;
+        private AtomicReference<JMXConnector> wrappedJMXC =
+                new AtomicReference<JMXConnector>();
+        private AtomicReference<MBeanServerConnection> wrappedMBSC =
+                new AtomicReference<MBeanServerConnection>();
+        private final NotificationBroadcasterSupport broadcaster =
+                new NotificationBroadcasterSupport();
+        private final Lock connectLock = new ReentrantLock();
+
+        ReconnectableJMXConnector(JMXServiceURL url) {
+            this.url = url;
+        }
+
+        private class ReconnectIH implements InvocationHandler {
+            public Object invoke(Object proxy, Method method, Object[] args)
+                    throws Throwable {
+                try {
+                    return method.invoke(wrappedMBSC.get(), args);
+                } catch (InvocationTargetException e) {
+                    if (e.getCause() instanceof IOException) {
+                        connect();
+                        try {
+                            return method.invoke(wrappedMBSC.get(),args);
+                        } catch (InvocationTargetException ee) {
+                            throw ee.getCause();
+                        }
+                    }
+                    throw e.getCause();
+                }
+            }
+        }
+
+        private class FailureListener implements NotificationListener {
+            public void handleNotification(Notification n, Object h) {
+                String type = n.getType();
+                if (type.equals(JMXConnectionNotification.FAILED)) {
+                    try {
+                        connect();
+                    } catch (IOException e) {
+                        broadcaster.sendNotification(n);
+                    }
+                } else if (type.equals(JMXConnectionNotification.NOTIFS_LOST))
+                    broadcaster.sendNotification(n);
+            }
+        }
+
+        public void connect() throws IOException {
+            connectLock.lock();
+            try {
+                connectWithLock();
+            } finally {
+                connectLock.unlock();
+            }
+        }
+
+        private void connectWithLock() throws IOException {
+            MBeanServerConnection mbsc = wrappedMBSC.get();
+            if (mbsc != null) {
+                try {
+                    mbsc.getDefaultDomain();
+                    return;  // the connection works
+                } catch (IOException e) {
+                    // OK: the connection doesn't work, so make a new one
+                }
+            }
+            // This is where we would need to add the fancy logic that
+            // allows the connection to keep failing for a while
+            // before giving up.
+            JMXConnector jmxc = JMXConnectorFactory.connect(url);
+            jmxc.addConnectionNotificationListener(
+                    new FailureListener(), null, null);
+            wrappedJMXC.set(jmxc);
+            if (false)
+                wrappedMBSC.set(jmxc.getMBeanServerConnection());
+            else {
+                mbsc = jmxc.getMBeanServerConnection();
+                InvocationHandler ih = new BreakableIH(mbsc);
+                mbsc = (MBeanServerConnection) Proxy.newProxyInstance(
+                        MBeanServerConnection.class.getClassLoader(),
+                        new Class<?>[] {MBeanServerConnection.class},
+                        ih);
+                wrappedMBSC.set(mbsc);
+            }
+        }
+
+        private BreakableIH breakableIH() {
+            MBeanServerConnection mbsc = wrappedMBSC.get();
+            return (BreakableIH) Proxy.getInvocationHandler(mbsc);
+        }
+
+        void suspend() {
+            BreakableIH ih = breakableIH();
+            ih.suspend();
+        }
+
+        void kill() throws IOException {
+            BreakableIH ih = breakableIH();
+            wrappedJMXC.get().close();
+            ih.kill();
+        }
+
+        public void connect(Map<String, ?> env) throws IOException {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        private final AtomicReference<MBeanServerConnection> mbscRef =
+                new AtomicReference<MBeanServerConnection>();
+
+        public MBeanServerConnection getMBeanServerConnection()
+                throws IOException {
+            connect();
+            // Synchro here is not strictly correct: two threads could make
+            // an MBSC at the same time.  OK for a test but beware for real
+            // code.
+            MBeanServerConnection mbsc = mbscRef.get();
+            if (mbsc != null)
+                return mbsc;
+            mbsc = (MBeanServerConnection) Proxy.newProxyInstance(
+                    MBeanServerConnection.class.getClassLoader(),
+                    new Class<?>[] {MBeanServerConnection.class},
+                    new ReconnectIH());
+            mbsc = EventClient.getEventClientConnection(mbsc);
+            mbscRef.set(mbsc);
+            return mbsc;
+        }
+
+        public MBeanServerConnection getMBeanServerConnection(
+                Subject delegationSubject) throws IOException {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        public void close() throws IOException {
+            wrappedJMXC.get().close();
+        }
+
+        public void addConnectionNotificationListener(
+                NotificationListener l, NotificationFilter f, Object h) {
+            broadcaster.addNotificationListener(l, f, h);
+        }
+
+        public void removeConnectionNotificationListener(NotificationListener l)
+                throws ListenerNotFoundException {
+            broadcaster.removeNotificationListener(l);
+        }
+
+        public void removeConnectionNotificationListener(
+                NotificationListener l, NotificationFilter f, Object h)
+                throws ListenerNotFoundException {
+            broadcaster.removeNotificationListener(l, f, h);
+        }
+
+        public String getConnectionId() throws IOException {
+            return wrappedJMXC.get().getConnectionId();
+        }
+    }
+
+    // InvocationHandler that allows us to perform a two-phase "break" of
+    // an object.  The first phase suspends the object, so that calls to
+    // it are blocked just before they return.  The second phase unblocks
+    // suspended threads and causes them to throw IOException.
+    private static class BreakableIH implements InvocationHandler {
+        private final Object wrapped;
+        private final Holder<String> state = new Holder<String>("running");
+
+        BreakableIH(Object wrapped) {
+            this.wrapped = wrapped;
+        }
+
+        void suspend() {
+            state.set("suspended");
+        }
+
+        void kill() {
+            state.set("killed");
+        }
+
+        public Object invoke(Object proxy, Method method, Object[] args)
+                throws Throwable {
+            Object result;
+            try {
+                result = method.invoke(wrapped, args);
+            } catch (InvocationTargetException e) {
+                throw e.getCause();
+            }
+            String s = state.get();
+            if (s.equals("suspended"))
+                state.waitUntilEqual("killed", 3, TimeUnit.SECONDS);
+            else if (s.equals("killed"))
+                throw new IOException("Broken");
+            return result;
+        }
+    }
+
+    private static class Holder<T> {
+        private T held;
+        private Lock lock = new ReentrantLock();
+        private Condition changed = lock.newCondition();
+
+        Holder(T value) {
+            lock.lock();
+            this.held = value;
+            lock.unlock();
+        }
+
+        void waitUntilEqual(T value, long timeout, TimeUnit units)
+                throws InterruptedException {
+            long millis = units.toMillis(timeout);
+            long stop = System.currentTimeMillis() + millis;
+            Date stopDate = new Date(stop);
+            lock.lock();
+            try {
+                while (!value.equals(held)) {
+                    boolean ok = changed.awaitUntil(stopDate);
+                    if (!ok)
+                        throw new InterruptedException("Timed out");
+                }
+            } finally {
+                lock.unlock();
+            }
+        }
+
+        void set(T value) {
+            lock.lock();
+            try {
+                held = value;
+                changed.signalAll();
+            } finally {
+                lock.unlock();
+            }
+        }
+
+        T get() {
+            lock.lock();
+            try {
+                return held;
+            } finally {
+                lock.unlock();
+            }
+        }
+    }
+
+    private static class StoreListener implements NotificationListener {
+        final BlockingQueue<Notification> queue =
+                new ArrayBlockingQueue<Notification>(100);
+
+        public void handleNotification(Notification n, Object h) {
+            queue.add(n);
+        }
+
+        Notification nextNotification(long time, TimeUnit units)
+                throws InterruptedException {
+            Notification n = queue.poll(time, units);
+            if (n == null)
+                throw new NoSuchElementException("Notification wait timed out");
+            return n;
+        }
+
+        int notifCount() {
+            return queue.size();
+        }
+    }
+
+    public static interface SenderMBean {}
+    public static class Sender
+            extends NotificationBroadcasterSupport implements SenderMBean {
+        private AtomicLong seqNo = new AtomicLong(0);
+
+        void send() {
+            Notification n =
+                    new Notification("type", this, seqNo.getAndIncrement());
+            sendNotification(n);
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        MBeanServer mbs = MBeanServerFactory.newMBeanServer();
+        Sender sender = new Sender();
+        ObjectName name = new ObjectName("a:b=c");
+        mbs.registerMBean(sender, name);
+
+        System.out.println("Creating connector server");
+        JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///");
+        JMXConnectorServer cs = JMXConnectorServerFactory.newJMXConnectorServer(
+                url, null, mbs);
+        cs.start();
+
+        StoreListener csListener = new StoreListener();
+        cs.addNotificationListener(csListener, null, null);
+
+        System.out.println("Creating reconnectable client");
+        JMXServiceURL addr = cs.getAddress();
+        ReconnectableJMXConnector cc = new ReconnectableJMXConnector(addr);
+        MBeanServerConnection mbsc = cc.getMBeanServerConnection();
+
+        System.out.println("Checking server has sent new-client notif");
+        Notification csn = csListener.nextNotification(1, TimeUnit.SECONDS);
+        assertEquals("CS notif type",
+                JMXConnectionNotification.OPENED, csn.getType());
+
+        StoreListener listener = new StoreListener();
+        mbsc.addNotificationListener(name, listener, null, null);
+
+        System.out.println("Sending 10 notifs and checking they are received");
+        for (int i = 0; i < 10; i++)
+            sender.send();
+        checkNotifs(listener, 0, 10);
+
+        System.out.println("Suspending the fetchNotifs operation");
+        cc.suspend();
+        System.out.println("Sending a notif while fetchNotifs is suspended");
+        sender.send();
+        System.out.println("Brief wait before checking no notif is received");
+        Thread.sleep(2);
+        // dumpThreads();
+        assertEquals("notif queue while connector suspended",
+                0, listener.notifCount());
+        assertEquals("connector server notif queue while connector suspended",
+                0, csListener.notifCount());
+
+        System.out.println("Breaking the connection so fetchNotifs will fail over");
+        cc.kill();
+
+        System.out.println("Checking that client has reconnected");
+        csn = csListener.nextNotification(1, TimeUnit.SECONDS);
+        assertEquals("First CS notif type after kill",
+                JMXConnectionNotification.CLOSED, csn.getType());
+        csn = csListener.nextNotification(1, TimeUnit.SECONDS);
+        assertEquals("Second CS notif type after kill",
+                JMXConnectionNotification.OPENED, csn.getType());
+
+        System.out.println("Checking that suspended notif has been received");
+        checkNotifs(listener, 10, 11);
+    }
+
+    private static void checkNotifs(
+             StoreListener sl, long start, long stop)
+            throws Exception {
+        for (long i = start; i < stop; i++) {
+            Notification n = sl.nextNotification(1, TimeUnit.SECONDS);
+            assertEquals("received sequence number", i, n.getSequenceNumber());
+        }
+    }
+
+    private static void assertEquals(String what, Object expect, Object actual)
+    throws Exception {
+        if (!expect.equals(actual)) {
+            fail(what + " should be " + expect + " but is " + actual);
+        }
+    }
+
+    private static void fail(String why) throws Exception {
+        throw new Exception("TEST FAILED: " + why);
+    }
+
+    private static void dumpThreads() {
+        System.out.println("Thread stack dump");
+        Map<Thread, StackTraceElement[]> traces = Thread.getAllStackTraces();
+        for (Map.Entry<Thread, StackTraceElement[]> entry : traces.entrySet()) {
+            Thread t = entry.getKey();
+            System.out.println("===Thread " + t.getName() + "===");
+            for (StackTraceElement ste : entry.getValue())
+                System.out.println("    " + ste);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/eventService/SharingThreadTest.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,365 @@
+/*/*
+ * Copyright 2007 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test SharingThreadTest.java 1.3 08/01/22
+ * @bug 5108776
+ * @summary Basic test for EventClient to see internal thread management.
+ * @author Shanliang JIANG
+ * @run clean SharingThreadTest
+ * @run build SharingThreadTest
+ * @run main SharingThreadTest
+ */
+
+import java.io.IOException;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.Executor;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.Notification;
+import javax.management.NotificationBroadcasterSupport;
+import javax.management.NotificationFilter;
+import javax.management.NotificationListener;
+import javax.management.ObjectName;
+import javax.management.event.EventClient;
+import javax.management.event.EventClientDelegate;
+import javax.management.event.EventClientDelegateMBean;
+import javax.management.event.FetchingEventRelay;
+import javax.management.event.RMIPushEventRelay;
+import javax.management.remote.JMXConnector;
+import javax.management.remote.JMXConnectorFactory;
+import javax.management.remote.JMXConnectorServer;
+import javax.management.remote.JMXConnectorServerFactory;
+import javax.management.remote.JMXServiceURL;
+
+
+public class SharingThreadTest {
+
+    private static MBeanServer mbeanServer = MBeanServerFactory.createMBeanServer();
+    private static ObjectName emitter;
+    private static NotificationEmitter emitterImpl;
+    private static JMXServiceURL url;
+    private static JMXConnectorServer server;
+
+
+    private static int toSend = 10;
+    private static final long bigWaiting = 6000;
+    private static int counter = 0;
+    private static int jobs = 10;
+    private static int endedJobs = 0;
+
+    private static volatile String failure;
+
+    private static Executor sharedExecutor = new ThreadPoolExecutor(0, 1, 1000,
+            TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(jobs));
+            //Executors.newFixedThreadPool(1);
+
+    public static void main(String[] args) throws Exception {
+        System.out.println(">>> Test on sharing threads for multiple EventClient.");
+
+        // for 1.5
+        if (System.getProperty("java.version").startsWith("1.5") &&
+                !mbeanServer.isRegistered(EventClientDelegateMBean.OBJECT_NAME)) {
+            System.out.print("Working on "+System.getProperty("java.version")+
+                    " register "+EventClientDelegateMBean.OBJECT_NAME);
+
+            mbeanServer.registerMBean(EventClientDelegate.
+                    getEventClientDelegate(mbeanServer),
+                    EventClientDelegateMBean.OBJECT_NAME);
+
+            sharedExecutor = new ThreadPoolExecutor(1, 1, 1000,
+            TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(jobs));
+        }
+
+        emitter = new ObjectName("Default:name=NotificationEmitter");
+        emitterImpl = new NotificationEmitter();
+        mbeanServer.registerMBean(emitterImpl, emitter);
+
+        String[] types = new String[]{"PushEventRelay", "FetchingEventRelay"};
+        String[] protos = new String[]{"rmi", "iiop", "jmxmp"};
+        for (String prot : protos) {
+            url = new JMXServiceURL(prot, null, 0);
+
+            try {
+                server =
+                        JMXConnectorServerFactory.newJMXConnectorServer(url,
+                        null, mbeanServer);
+                server.start();
+            } catch (Exception e) {
+                System.out.println(">>> Skip "+prot+", not support.");
+                continue;
+            }
+
+            url = server.getAddress();
+
+            // noise
+            Thread noise = new Thread(new Runnable() {
+                public void run() {
+                    while (true) {
+                        emitterImpl.sendNotif(1, null);
+                        try {
+                            Thread.sleep(10);
+                        } catch (Exception e) {
+                            // OK
+                        }
+                    }
+                }
+            });
+            noise.setDaemon(true);
+            noise.start();
+
+            try {
+                for (String type: types) {
+                    System.out.println("\n\n>>> Testing "+type+" on "+url+" ...");
+                    JMXConnector conn = newConn();
+                    try {
+                        testType(type, conn);
+                    } finally {
+                        conn.close();
+                        System.out.println(">>> Testing "+type+" on "+url+" ... done");
+                    }
+                }
+            } finally {
+                server.stop();
+            }
+        }
+    }
+
+    private static void testType(String type, JMXConnector conn) throws Exception {
+        Thread[] threads = new Thread[jobs];
+        for (int i=0; i<jobs; i++) {
+            threads[i] = new Thread(new Job(type, conn));
+            threads[i].setDaemon(true);
+            threads[i].start();
+        }
+
+        // to wait
+        long toWait = bigWaiting*jobs;
+        long stopTime = System.currentTimeMillis() + toWait;
+
+        synchronized(SharingThreadTest.class) {
+            while (endedJobs < jobs && toWait > 0 && failure == null) {
+                SharingThreadTest.class.wait(toWait);
+                toWait = stopTime - System.currentTimeMillis();
+            }
+        }
+
+        if (endedJobs != jobs && failure == null) {
+            throw new RuntimeException("Need to set bigger waiting timeout?");
+        }
+
+        endedJobs = 0;
+    }
+
+    public static class Job implements Runnable {
+        public Job(String type, JMXConnector conn) {
+            this.type = type;
+            this.conn = conn;
+        }
+        public void run() {
+            try {
+                test(type, conn);
+
+                synchronized(SharingThreadTest.class) {
+                    endedJobs++;
+                    if (endedJobs>=jobs) {
+                        SharingThreadTest.class.notify();
+                    }
+                }
+            } catch (RuntimeException re) {
+                re.printStackTrace(System.out);
+                throw re;
+            } catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+        private final String type;
+        private final JMXConnector conn;
+    }
+
+    private static void test(String type, JMXConnector conn) throws Exception {
+        String id = getId();
+
+        Listener listener = new Listener(id);
+        Filter filter = new Filter(id);
+
+        //newConn();
+        EventClient ec = newEventClient(type, conn);
+
+        System.out.println(">>> ("+id+") To receive notifications "+toSend);
+        ec.addNotificationListener(emitter,
+                listener, filter, null);
+
+        emitterImpl.sendNotif(toSend, id);
+        listener.waitNotifs(bigWaiting, toSend);
+        if (listener.received != toSend) {
+            throw new RuntimeException(">>> ("+id+") Expected to receive: "
+                    +toSend+", but got: "+listener.received);
+        }
+
+        ec.close();
+    }
+
+//--------------------------
+// private classes
+//--------------------------
+
+    private static class Listener implements NotificationListener {
+        public Listener(String id) {
+            this.id = id;
+        }
+        public void handleNotification(Notification notif, Object handback) {
+            if (!id.equals(notif.getUserData())) {
+                System.out.println("("+id+") Filter error, my id is: "+id+
+                        ", but got "+notif.getUserData());
+                System.exit(1);
+            }
+            System.out.println("("+id+") received "+notif.getSequenceNumber());
+            synchronized (this) {
+                received++;
+
+                if (sequenceNB < 0) {
+                    sequenceNB = notif.getSequenceNumber();
+                } else if(++sequenceNB != notif.getSequenceNumber()) {
+                    fail("(" + id + ") Wrong sequence number, expected: "
+                            +sequenceNB+", but got: "+notif.getSequenceNumber());
+                }
+                if (received >= toSend || failure != null) {
+                    this.notify();
+                }
+            }
+        }
+
+        public void waitNotifs(long timeout, int nb) throws Exception {
+            long toWait = timeout;
+            long stopTime = System.currentTimeMillis() + timeout;
+            synchronized(this) {
+                while (received < nb && toWait > 0 && failure == null) {
+                    this.wait(toWait);
+                    toWait = stopTime - System.currentTimeMillis();
+                }
+            }
+        }
+
+        private String id;
+        private int received = 0;
+
+        private long sequenceNB = -1;
+    }
+
+    private static class Filter implements NotificationFilter {
+        public Filter(String id) {
+            this.id = id;
+        }
+
+        public boolean isNotificationEnabled(Notification n) {
+            return id.equals(n.getUserData());
+        }
+        private String id;
+    }
+
+    public static class NotificationEmitter extends NotificationBroadcasterSupport
+            implements NotificationEmitterMBean {
+
+        /**
+         * Send Notification objects.
+         *
+         * @param nb The number of notifications to send
+         */
+        public void sendNotif(int nb, String userData) {
+            new Thread(new SendJob(nb, userData)).start();
+        }
+
+        private class SendJob implements Runnable {
+            public SendJob(int nb, String userData) {
+                this.nb = nb;
+                this.userData = userData;
+            }
+
+            public void run() {
+                if (userData != null) {
+                    System.out.println(">>> ("+userData+") sending "+nb);
+                }
+                long sequenceNumber = 0;
+                for (int i = 0; i<nb; i++) {
+                    Notification notif = new Notification(myType, emitter,
+                            sequenceNumber++);
+                    notif.setUserData(userData);
+                    sendNotification(notif);
+                    Thread.yield();
+                    try {
+                        Thread.sleep(1);
+                    } catch (Exception e) {}
+                }
+                if (userData != null) {
+                    System.out.println(">>> ("+userData+") sending done");
+                }
+            }
+            private int nb;
+            private String userData;
+        }
+        private final String myType = "notification.my_notification";
+    }
+
+    public interface NotificationEmitterMBean {
+        public void sendNotif(int nb, String userData);
+    }
+
+    private static JMXConnector newConn() throws IOException {
+        return JMXConnectorFactory.connect(url);
+    }
+
+    private static EventClient newEventClient(String type, JMXConnector conn)
+            throws Exception {
+        EventClientDelegateMBean proxy =
+                EventClientDelegate.getProxy(conn.getMBeanServerConnection());
+        if (type.equals("PushEventRelay")) {
+            return new EventClient(proxy,
+                    new RMIPushEventRelay(proxy), sharedExecutor, null, 600);
+        } else if (type.equals("FetchingEventRelay")) {
+            return new EventClient(proxy,
+                    new FetchingEventRelay(proxy,
+                    FetchingEventRelay.DEFAULT_BUFFER_SIZE,
+                    10,
+                    FetchingEventRelay.DEFAULT_MAX_NOTIFICATIONS,
+                    sharedExecutor),
+                    null, null, 600);
+        } else {
+            throw new RuntimeException("Wrong event client type: "+type);
+        }
+    }
+
+    private static String getId() {
+        synchronized(SharingThreadTest.class) {
+            return String.valueOf(counter++);
+        }
+    }
+
+    private static void fail(String msg) {
+        System.out.println("FAIL: " + msg);
+        failure = msg;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/eventService/SubscribeTest.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @bug 5108776
+ * @summary Test that EventSubscriber.subscribe works
+ * @author Eamonn McManus
+ */
+
+import java.lang.management.ManagementFactory;
+import javax.management.MBeanServer;
+import javax.management.Notification;
+import javax.management.NotificationBroadcasterSupport;
+import javax.management.NotificationFilter;
+import javax.management.NotificationListener;
+import javax.management.ObjectName;
+import javax.management.event.EventSubscriber;
+
+public class SubscribeTest {
+    private static class CountListener implements NotificationListener {
+        volatile int count;
+
+        public void handleNotification(Notification n, Object h) {
+            count++;
+        }
+    }
+
+    private static class SwitchFilter implements NotificationFilter {
+        volatile boolean enabled;
+
+        public boolean isNotificationEnabled(Notification n) {
+            return enabled;
+        }
+    }
+
+    public static interface SenderMBean {}
+
+    public static class Sender extends NotificationBroadcasterSupport
+            implements SenderMBean {
+        void send() {
+            Notification n = new Notification("type", this, 1L);
+            sendNotification(n);
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
+        ObjectName name1 = new ObjectName("d:type=Sender,id=1");
+        ObjectName name2 = new ObjectName("d:type=Sender,id=2");
+        ObjectName pattern = new ObjectName("d:type=Sender,*");
+        Sender sender1 = new Sender();
+        Sender sender2 = new Sender();
+        mbs.registerMBean(sender1, name1);
+        mbs.registerMBean(sender2, name2);
+
+        EventSubscriber sub = EventSubscriber.getEventSubscriber(mbs);
+
+        System.out.println("Single subscribe covering both MBeans");
+        CountListener listen1 = new CountListener();
+        sub.subscribe(pattern, listen1, null, null);
+        sender1.send();
+        assertEquals("Notifs after sender1 send", 1, listen1.count);
+        sender2.send();
+        assertEquals("Notifs after sender2 send", 2, listen1.count);
+
+        System.out.println("Unsubscribe");
+        sub.unsubscribe(pattern, listen1);
+        sender1.send();
+        assertEquals("Notifs after sender1 send", 2, listen1.count);
+
+        System.out.println("Subscribe twice to same MBean with same listener " +
+                "but different filters");
+        SwitchFilter filter1 = new SwitchFilter();
+        sub.subscribe(name1, listen1, null, null);
+        sub.subscribe(name1, listen1, filter1, null);
+        listen1.count = 0;
+        sender1.send();
+        // switch is off, so only one notif expected
+        assertEquals("Notifs after sender1 send", 1, listen1.count);
+        filter1.enabled = true;
+        sender1.send();
+        // switch is on, so two more notifs expected
+        assertEquals("Notifs after sender1 send", 3, listen1.count);
+
+        System.out.println("Remove those subscriptions");
+        sub.unsubscribe(name1, listen1);
+        sender1.send();
+        assertEquals("Notifs after sender1 send", 3, listen1.count);
+    }
+
+    private static void assertEquals(String what, Object expected, Object actual)
+    throws Exception {
+        if (!equal(expected, actual)) {
+            String msg = "Expected " + expected + "; got " + actual;
+            throw new Exception("TEST FAILED: " + what + ": " + msg);
+        }
+    }
+
+    private static boolean equal(Object x, Object y) {
+        if (x == y)
+            return true;
+        if (x == null)
+            return false;
+        return (x.equals(y));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/eventService/UsingEventService.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,84 @@
+/*
+ * @test UsingEventService.java 1.10 08/01/22
+ * @bug 5108776
+ * @summary Basic test for EventManager.
+ * @author Shanliang JIANG
+ * @run clean UsingEventService
+ * @run build UsingEventService
+ * @run main UsingEventService
+ */
+
+import java.util.HashMap;
+import java.util.Map;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerConnection;
+import javax.management.MBeanServerFactory;
+import javax.management.Notification;
+import javax.management.NotificationListener;
+import javax.management.ObjectName;
+import javax.management.event.EventConsumer;
+import javax.management.remote.JMXConnector;
+import javax.management.remote.JMXConnectorFactory;
+import javax.management.remote.JMXConnectorServer;
+import javax.management.remote.JMXConnectorServerFactory;
+import javax.management.remote.JMXServiceURL;
+
+public class UsingEventService {
+    private static JMXServiceURL url;
+    private static JMXConnectorServer server;
+    private static JMXConnector conn;
+    private static MBeanServerConnection client;
+
+    public static void main(String[] args) throws Exception {
+        if (System.getProperty("java.version").startsWith("1.5")) {
+            System.out.println(">>> UsingEventService-main not available for JDK1.5, bye");
+            return;
+        }
+
+        ObjectName oname = new ObjectName("test:t=t");
+        Notification n = new Notification("", oname, 0);
+
+        System.out.println(">>> UsingEventService-main basic tests ...");
+        MBeanServer mbeanServer = MBeanServerFactory.createMBeanServer();
+
+        url = new JMXServiceURL("rmi", null, 0) ;
+        JMXConnectorServer server =
+                JMXConnectorServerFactory.newJMXConnectorServer(url, null, mbeanServer);
+        server.start();
+        url = server.getAddress();
+
+        System.out.println(">>> UsingEventService-main test to not use the event service...");
+        conn = JMXConnectorFactory.connect(url, null);
+        client = conn.getMBeanServerConnection();
+
+        System.out.println(">>> UsingEventService-main test to use the event service...");
+        Map env = new HashMap(1);
+        env.put("jmx.remote.use.event.service", "true");
+        conn = JMXConnectorFactory.connect(url, env);
+        client = conn.getMBeanServerConnection();
+
+        ((EventConsumer)client).subscribe(oname, listener, null, null);
+
+        System.out.println(">>> UsingEventService-main using event service as expected!");
+
+        System.out.println(">>> UsingEventService-main test to use" +
+                " the event service with system property...");
+
+        System.setProperty("jmx.remote.use.event.service", "true");
+        conn = JMXConnectorFactory.connect(url, null);
+        client = conn.getMBeanServerConnection();
+
+        ((EventConsumer)client).subscribe(oname, listener, null, null);
+
+        System.out.println("" +
+                ">>> UsingEventService-main using event service as expected!");
+
+        System.out.println(">>> Happy bye bye!");
+    }
+
+    private final static NotificationListener listener = new NotificationListener() {
+        public void handleNotification(Notification n, Object hk) {
+            //
+        }
+    };
+}
--- a/jdk/test/javax/management/mxbean/GenericArrayTypeTest.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/test/javax/management/mxbean/GenericArrayTypeTest.java	Wed Jul 05 16:40:29 2017 +0200
@@ -32,17 +32,19 @@
  */
 
 import java.lang.management.ManagementFactory;
-import java.lang.management.MonitorInfo;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import javax.management.Attribute;
 import javax.management.JMX;
 import javax.management.MBeanServer;
 import javax.management.MBeanServerConnection;
 import javax.management.ObjectName;
+import javax.management.StandardMBean;
+import javax.management.openmbean.CompositeData;
 import javax.management.remote.JMXConnector;
 import javax.management.remote.JMXConnectorFactory;
 import javax.management.remote.JMXConnectorServer;
@@ -50,6 +52,58 @@
 import javax.management.remote.JMXServiceURL;
 
 public class GenericArrayTypeTest {
+    // A version of java.lang.management.MonitorInfo so we can run this test
+    // on JDK 5, where that class didn't exist.
+    public static class MonitorInfo {
+        private final String className;
+        private final int identityHashCode;
+        private final int lockedStackDepth;
+        private final StackTraceElement lockedStackFrame;
+
+        public MonitorInfo(
+                String className, int identityHashCode,
+                int lockedStackDepth, StackTraceElement lockedStackFrame) {
+            this.className = className;
+            this.identityHashCode = identityHashCode;
+            this.lockedStackDepth = lockedStackDepth;
+            this.lockedStackFrame = lockedStackFrame;
+        }
+
+        public static MonitorInfo from(CompositeData cd) {
+            try {
+                CompositeData stecd = (CompositeData) cd.get("lockedStackFrame");
+                StackTraceElement ste = new StackTraceElement(
+                        (String) stecd.get("className"),
+                        (String) stecd.get("methodName"),
+                        (String) stecd.get("fileName"),
+                        (Integer) stecd.get("lineNumber"));
+                return new MonitorInfo(
+                        (String) cd.get("className"),
+                        (Integer) cd.get("identityHashCode"),
+                        (Integer) cd.get("lockedStackDepth"),
+                        ste);
+            } catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+        public String getClassName() {
+            return className;
+        }
+
+        public int getIdentityHashCode() {
+            return identityHashCode;
+        }
+
+        public int getLockedStackDepth() {
+            return lockedStackDepth;
+        }
+
+        public StackTraceElement getLockedStackFrame() {
+            return lockedStackFrame;
+        }
+    }
+
 
     public interface TestMXBean {
 
--- a/jdk/test/javax/management/mxbean/LeakTest.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/test/javax/management/mxbean/LeakTest.java	Wed Jul 05 16:40:29 2017 +0200
@@ -25,7 +25,7 @@
  * @bug 6482247
  * @summary Test that creating MXBeans does not introduce memory leaks.
  * @author Eamonn McManus
- * @run build LeakTest
+ * @run build LeakTest RandomMXBeanTest
  * @run main LeakTest
  */
 
--- a/jdk/test/javax/management/mxbean/MBeanOperationInfoTest.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/test/javax/management/mxbean/MBeanOperationInfoTest.java	Wed Jul 05 16:40:29 2017 +0200
@@ -86,7 +86,8 @@
         if (error > 0) {
             System.out.println("\nTEST FAILED");
             throw new Exception("TEST FAILED: " + error + " wrong return types");
-        } else if (tested != returnTypes.length) {
+        } else if (tested != returnTypes.length &&
+                   !System.getProperty("java.specification.version").equals("1.5")) {
             System.out.println("\nTEST FAILED");
             throw new Exception("TEST FAILED: " + tested + " cases tested, " +
             returnTypes.length + " expected");
--- a/jdk/test/javax/management/mxbean/MXBeanTest.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/test/javax/management/mxbean/MXBeanTest.java	Wed Jul 05 16:40:29 2017 +0200
@@ -149,7 +149,7 @@
             if (mbai.getName().equals("Ints")
                 && mbai.isReadable() && !mbai.isWritable()
                 && mbai.getDescriptor().getFieldValue("openType")
-                    .equals(new ArrayType(SimpleType.INTEGER, true))
+                    .equals(new ArrayType<int[]>(SimpleType.INTEGER, true))
                 && attrs[0].getType().equals("[I"))
                 success("MBeanAttributeInfo");
             else
--- a/jdk/test/javax/management/mxbean/ThreadMXBeanTest.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/test/javax/management/mxbean/ThreadMXBeanTest.java	Wed Jul 05 16:40:29 2017 +0200
@@ -46,7 +46,8 @@
         long[] ids1 = proxy.getAllThreadIds();
 
         // Add some random ids to the list so we'll get back null ThreadInfo
-        long[] ids2 = Arrays.copyOf(ids1, ids1.length + 10);
+        long[] ids2 = new long[ids1.length + 10];
+        System.arraycopy(ids1, 0, ids2, 0, ids1.length);
         Random r = new Random();
         for (int i = ids1.length; i < ids2.length; i++)
             ids2[i] = Math.abs(r.nextLong());
--- a/jdk/test/javax/management/mxbean/TigerMXBean.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/test/javax/management/mxbean/TigerMXBean.java	Wed Jul 05 16:40:29 2017 +0200
@@ -83,20 +83,20 @@
     Tuiseal opEnum(Tuiseal x, Tuiseal y);
 
     List<String> StringList = Arrays.asList(new String[] {"a", "b", "x"});
-    ArrayType StringListType =
+    ArrayType<?> StringListType =
         MerlinMXBean.ArrayTypeMaker.make(1, SimpleType.STRING);
     List<String> getStringList();
     void setStringList(List<String> x);
     List<String> opStringList(List<String> x, List<String> y);
 
-    Set<String> StringSet = new HashSet(StringList);
-    ArrayType StringSetType = StringListType;
+    Set<String> StringSet = new HashSet<String>(StringList);
+    ArrayType<?> StringSetType = StringListType;
     Set<String> getStringSet();
     void setStringSet(Set<String> x);
     Set<String> opStringSet(Set<String> x, Set<String> y);
 
-    SortedSet<String> SortedStringSet = new TreeSet(StringList);
-    ArrayType SortedStringSetType = StringListType;
+    SortedSet<String> SortedStringSet = new TreeSet<String>(StringList);
+    ArrayType<?> SortedStringSetType = StringListType;
     SortedSet<String> getSortedStringSet();
     void setSortedStringSet(SortedSet<String> x);
     SortedSet<String> opSortedStringSet(SortedSet<String> x,
@@ -119,7 +119,7 @@
                                     Map<String,List<String>> y);
 
     SortedMap<String,String> XSortedMap =
-        new TreeMap(Collections.singletonMap("foo", "bar"));
+        new TreeMap<String,String>(Collections.singletonMap("foo", "bar"));
     String XSortedMapTypeName =
         "java.util.SortedMap<java.lang.String, java.lang.String>";
     CompositeType XSortedMapRowType = MerlinMXBean.CompositeTypeMaker.make(
@@ -137,8 +137,8 @@
 
     // For bug 6319960, try constructing Set and Map with non-Comparable
 
-    Set<Point> PointSet = new HashSet(Collections.singleton(Point));
-    ArrayType PointSetType =
+    Set<Point> PointSet = new HashSet<Point>(Collections.singleton(Point));
+    ArrayType<?> PointSetType =
         MerlinMXBean.ArrayTypeMaker.make(1, PointType);
     Set<Point> getPointSet();
     void setPointSet(Set<Point> x);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/openmbean/CompositeDataStringTest.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+import javax.management.openmbean.CompositeType;
+import javax.management.openmbean.OpenType;
+import javax.management.openmbean.SimpleType;
+
+/*
+ * @test
+ * @bug 6610174
+ * @summary Test that CompositeDataSupport.toString() represents arrays correctly
+ * @author Eamonn McManus
+ */
+import javax.management.openmbean.ArrayType;
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.CompositeDataSupport;
+
+public class CompositeDataStringTest {
+    public static void main(String[] args) throws Exception {
+        CompositeType basicCT = new CompositeType(
+                "basicCT", "basic CompositeType",
+                new String[] {"name", "value"},
+                new String[] {"name", "value"},
+                new OpenType<?>[] {SimpleType.STRING, SimpleType.INTEGER});
+        CompositeType ct = new CompositeType(
+                "noddy", "descr",
+                new String[] {"strings", "ints", "cds"},
+                new String[] {"string array", "int array", "composite data array"},
+                new OpenType<?>[] {
+                    ArrayType.getArrayType(SimpleType.STRING),
+                    ArrayType.getPrimitiveArrayType(int[].class),
+                    ArrayType.getArrayType(basicCT)
+                });
+        CompositeData basicCD1 = new CompositeDataSupport(
+                basicCT, new String[] {"name", "value"}, new Object[] {"ceathar", 4});
+        CompositeData basicCD2 = new CompositeDataSupport(
+                basicCT, new String[] {"name", "value"}, new Object[] {"naoi", 9});
+        CompositeData cd = new CompositeDataSupport(
+                ct,
+                new String[] {"strings", "ints", "cds"},
+                new Object[] {
+                    new String[] {"fred", "jim", "sheila"},
+                    new int[] {2, 3, 5, 7},
+                    new CompositeData[] {basicCD1, basicCD2}
+                });
+        String s = cd.toString();
+        System.out.println("CompositeDataSupport.toString(): " + s);
+        String[] expected = {
+            "fred, jim, sheila",
+            "2, 3, 5, 7",
+            "ceathar",
+            "naoi",
+        };
+        boolean ok = true;
+        for (String expect : expected) {
+            if (s.contains(expect))
+                System.out.println("OK: string contains <" + expect + ">");
+            else {
+                ok = false;
+                System.out.println("NOT OK: string does not contain <" +
+                        expect + ">");
+            }
+        }
+        if (ok)
+            System.out.println("TEST PASSED");
+        else
+            throw new Exception("TEST FAILED: string did not contain expected substrings");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/openmbean/TabularDataOrderTest.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,190 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @bug 6334663
+ * @summary Test that TabularDataSupport preserves the order elements were added
+ * @author Eamonn McManus
+ */
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import javax.management.JMX;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.ObjectName;
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.CompositeDataSupport;
+import javax.management.openmbean.CompositeType;
+import javax.management.openmbean.OpenDataException;
+import javax.management.openmbean.OpenType;
+import javax.management.openmbean.SimpleType;
+import javax.management.openmbean.TabularData;
+import javax.management.openmbean.TabularDataSupport;
+import javax.management.openmbean.TabularType;
+
+public class TabularDataOrderTest {
+    private static String failure;
+
+    private static final String COMPAT_PROP_NAME = "jmx.tabular.data.hash.map";
+
+    private static final String[] intNames = {
+        "unus", "duo", "tres", "quatuor", "quinque", "sex", "septem",
+        "octo", "novem", "decim",
+    };
+    private static final Map<String, Integer> stringToValue =
+            new LinkedHashMap<String, Integer>();
+    static {
+        for (int i = 0; i < intNames.length; i++)
+            stringToValue.put(intNames[i], i + 1);
+    }
+
+    public static interface TestMXBean {
+        public Map<String, Integer> getMap();
+    }
+
+    public static class TestImpl implements TestMXBean {
+        public Map<String, Integer> getMap() {
+            return stringToValue;
+        }
+    }
+
+    private static final CompositeType ct;
+    private static final TabularType tt;
+    static {
+        try {
+            ct = new CompositeType(
+                    "a.b.c", "name and int",
+                    new String[] {"name", "int"},
+                    new String[] {"name of integer", "value of integer"},
+                    new OpenType<?>[] {SimpleType.STRING, SimpleType.INTEGER});
+            tt = new TabularType(
+                    "d.e.f", "name and int indexed by name", ct,
+                    new String[] {"name"});
+        } catch (OpenDataException e) {
+            throw new AssertionError(e);
+        }
+    }
+
+    private static TabularData makeTable() throws OpenDataException {
+        TabularData td = new TabularDataSupport(tt);
+        for (Map.Entry<String, Integer> entry : stringToValue.entrySet()) {
+            CompositeData cd = new CompositeDataSupport(
+                    ct,
+                    new String[] {"name", "int"},
+                    new Object[] {entry.getKey(), entry.getValue()});
+            td.put(cd);
+        }
+        return td;
+    }
+
+    public static void main(String[] args) throws Exception {
+        System.out.println("Testing standard behaviour");
+        TabularData td = makeTable();
+        System.out.println(td);
+
+        // Test that a default TabularData has the order keys were added in
+        int last = 0;
+        boolean ordered = true;
+        for (Object x : td.values()) {
+            CompositeData cd = (CompositeData) x;
+            String name = (String) cd.get("name");
+            int value = (Integer) cd.get("int");
+            System.out.println(name + " = " + value);
+            if (last + 1 != value)
+                ordered = false;
+            last = value;
+        }
+        if (!ordered)
+            fail("Order not preserved");
+
+        // Now test the undocumented property that causes HashMap to be used
+        // instead of LinkedHashMap, in case serializing to a 1.3 client.
+        // We serialize and deserialize in case the implementation handles
+        // this at serialization time.  Then we look at object fields; that's
+        // not guaranteed to work but at worst it will fail spuriously and
+        // we'll have to update the test.
+        System.out.println("Testing compatible behaviour");
+        System.setProperty(COMPAT_PROP_NAME, "true");
+        td = makeTable();
+        System.out.println(td);
+        ByteArrayOutputStream bout = new ByteArrayOutputStream();
+        ObjectOutputStream oout = new ObjectOutputStream(bout);
+        oout.writeObject(td);
+        oout.close();
+        byte[] bytes = bout.toByteArray();
+        ByteArrayInputStream bin = new ByteArrayInputStream(bytes);
+        ObjectInputStream oin = new ObjectInputStream(bin);
+        td = (TabularData) oin.readObject();
+        boolean found = false;
+        for (Field f : td.getClass().getDeclaredFields()) {
+            if (Modifier.isStatic(f.getModifiers()))
+                continue;
+            f.setAccessible(true);
+            Object x = f.get(td);
+            if (x != null && x.getClass() == HashMap.class) {
+                found = true;
+                System.out.println(
+                        x.getClass().getName() + " TabularDataSupport." +
+                        f.getName() + " = " + x);
+                break;
+            }
+        }
+        if (!found) {
+            fail("TabularDataSupport does not contain HashMap though " +
+                    COMPAT_PROP_NAME + "=true");
+        }
+        System.clearProperty(COMPAT_PROP_NAME);
+
+        System.out.println("Testing MXBean behaviour");
+        MBeanServer mbs = MBeanServerFactory.newMBeanServer();
+        ObjectName name = new ObjectName("a:b=c");
+        mbs.registerMBean(new TestImpl(), name);
+        TestMXBean proxy = JMX.newMXBeanProxy(mbs, name, TestMXBean.class);
+        Map<String, Integer> map = proxy.getMap();
+        List<String> origNames = new ArrayList<String>(stringToValue.keySet());
+        List<String> proxyNames = new ArrayList<String>(map.keySet());
+        if (!origNames.equals(proxyNames))
+            fail("Order mangled after passage through MXBean: " + proxyNames);
+
+        if (failure == null)
+            System.out.println("TEST PASSED");
+        else
+            throw new Exception("TEST FAILED: " + failure);
+    }
+
+    private static void fail(String why) {
+        System.out.println("FAILED: " + why);
+        failure = why;
+    }
+}
--- a/jdk/test/javax/management/query/QueryNotifFilterTest.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/test/javax/management/query/QueryNotifFilterTest.java	Wed Jul 05 16:40:29 2017 +0200
@@ -98,7 +98,7 @@
             this.queryString = queryString;
         }
         abstract boolean apply(MBeanServer mbs, ObjectName name) throws Exception;
-        @Override
+        //@Override - doesn't override in JDK5
         public boolean apply(ObjectName name) {
             try {
                 return apply(getMBeanServer(), name);
--- a/jdk/test/javax/management/remote/mandatory/connection/CloseServerTest.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/test/javax/management/remote/mandatory/connection/CloseServerTest.java	Wed Jul 05 16:40:29 2017 +0200
@@ -31,11 +31,16 @@
  * @run main CloseServerTest
  */
 
+import com.sun.jmx.remote.util.EnvHelp;
 import java.net.MalformedURLException;
-import java.io.IOException;
 
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
 import javax.management.*;
 import javax.management.remote.*;
+import javax.management.remote.rmi.RMIConnectorServer;
 
 public class CloseServerTest {
     private static final String[] protocols = {"rmi", "iiop", "jmxmp"};
@@ -131,40 +136,54 @@
 
             server.stop();
 
-            // with a client listener, but close the server first
-            System.out.println(">>> Open, start a server, create a client, add a listener, close the server then the client.");
-            server = JMXConnectorServerFactory.newJMXConnectorServer(u, null, mbs);
-            server.start();
+            List<Map<String, String>> envs = Arrays.asList(
+                    Collections.singletonMap(
+                        RMIConnectorServer.DELEGATE_TO_EVENT_SERVICE, "false"),
+                    Collections.singletonMap(
+                        RMIConnectorServer.DELEGATE_TO_EVENT_SERVICE, "true"));
+
+            for (Map<String, String> env : envs) {
+                    System.out.println(
+                            ">>>>>>>> " + RMIConnectorServer.DELEGATE_TO_EVENT_SERVICE +
+                            " = " + env.get(RMIConnectorServer.DELEGATE_TO_EVENT_SERVICE));
+
+                // with a client listener, but close the server first
+                System.out.println(">>> Open, start a server, create a client, " +
+                        "add a listener, close the server then the client.");
+                server = JMXConnectorServerFactory.newJMXConnectorServer(u, env, mbs);
+                server.start();
+
+                addr = server.getAddress();
+                client = JMXConnectorFactory.newJMXConnector(addr, null);
+                client.connect(null);
 
-            addr = server.getAddress();
-            client = JMXConnectorFactory.newJMXConnector(addr, null);
-            client.connect(null);
+                mserver = client.getMBeanServerConnection();
+                mserver.addNotificationListener(delegateName, dummyListener, null, null);
+
+                server.stop();
+
+                try {
+                    client.close();
+                } catch (Exception e) {
+                    // ok, it is because the server has been closed.
+                }
 
-            mserver = client.getMBeanServerConnection();
-            mserver.addNotificationListener(delegateName, dummyListener, null, null);
+                // with a client listener, but close the client first
+                System.out.println(">>> Open, start a server, create a client, " +
+                        "add a listener, close the client then the server.");
+                server = JMXConnectorServerFactory.newJMXConnectorServer(u, env, mbs);
+                server.start();
 
-            server.stop();
+                addr = server.getAddress();
+                client = JMXConnectorFactory.newJMXConnector(addr, null);
+                client.connect(null);
 
-            try {
+                mserver = client.getMBeanServerConnection();
+                mserver.addNotificationListener(delegateName, dummyListener, null, null);
+
                 client.close();
-            } catch (Exception e) {
-                // ok, it is because the server has been closed.
+                server.stop();
             }
-
-            // with a client listener, but close the client first
-            System.out.println(">>> Open, start a server, create a client, add a listener, close the client then the server.");
-            server = JMXConnectorServerFactory.newJMXConnectorServer(u, null, mbs);
-            server.start();
-
-            addr = server.getAddress();
-            client = JMXConnectorFactory.newJMXConnector(addr, null);
-            client.connect(null);
-
-            mserver = client.getMBeanServerConnection();
-            mserver.addNotificationListener(delegateName, dummyListener, null, null);
-
-            client.close();
-            server.stop();
         } catch (MalformedURLException e) {
             System.out.println(">>> Skipping unsupported URL " + u);
             return true;
--- a/jdk/test/javax/management/remote/mandatory/connection/DeadLockTest.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/test/javax/management/remote/mandatory/connection/DeadLockTest.java	Wed Jul 05 16:40:29 2017 +0200
@@ -37,6 +37,7 @@
 
 import javax.management.*;
 import javax.management.remote.*;
+import javax.management.remote.rmi.RMIConnectorServer;
 
 public class DeadLockTest {
     private static final String[] protocols = {"rmi", "iiop", "jmxmp"};
@@ -72,6 +73,9 @@
         // disable the client ping
         env.put("jmx.remote.x.client.connection.check.period", "0");
 
+        // ensure we are not internally using the Event Service on the server
+        env.put(RMIConnectorServer.DELEGATE_TO_EVENT_SERVICE, "false");
+
         try {
             u = new JMXServiceURL(proto, null, 0);
             server = JMXConnectorServerFactory.newJMXConnectorServer(u, env, mbs);
--- a/jdk/test/javax/management/remote/mandatory/connection/IdleTimeoutTest.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/test/javax/management/remote/mandatory/connection/IdleTimeoutTest.java	Wed Jul 05 16:40:29 2017 +0200
@@ -50,6 +50,8 @@
 import javax.management.remote.JMXConnectorServerFactory;
 import javax.management.remote.JMXServiceURL;
 import com.sun.jmx.remote.util.EnvHelp;
+import java.util.Collections;
+import javax.management.remote.rmi.RMIConnectorServer;
 
 public class IdleTimeoutTest {
     public static void main(String[] args) throws Exception {
@@ -88,8 +90,13 @@
 
     private static long getIdleTimeout(MBeanServer mbs, JMXServiceURL url)
         throws Exception {
+        // If the connector server is using the Event Service, then connections
+        // never time out.  This is by design.
+        Map<String, String> env =
+            Collections.singletonMap(
+                RMIConnectorServer.DELEGATE_TO_EVENT_SERVICE, "false");
         JMXConnectorServer server =
-            JMXConnectorServerFactory.newJMXConnectorServer(url, null, mbs);
+            JMXConnectorServerFactory.newJMXConnectorServer(url, env, mbs);
         server.start();
         try {
             url = server.getAddress();
@@ -164,6 +171,7 @@
 
         Map idleMap = new HashMap();
         idleMap.put(EnvHelp.SERVER_CONNECTION_TIMEOUT, new Long(timeout));
+        idleMap.put(RMIConnectorServer.DELEGATE_TO_EVENT_SERVICE, "false");
         JMXConnectorServer server =
             JMXConnectorServerFactory.newJMXConnectorServer(url,idleMap,mbs);
 
--- a/jdk/test/javax/management/remote/mandatory/connection/RMIExitTest.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/test/javax/management/remote/mandatory/connection/RMIExitTest.java	Wed Jul 05 16:40:29 2017 +0200
@@ -35,6 +35,8 @@
 import java.net.MalformedURLException;
 import java.io.IOException;
 
+import java.util.Collections;
+import java.util.Map;
 import javax.management.MBeanServerFactory;
 import javax.management.MBeanServer;
 import javax.management.ObjectName;
@@ -47,12 +49,14 @@
 import javax.management.remote.JMXConnector;
 import javax.management.remote.JMXConnectorServerFactory;
 import javax.management.remote.JMXConnectorFactory;
+import javax.management.remote.rmi.RMIConnectorServer;
 
 /**
  * VM shutdown hook. Test that the hook is called less than 5 secs
  * after expected exit.
  */
 class TimeChecker extends Thread {
+    @Override
     public void run() {
         System.out.println("shutdown hook called");
         long elapsedTime =
@@ -81,12 +85,15 @@
     public static void main(String[] args) {
         System.out.println("Start test");
         Runtime.getRuntime().addShutdownHook(new TimeChecker());
-        test();
+        test(false);
+        test(true);
         exitStartTime = System.currentTimeMillis();
         System.out.println("End test");
     }
 
-    private static void test() {
+    private static void test(boolean eventService) {
+        System.out.println(
+                "---testing with" + (eventService ? "" : "out") + " Event Service");
         try {
             JMXServiceURL u = new JMXServiceURL("rmi", null, 0);
             JMXConnectorServer server;
@@ -105,8 +112,11 @@
                         }
                     };
 
+            Map<String, String> env = Collections.singletonMap(
+                    RMIConnectorServer.DELEGATE_TO_EVENT_SERVICE,
+                    Boolean.toString(eventService));
             server = JMXConnectorServerFactory.newJMXConnectorServer(u,
-                                                                     null,
+                                                                     env,
                                                                      mbs);
             server.start();
 
--- a/jdk/test/javax/management/remote/mandatory/connection/ReconnectTest.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/test/javax/management/remote/mandatory/connection/ReconnectTest.java	Wed Jul 05 16:40:29 2017 +0200
@@ -33,10 +33,10 @@
 
 import java.util.*;
 import java.net.MalformedURLException;
-import java.io.IOException;
 
 import javax.management.*;
 import javax.management.remote.*;
+import javax.management.remote.rmi.RMIConnectorServer;
 
 public class ReconnectTest {
     private static final String[] protocols = {"rmi", "iiop", "jmxmp"};
@@ -48,6 +48,7 @@
         String timeout = "1000";
         env.put("jmx.remote.x.server.connection.timeout", timeout);
         env.put("jmx.remote.x.client.connection.check.period", timeout);
+        env.put(RMIConnectorServer.DELEGATE_TO_EVENT_SERVICE, "false");
     }
 
     public static void main(String[] args) throws Exception {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/remote/mandatory/connectorServer/ForwarderChainTest.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,274 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+import java.util.NoSuchElementException;
+import java.util.Random;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerConnection;
+import javax.management.MBeanServerFactory;
+import javax.management.remote.IdentityMBeanServerForwarder;
+import javax.management.remote.JMXConnector;
+import javax.management.remote.JMXConnectorFactory;
+import javax.management.remote.JMXConnectorServer;
+import javax.management.remote.JMXServiceURL;
+import javax.management.remote.MBeanServerForwarder;
+
+/*
+ * @test
+ * @bug 6218920
+ * @summary Tests manipulation of MBeanServerForwarder chains.
+ * @author Eamonn McManus
+ */
+import javax.management.remote.rmi.RMIConnectorServer;
+
+public class ForwarderChainTest {
+    private static final TestMBeanServerForwarder[] forwarders =
+            new TestMBeanServerForwarder[10];
+    static {
+        for (int i = 0; i < forwarders.length; i++)
+            forwarders[i] = new TestMBeanServerForwarder(i);
+    }
+
+    private static class TestMBeanServerForwarder
+            extends IdentityMBeanServerForwarder {
+        private final int index;
+        volatile int defaultDomainCount;
+
+        TestMBeanServerForwarder(int index) {
+            this.index = index;
+        }
+
+        @Override
+        public String getDefaultDomain() {
+            defaultDomainCount++;
+            return super.getDefaultDomain();
+        }
+
+        @Override
+        public String toString() {
+            return "forwarders[" + index + "]";
+        }
+    }
+
+    private static String failure;
+
+    public static void main(String[] args) throws Exception {
+
+        System.out.println("===Test with newly created, unattached server===");
+
+        JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///");
+        JMXConnectorServer cs = new RMIConnectorServer(url, null);
+        test(cs, null);
+
+        System.out.println("===Test with server attached to MBS===");
+        MBeanServer mbs = MBeanServerFactory.newMBeanServer();
+        cs = new RMIConnectorServer(url, null, mbs);
+        test(cs, mbs);
+
+        System.out.println("===Remove any leftover forwarders===");
+        while (cs.getSystemMBeanServer() instanceof MBeanServerForwarder) {
+            MBeanServerForwarder mbsf =
+                    (MBeanServerForwarder) cs.getSystemMBeanServer();
+            cs.removeMBeanServerForwarder(mbsf);
+        }
+        expectChain(cs, "U", mbs);
+
+        System.out.println("===Ensure forwarders are called===");
+        cs.setMBeanServerForwarder(forwarders[0]);
+        cs.setSystemMBeanServerForwarder(forwarders[1]);
+        expectChain(cs, "1U0", mbs);
+        cs.start();
+        if (forwarders[0].defaultDomainCount != 0 ||
+                forwarders[1].defaultDomainCount != 0) {
+            fail("defaultDomainCount not zero");
+        }
+        JMXServiceURL addr = cs.getAddress();
+        JMXConnector cc = JMXConnectorFactory.connect(addr);
+        MBeanServerConnection mbsc = cc.getMBeanServerConnection();
+        mbsc.getDefaultDomain();
+        cc.close();
+        cs.stop();
+        for (boolean system : new boolean[] {false, true}) {
+            TestMBeanServerForwarder mbsf = system ? forwarders[1] : forwarders[0];
+            if (mbsf.defaultDomainCount != 1) {
+                fail((system ? "System" : "User") + " forwarder called " +
+                        mbsf.defaultDomainCount + " times");
+            }
+        }
+
+        if (failure == null)
+            System.out.println("TEST PASSED");
+        else
+            throw new Exception("TEST FAILED: " + failure);
+    }
+
+    private static void test(JMXConnectorServer cs, MBeanServer end) {
+        // A newly-created connector server might have system forwarders,
+        // so get rid of those.
+        while (cs.getSystemMBeanServer() != cs.getMBeanServer())
+            cs.removeMBeanServerForwarder((MBeanServerForwarder) cs.getSystemMBeanServer());
+
+        expectChain(cs, "U", end);
+
+        System.out.println("Add a user forwarder");
+        cs.setMBeanServerForwarder(forwarders[0]);
+        expectChain(cs, "U0", end);
+
+        System.out.println("Add another user forwarder");
+        cs.setMBeanServerForwarder(forwarders[1]);
+        expectChain(cs, "U10", end);
+
+        System.out.println("Add a system forwarder");
+        cs.setSystemMBeanServerForwarder(forwarders[2]);
+        expectChain(cs, "2U10", end);
+
+        System.out.println("Add another user forwarder");
+        cs.setMBeanServerForwarder(forwarders[3]);
+        expectChain(cs, "2U310", end);
+
+        System.out.println("Add another system forwarder");
+        cs.setSystemMBeanServerForwarder(forwarders[4]);
+        expectChain(cs, "42U310", end);
+
+        System.out.println("Remove the first user forwarder");
+        cs.removeMBeanServerForwarder(forwarders[3]);
+        expectChain(cs, "42U10", end);
+
+        System.out.println("Remove the last user forwarder");
+        cs.removeMBeanServerForwarder(forwarders[0]);
+        expectChain(cs, "42U1", end);
+
+        System.out.println("Remove the first system forwarder");
+        cs.removeMBeanServerForwarder(forwarders[4]);
+        expectChain(cs, "2U1", end);
+
+        System.out.println("Remove the last system forwarder");
+        cs.removeMBeanServerForwarder(forwarders[2]);
+        expectChain(cs, "U1", end);
+
+        System.out.println("Remove the last forwarder");
+        cs.removeMBeanServerForwarder(forwarders[1]);
+        expectChain(cs, "U", end);
+
+        System.out.println("---Doing random manipulations---");
+        // In this loop we pick one of the forwarders at random each time.
+        // If it is already in the chain, then we remove it.  If it is not
+        // in the chain, then we do one of three things: try to remove it
+        // (expecting an exception); add it to the user chain; or add it
+        // to the system chain.
+        // A subtle point is that if there is no MBeanServer then
+        // cs.setMBeanServerForwarder(mbsf) does not change mbsf.getMBeanServer().
+        // Since we're recycling a random forwarder[i], we explicitly
+        // call mbsf.setMBeanServer(null) in this case.
+        String chain = "U";
+        Random r = new Random();
+        for (int i = 0; i < 50; i++) {
+            int fwdi = r.nextInt(10);
+            MBeanServerForwarder mbsf = forwarders[fwdi];
+            char c = (char) ('0' + fwdi);
+            int ci = chain.indexOf(c);
+            if (ci >= 0) {
+                System.out.println("Remove " + c);
+                cs.removeMBeanServerForwarder(mbsf);
+                chain = chain.substring(0, ci) + chain.substring(ci + 1);
+            } else {
+                switch (r.nextInt(3)) {
+                    case 0: { // try to remove it
+                        try {
+                            System.out.println("Try to remove absent " + c);
+                            cs.removeMBeanServerForwarder(mbsf);
+                            fail("Remove succeeded but should not have");
+                            return;
+                        } catch (NoSuchElementException e) {
+                        }
+                        break;
+                    }
+                    case 1: { // add it to the user chain
+                        System.out.println("Add " + c + " to user chain");
+                        if (cs.getMBeanServer() == null)
+                            mbsf.setMBeanServer(null);
+                        cs.setMBeanServerForwarder(mbsf);
+                        int postu = chain.indexOf('U') + 1;
+                        chain = chain.substring(0, postu) + c +
+                                chain.substring(postu);
+                        break;
+                    }
+                    case 2: { // add it to the system chain
+                        System.out.println("Add " + c + " to system chain");
+                        if (cs.getSystemMBeanServer() == null)
+                            mbsf.setMBeanServer(null);
+                        cs.setSystemMBeanServerForwarder(mbsf);
+                        chain = c + chain;
+                        break;
+                    }
+                }
+            }
+            expectChain(cs, chain, end);
+        }
+    }
+
+    /*
+     * Check that the forwarder chain has the expected contents.  The forwarders
+     * are encoded as a string.  For example, "12U34" means that the system
+     * chain contains forwarders[1] followed by forwarders[2], and the user
+     * chain contains forwarders[3] followed by forwarders[4].  Since the
+     * user chain is attached to the end of the system chain, another way to
+     * look at this is that the U marks the transition from one to the other.
+     *
+     * After traversing the chains, we should be pointing at "end".
+     */
+    private static void expectChain(
+            JMXConnectorServer cs, String chain, MBeanServer end) {
+        System.out.println("...expected chain: " + chain);
+        MBeanServer curr = cs.getSystemMBeanServer();
+        int i = 0;
+        while (i < chain.length()) {
+            char c = chain.charAt(i);
+            if (c == 'U') {
+                if (cs.getMBeanServer() != curr) {
+                    fail("User chain should have started here: " + curr);
+                    return;
+                }
+            } else {
+                int fwdi = c - '0';
+                MBeanServerForwarder forwarder = forwarders[fwdi];
+                if (curr != forwarder) {
+                    fail("Expected forwarder " + c + " here: " + curr);
+                    return;
+                }
+                curr = ((MBeanServerForwarder) curr).getMBeanServer();
+            }
+            i++;
+        }
+        if (curr != end) {
+            fail("End of chain is " + curr + ", should be " + end);
+            return;
+        }
+        System.out.println("...OK");
+    }
+
+    private static void fail(String msg) {
+        System.out.println("FAILED: " + msg);
+        failure = msg;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/remote/mandatory/connectorServer/StandardForwardersTest.java	Wed Jul 05 16:40:29 2017 +0200
@@ -0,0 +1,177 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+import java.lang.management.ManagementFactory;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.management.MBeanServer;
+import javax.management.event.EventClientDelegate;
+import javax.management.remote.JMXConnectorServer;
+
+/*
+ * @test
+ * @bug 6663757
+ * @summary Tests standard MBeanServerForwarders introduced by connector server
+ * options.
+ * @author Eamonn McManus
+ */
+import javax.management.remote.JMXConnectorServerFactory;
+import javax.management.remote.JMXServiceURL;
+import javax.management.remote.MBeanServerForwarder;
+
+public class StandardForwardersTest {
+    private static String failure;
+
+    private static class Forwarder {
+        private final String attribute;
+        private final boolean defaultEnabled;
+        private final Class<?> expectedClass;
+
+        public Forwarder(String attribute, boolean defaultEnabled,
+                         Class<?> expectedClass) {
+            this.attribute = attribute;
+            this.defaultEnabled = defaultEnabled;
+            this.expectedClass = expectedClass;
+        }
+    }
+
+    private static enum Status {DISABLED, ENABLED, DEFAULT}
+
+    public static void main(String[] args) throws Exception {
+        MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
+
+        MBeanServerForwarder ecdFwd =
+                EventClientDelegate.newForwarder();
+        Forwarder ecd = new Forwarder(
+                JMXConnectorServer.EVENT_CLIENT_DELEGATE_FORWARDER, true,
+                ecdFwd.getClass());
+
+        Forwarder[] forwarders = {ecd};
+
+        // Now go through every combination of forwarders.  Each forwarder
+        // may be explicitly enabled, explicitly disabled, or left to its
+        // default value.
+        int nStatus = Status.values().length;
+        int limit = (int) Math.pow(nStatus, forwarders.length);
+        for (int i = 0; i < limit; i++) {
+            Status[] status = new Status[forwarders.length];
+            int ii = i;
+            for (int j = 0; j < status.length; j++) {
+                status[j] = Status.values()[ii % nStatus];
+                ii /= nStatus;
+            }
+            Map<String, String> env = new HashMap<String, String>();
+            String test = "";
+            for (int j = 0; j < status.length; j++) {
+                if (!test.equals(""))
+                    test += "; ";
+                test += forwarders[j].attribute;
+                switch (status[j]) {
+                case DISABLED:
+                    test += "=false";
+                    env.put(forwarders[j].attribute, "false");
+                    break;
+                case ENABLED:
+                    test += "=true";
+                    env.put(forwarders[j].attribute, "true");
+                    break;
+                case DEFAULT:
+                    test += "=default(" + forwarders[j].defaultEnabled + ")";
+                    break;
+                }
+            }
+            boolean consistent = isConsistent(env);
+            test += "; (" + (consistent ? "" : "in") + "consistent)";
+            System.out.println(test);
+            JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///");
+            try {
+                JMXConnectorServer cs =
+                    JMXConnectorServerFactory.newJMXConnectorServer(url, env, mbs);
+                if (!consistent) {
+                    fail("Inconsistent attributes should have been rejected " +
+                            "but were not");
+                }
+                checkForwarders(cs, forwarders, status);
+            } catch (IllegalArgumentException e) {
+                if (consistent) {
+                    fail("Consistent attributes provoked IllegalArgumentException");
+                    e.printStackTrace(System.out);
+                }
+            }
+        }
+
+        if (failure == null)
+            System.out.println("TEST PASSED");
+        else
+            throw new Exception(failure);
+    }
+
+    // Check that the classes of the forwarders in the system chain correspond
+    // to what we expect given the options we have passed.  This check is a bit
+    // superficial in the sense that a forwarder might be for example a
+    // SingleMBeanForwarderHandler but that doesn't prove that it is the
+    // right Single MBean.  Nevertheless the test should expose any severe
+    // wrongness.
+    //
+    // The check here makes some assumptions that could become untrue in the
+    // future. First, it assumes that the forwarders that are added have
+    // exactly the classes that are in the Forwarder[] array. So for example
+    // the forwarder for CONTEXT_FORWARDER must be of the same class as an
+    // explicit call to ClientContext.newContextForwarder. The spec doesn't
+    // require that - it only requires that the forwarder have the same
+    // behaviour. The second assumption is that the connector server doesn't
+    // add any forwarders of its own into the system chain, and again the spec
+    // doesn't disallow that.
+    private static void checkForwarders(
+            JMXConnectorServer cs, Forwarder[] forwarders, Status[] status) {
+        List<Class<?>> expectedClasses = new ArrayList<Class<?>>();
+        for (int i = 0; i < forwarders.length; i++) {
+            if (status[i] == Status.ENABLED ||
+                    (status[i] == Status.DEFAULT && forwarders[i].defaultEnabled))
+                expectedClasses.add(forwarders[i].expectedClass);
+        }
+        MBeanServer stop = cs.getMBeanServer();
+        List<Class<?>> foundClasses = new ArrayList<Class<?>>();
+        for (MBeanServer mbs = cs.getSystemMBeanServer(); mbs != stop;
+             mbs = ((MBeanServerForwarder) mbs).getMBeanServer())
+            foundClasses.add(mbs.getClass());
+        if (!expectedClasses.equals(foundClasses)) {
+            fail("Incorrect forwarder chain: expected " + expectedClasses +
+                    "; found " + foundClasses);
+        }
+    }
+
+    // env is consistent if either (a) localizer is not enabled or (b)
+    // localizer is enabled and context is enabled.
+    // Neither of those is present in this codebase so env is always consistent.
+    private static boolean isConsistent(Map<String, String> env) {
+        return true;
+    }
+
+    private static void fail(String why) {
+        System.out.println("FAILED: " + why);
+        failure = why;
+    }
+}
--- a/jdk/test/javax/management/remote/mandatory/loading/MissingClassTest.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/test/javax/management/remote/mandatory/loading/MissingClassTest.java	Wed Jul 05 16:40:29 2017 +0200
@@ -44,13 +44,33 @@
   We also test objects that are of known class but not serializable.
   The test cases are similar.
  */
-import java.io.*;
-import java.net.*;
-import java.util.*;
-import javax.management.*;
-import javax.management.loading.*;
-import javax.management.remote.*;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.NotSerializableException;
+import java.io.ObjectOutputStream;
+import java.net.MalformedURLException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Random;
+import java.util.Set;
+import javax.management.Attribute;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerConnection;
+import javax.management.MBeanServerFactory;
+import javax.management.Notification;
+import javax.management.NotificationBroadcasterSupport;
+import javax.management.NotificationFilter;
+import javax.management.NotificationListener;
+import javax.management.ObjectName;
+import javax.management.remote.JMXConnectionNotification;
+import javax.management.remote.JMXConnector;
+import javax.management.remote.JMXConnectorFactory;
+import javax.management.remote.JMXConnectorServer;
+import javax.management.remote.JMXConnectorServerFactory;
+import javax.management.remote.JMXServiceURL;
 import javax.management.remote.rmi.RMIConnectorServer;
+import org.omg.CORBA.MARSHAL;
 
 public class MissingClassTest {
     private static final int NNOTIFS = 50;
@@ -84,7 +104,6 @@
             serverLoader.loadClass("$ClientUnknown$").newInstance();
 
         final String[] protos = {"rmi", /*"iiop",*/ "jmxmp"};
-        // iiop commented out until bug 4935098 is fixed
         boolean ok = true;
         for (int i = 0; i < protos.length; i++) {
             try {
@@ -105,7 +124,16 @@
     }
 
     private static boolean test(String proto) throws Exception {
-        System.out.println("Testing for proto " + proto);
+        boolean ok = true;
+        for (boolean eventService : new boolean[] {false, true})
+            ok &= test(proto, eventService);
+        return ok;
+    }
+
+    private static boolean test(String proto, boolean eventService)
+            throws Exception {
+        System.out.println("Testing for proto " + proto + " with" +
+                (eventService ? "" : "out") + " Event Service");
 
         boolean ok = true;
 
@@ -117,6 +145,8 @@
         Map serverMap = new HashMap();
         serverMap.put(JMXConnectorServerFactory.DEFAULT_CLASS_LOADER,
                       serverLoader);
+        serverMap.put(RMIConnectorServer.DELEGATE_TO_EVENT_SERVICE,
+                Boolean.toString(eventService));
 
         // make sure no auto-close at server side
         serverMap.put("jmx.remote.x.server.connection.timeout", "888888888");
@@ -155,6 +185,8 @@
             ok = false;
         } catch (IOException e) {
             Throwable cause = e.getCause();
+            if (cause instanceof MARSHAL)  // see CR 4935098
+                cause = cause.getCause();
             if (cause instanceof ClassNotFoundException) {
                 System.out.println("Success: got an IOException wrapping " +
                                    "a ClassNotFoundException");
@@ -177,6 +209,8 @@
             ok = false;
         } catch (IOException e) {
             Throwable wrapped = e.getCause();
+            if (wrapped instanceof MARSHAL)  // see CR 4935098
+                wrapped = wrapped.getCause();
             if (wrapped instanceof ClassNotFoundException) {
                 System.out.println("Success: got an IOException wrapping " +
                                    "a ClassNotFoundException: " +
@@ -228,6 +262,8 @@
                 ok = false;
             } catch (IOException e) {
                 Throwable cause = e.getCause();
+                if (cause instanceof MARSHAL)  // see CR 4935098
+                    cause = cause.getCause();
                 if (cause instanceof ClassNotFoundException) {
                     System.out.println("Success: got an IOException " +
                                        "wrapping a ClassNotFoundException");
@@ -461,12 +497,13 @@
         while ((remain = deadline - System.currentTimeMillis()) >= 0) {
             synchronized (result) {
                 if (result.failed
-                    || (result.knownCount == NNOTIFS
-                        && result.lostCount == NNOTIFS*2))
+                    || (result.knownCount >= NNOTIFS
+                        && result.lostCount >= NNOTIFS*2))
                     break;
                 result.wait(remain);
             }
         }
+        Thread.sleep(2);  // allow any spurious extra notifs to arrive
         if (result.failed) {
             System.out.println("TEST FAILS: Notification strangeness");
             return false;
@@ -476,6 +513,11 @@
                                "got NOTIFS_LOST for unknown and " +
                                "unserializable ones");
             return true;
+        } else if (result.knownCount >= NNOTIFS
+                || result.lostCount >= NNOTIFS*2) {
+            System.out.println("TEST FAILS: Received too many notifs: " +
+                    "known=" + result.knownCount + "; lost=" + result.lostCount);
+            return false;
         } else {
             System.out.println("TEST FAILS: Timed out without receiving " +
                                "all notifs: known=" + result.knownCount +
--- a/jdk/test/javax/management/remote/mandatory/notif/AddRemoveTest.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/test/javax/management/remote/mandatory/notif/AddRemoveTest.java	Wed Jul 05 16:40:29 2017 +0200
@@ -33,10 +33,12 @@
  */
 
 import java.net.MalformedURLException;
-import java.io.IOException;
 
+import java.util.Collections;
+import java.util.Map;
 import javax.management.*;
 import javax.management.remote.*;
+import javax.management.remote.rmi.RMIConnectorServer;
 
 public class AddRemoveTest {
     private static final String[] protocols = {"rmi", "iiop", "jmxmp"};
@@ -69,9 +71,16 @@
         }
     }
 
-    private static boolean test(String proto)
+    private static boolean test(String proto) throws Exception {
+        boolean ok = test(proto, false);
+        ok &= test(proto, true);
+        return ok;
+    }
+
+    private static boolean test(String proto, boolean eventService)
             throws Exception {
-        System.out.println(">>> Test for protocol " + proto);
+        System.out.println(">>> Test for protocol " + proto + " with" +
+                (eventService ? "" : "out") + " event service");
         JMXServiceURL u = new JMXServiceURL(proto, null, 0);
         JMXConnectorServer server;
         JMXServiceURL addr;
@@ -89,7 +98,10 @@
 
         try {
             // with a client listener, but close the server first
-            server = JMXConnectorServerFactory.newJMXConnectorServer(u, null, mbs);
+            Map<String, String> env = Collections.singletonMap(
+                    RMIConnectorServer.DELEGATE_TO_EVENT_SERVICE,
+                    Boolean.toString(eventService));
+            server = JMXConnectorServerFactory.newJMXConnectorServer(u, env, mbs);
             server.start();
 
             addr = server.getAddress();
--- a/jdk/test/javax/management/remote/mandatory/notif/DiffHBTest.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/test/javax/management/remote/mandatory/notif/DiffHBTest.java	Wed Jul 05 16:40:29 2017 +0200
@@ -31,11 +31,12 @@
  * @run main DiffHBTest
  */
 
-import java.net.MalformedURLException;
-import java.io.IOException;
 
+import java.util.Collections;
+import java.util.Map;
 import javax.management.*;
 import javax.management.remote.*;
+import javax.management.remote.rmi.RMIConnectorServer;
 
 /**
  * This test registeres an unique listener with two different handbacks,
@@ -48,11 +49,6 @@
     private static ObjectName delegateName;
     private static ObjectName timerName;
 
-    public static int received = 0;
-    public static final int[] receivedLock = new int[0];
-    public static Notification receivedNotif = null;
-
-    public static Object receivedHB = null;
     public static final String[] hbs = new String[] {"0", "1"};
 
     public static void main(String[] args) throws Exception {
@@ -61,162 +57,174 @@
         delegateName = new ObjectName("JMImplementation:type=MBeanServerDelegate");
         timerName = new ObjectName("MBean:name=Timer");
 
-        boolean ok = true;
+        String errors = "";
+
         for (int i = 0; i < protocols.length; i++) {
-            try {
-                if (!test(protocols[i])) {
-                    System.out.println(">>> Test failed for " + protocols[i]);
-                    ok = false;
+            final String s = test(protocols[i]);
+            if (s != null) {
+                if ("".equals(errors)) {
+                    errors = "Failed to " + protocols[i] + ": "+s;
                 } else {
-                    System.out.println(">>> Test successed for " + protocols[i]);
+                    errors = "\tFailed to " + protocols[i] + ": "+s;
                 }
-            } catch (Exception e) {
-                System.out.println(">>> Test failed for " + protocols[i]);
-                e.printStackTrace(System.out);
-                ok = false;
             }
         }
 
-        if (ok) {
-            System.out.println(">>> Test passed");
+        if ("".equals(errors)) {
+            System.out.println(">>> Passed!");
         } else {
-            System.out.println(">>> TEST FAILED");
-            System.exit(1);
+            System.out.println(">>> Failed!");
+
+            throw new RuntimeException(errors);
         }
     }
 
-    private static boolean test(String proto) throws Exception {
-        System.out.println(">>> Test for protocol " + proto);
+    private static String test(String proto) throws Exception {
+        String ret = null;
+        for (boolean eventService : new boolean[] {false, true}) {
+            String s = test(proto, eventService);
+            if (s != null) {
+                if (ret == null)
+                    ret = s;
+                else
+                    ret = ret + "; " + s;
+            }
+        }
+        return ret;
+    }
+
+    private static String test(String proto, boolean eventService)
+            throws Exception {
+        System.out.println(">>> Test for protocol " + proto + " with" +
+                (eventService ? "" : "out") + " event service");
         JMXServiceURL u = new JMXServiceURL(proto, null, 0);
         JMXConnectorServer server;
-        JMXServiceURL addr;
         JMXConnector client;
-        MBeanServerConnection mserver;
-
-        final NotificationListener dummyListener = new NotificationListener() {
-                public void handleNotification(Notification n, Object o) {
-                    synchronized(receivedLock) {
-                        if (n == null) {
-                            System.out.println(">>> Got a null notification.");
-                            System.exit(1);
-                        }
-
-                        // check number
-                        if (received > 2) {
-                            System.out.println(">>> Expect to receive 2 notifs,  but get "+received);
-                            System.exit(1);
-                        }
-
-                        if (received == 0) { // first time
-                            receivedNotif = n;
-                            receivedHB = o;
-
-                            if (!hbs[0].equals(o) && !hbs[1].equals(o)) {
-                                System.out.println(">>> Unkown handback: "+o);
-                                System.exit(1);
-                            }
-                        } else { // second time
-                            if (!receivedNotif.equals(n)) {
-                                System.out.println(">>> Not get same notif twice.");
-                                System.exit(1);
-                            } else if (!hbs[0].equals(o) && !hbs[1].equals(o)) { // validate handback
-                                System.out.println(">>> Unkown handback: "+o);
-                                System.exit(1);
-                            } else if (receivedHB.equals(o)) {
-                                System.out.println(">>> Got same handback twice: "+o);
-                                System.exit(1);
-                            }
-                        }
-
-                        ++received;
-
-                        if (received == 2) {
-                            receivedLock.notify();
-                        }
-                    }
-                }
-            };
 
         try {
-            server = JMXConnectorServerFactory.newJMXConnectorServer(u, null, mbs);
+            Map<String, String> env = Collections.singletonMap(
+                    RMIConnectorServer.DELEGATE_TO_EVENT_SERVICE,
+                    Boolean.toString(eventService));
+            server =
+                    JMXConnectorServerFactory.newJMXConnectorServer(u, env, mbs);
             server.start();
+            JMXServiceURL addr = server.getAddress();
+            client = JMXConnectorFactory.connect(addr, null);
+        } catch (Exception e) {
+            // not support
+            System.out.println(">>> not support: " + proto);
+            return null;
+        }
 
-            addr = server.getAddress();
-            client = JMXConnectorFactory.newJMXConnector(addr, null);
-            client.connect(null);
-
-            mserver = client.getMBeanServerConnection();
-
-            mserver.addNotificationListener(delegateName, dummyListener, null, hbs[0]);
-            mserver.addNotificationListener(delegateName, dummyListener, null, hbs[1]);
+        MBeanServerConnection mserver = client.getMBeanServerConnection();
 
-            for (int i=0; i<20; i++) {
-                synchronized(receivedLock) {
-                    received = 0;
-                }
-
-                mserver.createMBean("javax.management.timer.Timer", timerName);
+        System.out.print(">>>\t");
+        for (int i=0; i<5; i++) {
+            System.out.print(i + "\t");
+            final MyListener dummyListener = new MyListener();
+            mserver.addNotificationListener(
+                    delegateName, dummyListener, null, hbs[0]);
+            mserver.addNotificationListener(
+                    delegateName, dummyListener, null, hbs[1]);
 
-                synchronized(receivedLock) {
-                    if (received != 2) {
-                        long remainingTime = waitingTime;
-                        final long startTime = System.currentTimeMillis();
+            mserver.createMBean("javax.management.timer.Timer", timerName);
+
+            long remainingTime = waitingTime;
+            final long startTime = System.currentTimeMillis();
 
-                        while (received != 2 && remainingTime > 0) {
-                            receivedLock.wait(remainingTime);
-                            remainingTime = waitingTime -
+            try {
+                synchronized(dummyListener) {
+                    while (!dummyListener.done && remainingTime > 0) {
+                        dummyListener.wait(remainingTime);
+                        remainingTime = waitingTime -
                                 (System.currentTimeMillis() - startTime);
-                        }
                     }
 
-                    if (received != 2) {
-                        System.out.println(">>> Expected 2 notifis, but received "+received);
+                    if (dummyListener.errorInfo != null) {
+                        return dummyListener.errorInfo;
+                    }
+                }
+            } finally {
+                //System.out.println("Unregister: "+i);
+                mserver.unregisterMBean(timerName);
+                mserver.removeNotificationListener(delegateName, dummyListener);
+            }
+        }
+
+        System.out.println("");
+        client.close();
+        server.stop();
+
+        return null;
+    }
+
+    private static class MyListener implements NotificationListener {
+        public boolean done = false;
+        public String errorInfo = null;
 
-                        return false;
-                    }
+        private int received = 0;
+        private MBeanServerNotification receivedNotif = null;
+        private Object receivedHB = null;
+        public void handleNotification(Notification n, Object o) {
+            if (!(n instanceof MBeanServerNotification)) {
+                failed("Received an unexpected notification: "+n);
+                return;
+            }
+
+            if (!hbs[0].equals(o) && !hbs[1].equals(o)) {
+                failed("Unkown handback: "+o);
+                return;
+            }
+
+            // what we need
+            final MBeanServerNotification msn = (MBeanServerNotification)n;
+            if (!(MBeanServerNotification.REGISTRATION_NOTIFICATION.equals(
+                    msn.getType())) ||
+                    !msn.getMBeanName().equals(timerName)) {
+                return;
+            }
+
+            synchronized(this) {
+                received++;
+
+                if (received == 1) { // first time
+                    receivedNotif = msn;
+                    receivedHB = o;
+
+                    return;
                 }
 
+                if (received > 2) {
+                    failed("Expect to receive 2 notifs,  but get "+received);
 
-                synchronized(receivedLock) {
-                    received = 0;
+                    return;
                 }
 
-                mserver.unregisterMBean(timerName);
-
-                synchronized(receivedLock) {
-                    if (received != 2) {
-
-                        long remainingTime = waitingTime;
-                        final long startTime = System.currentTimeMillis();
-
-                        while (received != 2 && remainingTime >0) {
-                            receivedLock.wait(remainingTime);
-                            remainingTime = waitingTime -
-                                (System.currentTimeMillis() - startTime);
-                        }
-                    }
+                // second time
+                if (receivedHB.equals(o)) {
+                    failed("Got same handback twice: "+o);
+                } else if(!hbs[0].equals(o) && !hbs[1].equals(o)) {
+                    failed("Unknown handback: "+o);
+                } else if (receivedNotif.getSequenceNumber() !=
+                        msn.getSequenceNumber()) {
+                    failed("expected to receive:\n"
+                            +receivedNotif
+                            +"\n but got\n"+msn);
+                }
 
-                    if (received != 2) {
-                        System.out.println(">>> Expected 2 notifis, but received "+received);
-
-                        return false;
-                    }
-                }
+                // passed
+                done = true;
+                this.notify();
             }
-
-            mserver.removeNotificationListener(delegateName, dummyListener);
-
-            client.close();
-
-            server.stop();
-
-        } catch (MalformedURLException e) {
-            System.out.println(">>> Skipping unsupported URL " + u);
-            return true;
         }
 
-        return true;
+        private void failed(String errorInfo) {
+            this.errorInfo = errorInfo;
+            done = true;
+
+            this.notify();
+        }
     }
 
-    private final static long waitingTime = 10000;
+    private final static long waitingTime = 2000;
 }
--- a/jdk/test/javax/management/remote/mandatory/notif/EmptyDomainNotificationTest.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/test/javax/management/remote/mandatory/notif/EmptyDomainNotificationTest.java	Wed Jul 05 16:40:29 2017 +0200
@@ -29,11 +29,12 @@
  * @author Shanliang JIANG
  * @run clean EmptyDomainNotificationTest
  * @run build EmptyDomainNotificationTest
- * @run main EmptyDomainNotificationTest
+ * @run main EmptyDomainNotificationTest classic
+ * @run main EmptyDomainNotificationTest event
  */
 
-import java.util.ArrayList;
-import java.util.List;
+import java.util.Collections;
+import java.util.Map;
 import javax.management.MBeanServer;
 import javax.management.MBeanServerConnection;
 import javax.management.MBeanServerFactory;
@@ -46,6 +47,7 @@
 import javax.management.remote.JMXConnectorServer;
 import javax.management.remote.JMXConnectorServerFactory;
 import javax.management.remote.JMXServiceURL;
+import javax.management.remote.rmi.RMIConnectorServer;
 
 public class EmptyDomainNotificationTest {
 
@@ -80,11 +82,25 @@
 
     public static void main(String[] args) throws Exception {
 
+        String type = args[0];
+        boolean eventService;
+        if (type.equals("classic"))
+            eventService = false;
+        else if (type.equals("event"))
+            eventService = true;
+        else
+            throw new IllegalArgumentException(type);
+
         final MBeanServer mbs = MBeanServerFactory.createMBeanServer();
 
         final JMXServiceURL url = new JMXServiceURL("service:jmx:rmi://");
 
-        JMXConnectorServer server = JMXConnectorServerFactory.newJMXConnectorServer(url, null, mbs);
+        Map<String, String> env = Collections.singletonMap(
+                RMIConnectorServer.DELEGATE_TO_EVENT_SERVICE,
+                Boolean.toString(eventService));
+
+        JMXConnectorServer server =
+                JMXConnectorServerFactory.newJMXConnectorServer(url, env, mbs);
         server.start();
 
         JMXConnector client = JMXConnectorFactory.connect(server.getAddress(), null);
--- a/jdk/test/javax/management/remote/mandatory/notif/ListenerScaleTest.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/test/javax/management/remote/mandatory/notif/ListenerScaleTest.java	Wed Jul 05 16:40:29 2017 +0200
@@ -51,18 +51,29 @@
  * been compiled by the second.
  */
 
-import java.lang.management.ManagementFactory;
-import javax.management.*;
-import javax.management.remote.*;
-import java.util.concurrent.*;
+import java.util.Collections;
+import java.util.Map;
+import java.util.concurrent.Semaphore;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerConnection;
+import javax.management.MBeanServerFactory;
+import javax.management.MalformedObjectNameException;
+import javax.management.Notification;
+import javax.management.NotificationBroadcasterSupport;
+import javax.management.NotificationListener;
+import javax.management.ObjectName;
+import javax.management.remote.JMXConnector;
+import javax.management.remote.JMXConnectorFactory;
+import javax.management.remote.JMXConnectorServer;
+import javax.management.remote.JMXConnectorServerFactory;
+import javax.management.remote.JMXServiceURL;
+import javax.management.remote.rmi.RMIConnectorServer;
 
 public class ListenerScaleTest {
     private static final int WARMUP_WITH_ONE_MBEAN = 1000;
     private static final int NOTIFS_TO_TIME = 100;
     private static final int EXTRA_MBEANS = 20000;
 
-    private static final MBeanServer mbs =
-        ManagementFactory.getPlatformMBeanServer();
     private static final ObjectName testObjectName;
     static {
         try {
@@ -87,7 +98,7 @@
             }
         };
 
-    private static final long timeNotif() {
+    private static final long timeNotif(MBeanServer mbs) {
         try {
             startTime = System.nanoTime();
             nnotifs = 0;
@@ -117,12 +128,20 @@
         };
 
     public static void main(String[] args) throws Exception {
-        MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
+        test(false);
+        test(true);
+    }
+
+    private static void test(boolean eventService) throws Exception {
+        MBeanServer mbs = MBeanServerFactory.newMBeanServer();
         Sender sender = new Sender();
         mbs.registerMBean(sender, testObjectName);
         JMXServiceURL url = new JMXServiceURL("service:jmx:rmi://");
+        Map<String, String> env = Collections.singletonMap(
+                RMIConnectorServer.DELEGATE_TO_EVENT_SERVICE,
+                Boolean.toString(eventService));
         JMXConnectorServer cs =
-            JMXConnectorServerFactory.newJMXConnectorServer(url, null, mbs);
+            JMXConnectorServerFactory.newJMXConnectorServer(url, env, mbs);
         cs.start();
         JMXServiceURL addr = cs.getAddress();
         JMXConnector cc = JMXConnectorFactory.connect(addr);
@@ -140,7 +159,7 @@
         mbsc.addNotificationListener(testObjectName, timingListener, null, null);
         long singleMBeanTime = 0;
         for (int i = 0; i < WARMUP_WITH_ONE_MBEAN; i++)
-            singleMBeanTime = timeNotif();
+            singleMBeanTime = timeNotif(mbs);
         if (singleMBeanTime == 0)
             singleMBeanTime = 1;
         System.out.println("Time with a single MBean: " + singleMBeanTime + "ns");
@@ -165,7 +184,7 @@
         }
         System.out.println();
         System.out.println("Timing a notification send now");
-        long manyMBeansTime = timeNotif();
+        long manyMBeansTime = timeNotif(mbs);
         System.out.println("Time with many MBeans: " + manyMBeansTime + "ns");
         double ratio = (double) manyMBeansTime / singleMBeanTime;
         if (ratio > 100.0)
--- a/jdk/test/javax/management/remote/mandatory/notif/NotifBufferSizePropertyNameTest.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/test/javax/management/remote/mandatory/notif/NotifBufferSizePropertyNameTest.java	Wed Jul 05 16:40:29 2017 +0200
@@ -31,11 +31,11 @@
  * @run main NotifBufferSizePropertyNameTest
  */
 
-import java.io.IOException;
 import java.util.*;
 
 import javax.management.*;
 import javax.management.remote.*;
+import javax.management.remote.rmi.RMIConnectorServer;
 
 /**
  * This class tests also the size of a server notification buffer.
@@ -88,6 +88,9 @@
     private static void test(Map env) throws Exception {
         final MBeanServer mbs = MBeanServerFactory.newMBeanServer();
 
+        env = new HashMap((env == null) ? Collections.emptyMap() : env);
+        env.put(RMIConnectorServer.DELEGATE_TO_EVENT_SERVICE, "false");
+
         mbs.registerMBean(new NotificationEmitter(), oname);
         JMXConnectorServer server = JMXConnectorServerFactory.newJMXConnectorServer(
                                                                                url,
--- a/jdk/test/javax/management/remote/mandatory/notif/NotifReconnectDeadlockTest.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/test/javax/management/remote/mandatory/notif/NotifReconnectDeadlockTest.java	Wed Jul 05 16:40:29 2017 +0200
@@ -22,7 +22,7 @@
  */
 
 /*
- * @test NotifReconnectDeadlockTest
+ * @test
  * @bug 6199899
  * @summary Tests reconnection done by a fetching notif thread.
  * @author Shanliang JIANG
@@ -31,11 +31,21 @@
  * @run main NotifReconnectDeadlockTest
  */
 
-import java.io.IOException;
-import java.util.*;
-
-import javax.management.*;
-import javax.management.remote.*;
+import java.util.HashMap;
+import java.util.Map;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.Notification;
+import javax.management.NotificationBroadcasterSupport;
+import javax.management.NotificationListener;
+import javax.management.ObjectName;
+import javax.management.remote.JMXConnectionNotification;
+import javax.management.remote.JMXConnector;
+import javax.management.remote.JMXConnectorFactory;
+import javax.management.remote.JMXConnectorServer;
+import javax.management.remote.JMXConnectorServerFactory;
+import javax.management.remote.JMXServiceURL;
+import javax.management.remote.rmi.RMIConnectorServer;
 
 /**
  * "This test checks for a bug whereby reconnection did not work if (a) it was
@@ -64,6 +74,7 @@
         Map env = new HashMap(2);
         env.put("jmx.remote.x.server.connection.timeout", new Long(serverTimeout));
         env.put("jmx.remote.x.client.connection.check.period", new Long(Long.MAX_VALUE));
+        env.put(RMIConnectorServer.DELEGATE_TO_EVENT_SERVICE, "false");
 
         final MBeanServer mbs = MBeanServerFactory.newMBeanServer();
 
--- a/jdk/test/javax/management/remote/mandatory/notif/NotificationAccessControllerTest.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/test/javax/management/remote/mandatory/notif/NotificationAccessControllerTest.java	Wed Jul 05 16:40:29 2017 +0200
@@ -156,7 +156,8 @@
                            List<Notification> received,
                            List<ObjectName> expected) {
         if (received.size() != size) {
-            echo("Error: expecting " + size + " notifications");
+            echo("Error: expecting " + size + " notifications, got " +
+                    received.size());
             return 1;
         } else {
             for (Notification n : received) {
--- a/jdk/test/javax/management/remote/mandatory/notif/NotificationBufferCreationTest.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/test/javax/management/remote/mandatory/notif/NotificationBufferCreationTest.java	Wed Jul 05 16:40:29 2017 +0200
@@ -32,6 +32,8 @@
  */
 import java.net.MalformedURLException;
 
+import java.util.Collections;
+import java.util.Map;
 import javax.management.MBeanServerFactory;
 import javax.management.MBeanServer;
 import javax.management.MBeanServerConnection;
@@ -44,6 +46,7 @@
 import javax.management.remote.JMXConnectorServer;
 import javax.management.remote.JMXConnectorServerFactory;
 import javax.management.remote.JMXServiceURL;
+import javax.management.remote.rmi.RMIConnectorServer;
 
 public class NotificationBufferCreationTest {
     private static final MBeanServer mbs =
@@ -86,6 +89,8 @@
         JMXServiceURL u = null;
         try {
             u = new JMXServiceURL(protocol, null, 0);
+            Map<String, String> env = Collections.singletonMap(
+                    RMIConnectorServer.DELEGATE_TO_EVENT_SERVICE, "false");
             server =
                 JMXConnectorServerFactory.newJMXConnectorServer(u,
                                                                 null,
--- a/jdk/test/javax/management/remote/mandatory/notif/NotificationBufferDeadlockTest.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/test/javax/management/remote/mandatory/notif/NotificationBufferDeadlockTest.java	Wed Jul 05 16:40:29 2017 +0200
@@ -35,7 +35,9 @@
 import java.lang.reflect.Method;
 import java.lang.reflect.Proxy;
 import java.net.MalformedURLException;
+import java.util.Collections;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 import java.util.Vector;
 import javax.management.*;
@@ -88,6 +90,7 @@
  * If the logic for adding the notification buffer's listener is incorrect
  * we could remove zero or two notifications from an MBean.
  */
+import javax.management.remote.rmi.RMIConnectorServer;
 public class NotificationBufferDeadlockTest {
     public static void main(String[] args) throws Exception {
         System.out.println("Check no deadlock if notif sent while initial " +
@@ -109,7 +112,13 @@
     }
 
     private static void test(String proto) throws Exception {
-        System.out.println("Testing protocol " + proto);
+        test(proto, false);
+        test(proto, true);
+    }
+
+    private static void test(String proto, boolean eventService) throws Exception {
+        System.out.println("Testing protocol " + proto + " with" +
+                (eventService ? "" : "out") + " event service");
         MBeanServer mbs = MBeanServerFactory.newMBeanServer();
         ObjectName testName = newName();
         DeadlockTest test = new DeadlockTest();
@@ -117,8 +126,11 @@
         JMXServiceURL url = new JMXServiceURL("service:jmx:" + proto + ":///");
         JMXConnectorServer cs;
         try {
+            Map<String, String> env = Collections.singletonMap(
+                    RMIConnectorServer.DELEGATE_TO_EVENT_SERVICE,
+                    Boolean.toString(eventService));
             cs =
-                JMXConnectorServerFactory.newJMXConnectorServer(url, null, mbs);
+                JMXConnectorServerFactory.newJMXConnectorServer(url, env, mbs);
         } catch (MalformedURLException e) {
             System.out.println("...protocol not supported, ignoring");
             return;
--- a/jdk/test/javax/management/remote/mandatory/notif/NotificationEmissionTest.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/test/javax/management/remote/mandatory/notif/NotificationEmissionTest.java	Wed Jul 05 16:40:29 2017 +0200
@@ -29,11 +29,16 @@
  * @author Luis-Miguel Alventosa
  * @run clean NotificationEmissionTest
  * @run build NotificationEmissionTest
- * @run main NotificationEmissionTest 1
- * @run main NotificationEmissionTest 2
- * @run main NotificationEmissionTest 3
- * @run main NotificationEmissionTest 4
- * @run main NotificationEmissionTest 5
+ * @run main NotificationEmissionTest 1 Classic
+ * @run main NotificationEmissionTest 2 Classic
+ * @run main NotificationEmissionTest 3 Classic
+ * @run main NotificationEmissionTest 4 Classic
+ * @run main NotificationEmissionTest 5 Classic
+ * @run main NotificationEmissionTest 1 EventService
+ * @run main NotificationEmissionTest 2 EventService
+ * @run main NotificationEmissionTest 3 EventService
+ * @run main NotificationEmissionTest 4 EventService
+ * @run main NotificationEmissionTest 5 EventService
  */
 
 import java.io.File;
@@ -56,9 +61,15 @@
 import javax.management.remote.JMXConnectorServerFactory;
 import javax.management.remote.JMXPrincipal;
 import javax.management.remote.JMXServiceURL;
+import javax.management.remote.rmi.RMIConnectorServer;
 import javax.security.auth.Subject;
 
 public class NotificationEmissionTest {
+    private final boolean eventService;
+
+    public NotificationEmissionTest(boolean eventService) {
+        this.eventService = eventService;
+    }
 
     public class CustomJMXAuthenticator implements JMXAuthenticator {
         public Subject authenticate(Object credentials) {
@@ -102,7 +113,8 @@
                            List<Notification> received,
                            List<ObjectName> expected) {
         if (received.size() != size) {
-            echo("Error: expecting " + size + " notifications");
+            echo("Error: expecting " + size + " notifications, got " +
+                    received.size());
             return 1;
         } else {
             for (Notification n : received) {
@@ -216,8 +228,13 @@
             //
             final Map<String,Object> env = new HashMap<String,Object>();
             env.put("jmx.remote.authenticator", new CustomJMXAuthenticator());
-            if (prop)
+            env.put(RMIConnectorServer.EVENT_CLIENT_DELEGATE_FORWARDER,
+                    Boolean.toString(eventService));
+            if (prop) {
+                echo("Setting jmx.remote.x.check.notification.emission to " +
+                        propValue);
                 env.put("jmx.remote.x.check.notification.emission", propValue);
+            }
 
             // Create the JMXServiceURL
             //
@@ -282,9 +299,24 @@
                 new Object[] {2, nb3},
                 new String[] {"int", "javax.management.ObjectName"});
 
+            // If the check is effective and we're using policy.negative,
+            // then we should see the two notifs sent by nb2 (of which one
+            // has a getSource() that is nb3), but not the notif sent by nb1.
+            // Otherwise we should see all three notifs.  If we're using the
+            // Event Service with a Security Manager then the logic to
+            // reapply the addNL permission test for every notification is
+            // always enabled, regardless of the value of
+            // jmx.remote.x.check.notification.emission.  Otherwise, the
+            // test is only applied if that property is explicitly true.
+            int expectedNotifs =
+                    ((prop || eventService) && sm && !policyPositive) ? 2 : 3;
+
             // Wait for notifications to be emitted
             //
-            Thread.sleep(2000);
+            long deadline = System.currentTimeMillis() + 2000;
+            while (li.notifs.size() < expectedNotifs &&
+                    System.currentTimeMillis() < deadline)
+                Thread.sleep(1);
 
             // Remove notification listener
             //
@@ -297,16 +329,10 @@
             sources.add(nb2);
             sources.add(nb3);
 
-            if (prop && sm && !policyPositive) {
-                // List must contain two notifs from sources nb2 and nb3
-                //
-                result = checkNotifs(2, li.notifs, sources);
-            } else {
-                // List must contain three notifs from sources nb1, nb2 and nb3
-                //
-                result = checkNotifs(3, li.notifs, sources);
-            }
+            result = checkNotifs(expectedNotifs, li.notifs, sources);
             if (result > 0) {
+                echo("...SecurityManager=" + sm + "; policy=" + policyPositive +
+                        "; eventService=" + eventService);
                 return result;
             }
         } finally {
@@ -336,9 +362,18 @@
     public static void main(String[] args) throws Exception {
 
         echo("\n--- Check the emission of notifications " +
-             "when a Security Manager is installed ---");
+             "when a Security Manager is installed [" +
+             args[1] + "] ---");
 
-        NotificationEmissionTest net = new NotificationEmissionTest();
+        boolean eventService;
+        if (args[1].equals("Classic"))
+            eventService = false;
+        else if (args[1].equals("EventService"))
+            eventService = true;
+        else
+            throw new IllegalArgumentException(args[1]);
+
+        NotificationEmissionTest net = new NotificationEmissionTest(eventService);
 
         int error = 0;
 
--- a/jdk/test/javax/management/remote/mandatory/notif/RMINotifTest.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/test/javax/management/remote/mandatory/notif/RMINotifTest.java	Wed Jul 05 16:40:29 2017 +0200
@@ -22,36 +22,53 @@
  */
 
 /*
- * @test RMINotifTest.java
+ * @test
  * @bug 7654321
- * @summary Tests to receive notifications for opened and closed connect
-ions
+ * @summary Tests to receive notifications for opened and closed connections
  * @author sjiang
  * @run clean RMINotifTest
  * @run build RMINotifTest
- * @run main RMINotifTest
+ * @run main RMINotifTest classic
+ * @run main RMINotifTest event
  */
 
 // java imports
 //
-import java.io.IOException;
-import java.net.UnknownHostException;
 
-import java.rmi.*;
-import java.rmi.registry.*;
+import java.rmi.RemoteException;
+import java.rmi.registry.LocateRegistry;
+import java.rmi.registry.Registry;
+import java.util.Collections;
+import java.util.Map;
 import java.util.Random;
-
-// JMX imports
-//
-import javax.management.* ;
-
-import javax.management.remote.*;
-import javax.management.remote.rmi.*;
+import javax.management.MBeanNotificationInfo;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerConnection;
+import javax.management.MBeanServerFactory;
+import javax.management.Notification;
+import javax.management.NotificationBroadcasterSupport;
+import javax.management.NotificationFilterSupport;
+import javax.management.NotificationListener;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.remote.JMXConnector;
+import javax.management.remote.JMXConnectorFactory;
+import javax.management.remote.JMXConnectorServer;
+import javax.management.remote.JMXConnectorServerFactory;
 import javax.management.remote.JMXServiceURL;
+import javax.management.remote.rmi.RMIConnectorServer;
 
 public class RMINotifTest {
 
     public static void main(String[] args) {
+        String eventService;
+        if (args[0].equals("classic"))
+            eventService = "false";
+        else if (args[0].equals("event"))
+            eventService = "true";
+        else
+            throw new IllegalArgumentException(args[0]);
+
         try {
             // create a rmi registry
             Registry reg = null;
@@ -88,9 +105,10 @@
                                   "/jndi/rmi://:" + port + "/server" + port);
             System.out.println("RMIConnectorServer address " + url);
 
+            Map<String, String> env = Collections.singletonMap(
+                    RMIConnectorServer.DELEGATE_TO_EVENT_SERVICE, eventService);
             JMXConnectorServer sServer =
-                JMXConnectorServerFactory.newJMXConnectorServer(url, null,
-                                                                null);
+                JMXConnectorServerFactory.newJMXConnectorServer(url, env, null);
 
             ObjectInstance ss = server.registerMBean(sServer, new ObjectName("Default:name=RmiConnectorServer"));
 
--- a/jdk/test/javax/management/remote/mandatory/notif/UnexpectedNotifTest.java	Thu Aug 14 22:17:02 2008 -0700
+++ b/jdk/test/javax/management/remote/mandatory/notif/UnexpectedNotifTest.java	Wed Jul 05 16:40:29 2017 +0200
@@ -32,68 +32,88 @@
  * @run main UnexpectedNotifTest
  */
 
-// java imports
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import javax.management.MBeanNotificationInfo;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerConnection;
+import javax.management.MBeanServerFactory;
+import javax.management.Notification;
+import javax.management.NotificationBroadcasterSupport;
+import javax.management.NotificationListener;
+import javax.management.ObjectName;
+import javax.management.remote.JMXConnector;
+import javax.management.remote.JMXConnectorFactory;
+import javax.management.remote.JMXConnectorServer;
+import javax.management.remote.JMXConnectorServerFactory;
+import javax.management.remote.JMXServiceURL;
 //
-import java.io.IOException;
-
-// JMX imports
-//
-import javax.management.*;
-import javax.management.remote.*;
+import javax.management.remote.rmi.RMIConnectorServer;
 
 public class UnexpectedNotifTest {
 
     public static void main(String[] args) throws Exception {
-        String[] protos = null;
+        List<String> protos = new ArrayList<String>();
+        protos.add("rmi");
         try {
             Class.forName("javax.management.remote.jmxmp.JMXMPConnectorServer");
-            protos = new String[2];
-            protos[0] = "rmi";
-            protos[1] = "jmxmp";
+            protos.add("jmxmp");
         } catch (ClassNotFoundException e) {
-            protos = new String[1];
-            protos[0] = "rmi";
+            // OK: JMXMP not present so don't test it.
+        }
+        for (String proto : protos) {
+            test(proto, false);
+            test(proto, true);
         }
-        for (int i = 0; i < protos.length; i++) {
-            System.out.println("Unexpected notifications test for protocol " +
-                               protos[i]);
-            MBeanServer mbs = null;
-            try {
-                // Create a MBeanServer
-                //
-                mbs = MBeanServerFactory.createMBeanServer();
+    }
 
-                // Create a NotificationEmitter MBean
-                //
-                mbean = new ObjectName ("Default:name=NotificationEmitter");
-                mbs.registerMBean(new NotificationEmitter(), mbean);
+    private static void test(String proto, boolean eventService)
+            throws Exception {
+        System.out.println("Unexpected notifications test for protocol " +
+                           proto + " with" +
+                           (eventService ? "" : "out") + " event service");
+        MBeanServer mbs = null;
+        try {
+            // Create a MBeanServer
+            //
+            mbs = MBeanServerFactory.createMBeanServer();
+
+            // Create a NotificationEmitter MBean
+            //
+            mbean = new ObjectName ("Default:name=NotificationEmitter");
+            mbs.registerMBean(new NotificationEmitter(), mbean);
 
-                // Create a connector server
-                //
-                url = new JMXServiceURL("service:jmx:" + protos[i] + "://");
-                server = JMXConnectorServerFactory.newJMXConnectorServer(url,
-                                                                         null,
-                                                                         mbs);
+            // Create a connector server
+            //
+            url = new JMXServiceURL("service:jmx:" + proto + "://");
+            Map<String, String> env = Collections.singletonMap(
+                    RMIConnectorServer.DELEGATE_TO_EVENT_SERVICE,
+                    Boolean.toString(eventService));
 
-                mbs.registerMBean(
-                            server,
-                            new ObjectName("Default:name=ConnectorServer"));
+            server = JMXConnectorServerFactory.newJMXConnectorServer(url,
+                                                                     env,
+                                                                     mbs);
 
-                server.start();
+            mbs.registerMBean(
+                        server,
+                        new ObjectName("Default:name=ConnectorServer"));
 
-                url = server.getAddress();
+            server.start();
+
+            url = server.getAddress();
 
-                for (int j = 0; j < 2; j++) {
-                    test();
-                }
-            } finally {
-                // Stop server
-                //
-                server.stop();
-                // Release the MBeanServer
-                //
-                MBeanServerFactory.releaseMBeanServer(mbs);
+            for (int j = 0; j < 2; j++) {
+                test();
             }
+        } finally {
+            // Stop server
+            //
+            server.stop();
+            // Release the MBeanServer
+            //
+            MBeanServerFactory.releaseMBeanServer(mbs);
         }
     }