Merge jdk7-b34
authorduke
Wed, 05 Jul 2017 16:40:31 +0200
changeset 1051 90cf935adb35
parent 1050 8444a48d787d (diff)
parent 946 a26a64878860 (current diff)
child 1052 12555bdf3bc6
child 1053 26dc44e4ee9f
child 1054 a8a80ae24f31
child 1080 f37e2470107d
child 1087 b24f516b76d7
child 1102 2b8dd97d6682
child 1104 74058712101b
child 1106 a4639ed3162c
child 1108 d23dfe93edc9
child 1109 853d8c191eac
child 1117 78c43ef52a0a
child 1161 3a209f585a3f
child 1192 715cf9378c53
child 1196 8004ddea3ea2
Merge
--- a/.hgtags-top-repo	Wed Jul 05 16:39:59 2017 +0200
+++ b/.hgtags-top-repo	Wed Jul 05 16:40:31 2017 +0200
@@ -7,3 +7,4 @@
 2dab2f712e1832c92acfa63ec0337048b9422c20 jdk7-b30
 3300a35a0bd56d695b92fe0b34f03ebbfc939064 jdk7-b31
 64da805be725721bf2004e7409a0d7a16fc8ddbc jdk7-b32
+bb1ef4ee3d2c8cbf43a37d372325a7952be590b9 jdk7-b33
--- a/Makefile	Wed Jul 05 16:39:59 2017 +0200
+++ b/Makefile	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/corba/.hgtags	Wed Jul 05 16:40:31 2017 +0200
@@ -7,3 +7,4 @@
 c0252adbb2abbfdd6c35595429ac6fbdd98e20ac jdk7-b30
 ef6af34d75a7b44e77083f1d4ee47631fa09d3b4 jdk7-b31
 80a0f46a6203e727012bd579fe38a609b83decce jdk7-b32
+6a5b9d2f8b20de54e3bfe33cd12bd0793caedc4e jdk7-b33
--- a/hotspot/.hgtags	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/.hgtags	Wed Jul 05 16:40:31 2017 +0200
@@ -7,3 +7,4 @@
 d1605aabd0a15ecf93787c47de63073c33fba52d jdk7-b30
 9c2ecc2ffb125f14fab3857fe7689598956348a0 jdk7-b31
 b727c32788a906c04839516ae7443a085185a300 jdk7-b32
+585535ec8a14adafa6bfea65d6975e29094c8cec jdk7-b33
--- a/hotspot/agent/make/Makefile	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/agent/make/Makefile	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/agent/make/bugspot.bat	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/agent/make/build.xml	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/agent/make/hsdb.bat	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/agent/make/hsdb.sh	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/agent/make/saenv.bat	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/agent/make/saenv.sh	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/agent/make/saenv64.bat	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/agent/make/saenv64.sh	Wed Jul 05 16:40:31 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:31 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:31 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:31 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:31 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:31 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:31 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:31 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:31 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:31 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:31 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:31 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:31 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:31 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:31 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:31 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:31 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:31 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:31 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:31 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:31 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:31 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:31 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:31 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:31 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:31 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:31 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:31 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:31 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:31 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:31 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:31 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:31 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:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/HeapSummary.java	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/PermStat.java	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/make/hotspot_distro	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/make/hotspot_version	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/make/jprt.config	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/make/linux/makefiles/vm.make	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/make/solaris/makefiles/fastdebug.make	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/make/solaris/makefiles/sparcWorks.make	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/make/windows/makefiles/defs.make	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/cpu/x86/vm/stubGenerator_x86_32.cpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/os/linux/vm/os_linux.cpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/os/solaris/vm/osThread_solaris.cpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/os/solaris/vm/os_solaris.cpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/os/windows/vm/os_windows.cpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/adlc/formssel.cpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/ci/ciMethodBlocks.cpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/classfile/javaClasses.cpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/compiler/oopMap.cpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/compiler/oopMap.hpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/binaryTreeDictionary.cpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/freeBlockDictionary.hpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/freeChunk.hpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/gc_implementation/includeDB_gc_concurrentMarkSweep	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/gc_implementation/includeDB_gc_parNew	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/gc_implementation/includeDB_gc_parallelScavenge	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/gc_implementation/includeDB_gc_shared	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/gc_implementation/parNew/asParNewGeneration.cpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/asPSYoungGen.cpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/cardTableExtension.cpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.hpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweepDecorator.cpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psOldGen.cpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psOldGen.hpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.hpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psYoungGen.cpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psYoungGen.hpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/gc_implementation/shared/gcUtil.hpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/gc_implementation/shared/mutableNUMASpace.cpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/gc_implementation/shared/mutableNUMASpace.hpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/gc_implementation/shared/mutableSpace.cpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/gc_implementation/shared/mutableSpace.hpp	Wed Jul 05 16:40:31 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:31 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:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/includeDB_core	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/includeDB_features	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/memory/compactingPermGenGen.cpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/memory/compactingPermGenGen.hpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/memory/defNewGeneration.cpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/memory/defNewGeneration.hpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/memory/dump.cpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/memory/genCollectedHeap.cpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/memory/genCollectedHeap.hpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/memory/genMarkSweep.cpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/memory/generation.cpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/memory/generation.hpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/memory/space.cpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/memory/space.hpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/memory/universe.cpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/opto/bytecodeInfo.cpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/opto/c2_globals.hpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/opto/callnode.cpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/opto/cfgnode.cpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/opto/compile.cpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/opto/escape.cpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/opto/escape.hpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/opto/idealGraphPrinter.cpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/opto/ifnode.cpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/opto/lcm.cpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/opto/loopopts.cpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/opto/macro.cpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/opto/macro.hpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/opto/memnode.cpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/opto/memnode.hpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/opto/node.hpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/opto/parse.hpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/opto/parse2.cpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/opto/superword.cpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/opto/type.cpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/runtime/arguments.cpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/runtime/arguments.hpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/runtime/globals.hpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/runtime/init.cpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/runtime/java.cpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/runtime/java.hpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/runtime/os.cpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/runtime/os.hpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/runtime/statSampler.cpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/runtime/thread.cpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/runtime/threadLocalStorage.cpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/runtime/threadLocalStorage.hpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/runtime/vmStructs.cpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/services/threadService.cpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/src/share/vm/utilities/globalDefinitions.hpp	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/test/compiler/6646019/Test.java	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/test/compiler/6689060/Test.java	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/hotspot/test/compiler/6695810/Test.java	Wed Jul 05 16:40:31 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:31 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:31 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:31 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:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jaxp/.hgtags	Wed Jul 05 16:40:31 2017 +0200
@@ -7,3 +7,4 @@
 2d94a238a1641d074e6032dcdceed461d6f85d6a jdk7-b30
 255d64ee287e926e8629dd80bc67690e65eeba30 jdk7-b31
 400a5ee432cc2db9031e06852ddde9264a192b48 jdk7-b32
+95375835527f0bf06124ce984266e2ad5de8a6dc jdk7-b33
--- a/jaxws/.hgtags	Wed Jul 05 16:39:59 2017 +0200
+++ b/jaxws/.hgtags	Wed Jul 05 16:40:31 2017 +0200
@@ -7,3 +7,4 @@
 7f2466f8cc7009702e548d1a763254f546024d7e jdk7-b30
 f978623825364a2ad9c6f51d02fc9424a8b0bc86 jdk7-b31
 e6daca2eced9d84b01255cabcfcc49164c26405e jdk7-b32
+6dcbcfb9551aaa2a80906c28ab48c9a8564e0e64 jdk7-b33
--- a/jdk/.hgtags	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/.hgtags	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/make/common/shared/Defs-windows.gmk	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/make/docs/CORE_PKGS.gmk	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/make/jprt.properties	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/make/netbeans/jconsole/build.properties	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/make/netbeans/jconsole/build.xml	Wed Jul 05 16:40:31 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:31 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:31 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:31 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:31 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:31 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:31 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:31 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:31 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:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/src/share/classes/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java	Wed Jul 05 16:40:31 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:31 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:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/src/share/classes/com/sun/jmx/interceptor/package.html	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/DefaultMXBeanMappingFactory.java	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanInjector.java	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanSupport.java	Wed Jul 05 16:40:31 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:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/Util.java	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/src/share/classes/com/sun/jmx/remote/internal/ClientNotifForwarder.java	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/src/share/classes/com/sun/jmx/remote/internal/ProxyInputStream.java	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/src/share/classes/com/sun/jmx/remote/internal/ProxyRef.java	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/src/share/classes/com/sun/jmx/remote/internal/ServerNotifForwarder.java	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/src/share/classes/com/sun/jmx/remote/security/FileLoginModule.java	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/src/share/classes/com/sun/jmx/remote/util/EnvHelp.java	Wed Jul 05 16:40:31 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:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/src/share/classes/com/sun/jmx/snmp/tasks/ThreadService.java	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/src/share/classes/java/util/Timer.java	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/src/share/classes/java/util/concurrent/ScheduledThreadPoolExecutor.java	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/src/share/classes/javax/management/ImmutableDescriptor.java	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/src/share/classes/javax/management/MBeanRegistration.java	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/src/share/classes/javax/management/MBeanServer.java	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/src/share/classes/javax/management/MBeanServerConnection.java	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/src/share/classes/javax/management/MBeanServerNotification.java	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/src/share/classes/javax/management/MXBean.java	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/src/share/classes/javax/management/ObjectName.java	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/src/share/classes/javax/management/QueryParser.java	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/src/share/classes/javax/management/StringValueExp.java	Wed Jul 05 16:40:31 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:31 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:31 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:31 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:31 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:31 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:31 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:31 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:31 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:31 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:31 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:31 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:31 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:31 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:31 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:31 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:31 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:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/src/share/classes/javax/management/loading/MLet.java	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/src/share/classes/javax/management/modelmbean/ModelMBeanInfoSupport.java	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/src/share/classes/javax/management/modelmbean/RequiredModelMBean.java	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/src/share/classes/javax/management/openmbean/CompositeDataSupport.java	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/src/share/classes/javax/management/openmbean/MXBeanMapping.java	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/src/share/classes/javax/management/openmbean/MXBeanMappingFactory.java	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/src/share/classes/javax/management/openmbean/TabularDataSupport.java	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/src/share/classes/javax/management/relation/RelationService.java	Wed Jul 05 16:40:31 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:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/src/share/classes/javax/management/remote/JMXConnector.java	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/src/share/classes/javax/management/remote/JMXConnectorServer.java	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/src/share/classes/javax/management/remote/JMXConnectorServerFactory.java	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/src/share/classes/javax/management/remote/JMXConnectorServerMBean.java	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/src/share/classes/javax/management/remote/rmi/RMIConnectionImpl.java	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/src/share/classes/javax/management/remote/rmi/RMIConnector.java	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/src/share/classes/javax/management/remote/rmi/RMIConnectorServer.java	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/src/share/classes/sun/tools/jconsole/inspector/TableSorter.java	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/src/share/classes/sun/tools/jconsole/inspector/XMBeanAttributes.java	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/src/share/classes/sun/tools/jconsole/inspector/XPlotter.java	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/src/share/classes/sun/tools/jconsole/inspector/XSheet.java	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/src/share/classes/sun/tools/jconsole/inspector/XTable.java	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/src/share/classes/sun/tools/jconsole/inspector/XTextFieldEditor.java	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/test/com/sun/jdi/Solaris32AndSolaris64Test.sh	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/test/java/lang/management/ManagementFactory/ThreadMXBeanProxy.java	Wed Jul 05 16:40:31 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:31 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:31 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:31 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:31 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:31 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:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/test/javax/management/ObjectName/SerialCompatTest.java	Wed Jul 05 16:40:31 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:31 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:31 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:31 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:31 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:31 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:31 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:31 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:31 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:31 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:31 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:31 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:31 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:31 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:31 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:31 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:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/test/javax/management/mxbean/GenericArrayTypeTest.java	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/test/javax/management/mxbean/LeakTest.java	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/test/javax/management/mxbean/MBeanOperationInfoTest.java	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/test/javax/management/mxbean/MXBeanTest.java	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/test/javax/management/mxbean/ThreadMXBeanTest.java	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/test/javax/management/mxbean/TigerMXBean.java	Wed Jul 05 16:40:31 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:31 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:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/test/javax/management/query/QueryNotifFilterTest.java	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/test/javax/management/remote/mandatory/connection/CloseServerTest.java	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/test/javax/management/remote/mandatory/connection/DeadLockTest.java	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/test/javax/management/remote/mandatory/connection/IdleTimeoutTest.java	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/test/javax/management/remote/mandatory/connection/RMIExitTest.java	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/test/javax/management/remote/mandatory/connection/ReconnectTest.java	Wed Jul 05 16:40:31 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:31 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:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/test/javax/management/remote/mandatory/loading/MissingClassTest.java	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/test/javax/management/remote/mandatory/notif/AddRemoveTest.java	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/test/javax/management/remote/mandatory/notif/DiffHBTest.java	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/test/javax/management/remote/mandatory/notif/EmptyDomainNotificationTest.java	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/test/javax/management/remote/mandatory/notif/ListenerScaleTest.java	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/test/javax/management/remote/mandatory/notif/NotifBufferSizePropertyNameTest.java	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/test/javax/management/remote/mandatory/notif/NotifReconnectDeadlockTest.java	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/test/javax/management/remote/mandatory/notif/NotificationAccessControllerTest.java	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/test/javax/management/remote/mandatory/notif/NotificationBufferCreationTest.java	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/test/javax/management/remote/mandatory/notif/NotificationBufferDeadlockTest.java	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/test/javax/management/remote/mandatory/notif/NotificationEmissionTest.java	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/test/javax/management/remote/mandatory/notif/RMINotifTest.java	Wed Jul 05 16:40:31 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	Wed Jul 05 16:39:59 2017 +0200
+++ b/jdk/test/javax/management/remote/mandatory/notif/UnexpectedNotifTest.java	Wed Jul 05 16:40:31 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);
         }
     }
 
--- a/langtools/.hgtags	Wed Jul 05 16:39:59 2017 +0200
+++ b/langtools/.hgtags	Wed Jul 05 16:40:31 2017 +0200
@@ -7,3 +7,4 @@
 eaf608c64fecf70f955dc9f29f94c055b183aeec jdk7-b30
 07c916ecfc71f6bf432e4ff09bfbfb6290b5703c jdk7-b31
 13aee98cc0d8e24a084b62ad1d48d2a49792416c jdk7-b32
+0a5f04fb72825302a80a67c636a7ddc410ead266 jdk7-b33
--- a/langtools/src/share/classes/com/sun/tools/apt/util/Bark.java	Wed Jul 05 16:39:59 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/apt/util/Bark.java	Wed Jul 05 16:40:31 2017 +0200
@@ -87,7 +87,7 @@
         context.put(barkKey, this);
 
         // register additional resource bundle for APT messages.
-        Messages aptMessages = new Messages(Messages.getDefaultBundle());
+        Messages aptMessages = Messages.instance(context);
         aptMessages.add("com.sun.tools.apt.resources.apt");
         aptDiags = new JCDiagnostic.Factory(aptMessages, "apt");
 
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java	Wed Jul 05 16:39:59 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java	Wed Jul 05 16:40:31 2017 +0200
@@ -923,14 +923,7 @@
                 public Object call() {
                     JavaFileObject source = log.useSource(env.toplevel.sourcefile);
                     try {
-                        // In order to catch self-references, we set
-                        // the variable's declaration position to
-                        // maximal possible value, effectively marking
-                        // the variable as undefined.
-                        int pos = VarSymbol.this.pos;
-                        VarSymbol.this.pos = Position.MAXPOS;
                         Type itype = attr.attribExpr(initializer, env, type);
-                        VarSymbol.this.pos = pos;
                         if (itype.constValue() != null)
                             return attr.coerce(itype, type).constValue();
                         else
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Symtab.java	Wed Jul 05 16:39:59 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Symtab.java	Wed Jul 05 16:40:31 2017 +0200
@@ -75,6 +75,7 @@
 
     private final Name.Table names;
     private final ClassReader reader;
+    private final Target target;
 
     /** A symbol for the root package.
      */
@@ -144,6 +145,7 @@
     public final Type suppressWarningsType;
     public final Type inheritedType;
     public final Type proprietaryType;
+    public final Type systemType;
 
     /** The symbol representing the length field of an array.
      */
@@ -272,6 +274,55 @@
         return reader.enterClass(names.fromString(s)).type;
     }
 
+    public void synthesizeEmptyInterfaceIfMissing(final Type type) {
+        final Completer completer = type.tsym.completer;
+        if (completer != null) {
+            type.tsym.completer = new Completer() {
+                public void complete(Symbol sym) throws CompletionFailure {
+                    try {
+                        completer.complete(sym);
+                    } catch (CompletionFailure e) {
+                        sym.flags_field |= (PUBLIC | INTERFACE);
+                        ((ClassType) sym.type).supertype_field = objectType;
+                    }
+                }
+            };
+        }
+    }
+
+    public void synthesizeBoxTypeIfMissing(final Type type) {
+        ClassSymbol sym = reader.enterClass(boxedName[type.tag]);
+        final Completer completer = sym.completer;
+        if (completer != null) {
+            sym.completer = new Completer() {
+                public void complete(Symbol sym) throws CompletionFailure {
+                    try {
+                        completer.complete(sym);
+                    } catch (CompletionFailure e) {
+                        sym.flags_field |= PUBLIC;
+                        ((ClassType) sym.type).supertype_field = objectType;
+                        Name n = target.boxWithConstructors() ? names.init : names.valueOf;
+                        MethodSymbol boxMethod =
+                            new MethodSymbol(PUBLIC | STATIC,
+                                n,
+                                new MethodType(List.of(type), sym.type,
+                                    List.<Type>nil(), methodClass),
+                                sym);
+                        sym.members().enter(boxMethod);
+                        MethodSymbol unboxMethod =
+                            new MethodSymbol(PUBLIC,
+                                type.tsym.name.append(names.Value), // x.intValue()
+                                new MethodType(List.<Type>nil(), type,
+                                    List.<Type>nil(), methodClass),
+                                sym);
+                        sym.members().enter(unboxMethod);
+                    }
+                }
+            };
+        }
+
+    }
+
     /** Constructor; enters all predefined identifiers and operators
      *  into symbol table.
      */
@@ -279,6 +330,7 @@
         context.put(symtabKey, this);
 
         names = Name.Table.instance(context);
+        target = Target.instance(context);
 
         // Create the unknown type
         unknownType = new Type(TypeTags.UNKNOWN, null);
@@ -373,7 +425,7 @@
         collectionsType = enterClass("java.util.Collections");
         comparableType = enterClass("java.lang.Comparable");
         arraysType = enterClass("java.util.Arrays");
-        iterableType = Target.instance(context).hasIterable()
+        iterableType = target.hasIterable()
             ? enterClass("java.lang.Iterable")
             : enterClass("java.util.Collection");
         iteratorType = enterClass("java.util.Iterator");
@@ -383,6 +435,12 @@
         deprecatedType = enterClass("java.lang.Deprecated");
         suppressWarningsType = enterClass("java.lang.SuppressWarnings");
         inheritedType = enterClass("java.lang.annotation.Inherited");
+        systemType = enterClass("java.lang.System");
+
+        synthesizeEmptyInterfaceIfMissing(cloneableType);
+        synthesizeEmptyInterfaceIfMissing(serializableType);
+        synthesizeBoxTypeIfMissing(doubleType);
+        synthesizeBoxTypeIfMissing(floatType);
 
         // Enter a synthetic class that is used to mark Sun
         // proprietary classes in ct.sym.  This class does not have a
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Types.java	Wed Jul 05 16:39:59 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Types.java	Wed Jul 05 16:40:31 2017 +0200
@@ -305,6 +305,11 @@
         else if (t.tag == TYPEVAR) {
             return isSubtypeUnchecked(t.getUpperBound(), s, warn);
         }
+        else if (s.tag == UNDETVAR) {
+            UndetVar uv = (UndetVar)s;
+            if (uv.inst != null)
+                return isSubtypeUnchecked(t, uv.inst, warn);
+        }
         else if (!s.isRaw()) {
             Type t2 = asSuper(t, s.tsym);
             if (t2 != null && t2.isRaw()) {
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java	Wed Jul 05 16:39:59 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java	Wed Jul 05 16:40:31 2017 +0200
@@ -79,6 +79,7 @@
     final Enter enter;
     final Target target;
     final Types types;
+    final JCDiagnostic.Factory diags;
     final Annotate annotate;
 
     public static Attr instance(Context context) {
@@ -102,6 +103,7 @@
         cfolder = ConstFold.instance(context);
         target = Target.instance(context);
         types = Types.instance(context);
+        diags = JCDiagnostic.Factory.instance(context);
         annotate = Annotate.instance(context);
 
         Options options = Options.instance(context);
@@ -728,9 +730,8 @@
                     // In order to catch self-references, we set the variable's
                     // declaration position to maximal possible value, effectively
                     // marking the variable as undefined.
-                    v.pos = Position.MAXPOS;
+                    initEnv.info.enclVar = v;
                     attribExpr(tree.init, initEnv, v.type);
-                    v.pos = tree.pos;
                 }
             }
             result = tree.type = v.type;
@@ -2196,18 +2197,19 @@
             // This check applies only to class and instance
             // variables.  Local variables follow different scope rules,
             // and are subject to definite assignment checking.
-            if (v.pos > tree.pos &&
+            if ((env.info.enclVar == v || v.pos > tree.pos) &&
                 v.owner.kind == TYP &&
                 canOwnInitializer(env.info.scope.owner) &&
                 v.owner == env.info.scope.owner.enclClass() &&
                 ((v.flags() & STATIC) != 0) == Resolve.isStatic(env) &&
                 (env.tree.getTag() != JCTree.ASSIGN ||
                  TreeInfo.skipParens(((JCAssign) env.tree).lhs) != tree)) {
-
+                String suffix = (env.info.enclVar == v) ?
+                                "self.ref" : "forward.ref";
                 if (!onlyWarning || isStaticEnumField(v)) {
-                    log.error(tree.pos(), "illegal.forward.ref");
+                    log.error(tree.pos(), "illegal." + suffix);
                 } else if (useBeforeDeclarationWarning) {
-                    log.warning(tree.pos(), "forward.ref", v);
+                    log.warning(tree.pos(), suffix, v);
                 }
             }
 
@@ -2419,7 +2421,7 @@
 
         if (false) {
             // TODO: make assertConvertible work
-            chk.typeError(tree.pos(), JCDiagnostic.fragment("incompatible.types"), actual, formal);
+            chk.typeError(tree.pos(), diags.fragment("incompatible.types"), actual, formal);
             throw new AssertionError("Tree: " + tree
                                      + " actual:" + actual
                                      + " formal: " + formal);
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/AttrContext.java	Wed Jul 05 16:39:59 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/AttrContext.java	Wed Jul 05 16:40:31 2017 +0200
@@ -66,6 +66,11 @@
      */
     Lint lint;
 
+    /** The variable whose initializer is being attributed
+     * useful for detecting self-references in variable initializers
+     */
+    Symbol enclVar = null;
+
     /** Duplicate this context, replacing scope field and copying all others.
      */
     AttrContext dup(Scope scope) {
@@ -77,6 +82,7 @@
         info.varArgs = varArgs;
         info.tvars = tvars;
         info.lint = lint;
+        info.enclVar = enclVar;
         return info;
     }
 
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java	Wed Jul 05 16:39:59 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java	Wed Jul 05 16:40:31 2017 +0200
@@ -63,6 +63,7 @@
     private final Target target;
     private final Source source;
     private final Types types;
+    private final JCDiagnostic.Factory diags;
     private final boolean skipAnnotations;
     private final TreeInfo treeinfo;
 
@@ -86,6 +87,7 @@
         syms = Symtab.instance(context);
         infer = Infer.instance(context);
         this.types = Types.instance(context);
+        diags = JCDiagnostic.Factory.instance(context);
         Options options = Options.instance(context);
         target = Target.instance(context);
         source = Source.instance(context);
@@ -343,7 +345,7 @@
         if (types.isAssignable(found, req, convertWarner(pos, found, req)))
             return found;
         if (found.tag <= DOUBLE && req.tag <= DOUBLE)
-            return typeError(pos, JCDiagnostic.fragment("possible.loss.of.precision"), found, req);
+            return typeError(pos, diags.fragment("possible.loss.of.precision"), found, req);
         if (found.isSuperBound()) {
             log.error(pos, "assignment.from.super-bound", found);
             return syms.errType;
@@ -352,7 +354,7 @@
             log.error(pos, "assignment.to.extends-bound", req);
             return syms.errType;
         }
-        return typeError(pos, JCDiagnostic.fragment("incompatible.types"), found, req);
+        return typeError(pos, diags.fragment("incompatible.types"), found, req);
     }
 
     /** Instantiate polymorphic type to some prototype, unless
@@ -380,7 +382,7 @@
                 } else {
                     JCDiagnostic d = ex.getDiagnostic();
                     return typeError(pos,
-                                     JCDiagnostic.fragment("incompatible.types" + (d!=null ? ".1" : ""), d),
+                                     diags.fragment("incompatible.types" + (d!=null ? ".1" : ""), d),
                                      t, pt);
                 }
             }
@@ -401,7 +403,7 @@
             return req;
         } else {
             return typeError(pos,
-                             JCDiagnostic.fragment("inconvertible.types"),
+                             diags.fragment("inconvertible.types"),
                              found, req);
         }
     }
@@ -480,9 +482,9 @@
     Type checkClassType(DiagnosticPosition pos, Type t) {
         if (t.tag != CLASS && t.tag != ERROR)
             return typeTagError(pos,
-                                JCDiagnostic.fragment("type.req.class"),
+                                diags.fragment("type.req.class"),
                                 (t.tag == TYPEVAR)
-                                ? JCDiagnostic.fragment("type.parameter", t)
+                                ? diags.fragment("type.parameter", t)
                                 : t);
         else
             return t;
@@ -515,7 +517,7 @@
     Type checkReifiableReferenceType(DiagnosticPosition pos, Type t) {
         if (t.tag != CLASS && t.tag != ARRAY && t.tag != ERROR) {
             return typeTagError(pos,
-                                JCDiagnostic.fragment("type.req.class.array"),
+                                diags.fragment("type.req.class.array"),
                                 t);
         } else if (!types.isReifiable(t)) {
             log.error(pos, "illegal.generic.type.for.instof");
@@ -540,7 +542,7 @@
             return t;
         default:
             return typeTagError(pos,
-                                JCDiagnostic.fragment("type.req.ref"),
+                                diags.fragment("type.req.ref"),
                                 t);
         }
     }
@@ -560,7 +562,7 @@
             return t;
         default:
             return typeTagError(pos,
-                                JCDiagnostic.fragment("type.req.ref"),
+                                diags.fragment("type.req.ref"),
                                 t);
         }
     }
@@ -1028,7 +1030,7 @@
      *  @param other  The overridden method.
      *  @return       An internationalized string.
      */
-    static Object cannotOverride(MethodSymbol m, MethodSymbol other) {
+    Object cannotOverride(MethodSymbol m, MethodSymbol other) {
         String key;
         if ((other.owner.flags() & INTERFACE) == 0)
             key = "cant.override";
@@ -1036,7 +1038,7 @@
             key = "cant.implement";
         else
             key = "clashes.with";
-        return JCDiagnostic.fragment(key, m, m.location(), other, other.location());
+        return diags.fragment(key, m, m.location(), other, other.location());
     }
 
     /** A customized "override" warning message.
@@ -1044,7 +1046,7 @@
      *  @param other  The overridden method.
      *  @return       An internationalized string.
      */
-    static Object uncheckedOverrides(MethodSymbol m, MethodSymbol other) {
+    Object uncheckedOverrides(MethodSymbol m, MethodSymbol other) {
         String key;
         if ((other.owner.flags() & INTERFACE) == 0)
             key = "unchecked.override";
@@ -1052,7 +1054,7 @@
             key = "unchecked.implement";
         else
             key = "unchecked.clash.with";
-        return JCDiagnostic.fragment(key, m, m.location(), other, other.location());
+        return diags.fragment(key, m, m.location(), other, other.location());
     }
 
     /** A customized "override" warning message.
@@ -1060,7 +1062,7 @@
      *  @param other  The overridden method.
      *  @return       An internationalized string.
      */
-    static Object varargsOverrides(MethodSymbol m, MethodSymbol other) {
+    Object varargsOverrides(MethodSymbol m, MethodSymbol other) {
         String key;
         if ((other.owner.flags() & INTERFACE) == 0)
             key = "varargs.override";
@@ -1068,7 +1070,7 @@
             key = "varargs.implement";
         else
             key = "varargs.clash.with";
-        return JCDiagnostic.fragment(key, m, m.location(), other, other.location());
+        return diags.fragment(key, m, m.location(), other, other.location());
     }
 
     /** Check that this method conforms with overridden method 'other'.
@@ -1157,7 +1159,7 @@
                 // allow limited interoperability with covariant returns
             } else {
                 typeError(TreeInfo.diagnosticPositionFor(m, tree),
-                          JCDiagnostic.fragment("override.incompatible.ret",
+                          diags.fragment("override.incompatible.ret",
                                          cannotOverride(m, other)),
                           mtres, otres);
                 return;
@@ -1165,7 +1167,7 @@
         } else if (overrideWarner.warned) {
             warnUnchecked(TreeInfo.diagnosticPositionFor(m, tree),
                           "prob.found.req",
-                          JCDiagnostic.fragment("override.unchecked.ret",
+                          diags.fragment("override.unchecked.ret",
                                               uncheckedOverrides(m, other)),
                           mtres, otres);
         }
@@ -2170,7 +2172,7 @@
             boolean warned = this.warned;
             super.warnUnchecked();
             if (warned) return; // suppress redundant diagnostics
-            Object problem = JCDiagnostic.fragment(key);
+            Object problem = diags.fragment(key);
             Check.this.warnUnchecked(pos(), "prob.found.req", problem, found, expected);
         }
     }
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java	Wed Jul 05 16:39:59 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java	Wed Jul 05 16:40:31 2017 +0200
@@ -29,6 +29,7 @@
 import com.sun.tools.javac.util.List;
 import com.sun.tools.javac.code.*;
 import com.sun.tools.javac.code.Type.*;
+import com.sun.tools.javac.util.JCDiagnostic;
 
 import static com.sun.tools.javac.code.Flags.*;
 import static com.sun.tools.javac.code.Kinds.*;
@@ -50,6 +51,7 @@
 
     Symtab syms;
     Types types;
+    JCDiagnostic.Factory diags;
 
     public static Infer instance(Context context) {
         Infer instance = context.get(inferKey);
@@ -62,6 +64,11 @@
         context.put(inferKey, this);
         syms = Symtab.instance(context);
         types = Types.instance(context);
+        diags = JCDiagnostic.Factory.instance(context);
+        ambiguousNoInstanceException =
+            new NoInstanceException(true, diags);
+        unambiguousNoInstanceException =
+            new NoInstanceException(false, diags);
     }
 
     public static class NoInstanceException extends RuntimeException {
@@ -70,35 +77,35 @@
         boolean isAmbiguous; // exist several incomparable best instances?
 
         JCDiagnostic diagnostic;
+        JCDiagnostic.Factory diags;
 
-        NoInstanceException(boolean isAmbiguous) {
+        NoInstanceException(boolean isAmbiguous, JCDiagnostic.Factory diags) {
             this.diagnostic = null;
             this.isAmbiguous = isAmbiguous;
+            this.diags = diags;
         }
         NoInstanceException setMessage(String key) {
-            this.diagnostic = JCDiagnostic.fragment(key);
+            this.diagnostic = diags.fragment(key);
             return this;
         }
         NoInstanceException setMessage(String key, Object arg1) {
-            this.diagnostic = JCDiagnostic.fragment(key, arg1);
+            this.diagnostic = diags.fragment(key, arg1);
             return this;
         }
         NoInstanceException setMessage(String key, Object arg1, Object arg2) {
-            this.diagnostic = JCDiagnostic.fragment(key, arg1, arg2);
+            this.diagnostic = diags.fragment(key, arg1, arg2);
             return this;
         }
         NoInstanceException setMessage(String key, Object arg1, Object arg2, Object arg3) {
-            this.diagnostic = JCDiagnostic.fragment(key, arg1, arg2, arg3);
+            this.diagnostic = diags.fragment(key, arg1, arg2, arg3);
             return this;
         }
         public JCDiagnostic getDiagnostic() {
             return diagnostic;
         }
     }
-    private final NoInstanceException ambiguousNoInstanceException =
-        new NoInstanceException(true);
-    private final NoInstanceException unambiguousNoInstanceException =
-        new NoInstanceException(false);
+    private final NoInstanceException ambiguousNoInstanceException;
+    private final NoInstanceException unambiguousNoInstanceException;
 
 /***************************************************************************
  * Auxiliary type values and classes
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Lower.java	Wed Jul 05 16:39:59 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Lower.java	Wed Jul 05 16:40:31 2017 +0200
@@ -2110,16 +2110,64 @@
 
         Symbol valuesSym = lookupMethod(tree.pos(), names.values,
                                         tree.type, List.<Type>nil());
-        JCTypeCast valuesResult =
-            make.TypeCast(valuesSym.type.getReturnType(),
-                          make.App(make.Select(make.Ident(valuesVar),
-                                               syms.arrayCloneMethod)));
+        List<JCStatement> valuesBody;
+        if (useClone()) {
+            // return (T[]) $VALUES.clone();
+            JCTypeCast valuesResult =
+                make.TypeCast(valuesSym.type.getReturnType(),
+                              make.App(make.Select(make.Ident(valuesVar),
+                                                   syms.arrayCloneMethod)));
+            valuesBody = List.<JCStatement>of(make.Return(valuesResult));
+        } else {
+            // template: T[] $result = new T[$values.length];
+            Name resultName = names.fromString(target.syntheticNameChar() + "result");
+            while (tree.sym.members().lookup(resultName).scope != null) // avoid name clash
+                resultName = names.fromString(resultName + "" + target.syntheticNameChar());
+            VarSymbol resultVar = new VarSymbol(FINAL|SYNTHETIC,
+                                                resultName,
+                                                arrayType,
+                                                valuesSym);
+            JCNewArray resultArray = make.NewArray(make.Type(types.erasure(tree.type)),
+                                  List.of(make.Select(make.Ident(valuesVar), syms.lengthVar)),
+                                  null);
+            resultArray.type = arrayType;
+            JCVariableDecl decl = make.VarDef(resultVar, resultArray);
+
+            // template: System.arraycopy($VALUES, 0, $result, 0, $VALUES.length);
+            if (systemArraycopyMethod == null) {
+                systemArraycopyMethod =
+                    new MethodSymbol(PUBLIC | STATIC,
+                                     names.fromString("arraycopy"),
+                                     new MethodType(List.<Type>of(syms.objectType,
+                                                            syms.intType,
+                                                            syms.objectType,
+                                                            syms.intType,
+                                                            syms.intType),
+                                                    syms.voidType,
+                                                    List.<Type>nil(),
+                                                    syms.methodClass),
+                                     syms.systemType.tsym);
+            }
+            JCStatement copy =
+                make.Exec(make.App(make.Select(make.Ident(syms.systemType.tsym),
+                                               systemArraycopyMethod),
+                          List.of(make.Ident(valuesVar), make.Literal(0),
+                                  make.Ident(resultVar), make.Literal(0),
+                                  make.Select(make.Ident(valuesVar), syms.lengthVar))));
+
+            // template: return $result;
+            JCStatement ret = make.Return(make.Ident(resultVar));
+            valuesBody = List.<JCStatement>of(decl, copy, ret);
+        }
+
         JCMethodDecl valuesDef =
-            make.MethodDef((MethodSymbol)valuesSym,
-                           make.Block(0, List.<JCStatement>nil()
-                                      .prepend(make.Return(valuesResult))));
+             make.MethodDef((MethodSymbol)valuesSym, make.Block(0, valuesBody));
+
         enumDefs.append(valuesDef);
 
+        if (debugLower)
+            System.err.println(tree.sym + ".valuesDef = " + valuesDef);
+
         /** The template for the following code is:
          *
          *     public static E valueOf(String name) {
@@ -2155,6 +2203,17 @@
             addEnumCompatibleMembers(tree);
         }
     }
+        // where
+        private MethodSymbol systemArraycopyMethod;
+        private boolean useClone() {
+            try {
+                Scope.Entry e = syms.objectType.tsym.members().lookup(names.clone);
+                return (e.sym != null);
+            }
+            catch (CompletionFailure e) {
+                return false;
+            }
+        }
 
     /** Translate an enumeration constant and its initializer. */
     private void visitEnumConstantDef(JCVariableDecl var, int ordinal) {
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/MemberEnter.java	Wed Jul 05 16:39:59 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/MemberEnter.java	Wed Jul 05 16:40:31 2017 +0200
@@ -72,6 +72,7 @@
     private final Todo todo;
     private final Annotate annotate;
     private final Types types;
+    private final JCDiagnostic.Factory diags;
     private final Target target;
 
     private final boolean skipAnnotations;
@@ -96,6 +97,7 @@
         todo = Todo.instance(context);
         annotate = Annotate.instance(context);
         types = Types.instance(context);
+        diags = JCDiagnostic.Factory.instance(context);
         target = Target.instance(context);
         skipAnnotations =
             Options.instance(context).get("skipAnnotations") != null;
@@ -133,7 +135,7 @@
         if (tsym.kind == PCK && tsym.members().elems == null && !tsym.exists()) {
             // If we can't find java.lang, exit immediately.
             if (((PackageSymbol)tsym).fullname.equals(names.java_lang)) {
-                JCDiagnostic msg = JCDiagnostic.fragment("fatal.err.no.java.lang");
+                JCDiagnostic msg = diags.fragment("fatal.err.no.java.lang");
                 throw new FatalError(msg);
             } else {
                 log.error(pos, "doesnt.exist", tsym);
@@ -319,7 +321,7 @@
                         log.error(pos, "cant.resolve.location",
                                   KindName.STATIC,
                                   name, List.<Type>nil(), List.<Type>nil(),
-                                  typeKindName(tsym.type),
+                                  Kinds.typeKindName(tsym.type),
                                   tsym.type);
                     }
                 } finally {
@@ -625,8 +627,11 @@
         tree.sym = v;
         if (tree.init != null) {
             v.flags_field |= HASINIT;
-            if ((v.flags_field & FINAL) != 0 && tree.init.getTag() != JCTree.NEWCLASS)
-                v.setLazyConstValue(initEnv(tree, env), log, attr, tree.init);
+            if ((v.flags_field & FINAL) != 0 && tree.init.getTag() != JCTree.NEWCLASS) {
+                Env<AttrContext> initEnv = getInitEnv(tree, env);
+                initEnv.info.enclVar = v;
+                v.setLazyConstValue(initEnv(tree, initEnv), log, attr, tree.init);
+            }
         }
         if (chk.checkUnique(tree.pos(), v, enclScope)) {
             chk.checkTransparentVar(tree.pos(), v, enclScope);
@@ -826,6 +831,9 @@
             // Save class environment for later member enter (2) processing.
             halfcompleted.append(env);
 
+            // Mark class as not yet attributed.
+            c.flags_field |= UNATTRIBUTED;
+
             // If this is a toplevel-class, make sure any preceding import
             // clauses have been seen.
             if (c.owner.kind == PCK) {
@@ -833,9 +841,6 @@
                 todo.append(env);
             }
 
-            // Mark class as not yet attributed.
-            c.flags_field |= UNATTRIBUTED;
-
             if (c.owner.kind == TYP)
                 c.owner.complete();
 
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java	Wed Jul 05 16:39:59 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java	Wed Jul 05 16:40:31 2017 +0200
@@ -59,6 +59,7 @@
     ClassReader reader;
     TreeInfo treeinfo;
     Types types;
+    JCDiagnostic.Factory diags;
     public final boolean boxingEnabled; // = source.allowBoxing();
     public final boolean varargsEnabled; // = source.allowVarargs();
     private final boolean debugResolve;
@@ -92,6 +93,7 @@
         reader = ClassReader.instance(context);
         treeinfo = TreeInfo.instance(context);
         types = Types.instance(context);
+        diags = JCDiagnostic.Factory.instance(context);
         Source source = Source.instance(context);
         boxingEnabled = source.allowBoxing();
         varargsEnabled = source.allowVarargs();
@@ -449,7 +451,7 @@
         Symbol sym = findField(env, site, name, site.tsym);
         if (sym.kind == VAR) return (VarSymbol)sym;
         else throw new FatalError(
-                 JCDiagnostic.fragment("fatal.err.cant.locate.field",
+                 diags.fragment("fatal.err.cant.locate.field",
                                 name));
     }
 
@@ -1248,7 +1250,7 @@
             pos, env, site, name, argtypes, typeargtypes);
         if (sym.kind == MTH) return (MethodSymbol)sym;
         else throw new FatalError(
-                 JCDiagnostic.fragment("fatal.err.cant.locate.meth",
+                 diags.fragment("fatal.err.cant.locate.meth",
                                 name));
     }
 
@@ -1320,7 +1322,7 @@
             pos, env, site, argtypes, typeargtypes);
         if (sym.kind == MTH) return (MethodSymbol)sym;
         else throw new FatalError(
-                 JCDiagnostic.fragment("fatal.err.cant.locate.ctor", site));
+                 diags.fragment("fatal.err.cant.locate.ctor", site));
     }
 
     /** Resolve operator.
--- a/langtools/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java	Wed Jul 05 16:39:59 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java	Wed Jul 05 16:40:31 2017 +0200
@@ -27,6 +27,7 @@
 
 import java.io.*;
 import java.util.HashSet;
+import java.util.LinkedHashSet;
 import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.MissingResourceException;
@@ -1185,14 +1186,16 @@
          * are processed through attribute and flow before subtypes are translated.
          */
         class ScanNested extends TreeScanner {
-            Set<Env<AttrContext>> dependencies = new HashSet<Env<AttrContext>>();
+            Set<Env<AttrContext>> dependencies = new LinkedHashSet<Env<AttrContext>>();
             public void visitClassDef(JCClassDecl node) {
                 Type st = types.supertype(node.sym.type);
                 if (st.tag == TypeTags.CLASS) {
                     ClassSymbol c = st.tsym.outermostClass();
                     Env<AttrContext> stEnv = enter.getEnv(c);
-                    if (stEnv != null && env != stEnv)
-                        dependencies.add(stEnv);
+                    if (stEnv != null && env != stEnv) {
+                        if (dependencies.add(stEnv))
+                            scan(stEnv.tree);
+                    }
                 }
                 super.visitClassDef(node);
             }
@@ -1204,6 +1207,11 @@
                 flow(attribute(dep));
         }
 
+        //We need to check for error another time as more classes might
+        //have been attributed and analyzed at this stage
+        if (errorCount() > 0)
+            return;
+
         if (verboseCompilePolicy)
             log.printLines(log.noticeWriter, "[desugar " + env.enclClass.sym + "]");
 
--- a/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties	Wed Jul 05 16:39:59 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties	Wed Jul 05 16:40:31 2017 +0200
@@ -200,6 +200,10 @@
     illegal forward reference
 compiler.warn.forward.ref=\
     reference to variable ''{0}'' before it has been initialized
+compiler.err.illegal.self.ref=\
+    self-reference in initializer
+compiler.warn.self.ref=\
+    self-reference in initializer of variable ''{0}''
 compiler.err.illegal.generic.type.for.instof=\
     illegal generic type for instanceof
 compiler.err.illegal.initializer.for.type=\
--- a/langtools/src/share/classes/com/sun/tools/javac/util/JCDiagnostic.java	Wed Jul 05 16:39:59 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/javac/util/JCDiagnostic.java	Wed Jul 05 16:40:31 2017 +0200
@@ -59,20 +59,19 @@
             return instance;
         }
 
-        final Messages messages;
+        DiagnosticFormatter<JCDiagnostic> formatter;
         final String prefix;
 
         /** Create a new diagnostic factory. */
         protected Factory(Context context) {
+            this(Messages.instance(context), "compiler");
             context.put(diagnosticFactoryKey, this);
-            messages = Messages.instance(context);
-            prefix = "compiler";
         }
 
         /** Create a new diagnostic factory. */
         public Factory(Messages messages, String prefix) {
-            this.messages = messages;
             this.prefix = prefix;
+            this.formatter = new BasicDiagnosticFormatter(messages);
         }
 
         /**
@@ -84,7 +83,7 @@
          */
         public JCDiagnostic error(
                 DiagnosticSource source, DiagnosticPosition pos, String key, Object... args) {
-            return new JCDiagnostic(messages, ERROR, true, source, pos, qualify(ERROR, key), args);
+            return new JCDiagnostic(formatter, ERROR, true, source, pos, qualify(ERROR, key), args);
         }
 
         /**
@@ -97,7 +96,7 @@
          */
         public JCDiagnostic mandatoryWarning(
                  DiagnosticSource source, DiagnosticPosition pos, String key, Object... args) {
-            return new JCDiagnostic(messages, WARNING, true, source, pos, qualify(WARNING, key), args);
+            return new JCDiagnostic(formatter, WARNING, true, source, pos, qualify(WARNING, key), args);
         }
 
         /**
@@ -109,7 +108,7 @@
          */
         public JCDiagnostic warning(
                 DiagnosticSource source, DiagnosticPosition pos, String key, Object... args) {
-            return new JCDiagnostic(messages, WARNING, false, source, pos, qualify(WARNING, key), args);
+            return new JCDiagnostic(formatter, WARNING, false, source, pos, qualify(WARNING, key), args);
         }
 
         /**
@@ -119,7 +118,7 @@
          *  @see MandatoryWarningHandler
          */
         public JCDiagnostic mandatoryNote(DiagnosticSource source, String key, Object... args) {
-            return new JCDiagnostic(messages, NOTE, true, source, null, qualify(NOTE, key), args);
+            return new JCDiagnostic(formatter, NOTE, true, source, null, qualify(NOTE, key), args);
         }
 
         /**
@@ -140,7 +139,7 @@
          */
         public JCDiagnostic note(
                 DiagnosticSource source, DiagnosticPosition pos, String key, Object... args) {
-            return new JCDiagnostic(messages, NOTE, false, source, pos, qualify(NOTE, key), args);
+            return new JCDiagnostic(formatter, NOTE, false, source, pos, qualify(NOTE, key), args);
         }
 
         /**
@@ -149,7 +148,7 @@
          *  @param args   Fields of the error message.
          */
         public JCDiagnostic fragment(String key, Object... args) {
-            return new JCDiagnostic(messages, FRAGMENT, false, null, null, qualify(FRAGMENT, key), args);
+            return new JCDiagnostic(formatter, FRAGMENT, false, null, null, qualify(FRAGMENT, key), args);
         }
 
         protected String qualify(DiagnosticType t, String key) {
@@ -163,10 +162,11 @@
      * Create a fragment diagnostic, for use as an argument in other diagnostics
      *  @param key    The key for the localized error message.
      *  @param args   Fields of the error message.
+     *
      */
-    // should be deprecated
+    @Deprecated
     public static JCDiagnostic fragment(String key, Object... args) {
-        return new JCDiagnostic(Messages.getDefaultMessages(),
+        return new JCDiagnostic(getFragmentFormatter(),
                               FRAGMENT,
                               false,
                               null,
@@ -174,6 +174,14 @@
                               "compiler." + FRAGMENT.key + "." + key,
                               args);
     }
+    //where
+    @Deprecated
+    public static DiagnosticFormatter<JCDiagnostic> getFragmentFormatter() {
+        if (fragmentFormatter == null) {
+            fragmentFormatter = new BasicDiagnosticFormatter(Messages.getDefaultMessages());
+        }
+        return fragmentFormatter;
+    }
 
     /**
      * A DiagnosticType defines the type of the diagnostic.
@@ -247,7 +255,6 @@
         private final int pos;
     }
 
-    private final Messages messages;
     private final DiagnosticType type;
     private final DiagnosticSource source;
     private final DiagnosticPosition position;
@@ -266,7 +273,7 @@
      * @param key a resource key to identify the text of the diagnostic
      * @param args arguments to be included in the text of the diagnostic
      */
-    protected JCDiagnostic(Messages messages,
+    protected JCDiagnostic(DiagnosticFormatter<JCDiagnostic> formatter,
                        DiagnosticType dt,
                        boolean mandatory,
                        DiagnosticSource source,
@@ -276,7 +283,7 @@
         if (source == null && pos != null && pos.getPreferredPosition() != Position.NOPOS)
             throw new IllegalArgumentException();
 
-        this.messages = messages;
+        this.defaultFormatter = formatter;
         this.type = dt;
         this.mandatory = mandatory;
         this.source = source;
@@ -398,25 +405,19 @@
      * @return the prefix string associated with a particular type of diagnostic
      */
     public String getPrefix(DiagnosticType dt) {
-        return getFormatter().formatKind(this, Locale.getDefault());
+        return defaultFormatter.formatKind(this, Locale.getDefault());
     }
 
-     private DiagnosticFormatter<JCDiagnostic> getFormatter() {
-        if (defaultFormatter == null) {
-            defaultFormatter = new BasicDiagnosticFormatter(messages);
-        }
-        return defaultFormatter;
-    }
-
-
     /**
      * Return the standard presentation of this diagnostic.
      */
     public String toString() {
-        return getFormatter().format(this,Locale.getDefault());
+        return defaultFormatter.format(this,Locale.getDefault());
     }
 
-    private static DiagnosticFormatter<JCDiagnostic> defaultFormatter;
+    private DiagnosticFormatter<JCDiagnostic> defaultFormatter;
+    @Deprecated
+    private static DiagnosticFormatter<JCDiagnostic> fragmentFormatter;
 
     // Methods for javax.tools.Diagnostic
 
@@ -440,6 +441,6 @@
 
     public String getMessage(Locale locale) {
         // RFE 6406133: JCDiagnostic.getMessage ignores locale argument
-        return getFormatter().formatMessage(this, locale);
+        return defaultFormatter.formatMessage(this, locale);
     }
 }
--- a/langtools/src/share/classes/com/sun/tools/javap/ClassWriter.java	Wed Jul 05 16:39:59 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/javap/ClassWriter.java	Wed Jul 05 16:40:31 2017 +0200
@@ -25,6 +25,7 @@
 
 package com.sun.tools.javap;
 
+import java.net.URI;
 import java.util.Collection;
 import java.util.List;
 
@@ -35,6 +36,7 @@
 import com.sun.tools.classfile.Code_attribute;
 import com.sun.tools.classfile.ConstantPool;
 import com.sun.tools.classfile.ConstantPoolException;
+import com.sun.tools.classfile.ConstantValue_attribute;
 import com.sun.tools.classfile.Descriptor;
 import com.sun.tools.classfile.DescriptorException;
 import com.sun.tools.classfile.Exceptions_attribute;
@@ -45,6 +47,8 @@
 import com.sun.tools.classfile.SourceFile_attribute;
 import com.sun.tools.classfile.Type;
 
+import java.text.DateFormat;
+import java.util.Date;
 import static com.sun.tools.classfile.AccessFlags.*;
 
 /*
@@ -72,6 +76,23 @@
         constantWriter = ConstantWriter.instance(context);
     }
 
+    void setDigest(String name, byte[] digest) {
+        this.digestName = name;
+        this.digest = digest;
+    }
+
+    void setFile(URI uri) {
+        this.uri = uri;
+    }
+
+    void setFileSize(int size) {
+        this.size = size;
+    }
+
+    void setLastModified(long lastModified) {
+        this.lastModified = lastModified;
+    }
+
     ClassFile getClassFile() {
         return classFile;
     }
@@ -84,6 +105,32 @@
         classFile = cf;
         constant_pool = classFile.constant_pool;
 
+        if ((options.sysInfo || options.verbose) && !options.compat) {
+            if (uri != null) {
+                if (uri.getScheme().equals("file"))
+                    println("Classfile " + uri.getPath());
+                else
+                    println("Classfile " + uri);
+            }
+            if (lastModified != -1) {
+                Date lm = new Date(lastModified);
+                DateFormat df = DateFormat.getDateInstance();
+                if (size > 0) {
+                    println("Last modified " + df.format(lm) + "; size " + size + " bytes");
+                } else {
+                    println("Last modified " + df.format(lm));
+                }
+            } else if (size > 0) {
+                println("Size " + size + " bytes");
+            }
+            if (digestName != null && digest != null) {
+                StringBuilder sb = new StringBuilder();
+                for (byte b: digest)
+                    sb.append(String.format("%02x", b));
+                println(digestName + " checksum " + sb);
+            }
+        }
+
         Attribute sfa = cf.getAttribute(Attribute.SourceFile);
         if (sfa instanceof SourceFile_attribute) {
             println("Compiled from \"" + getSourceFile((SourceFile_attribute) sfa) + "\"");
@@ -185,6 +232,14 @@
         }
         print(" ");
         print(getFieldName(f));
+        if (options.showConstants && !options.compat) { // BUG 4111861 print static final field contents
+            Attribute a = f.attributes.get(Attribute.ConstantValue);
+            if (a instanceof ConstantValue_attribute) {
+                print(" = ");
+                ConstantValue_attribute cv = (ConstantValue_attribute) a;
+                print(getConstantValue(f.descriptor, cv.constantvalue_index));
+            }
+        }
         print(";");
         println();
 
@@ -481,11 +536,91 @@
         }
     }
 
+    /**
+     * Get the value of an entry in the constant pool as a Java constant.
+     * Characters and booleans are represented by CONSTANT_Intgere entries.
+     * Character and string values are processed to escape characters outside
+     * the basic printable ASCII set.
+     * @param d the descriptor, giving the expected type of the constant
+     * @param index the index of the value in the constant pool
+     * @return a printable string containing the value of the constant.
+     */
+    String getConstantValue(Descriptor d, int index) {
+        try {
+            ConstantPool.CPInfo cpInfo = constant_pool.get(index);
+
+            switch (cpInfo.getTag()) {
+                case ConstantPool.CONSTANT_Integer: {
+                    ConstantPool.CONSTANT_Integer_info info =
+                            (ConstantPool.CONSTANT_Integer_info) cpInfo;
+                    String t = d.getValue(constant_pool);
+                    if (t.equals("C")) { // character
+                        return getConstantCharValue((char) info.value);
+                    } else if (t.equals("Z")) { // boolean
+                        return String.valueOf(info.value == 1);
+                    } else { // other: assume integer
+                        return String.valueOf(info.value);
+                    }
+                }
+
+                case ConstantPool.CONSTANT_String: {
+                    ConstantPool.CONSTANT_String_info info =
+                            (ConstantPool.CONSTANT_String_info) cpInfo;
+                    return getConstantStringValue(info.getString());
+                }
+
+                default:
+                    return constantWriter.stringValue(cpInfo);
+            }
+        } catch (ConstantPoolException e) {
+            return "#" + index;
+        }
+    }
+
+    private String getConstantCharValue(char c) {
+        StringBuilder sb = new StringBuilder();
+        sb.append('\'');
+        sb.append(esc(c, '\''));
+        sb.append('\'');
+        return sb.toString();
+    }
+
+    private String getConstantStringValue(String s) {
+        StringBuilder sb = new StringBuilder();
+        sb.append("\"");
+        for (int i = 0; i < s.length(); i++) {
+            sb.append(esc(s.charAt(i), '"'));
+        }
+        sb.append("\"");
+        return sb.toString();
+    }
+
+    private String esc(char c, char quote) {
+        if (32 <= c && c <= 126 && c != quote)
+            return String.valueOf(c);
+        else switch (c) {
+            case '\b': return "\\b";
+            case '\n': return "\\n";
+            case '\t': return "\\t";
+            case '\f': return "\\f";
+            case '\r': return "\\r";
+            case '\\': return "\\\\";
+            case '\'': return "\\'";
+            case '\"': return "\\\"";
+            default:   return String.format("\\u%04x", (int) c);
+        }
+    }
+
     private Options options;
     private AttributeWriter attrWriter;
     private CodeWriter codeWriter;
     private ConstantWriter constantWriter;
     private ClassFile classFile;
+    private URI uri;
+    private long lastModified;
+    private String digestName;
+    private byte[] digest;
+    private int size;
     private ConstantPool constant_pool;
     private Method method;
     private static final String NEWLINE = System.getProperty("line.separator", "\n");
--- a/langtools/src/share/classes/com/sun/tools/javap/JavapTask.java	Wed Jul 05 16:39:59 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/javap/JavapTask.java	Wed Jul 05 16:40:31 2017 +0200
@@ -16,7 +16,7 @@
  *
  * 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-15301 USA.
+ * 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
@@ -27,11 +27,15 @@
 
 import java.io.EOFException;
 import java.io.FileNotFoundException;
+import java.io.FilterInputStream;
+import java.io.InputStream;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.io.PrintWriter;
 import java.io.StringWriter;
 import java.io.Writer;
+import java.security.DigestInputStream;
+import java.security.MessageDigest;
 import java.text.MessageFormat;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -199,6 +203,12 @@
             }
         },
 
+        new Option(false, "-sysinfo") {
+            void process(JavapTask task, String opt, String arg) {
+                task.options.sysInfo = true;
+            }
+        },
+
         new Option(false, "-Xold") {
             void process(JavapTask task, String opt, String arg) throws BadArgs {
                 // -Xold is only supported as first arg when invoked from
@@ -229,6 +239,12 @@
             void process(JavapTask task, String opt, String arg) {
                 task.options.ignoreSymbolFile = true;
             }
+        },
+
+        new Option(false, "-constants") {
+            void process(JavapTask task, String opt, String arg) {
+                task.options.showConstants = true;
+            }
         }
 
     };
@@ -488,8 +504,27 @@
                 Attribute.Factory attributeFactory = new Attribute.Factory();
                 attributeFactory.setCompat(options.compat);
                 attributeFactory.setJSR277(options.jsr277);
-                ClassFile cf = ClassFile.read(fo.openInputStream(), attributeFactory);
+
+                InputStream in = fo.openInputStream();
+                SizeInputStream sizeIn = null;
+                MessageDigest md  = null;
+                if (options.sysInfo || options.verbose) {
+                    md = MessageDigest.getInstance("MD5");
+                    in = new DigestInputStream(in, md);
+                    in = sizeIn = new SizeInputStream(in);
+                }
+
+                ClassFile cf = ClassFile.read(in, attributeFactory);
+
+                if (options.sysInfo || options.verbose) {
+                    classWriter.setFile(fo.toUri());
+                    classWriter.setLastModified(fo.getLastModified());
+                    classWriter.setDigest("MD5", md.digest());
+                    classWriter.setFileSize(sizeIn.size());
+                }
+
                 classWriter.write(cf);
+
             } catch (ConstantPoolException e) {
                 diagnosticListener.report(createDiagnostic("err.bad.constant.pool", className, e.getLocalizedMessage()));
                 ok = false;
@@ -659,4 +694,31 @@
     Map<Locale, ResourceBundle> bundles;
 
     private static final String progname = "javap";
+
+    private static class SizeInputStream extends FilterInputStream {
+        SizeInputStream(InputStream in) {
+            super(in);
+        }
+
+        int size() {
+            return size;
+        }
+
+        @Override
+        public int read(byte[] buf, int offset, int length) throws IOException {
+            int n = super.read(buf, offset, length);
+            if (n > 0)
+                size += n;
+            return n;
+        }
+
+        @Override
+        public int read() throws IOException {
+            int b = super.read();
+            size += 1;
+            return b;
+        }
+
+        private int size;
+    }
 }
--- a/langtools/src/share/classes/com/sun/tools/javap/Options.java	Wed Jul 05 16:39:59 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/javap/Options.java	Wed Jul 05 16:40:31 2017 +0200
@@ -80,6 +80,8 @@
     public boolean showDisassembled;
     public boolean showInternalSignatures;
     public boolean showAllAttrs;
+    public boolean showConstants;
+    public boolean sysInfo;
 
     public boolean compat;             // bug-for-bug compatibility mode with old javap
     public boolean jsr277;
--- a/langtools/src/share/classes/com/sun/tools/javap/resources/javap.properties	Wed Jul 05 16:39:59 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/javap/resources/javap.properties	Wed Jul 05 16:40:31 2017 +0200
@@ -63,5 +63,10 @@
 main.opt.bootclasspath=\
 \  -bootclasspath <path>    Override location of bootstrap class files
 
+main.opt.constants=\
+\  -constants               Show static final constants
 
 
+main.opt.sysinfo=\
+\  -sysinfo                 Show system info (path, size, date, MD5 hash)\n\
+\                           of class being processed
--- a/langtools/test/tools/javac/5045412/Bar.java	Wed Jul 05 16:39:59 2017 +0200
+++ b/langtools/test/tools/javac/5045412/Bar.java	Wed Jul 05 16:40:31 2017 +0200
@@ -1,13 +1,36 @@
-/**
- * @test  /nodynamiccopyright/
- * @bug 5045412
- * @compile/fail/ref=out -XDstdout -XDrawDiagnostics -Xlint:serial -XDfailcomplete=java.io.Serializable Bar.java
+/*
+ * Copyright 2005-2006 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  /nodynamiccopyright/
- * @bug 5045412
- * @compile/fail/ref=out -XDstdout -XDrawDiagnostics -Xlint:serial -XDfailcomplete=java.io.Serializable Bar.java Foo.java
+ * @test
+ * @bug 5045412 6627366
+ * @compile -Xlint:serial -XDfailcomplete=java.io.Serializable Bar.java
+ */
+
+/**
+ * @test
+ * @bug 5045412 6627366
+ * @compile -Xlint:serial -XDfailcomplete=java.io.Serializable Bar.java Foo.java
  */
 
 class Bar implements java.io.Serializable { }
--- a/langtools/test/tools/javac/5045412/Foo.java	Wed Jul 05 16:39:59 2017 +0200
+++ b/langtools/test/tools/javac/5045412/Foo.java	Wed Jul 05 16:40:31 2017 +0200
@@ -23,14 +23,14 @@
 
 /**
  * @test
- * @bug 5045412
+ * @bug 5045412 6627366
  * @compile -Xlint:serial -XDfailcomplete=java.io.Serializable Foo.java
  */
 
 /**
  * @test
- * @bug 5045412
- * @compile/fail/ref=out -XDstdout -XDrawDiagnostics -Xlint:serial -XDfailcomplete=java.io.Serializable Foo.java Bar.java
+ * @bug 5045412 6627366
+ * @compile -Xlint:serial -XDfailcomplete=java.io.Serializable Foo.java Bar.java
  */
 
 class Foo { }
--- a/langtools/test/tools/javac/5045412/out	Wed Jul 05 16:39:59 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-Bar.java:13:29: compiler.err.cant.resolve.location: kindname.class, Serializable, , , kindname.package, java.io
-1 error
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/6627362/T6627362.java	Wed Jul 05 16:40:31 2017 +0200
@@ -0,0 +1,133 @@
+/*
+ * 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 6627362
+ * @summary javac generates code that uses array.clone,
+ *          which is not available on JavaCard
+ */
+
+import java.io.*;
+import java.lang.reflect.*;
+import java.net.*;
+import java.util.*;
+
+public class T6627362 {
+    static String testSrc = System.getProperty("test.src", ".");
+
+    public static void main(String... args) throws Exception {
+        new T6627362().run();
+    }
+
+    public void run() throws Exception {
+        testStandard();
+        testNoClone();
+        if (errors > 0)
+            throw new Error(errors + " test cases failed");
+    }
+
+    void testStandard() throws Exception {
+        // compile and disassemble E.java, check for reference to Object.clone()
+        File x = new File(testSrc, "x");
+        String[] jcArgs = { "-d", ".",
+                            new File(x, "E.java").getPath() };
+        compile(jcArgs);
+
+        String[] jpArgs = { "-classpath", ".", "-c", "E" };
+
+        StringWriter sw = new StringWriter();
+        javap(new PrintWriter(sw, true), jpArgs);
+        check(sw.toString(), "Method \"[LE;\".clone:()Ljava/lang/Object;");
+        callValues();
+    }
+
+    void testNoClone() throws Exception {
+        // compile and disassemble E.java, using modified Object.java,
+        // check for reference to System.arraycopy
+        File x = new File(testSrc, "x");
+        String[] jcArgs = { "-d", ".",
+                            new File(x, "E.java").getPath(),
+                            new File(x, "Object.java").getPath()};
+        compile(jcArgs);
+
+        String[] jpArgs = { "-classpath", ".", "-c", "E" };
+
+        StringWriter sw = new StringWriter();
+        javap(new PrintWriter(sw, true), jpArgs);
+        check(sw.toString(), "//Method java/lang/System.arraycopy:(Ljava/lang/Object;ILjava/lang/Object;II)V");
+        callValues();
+    }
+
+    void compile(String... args) {
+        int rc = com.sun.tools.javac.Main.compile(args);
+        if (rc != 0)
+            throw new Error("javac failed: " + Arrays.asList(args) + ": " + rc);
+    }
+
+    void javap(PrintWriter out, String... args) throws Exception {
+        // for now, we have to exec javap
+        File javaHome = new File(System.getProperty("java.home"));
+        if (javaHome.getName().equals("jre"))
+            javaHome = javaHome.getParentFile();
+        File javap = new File(new File(javaHome, "bin"), "javap");
+        String[] cmd = new String[args.length + 1];
+        cmd[0] = javap.getPath();
+        System.arraycopy(args, 0, cmd, 1, args.length);
+        Process p = new ProcessBuilder(cmd).redirectErrorStream(true).start();
+        p.getOutputStream().close();
+        BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()));
+        String line;
+        while ((line = in.readLine()) != null)
+            out.println(line);
+        int rc = p.waitFor();
+        if (rc != 0)
+            throw new Error("javap failed: " + Arrays.asList(args) + ": " + rc);
+    }
+
+    void check(String s, String require) {
+        if (s.indexOf(require) == -1) {
+            System.err.println("Can't find " + require);
+            errors++;
+        }
+    }
+
+    void callValues() {
+        try {
+            File dot = new File(System.getProperty("user.dir"));
+            ClassLoader cl = new URLClassLoader(new URL[] { dot.toURL() });
+            Class<?> e_class = cl.loadClass("E");
+            Method m = e_class.getMethod("values", new Class[] { });
+            //System.err.println(m);
+            Object o = m.invoke(null, (Object[]) null);
+            List<Object> v = Arrays.asList((Object[]) o);
+            if (!v.toString().equals("[a, b, c]"))
+                throw new Error("unexpected result for E.values(): " + v);
+        } catch (Exception e) {
+            throw new Error(e);
+        }
+    }
+
+    int errors;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/6627362/x/E.java	Wed Jul 05 16:40:31 2017 +0200
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+public enum E {
+    a, b, c
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/6627362/x/Object.java	Wed Jul 05 16:40:31 2017 +0200
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+package java.lang;
+
+/*
+ * Object, without clone()
+ */
+public class Object {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/6734819/T6734819a.java	Wed Jul 05 16:40:31 2017 +0200
@@ -0,0 +1,39 @@
+/*
+ * 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 6734819
+ * @summary Javac performs flows analysis on already translated classes
+ * @author Maurizio Cimadamore
+ *
+ * @compile/ref=T6734819a.out -XDrawDiagnostics -Xlint:all -XDverboseCompilePolicy T6734819a.java
+ */
+class Y extends W {}
+class W extends Z {}
+
+class Z {
+    void m(Z z) {
+        W w = (W)z;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/6734819/T6734819a.out	Wed Jul 05 16:40:31 2017 +0200
@@ -0,0 +1,12 @@
+[attribute Y]
+[flow Y]
+[attribute W]
+[flow W]
+[attribute Z]
+[flow Z]
+[desugar Y]
+[generate code Y]
+[desugar W]
+[generate code W]
+[desugar Z]
+[generate code Z]
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/6734819/T6734819b.java	Wed Jul 05 16:40:31 2017 +0200
@@ -0,0 +1,35 @@
+/*
+ * 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 6734819
+ * @summary Javac performs flows analysis on already translated classes
+ * @author Maurizio Cimadamore
+ *
+ * @compile/ref=T6734819b.out -XDrawDiagnostics -Xlint:all -XDverboseCompilePolicy T6734819b.java
+ */
+class A extends B {}
+class B {
+    class C extends B {}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/6734819/T6734819b.out	Wed Jul 05 16:40:31 2017 +0200
@@ -0,0 +1,9 @@
+[attribute A]
+[flow A]
+[attribute B]
+[flow B]
+[desugar A]
+[generate code A]
+[desugar B]
+[generate code B]
+[generate code B]
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/6734819/T6734819c.java	Wed Jul 05 16:40:31 2017 +0200
@@ -0,0 +1,40 @@
+/*
+ * 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 6734819
+ * @summary Javac performs flows analysis on already translated classes
+ * @author Maurizio Cimadamore
+ *
+ * @compile/fail/ref=T6734819c.out -XDrawDiagnostics -Xlint:all -XDverboseCompilePolicy T6734819c.java
+ */
+class Y extends W {}
+class W extends Z {}
+
+class Z {
+    void m(Z z) {
+        return;
+        W w = (W)z;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/6734819/T6734819c.out	Wed Jul 05 16:40:31 2017 +0200
@@ -0,0 +1,8 @@
+[attribute Y]
+[flow Y]
+[attribute W]
+[flow W]
+[attribute Z]
+[flow Z]
+T6734819c.java:38:11: compiler.err.unreachable.stmt
+1 error
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/ForwardReference/T6676362a.java	Wed Jul 05 16:40:31 2017 +0200
@@ -0,0 +1,36 @@
+/*
+ * 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 6676362
+ * @summary Spurious forward reference error with final var + instance variable initializer
+ * @author Maurizio Cimadamore
+ *
+ * @compile T6676362a.java
+ */
+
+public class T6676362a {
+    Object o = new Object() {Object m() {return o2;}};
+    final Object o2 = o;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/ForwardReference/T6676362b.java	Wed Jul 05 16:40:31 2017 +0200
@@ -0,0 +1,36 @@
+/*
+ * 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 6676362
+ * @summary Spurious forward reference error with final var + instance variable initializer
+ * @author Maurizio Cimadamore
+ *
+ * @compile T6676362b.java
+ */
+
+public class T6676362b {
+    static final int i1 = T6676362b.i2; //legal - usage is not via simple name
+    static final int i2 = i1;
+}
--- a/langtools/test/tools/javac/enum/forwardRef/T6425594.out	Wed Jul 05 16:39:59 2017 +0200
+++ b/langtools/test/tools/javac/enum/forwardRef/T6425594.out	Wed Jul 05 16:40:31 2017 +0200
@@ -1,4 +1,4 @@
-T6425594.java:10:28: compiler.warn.forward.ref: x
+T6425594.java:10:28: compiler.warn.self.ref: x
 T6425594.java:11:26: compiler.err.illegal.forward.ref
 1 error
 1 warning
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/generics/inference/6718364/T6718364.java	Wed Jul 05 16:40:31 2017 +0200
@@ -0,0 +1,38 @@
+/*
+ * 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 6718364
+ * @summary inference fails when a generic method is invoked with raw arguments
+ * @compile/ref=T6718364.out -XDstdout -XDrawDiagnostics -Xlint:unchecked T6718364.java
+ */
+class T6718364 {
+    class X<T> {}
+
+    public <T> void m(X<T> x, T t) {}
+
+    public void test() {
+        m(new X<X<Integer>>(), new X());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/generics/inference/6718364/T6718364.out	Wed Jul 05 16:40:31 2017 +0200
@@ -0,0 +1,3 @@
+T6718364.java:36:32: compiler.warn.prob.found.req: (- compiler.misc.unchecked.assign), T6718364.X, T6718364.X<java.lang.Integer>
+T6718364.java:36:10: compiler.warn.unchecked.meth.invocation.applied: <T>m(T6718364.X<T>,T), T6718364, , T6718364.X<T6718364.X<java.lang.Integer>>,T6718364.X
+2 warnings
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/staticImport/6695838/T6695838.java	Wed Jul 05 16:40:31 2017 +0200
@@ -0,0 +1,31 @@
+/*
+ * 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 6695838
+ * @summary javac does not detect cyclic inheritance involving static inner classes after import clause
+ * @author Maurizio Cimadamore
+ *
+ * @compile/fail a/FooInterface.java
+ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/staticImport/6695838/a/Foo.java	Wed Jul 05 16:40:31 2017 +0200
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+package a;
+
+class Foo implements FooInterface {
+    public static interface InnerInterface {}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/staticImport/6695838/a/FooInterface.java	Wed Jul 05 16:40:31 2017 +0200
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+package a;
+
+import a.Foo.InnerInterface;
+
+public interface FooInterface extends Foo.InnerInterface {}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/synthesize/Boolean.java	Wed Jul 05 16:40:31 2017 +0200
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+package java.lang;
+
+public class Boolean
+{
+    public static Boolean valueOf(boolean v) {
+        return new Boolean(v);
+    }
+
+    public Boolean(boolean v) {
+        value = v;
+    }
+
+    public boolean booleanValue() {
+        return value;
+    }
+
+    private boolean value;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/synthesize/Byte.java	Wed Jul 05 16:40:31 2017 +0200
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+package java.lang;
+
+public class Byte
+{
+    public static Byte valueOf(byte v) {
+        return new Byte(v);
+    }
+
+    public Byte(byte v) {
+        value = v;
+    }
+
+    public byte byteValue() {
+        return value;
+    }
+
+    private byte value;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/synthesize/Character.java	Wed Jul 05 16:40:31 2017 +0200
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+package java.lang;
+
+public class Character
+{
+    public static Character valueOf(char v) {
+        return new Character(v);
+    }
+
+    public Character(char v) {
+        value = v;
+    }
+
+    public char characterValue() {
+        return value;
+    }
+
+    private char value;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/synthesize/Cloneable.java	Wed Jul 05 16:40:31 2017 +0200
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+package java.lang;
+
+public interface Cloneable {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/synthesize/Double.java	Wed Jul 05 16:40:31 2017 +0200
@@ -0,0 +1,18 @@
+package java.lang;
+
+public class Double extends Number
+{
+    public static Double valueOf(double v) {
+        return new Double(v);
+    }
+
+    public Double(double v) {
+        value = v;
+    }
+
+    public double doubleValue() {
+        return value;
+    }
+
+    private double value;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/synthesize/Float.java	Wed Jul 05 16:40:31 2017 +0200
@@ -0,0 +1,18 @@
+package java.lang;
+
+public class Float extends Number
+{
+    public static Float valueOf(float v) {
+        return new Float(v);
+    }
+
+    public Float(float v) {
+        value = v;
+    }
+
+    public float floatValue() {
+        return value;
+    }
+
+    private float value;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/synthesize/Integer.java	Wed Jul 05 16:40:31 2017 +0200
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+package java.lang;
+
+public class Integer extends Number
+{
+    public static Integer valueOf(int v) {
+        return new Integer(v);
+    }
+
+    public Integer(int v) {
+        value = v;
+    }
+
+    public int integerValue() {
+        return value;
+    }
+
+    private int value;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/synthesize/Long.java	Wed Jul 05 16:40:31 2017 +0200
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+package java.lang;
+
+public class Long extends Number
+{
+    public static Long valueOf(long v) {
+        return new Long(v);
+    }
+
+    public Long(long v) {
+        value = v;
+    }
+
+    public long longValue() {
+        return value;
+    }
+
+    private long value;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/synthesize/Main.java	Wed Jul 05 16:40:31 2017 +0200
@@ -0,0 +1,122 @@
+/*
+ * 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 6627364 6627366
+ * @summary Synthesize important classes if they are missing from the (boot)classpath
+ */
+
+import java.io.*;
+import java.util.*;
+
+public class Main
+{
+    File testSrc = new File(System.getProperty("test.src"));
+
+    public static void main(String[] args) throws Exception {
+        new Main().run();
+    }
+
+    public void run() throws Exception {
+
+        // compile with standard bootclasspath
+        compile(true, "Test.java");
+
+        // compile with various missing system classes
+
+        List<String> base_files = Arrays.asList(
+            "Boolean.java",
+            "Byte.java",
+            "Character.java",
+            "Integer.java",
+            "Long.java",
+            "Number.java",
+            "Object.java",
+            "Short.java",
+            "Void.java"
+        );
+
+        List<String> extra_files = Arrays.asList(
+            "Double.java",
+            "Float.java",
+            "Cloneable.java",
+            "Serializable.java"
+        );
+
+        List<String> files = new ArrayList<String>();
+        files.addAll(base_files);
+        files.add("Test.java");
+
+        compile(false, files);
+
+        for (String f: extra_files) {
+            files = new ArrayList<String>();
+            files.addAll(base_files);
+            files.addAll(extra_files);
+            files.remove(f);
+            files.add("Test.java");
+            compile(false, files);
+        }
+
+        if (errors > 0)
+            throw new Exception(errors + " errors occurred");
+    }
+
+    void compile(boolean stdBootClassPath, String... files) {
+        compile(stdBootClassPath, Arrays.asList(files));
+    }
+
+    void compile(boolean stdBootClassPath, List<String> files) {
+        File empty = new File("empty");
+        empty.mkdirs();
+
+        List<String> args = new ArrayList<String>();
+        args.add("-classpath");
+        args.add("empty");
+
+        if (!stdBootClassPath) {
+            args.add("-bootclasspath");
+            args.add("empty");
+        }
+        args.add("-d");
+        args.add(".");
+        for (String f: files)
+            args.add(new File(testSrc, f).getPath());
+
+        System.out.println("Compile: " + args);
+        StringWriter out = new StringWriter();
+        int rc = com.sun.tools.javac.Main.compile(args.toArray(new String[args.size()]),
+                                                  new PrintWriter(out));
+        System.out.println(out.toString());
+        System.out.println("result: " + rc);
+        System.out.println();
+
+        if (rc != 0)
+            errors++;
+    }
+
+    private int errors;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/synthesize/Number.java	Wed Jul 05 16:40:31 2017 +0200
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+package java.lang;
+
+public class Number
+{
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/synthesize/Object.java	Wed Jul 05 16:40:31 2017 +0200
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+package java.lang;
+
+public class Object
+{
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/synthesize/Serializable.java	Wed Jul 05 16:40:31 2017 +0200
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+package java.io;
+
+public interface Serializable {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/synthesize/Short.java	Wed Jul 05 16:40:31 2017 +0200
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+package java.lang;
+
+public class Short extends Number
+{
+    public static Short valueOf(short v) {
+        return new Short(v);
+    }
+
+    public Short(short v) {
+        value = v;
+    }
+
+    public short shortValue() {
+        return value;
+    }
+
+    private short value;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/synthesize/Test.java	Wed Jul 05 16:40:31 2017 +0200
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+// This code (indirectly) requires the presence of
+// Cloneable and Serializable (supertypes for Java arrays)
+// Double and Float (for boxing/unboxing)
+public class Test
+{
+    Object f(boolean b, int[] array) {
+        return b ? array : 2;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/synthesize/Void.java	Wed Jul 05 16:40:31 2017 +0200
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+package java.lang;
+
+public class Void
+{
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javap/4111861/A.java	Wed Jul 05 16:40:31 2017 +0200
@@ -0,0 +1,14 @@
+class A {
+    public static final int i = 42;
+    public static final boolean b = true;
+    public static final float f = 1.0f;
+    public static final double d = 1.0d;
+    public static final short s = 1;
+    public static final long l = 1l;
+    public static final char cA = 'A';
+    public static final char c0 = '\u0000';
+    public static final char cn = '\n';
+    public static final char cq1 = '\'';
+    public static final char cq2 = '"';
+    public static final java.lang.String t1 = "abc \u0000 \f\n\r\t'\"";
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javap/4111861/T4111861.java	Wed Jul 05 16:40:31 2017 +0200
@@ -0,0 +1,101 @@
+/*
+ * 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.io.*;
+
+/*
+ * @test
+ * @bug 4111861
+ * @summary static final field contents are not displayed
+ */
+public class T4111861 {
+    public static void main(String... args) throws Exception {
+        new T4111861().run();
+    }
+
+    void run() throws Exception {
+        File testSrc = new File(System.getProperty("test.src", "."));
+        File a_java = new File(testSrc, "A.java");
+        javac("-d", ".", a_java.getPath());
+
+        String out = javap("-classpath", ".", "-constants", "A");
+
+        String a = read(a_java);
+
+        if (!filter(out).equals(filter(read(a_java)))) {
+            System.out.println(out);
+            throw new Exception("unexpected output");
+        }
+    }
+
+    String javac(String... args) throws Exception {
+        StringWriter sw = new StringWriter();
+        PrintWriter pw = new PrintWriter(sw);
+        int rc = com.sun.tools.javac.Main.compile(args, pw);
+        if (rc != 0)
+            throw new Exception("javac failed, rc=" + rc);
+        return sw.toString();
+    }
+
+    String javap(String... args) throws Exception {
+        StringWriter sw = new StringWriter();
+        PrintWriter pw = new PrintWriter(sw);
+        int rc = com.sun.tools.javap.Main.run(args, pw);
+        if (rc != 0)
+            throw new Exception("javap failed, rc=" + rc);
+        return sw.toString();
+    }
+
+    String read(File f) throws IOException {
+        StringBuilder sb = new StringBuilder();
+        BufferedReader in = new BufferedReader(new FileReader(f));
+        try {
+            String line;
+            while ((line = in.readLine()) != null) {
+                sb.append(line);
+                sb.append('\n');
+            }
+        } finally {
+            in.close();
+        }
+        return sb.toString();
+    }
+
+    // return those lines beginning "public static final"
+    String filter(String s) throws IOException {
+        StringBuilder sb = new StringBuilder();
+        BufferedReader in = new BufferedReader(new StringReader(s));
+        try {
+            String line;
+            while ((line = in.readLine()) != null) {
+                if (line.indexOf("public static final") > 0) {
+                    sb.append(line);
+                    sb.append('\n');
+                }
+            }
+        } finally {
+            in.close();
+        }
+        return sb.toString();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javap/T4884240.java	Wed Jul 05 16:40:31 2017 +0200
@@ -0,0 +1,56 @@
+/*
+ * 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-15301 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 4884240
+ * @summary additional option required for javap
+ */
+
+import java.io.*;
+
+public class T4884240 {
+    public static void main(String... args) throws Exception {
+        new T4884240().run();
+    }
+
+    public void run() throws Exception {
+        StringWriter sw = new StringWriter();
+        PrintWriter pw = new PrintWriter(sw);
+        String[] args = { "-sysinfo", "java.lang.Object" };
+        int rc = com.sun.tools.javap.Main.run(args, pw);
+        if (rc != 0)
+            throw new Exception("unexpected return code: " + rc);
+        pw.close();
+        String[] lines = sw.toString().split("\n");
+        if (lines.length < 3
+            || !lines[0].startsWith("Classfile")
+            || !lines[1].startsWith("Last modified")
+            || !lines[2].startsWith("MD5")) {
+            System.out.println(sw);
+            throw new Exception("unexpected output");
+        }
+    }
+}
--- a/langtools/test/tools/javap/T6622260.java	Wed Jul 05 16:39:59 2017 +0200
+++ b/langtools/test/tools/javap/T6622260.java	Wed Jul 05 16:40:31 2017 +0200
@@ -189,6 +189,10 @@
 
     void verify(String output) {
         System.out.println(output);
+        if (output.startsWith("Classfile")) {
+            // make sure to ignore filename
+            output = output.substring(output.indexOf('\n'));
+        }
         if (output.indexOf("-") >= 0)
             throw new Error("- found in output");
         if (output.indexOf("FFFFFF") >= 0)